Coverage Report

Created: 2025-12-31 08:30

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/ogr/ogrcompoundcurve.cpp
Line
Count
Source
1
/******************************************************************************
2
 *
3
 * Project:  OpenGIS Simple Features Reference Implementation
4
 * Purpose:  The OGRCompoundCurve 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 <cmath>
17
#include <cstddef>
18
19
#include "cpl_error.h"
20
#include "ogr_core.h"
21
#include "ogr_geometry.h"
22
#include "ogr_p.h"
23
#include "ogr_spatialref.h"
24
25
/************************************************************************/
26
/*             OGRCompoundCurve( const OGRCompoundCurve& )              */
27
/************************************************************************/
28
29
/**
30
 * \brief Copy constructor.
31
 */
32
33
50.0k
OGRCompoundCurve::OGRCompoundCurve(const OGRCompoundCurve &) = default;
34
35
/************************************************************************/
36
/*                 operator=( const OGRCompoundCurve&)                  */
37
/************************************************************************/
38
39
/**
40
 * \brief Assignment operator.
41
 */
42
43
OGRCompoundCurve &OGRCompoundCurve::operator=(const OGRCompoundCurve &other)
44
0
{
45
0
    if (this != &other)
46
0
    {
47
0
        OGRCurve::operator=(other);
48
49
0
        oCC = other.oCC;
50
0
    }
51
0
    return *this;
52
0
}
53
54
/************************************************************************/
55
/*                               clone()                                */
56
/************************************************************************/
57
58
OGRCompoundCurve *OGRCompoundCurve::clone() const
59
60
50.0k
{
61
50.0k
    auto ret = new (std::nothrow) OGRCompoundCurve(*this);
62
50.0k
    if (ret)
63
50.0k
    {
64
50.0k
        if (ret->WkbSize() != WkbSize())
65
0
        {
66
0
            delete ret;
67
0
            ret = nullptr;
68
0
        }
69
50.0k
    }
70
50.0k
    return ret;
71
50.0k
}
72
73
/************************************************************************/
74
/*                          getGeometryType()                           */
75
/************************************************************************/
76
77
OGRwkbGeometryType OGRCompoundCurve::getGeometryType() const
78
79
471k
{
80
471k
    if ((flags & OGR_G_3D) && (flags & OGR_G_MEASURED))
81
136k
        return wkbCompoundCurveZM;
82
335k
    else if (flags & OGR_G_MEASURED)
83
47.7k
        return wkbCompoundCurveM;
84
287k
    else if (flags & OGR_G_3D)
85
50.3k
        return wkbCompoundCurveZ;
86
237k
    else
87
237k
        return wkbCompoundCurve;
88
471k
}
89
90
/************************************************************************/
91
/*                          getGeometryName()                           */
92
/************************************************************************/
93
94
const char *OGRCompoundCurve::getGeometryName() const
95
96
100k
{
97
100k
    return "COMPOUNDCURVE";
98
100k
}
99
100
/************************************************************************/
101
/*                              WkbSize()                               */
102
/************************************************************************/
103
size_t OGRCompoundCurve::WkbSize() const
104
367k
{
105
367k
    return oCC.WkbSize();
106
367k
}
107
108
/************************************************************************/
109
/*                       addCurveDirectlyFromWkt()                      */
110
/************************************************************************/
111
112
OGRErr OGRCompoundCurve::addCurveDirectlyFromWkb(OGRGeometry *poSelf,
113
                                                 OGRCurve *poCurve)
114
26.1k
{
115
26.1k
    OGRCompoundCurve *poCC = poSelf->toCompoundCurve();
116
26.1k
    return poCC->addCurveDirectlyInternal(poCurve, DEFAULT_TOLERANCE_EPSILON,
117
26.1k
                                          FALSE);
118
26.1k
}
119
120
/************************************************************************/
121
/*                           importFromWkb()                            */
122
/************************************************************************/
123
124
OGRErr OGRCompoundCurve::importFromWkb(const unsigned char *pabyData,
125
                                       size_t nSize, OGRwkbVariant eWkbVariant,
126
                                       size_t &nBytesConsumedOut)
127
84.1k
{
128
84.1k
    OGRwkbByteOrder eByteOrder = wkbNDR;
129
84.1k
    size_t nDataOffset = 0;
130
    // coverity[tainted_data]
131
84.1k
    OGRErr eErr = oCC.importPreambleFromWkb(this, pabyData, nSize, nDataOffset,
132
84.1k
                                            eByteOrder, 9, eWkbVariant);
133
84.1k
    if (eErr != OGRERR_NONE)
134
8.44k
        return eErr;
135
136
75.7k
    eErr = oCC.importBodyFromWkb(this, pabyData + nDataOffset, nSize,
137
75.7k
                                 false,  // bAcceptCompoundCurve
138
75.7k
                                 addCurveDirectlyFromWkb, eWkbVariant,
139
75.7k
                                 nBytesConsumedOut);
140
75.7k
    if (eErr == OGRERR_NONE)
141
64.3k
        nBytesConsumedOut += nDataOffset;
142
75.7k
    return eErr;
143
84.1k
}
144
145
/************************************************************************/
146
/*                            exportToWkb()                             */
147
/************************************************************************/
148
149
OGRErr OGRCompoundCurve::exportToWkb(unsigned char *pabyData,
150
                                     const OGRwkbExportOptions *psOptions) const
151
37.1k
{
152
37.1k
    OGRwkbExportOptions sOptions(psOptions ? *psOptions
153
37.1k
                                           : OGRwkbExportOptions());
154
155
    // Does not make sense for new geometries, so patch it.
156
37.1k
    if (sOptions.eWkbVariant == wkbVariantOldOgc)
157
9.07k
        sOptions.eWkbVariant = wkbVariantIso;
158
37.1k
    return oCC.exportToWkb(this, pabyData, &sOptions);
159
37.1k
}
160
161
/************************************************************************/
162
/*                       addCurveDirectlyFromWkt()                      */
163
/************************************************************************/
164
165
OGRErr OGRCompoundCurve::addCurveDirectlyFromWkt(OGRGeometry *poSelf,
166
                                                 OGRCurve *poCurve)
167
21.9k
{
168
21.9k
    return poSelf->toCompoundCurve()->addCurveDirectly(poCurve);
169
21.9k
}
170
171
/************************************************************************/
172
/*                           importFromWkt()                            */
173
/************************************************************************/
174
175
OGRErr OGRCompoundCurve::importFromWkt(const char **ppszInput)
176
33.2k
{
177
33.2k
    return importCurveCollectionFromWkt(ppszInput,
178
33.2k
                                        FALSE,  // bAllowEmptyComponent
179
33.2k
                                        TRUE,   // bAllowLineString
180
33.2k
                                        TRUE,   // bAllowCurve
181
33.2k
                                        FALSE,  // bAllowCompoundCurve
182
33.2k
                                        addCurveDirectlyFromWkt);
183
33.2k
}
184
185
/************************************************************************/
186
/*                            exportToWkt()                             */
187
/************************************************************************/
188
std::string OGRCompoundCurve::exportToWkt(const OGRWktOptions &opts,
189
                                          OGRErr *err) const
190
32.9k
{
191
32.9k
    return oCC.exportToWkt(this, opts, err);
192
32.9k
}
193
194
/************************************************************************/
195
/*                               empty()                                */
196
/************************************************************************/
197
198
void OGRCompoundCurve::empty()
199
117k
{
200
117k
    oCC.empty(this);
201
117k
}
202
203
/************************************************************************/
204
/*                            getEnvelope()                             */
205
/************************************************************************/
206
207
void OGRCompoundCurve::getEnvelope(OGREnvelope *psEnvelope) const
208
226
{
209
226
    oCC.getEnvelope(psEnvelope);
210
226
}
211
212
/************************************************************************/
213
/*                            getEnvelope()                             */
214
/************************************************************************/
215
216
void OGRCompoundCurve::getEnvelope(OGREnvelope3D *psEnvelope) const
217
12.9k
{
218
12.9k
    oCC.getEnvelope(psEnvelope);
219
12.9k
}
220
221
/************************************************************************/
222
/*                               IsEmpty()                              */
223
/************************************************************************/
224
225
OGRBoolean OGRCompoundCurve::IsEmpty() const
226
237k
{
227
237k
    return oCC.IsEmpty();
228
237k
}
229
230
/************************************************************************/
231
/*                             get_Length()                             */
232
/*                                                                      */
233
/*      For now we return a simple euclidean 2D distance.               */
234
/************************************************************************/
235
236
double OGRCompoundCurve::get_Length() const
237
0
{
238
0
    double dfLength = 0.0;
239
0
    for (int iGeom = 0; iGeom < oCC.nCurveCount; iGeom++)
240
0
        dfLength += oCC.papoCurves[iGeom]->get_Length();
241
0
    return dfLength;
242
0
}
243
244
/************************************************************************/
245
/*                             StartPoint()                             */
246
/************************************************************************/
247
248
void OGRCompoundCurve::StartPoint(OGRPoint *p) const
249
39.7k
{
250
39.7k
    CPLAssert(oCC.nCurveCount > 0);
251
39.7k
    oCC.papoCurves[0]->StartPoint(p);
252
39.7k
}
253
254
/************************************************************************/
255
/*                              EndPoint()                              */
256
/************************************************************************/
257
258
void OGRCompoundCurve::EndPoint(OGRPoint *p) const
259
30.2k
{
260
30.2k
    CPLAssert(oCC.nCurveCount > 0);
261
30.2k
    oCC.papoCurves[oCC.nCurveCount - 1]->EndPoint(p);
262
30.2k
}
263
264
/************************************************************************/
265
/*                               Value()                                */
266
/************************************************************************/
267
268
void OGRCompoundCurve::Value(double dfDistance, OGRPoint *poPoint) const
269
0
{
270
271
0
    if (dfDistance < 0)
272
0
    {
273
0
        StartPoint(poPoint);
274
0
        return;
275
0
    }
276
277
0
    double dfLength = 0.0;
278
0
    for (int iGeom = 0; iGeom < oCC.nCurveCount; iGeom++)
279
0
    {
280
0
        const double dfSegLength = oCC.papoCurves[iGeom]->get_Length();
281
0
        if (dfSegLength > 0)
282
0
        {
283
0
            if ((dfLength <= dfDistance) &&
284
0
                ((dfLength + dfSegLength) >= dfDistance))
285
0
            {
286
0
                oCC.papoCurves[iGeom]->Value(dfDistance - dfLength, poPoint);
287
288
0
                return;
289
0
            }
290
291
0
            dfLength += dfSegLength;
292
0
        }
293
0
    }
294
295
0
    EndPoint(poPoint);
296
0
}
297
298
/************************************************************************/
299
/*                         CurveToLineInternal()                        */
300
/************************************************************************/
301
302
OGRLineString *
303
OGRCompoundCurve::CurveToLineInternal(double dfMaxAngleStepSizeDegrees,
304
                                      const char *const *papszOptions,
305
                                      int bIsLinearRing) const
306
86.1k
{
307
86.1k
    OGRLineString *const poLine =
308
86.1k
        bIsLinearRing ? new OGRLinearRing() : new OGRLineString();
309
86.1k
    poLine->assignSpatialReference(getSpatialReference());
310
314k
    for (int iGeom = 0; iGeom < oCC.nCurveCount; iGeom++)
311
228k
    {
312
228k
        OGRLineString *poSubLS = oCC.papoCurves[iGeom]->CurveToLine(
313
228k
            dfMaxAngleStepSizeDegrees, papszOptions);
314
228k
        poLine->addSubLineString(poSubLS, (iGeom == 0) ? 0 : 1);
315
228k
        delete poSubLS;
316
228k
    }
317
86.1k
    return poLine;
318
86.1k
}
319
320
/************************************************************************/
321
/*                          CurveToLine()                               */
322
/************************************************************************/
323
324
OGRLineString *
325
OGRCompoundCurve::CurveToLine(double dfMaxAngleStepSizeDegrees,
326
                              const char *const *papszOptions) const
327
84.5k
{
328
84.5k
    return CurveToLineInternal(dfMaxAngleStepSizeDegrees, papszOptions, FALSE);
329
84.5k
}
330
331
/************************************************************************/
332
/*                               Equals()                                */
333
/************************************************************************/
334
335
OGRBoolean OGRCompoundCurve::Equals(const OGRGeometry *poOther) const
336
0
{
337
0
    if (poOther == this)
338
0
        return TRUE;
339
340
0
    if (poOther->getGeometryType() != getGeometryType())
341
0
        return FALSE;
342
343
0
    return oCC.Equals(&(poOther->toCompoundCurve()->oCC));
344
0
}
345
346
/************************************************************************/
347
/*                       setCoordinateDimension()                       */
348
/************************************************************************/
349
350
bool OGRCompoundCurve::setCoordinateDimension(int nNewDimension)
351
118k
{
352
118k
    return oCC.setCoordinateDimension(this, nNewDimension);
353
118k
}
354
355
bool OGRCompoundCurve::set3D(OGRBoolean bIs3D)
356
101k
{
357
101k
    return oCC.set3D(this, bIs3D);
358
101k
}
359
360
bool OGRCompoundCurve::setMeasured(OGRBoolean bIsMeasured)
361
225k
{
362
225k
    return oCC.setMeasured(this, bIsMeasured);
363
225k
}
364
365
/************************************************************************/
366
/*                       assignSpatialReference()                       */
367
/************************************************************************/
368
369
void OGRCompoundCurve::assignSpatialReference(const OGRSpatialReference *poSR)
370
179k
{
371
179k
    oCC.assignSpatialReference(this, poSR);
372
179k
}
373
374
/************************************************************************/
375
/*                          getNumCurves()                              */
376
/************************************************************************/
377
378
/**
379
 * \brief Return the number of curves.
380
 *
381
 * Note that the number of curves making this compound curve.
382
 *
383
 * Relates to the ISO SQL/MM ST_NumCurves() function.
384
 *
385
 * @return number of curves.
386
 */
387
388
int OGRCompoundCurve::getNumCurves() const
389
105k
{
390
105k
    return oCC.nCurveCount;
391
105k
}
392
393
/************************************************************************/
394
/*                           getCurve()                                 */
395
/************************************************************************/
396
397
/**
398
 * \brief Fetch reference to indicated internal ring.
399
 *
400
 * Note that the returned curve pointer is to an internal data object of the
401
 * OGRCompoundCurve.  It should not be modified or deleted by the application,
402
 * and the pointer is only valid till the polygon is next modified.  Use the
403
 * OGRGeometry::clone() method to make a separate copy within the application.
404
 *
405
 * Relates to the ISO SQL/MM ST_CurveN() function.
406
 *
407
 * @param iRing curve index from 0 to getNumCurves() - 1.
408
 *
409
 * @return pointer to curve.  May be NULL.
410
 */
411
412
OGRCurve *OGRCompoundCurve::getCurve(int iRing)
413
0
{
414
0
    return oCC.getCurve(iRing);
415
0
}
416
417
/************************************************************************/
418
/*                           getCurve()                                 */
419
/************************************************************************/
420
421
/**
422
 * \brief Fetch reference to indicated internal ring.
423
 *
424
 * Note that the returned curve pointer is to an internal data object of the
425
 * OGRCompoundCurve.  It should not be modified or deleted by the application,
426
 * and the pointer is only valid till the polygon is next modified.  Use the
427
 * OGRGeometry::clone() method to make a separate copy within the application.
428
 *
429
 * Relates to the ISO SQL/MM ST_CurveN() function.
430
 *
431
 * @param iCurve curve index from 0 to getNumCurves() - 1.
432
 *
433
 * @return pointer to curve.  May be NULL.
434
 */
435
436
const OGRCurve *OGRCompoundCurve::getCurve(int iCurve) const
437
33.3k
{
438
33.3k
    return oCC.getCurve(iCurve);
439
33.3k
}
440
441
/************************************************************************/
442
/*                           stealCurve()                               */
443
/************************************************************************/
444
445
/**
446
 * \brief "Steal" reference to curve.
447
 *
448
 * @param iCurve curve index from 0 to getNumCurves() - 1.
449
 *
450
 * @return pointer to curve.  May be NULL.
451
 */
452
453
OGRCurve *OGRCompoundCurve::stealCurve(int iCurve)
454
2.78k
{
455
2.78k
    return oCC.stealCurve(iCurve);
456
2.78k
}
457
458
/************************************************************************/
459
/*                            addCurve()                                */
460
/************************************************************************/
461
462
/**
463
 * \brief Add a curve to the container.
464
 *
465
 * The passed geometry is cloned to make an internal copy.
466
 *
467
 * There is no ISO SQL/MM analog to this method.
468
 *
469
 * This method is the same as the C function OGR_G_AddGeometry().
470
 *
471
 * @param poCurve geometry to add to the container.
472
 * @param dfToleranceEps relative tolerance when checking that the first point
473
 * of a segment matches then end point of the previous one. Default value:
474
 * OGRCompoundCurve::DEFAULT_TOLERANCE_EPSILON.
475
 *
476
 * @return OGRERR_NONE if successful, or OGRERR_FAILURE in case of error
477
 * (for example if curves are not contiguous)
478
 */
479
480
OGRErr OGRCompoundCurve::addCurve(const OGRCurve *poCurve,
481
                                  double dfToleranceEps)
482
0
{
483
0
    OGRCurve *poClonedCurve = poCurve->clone();
484
0
    const OGRErr eErr = addCurveDirectly(poClonedCurve, dfToleranceEps);
485
0
    if (eErr != OGRERR_NONE)
486
0
        delete poClonedCurve;
487
0
    return eErr;
488
0
}
489
490
/************************************************************************/
491
/*                          addCurveDirectly()                          */
492
/************************************************************************/
493
494
/**
495
 * \brief Add a curve directly to the container.
496
 *
497
 * Ownership of the passed geometry is taken by the container rather than
498
 * cloning as addCurve() does, but only if the method is successful.
499
 * If the method fails, ownership still belongs to the caller.
500
 *
501
 * There is no ISO SQL/MM analog to this method.
502
 *
503
 * This method is the same as the C function OGR_G_AddGeometryDirectly().
504
 *
505
 * @param poCurve geometry to add to the container.
506
 * @param dfToleranceEps relative tolerance when checking that the first point
507
 * of a segment matches then end point of the previous one. Default value:
508
 * OGRCompoundCurve::DEFAULT_TOLERANCE_EPSILON.
509
 *
510
 * @return OGRERR_NONE if successful, or OGRERR_FAILURE in case of error
511
 * (for example if curves are not contiguous)
512
 */
513
OGRErr OGRCompoundCurve::addCurveDirectly(OGRCurve *poCurve,
514
                                          double dfToleranceEps)
515
443k
{
516
443k
    return addCurveDirectlyInternal(poCurve, dfToleranceEps, TRUE);
517
443k
}
518
519
OGRErr OGRCompoundCurve::addCurveDirectlyInternal(OGRCurve *poCurve,
520
                                                  double dfToleranceEps,
521
                                                  int bNeedRealloc)
522
508k
{
523
508k
    if (poCurve->getNumPoints() == 1)
524
731
    {
525
731
        CPLError(CE_Failure, CPLE_AppDefined,
526
731
                 "Invalid curve: not enough points");
527
731
        return OGRERR_FAILURE;
528
731
    }
529
530
507k
    const OGRwkbGeometryType eCurveType =
531
507k
        wkbFlatten(poCurve->getGeometryType());
532
507k
    if (EQUAL(poCurve->getGeometryName(), "LINEARRING"))
533
1
    {
534
1
        CPLError(CE_Failure, CPLE_AppDefined, "Linearring not allowed.");
535
1
        return OGRERR_FAILURE;
536
1
    }
537
507k
    else if (eCurveType == wkbCompoundCurve)
538
155
    {
539
155
        CPLError(CE_Failure, CPLE_AppDefined,
540
155
                 "Cannot add a compound curve inside a compound curve");
541
155
        return OGRERR_FAILURE;
542
155
    }
543
544
507k
    if (oCC.nCurveCount > 0)
545
373k
    {
546
373k
        if (oCC.papoCurves[oCC.nCurveCount - 1]->IsEmpty() ||
547
372k
            poCurve->IsEmpty())
548
968
        {
549
968
            CPLError(CE_Failure, CPLE_AppDefined, "Non contiguous curves");
550
968
            return OGRERR_FAILURE;
551
968
        }
552
553
372k
        OGRPoint oEnd;
554
372k
        OGRPoint start;
555
372k
        oCC.papoCurves[oCC.nCurveCount - 1]->EndPoint(&oEnd);
556
372k
        poCurve->StartPoint(&start);
557
372k
        if (fabs(oEnd.getX() - start.getX()) >
558
372k
                dfToleranceEps * fabs(start.getX()) ||
559
257k
            fabs(oEnd.getY() - start.getY()) >
560
257k
                dfToleranceEps * fabs(start.getY()) ||
561
195k
            fabs(oEnd.getZ() - start.getZ()) >
562
195k
                dfToleranceEps * fabs(start.getZ()))
563
178k
        {
564
178k
            poCurve->EndPoint(&start);
565
178k
            if (fabs(oEnd.getX() - start.getX()) >
566
178k
                    dfToleranceEps * fabs(start.getX()) ||
567
84.5k
                fabs(oEnd.getY() - start.getY()) >
568
84.5k
                    dfToleranceEps * fabs(start.getY()) ||
569
33.5k
                fabs(oEnd.getZ() - start.getZ()) >
570
33.5k
                    dfToleranceEps * fabs(start.getZ()))
571
144k
            {
572
144k
                CPLError(CE_Failure, CPLE_AppDefined, "Non contiguous curves");
573
144k
                return OGRERR_FAILURE;
574
144k
            }
575
576
33.3k
            CPLDebug("GML", "reversing curve");
577
33.3k
            poCurve->toSimpleCurve()->reversePoints();
578
33.3k
        }
579
        // Patch so that it matches exactly.
580
227k
        poCurve->toSimpleCurve()->setPoint(0, &oEnd);
581
227k
    }
582
583
361k
    return oCC.addCurveDirectly(this, poCurve, bNeedRealloc);
584
507k
}
585
586
/************************************************************************/
587
/*                          addCurve()                                  */
588
/************************************************************************/
589
590
/**
591
 * \brief Add a curve directly to the container.
592
 *
593
 * There is no ISO SQL/MM analog to this method.
594
 *
595
 * This method is the same as the C function OGR_G_AddGeometryDirectly().
596
 *
597
 * @param poCurve geometry to add to the container.
598
 * @param dfToleranceEps relative tolerance when checking that the first point
599
 * of a segment matches then end point of the previous one. Default value:
600
 * OGRCompoundCurve::DEFAULT_TOLERANCE_EPSILON.
601
 *
602
 * @return OGRERR_NONE if successful, or OGRERR_FAILURE in case of error
603
 * (for example if curves are not contiguous)
604
 */
605
OGRErr OGRCompoundCurve::addCurve(std::unique_ptr<OGRCurve> poCurve,
606
                                  double dfToleranceEps)
607
38.4k
{
608
38.4k
    OGRCurve *poCurvePtr = poCurve.release();
609
38.4k
    OGRErr eErr = addCurveDirectlyInternal(poCurvePtr, dfToleranceEps, TRUE);
610
38.4k
    if (eErr != OGRERR_NONE)
611
448
        delete poCurvePtr;
612
38.4k
    return eErr;
613
38.4k
}
614
615
/************************************************************************/
616
/*                             transform()                              */
617
/************************************************************************/
618
619
OGRErr OGRCompoundCurve::transform(OGRCoordinateTransformation *poCT)
620
963
{
621
963
    return oCC.transform(this, poCT);
622
963
}
623
624
/************************************************************************/
625
/*                            flattenTo2D()                             */
626
/************************************************************************/
627
628
void OGRCompoundCurve::flattenTo2D()
629
0
{
630
0
    oCC.flattenTo2D(this);
631
0
}
632
633
/************************************************************************/
634
/*                              segmentize()                            */
635
/************************************************************************/
636
637
bool OGRCompoundCurve::segmentize(double dfMaxLength)
638
0
{
639
0
    return oCC.segmentize(dfMaxLength);
640
0
}
641
642
/************************************************************************/
643
/*                               swapXY()                               */
644
/************************************************************************/
645
646
void OGRCompoundCurve::swapXY()
647
0
{
648
0
    oCC.swapXY();
649
0
}
650
651
/************************************************************************/
652
/*                         hasCurveGeometry()                           */
653
/************************************************************************/
654
655
OGRBoolean OGRCompoundCurve::hasCurveGeometry(int bLookForNonLinear) const
656
104k
{
657
104k
    if (bLookForNonLinear)
658
24.1k
    {
659
24.1k
        return oCC.hasCurveGeometry(bLookForNonLinear);
660
24.1k
    }
661
662
80.4k
    return TRUE;
663
104k
}
664
665
/************************************************************************/
666
/*                         getLinearGeometry()                        */
667
/************************************************************************/
668
669
OGRGeometry *
670
OGRCompoundCurve::getLinearGeometry(double dfMaxAngleStepSizeDegrees,
671
                                    const char *const *papszOptions) const
672
31.4k
{
673
31.4k
    return CurveToLine(dfMaxAngleStepSizeDegrees, papszOptions);
674
31.4k
}
675
676
/************************************************************************/
677
/*                           getNumPoints()                             */
678
/************************************************************************/
679
680
int OGRCompoundCurve::getNumPoints() const
681
16.1k
{
682
16.1k
    int nPoints = 0;
683
57.4k
    for (int i = 0; i < oCC.nCurveCount; i++)
684
41.3k
    {
685
41.3k
        nPoints += oCC.papoCurves[i]->getNumPoints();
686
41.3k
        if (i != 0)
687
25.2k
            nPoints--;
688
41.3k
    }
689
16.1k
    return nPoints;
690
16.1k
}
691
692
/************************************************************************/
693
/*                      OGRCompoundCurvePointIterator                   */
694
/************************************************************************/
695
696
class OGRCompoundCurvePointIterator final : public OGRPointIterator
697
{
698
    CPL_DISALLOW_COPY_ASSIGN(OGRCompoundCurvePointIterator)
699
700
    const OGRCompoundCurve *poCC = nullptr;
701
    int iCurCurve = 0;
702
    OGRPointIterator *poCurveIter = nullptr;
703
704
  public:
705
    explicit OGRCompoundCurvePointIterator(const OGRCompoundCurve *poCCIn)
706
8.07k
        : poCC(poCCIn)
707
8.07k
    {
708
8.07k
    }
709
710
    ~OGRCompoundCurvePointIterator() override
711
8.07k
    {
712
8.07k
        delete poCurveIter;
713
8.07k
    }
714
715
    OGRBoolean getNextPoint(OGRPoint *p) override;
716
};
717
718
/************************************************************************/
719
/*                            getNextPoint()                            */
720
/************************************************************************/
721
722
OGRBoolean OGRCompoundCurvePointIterator::getNextPoint(OGRPoint *p)
723
54.1k
{
724
54.1k
    if (iCurCurve == poCC->getNumCurves())
725
0
        return FALSE;
726
54.1k
    if (poCurveIter == nullptr)
727
8.07k
        poCurveIter = poCC->getCurve(0)->getPointIterator();
728
54.1k
    if (!poCurveIter->getNextPoint(p))
729
15.3k
    {
730
15.3k
        iCurCurve++;
731
15.3k
        if (iCurCurve == poCC->getNumCurves())
732
6.95k
            return FALSE;
733
8.39k
        delete poCurveIter;
734
8.39k
        poCurveIter = poCC->getCurve(iCurCurve)->getPointIterator();
735
        // Skip first point.
736
8.39k
        return poCurveIter->getNextPoint(p) && poCurveIter->getNextPoint(p);
737
15.3k
    }
738
38.7k
    return TRUE;
739
54.1k
}
740
741
/************************************************************************/
742
/*                         getPointIterator()                           */
743
/************************************************************************/
744
745
OGRPointIterator *OGRCompoundCurve::getPointIterator() const
746
8.07k
{
747
8.07k
    return new OGRCompoundCurvePointIterator(this);
748
8.07k
}
749
750
/************************************************************************/
751
/*                         CastToLineString()                        */
752
/************************************************************************/
753
754
//! @cond Doxygen_Suppress
755
OGRLineString *OGRCompoundCurve::CastToLineString(OGRCompoundCurve *poCC)
756
1.63k
{
757
2.15k
    for (int i = 0; i < poCC->oCC.nCurveCount; i++)
758
518
    {
759
518
        poCC->oCC.papoCurves[i] =
760
518
            OGRCurve::CastToLineString(poCC->oCC.papoCurves[i]);
761
518
        if (poCC->oCC.papoCurves[i] == nullptr)
762
0
        {
763
0
            delete poCC;
764
0
            return nullptr;
765
0
        }
766
518
    }
767
768
1.63k
    if (poCC->oCC.nCurveCount == 1)
769
472
    {
770
472
        OGRLineString *poLS = poCC->oCC.papoCurves[0]->toLineString();
771
472
        poLS->assignSpatialReference(poCC->getSpatialReference());
772
472
        poCC->oCC.papoCurves[0] = nullptr;
773
472
        delete poCC;
774
472
        return poLS;
775
472
    }
776
777
1.16k
    OGRLineString *poLS = poCC->CurveToLineInternal(0, nullptr, FALSE);
778
1.16k
    delete poCC;
779
1.16k
    return poLS;
780
1.63k
}
781
782
/************************************************************************/
783
/*                           CastToLinearRing()                         */
784
/************************************************************************/
785
786
/**
787
 * \brief Cast to linear ring.
788
 *
789
 * The passed in geometry is consumed and a new one returned (or NULL in case
790
 * of failure)
791
 *
792
 * @param poCC the input geometry - ownership is passed to the method.
793
 * @return new geometry.
794
 */
795
796
OGRLinearRing *OGRCompoundCurve::CastToLinearRing(OGRCompoundCurve *poCC)
797
687
{
798
1.63k
    for (int i = 0; i < poCC->oCC.nCurveCount; i++)
799
951
    {
800
951
        poCC->oCC.papoCurves[i] =
801
951
            OGRCurve::CastToLineString(poCC->oCC.papoCurves[i]);
802
951
        if (poCC->oCC.papoCurves[i] == nullptr)
803
0
        {
804
0
            delete poCC;
805
0
            return nullptr;
806
0
        }
807
951
    }
808
809
687
    if (poCC->oCC.nCurveCount == 1)
810
271
    {
811
271
        OGRLinearRing *poLR =
812
271
            OGRCurve::CastToLinearRing(poCC->oCC.papoCurves[0]);
813
271
        if (poLR != nullptr)
814
67
        {
815
67
            poLR->assignSpatialReference(poCC->getSpatialReference());
816
67
        }
817
271
        poCC->oCC.papoCurves[0] = nullptr;
818
271
        delete poCC;
819
271
        return poLR;
820
271
    }
821
822
416
    OGRLinearRing *poLR =
823
416
        poCC->CurveToLineInternal(0, nullptr, TRUE)->toLinearRing();
824
416
    delete poCC;
825
416
    return poLR;
826
687
}
827
828
/************************************************************************/
829
/*                     GetCasterToLineString()                          */
830
/************************************************************************/
831
832
OGRLineString *OGRCompoundCurve::CasterToLineString(OGRCurve *poCurve)
833
1.63k
{
834
1.63k
    OGRCompoundCurve *poCC = poCurve->toCompoundCurve();
835
1.63k
    return OGRCompoundCurve::CastToLineString(poCC);
836
1.63k
}
837
838
OGRCurveCasterToLineString OGRCompoundCurve::GetCasterToLineString() const
839
1.63k
{
840
1.63k
    return OGRCompoundCurve::CasterToLineString;
841
1.63k
}
842
843
/************************************************************************/
844
/*                        GetCasterToLinearRing()                       */
845
/************************************************************************/
846
847
OGRLinearRing *OGRCompoundCurve::CasterToLinearRing(OGRCurve *poCurve)
848
687
{
849
687
    OGRCompoundCurve *poCC = poCurve->toCompoundCurve();
850
687
    return OGRCompoundCurve::CastToLinearRing(poCC);
851
687
}
852
853
OGRCurveCasterToLinearRing OGRCompoundCurve::GetCasterToLinearRing() const
854
687
{
855
687
    return OGRCompoundCurve::CasterToLinearRing;
856
687
}
857
858
//! @endcond
859
860
/************************************************************************/
861
/*                           get_Area()                                 */
862
/************************************************************************/
863
864
double OGRCompoundCurve::get_Area() const
865
9.50k
{
866
9.50k
    if (IsEmpty() || !get_IsClosed())
867
4.91k
        return 0;
868
869
    // Optimization for convex rings.
870
4.59k
    if (IsConvex())
871
3.47k
    {
872
        // Compute area of shape without the circular segments.
873
3.47k
        OGRPointIterator *poIter = getPointIterator();
874
3.47k
        OGRLineString oLS;
875
3.47k
        oLS.setNumPoints(getNumPoints());
876
3.47k
        OGRPoint p;
877
24.8k
        for (int i = 0; poIter->getNextPoint(&p); i++)
878
21.4k
        {
879
21.4k
            oLS.setPoint(i, p.getX(), p.getY());
880
21.4k
        }
881
3.47k
        double dfArea = oLS.get_Area();
882
3.47k
        delete poIter;
883
884
        // Add the area of the spherical segments.
885
3.47k
        dfArea += get_AreaOfCurveSegments();
886
887
3.47k
        return dfArea;
888
3.47k
    }
889
890
1.11k
    OGRLineString *poLS = CurveToLine();
891
1.11k
    double dfArea = poLS->get_Area();
892
1.11k
    delete poLS;
893
894
1.11k
    return dfArea;
895
4.59k
}
896
897
/************************************************************************/
898
/*                        get_GeodesicArea()                            */
899
/************************************************************************/
900
901
double OGRCompoundCurve::get_GeodesicArea(
902
    const OGRSpatialReference *poSRSOverride) const
903
0
{
904
0
    if (IsEmpty())
905
0
        return 0;
906
907
0
    if (!get_IsClosed())
908
0
    {
909
0
        CPLError(CE_Failure, CPLE_AppDefined, "Non-closed geometry");
910
0
        return -1;
911
0
    }
912
913
0
    if (!poSRSOverride)
914
0
        poSRSOverride = getSpatialReference();
915
916
0
    auto poLS = std::unique_ptr<OGRLineString>(CurveToLine());
917
0
    return poLS->get_GeodesicArea(poSRSOverride);
918
0
}
919
920
/************************************************************************/
921
/*                        get_GeodesicLength()                          */
922
/************************************************************************/
923
924
double OGRCompoundCurve::get_GeodesicLength(
925
    const OGRSpatialReference *poSRSOverride) const
926
0
{
927
0
    if (IsEmpty())
928
0
        return 0;
929
930
0
    if (!poSRSOverride)
931
0
        poSRSOverride = getSpatialReference();
932
933
0
    auto poLS = std::unique_ptr<OGRLineString>(CurveToLine());
934
0
    return poLS->get_GeodesicLength(poSRSOverride);
935
0
}
936
937
/************************************************************************/
938
/*                       get_AreaOfCurveSegments()                      */
939
/************************************************************************/
940
941
/** Return area of curve segments
942
 * @return area.
943
 */
944
double OGRCompoundCurve::get_AreaOfCurveSegments() const
945
3.47k
{
946
3.47k
    double dfArea = 0;
947
10.9k
    for (int i = 0; i < getNumCurves(); i++)
948
7.43k
    {
949
7.43k
        const OGRCurve *poPart = getCurve(i);
950
7.43k
        dfArea += poPart->get_AreaOfCurveSegments();
951
7.43k
    }
952
3.47k
    return dfArea;
953
3.47k
}
954
955
/************************************************************************/
956
/*                           hasEmptyParts()                            */
957
/************************************************************************/
958
959
bool OGRCompoundCurve::hasEmptyParts() const
960
0
{
961
0
    return oCC.hasEmptyParts();
962
0
}
963
964
/************************************************************************/
965
/*                          removeEmptyParts()                          */
966
/************************************************************************/
967
968
void OGRCompoundCurve::removeEmptyParts()
969
0
{
970
0
    oCC.removeEmptyParts();
971
0
}
972
973
/************************************************************************/
974
/*                           reversePoints()                            */
975
/************************************************************************/
976
977
/**
978
 * \brief Reverse point order.
979
 *
980
 * This method updates the points in this curve in place
981
 * reversing the point ordering (first for last, etc) and component ordering.
982
 *
983
 * @since 3.10
984
 */
985
void OGRCompoundCurve::reversePoints()
986
987
0
{
988
0
    oCC.reversePoints();
989
0
}