Coverage Report

Created: 2025-06-13 06:18

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