Coverage Report

Created: 2025-12-03 08:24

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
3
{
42
3
    auto poLR = std::make_unique<OGRLinearRing>();
43
3
    poLR->addPoint(x1, y1);
44
3
    poLR->addPoint(x1, y2);
45
3
    poLR->addPoint(x2, y2);
46
3
    poLR->addPoint(x2, y1);
47
3
    poLR->addPoint(x1, y1);
48
3
    addRingDirectly(poLR.release());
49
3
}
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
5.55M
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
5.54M
{
101
5.54M
    auto ret = new (std::nothrow) OGRPolygon(*this);
102
5.54M
    if (ret)
103
5.54M
    {
104
5.54M
        if (ret->WkbSize() != WkbSize())
105
0
        {
106
0
            delete ret;
107
0
            ret = nullptr;
108
0
        }
109
5.54M
    }
110
5.54M
    return ret;
111
5.54M
}
112
113
/************************************************************************/
114
/*                          getGeometryType()                           */
115
/************************************************************************/
116
117
OGRwkbGeometryType OGRPolygon::getGeometryType() const
118
119
25.8M
{
120
25.8M
    if ((flags & OGR_G_3D) && (flags & OGR_G_MEASURED))
121
302k
        return wkbPolygonZM;
122
25.5M
    else if (flags & OGR_G_MEASURED)
123
42.8k
        return wkbPolygonM;
124
25.4M
    else if (flags & OGR_G_3D)
125
21.9M
        return wkbPolygon25D;
126
3.54M
    else
127
3.54M
        return wkbPolygon;
128
25.8M
}
129
130
/************************************************************************/
131
/*                          getGeometryName()                           */
132
/************************************************************************/
133
134
const char *OGRPolygon::getGeometryName() const
135
136
121k
{
137
121k
    return "POLYGON";
138
121k
}
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
38.4k
{
161
38.4k
    if (oCC.nCurveCount > 0)
162
36.3k
        return oCC.papoCurves[0]->toLinearRing();
163
164
2.09k
    return nullptr;
165
38.4k
}
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
153k
{
184
153k
    if (oCC.nCurveCount > 0)
185
101k
        return oCC.papoCurves[0]->toLinearRing();
186
187
52.3k
    return nullptr;
188
153k
}
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
1.14M
{
231
1.14M
    if (iRing < 0 || iRing >= oCC.nCurveCount - 1)
232
0
        return nullptr;
233
234
1.14M
    return oCC.papoCurves[iRing + 1]->toLinearRing();
235
1.14M
}
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
1.34M
{
256
1.34M
    if (iRing < 0 || iRing >= oCC.nCurveCount - 1)
257
0
        return nullptr;
258
259
1.34M
    return oCC.papoCurves[iRing + 1]->toLinearRing();
260
1.34M
}
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
1.62M
{
292
1.62M
    return poRing != nullptr && EQUAL(poRing->getGeometryName(), "LINEARRING");
293
1.62M
}
294
295
/************************************************************************/
296
/*                            checkRing()                               */
297
/************************************************************************/
298
299
bool OGRPolygon::checkRing(const OGRCurve *poNewRing) const
300
1.62M
{
301
1.62M
    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
1.62M
    if (!poNewRing->IsEmpty() && !poNewRing->get_IsClosed())
309
295k
    {
310
        // This configuration option name must be the same as in
311
        // OGRCurvePolygon::checkRing()
312
295k
        const char *pszEnvVar =
313
295k
            CPLGetConfigOption("OGR_GEOMETRY_ACCEPT_UNCLOSED_RING", nullptr);
314
295k
        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
295k
        else
320
295k
        {
321
295k
            CPLError(CE_Warning, CPLE_AppDefined, "Non closed ring detected.%s",
322
295k
                     pszEnvVar == nullptr
323
295k
                         ? " To avoid accepting it, set the "
324
295k
                           "OGR_GEOMETRY_ACCEPT_UNCLOSED_RING configuration "
325
295k
                           "option to NO"
326
295k
                         : "");
327
295k
        }
328
295k
    }
329
330
1.62M
    return true;
331
1.62M
}
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
12.3M
{
345
12.3M
    size_t nSize = 9;
346
347
12.3M
    for (auto &&poRing : *this)
348
14.7M
    {
349
14.7M
        nSize += poRing->_WkbSize(flags);
350
14.7M
    }
351
352
12.3M
    return nSize;
353
12.3M
}
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
114k
{
367
114k
    OGRwkbByteOrder eByteOrder = wkbNDR;
368
114k
    size_t nDataOffset = 0;
369
370
114k
    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
114k
    nBytesConsumedOut = 0;
399
400
    // coverity[tainted_data]
401
114k
    OGRErr eErr = oCC.importPreambleFromWkb(this, pabyData, nSize, nDataOffset,
402
114k
                                            eByteOrder, 4, eWkbVariant);
403
114k
    if (eErr != OGRERR_NONE)
404
9.93k
        return eErr;
405
406
    /* -------------------------------------------------------------------- */
407
    /*      Get the rings.                                                  */
408
    /* -------------------------------------------------------------------- */
409
1.64M
    for (int iRing = 0; iRing < oCC.nCurveCount; iRing++)
410
1.55M
    {
411
1.55M
        OGRLinearRing *poLR = new OGRLinearRing();
412
1.55M
        oCC.papoCurves[iRing] = poLR;
413
1.55M
        size_t nBytesConsumedRing = 0;
414
1.55M
        eErr = poLR->_importFromWkb(eByteOrder, flags, pabyData + nDataOffset,
415
1.55M
                                    nSize, nBytesConsumedRing);
416
1.55M
        if (eErr != OGRERR_NONE)
417
15.1k
        {
418
15.1k
            delete oCC.papoCurves[iRing];
419
15.1k
            oCC.nCurveCount = iRing;
420
15.1k
            return eErr;
421
15.1k
        }
422
423
1.53M
        CPLAssert(nBytesConsumedRing > 0);
424
1.53M
        if (nSize != static_cast<size_t>(-1))
425
1.53M
        {
426
1.53M
            CPLAssert(nSize >= nBytesConsumedRing);
427
1.53M
            nSize -= nBytesConsumedRing;
428
1.53M
        }
429
430
1.53M
        nDataOffset += nBytesConsumedRing;
431
1.53M
    }
432
89.8k
    nBytesConsumedOut = nDataOffset;
433
434
89.8k
    return OGRERR_NONE;
435
105k
}
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
75.7k
{
447
75.7k
    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
75.7k
    pabyData[0] = DB2_V72_UNFIX_BYTE_ORDER(
457
75.7k
        static_cast<unsigned char>(psOptions->eByteOrder));
458
459
    /* -------------------------------------------------------------------- */
460
    /*      Set the geometry feature type.                                  */
461
    /* -------------------------------------------------------------------- */
462
75.7k
    GUInt32 nGType = getGeometryType();
463
464
75.7k
    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
75.7k
    else if (psOptions->eWkbVariant == wkbVariantIso)
475
38.0k
        nGType = getIsoGeometryType();
476
477
75.7k
    if (OGR_SWAP(psOptions->eByteOrder))
478
0
    {
479
0
        nGType = CPL_SWAP32(nGType);
480
0
    }
481
482
75.7k
    memcpy(pabyData + 1, &nGType, 4);
483
484
    /* -------------------------------------------------------------------- */
485
    /*      Copy in the raw data.                                           */
486
    /* -------------------------------------------------------------------- */
487
75.7k
    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
75.7k
    else
493
75.7k
    {
494
75.7k
        memcpy(pabyData + 5, &oCC.nCurveCount, 4);
495
75.7k
    }
496
497
    /* ==================================================================== */
498
    /*      Serialize each of the rings.                                    */
499
    /* ==================================================================== */
500
75.7k
    size_t nOffset = 9;
501
502
75.7k
    for (auto &&poRing : *this)
503
2.76M
    {
504
2.76M
        poRing->_exportToWkb(flags, pabyData + nOffset, psOptions);
505
506
2.76M
        nOffset += poRing->_WkbSize(flags);
507
2.76M
    }
508
509
75.7k
    return OGRERR_NONE;
510
75.7k
}
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
51.1k
{
522
51.1k
    int bHasZ = FALSE;
523
51.1k
    int bHasM = FALSE;
524
51.1k
    bool bIsEmpty = false;
525
51.1k
    OGRErr eErr = importPreambleFromWkt(ppszInput, &bHasZ, &bHasM, &bIsEmpty);
526
51.1k
    flags = 0;
527
51.1k
    if (eErr != OGRERR_NONE)
528
4.71k
        return eErr;
529
46.4k
    if (bHasZ)
530
2.97k
        flags |= OGR_G_3D;
531
46.4k
    if (bHasM)
532
39.0k
        flags |= OGR_G_MEASURED;
533
46.4k
    if (bIsEmpty)
534
4.42k
        return OGRERR_NONE;
535
536
42.0k
    OGRRawPoint *paoPoints = nullptr;
537
42.0k
    int nMaxPoints = 0;
538
42.0k
    double *padfZ = nullptr;
539
540
42.0k
    eErr = importFromWKTListOnly(ppszInput, bHasZ, bHasM, paoPoints, nMaxPoints,
541
42.0k
                                 padfZ);
542
543
42.0k
    CPLFree(paoPoints);
544
42.0k
    CPLFree(padfZ);
545
546
42.0k
    return eErr;
547
46.4k
}
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
117k
{
561
117k
    char szToken[OGR_WKT_TOKEN_MAX] = {};
562
117k
    const char *pszInput = *ppszInput;
563
564
    // Skip first '('.
565
117k
    pszInput = OGRWktReadToken(pszInput, szToken);
566
117k
    if (EQUAL(szToken, "EMPTY"))
567
0
    {
568
0
        *ppszInput = pszInput;
569
0
        return OGRERR_NONE;
570
0
    }
571
117k
    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
117k
    int nMaxRings = 0;
580
117k
    double *padfM = nullptr;
581
582
117k
    do
583
267k
    {
584
267k
        const char *pszNext = OGRWktReadToken(pszInput, szToken);
585
267k
        if (EQUAL(szToken, "EMPTY"))
586
27.2k
        {
587
            /* --------------------------------------------------------------------
588
             */
589
            /*      Do we need to grow the ring array? */
590
            /* --------------------------------------------------------------------
591
             */
592
27.2k
            if (oCC.nCurveCount == nMaxRings)
593
7.92k
            {
594
7.92k
                nMaxRings = nMaxRings * 2 + 1;
595
7.92k
                oCC.papoCurves = static_cast<OGRCurve **>(CPLRealloc(
596
7.92k
                    oCC.papoCurves, nMaxRings * sizeof(OGRLinearRing *)));
597
7.92k
            }
598
27.2k
            oCC.papoCurves[oCC.nCurveCount] = new OGRLinearRing();
599
27.2k
            oCC.nCurveCount++;
600
601
27.2k
            pszInput = OGRWktReadToken(pszNext, szToken);
602
27.2k
            if (!EQUAL(szToken, ","))
603
5.28k
                break;
604
605
21.9k
            continue;
606
27.2k
        }
607
608
        /* --------------------------------------------------------------------
609
         */
610
        /*      Read points for one ring from input. */
611
        /* --------------------------------------------------------------------
612
         */
613
240k
        int nPoints = 0;
614
240k
        int flagsFromInput = flags;
615
240k
        if (flagsFromInput == 0)
616
87.3k
        {
617
            // Flags was not set, this is not called by us.
618
87.3k
            if (bHasM)
619
11.8k
                flagsFromInput |= OGR_G_MEASURED;
620
87.3k
            if (bHasZ)
621
9.26k
                flagsFromInput |= OGR_G_3D;
622
87.3k
        }
623
624
240k
        pszInput = OGRWktReadPointsM(pszInput, &paoPoints, &padfZ, &padfM,
625
240k
                                     &flagsFromInput, &nMaxPoints, &nPoints);
626
240k
        if (pszInput == nullptr || nPoints == 0)
627
83.7k
        {
628
83.7k
            CPLFree(padfM);
629
83.7k
            return OGRERR_CORRUPT_DATA;
630
83.7k
        }
631
156k
        if ((flagsFromInput & OGR_G_3D) && !(flags & OGR_G_3D))
632
21.6k
        {
633
21.6k
            flags |= OGR_G_3D;
634
21.6k
            bHasZ = TRUE;
635
21.6k
        }
636
156k
        if ((flagsFromInput & OGR_G_MEASURED) && !(flags & OGR_G_MEASURED))
637
9.35k
        {
638
9.35k
            flags |= OGR_G_MEASURED;
639
9.35k
            bHasM = TRUE;
640
9.35k
        }
641
642
        /* --------------------------------------------------------------------
643
         */
644
        /*      Do we need to grow the ring array? */
645
        /* --------------------------------------------------------------------
646
         */
647
156k
        if (oCC.nCurveCount == nMaxRings)
648
55.5k
        {
649
55.5k
            nMaxRings = nMaxRings * 2 + 1;
650
55.5k
            oCC.papoCurves = static_cast<OGRCurve **>(CPLRealloc(
651
55.5k
                oCC.papoCurves, nMaxRings * sizeof(OGRLinearRing *)));
652
55.5k
        }
653
654
        /* --------------------------------------------------------------------
655
         */
656
        /*      Create the new ring, and assign to ring list. */
657
        /* --------------------------------------------------------------------
658
         */
659
156k
        OGRLinearRing *poLR = new OGRLinearRing();
660
156k
        oCC.papoCurves[oCC.nCurveCount] = poLR;
661
662
156k
        if (bHasM && bHasZ)
663
79.1k
            poLR->setPoints(nPoints, paoPoints, padfZ, padfM);
664
77.4k
        else if (bHasM)
665
12.6k
            poLR->setPointsM(nPoints, paoPoints, padfM);
666
64.8k
        else if (bHasZ)
667
39.8k
            poLR->setPoints(nPoints, paoPoints, padfZ);
668
24.9k
        else
669
24.9k
            poLR->setPoints(nPoints, paoPoints);
670
671
156k
        oCC.nCurveCount++;
672
673
        /* --------------------------------------------------------------------
674
         */
675
        /*      Read the delimiter following the ring. */
676
        /* --------------------------------------------------------------------
677
         */
678
679
156k
        pszInput = OGRWktReadToken(pszInput, szToken);
680
178k
    } while (szToken[0] == ',');
681
682
34.1k
    CPLFree(padfM);
683
684
    /* -------------------------------------------------------------------- */
685
    /*      freak if we don't get a closing bracket.                        */
686
    /* -------------------------------------------------------------------- */
687
688
34.1k
    if (szToken[0] != ')')
689
7.71k
        return OGRERR_CORRUPT_DATA;
690
691
26.4k
    *ppszInput = pszInput;
692
26.4k
    return OGRERR_NONE;
693
34.1k
}
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
77.7k
{
707
77.7k
    std::string wkt;
708
    /* -------------------------------------------------------------------- */
709
    /*      If we have no valid exterior ring, return POLYGON EMPTY.        */
710
    /* -------------------------------------------------------------------- */
711
77.7k
    wkt = getGeometryName();
712
77.7k
    wkt += wktTypeString(opts.variant);
713
77.7k
    if (getExteriorRing() == nullptr || getExteriorRing()->IsEmpty())
714
67.2k
        wkt += "EMPTY";
715
716
    /* -------------------------------------------------------------------- */
717
    /*      Build a list of strings containing the stuff for each ring.     */
718
    /* -------------------------------------------------------------------- */
719
720
10.4k
    else
721
10.4k
    {
722
10.4k
        try
723
10.4k
        {
724
10.4k
            bool first(true);
725
10.4k
            wkt += '(';
726
1.68M
            for (int iRing = 0; iRing < oCC.nCurveCount; iRing++)
727
1.67M
            {
728
1.67M
                OGRLinearRing *poLR = oCC.papoCurves[iRing]->toLinearRing();
729
1.67M
                if (poLR->getNumPoints())
730
16.5k
                {
731
16.5k
                    if (!first)
732
6.04k
                        wkt += ',';
733
16.5k
                    first = false;
734
16.5k
                    OGRErr subgeomErr = OGRERR_NONE;
735
16.5k
                    std::string tempWkt = poLR->exportToWkt(opts, &subgeomErr);
736
16.5k
                    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
16.5k
                    wkt += tempWkt.substr(tempWkt.find_first_of('('));
745
16.5k
                }
746
1.67M
            }
747
10.4k
            wkt += ')';
748
10.4k
        }
749
10.4k
        catch (const std::bad_alloc &e)
750
10.4k
        {
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
10.4k
    }
757
758
77.7k
    if (err)
759
77.7k
        *err = OGRERR_NONE;
760
77.7k
    return wkt;
761
77.7k
}
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
48.8k
{
811
48.8k
    for (auto &&poRing : *this)
812
49.0k
        poRing->closeRings();
813
48.8k
}
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
938k
{
832
938k
    return FALSE;
833
938k
}
834
835
/************************************************************************/
836
/*                         getLinearGeometry()                        */
837
/************************************************************************/
838
839
OGRGeometry *
840
OGRPolygon::getLinearGeometry(double dfMaxAngleStepSizeDegrees,
841
                              const char *const *papszOptions) const
842
23
{
843
23
    return OGRGeometry::getLinearGeometry(dfMaxAngleStepSizeDegrees,
844
23
                                          papszOptions);
845
23
}
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
4.36k
{
911
4.36k
    return poSurface->toPolygon();
912
4.36k
}
913
914
OGRSurfaceCasterToPolygon OGRPolygon::GetCasterToPolygon() const
915
4.36k
{
916
4.36k
    return ::CasterToPolygon;
917
4.36k
}
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 */