Coverage Report

Created: 2025-06-13 06:18

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