Coverage Report

Created: 2025-11-16 06:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/ogr/ogrpolygon.cpp
Line
Count
Source
1
/******************************************************************************
2
 *
3
 * Project:  OpenGIS Simple Features Reference Implementation
4
 * Purpose:  The OGRPolygon geometry class.
5
 * Author:   Frank Warmerdam, warmerdam@pobox.com
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 1999, Frank Warmerdam
9
 * Copyright (c) 2008-2014, Even Rouault <even dot rouault at spatialys.com>
10
 *
11
 * SPDX-License-Identifier: MIT
12
 ****************************************************************************/
13
14
#include "cpl_port.h"
15
#include "ogr_geometry.h"
16
17
#include <cstring>
18
#include <cstddef>
19
#include <new>
20
21
#include "cpl_conv.h"
22
#include "cpl_error.h"
23
#include "cpl_vsi.h"
24
#include "ogr_api.h"
25
#include "ogr_core.h"
26
#include "ogr_geos.h"
27
#include "ogr_sfcgal.h"
28
#include "ogr_p.h"
29
30
/************************************************************************/
31
/*        OGRPolygon(double x1, double y1, double x2, double y2)        */
32
/************************************************************************/
33
34
/**
35
 * \brief Construct a rectangular polygon from opposite corner coordinates.
36
 *
37
 * @since GDAL 3.11
38
 */
39
40
OGRPolygon::OGRPolygon(double x1, double y1, double x2, double y2)
41
0
{
42
0
    auto poLR = std::make_unique<OGRLinearRing>();
43
0
    poLR->addPoint(x1, y1);
44
0
    poLR->addPoint(x1, y2);
45
0
    poLR->addPoint(x2, y2);
46
0
    poLR->addPoint(x2, y1);
47
0
    poLR->addPoint(x1, y1);
48
0
    addRingDirectly(poLR.release());
49
0
}
50
51
/************************************************************************/
52
/*                OGRPolygon(const OGREnvelope &envelope)               */
53
/************************************************************************/
54
55
/**
56
 * \brief Construct a rectangular polygon from opposite corner coordinates
57
 * of a OGREnvelope.
58
 *
59
 * @since GDAL 3.11
60
 */
61
62
OGRPolygon::OGRPolygon(const OGREnvelope &envelope)
63
0
    : OGRPolygon(envelope.MinX, envelope.MinY, envelope.MaxX, envelope.MaxY)
64
0
{
65
0
}
66
67
/************************************************************************/
68
/*                     OGRPolygon( const OGRPolygon& )                  */
69
/************************************************************************/
70
71
/**
72
 * \brief Copy constructor.
73
 */
74
75
0
OGRPolygon::OGRPolygon(const OGRPolygon &) = default;
76
77
/************************************************************************/
78
/*                     operator=( const OGRPolygon&)                    */
79
/************************************************************************/
80
81
/**
82
 * \brief Assignment operator.
83
 */
84
85
OGRPolygon &OGRPolygon::operator=(const OGRPolygon &other)
86
0
{
87
0
    if (this != &other)
88
0
    {
89
0
        OGRCurvePolygon::operator=(other);
90
0
    }
91
0
    return *this;
92
0
}
93
94
/************************************************************************/
95
/*                               clone()                                */
96
/************************************************************************/
97
98
OGRPolygon *OGRPolygon::clone() const
99
100
0
{
101
0
    auto ret = new (std::nothrow) OGRPolygon(*this);
102
0
    if (ret)
103
0
    {
104
0
        if (ret->WkbSize() != WkbSize())
105
0
        {
106
0
            delete ret;
107
0
            ret = nullptr;
108
0
        }
109
0
    }
110
0
    return ret;
111
0
}
112
113
/************************************************************************/
114
/*                          getGeometryType()                           */
115
/************************************************************************/
116
117
OGRwkbGeometryType OGRPolygon::getGeometryType() const
118
119
10.5k
{
120
10.5k
    if ((flags & OGR_G_3D) && (flags & OGR_G_MEASURED))
121
6.63k
        return wkbPolygonZM;
122
3.96k
    else if (flags & OGR_G_MEASURED)
123
920
        return wkbPolygonM;
124
3.04k
    else if (flags & OGR_G_3D)
125
2.09k
        return wkbPolygon25D;
126
951
    else
127
951
        return wkbPolygon;
128
10.5k
}
129
130
/************************************************************************/
131
/*                          getGeometryName()                           */
132
/************************************************************************/
133
134
const char *OGRPolygon::getGeometryName() const
135
136
637
{
137
637
    return "POLYGON";
138
637
}
139
140
/************************************************************************/
141
/*                          getExteriorRing()                           */
142
/************************************************************************/
143
144
/**
145
 * \brief Fetch reference to external polygon ring.
146
 *
147
 * Note that the returned ring pointer is to an internal data object of
148
 * the OGRPolygon.  It should not be modified or deleted by the application,
149
 * and the pointer is only valid till the polygon is next modified.  Use
150
 * the OGRGeometry::clone() method to make a separate copy within the
151
 * application.
152
 *
153
 * Relates to the SFCOM IPolygon::get_ExteriorRing() method.
154
 *
155
 * @return pointer to external ring.  May be NULL if the OGRPolygon is empty.
156
 */
157
158
OGRLinearRing *OGRPolygon::getExteriorRing()
159
160
0
{
161
0
    if (oCC.nCurveCount > 0)
162
0
        return oCC.papoCurves[0]->toLinearRing();
163
164
0
    return nullptr;
165
0
}
166
167
/**
168
 * \brief Fetch reference to external polygon ring.
169
 *
170
 * Note that the returned ring pointer is to an internal data object of
171
 * the OGRPolygon.  It should not be modified or deleted by the application,
172
 * and the pointer is only valid till the polygon is next modified.  Use
173
 * the OGRGeometry::clone() method to make a separate copy within the
174
 * application.
175
 *
176
 * Relates to the SFCOM IPolygon::get_ExteriorRing() method.
177
 *
178
 * @return pointer to external ring.  May be NULL if the OGRPolygon is empty.
179
 */
180
181
const OGRLinearRing *OGRPolygon::getExteriorRing() const
182
183
0
{
184
0
    if (oCC.nCurveCount > 0)
185
0
        return oCC.papoCurves[0]->toLinearRing();
186
187
0
    return nullptr;
188
0
}
189
190
/************************************************************************/
191
/*                          stealExteriorRing()                         */
192
/************************************************************************/
193
194
/**
195
 * \brief "Steal" reference to external polygon ring.
196
 *
197
 * After the call to that function, only call to stealInteriorRing() or
198
 * destruction of the OGRPolygon is valid. Other operations may crash.
199
 *
200
 * @return pointer to external ring.  May be NULL if the OGRPolygon is empty.
201
 */
202
203
OGRLinearRing *OGRPolygon::stealExteriorRing()
204
0
{
205
0
    return stealExteriorRingCurve()->toLinearRing();
206
0
}
207
208
/************************************************************************/
209
/*                          getInteriorRing()                           */
210
/************************************************************************/
211
212
/**
213
 * \brief Fetch reference to indicated internal ring.
214
 *
215
 * Note that the returned ring pointer is to an internal data object of
216
 * the OGRPolygon.  It should not be modified or deleted by the application,
217
 * and the pointer is only valid till the polygon is next modified.  Use
218
 * the OGRGeometry::clone() method to make a separate copy within the
219
 * application.
220
 *
221
 * Relates to the SFCOM IPolygon::get_InternalRing() method.
222
 *
223
 * @param iRing internal ring index from 0 to getNumInteriorRings() - 1.
224
 *
225
 * @return pointer to interior ring.  May be NULL.
226
 */
227
228
OGRLinearRing *OGRPolygon::getInteriorRing(int iRing)
229
230
0
{
231
0
    if (iRing < 0 || iRing >= oCC.nCurveCount - 1)
232
0
        return nullptr;
233
234
0
    return oCC.papoCurves[iRing + 1]->toLinearRing();
235
0
}
236
237
/**
238
 * \brief Fetch reference to indicated internal ring.
239
 *
240
 * Note that the returned ring pointer is to an internal data object of
241
 * the OGRPolygon.  It should not be modified or deleted by the application,
242
 * and the pointer is only valid till the polygon is next modified.  Use
243
 * the OGRGeometry::clone() method to make a separate copy within the
244
 * application.
245
 *
246
 * Relates to the SFCOM IPolygon::get_InternalRing() method.
247
 *
248
 * @param iRing internal ring index from 0 to getNumInteriorRings() - 1.
249
 *
250
 * @return pointer to interior ring.  May be NULL.
251
 */
252
253
const OGRLinearRing *OGRPolygon::getInteriorRing(int iRing) const
254
255
0
{
256
0
    if (iRing < 0 || iRing >= oCC.nCurveCount - 1)
257
0
        return nullptr;
258
259
0
    return oCC.papoCurves[iRing + 1]->toLinearRing();
260
0
}
261
262
/************************************************************************/
263
/*                          stealInteriorRing()                         */
264
/************************************************************************/
265
266
/**
267
 * \brief "Steal" reference to indicated interior ring.
268
 *
269
 * After the call to that function, only call to stealInteriorRing() or
270
 * destruction of the OGRPolygon is valid. Other operations may crash.
271
 *
272
 * @param iRing internal ring index from 0 to getNumInteriorRings() - 1.
273
 * @return pointer to interior ring.  May be NULL.
274
 */
275
276
OGRLinearRing *OGRPolygon::stealInteriorRing(int iRing)
277
0
{
278
0
    if (iRing < 0 || iRing >= oCC.nCurveCount - 1)
279
0
        return nullptr;
280
0
    OGRLinearRing *poRet = oCC.papoCurves[iRing + 1]->toLinearRing();
281
0
    oCC.papoCurves[iRing + 1] = nullptr;
282
0
    return poRet;
283
0
}
284
285
/*! @cond Doxygen_Suppress */
286
287
/************************************************************************/
288
/*                            isRingCorrectType()                               */
289
/************************************************************************/
290
bool OGRPolygon::isRingCorrectType(const OGRCurve *poRing) const
291
0
{
292
0
    return poRing != nullptr && EQUAL(poRing->getGeometryName(), "LINEARRING");
293
0
}
294
295
/************************************************************************/
296
/*                            checkRing()                               */
297
/************************************************************************/
298
299
bool OGRPolygon::checkRing(const OGRCurve *poNewRing) const
300
0
{
301
0
    if (!isRingCorrectType(poNewRing))
302
0
    {
303
0
        CPLError(CE_Failure, CPLE_AppDefined,
304
0
                 "Wrong curve type. Expected LINEARRING.");
305
0
        return false;
306
0
    }
307
308
0
    if (!poNewRing->IsEmpty() && !poNewRing->get_IsClosed())
309
0
    {
310
        // This configuration option name must be the same as in
311
        // OGRCurvePolygon::checkRing()
312
0
        const char *pszEnvVar =
313
0
            CPLGetConfigOption("OGR_GEOMETRY_ACCEPT_UNCLOSED_RING", nullptr);
314
0
        if (pszEnvVar != nullptr && !CPLTestBool(pszEnvVar))
315
0
        {
316
0
            CPLError(CE_Failure, CPLE_AppDefined, "Non closed ring detected.");
317
0
            return false;
318
0
        }
319
0
        else
320
0
        {
321
0
            CPLError(CE_Warning, CPLE_AppDefined, "Non closed ring detected.%s",
322
0
                     pszEnvVar == nullptr
323
0
                         ? " To avoid accepting it, set the "
324
0
                           "OGR_GEOMETRY_ACCEPT_UNCLOSED_RING configuration "
325
0
                           "option to NO"
326
0
                         : "");
327
0
        }
328
0
    }
329
330
0
    return true;
331
0
}
332
333
/*! @endcond */
334
335
/************************************************************************/
336
/*                              WkbSize()                               */
337
/*                                                                      */
338
/*      Return the size of this object in well known binary             */
339
/*      representation including the byte order, and type information.  */
340
/************************************************************************/
341
342
size_t OGRPolygon::WkbSize() const
343
344
0
{
345
0
    size_t nSize = 9;
346
347
0
    for (auto &&poRing : *this)
348
0
    {
349
0
        nSize += poRing->_WkbSize(flags);
350
0
    }
351
352
0
    return nSize;
353
0
}
354
355
/************************************************************************/
356
/*                           importFromWkb()                            */
357
/*                                                                      */
358
/*      Initialize from serialized stream in well known binary          */
359
/*      format.                                                         */
360
/************************************************************************/
361
362
OGRErr OGRPolygon::importFromWkb(const unsigned char *pabyData, size_t nSize,
363
                                 OGRwkbVariant eWkbVariant,
364
                                 size_t &nBytesConsumedOut)
365
366
0
{
367
0
    OGRwkbByteOrder eByteOrder = wkbNDR;
368
0
    size_t nDataOffset = 0;
369
370
0
    if (oCC.nCurveCount == 1 && flags == 0 && nSize >= 9 &&
371
0
        pabyData[0] == wkbNDR &&
372
0
        memcmp(pabyData + 1, "\x03\x00\x00\x00\x01\x00\x00\x00", 8) == 0)
373
0
    {
374
        // Optimization to import a Intel-ordered 1-ring polygon on
375
        // top of an existing 1-ring polygon, to save dynamic memory
376
        // allocations.
377
0
        size_t nBytesConsumedRing = 0;
378
0
        nDataOffset = 9;
379
        // cppcheck-suppress knownConditionTrueFalse
380
0
        if (nSize != static_cast<size_t>(-1))
381
0
            nSize -= nDataOffset;
382
0
        OGRErr eErr =
383
0
            cpl::down_cast<OGRLinearRing *>(oCC.papoCurves[0])
384
0
                ->_importFromWkb(eByteOrder, flags, pabyData + nDataOffset,
385
0
                                 nSize, nBytesConsumedRing);
386
0
        if (eErr == OGRERR_NONE)
387
0
        {
388
0
            nBytesConsumedOut = nDataOffset + nBytesConsumedRing;
389
0
        }
390
0
        else
391
0
        {
392
0
            empty();
393
0
        }
394
395
0
        return eErr;
396
0
    }
397
398
0
    nBytesConsumedOut = 0;
399
400
    // coverity[tainted_data]
401
0
    OGRErr eErr = oCC.importPreambleFromWkb(this, pabyData, nSize, nDataOffset,
402
0
                                            eByteOrder, 4, eWkbVariant);
403
0
    if (eErr != OGRERR_NONE)
404
0
        return eErr;
405
406
    /* -------------------------------------------------------------------- */
407
    /*      Get the rings.                                                  */
408
    /* -------------------------------------------------------------------- */
409
0
    for (int iRing = 0; iRing < oCC.nCurveCount; iRing++)
410
0
    {
411
0
        OGRLinearRing *poLR = new OGRLinearRing();
412
0
        oCC.papoCurves[iRing] = poLR;
413
0
        size_t nBytesConsumedRing = 0;
414
0
        eErr = poLR->_importFromWkb(eByteOrder, flags, pabyData + nDataOffset,
415
0
                                    nSize, nBytesConsumedRing);
416
0
        if (eErr != OGRERR_NONE)
417
0
        {
418
0
            delete oCC.papoCurves[iRing];
419
0
            oCC.nCurveCount = iRing;
420
0
            return eErr;
421
0
        }
422
423
0
        CPLAssert(nBytesConsumedRing > 0);
424
0
        if (nSize != static_cast<size_t>(-1))
425
0
        {
426
0
            CPLAssert(nSize >= nBytesConsumedRing);
427
0
            nSize -= nBytesConsumedRing;
428
0
        }
429
430
0
        nDataOffset += nBytesConsumedRing;
431
0
    }
432
0
    nBytesConsumedOut = nDataOffset;
433
434
0
    return OGRERR_NONE;
435
0
}
436
437
/************************************************************************/
438
/*                            exportToWkb()                             */
439
/*                                                                      */
440
/*      Build a well known binary representation of this object.        */
441
/************************************************************************/
442
443
OGRErr OGRPolygon::exportToWkb(unsigned char *pabyData,
444
                               const OGRwkbExportOptions *psOptions) const
445
446
0
{
447
0
    if (psOptions == nullptr)
448
0
    {
449
0
        static const OGRwkbExportOptions defaultOptions;
450
0
        psOptions = &defaultOptions;
451
0
    }
452
453
    /* -------------------------------------------------------------------- */
454
    /*      Set the byte order.                                             */
455
    /* -------------------------------------------------------------------- */
456
0
    pabyData[0] = DB2_V72_UNFIX_BYTE_ORDER(
457
0
        static_cast<unsigned char>(psOptions->eByteOrder));
458
459
    /* -------------------------------------------------------------------- */
460
    /*      Set the geometry feature type.                                  */
461
    /* -------------------------------------------------------------------- */
462
0
    GUInt32 nGType = getGeometryType();
463
464
0
    if (psOptions->eWkbVariant == wkbVariantPostGIS1)
465
0
    {
466
0
        nGType = wkbFlatten(nGType);
467
0
        if (Is3D())
468
            // Explicitly set wkb25DBit.
469
0
            nGType =
470
0
                static_cast<OGRwkbGeometryType>(nGType | wkb25DBitInternalUse);
471
0
        if (IsMeasured())
472
0
            nGType = static_cast<OGRwkbGeometryType>(nGType | 0x40000000);
473
0
    }
474
0
    else if (psOptions->eWkbVariant == wkbVariantIso)
475
0
        nGType = getIsoGeometryType();
476
477
0
    if (OGR_SWAP(psOptions->eByteOrder))
478
0
    {
479
0
        nGType = CPL_SWAP32(nGType);
480
0
    }
481
482
0
    memcpy(pabyData + 1, &nGType, 4);
483
484
    /* -------------------------------------------------------------------- */
485
    /*      Copy in the raw data.                                           */
486
    /* -------------------------------------------------------------------- */
487
0
    if (OGR_SWAP(psOptions->eByteOrder))
488
0
    {
489
0
        const int nCount = CPL_SWAP32(oCC.nCurveCount);
490
0
        memcpy(pabyData + 5, &nCount, 4);
491
0
    }
492
0
    else
493
0
    {
494
0
        memcpy(pabyData + 5, &oCC.nCurveCount, 4);
495
0
    }
496
497
    /* ==================================================================== */
498
    /*      Serialize each of the rings.                                    */
499
    /* ==================================================================== */
500
0
    size_t nOffset = 9;
501
502
0
    for (auto &&poRing : *this)
503
0
    {
504
0
        poRing->_exportToWkb(flags, pabyData + nOffset, psOptions);
505
506
0
        nOffset += poRing->_WkbSize(flags);
507
0
    }
508
509
0
    return OGRERR_NONE;
510
0
}
511
512
/************************************************************************/
513
/*                           importFromWkt()                            */
514
/*                                                                      */
515
/*      Instantiate from well known text format.  Currently this is     */
516
/*      `POLYGON ((x y, x y, ...),(x y, ...),...)'.                     */
517
/************************************************************************/
518
519
OGRErr OGRPolygon::importFromWkt(const char **ppszInput)
520
521
638
{
522
638
    int bHasZ = FALSE;
523
638
    int bHasM = FALSE;
524
638
    bool bIsEmpty = false;
525
638
    OGRErr eErr = importPreambleFromWkt(ppszInput, &bHasZ, &bHasM, &bIsEmpty);
526
638
    flags = 0;
527
638
    if (eErr != OGRERR_NONE)
528
2
        return eErr;
529
636
    if (bHasZ)
530
380
        flags |= OGR_G_3D;
531
636
    if (bHasM)
532
121
        flags |= OGR_G_MEASURED;
533
636
    if (bIsEmpty)
534
0
        return OGRERR_NONE;
535
536
636
    OGRRawPoint *paoPoints = nullptr;
537
636
    int nMaxPoints = 0;
538
636
    double *padfZ = nullptr;
539
540
636
    eErr = importFromWKTListOnly(ppszInput, bHasZ, bHasM, paoPoints, nMaxPoints,
541
636
                                 padfZ);
542
543
636
    CPLFree(paoPoints);
544
636
    CPLFree(padfZ);
545
546
636
    return eErr;
547
636
}
548
549
/*! @cond Doxygen_Suppress */
550
/************************************************************************/
551
/*                        importFromWKTListOnly()                       */
552
/*                                                                      */
553
/*      Instantiate from "((x y, x y, ...),(x y, ...),...)"             */
554
/************************************************************************/
555
556
OGRErr OGRPolygon::importFromWKTListOnly(const char **ppszInput, int bHasZ,
557
                                         int bHasM, OGRRawPoint *&paoPoints,
558
                                         int &nMaxPoints, double *&padfZ)
559
560
2.20k
{
561
2.20k
    char szToken[OGR_WKT_TOKEN_MAX] = {};
562
2.20k
    const char *pszInput = *ppszInput;
563
564
    // Skip first '('.
565
2.20k
    pszInput = OGRWktReadToken(pszInput, szToken);
566
2.20k
    if (EQUAL(szToken, "EMPTY"))
567
0
    {
568
0
        *ppszInput = pszInput;
569
0
        return OGRERR_NONE;
570
0
    }
571
2.20k
    if (!EQUAL(szToken, "("))
572
0
        return OGRERR_CORRUPT_DATA;
573
574
    /* ==================================================================== */
575
    /*      Read each ring in turn.  Note that we try to reuse the same     */
576
    /*      point list buffer from ring to ring to cut down on              */
577
    /*      allocate/deallocate overhead.                                   */
578
    /* ==================================================================== */
579
2.20k
    int nMaxRings = 0;
580
2.20k
    double *padfM = nullptr;
581
582
2.20k
    do
583
2.75k
    {
584
2.75k
        const char *pszNext = OGRWktReadToken(pszInput, szToken);
585
2.75k
        if (EQUAL(szToken, "EMPTY"))
586
9
        {
587
            /* --------------------------------------------------------------------
588
             */
589
            /*      Do we need to grow the ring array? */
590
            /* --------------------------------------------------------------------
591
             */
592
9
            if (oCC.nCurveCount == nMaxRings)
593
8
            {
594
8
                nMaxRings = nMaxRings * 2 + 1;
595
8
                oCC.papoCurves = static_cast<OGRCurve **>(CPLRealloc(
596
8
                    oCC.papoCurves, nMaxRings * sizeof(OGRLinearRing *)));
597
8
            }
598
9
            oCC.papoCurves[oCC.nCurveCount] = new OGRLinearRing();
599
9
            oCC.nCurveCount++;
600
601
9
            pszInput = OGRWktReadToken(pszNext, szToken);
602
9
            if (!EQUAL(szToken, ","))
603
1
                break;
604
605
8
            continue;
606
9
        }
607
608
        /* --------------------------------------------------------------------
609
         */
610
        /*      Read points for one ring from input. */
611
        /* --------------------------------------------------------------------
612
         */
613
2.74k
        int nPoints = 0;
614
2.74k
        int flagsFromInput = flags;
615
2.74k
        if (flagsFromInput == 0)
616
1.73k
        {
617
            // Flags was not set, this is not called by us.
618
1.73k
            if (bHasM)
619
345
                flagsFromInput |= OGR_G_MEASURED;
620
1.73k
            if (bHasZ)
621
181
                flagsFromInput |= OGR_G_3D;
622
1.73k
        }
623
624
2.74k
        pszInput = OGRWktReadPointsM(pszInput, &paoPoints, &padfZ, &padfM,
625
2.74k
                                     &flagsFromInput, &nMaxPoints, &nPoints);
626
2.74k
        if (pszInput == nullptr || nPoints == 0)
627
138
        {
628
138
            CPLFree(padfM);
629
138
            return OGRERR_CORRUPT_DATA;
630
138
        }
631
2.61k
        if ((flagsFromInput & OGR_G_3D) && !(flags & OGR_G_3D))
632
734
        {
633
734
            flags |= OGR_G_3D;
634
734
            bHasZ = TRUE;
635
734
        }
636
2.61k
        if ((flagsFromInput & OGR_G_MEASURED) && !(flags & OGR_G_MEASURED))
637
678
        {
638
678
            flags |= OGR_G_MEASURED;
639
678
            bHasM = TRUE;
640
678
        }
641
642
        /* --------------------------------------------------------------------
643
         */
644
        /*      Do we need to grow the ring array? */
645
        /* --------------------------------------------------------------------
646
         */
647
2.61k
        if (oCC.nCurveCount == nMaxRings)
648
2.19k
        {
649
2.19k
            nMaxRings = nMaxRings * 2 + 1;
650
2.19k
            oCC.papoCurves = static_cast<OGRCurve **>(CPLRealloc(
651
2.19k
                oCC.papoCurves, nMaxRings * sizeof(OGRLinearRing *)));
652
2.19k
        }
653
654
        /* --------------------------------------------------------------------
655
         */
656
        /*      Create the new ring, and assign to ring list. */
657
        /* --------------------------------------------------------------------
658
         */
659
2.61k
        OGRLinearRing *poLR = new OGRLinearRing();
660
2.61k
        oCC.papoCurves[oCC.nCurveCount] = poLR;
661
662
2.61k
        if (bHasM && bHasZ)
663
505
            poLR->setPoints(nPoints, paoPoints, padfZ, padfM);
664
2.10k
        else if (bHasM)
665
360
            poLR->setPointsM(nPoints, paoPoints, padfM);
666
1.74k
        else if (bHasZ)
667
1.10k
            poLR->setPoints(nPoints, paoPoints, padfZ);
668
643
        else
669
643
            poLR->setPoints(nPoints, paoPoints);
670
671
2.61k
        oCC.nCurveCount++;
672
673
        /* --------------------------------------------------------------------
674
         */
675
        /*      Read the delimiter following the ring. */
676
        /* --------------------------------------------------------------------
677
         */
678
679
2.61k
        pszInput = OGRWktReadToken(pszInput, szToken);
680
2.61k
    } while (szToken[0] == ',');
681
682
2.06k
    CPLFree(padfM);
683
684
    /* -------------------------------------------------------------------- */
685
    /*      freak if we don't get a closing bracket.                        */
686
    /* -------------------------------------------------------------------- */
687
688
2.06k
    if (szToken[0] != ')')
689
8
        return OGRERR_CORRUPT_DATA;
690
691
2.06k
    *ppszInput = pszInput;
692
2.06k
    return OGRERR_NONE;
693
2.06k
}
694
695
/*! @endcond */
696
697
/************************************************************************/
698
/*                            exportToWkt()                             */
699
/*                                                                      */
700
/*      Translate this structure into its well known text format        */
701
/*      equivalent.  This could be made a lot more CPU efficient.       */
702
/************************************************************************/
703
704
std::string OGRPolygon::exportToWkt(const OGRWktOptions &opts,
705
                                    OGRErr *err) const
706
0
{
707
0
    std::string wkt;
708
    /* -------------------------------------------------------------------- */
709
    /*      If we have no valid exterior ring, return POLYGON EMPTY.        */
710
    /* -------------------------------------------------------------------- */
711
0
    wkt = getGeometryName();
712
0
    wkt += wktTypeString(opts.variant);
713
0
    if (getExteriorRing() == nullptr || getExteriorRing()->IsEmpty())
714
0
        wkt += "EMPTY";
715
716
    /* -------------------------------------------------------------------- */
717
    /*      Build a list of strings containing the stuff for each ring.     */
718
    /* -------------------------------------------------------------------- */
719
720
0
    else
721
0
    {
722
0
        try
723
0
        {
724
0
            bool first(true);
725
0
            wkt += '(';
726
0
            for (int iRing = 0; iRing < oCC.nCurveCount; iRing++)
727
0
            {
728
0
                OGRLinearRing *poLR = oCC.papoCurves[iRing]->toLinearRing();
729
0
                if (poLR->getNumPoints())
730
0
                {
731
0
                    if (!first)
732
0
                        wkt += ',';
733
0
                    first = false;
734
0
                    OGRErr subgeomErr = OGRERR_NONE;
735
0
                    std::string tempWkt = poLR->exportToWkt(opts, &subgeomErr);
736
0
                    if (subgeomErr != OGRERR_NONE)
737
0
                    {
738
0
                        if (err)
739
0
                            *err = subgeomErr;
740
0
                        return std::string();
741
0
                    }
742
743
                    // Remove leading "LINEARRING..."
744
0
                    wkt += tempWkt.substr(tempWkt.find_first_of('('));
745
0
                }
746
0
            }
747
0
            wkt += ')';
748
0
        }
749
0
        catch (const std::bad_alloc &e)
750
0
        {
751
0
            CPLError(CE_Failure, CPLE_OutOfMemory, "%s", e.what());
752
0
            if (err)
753
0
                *err = OGRERR_FAILURE;
754
0
            return std::string();
755
0
        }
756
0
    }
757
758
0
    if (err)
759
0
        *err = OGRERR_NONE;
760
0
    return wkt;
761
0
}
762
763
/************************************************************************/
764
/*                           IsPointOnSurface()                           */
765
/************************************************************************/
766
767
/** Return whether the point is on the surface.
768
 * @return TRUE or FALSE
769
 */
770
OGRBoolean OGRPolygon::IsPointOnSurface(const OGRPoint *pt) const
771
0
{
772
0
    if (nullptr == pt)
773
0
        return FALSE;
774
775
0
    bool bOnSurface = false;
776
    // The point must be in the outer ring, but not in the inner rings
777
0
    int iRing = 0;
778
0
    for (auto &&poRing : *this)
779
0
    {
780
0
        if (poRing->isPointInRing(pt))
781
0
        {
782
0
            if (iRing == 0)
783
0
            {
784
0
                bOnSurface = true;
785
0
            }
786
0
            else
787
0
            {
788
0
                return false;
789
0
            }
790
0
        }
791
0
        else
792
0
        {
793
0
            if (iRing == 0)
794
0
            {
795
0
                return false;
796
0
            }
797
0
        }
798
0
        iRing++;
799
0
    }
800
801
0
    return bOnSurface;
802
0
}
803
804
/************************************************************************/
805
/*                             closeRings()                             */
806
/************************************************************************/
807
808
void OGRPolygon::closeRings()
809
810
0
{
811
0
    for (auto &&poRing : *this)
812
0
        poRing->closeRings();
813
0
}
814
815
/************************************************************************/
816
/*                           CurvePolyToPoly()                          */
817
/************************************************************************/
818
819
OGRPolygon *
820
OGRPolygon::CurvePolyToPoly(CPL_UNUSED double dfMaxAngleStepSizeDegrees,
821
                            CPL_UNUSED const char *const *papszOptions) const
822
0
{
823
0
    return clone();
824
0
}
825
826
/************************************************************************/
827
/*                         hasCurveGeometry()                           */
828
/************************************************************************/
829
830
OGRBoolean OGRPolygon::hasCurveGeometry(CPL_UNUSED int bLookForNonLinear) const
831
589
{
832
589
    return FALSE;
833
589
}
834
835
/************************************************************************/
836
/*                         getLinearGeometry()                        */
837
/************************************************************************/
838
839
OGRGeometry *
840
OGRPolygon::getLinearGeometry(double dfMaxAngleStepSizeDegrees,
841
                              const char *const *papszOptions) const
842
0
{
843
0
    return OGRGeometry::getLinearGeometry(dfMaxAngleStepSizeDegrees,
844
0
                                          papszOptions);
845
0
}
846
847
/************************************************************************/
848
/*                             getCurveGeometry()                       */
849
/************************************************************************/
850
851
OGRGeometry *OGRPolygon::getCurveGeometry(const char *const *papszOptions) const
852
0
{
853
0
    OGRCurvePolygon *poCC = new OGRCurvePolygon();
854
0
    poCC->assignSpatialReference(getSpatialReference());
855
0
    bool bHasCurveGeometry = false;
856
0
    for (auto &&poRing : *this)
857
0
    {
858
0
        auto poSubGeom = poRing->getCurveGeometry(papszOptions);
859
0
        if (wkbFlatten(poSubGeom->getGeometryType()) != wkbLineString)
860
0
            bHasCurveGeometry = true;
861
0
        poCC->addRingDirectly(poSubGeom->toCurve());
862
0
    }
863
0
    if (!bHasCurveGeometry)
864
0
    {
865
0
        delete poCC;
866
0
        return clone();
867
0
    }
868
0
    return poCC;
869
0
}
870
871
/*! @cond Doxygen_Suppress */
872
/************************************************************************/
873
/*                        CastToCurvePolygon()                          */
874
/************************************************************************/
875
876
/**
877
 * \brief Cast to curve polygon.
878
 *
879
 * The passed in geometry is consumed and a new one returned .
880
 *
881
 * @param poPoly the input geometry - ownership is passed to the method.
882
 * @return new geometry.
883
 */
884
885
OGRCurvePolygon *OGRPolygon::CastToCurvePolygon(OGRPolygon *poPoly)
886
0
{
887
0
    OGRCurvePolygon *poCP = new OGRCurvePolygon();
888
0
    poCP->set3D(poPoly->Is3D());
889
0
    poCP->setMeasured(poPoly->IsMeasured());
890
0
    poCP->assignSpatialReference(poPoly->getSpatialReference());
891
0
    poCP->oCC.nCurveCount = poPoly->oCC.nCurveCount;
892
0
    poCP->oCC.papoCurves = poPoly->oCC.papoCurves;
893
0
    poPoly->oCC.nCurveCount = 0;
894
0
    poPoly->oCC.papoCurves = nullptr;
895
896
0
    for (auto &&poRing : *poCP)
897
0
    {
898
0
        poRing = OGRLinearRing::CastToLineString(poRing->toLinearRing());
899
0
    }
900
901
0
    delete poPoly;
902
0
    return poCP;
903
0
}
904
905
/************************************************************************/
906
/*                      GetCasterToPolygon()                            */
907
/************************************************************************/
908
909
static OGRPolygon *CasterToPolygon(OGRSurface *poSurface)
910
0
{
911
0
    return poSurface->toPolygon();
912
0
}
913
914
OGRSurfaceCasterToPolygon OGRPolygon::GetCasterToPolygon() const
915
0
{
916
0
    return ::CasterToPolygon;
917
0
}
918
919
/************************************************************************/
920
/*                      OGRSurfaceCasterToCurvePolygon()                */
921
/************************************************************************/
922
923
OGRCurvePolygon *OGRPolygon::CasterToCurvePolygon(OGRSurface *poSurface)
924
0
{
925
0
    return OGRPolygon::CastToCurvePolygon(poSurface->toPolygon());
926
0
}
927
928
OGRSurfaceCasterToCurvePolygon OGRPolygon::GetCasterToCurvePolygon() const
929
0
{
930
0
    return OGRPolygon::CasterToCurvePolygon;
931
0
}
932
933
/*! @endcond */