Coverage Report

Created: 2025-11-16 06:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/ogr/ogrcurvepolygon.cpp
Line
Count
Source
1
/******************************************************************************
2
 *
3
 * Project:  OpenGIS Simple Features Reference Implementation
4
 * Purpose:  The OGRCurvePolygon geometry class.
5
 * Author:   Even Rouault <even dot rouault at spatialys dot com>
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 2014, Even Rouault <even dot rouault at spatialys dot com>
9
 *
10
 * SPDX-License-Identifier: MIT
11
 ****************************************************************************/
12
13
#include "cpl_port.h"
14
#include "ogr_geometry.h"
15
16
#include <cstddef>
17
18
#include "cpl_error.h"
19
#include "ogr_api.h"
20
#include "ogr_core.h"
21
#include "ogr_geos.h"
22
#include "ogr_sfcgal.h"
23
#include "ogr_p.h"
24
#include "ogr_spatialref.h"
25
26
/************************************************************************/
27
/*               OGRCurvePolygon( const OGRCurvePolygon& )              */
28
/************************************************************************/
29
30
/**
31
 * \brief Copy constructor.
32
 */
33
34
0
OGRCurvePolygon::OGRCurvePolygon(const OGRCurvePolygon &) = default;
35
36
/************************************************************************/
37
/*                 operator=( const OGRCurvePolygon&)                  */
38
/************************************************************************/
39
40
/**
41
 * \brief Assignment operator.
42
 */
43
44
OGRCurvePolygon &OGRCurvePolygon::operator=(const OGRCurvePolygon &other)
45
0
{
46
0
    if (this != &other)
47
0
    {
48
0
        OGRSurface::operator=(other);
49
50
0
        for (const auto *poRing : other.oCC)
51
0
        {
52
0
            if (!isRingCorrectType(poRing))
53
0
            {
54
0
                CPLError(CE_Failure, CPLE_AppDefined,
55
0
                         "Illegal use of OGRCurvePolygon::operator=(): "
56
0
                         "trying to assign an incompatible sub-geometry");
57
0
                return *this;
58
0
            }
59
0
        }
60
61
0
        oCC = other.oCC;
62
0
    }
63
0
    return *this;
64
0
}
65
66
/************************************************************************/
67
/*                               clone()                                */
68
/************************************************************************/
69
70
OGRCurvePolygon *OGRCurvePolygon::clone() const
71
72
0
{
73
0
    return new (std::nothrow) OGRCurvePolygon(*this);
74
0
}
75
76
/************************************************************************/
77
/*                               empty()                                */
78
/************************************************************************/
79
80
void OGRCurvePolygon::empty()
81
82
745
{
83
745
    oCC.empty(this);
84
745
}
85
86
/************************************************************************/
87
/*                          getGeometryType()                           */
88
/************************************************************************/
89
90
OGRwkbGeometryType OGRCurvePolygon::getGeometryType() const
91
92
1
{
93
1
    if ((flags & OGR_G_3D) && (flags & OGR_G_MEASURED))
94
0
        return wkbCurvePolygonZM;
95
1
    else if (flags & OGR_G_MEASURED)
96
1
        return wkbCurvePolygonM;
97
0
    else if (flags & OGR_G_3D)
98
0
        return wkbCurvePolygonZ;
99
0
    else
100
0
        return wkbCurvePolygon;
101
1
}
102
103
/************************************************************************/
104
/*                            getDimension()                            */
105
/************************************************************************/
106
107
int OGRCurvePolygon::getDimension() const
108
109
0
{
110
0
    return 2;
111
0
}
112
113
/************************************************************************/
114
/*                            flattenTo2D()                             */
115
/************************************************************************/
116
117
void OGRCurvePolygon::flattenTo2D()
118
119
0
{
120
0
    oCC.flattenTo2D(this);
121
0
}
122
123
/************************************************************************/
124
/*                          getGeometryName()                           */
125
/************************************************************************/
126
127
const char *OGRCurvePolygon::getGeometryName() const
128
129
107
{
130
107
    return "CURVEPOLYGON";
131
107
}
132
133
/************************************************************************/
134
/*                         getExteriorRingCurve()                       */
135
/************************************************************************/
136
137
/**
138
 * \brief Fetch reference to external polygon ring.
139
 *
140
 * Note that the returned ring pointer is to an internal data object of the
141
 * OGRCurvePolygon.  It should not be modified or deleted by the application,
142
 * and the pointer is only valid till the polygon is next modified.  Use the
143
 * OGRGeometry::clone() method to make a separate copy within the application.
144
 *
145
 * Relates to the Simple Features for COM (SFCOM) IPolygon::get_ExteriorRing()
146
 * method.
147
 * TODO(rouault): What does that mean?
148
 *
149
 * @return pointer to external ring.  May be NULL if the OGRCurvePolygon is
150
 * empty.
151
 */
152
153
OGRCurve *OGRCurvePolygon::getExteriorRingCurve()
154
155
6.22k
{
156
6.22k
    return oCC.getCurve(0);
157
6.22k
}
158
159
/**
160
 * \brief Fetch reference to external polygon ring.
161
 *
162
 * Note that the returned ring pointer is to an internal data object of the
163
 * OGRCurvePolygon.  It should not be modified or deleted by the application,
164
 * and the pointer is only valid till the polygon is next modified.  Use the
165
 * OGRGeometry::clone() method to make a separate copy within the application.
166
 *
167
 * Relates to the SFCOM IPolygon::get_ExteriorRing() method.
168
 *
169
 * @return pointer to external ring.  May be NULL if the OGRCurvePolygon is
170
 * empty.
171
 */
172
const OGRCurve *OGRCurvePolygon::getExteriorRingCurve() const
173
174
0
{
175
0
    return oCC.getCurve(0);
176
0
}
177
178
/************************************************************************/
179
/*                        getNumInteriorRings()                         */
180
/************************************************************************/
181
182
/**
183
 * \brief Fetch the number of internal rings.
184
 *
185
 * Relates to the SFCOM IPolygon::get_NumInteriorRings() method.
186
 *
187
 * @return count of internal rings, zero or more.
188
 */
189
190
int OGRCurvePolygon::getNumInteriorRings() const
191
192
4.23k
{
193
4.23k
    if (oCC.nCurveCount > 0)
194
4.23k
        return oCC.nCurveCount - 1;
195
0
    else
196
0
        return 0;
197
4.23k
}
198
199
/************************************************************************/
200
/*                       getInteriorRingCurve()                         */
201
/************************************************************************/
202
203
/**
204
 * \brief Fetch reference to indicated internal ring.
205
 *
206
 * Note that the returned ring pointer is to an internal data object of the
207
 * OGRCurvePolygon.  It should not be modified or deleted by the application,
208
 * and the pointer is only valid till the polygon is next modified.  Use the
209
 * OGRGeometry::clone() method to make a separate copy within the application.
210
 *
211
 * Relates to the SFCOM IPolygon::get_InternalRing() method.
212
 *
213
 * @param iRing internal ring index from 0 to getNumInteriorRings() - 1.
214
 *
215
 * @return pointer to interior ring.  May be NULL.
216
 */
217
218
OGRCurve *OGRCurvePolygon::getInteriorRingCurve(int iRing)
219
220
307
{
221
307
    return oCC.getCurve(iRing + 1);
222
307
}
223
224
/**
225
 * \brief Fetch reference to indicated internal ring.
226
 *
227
 * Note that the returned ring pointer is to an internal data object of the
228
 * OGRCurvePolygon.  It should not be modified or deleted by the application,
229
 * and the pointer is only valid till the polygon is next modified.  Use the
230
 * OGRGeometry::clone() method to make a separate copy within the application.
231
 *
232
 * Relates to the SFCOM IPolygon::get_InternalRing() method.
233
 *
234
 * @param iRing internal ring index from 0 to getNumInteriorRings() - 1.
235
 *
236
 * @return pointer to interior ring.  May be NULL.
237
 */
238
239
const OGRCurve *OGRCurvePolygon::getInteriorRingCurve(int iRing) const
240
241
0
{
242
0
    return oCC.getCurve(iRing + 1);
243
0
}
244
245
/************************************************************************/
246
/*                        stealExteriorRingCurve()                      */
247
/************************************************************************/
248
249
/**
250
 * \brief "Steal" reference to external ring.
251
 *
252
 * After the call to that function, only call to stealInteriorRing() or
253
 * destruction of the OGRCurvePolygon is valid. Other operations may crash.
254
 *
255
 * @return pointer to external ring.  May be NULL if the OGRCurvePolygon is
256
 * empty.
257
 */
258
259
OGRCurve *OGRCurvePolygon::stealExteriorRingCurve()
260
0
{
261
0
    if (oCC.nCurveCount == 0)
262
0
        return nullptr;
263
0
    OGRCurve *poRet = oCC.papoCurves[0];
264
0
    oCC.papoCurves[0] = nullptr;
265
0
    return poRet;
266
0
}
267
268
/************************************************************************/
269
/*                            removeRing()                              */
270
/************************************************************************/
271
272
/**
273
 * \brief Remove a geometry from the container.
274
 *
275
 * Removing a geometry will cause the geometry count to drop by one, and all
276
 * "higher" geometries will shuffle down one in index.
277
 *
278
 * There is no SFCOM analog to this method.
279
 *
280
 * @param iIndex the index of the geometry to delete.  A value of -1 is a
281
 * special flag meaning that all geometries should be removed.
282
 *
283
 * @param bDelete if true the geometry will be deallocated, otherwise it will
284
 * not.  The default is true as the container is considered to own the
285
 * geometries in it.
286
 *
287
 * @return OGRERR_NONE if successful, or OGRERR_FAILURE if the index is
288
 * out of range.
289
 */
290
291
OGRErr OGRCurvePolygon::removeRing(int iIndex, bool bDelete)
292
0
{
293
0
    return oCC.removeCurve(iIndex, bDelete);
294
0
}
295
296
/************************************************************************/
297
/*                              addRing()                               */
298
/************************************************************************/
299
300
/**
301
 * \brief Add a ring to a polygon.
302
 *
303
 * If the polygon has no external ring (it is empty) this will be used as
304
 * the external ring, otherwise it is used as an internal ring.  The passed
305
 * OGRCurve remains the responsibility of the caller (an internal copy
306
 * is made).
307
 *
308
 * This method has no SFCOM analog.
309
 *
310
 * @param poNewRing ring to be added to the polygon.
311
 * @return OGRERR_NONE in case of success
312
 */
313
314
OGRErr OGRCurvePolygon::addRing(const OGRCurve *poNewRing)
315
316
0
{
317
0
    OGRCurve *poNewRingCloned = poNewRing->clone();
318
0
    OGRErr eErr = addRingDirectly(poNewRingCloned);
319
0
    if (eErr != OGRERR_NONE)
320
0
        delete poNewRingCloned;
321
0
    return eErr;
322
0
}
323
324
/************************************************************************/
325
/*                            isRingCorrectType()                       */
326
/************************************************************************/
327
bool OGRCurvePolygon::isRingCorrectType(const OGRCurve *poRing) const
328
820
{
329
820
    return poRing && !EQUAL(poRing->getGeometryName(), "LINEARRING");
330
820
}
331
332
/************************************************************************/
333
/*                            checkRing()                               */
334
/************************************************************************/
335
336
bool OGRCurvePolygon::checkRing(const OGRCurve *poNewRing) const
337
820
{
338
820
    if (!isRingCorrectType(poNewRing))
339
0
    {
340
0
        CPLError(CE_Failure, CPLE_AppDefined, "Linearring not allowed.");
341
0
        return false;
342
0
    }
343
344
820
    if (!poNewRing->IsEmpty() && !poNewRing->get_IsClosed())
345
638
    {
346
        // This configuration option name must be the same as in
347
        // OGRPolygon::checkRing()
348
638
        const char *pszEnvVar =
349
638
            CPLGetConfigOption("OGR_GEOMETRY_ACCEPT_UNCLOSED_RING", nullptr);
350
638
        if (pszEnvVar != nullptr && !CPLTestBool(pszEnvVar))
351
0
        {
352
0
            CPLError(CE_Failure, CPLE_AppDefined, "Non closed ring detected.");
353
0
            return false;
354
0
        }
355
638
        else
356
638
        {
357
638
            CPLError(CE_Warning, CPLE_AppDefined, "Non closed ring detected.%s",
358
638
                     pszEnvVar == nullptr
359
638
                         ? " To avoid accepting it, set the "
360
638
                           "OGR_GEOMETRY_ACCEPT_UNCLOSED_RING configuration "
361
638
                           "option to NO"
362
638
                         : "");
363
638
        }
364
638
    }
365
366
820
    if (wkbFlatten(poNewRing->getGeometryType()) == wkbLineString)
367
820
    {
368
820
        if (poNewRing->getNumPoints() < 4)
369
4
        {
370
4
            return false;
371
4
        }
372
820
    }
373
374
816
    return true;
375
820
}
376
377
/************************************************************************/
378
/*                          addRingDirectly()                           */
379
/************************************************************************/
380
381
/**
382
 * \brief Add a ring to a polygon.
383
 *
384
 * If the polygon has no external ring (it is empty) this will be used as
385
 * the external ring, otherwise it is used as an internal ring.  Ownership
386
 * of the passed ring is assumed by the OGRCurvePolygon, but otherwise this
387
 * method operates the same as OGRCurvePolygon::AddRing().
388
 *
389
 * This method has no SFCOM analog.
390
 *
391
 * @param poNewRing ring to be added to the polygon.
392
 * @return OGRERR_NONE in case of success
393
 */
394
395
OGRErr OGRCurvePolygon::addRingDirectly(OGRCurve *poNewRing)
396
820
{
397
820
    return addRingDirectlyInternal(poNewRing, TRUE);
398
820
}
399
400
OGRErr OGRCurvePolygon::addRingDirectlyInternal(OGRCurve *poNewRing,
401
                                                int bNeedRealloc)
402
820
{
403
820
    if (!checkRing(poNewRing))
404
4
        return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
405
406
816
    HomogenizeDimensionalityWith(poNewRing);
407
408
816
    return oCC.addCurveDirectly(this, poNewRing, bNeedRealloc);
409
820
}
410
411
/************************************************************************/
412
/*                             addRing()                                */
413
/************************************************************************/
414
415
/**
416
 * \brief Add a ring to a polygon.
417
 *
418
 * If the polygon has no external ring (it is empty) this will be used as
419
 * the external ring, otherwise it is used as an internal ring.
420
 *
421
 * This method has no SFCOM analog.
422
 *
423
 * @param poNewRing ring to be added to the polygon.
424
 * @return OGRERR_NONE in case of success
425
 */
426
OGRErr OGRCurvePolygon::addRing(std::unique_ptr<OGRCurve> poNewRing)
427
0
{
428
0
    OGRCurve *poNewRingPtr = poNewRing.release();
429
0
    OGRErr eErr = addRingDirectlyInternal(poNewRingPtr, TRUE);
430
0
    if (eErr != OGRERR_NONE)
431
0
        delete poNewRingPtr;
432
0
    return eErr;
433
0
}
434
435
/************************************************************************/
436
/*                              WkbSize()                               */
437
/*                                                                      */
438
/*      Return the size of this object in well known binary             */
439
/*      representation including the byte order, and type information.  */
440
/************************************************************************/
441
442
size_t OGRCurvePolygon::WkbSize() const
443
444
0
{
445
0
    return oCC.WkbSize();
446
0
}
447
448
/************************************************************************/
449
/*                       addCurveDirectlyFromWkb()                      */
450
/************************************************************************/
451
452
OGRErr OGRCurvePolygon::addCurveDirectlyFromWkb(OGRGeometry *poSelf,
453
                                                OGRCurve *poCurve)
454
0
{
455
0
    OGRCurvePolygon *poCP = poSelf->toCurvePolygon();
456
0
    return poCP->addRingDirectlyInternal(poCurve, FALSE);
457
0
}
458
459
/************************************************************************/
460
/*                           importFromWkb()                            */
461
/*                                                                      */
462
/*      Initialize from serialized stream in well known binary          */
463
/*      format.                                                         */
464
/************************************************************************/
465
466
OGRErr OGRCurvePolygon::importFromWkb(const unsigned char *pabyData,
467
                                      size_t nSize, OGRwkbVariant eWkbVariant,
468
                                      size_t &nBytesConsumedOut)
469
470
0
{
471
0
    nBytesConsumedOut = 0;
472
0
    OGRwkbByteOrder eByteOrder;
473
0
    size_t nDataOffset = 0;
474
    // coverity[tainted_data]
475
0
    OGRErr eErr = oCC.importPreambleFromWkb(this, pabyData, nSize, nDataOffset,
476
0
                                            eByteOrder, 9, eWkbVariant);
477
0
    if (eErr != OGRERR_NONE)
478
0
        return eErr;
479
480
0
    eErr = oCC.importBodyFromWkb(this, pabyData + nDataOffset, nSize,
481
0
                                 true,  // bAcceptCompoundCurve
482
0
                                 addCurveDirectlyFromWkb, eWkbVariant,
483
0
                                 nBytesConsumedOut);
484
0
    if (eErr == OGRERR_NONE)
485
0
        nBytesConsumedOut += nDataOffset;
486
0
    return eErr;
487
0
}
488
489
/************************************************************************/
490
/*                            exportToWkb()                             */
491
/*                                                                      */
492
/*      Build a well known binary representation of this object.        */
493
/************************************************************************/
494
495
OGRErr OGRCurvePolygon::exportToWkb(unsigned char *pabyData,
496
                                    const OGRwkbExportOptions *psOptions) const
497
0
{
498
0
    OGRwkbExportOptions sOptions(psOptions ? *psOptions
499
0
                                           : OGRwkbExportOptions());
500
501
    // Does not make sense for new geometries, so patch it.
502
0
    if (sOptions.eWkbVariant == wkbVariantOldOgc)
503
0
        sOptions.eWkbVariant = wkbVariantIso;
504
0
    return oCC.exportToWkb(this, pabyData, &sOptions);
505
0
}
506
507
/************************************************************************/
508
/*                       addCurveDirectlyFromWkt()                      */
509
/************************************************************************/
510
511
OGRErr OGRCurvePolygon::addCurveDirectlyFromWkt(OGRGeometry *poSelf,
512
                                                OGRCurve *poCurve)
513
820
{
514
820
    OGRCurvePolygon *poCP = poSelf->toCurvePolygon();
515
820
    return poCP->addRingDirectly(poCurve);
516
820
}
517
518
/************************************************************************/
519
/*                           importFromWkt()                            */
520
/*                                                                      */
521
/*      Instantiate from well known text format.                        */
522
/************************************************************************/
523
524
OGRErr OGRCurvePolygon::importFromWkt(const char **ppszInput)
525
526
107
{
527
107
    return importCurveCollectionFromWkt(ppszInput,
528
107
                                        FALSE,  // bAllowEmptyComponent
529
107
                                        TRUE,   // bAllowLineString
530
107
                                        TRUE,   // bAllowCurve
531
107
                                        TRUE,   // bAllowCompoundCurve
532
107
                                        addCurveDirectlyFromWkt);
533
107
}
534
535
/************************************************************************/
536
/*                            exportToWkt()                             */
537
/************************************************************************/
538
539
std::string OGRCurvePolygon::exportToWkt(const OGRWktOptions &opts,
540
                                         OGRErr *err) const
541
0
{
542
0
    return oCC.exportToWkt(this, opts, err);
543
0
}
544
545
/************************************************************************/
546
/*                           CurvePolyToPoly()                          */
547
/************************************************************************/
548
549
/**
550
 * \brief Return a polygon from a curve polygon.
551
 *
552
 * This method is the same as C function OGR_G_CurvePolyToPoly().
553
 *
554
 * The returned geometry is a new instance whose ownership belongs to
555
 * the caller.
556
 *
557
 * @param dfMaxAngleStepSizeDegrees the largest step in degrees along the
558
 * arc, zero to use the default setting.
559
 * @param papszOptions options as a null-terminated list of strings.
560
 *                     Unused for now. Must be set to NULL.
561
 *
562
 * @return a linestring
563
 */
564
565
OGRPolygon *
566
OGRCurvePolygon::CurvePolyToPoly(double dfMaxAngleStepSizeDegrees,
567
                                 const char *const *papszOptions) const
568
0
{
569
0
    OGRPolygon *poPoly = new OGRPolygon();
570
0
    poPoly->assignSpatialReference(getSpatialReference());
571
0
    for (int iRing = 0; iRing < oCC.nCurveCount; iRing++)
572
0
    {
573
0
        OGRLineString *poLS = oCC.papoCurves[iRing]->CurveToLine(
574
0
            dfMaxAngleStepSizeDegrees, papszOptions);
575
0
        OGRLinearRing *poRing = OGRCurve::CastToLinearRing(poLS);
576
0
        if (poRing == nullptr)
577
0
        {
578
0
            CPLError(CE_Failure, CPLE_IllegalArg,
579
0
                     "OGRCurve::CastToLinearRing failed");
580
0
            break;
581
0
        }
582
0
        poPoly->addRingDirectly(poRing);
583
0
    }
584
0
    return poPoly;
585
0
}
586
587
/************************************************************************/
588
/*                         hasCurveGeometry()                           */
589
/************************************************************************/
590
591
OGRBoolean OGRCurvePolygon::hasCurveGeometry(int bLookForNonLinear) const
592
1
{
593
1
    if (bLookForNonLinear)
594
0
    {
595
0
        return oCC.hasCurveGeometry(bLookForNonLinear);
596
0
    }
597
598
1
    return TRUE;
599
1
}
600
601
/************************************************************************/
602
/*                         getLinearGeometry()                        */
603
/************************************************************************/
604
605
OGRGeometry *
606
OGRCurvePolygon::getLinearGeometry(double dfMaxAngleStepSizeDegrees,
607
                                   const char *const *papszOptions) const
608
0
{
609
0
    return CurvePolyToPoly(dfMaxAngleStepSizeDegrees, papszOptions);
610
0
}
611
612
/************************************************************************/
613
/*                            getEnvelope()                             */
614
/************************************************************************/
615
616
void OGRCurvePolygon::getEnvelope(OGREnvelope *psEnvelope) const
617
618
0
{
619
0
    oCC.getEnvelope(psEnvelope);
620
0
}
621
622
/************************************************************************/
623
/*                            getEnvelope()                             */
624
/************************************************************************/
625
626
void OGRCurvePolygon::getEnvelope(OGREnvelope3D *psEnvelope) const
627
628
0
{
629
0
    oCC.getEnvelope(psEnvelope);
630
0
}
631
632
/************************************************************************/
633
/*                               Equals()                               */
634
/************************************************************************/
635
636
OGRBoolean OGRCurvePolygon::Equals(const OGRGeometry *poOther) const
637
638
0
{
639
0
    if (poOther == this)
640
0
        return TRUE;
641
642
0
    if (poOther->getGeometryType() != getGeometryType())
643
0
        return FALSE;
644
645
0
    if (IsEmpty() && poOther->IsEmpty())
646
0
        return TRUE;
647
648
0
    return oCC.Equals(&(poOther->toCurvePolygon()->oCC));
649
0
}
650
651
/************************************************************************/
652
/*                             transform()                              */
653
/************************************************************************/
654
655
OGRErr OGRCurvePolygon::transform(OGRCoordinateTransformation *poCT)
656
657
0
{
658
0
    return oCC.transform(this, poCT);
659
0
}
660
661
/************************************************************************/
662
/*                              get_Length()                            */
663
/************************************************************************/
664
665
double OGRCurvePolygon::get_Length() const
666
667
0
{
668
0
    double dfLength = 0.0;
669
0
    for (const auto &poCurve : *this)
670
0
    {
671
0
        dfLength += poCurve->get_Length();
672
0
    }
673
674
0
    return dfLength;
675
0
}
676
677
/************************************************************************/
678
/*                        get_GeodesicLength()                          */
679
/************************************************************************/
680
681
double OGRCurvePolygon::get_GeodesicLength(
682
    const OGRSpatialReference *poSRSOverride) const
683
684
0
{
685
0
    if (!poSRSOverride)
686
0
        poSRSOverride = getSpatialReference();
687
688
0
    double dfLength = 0.0;
689
0
    for (const auto &poCurve : *this)
690
0
    {
691
0
        const double dfLocalLength = poCurve->get_GeodesicLength(poSRSOverride);
692
0
        if (dfLocalLength < 0)
693
0
            return dfLocalLength;
694
0
        dfLength += dfLocalLength;
695
0
    }
696
697
0
    return dfLength;
698
0
}
699
700
/************************************************************************/
701
/*                              get_Area()                              */
702
/************************************************************************/
703
704
double OGRCurvePolygon::get_Area() const
705
706
0
{
707
0
    if (getExteriorRingCurve() == nullptr)
708
0
        return 0.0;
709
710
0
    double dfArea = getExteriorRingCurve()->get_Area();
711
712
0
    for (int iRing = 0; iRing < getNumInteriorRings(); iRing++)
713
0
    {
714
0
        dfArea -= getInteriorRingCurve(iRing)->get_Area();
715
0
    }
716
717
0
    return dfArea;
718
0
}
719
720
/************************************************************************/
721
/*                        get_GeodesicArea()                            */
722
/************************************************************************/
723
724
double OGRCurvePolygon::get_GeodesicArea(
725
    const OGRSpatialReference *poSRSOverride) const
726
727
0
{
728
0
    if (getExteriorRingCurve() == nullptr)
729
0
        return 0.0;
730
731
0
    if (!poSRSOverride)
732
0
        poSRSOverride = getSpatialReference();
733
734
0
    double dfArea = getExteriorRingCurve()->get_GeodesicArea(poSRSOverride);
735
0
    if (dfArea > 0)
736
0
    {
737
0
        for (int iRing = 0; iRing < getNumInteriorRings(); iRing++)
738
0
        {
739
0
            dfArea -=
740
0
                getInteriorRingCurve(iRing)->get_GeodesicArea(poSRSOverride);
741
0
        }
742
0
    }
743
744
0
    return dfArea;
745
0
}
746
747
/************************************************************************/
748
/*                       setCoordinateDimension()                       */
749
/************************************************************************/
750
751
bool OGRCurvePolygon::setCoordinateDimension(int nNewDimension)
752
753
745
{
754
745
    return oCC.setCoordinateDimension(this, nNewDimension);
755
745
}
756
757
bool OGRCurvePolygon::set3D(OGRBoolean bIs3D)
758
819
{
759
819
    return oCC.set3D(this, bIs3D);
760
819
}
761
762
bool OGRCurvePolygon::setMeasured(OGRBoolean bIsMeasured)
763
1.71k
{
764
1.71k
    return oCC.setMeasured(this, bIsMeasured);
765
1.71k
}
766
767
/************************************************************************/
768
/*                       assignSpatialReference()                       */
769
/************************************************************************/
770
771
void OGRCurvePolygon::assignSpatialReference(const OGRSpatialReference *poSR)
772
2.51k
{
773
2.51k
    oCC.assignSpatialReference(this, poSR);
774
2.51k
}
775
776
/************************************************************************/
777
/*                               IsEmpty()                              */
778
/************************************************************************/
779
780
OGRBoolean OGRCurvePolygon::IsEmpty() const
781
0
{
782
0
    return oCC.IsEmpty();
783
0
}
784
785
/************************************************************************/
786
/*                              segmentize()                            */
787
/************************************************************************/
788
789
bool OGRCurvePolygon::segmentize(double dfMaxLength)
790
0
{
791
0
    if (EQUAL(getGeometryName(), "TRIANGLE"))
792
0
    {
793
0
        CPLError(CE_Failure, CPLE_NotSupported,
794
0
                 "segmentize() is not valid for Triangle");
795
0
        return false;
796
0
    }
797
0
    return oCC.segmentize(dfMaxLength);
798
0
}
799
800
/************************************************************************/
801
/*                               swapXY()                               */
802
/************************************************************************/
803
804
void OGRCurvePolygon::swapXY()
805
0
{
806
0
    oCC.swapXY();
807
0
}
808
809
/************************************************************************/
810
/*                           ContainsPoint()                             */
811
/************************************************************************/
812
813
OGRBoolean OGRCurvePolygon::ContainsPoint(const OGRPoint *p) const
814
0
{
815
0
    if (getExteriorRingCurve() != nullptr && getNumInteriorRings() == 0)
816
0
    {
817
0
        const int nRet = getExteriorRingCurve()->ContainsPoint(p);
818
0
        if (nRet >= 0)
819
0
            return nRet;
820
0
    }
821
822
0
    return OGRGeometry::Contains(p);
823
0
}
824
825
/************************************************************************/
826
/*                          IntersectsPoint()                           */
827
/************************************************************************/
828
829
OGRBoolean OGRCurvePolygon::IntersectsPoint(const OGRPoint *p) const
830
0
{
831
0
    if (getExteriorRingCurve() != nullptr && getNumInteriorRings() == 0)
832
0
    {
833
0
        const int nRet = getExteriorRingCurve()->IntersectsPoint(p);
834
0
        if (nRet >= 0)
835
0
            return nRet;
836
0
    }
837
838
0
    return OGRGeometry::Intersects(p);
839
0
}
840
841
/************************************************************************/
842
/*                               Contains()                             */
843
/************************************************************************/
844
845
OGRBoolean OGRCurvePolygon::Contains(const OGRGeometry *poOtherGeom) const
846
847
0
{
848
0
    if (!IsEmpty() && poOtherGeom != nullptr &&
849
0
        wkbFlatten(poOtherGeom->getGeometryType()) == wkbPoint)
850
0
    {
851
0
        return ContainsPoint(poOtherGeom->toPoint());
852
0
    }
853
854
0
    return OGRGeometry::Contains(poOtherGeom);
855
0
}
856
857
/************************************************************************/
858
/*                              Intersects()                            */
859
/************************************************************************/
860
861
OGRBoolean OGRCurvePolygon::Intersects(const OGRGeometry *poOtherGeom) const
862
863
0
{
864
0
    if (!IsEmpty() && poOtherGeom != nullptr &&
865
0
        wkbFlatten(poOtherGeom->getGeometryType()) == wkbPoint)
866
0
    {
867
0
        return IntersectsPoint(poOtherGeom->toPoint());
868
0
    }
869
870
0
    return OGRGeometry::Intersects(poOtherGeom);
871
0
}
872
873
/************************************************************************/
874
/*                           CastToPolygon()                            */
875
/************************************************************************/
876
877
/**
878
 * \brief Convert to polygon.
879
 *
880
 * This method should only be called if the curve polygon actually only contains
881
 * instances of OGRLineString. This can be verified if hasCurveGeometry(TRUE)
882
 * returns FALSE. It is not intended to approximate curve polygons. For that
883
 * use getLinearGeometry().
884
 *
885
 * The passed in geometry is consumed and a new one returned (or NULL in case
886
 * of failure).
887
 *
888
 * @param poCP the input geometry - ownership is passed to the method.
889
 * @return new geometry.
890
 */
891
892
OGRPolygon *OGRCurvePolygon::CastToPolygon(OGRCurvePolygon *poCP)
893
0
{
894
0
    for (int i = 0; i < poCP->oCC.nCurveCount; i++)
895
0
    {
896
0
        poCP->oCC.papoCurves[i] =
897
0
            OGRCurve::CastToLinearRing(poCP->oCC.papoCurves[i]);
898
0
        if (poCP->oCC.papoCurves[i] == nullptr)
899
0
        {
900
0
            delete poCP;
901
0
            return nullptr;
902
0
        }
903
0
    }
904
0
    OGRPolygon *poPoly = new OGRPolygon();
905
0
    poPoly->setCoordinateDimension(poCP->getCoordinateDimension());
906
0
    poPoly->assignSpatialReference(poCP->getSpatialReference());
907
0
    poPoly->oCC.nCurveCount = poCP->oCC.nCurveCount;
908
0
    poPoly->oCC.papoCurves = poCP->oCC.papoCurves;
909
0
    poCP->oCC.nCurveCount = 0;
910
0
    poCP->oCC.papoCurves = nullptr;
911
0
    delete poCP;
912
0
    return poPoly;
913
0
}
914
915
//! @cond Doxygen_Suppress
916
/************************************************************************/
917
/*                      GetCasterToPolygon()                            */
918
/************************************************************************/
919
920
OGRPolygon *OGRCurvePolygon::CasterToPolygon(OGRSurface *poSurface)
921
0
{
922
0
    OGRCurvePolygon *poCurvePoly = poSurface->toCurvePolygon();
923
0
    return OGRCurvePolygon::CastToPolygon(poCurvePoly);
924
0
}
925
926
OGRSurfaceCasterToPolygon OGRCurvePolygon::GetCasterToPolygon() const
927
0
{
928
0
    return OGRCurvePolygon::CasterToPolygon;
929
0
}
930
931
/************************************************************************/
932
/*                      GetCasterToCurvePolygon()                       */
933
/************************************************************************/
934
935
static OGRCurvePolygon *CasterToCurvePolygon(OGRSurface *poSurface)
936
0
{
937
0
    return poSurface->toCurvePolygon();
938
0
}
939
940
OGRSurfaceCasterToCurvePolygon OGRCurvePolygon::GetCasterToCurvePolygon() const
941
0
{
942
0
    return ::CasterToCurvePolygon;
943
0
}
944
945
//! @endcond
946
947
/************************************************************************/
948
/*                           hasEmptyParts()                            */
949
/************************************************************************/
950
951
bool OGRCurvePolygon::hasEmptyParts() const
952
0
{
953
0
    return oCC.hasEmptyParts();
954
0
}
955
956
/************************************************************************/
957
/*                          removeEmptyParts()                          */
958
/************************************************************************/
959
960
void OGRCurvePolygon::removeEmptyParts()
961
0
{
962
0
    auto poExteriorRing = getExteriorRingCurve();
963
0
    if (poExteriorRing && poExteriorRing->IsEmpty())
964
0
        empty();
965
0
    else
966
0
        oCC.removeEmptyParts();
967
0
}