Coverage Report

Created: 2025-06-13 06:18

/src/gdal/ogr/ogr_api.cpp
Line
Count
Source (jump to first uncovered line)
1
/******************************************************************************
2
 *
3
 * Project:  OpenGIS Simple Features Reference Implementation
4
 * Purpose:  C API Functions that don't correspond one-to-one with C++
5
 *           methods, such as the "simplified" geometry access functions.
6
 * Author:   Frank Warmerdam, warmerdam@pobox.com
7
 *
8
 ******************************************************************************
9
 * Copyright (c) 2002, Frank Warmerdam
10
 * Copyright (c) 2009-2011, Even Rouault <even dot rouault at spatialys.com>
11
 *
12
 * SPDX-License-Identifier: MIT
13
 ****************************************************************************/
14
15
#include "cpl_port.h"
16
#include "ogr_api.h"
17
18
#include <cstddef>
19
20
#include "cpl_error.h"
21
#include "ogr_geometry.h"
22
#include "ogr_geos.h"
23
24
static bool bNonLinearGeometriesEnabled = true;
25
26
/************************************************************************/
27
/*                         OGRGetGEOSVersion()                          */
28
/************************************************************************/
29
30
/** \brief Get the GEOS version
31
 *
32
 * @param pnMajor Pointer to major version number, or NULL
33
 * @param pnMinor Pointer to minor version number, or NULL
34
 * @param pnPatch Pointer to patch version number, or NULL
35
 * @return TRUE if GDAL is built against GEOS
36
 * @since GDAL 3.4.0
37
 */
38
#ifdef HAVE_GEOS
39
bool OGRGetGEOSVersion(int *pnMajor, int *pnMinor, int *pnPatch)
40
{
41
    CPLStringList aosTokens(CSLTokenizeString2(GEOSversion(), ".", 0));
42
43
    if (pnMajor && aosTokens.size() > 0)
44
        *pnMajor = std::stoi(aosTokens[0]);
45
    if (pnMinor && aosTokens.size() > 1)
46
        *pnMinor = std::stoi(aosTokens[1]);
47
    if (pnPatch && aosTokens.size() > 2)
48
        *pnPatch = std::stoi(aosTokens[2]);
49
    return TRUE;
50
}
51
#else
52
bool OGRGetGEOSVersion(int *pnMajor, int *pnMinor, int *pnPatch)
53
0
{
54
0
    if (pnMajor)
55
0
        *pnMajor = 0;
56
0
    if (pnMinor)
57
0
        *pnMinor = 0;
58
0
    if (pnPatch)
59
0
        *pnPatch = 0;
60
0
    return FALSE;
61
0
}
62
#endif
63
64
/************************************************************************/
65
/*                           ToPointer()                                */
66
/************************************************************************/
67
68
static inline OGRGeometry *ToPointer(OGRGeometryH hGeom)
69
0
{
70
0
    return OGRGeometry::FromHandle(hGeom);
71
0
}
72
73
/************************************************************************/
74
/*                           ToHandle()                                 */
75
/************************************************************************/
76
77
static inline OGRGeometryH ToHandle(OGRGeometry *poGeom)
78
0
{
79
0
    return OGRGeometry::ToHandle(poGeom);
80
0
}
81
82
/************************************************************************/
83
/*                        OGR_G_GetPointCount()                         */
84
/************************************************************************/
85
/**
86
 * \brief Fetch number of points from a Point or a LineString/LinearRing
87
 * geometry.
88
 *
89
 * Only wkbPoint[25D] or wkbLineString[25D] may return a valid value.
90
 * Other geometry types will silently return 0.
91
 *
92
 * @param hGeom handle to the geometry from which to get the number of points.
93
 * @return the number of points.
94
 */
95
96
int OGR_G_GetPointCount(OGRGeometryH hGeom)
97
98
0
{
99
0
    VALIDATE_POINTER1(hGeom, "OGR_G_GetPointCount", 0);
100
101
0
    const OGRwkbGeometryType eGType =
102
0
        wkbFlatten(ToPointer(hGeom)->getGeometryType());
103
0
    if (eGType == wkbPoint)
104
0
    {
105
0
        return 1;
106
0
    }
107
0
    else if (OGR_GT_IsCurve(eGType))
108
0
    {
109
0
        return ToPointer(hGeom)->toCurve()->getNumPoints();
110
0
    }
111
0
    else
112
0
    {
113
        // autotest/pymod/ogrtest.py calls this method on any geometry. So keep
114
        // silent.
115
        // CPLError(CE_Failure, CPLE_NotSupported,
116
        //          "Incompatible geometry for operation");
117
0
        return 0;
118
0
    }
119
0
}
120
121
/************************************************************************/
122
/*                        OGR_G_SetPointCount()                         */
123
/************************************************************************/
124
/**
125
 * \brief Set number of points in a geometry.
126
 *
127
 * This method primary exists to preset the number of points in a linestring
128
 * geometry before setPoint() is used to assign them to avoid reallocating
129
 * the array larger with each call to addPoint().
130
 *
131
 * @param hGeom handle to the geometry.
132
 * @param nNewPointCount the new number of points for geometry.
133
 */
134
135
void OGR_G_SetPointCount(OGRGeometryH hGeom, int nNewPointCount)
136
137
0
{
138
0
    VALIDATE_POINTER0(hGeom, "OGR_G_SetPointCount");
139
140
0
    switch (wkbFlatten(ToPointer(hGeom)->getGeometryType()))
141
0
    {
142
0
        case wkbLineString:
143
0
        case wkbCircularString:
144
0
        {
145
0
            OGRSimpleCurve *poSC = ToPointer(hGeom)->toSimpleCurve();
146
0
            poSC->setNumPoints(nNewPointCount);
147
0
            break;
148
0
        }
149
0
        default:
150
0
            CPLError(CE_Failure, CPLE_NotSupported,
151
0
                     "Incompatible geometry for operation");
152
0
            break;
153
0
    }
154
0
}
155
156
/************************************************************************/
157
/*                        OGR_G_Get_Component()                         */
158
/************************************************************************/
159
template <typename Getter>
160
static double OGR_G_Get_Component(OGRGeometryH hGeom, int i)
161
0
{
162
0
    switch (wkbFlatten(ToPointer(hGeom)->getGeometryType()))
163
0
    {
164
0
        case wkbPoint:
165
0
        {
166
0
            if (i == 0)
167
0
            {
168
0
                return Getter::get(ToPointer(hGeom)->toPoint());
169
0
            }
170
0
            else
171
0
            {
172
0
                CPLError(CE_Failure, CPLE_NotSupported,
173
0
                         "Only i == 0 is supported");
174
0
                return 0.0;
175
0
            }
176
0
        }
177
178
0
        case wkbLineString:
179
0
        case wkbCircularString:
180
0
        {
181
0
            OGRSimpleCurve *poSC = ToPointer(hGeom)->toSimpleCurve();
182
0
            if (i < 0 || i >= poSC->getNumPoints())
183
0
            {
184
0
                CPLError(CE_Failure, CPLE_NotSupported, "Index out of bounds");
185
0
                return 0.0;
186
0
            }
187
0
            return Getter::get(poSC, i);
188
0
        }
189
190
0
        default:
191
0
            CPLError(CE_Failure, CPLE_NotSupported,
192
0
                     "Incompatible geometry for operation");
193
0
            return 0.0;
194
0
    }
195
0
}
Unexecuted instantiation: ogr_api.cpp:double OGR_G_Get_Component<OGR_G_GetX::Getter>(OGRGeometryHS*, int)
Unexecuted instantiation: ogr_api.cpp:double OGR_G_Get_Component<OGR_G_GetY::Getter>(OGRGeometryHS*, int)
Unexecuted instantiation: ogr_api.cpp:double OGR_G_Get_Component<OGR_G_GetZ::Getter>(OGRGeometryHS*, int)
Unexecuted instantiation: ogr_api.cpp:double OGR_G_Get_Component<OGR_G_GetM::Getter>(OGRGeometryHS*, int)
196
197
/************************************************************************/
198
/*                             OGR_G_GetX()                             */
199
/************************************************************************/
200
/**
201
 * \brief Fetch the x coordinate of a point from a Point or a
202
 * LineString/LinearRing geometry.
203
 *
204
 * @param hGeom handle to the geometry from which to get the x coordinate.
205
 * @param i point to get the x coordinate.
206
 * @return the X coordinate of this point.
207
 */
208
209
double OGR_G_GetX(OGRGeometryH hGeom, int i)
210
211
0
{
212
0
    VALIDATE_POINTER1(hGeom, "OGR_G_GetX", 0);
213
214
0
    struct Getter
215
0
    {
216
0
        static double get(const OGRPoint *poPoint)
217
0
        {
218
0
            return poPoint->getX();
219
0
        }
220
221
0
        static double get(const OGRSimpleCurve *poSC, int l_i)
222
0
        {
223
0
            return poSC->getX(l_i);
224
0
        }
225
0
    };
226
227
0
    return OGR_G_Get_Component<Getter>(hGeom, i);
228
0
}
229
230
/************************************************************************/
231
/*                             OGR_G_GetY()                             */
232
/************************************************************************/
233
/**
234
 * \brief Fetch the x coordinate of a point from a Point or a
235
 * LineString/LinearRing geometry.
236
 *
237
 * @param hGeom handle to the geometry from which to get the y coordinate.
238
 * @param i point to get the Y coordinate.
239
 * @return the Y coordinate of this point.
240
 */
241
242
double OGR_G_GetY(OGRGeometryH hGeom, int i)
243
244
0
{
245
0
    VALIDATE_POINTER1(hGeom, "OGR_G_GetY", 0);
246
247
0
    struct Getter
248
0
    {
249
0
        static double get(const OGRPoint *poPoint)
250
0
        {
251
0
            return poPoint->getY();
252
0
        }
253
254
0
        static double get(const OGRSimpleCurve *poSC, int l_i)
255
0
        {
256
0
            return poSC->getY(l_i);
257
0
        }
258
0
    };
259
260
0
    return OGR_G_Get_Component<Getter>(hGeom, i);
261
0
}
262
263
/************************************************************************/
264
/*                             OGR_G_GetZ()                             */
265
/************************************************************************/
266
/**
267
 * \brief Fetch the z coordinate of a point from a Point or a
268
 * LineString/LinearRing geometry.
269
 *
270
 * @param hGeom handle to the geometry from which to get the Z coordinate.
271
 * @param i point to get the Z coordinate.
272
 * @return the Z coordinate of this point.
273
 */
274
275
double OGR_G_GetZ(OGRGeometryH hGeom, int i)
276
277
0
{
278
0
    VALIDATE_POINTER1(hGeom, "OGR_G_GetZ", 0);
279
280
0
    struct Getter
281
0
    {
282
0
        static double get(const OGRPoint *poPoint)
283
0
        {
284
0
            return poPoint->getZ();
285
0
        }
286
287
0
        static double get(const OGRSimpleCurve *poSC, int l_i)
288
0
        {
289
0
            return poSC->getZ(l_i);
290
0
        }
291
0
    };
292
293
0
    return OGR_G_Get_Component<Getter>(hGeom, i);
294
0
}
295
296
/************************************************************************/
297
/*                             OGR_G_GetM()                             */
298
/************************************************************************/
299
/**
300
 * \brief Fetch the m coordinate of a point from a geometry.
301
 *
302
 * @param hGeom handle to the geometry from which to get the M coordinate.
303
 * @param i point to get the M coordinate.
304
 * @return the M coordinate of this point.
305
 */
306
307
double OGR_G_GetM(OGRGeometryH hGeom, int i)
308
309
0
{
310
0
    VALIDATE_POINTER1(hGeom, "OGR_G_GetM", 0);
311
312
0
    struct Getter
313
0
    {
314
0
        static double get(const OGRPoint *poPoint)
315
0
        {
316
0
            return poPoint->getM();
317
0
        }
318
319
0
        static double get(const OGRSimpleCurve *poSC, int l_i)
320
0
        {
321
0
            return poSC->getM(l_i);
322
0
        }
323
0
    };
324
325
0
    return OGR_G_Get_Component<Getter>(hGeom, i);
326
0
}
327
328
/************************************************************************/
329
/*                          OGR_G_GetPoints()                           */
330
/************************************************************************/
331
332
/**
333
 * \brief Returns all points of line string.
334
 *
335
 * This method copies all points into user arrays. The user provides the
336
 * stride between 2 consecutive elements of the array.
337
 *
338
 * On some CPU architectures, care must be taken so that the arrays are properly
339
 * aligned.
340
 *
341
 * @param hGeom handle to the geometry from which to get the coordinates.
342
 * @param pabyX a buffer of at least (sizeof(double) * nXStride * nPointCount)
343
 * bytes, may be NULL.
344
 * @param nXStride the number of bytes between 2 elements of pabyX.
345
 * @param pabyY a buffer of at least (sizeof(double) * nYStride * nPointCount)
346
 * bytes, may be NULL.
347
 * @param nYStride the number of bytes between 2 elements of pabyY.
348
 * @param pabyZ a buffer of at last size (sizeof(double) * nZStride *
349
 * nPointCount) bytes, may be NULL.
350
 * @param nZStride the number of bytes between 2 elements of pabyZ.
351
 *
352
 * @return the number of points
353
 *
354
 * @since OGR 1.9.0
355
 */
356
357
int OGR_G_GetPoints(OGRGeometryH hGeom, void *pabyX, int nXStride, void *pabyY,
358
                    int nYStride, void *pabyZ, int nZStride)
359
0
{
360
0
    VALIDATE_POINTER1(hGeom, "OGR_G_GetPoints", 0);
361
362
0
    int ret = 0;
363
0
    switch (wkbFlatten(ToPointer(hGeom)->getGeometryType()))
364
0
    {
365
0
        case wkbPoint:
366
0
        {
367
0
            OGRPoint *poPoint = ToPointer(hGeom)->toPoint();
368
0
            if (pabyX)
369
0
                *(static_cast<double *>(pabyX)) = poPoint->getX();
370
0
            if (pabyY)
371
0
                *(static_cast<double *>(pabyY)) = poPoint->getY();
372
0
            if (pabyZ)
373
0
                *(static_cast<double *>(pabyZ)) = poPoint->getZ();
374
0
            ret = 1;
375
0
            break;
376
0
        }
377
378
0
        case wkbLineString:
379
0
        case wkbCircularString:
380
0
        {
381
0
            OGRSimpleCurve *poSC = ToPointer(hGeom)->toSimpleCurve();
382
0
            poSC->getPoints(pabyX, nXStride, pabyY, nYStride, pabyZ, nZStride);
383
0
            ret = poSC->getNumPoints();
384
0
            break;
385
0
        }
386
387
0
        default:
388
0
        {
389
0
            CPLError(CE_Failure, CPLE_NotSupported,
390
0
                     "Incompatible geometry for operation");
391
0
            break;
392
0
        }
393
0
    }
394
0
    return ret;
395
0
}
396
397
/************************************************************************/
398
/*                          OGR_G_GetPointsZM()                         */
399
/************************************************************************/
400
401
/**
402
 * \brief Returns all points of line string.
403
 *
404
 * This method copies all points into user arrays. The user provides the
405
 * stride between 2 consecutive elements of the array.
406
 *
407
 * On some CPU architectures, care must be taken so that the arrays are properly
408
 * aligned.
409
 *
410
 * @param hGeom handle to the geometry from which to get the coordinates.
411
 * @param pabyX a buffer of at least (nXStride * nPointCount)
412
 * bytes, may be NULL.
413
 * @param nXStride the number of bytes between 2 elements of pabyX.
414
 * @param pabyY a buffer of at least (nYStride * nPointCount)
415
 * bytes, may be NULL.
416
 * @param nYStride the number of bytes between 2 elements of pabyY.
417
 * @param pabyZ a buffer of at last size (nZStride *
418
 * nPointCount) bytes, may be NULL.
419
 * @param nZStride the number of bytes between 2 elements of pabyZ.
420
 * @param pabyM a buffer of at last size (nMStride *
421
 * nPointCount) bytes, may be NULL.
422
 * @param nMStride the number of bytes between 2 elements of pabyM.
423
 *
424
 * @return the number of points
425
 *
426
 * @since OGR 1.9.0
427
 */
428
429
int OGR_G_GetPointsZM(OGRGeometryH hGeom, void *pabyX, int nXStride,
430
                      void *pabyY, int nYStride, void *pabyZ, int nZStride,
431
                      void *pabyM, int nMStride)
432
0
{
433
0
    VALIDATE_POINTER1(hGeom, "OGR_G_GetPointsZM", 0);
434
435
0
    int ret = 0;
436
0
    switch (wkbFlatten(ToPointer(hGeom)->getGeometryType()))
437
0
    {
438
0
        case wkbPoint:
439
0
        {
440
0
            OGRPoint *poPoint = ToPointer(hGeom)->toPoint();
441
0
            if (pabyX)
442
0
                *static_cast<double *>(pabyX) = poPoint->getX();
443
0
            if (pabyY)
444
0
                *static_cast<double *>(pabyY) = poPoint->getY();
445
0
            if (pabyZ)
446
0
                *static_cast<double *>(pabyZ) = poPoint->getZ();
447
0
            if (pabyM)
448
0
                *static_cast<double *>(pabyM) = poPoint->getM();
449
0
            ret = 1;
450
0
            break;
451
0
        }
452
453
0
        case wkbLineString:
454
0
        case wkbCircularString:
455
0
        {
456
0
            OGRSimpleCurve *poSC = ToPointer(hGeom)->toSimpleCurve();
457
0
            poSC->getPoints(pabyX, nXStride, pabyY, nYStride, pabyZ, nZStride,
458
0
                            pabyM, nMStride);
459
0
            ret = poSC->getNumPoints();
460
0
            break;
461
0
        }
462
463
0
        default:
464
0
        {
465
0
            CPLError(CE_Failure, CPLE_NotSupported,
466
0
                     "Incompatible geometry for operation");
467
0
            break;
468
0
        }
469
0
    }
470
471
0
    return ret;
472
0
}
473
474
/************************************************************************/
475
/*                           OGR_G_GetPoint()                           */
476
/************************************************************************/
477
478
/**
479
 * \brief Fetch a point in line string or a point geometry.
480
 *
481
 * @param hGeom handle to the geometry from which to get the coordinates.
482
 * @param i the vertex to fetch, from 0 to getNumPoints()-1, zero for a point.
483
 * @param pdfX value of x coordinate.
484
 * @param pdfY value of y coordinate.
485
 * @param pdfZ value of z coordinate.
486
 */
487
488
void OGR_G_GetPoint(OGRGeometryH hGeom, int i, double *pdfX, double *pdfY,
489
                    double *pdfZ)
490
491
0
{
492
0
    VALIDATE_POINTER0(hGeom, "OGR_G_GetPoint");
493
494
0
    switch (wkbFlatten(ToPointer(hGeom)->getGeometryType()))
495
0
    {
496
0
        case wkbPoint:
497
0
        {
498
0
            if (i == 0)
499
0
            {
500
0
                OGRPoint *poPoint = ToPointer(hGeom)->toPoint();
501
0
                *pdfX = poPoint->getX();
502
0
                *pdfY = poPoint->getY();
503
0
                if (pdfZ != nullptr)
504
0
                    *pdfZ = poPoint->getZ();
505
0
            }
506
0
            else
507
0
            {
508
0
                CPLError(CE_Failure, CPLE_NotSupported,
509
0
                         "Only i == 0 is supported");
510
0
            }
511
0
        }
512
0
        break;
513
514
0
        case wkbLineString:
515
0
        case wkbCircularString:
516
0
        {
517
0
            OGRSimpleCurve *poSC = ToPointer(hGeom)->toSimpleCurve();
518
0
            if (i < 0 || i >= poSC->getNumPoints())
519
0
            {
520
0
                CPLError(CE_Failure, CPLE_NotSupported, "Index out of bounds");
521
0
                *pdfX = 0.0;
522
0
                *pdfY = 0.0;
523
0
                if (pdfZ != nullptr)
524
0
                    *pdfZ = 0.0;
525
0
            }
526
0
            else
527
0
            {
528
0
                *pdfX = poSC->getX(i);
529
0
                *pdfY = poSC->getY(i);
530
0
                if (pdfZ != nullptr)
531
0
                    *pdfZ = poSC->getZ(i);
532
0
            }
533
0
        }
534
0
        break;
535
536
0
        default:
537
0
            CPLError(CE_Failure, CPLE_NotSupported,
538
0
                     "Incompatible geometry for operation");
539
0
            break;
540
0
    }
541
0
}
542
543
/************************************************************************/
544
/*                           OGR_G_GetPointZM()                         */
545
/************************************************************************/
546
547
/**
548
 * \brief Fetch a point in line string or a point geometry.
549
 *
550
 * @param hGeom handle to the geometry from which to get the coordinates.
551
 * @param i the vertex to fetch, from 0 to getNumPoints()-1, zero for a point.
552
 * @param pdfX value of x coordinate.
553
 * @param pdfY value of y coordinate.
554
 * @param pdfZ value of z coordinate.
555
 * @param pdfM value of m coordinate.
556
 */
557
558
void OGR_G_GetPointZM(OGRGeometryH hGeom, int i, double *pdfX, double *pdfY,
559
                      double *pdfZ, double *pdfM)
560
561
0
{
562
0
    VALIDATE_POINTER0(hGeom, "OGR_G_GetPointZM");
563
564
0
    switch (wkbFlatten(ToPointer(hGeom)->getGeometryType()))
565
0
    {
566
0
        case wkbPoint:
567
0
        {
568
0
            if (i == 0)
569
0
            {
570
0
                OGRPoint *poPoint = ToPointer(hGeom)->toPoint();
571
0
                *pdfX = poPoint->getX();
572
0
                *pdfY = poPoint->getY();
573
0
                if (pdfZ != nullptr)
574
0
                    *pdfZ = poPoint->getZ();
575
0
                if (pdfM != nullptr)
576
0
                    *pdfM = poPoint->getM();
577
0
            }
578
0
            else
579
0
            {
580
0
                CPLError(CE_Failure, CPLE_NotSupported,
581
0
                         "Only i == 0 is supported");
582
0
            }
583
0
        }
584
0
        break;
585
586
0
        case wkbLineString:
587
0
        case wkbCircularString:
588
0
        {
589
0
            OGRSimpleCurve *poSC = ToPointer(hGeom)->toSimpleCurve();
590
0
            if (i < 0 || i >= poSC->getNumPoints())
591
0
            {
592
0
                CPLError(CE_Failure, CPLE_NotSupported, "Index out of bounds");
593
0
                *pdfX = 0.0;
594
0
                *pdfY = 0.0;
595
0
                if (pdfZ != nullptr)
596
0
                    *pdfZ = 0.0;
597
0
                if (pdfM != nullptr)
598
0
                    *pdfM = 0.0;
599
0
            }
600
0
            else
601
0
            {
602
0
                *pdfX = poSC->getX(i);
603
0
                *pdfY = poSC->getY(i);
604
0
                if (pdfZ != nullptr)
605
0
                    *pdfZ = poSC->getZ(i);
606
0
                if (pdfM != nullptr)
607
0
                    *pdfM = poSC->getM(i);
608
0
            }
609
0
        }
610
0
        break;
611
612
0
        default:
613
0
            CPLError(CE_Failure, CPLE_NotSupported,
614
0
                     "Incompatible geometry for operation");
615
0
            break;
616
0
    }
617
0
}
618
619
/************************************************************************/
620
/*                           OGR_G_SetPoints()                          */
621
/************************************************************************/
622
/**
623
 * \brief Assign all points in a point or a line string geometry.
624
 *
625
 * This method clear any existing points assigned to this geometry,
626
 * and assigns a whole new set.
627
 *
628
 * @param hGeom handle to the geometry to set the coordinates.
629
 * @param nPointsIn number of points being passed in padfX and padfY.
630
 * @param pabyX list of X coordinates (double values) of points being assigned.
631
 * @param nXStride the number of bytes between 2 elements of pabyX.
632
 * @param pabyY list of Y coordinates (double values) of points being assigned.
633
 * @param nYStride the number of bytes between 2 elements of pabyY.
634
 * @param pabyZ list of Z coordinates (double values) of points being assigned
635
 * (defaults to NULL for 2D objects).
636
 * @param nZStride the number of bytes between 2 elements of pabyZ.
637
 */
638
639
void CPL_DLL OGR_G_SetPoints(OGRGeometryH hGeom, int nPointsIn,
640
                             const void *pabyX, int nXStride, const void *pabyY,
641
                             int nYStride, const void *pabyZ, int nZStride)
642
643
0
{
644
0
    VALIDATE_POINTER0(hGeom, "OGR_G_SetPoints");
645
646
0
    if (pabyX == nullptr || pabyY == nullptr)
647
0
    {
648
0
        CPLError(CE_Failure, CPLE_NotSupported,
649
0
                 "pabyX == NULL || pabyY == NULL");
650
0
        return;
651
0
    }
652
653
0
    const double *const padfX = static_cast<const double *>(pabyX);
654
0
    const double *const padfY = static_cast<const double *>(pabyY);
655
0
    const double *const padfZ = static_cast<const double *>(pabyZ);
656
657
0
    switch (wkbFlatten(ToPointer(hGeom)->getGeometryType()))
658
0
    {
659
0
        case wkbPoint:
660
0
        {
661
0
            OGRPoint *poPoint = ToPointer(hGeom)->toPoint();
662
0
            poPoint->setX(*padfX);
663
0
            poPoint->setY(*padfY);
664
0
            if (pabyZ != nullptr)
665
0
                poPoint->setZ(*(padfZ));
666
0
            break;
667
0
        }
668
0
        case wkbLineString:
669
0
        case wkbCircularString:
670
0
        {
671
0
            OGRSimpleCurve *poSC = ToPointer(hGeom)->toSimpleCurve();
672
673
0
            const int nSizeDouble = static_cast<int>(sizeof(double));
674
0
            if (nXStride == nSizeDouble && nYStride == nSizeDouble &&
675
0
                ((nZStride == 0 && pabyZ == nullptr) ||
676
0
                 (nZStride == nSizeDouble && pabyZ != nullptr)))
677
0
            {
678
0
                poSC->setPoints(nPointsIn, padfX, padfY, padfZ);
679
0
            }
680
0
            else
681
0
            {
682
0
                poSC->setNumPoints(nPointsIn);
683
684
                // TODO(schwehr): Create pasX and pasY.
685
0
                for (int i = 0; i < nPointsIn; ++i)
686
0
                {
687
0
                    const double x = *reinterpret_cast<const double *>(
688
0
                        static_cast<const char *>(pabyX) + i * nXStride);
689
0
                    const double y = *reinterpret_cast<const double *>(
690
0
                        static_cast<const char *>(pabyY) + i * nYStride);
691
0
                    if (pabyZ)
692
0
                    {
693
0
                        const double z = *reinterpret_cast<const double *>(
694
0
                            static_cast<const char *>(pabyZ) + i * nZStride);
695
0
                        poSC->setPoint(i, x, y, z);
696
0
                    }
697
0
                    else
698
0
                    {
699
0
                        poSC->setPoint(i, x, y);
700
0
                    }
701
0
                }
702
0
            }
703
0
            break;
704
0
        }
705
0
        default:
706
0
            CPLError(CE_Failure, CPLE_NotSupported,
707
0
                     "Incompatible geometry for operation");
708
0
            break;
709
0
    }
710
0
}
711
712
/************************************************************************/
713
/*                           OGR_G_SetPointsZM()                        */
714
/************************************************************************/
715
/**
716
 * \brief Assign all points in a point or a line string geometry.
717
 *
718
 * This method clear any existing points assigned to this geometry,
719
 * and assigns a whole new set.
720
 *
721
 * @param hGeom handle to the geometry to set the coordinates.
722
 * @param nPointsIn number of points being passed in padfX and padfY.
723
 * @param pX list of X coordinates (double values) of points being assigned.
724
 * @param nXStride the number of bytes between 2 elements of pX.
725
 * @param pY list of Y coordinates (double values) of points being assigned.
726
 * @param nYStride the number of bytes between 2 elements of pY.
727
 * @param pZ list of Z coordinates (double values) of points being assigned
728
 * (if not NULL, upgrades the geometry to have Z coordinate).
729
 * @param nZStride the number of bytes between 2 elements of pZ.
730
 * @param pM list of M coordinates (double values) of points being assigned
731
 * (if not NULL, upgrades the geometry to have M coordinate).
732
 * @param nMStride the number of bytes between 2 elements of pM.
733
 */
734
735
void CPL_DLL OGR_G_SetPointsZM(OGRGeometryH hGeom, int nPointsIn,
736
                               const void *pX, int nXStride, const void *pY,
737
                               int nYStride, const void *pZ, int nZStride,
738
                               const void *pM, int nMStride)
739
740
0
{
741
0
    VALIDATE_POINTER0(hGeom, "OGR_G_SetPointsZM");
742
743
0
    if (pX == nullptr || pY == nullptr)
744
0
    {
745
0
        CPLError(CE_Failure, CPLE_NotSupported,
746
0
                 "pabyX == NULL || pabyY == NULL");
747
0
        return;
748
0
    }
749
750
0
    const double *const padfX = static_cast<const double *>(pX);
751
0
    const double *const padfY = static_cast<const double *>(pY);
752
0
    const double *const padfZ = static_cast<const double *>(pZ);
753
0
    const double *const padfM = static_cast<const double *>(pM);
754
0
    const char *const pabyX = static_cast<const char *>(pX);
755
0
    const char *const pabyY = static_cast<const char *>(pY);
756
0
    const char *const pabyZ = static_cast<const char *>(pZ);
757
0
    const char *const pabyM = static_cast<const char *>(pM);
758
759
0
    switch (wkbFlatten(ToPointer(hGeom)->getGeometryType()))
760
0
    {
761
0
        case wkbPoint:
762
0
        {
763
0
            OGRPoint *poPoint = ToPointer(hGeom)->toPoint();
764
0
            poPoint->setX(*padfX);
765
0
            poPoint->setY(*padfY);
766
0
            if (pabyZ)
767
0
                poPoint->setZ(*padfZ);
768
0
            if (pabyM)
769
0
                poPoint->setM(*padfM);
770
0
            break;
771
0
        }
772
0
        case wkbLineString:
773
0
        case wkbCircularString:
774
0
        {
775
0
            OGRSimpleCurve *poSC = ToPointer(hGeom)->toSimpleCurve();
776
777
0
            const int nSizeDouble = static_cast<int>(sizeof(double));
778
0
            if (nXStride == nSizeDouble && nYStride == nSizeDouble &&
779
0
                ((nZStride == 0 && padfZ == nullptr) ||
780
0
                 (nZStride == nSizeDouble && padfZ != nullptr)) &&
781
0
                ((nMStride == 0 && padfM == nullptr) ||
782
0
                 (nMStride == nSizeDouble && padfM != nullptr)))
783
0
            {
784
0
                if (!padfZ && !padfM)
785
0
                    poSC->setPoints(nPointsIn, padfX, padfY);
786
0
                else if (pabyZ && !pabyM)
787
0
                    poSC->setPoints(nPointsIn, padfX, padfY, padfZ);
788
0
                else if (!pabyZ && pabyM)
789
0
                    poSC->setPointsM(nPointsIn, padfX, padfY, padfM);
790
0
                else
791
0
                    poSC->setPoints(nPointsIn, padfX, padfY, padfZ, padfM);
792
0
            }
793
0
            else
794
0
            {
795
0
                poSC->setNumPoints(nPointsIn);
796
797
0
                if (!pabyM)
798
0
                {
799
0
                    if (!pabyZ)
800
0
                    {
801
0
                        for (int i = 0; i < nPointsIn; ++i)
802
0
                        {
803
0
                            const double x = *reinterpret_cast<const double *>(
804
0
                                pabyX + i * nXStride);
805
0
                            const double y = *reinterpret_cast<const double *>(
806
0
                                pabyY + i * nYStride);
807
0
                            poSC->setPoint(i, x, y);
808
0
                        }
809
0
                    }
810
0
                    else
811
0
                    {
812
0
                        for (int i = 0; i < nPointsIn; ++i)
813
0
                        {
814
0
                            const double x = *reinterpret_cast<const double *>(
815
0
                                pabyX + i * nXStride);
816
0
                            const double y = *reinterpret_cast<const double *>(
817
0
                                pabyY + i * nYStride);
818
0
                            const double z = *reinterpret_cast<const double *>(
819
0
                                pabyZ + i * nZStride);
820
0
                            poSC->setPoint(i, x, y, z);
821
0
                        }
822
0
                    }
823
0
                }
824
0
                else
825
0
                {
826
0
                    if (!pabyZ)
827
0
                    {
828
0
                        for (int i = 0; i < nPointsIn; ++i)
829
0
                        {
830
0
                            const double x = *reinterpret_cast<const double *>(
831
0
                                pabyX + i * nXStride);
832
0
                            const double y = *reinterpret_cast<const double *>(
833
0
                                pabyY + i * nYStride);
834
0
                            const double m = *reinterpret_cast<const double *>(
835
0
                                pabyM + i * nMStride);
836
0
                            poSC->setPointM(i, x, y, m);
837
0
                        }
838
0
                    }
839
0
                    else
840
0
                    {
841
0
                        for (int i = 0; i < nPointsIn; ++i)
842
0
                        {
843
0
                            const double x = *reinterpret_cast<const double *>(
844
0
                                pabyX + i * nXStride);
845
0
                            const double y = *reinterpret_cast<const double *>(
846
0
                                pabyY + i * nYStride);
847
0
                            const double z = *reinterpret_cast<const double *>(
848
0
                                pabyZ + i * nZStride);
849
0
                            const double m = *reinterpret_cast<const double *>(
850
0
                                pabyM + i * nMStride);
851
0
                            poSC->setPoint(i, x, y, z, m);
852
0
                        }
853
0
                    }
854
0
                }
855
0
            }
856
0
            break;
857
0
        }
858
0
        default:
859
0
            CPLError(CE_Failure, CPLE_NotSupported,
860
0
                     "Incompatible geometry for operation");
861
0
            break;
862
0
    }
863
0
}
864
865
/************************************************************************/
866
/*                           OGR_G_SetPoint()                           */
867
/************************************************************************/
868
/**
869
 * \brief Set the location of a vertex in a point or linestring geometry.
870
 *
871
 * If iPoint is larger than the number of existing
872
 * points in the linestring, the point count will be increased to
873
 * accommodate the request.
874
 *
875
 * The geometry is promoted to include a Z component, if it does not already
876
 * have one.
877
 *
878
 * @param hGeom handle to the geometry to add a vertex to.
879
 * @param i the index of the vertex to assign (zero based) or
880
 *  zero for a point.
881
 * @param dfX input X coordinate to assign.
882
 * @param dfY input Y coordinate to assign.
883
 * @param dfZ input Z coordinate to assign (defaults to zero).
884
 */
885
886
void OGR_G_SetPoint(OGRGeometryH hGeom, int i, double dfX, double dfY,
887
                    double dfZ)
888
889
0
{
890
0
    VALIDATE_POINTER0(hGeom, "OGR_G_SetPoint");
891
892
0
    switch (wkbFlatten(ToPointer(hGeom)->getGeometryType()))
893
0
    {
894
0
        case wkbPoint:
895
0
        {
896
0
            if (i == 0)
897
0
            {
898
0
                OGRPoint *poPoint = ToPointer(hGeom)->toPoint();
899
0
                poPoint->setX(dfX);
900
0
                poPoint->setY(dfY);
901
0
                poPoint->setZ(dfZ);
902
0
            }
903
0
            else
904
0
            {
905
0
                CPLError(CE_Failure, CPLE_NotSupported,
906
0
                         "Only i == 0 is supported");
907
0
            }
908
0
        }
909
0
        break;
910
911
0
        case wkbLineString:
912
0
        case wkbCircularString:
913
0
        {
914
0
            if (i < 0)
915
0
            {
916
0
                CPLError(CE_Failure, CPLE_NotSupported, "Index out of bounds");
917
0
                return;
918
0
            }
919
0
            ToPointer(hGeom)->toSimpleCurve()->setPoint(i, dfX, dfY, dfZ);
920
0
            break;
921
0
        }
922
923
0
        default:
924
0
            CPLError(CE_Failure, CPLE_NotSupported,
925
0
                     "Incompatible geometry for operation");
926
0
            break;
927
0
    }
928
0
}
929
930
/************************************************************************/
931
/*                         OGR_G_SetPoint_2D()                          */
932
/************************************************************************/
933
/**
934
 * \brief Set the location of a vertex in a point or linestring geometry.
935
 *
936
 * If iPoint is larger than the number of existing
937
 * points in the linestring, the point count will be increased to
938
 * accommodate the request.
939
 *
940
 * @param hGeom handle to the geometry to add a vertex to.
941
 * @param i the index of the vertex to assign (zero based) or
942
 *  zero for a point.
943
 * @param dfX input X coordinate to assign.
944
 * @param dfY input Y coordinate to assign.
945
 */
946
947
void OGR_G_SetPoint_2D(OGRGeometryH hGeom, int i, double dfX, double dfY)
948
949
0
{
950
0
    VALIDATE_POINTER0(hGeom, "OGR_G_SetPoint_2D");
951
952
0
    switch (wkbFlatten(ToPointer(hGeom)->getGeometryType()))
953
0
    {
954
0
        case wkbPoint:
955
0
        {
956
0
            if (i == 0)
957
0
            {
958
0
                OGRPoint *poPoint = ToPointer(hGeom)->toPoint();
959
0
                poPoint->setX(dfX);
960
0
                poPoint->setY(dfY);
961
0
            }
962
0
            else
963
0
            {
964
0
                CPLError(CE_Failure, CPLE_NotSupported,
965
0
                         "Only i == 0 is supported");
966
0
            }
967
0
        }
968
0
        break;
969
970
0
        case wkbLineString:
971
0
        case wkbCircularString:
972
0
        {
973
0
            if (i < 0)
974
0
            {
975
0
                CPLError(CE_Failure, CPLE_NotSupported, "Index out of bounds");
976
0
                return;
977
0
            }
978
0
            ToPointer(hGeom)->toSimpleCurve()->setPoint(i, dfX, dfY);
979
0
            break;
980
0
        }
981
982
0
        default:
983
0
            CPLError(CE_Failure, CPLE_NotSupported,
984
0
                     "Incompatible geometry for operation");
985
0
            break;
986
0
    }
987
0
}
988
989
/************************************************************************/
990
/*                           OGR_G_SetPointM()                          */
991
/************************************************************************/
992
/**
993
 * \brief Set the location of a vertex in a point or linestring geometry.
994
 *
995
 * If iPoint is larger than the number of existing
996
 * points in the linestring, the point count will be increased to
997
 * accommodate the request.
998
 *
999
 * The geometry is promoted to include a M component, if it does not already
1000
 * have one.
1001
 *
1002
 * @param hGeom handle to the geometry to add a vertex to.
1003
 * @param i the index of the vertex to assign (zero based) or
1004
 *  zero for a point.
1005
 * @param dfX input X coordinate to assign.
1006
 * @param dfY input Y coordinate to assign.
1007
 * @param dfM input M coordinate to assign.
1008
 */
1009
1010
void OGR_G_SetPointM(OGRGeometryH hGeom, int i, double dfX, double dfY,
1011
                     double dfM)
1012
1013
0
{
1014
0
    VALIDATE_POINTER0(hGeom, "OGR_G_SetPointM");
1015
1016
0
    switch (wkbFlatten(ToPointer(hGeom)->getGeometryType()))
1017
0
    {
1018
0
        case wkbPoint:
1019
0
        {
1020
0
            if (i == 0)
1021
0
            {
1022
0
                OGRPoint *poPoint = ToPointer(hGeom)->toPoint();
1023
0
                poPoint->setX(dfX);
1024
0
                poPoint->setY(dfY);
1025
0
                poPoint->setM(dfM);
1026
0
            }
1027
0
            else
1028
0
            {
1029
0
                CPLError(CE_Failure, CPLE_NotSupported,
1030
0
                         "Only i == 0 is supported");
1031
0
            }
1032
0
        }
1033
0
        break;
1034
1035
0
        case wkbLineString:
1036
0
        case wkbCircularString:
1037
0
        {
1038
0
            if (i < 0)
1039
0
            {
1040
0
                CPLError(CE_Failure, CPLE_NotSupported, "Index out of bounds");
1041
0
                return;
1042
0
            }
1043
0
            ToPointer(hGeom)->toSimpleCurve()->setPointM(i, dfX, dfY, dfM);
1044
0
            break;
1045
0
        }
1046
1047
0
        default:
1048
0
            CPLError(CE_Failure, CPLE_NotSupported,
1049
0
                     "Incompatible geometry for operation");
1050
0
            break;
1051
0
    }
1052
0
}
1053
1054
/************************************************************************/
1055
/*                           OGR_G_SetPointZM()                         */
1056
/************************************************************************/
1057
/**
1058
 * \brief Set the location of a vertex in a point or linestring geometry.
1059
 *
1060
 * If iPoint is larger than the number of existing
1061
 * points in the linestring, the point count will be increased to
1062
 * accommodate the request.
1063
 *
1064
 * The geometry is promoted to include a Z and M component, if it does not
1065
 * already have them.
1066
 *
1067
 * @param hGeom handle to the geometry to add a vertex to.
1068
 * @param i the index of the vertex to assign (zero based) or
1069
 *  zero for a point.
1070
 * @param dfX input X coordinate to assign.
1071
 * @param dfY input Y coordinate to assign.
1072
 * @param dfZ input Z coordinate to assign.
1073
 * @param dfM input M coordinate to assign.
1074
 */
1075
1076
void OGR_G_SetPointZM(OGRGeometryH hGeom, int i, double dfX, double dfY,
1077
                      double dfZ, double dfM)
1078
1079
0
{
1080
0
    VALIDATE_POINTER0(hGeom, "OGR_G_SetPointZM");
1081
1082
0
    switch (wkbFlatten(ToPointer(hGeom)->getGeometryType()))
1083
0
    {
1084
0
        case wkbPoint:
1085
0
        {
1086
0
            if (i == 0)
1087
0
            {
1088
0
                OGRPoint *poPoint = ToPointer(hGeom)->toPoint();
1089
0
                poPoint->setX(dfX);
1090
0
                poPoint->setY(dfY);
1091
0
                poPoint->setZ(dfZ);
1092
0
                poPoint->setM(dfM);
1093
0
            }
1094
0
            else
1095
0
            {
1096
0
                CPLError(CE_Failure, CPLE_NotSupported,
1097
0
                         "Only i == 0 is supported");
1098
0
            }
1099
0
        }
1100
0
        break;
1101
1102
0
        case wkbLineString:
1103
0
        case wkbCircularString:
1104
0
        {
1105
0
            if (i < 0)
1106
0
            {
1107
0
                CPLError(CE_Failure, CPLE_NotSupported, "Index out of bounds");
1108
0
                return;
1109
0
            }
1110
0
            ToPointer(hGeom)->toSimpleCurve()->setPoint(i, dfX, dfY, dfZ, dfM);
1111
0
            break;
1112
0
        }
1113
1114
0
        default:
1115
0
            CPLError(CE_Failure, CPLE_NotSupported,
1116
0
                     "Incompatible geometry for operation");
1117
0
            break;
1118
0
    }
1119
0
}
1120
1121
/************************************************************************/
1122
/*                           OGR_G_AddPoint()                           */
1123
/************************************************************************/
1124
/**
1125
 * \brief Add a point to a geometry (line string or point).
1126
 *
1127
 * The vertex count of the line string is increased by one, and assigned from
1128
 * the passed location value.
1129
 *
1130
 * The geometry is promoted to include a Z component, if it does not already
1131
 * have one.
1132
 *
1133
 * @param hGeom handle to the geometry to add a point to.
1134
 * @param dfX x coordinate of point to add.
1135
 * @param dfY y coordinate of point to add.
1136
 * @param dfZ z coordinate of point to add.
1137
 */
1138
1139
void OGR_G_AddPoint(OGRGeometryH hGeom, double dfX, double dfY, double dfZ)
1140
1141
0
{
1142
0
    VALIDATE_POINTER0(hGeom, "OGR_G_AddPoint");
1143
1144
0
    switch (wkbFlatten(ToPointer(hGeom)->getGeometryType()))
1145
0
    {
1146
0
        case wkbPoint:
1147
0
        {
1148
0
            OGRPoint *poPoint = ToPointer(hGeom)->toPoint();
1149
0
            poPoint->setX(dfX);
1150
0
            poPoint->setY(dfY);
1151
0
            poPoint->setZ(dfZ);
1152
0
        }
1153
0
        break;
1154
1155
0
        case wkbLineString:
1156
0
        case wkbCircularString:
1157
0
            ToPointer(hGeom)->toSimpleCurve()->addPoint(dfX, dfY, dfZ);
1158
0
            break;
1159
1160
0
        default:
1161
0
            CPLError(CE_Failure, CPLE_NotSupported,
1162
0
                     "Incompatible geometry for operation");
1163
0
            break;
1164
0
    }
1165
0
}
1166
1167
/************************************************************************/
1168
/*                           OGR_G_AddPoint_2D()                        */
1169
/************************************************************************/
1170
/**
1171
 * \brief Add a point to a geometry (line string or point).
1172
 *
1173
 * The vertex count of the line string is increased by one, and assigned from
1174
 * the passed location value.
1175
 *
1176
 * If the geometry includes a Z or M component, the value for those components
1177
 * for the added point will be 0.
1178
 *
1179
 * @param hGeom handle to the geometry to add a point to.
1180
 * @param dfX x coordinate of point to add.
1181
 * @param dfY y coordinate of point to add.
1182
 */
1183
1184
void OGR_G_AddPoint_2D(OGRGeometryH hGeom, double dfX, double dfY)
1185
1186
0
{
1187
0
    VALIDATE_POINTER0(hGeom, "OGR_G_AddPoint_2D");
1188
1189
0
    switch (wkbFlatten(ToPointer(hGeom)->getGeometryType()))
1190
0
    {
1191
0
        case wkbPoint:
1192
0
        {
1193
0
            OGRPoint *poPoint = ToPointer(hGeom)->toPoint();
1194
0
            poPoint->setX(dfX);
1195
0
            poPoint->setY(dfY);
1196
0
        }
1197
0
        break;
1198
1199
0
        case wkbLineString:
1200
0
        case wkbCircularString:
1201
0
            ToPointer(hGeom)->toSimpleCurve()->addPoint(dfX, dfY);
1202
0
            break;
1203
1204
0
        default:
1205
0
            CPLError(CE_Failure, CPLE_NotSupported,
1206
0
                     "Incompatible geometry for operation");
1207
0
            break;
1208
0
    }
1209
0
}
1210
1211
/************************************************************************/
1212
/*                           OGR_G_AddPointM()                          */
1213
/************************************************************************/
1214
/**
1215
 * \brief Add a point to a geometry (line string or point).
1216
 *
1217
 * The vertex count of the line string is increased by one, and assigned from
1218
 * the passed location value.
1219
 *
1220
 * The geometry is promoted to include a M component, if it does not already
1221
 * have one.
1222
 *
1223
 * @param hGeom handle to the geometry to add a point to.
1224
 * @param dfX x coordinate of point to add.
1225
 * @param dfY y coordinate of point to add.
1226
 * @param dfM m coordinate of point to add.
1227
 */
1228
1229
void OGR_G_AddPointM(OGRGeometryH hGeom, double dfX, double dfY, double dfM)
1230
1231
0
{
1232
0
    VALIDATE_POINTER0(hGeom, "OGR_G_AddPointM");
1233
1234
0
    switch (wkbFlatten(ToPointer(hGeom)->getGeometryType()))
1235
0
    {
1236
0
        case wkbPoint:
1237
0
        {
1238
0
            OGRPoint *poPoint = ToPointer(hGeom)->toPoint();
1239
0
            poPoint->setX(dfX);
1240
0
            poPoint->setY(dfY);
1241
0
            poPoint->setM(dfM);
1242
0
        }
1243
0
        break;
1244
1245
0
        case wkbLineString:
1246
0
        case wkbCircularString:
1247
0
            ToPointer(hGeom)->toSimpleCurve()->addPointM(dfX, dfY, dfM);
1248
0
            break;
1249
1250
0
        default:
1251
0
            CPLError(CE_Failure, CPLE_NotSupported,
1252
0
                     "Incompatible geometry for operation");
1253
0
            break;
1254
0
    }
1255
0
}
1256
1257
/************************************************************************/
1258
/*                           OGR_G_AddPointZM()                         */
1259
/************************************************************************/
1260
/**
1261
 * \brief Add a point to a geometry (line string or point).
1262
 *
1263
 * The vertex count of the line string is increased by one, and assigned from
1264
 * the passed location value.
1265
 *
1266
 * The geometry is promoted to include a Z and M component, if it does not
1267
 * already have them.
1268
 *
1269
 * @param hGeom handle to the geometry to add a point to.
1270
 * @param dfX x coordinate of point to add.
1271
 * @param dfY y coordinate of point to add.
1272
 * @param dfZ z coordinate of point to add.
1273
 * @param dfM m coordinate of point to add.
1274
 */
1275
1276
void OGR_G_AddPointZM(OGRGeometryH hGeom, double dfX, double dfY, double dfZ,
1277
                      double dfM)
1278
1279
0
{
1280
0
    VALIDATE_POINTER0(hGeom, "OGR_G_AddPointZM");
1281
1282
0
    switch (wkbFlatten(ToPointer(hGeom)->getGeometryType()))
1283
0
    {
1284
0
        case wkbPoint:
1285
0
        {
1286
0
            OGRPoint *poPoint = ToPointer(hGeom)->toPoint();
1287
0
            poPoint->setX(dfX);
1288
0
            poPoint->setY(dfY);
1289
0
            poPoint->setZ(dfZ);
1290
0
            poPoint->setM(dfM);
1291
0
        }
1292
0
        break;
1293
1294
0
        case wkbLineString:
1295
0
        case wkbCircularString:
1296
0
            ToPointer(hGeom)->toSimpleCurve()->addPoint(dfX, dfY, dfZ, dfM);
1297
0
            break;
1298
1299
0
        default:
1300
0
            CPLError(CE_Failure, CPLE_NotSupported,
1301
0
                     "Incompatible geometry for operation");
1302
0
            break;
1303
0
    }
1304
0
}
1305
1306
/************************************************************************/
1307
/*                       OGR_G_GetGeometryCount()                       */
1308
/************************************************************************/
1309
/**
1310
 * \brief Fetch the number of elements in a geometry or number of geometries in
1311
 * container.
1312
 *
1313
 * Only geometries of type wkbPolygon[25D], wkbMultiPoint[25D],
1314
 * wkbMultiLineString[25D], wkbMultiPolygon[25D] or wkbGeometryCollection[25D]
1315
 * may return a valid value.  Other geometry types will silently return 0.
1316
 *
1317
 * For a polygon, the returned number is the number of rings (exterior ring +
1318
 * interior rings).
1319
 *
1320
 * @param hGeom single geometry or geometry container from which to get
1321
 * the number of elements.
1322
 * @return the number of elements.
1323
 */
1324
1325
int OGR_G_GetGeometryCount(OGRGeometryH hGeom)
1326
1327
0
{
1328
0
    VALIDATE_POINTER1(hGeom, "OGR_G_GetGeometryCount", 0);
1329
1330
0
    const auto poGeom = ToPointer(hGeom);
1331
0
    const OGRwkbGeometryType eType = wkbFlatten(poGeom->getGeometryType());
1332
0
    if (OGR_GT_IsSubClassOf(eType, wkbCurvePolygon))
1333
0
    {
1334
0
        if (poGeom->toCurvePolygon()->getExteriorRingCurve() == nullptr)
1335
0
            return 0;
1336
0
        else
1337
0
            return poGeom->toCurvePolygon()->getNumInteriorRings() + 1;
1338
0
    }
1339
0
    else if (OGR_GT_IsSubClassOf(eType, wkbCompoundCurve))
1340
0
    {
1341
0
        return poGeom->toCompoundCurve()->getNumCurves();
1342
0
    }
1343
0
    else if (OGR_GT_IsSubClassOf(eType, wkbGeometryCollection))
1344
0
    {
1345
0
        return poGeom->toGeometryCollection()->getNumGeometries();
1346
0
    }
1347
0
    else if (OGR_GT_IsSubClassOf(eType, wkbPolyhedralSurface))
1348
0
    {
1349
0
        return poGeom->toPolyhedralSurface()->getNumGeometries();
1350
0
    }
1351
0
    else
1352
0
    {
1353
        // autotest/pymod/ogrtest.py calls this method on any geometry. So keep
1354
        // silent.
1355
        // CPLError(CE_Failure, CPLE_NotSupported,
1356
        //          "Incompatible geometry for operation");
1357
0
        return 0;
1358
0
    }
1359
0
}
1360
1361
/************************************************************************/
1362
/*                        OGR_G_GetGeometryRef()                        */
1363
/************************************************************************/
1364
1365
/**
1366
 * \brief Fetch geometry from a geometry container.
1367
 *
1368
 * This function returns a handle to a geometry within the container.
1369
 * The returned geometry remains owned by the container, and should not be
1370
 * modified.  The handle is only valid until the next change to the
1371
 * geometry container.  Use OGR_G_Clone() to make a copy.
1372
 *
1373
 * This function relates to the SFCOM
1374
 * IGeometryCollection::get_Geometry() method.
1375
 *
1376
 * This function is the same as the CPP method
1377
 * OGRGeometryCollection::getGeometryRef().
1378
 *
1379
 * For a polygon, OGR_G_GetGeometryRef(iSubGeom) returns the exterior ring
1380
 * if iSubGeom == 0, and the interior rings for iSubGeom > 0.
1381
 *
1382
 * @param hGeom handle to the geometry container from which to get a
1383
 * geometry from.
1384
 * @param iSubGeom the index of the geometry to fetch, between 0 and
1385
 *          getNumGeometries() - 1.
1386
 * @return handle to the requested geometry.
1387
 */
1388
1389
OGRGeometryH OGR_G_GetGeometryRef(OGRGeometryH hGeom, int iSubGeom)
1390
1391
0
{
1392
0
    VALIDATE_POINTER1(hGeom, "OGR_G_GetGeometryRef", nullptr);
1393
1394
0
    const auto poGeom = ToPointer(hGeom);
1395
0
    const OGRwkbGeometryType eType = wkbFlatten(poGeom->getGeometryType());
1396
0
    if (OGR_GT_IsSubClassOf(eType, wkbCurvePolygon))
1397
0
    {
1398
0
        if (iSubGeom == 0)
1399
0
            return ToHandle(poGeom->toCurvePolygon()->getExteriorRingCurve());
1400
0
        else
1401
0
            return ToHandle(
1402
0
                poGeom->toCurvePolygon()->getInteriorRingCurve(iSubGeom - 1));
1403
0
    }
1404
0
    else if (OGR_GT_IsSubClassOf(eType, wkbCompoundCurve))
1405
0
    {
1406
0
        return ToHandle(poGeom->toCompoundCurve()->getCurve(iSubGeom));
1407
0
    }
1408
0
    else if (OGR_GT_IsSubClassOf(eType, wkbGeometryCollection))
1409
0
    {
1410
0
        return ToHandle(
1411
0
            poGeom->toGeometryCollection()->getGeometryRef(iSubGeom));
1412
0
    }
1413
0
    else if (OGR_GT_IsSubClassOf(eType, wkbPolyhedralSurface))
1414
0
    {
1415
0
        return ToHandle(
1416
0
            poGeom->toPolyhedralSurface()->getGeometryRef(iSubGeom));
1417
0
    }
1418
0
    else
1419
0
    {
1420
0
        CPLError(CE_Failure, CPLE_NotSupported,
1421
0
                 "Incompatible geometry for operation");
1422
0
        return nullptr;
1423
0
    }
1424
0
}
1425
1426
/************************************************************************/
1427
/*                         OGR_G_AddGeometry()                          */
1428
/************************************************************************/
1429
1430
/**
1431
 * \brief Add a geometry to a geometry container.
1432
 *
1433
 * Some subclasses of OGRGeometryCollection restrict the types of geometry
1434
 * that can be added, and may return an error.  The passed geometry is cloned
1435
 * to make an internal copy.
1436
 *
1437
 * There is no SFCOM analog to this method.
1438
 *
1439
 * This function is the same as the CPP method
1440
 * OGRGeometryCollection::addGeometry.
1441
 *
1442
 * For a polygon, hNewSubGeom must be a linearring. If the polygon is empty,
1443
 * the first added subgeometry will be the exterior ring. The next ones will be
1444
 * the interior rings.
1445
 *
1446
 * @param hGeom existing geometry container.
1447
 * @param hNewSubGeom geometry to add to the container.
1448
 *
1449
 * @return OGRERR_NONE if successful, or OGRERR_UNSUPPORTED_GEOMETRY_TYPE if
1450
 * the geometry type is illegal for the type of existing geometry.
1451
 */
1452
1453
OGRErr OGR_G_AddGeometry(OGRGeometryH hGeom, OGRGeometryH hNewSubGeom)
1454
1455
0
{
1456
0
    VALIDATE_POINTER1(hGeom, "OGR_G_AddGeometry", OGRERR_UNSUPPORTED_OPERATION);
1457
0
    VALIDATE_POINTER1(hNewSubGeom, "OGR_G_AddGeometry",
1458
0
                      OGRERR_UNSUPPORTED_OPERATION);
1459
1460
0
    OGRErr eErr = OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
1461
1462
0
    auto poGeom = ToPointer(hGeom);
1463
0
    auto poNewSubGeom = ToPointer(hNewSubGeom);
1464
0
    const OGRwkbGeometryType eType = wkbFlatten(poGeom->getGeometryType());
1465
0
    if (OGR_GT_IsSubClassOf(eType, wkbCurvePolygon))
1466
0
    {
1467
0
        if (OGR_GT_IsCurve(wkbFlatten(poNewSubGeom->getGeometryType())))
1468
0
            eErr = poGeom->toCurvePolygon()->addRing(poNewSubGeom->toCurve());
1469
0
    }
1470
0
    else if (OGR_GT_IsSubClassOf(eType, wkbCompoundCurve))
1471
0
    {
1472
0
        if (OGR_GT_IsCurve(wkbFlatten(poNewSubGeom->getGeometryType())))
1473
0
            eErr = poGeom->toCompoundCurve()->addCurve(poNewSubGeom->toCurve());
1474
0
    }
1475
0
    else if (OGR_GT_IsSubClassOf(eType, wkbGeometryCollection))
1476
0
    {
1477
0
        eErr = poGeom->toGeometryCollection()->addGeometry(poNewSubGeom);
1478
0
    }
1479
0
    else if (OGR_GT_IsSubClassOf(eType, wkbPolyhedralSurface))
1480
0
    {
1481
0
        eErr = poGeom->toPolyhedralSurface()->addGeometry(poNewSubGeom);
1482
0
    }
1483
1484
0
    return eErr;
1485
0
}
1486
1487
/************************************************************************/
1488
/*                     OGR_G_AddGeometryDirectly()                      */
1489
/************************************************************************/
1490
/**
1491
 * \brief Add a geometry directly to an existing geometry container.
1492
 *
1493
 * Some subclasses of OGRGeometryCollection restrict the types of geometry
1494
 * that can be added, and may return an error.  Ownership of the passed
1495
 * geometry is taken by the container rather than cloning as addGeometry()
1496
 * does.
1497
 *
1498
 * This function is the same as the CPP method
1499
 * OGRGeometryCollection::addGeometryDirectly.
1500
 *
1501
 * There is no SFCOM analog to this method.
1502
 *
1503
 * For a polygon, hNewSubGeom must be a linearring. If the polygon is empty,
1504
 * the first added subgeometry will be the exterior ring. The next ones will be
1505
 * the interior rings.
1506
 *
1507
 * @param hGeom existing geometry.
1508
 * @param hNewSubGeom geometry to add to the existing geometry.
1509
 *
1510
 * @return OGRERR_NONE if successful, or OGRERR_UNSUPPORTED_GEOMETRY_TYPE if
1511
 * the geometry type is illegal for the type of geometry container.
1512
 */
1513
1514
OGRErr OGR_G_AddGeometryDirectly(OGRGeometryH hGeom, OGRGeometryH hNewSubGeom)
1515
1516
0
{
1517
0
    VALIDATE_POINTER1(hGeom, "OGR_G_AddGeometryDirectly",
1518
0
                      OGRERR_UNSUPPORTED_OPERATION);
1519
0
    VALIDATE_POINTER1(hNewSubGeom, "OGR_G_AddGeometryDirectly",
1520
0
                      OGRERR_UNSUPPORTED_OPERATION);
1521
1522
0
    OGRErr eErr = OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
1523
1524
0
    auto poGeom = ToPointer(hGeom);
1525
0
    auto poNewSubGeom = ToPointer(hNewSubGeom);
1526
0
    const OGRwkbGeometryType eType = wkbFlatten(poGeom->getGeometryType());
1527
1528
0
    if (OGR_GT_IsSubClassOf(eType, wkbCurvePolygon))
1529
0
    {
1530
0
        if (OGR_GT_IsCurve(wkbFlatten(poNewSubGeom->getGeometryType())))
1531
0
            eErr = poGeom->toCurvePolygon()->addRingDirectly(
1532
0
                poNewSubGeom->toCurve());
1533
0
    }
1534
0
    else if (OGR_GT_IsSubClassOf(eType, wkbCompoundCurve))
1535
0
    {
1536
0
        if (OGR_GT_IsCurve(wkbFlatten(poNewSubGeom->getGeometryType())))
1537
0
            eErr = poGeom->toCompoundCurve()->addCurveDirectly(
1538
0
                poNewSubGeom->toCurve());
1539
0
    }
1540
0
    else if (OGR_GT_IsSubClassOf(eType, wkbGeometryCollection))
1541
0
    {
1542
0
        eErr =
1543
0
            poGeom->toGeometryCollection()->addGeometryDirectly(poNewSubGeom);
1544
0
    }
1545
0
    else if (OGR_GT_IsSubClassOf(eType, wkbPolyhedralSurface))
1546
0
    {
1547
0
        eErr = poGeom->toPolyhedralSurface()->addGeometryDirectly(poNewSubGeom);
1548
0
    }
1549
1550
0
    if (eErr != OGRERR_NONE)
1551
0
        delete poNewSubGeom;
1552
1553
0
    return eErr;
1554
0
}
1555
1556
/************************************************************************/
1557
/*                        OGR_G_RemoveGeometry()                        */
1558
/************************************************************************/
1559
1560
/**
1561
 * \brief Remove a geometry from an exiting geometry container.
1562
 *
1563
 * Removing a geometry will cause the geometry count to drop by one, and all
1564
 * "higher" geometries will shuffle down one in index.
1565
 *
1566
 * There is no SFCOM analog to this method.
1567
 *
1568
 * This function is the same as the CPP method
1569
 * OGRGeometryCollection::removeGeometry() for geometry collections,
1570
 * OGRCurvePolygon::removeRing() for polygons / curve polygons and
1571
 * OGRPolyhedralSurface::removeGeometry() for polyhedral surfaces and TINs.
1572
 *
1573
 * @param hGeom the existing geometry to delete from.
1574
 * @param iGeom the index of the geometry to delete.  A value of -1 is a
1575
 * special flag meaning that all geometries should be removed.
1576
 *
1577
 * @param bDelete if TRUE the geometry will be destroyed, otherwise it will
1578
 * not.  The default is TRUE as the existing geometry is considered to own the
1579
 * geometries in it.
1580
 *
1581
 * @return OGRERR_NONE if successful, or OGRERR_FAILURE if the index is
1582
 * out of range.
1583
 */
1584
1585
OGRErr OGR_G_RemoveGeometry(OGRGeometryH hGeom, int iGeom, int bDelete)
1586
1587
0
{
1588
0
    VALIDATE_POINTER1(hGeom, "OGR_G_RemoveGeometry", OGRERR_FAILURE);
1589
1590
0
    const auto poGeom = ToPointer(hGeom);
1591
0
    const OGRwkbGeometryType eType = wkbFlatten(poGeom->getGeometryType());
1592
0
    if (OGR_GT_IsSubClassOf(eType, wkbCurvePolygon))
1593
0
    {
1594
0
        return poGeom->toCurvePolygon()->removeRing(iGeom,
1595
0
                                                    CPL_TO_BOOL(bDelete));
1596
0
    }
1597
0
    else if (OGR_GT_IsSubClassOf(eType, wkbGeometryCollection))
1598
0
    {
1599
0
        return poGeom->toGeometryCollection()->removeGeometry(iGeom, bDelete);
1600
0
    }
1601
0
    else if (OGR_GT_IsSubClassOf(eType, wkbPolyhedralSurface))
1602
0
    {
1603
0
        return poGeom->toPolyhedralSurface()->removeGeometry(iGeom, bDelete);
1604
0
    }
1605
0
    else
1606
0
    {
1607
0
        return OGRERR_UNSUPPORTED_OPERATION;
1608
0
    }
1609
0
}
1610
1611
/************************************************************************/
1612
/*                           OGR_G_Length()                             */
1613
/************************************************************************/
1614
1615
/**
1616
 * \brief Compute length of a geometry.
1617
 *
1618
 * Computes the length for OGRCurve or MultiCurve objects.
1619
 * For surfaces, compute the sum of the lengths of their exterior
1620
 * and interior rings (since 3.10).
1621
 * Undefined for all other geometry types (returns zero).
1622
 *
1623
 * This function utilizes the C++ get_Length() method.
1624
 *
1625
 * @param hGeom the geometry to operate on.
1626
 * @return the length or 0.0 for unsupported geometry types.
1627
 *
1628
 * @since OGR 1.8.0
1629
 *
1630
 * @see OGR_G_GeodesicLength() for an alternative method returning lengths
1631
 * computed on the ellipsoid, and in meters.
1632
 */
1633
1634
double OGR_G_Length(OGRGeometryH hGeom)
1635
1636
0
{
1637
0
    VALIDATE_POINTER1(hGeom, "OGR_G_GetLength", 0);
1638
1639
0
    double dfLength = 0.0;
1640
1641
0
    const auto poGeom = ToPointer(hGeom);
1642
0
    const OGRwkbGeometryType eType = wkbFlatten(poGeom->getGeometryType());
1643
0
    if (OGR_GT_IsCurve(eType))
1644
0
    {
1645
0
        dfLength = poGeom->toCurve()->get_Length();
1646
0
    }
1647
0
    else if (OGR_GT_IsSurface(eType))
1648
0
    {
1649
0
        dfLength = poGeom->toSurface()->get_Length();
1650
0
    }
1651
0
    else if (OGR_GT_IsSubClassOf(eType, wkbGeometryCollection))
1652
0
    {
1653
0
        dfLength = poGeom->toGeometryCollection()->get_Length();
1654
0
    }
1655
0
    else
1656
0
    {
1657
0
        CPLError(CE_Warning, CPLE_AppDefined,
1658
0
                 "OGR_G_Length() called against a non-curve geometry type.");
1659
0
        dfLength = 0.0;
1660
0
    }
1661
1662
0
    return dfLength;
1663
0
}
1664
1665
/************************************************************************/
1666
/*                      OGR_G_GeodesicLength()                          */
1667
/************************************************************************/
1668
1669
/**
1670
 * \brief Get the length of the curve, considered as a geodesic line on the
1671
 * underlying ellipsoid of the SRS attached to the geometry.
1672
 *
1673
 * The returned length will always be in meters.
1674
 *
1675
 * <a href="https://geographiclib.sourceforge.io/html/python/geodesics.html">Geodesics</a>
1676
 * follow the shortest route on the surface of the ellipsoid.
1677
 *
1678
 * If the geometry' SRS is not a geographic one, geometries are reprojected to
1679
 * the underlying geographic SRS of the geometry' SRS.
1680
 * OGRSpatialReference::GetDataAxisToSRSAxisMapping() is honored.
1681
 *
1682
 * Note that geometries with circular arcs will be linearized in their original
1683
 * coordinate space first, so the resulting geodesic length will be an
1684
 * approximation.
1685
 *
1686
 * This function utilizes the C++ get_GeodesicLength() method.
1687
 *
1688
 * @param hGeom the geometry to operate on.
1689
 * @return the length or a negative value for unsupported geometry types.
1690
 *
1691
 * @since OGR 3.10
1692
 */
1693
1694
double OGR_G_GeodesicLength(OGRGeometryH hGeom)
1695
1696
0
{
1697
0
    VALIDATE_POINTER1(hGeom, "OGR_G_GeodesicLength", -1);
1698
1699
0
    double dfLength = 0.0;
1700
1701
0
    const auto poGeom = ToPointer(hGeom);
1702
0
    const OGRwkbGeometryType eType = wkbFlatten(poGeom->getGeometryType());
1703
0
    if (OGR_GT_IsCurve(eType))
1704
0
    {
1705
0
        dfLength = poGeom->toCurve()->get_GeodesicLength();
1706
0
    }
1707
0
    else if (OGR_GT_IsSurface(eType))
1708
0
    {
1709
0
        dfLength = poGeom->toSurface()->get_GeodesicLength();
1710
0
    }
1711
0
    else if (OGR_GT_IsSubClassOf(eType, wkbGeometryCollection))
1712
0
    {
1713
0
        dfLength = poGeom->toGeometryCollection()->get_GeodesicLength();
1714
0
    }
1715
0
    else
1716
0
    {
1717
0
        CPLError(
1718
0
            CE_Failure, CPLE_AppDefined,
1719
0
            "OGR_G_GeodesicLength() called against a non-curve geometry type.");
1720
0
        dfLength = -1.0;
1721
0
    }
1722
1723
0
    return dfLength;
1724
0
}
1725
1726
/************************************************************************/
1727
/*                           OGR_G_Area()                               */
1728
/************************************************************************/
1729
1730
/**
1731
 * \brief Compute geometry area.
1732
 *
1733
 * The returned area is a 2D Cartesian (planar) area in square units of the
1734
 * spatial reference system in use, so potentially "square degrees" for a
1735
 * geometry expressed in a geographic SRS.
1736
 *
1737
 * Computes the area for surfaces or closed curves.
1738
 * Undefined for all other geometry types (returns 0.0).
1739
 *
1740
 * This function utilizes the C++ OGRSurface::get_Area() method.
1741
 *
1742
 * @param hGeom the geometry to operate on.
1743
 * @return the area of the geometry in square units of the spatial reference
1744
 * system in use, or 0.0 for unsupported geometry types.
1745
1746
 * @see OGR_G_GeodesicArea() for an alternative function returning areas
1747
 * computed on the ellipsoid, and in square meters.
1748
 *
1749
 * @since OGR 1.8.0
1750
 */
1751
1752
double OGR_G_Area(OGRGeometryH hGeom)
1753
1754
0
{
1755
0
    VALIDATE_POINTER1(hGeom, "OGR_G_Area", 0);
1756
1757
0
    double dfArea = 0.0;
1758
1759
0
    const auto poGeom = ToPointer(hGeom);
1760
0
    const OGRwkbGeometryType eType = wkbFlatten(poGeom->getGeometryType());
1761
0
    if (OGR_GT_IsSurface(eType))
1762
0
    {
1763
0
        dfArea = poGeom->toSurface()->get_Area();
1764
0
    }
1765
0
    else if (OGR_GT_IsCurve(eType))
1766
0
    {
1767
0
        dfArea = poGeom->toCurve()->get_Area();
1768
0
    }
1769
0
    else if (OGR_GT_IsSubClassOf(eType, wkbGeometryCollection))
1770
0
    {
1771
0
        dfArea = poGeom->toGeometryCollection()->get_Area();
1772
0
    }
1773
0
    else
1774
0
    {
1775
0
        CPLError(CE_Warning, CPLE_AppDefined,
1776
0
                 "OGR_G_Area() called against non-surface geometry type.");
1777
1778
0
        dfArea = 0.0;
1779
0
    }
1780
1781
0
    return dfArea;
1782
0
}
1783
1784
/**
1785
 * \brief Compute geometry area (deprecated)
1786
 *
1787
 * @deprecated
1788
 * @see OGR_G_Area()
1789
 */
1790
double OGR_G_GetArea(OGRGeometryH hGeom)
1791
1792
0
{
1793
0
    return OGR_G_Area(hGeom);
1794
0
}
1795
1796
/************************************************************************/
1797
/*                         OGR_G_GeodesicArea()                         */
1798
/************************************************************************/
1799
1800
/**
1801
 * \brief Compute geometry area, considered as a surface on the underlying
1802
 * ellipsoid of the SRS attached to the geometry.
1803
 *
1804
 * The returned area will always be in square meters, and assumes that
1805
 * polygon edges describe geodesic lines on the ellipsoid.
1806
 *
1807
 * <a href="https://geographiclib.sourceforge.io/html/python/geodesics.html">Geodesics</a>
1808
 * follow the shortest route on the surface of the ellipsoid.
1809
 *
1810
 * If the geometry' SRS is not a geographic one, geometries are reprojected to
1811
 * the underlying geographic SRS of the geometry' SRS.
1812
 * OGRSpatialReference::GetDataAxisToSRSAxisMapping() is honored.
1813
 *
1814
 * Computes the area for surfaces or closed curves.
1815
 * Undefined for all other geometry types (returns a negative value).
1816
 *
1817
 * Note that geometries with circular arcs will be linearized in their original
1818
 * coordinate space first, so the resulting geodesic area will be an
1819
 * approximation.
1820
 *
1821
 * This function utilizes the C++ OGRSurface::get_GeodesicArea() method.
1822
 *
1823
 * @param hGeom the geometry to operate on.
1824
 * @return the area, or a negative value in case of error (unsupported geometry
1825
 * type, no SRS attached, etc.)
1826
 *
1827
 * @see OGR_G_Area() for an alternative method returning areas computed in
1828
 * 2D Cartesian space.
1829
 *
1830
 * @since OGR 3.9.0
1831
 */
1832
1833
double OGR_G_GeodesicArea(OGRGeometryH hGeom)
1834
1835
0
{
1836
0
    VALIDATE_POINTER1(hGeom, "OGR_G_GeodesicArea", -1);
1837
1838
0
    double dfArea = -1;
1839
1840
0
    const auto poGeom = ToPointer(hGeom);
1841
0
    const OGRwkbGeometryType eType = wkbFlatten(poGeom->getGeometryType());
1842
0
    if (OGR_GT_IsSurface(eType))
1843
0
    {
1844
0
        dfArea = poGeom->toSurface()->get_GeodesicArea();
1845
0
    }
1846
0
    else if (OGR_GT_IsCurve(eType))
1847
0
    {
1848
0
        dfArea = poGeom->toCurve()->get_GeodesicArea();
1849
0
    }
1850
0
    else if (OGR_GT_IsSubClassOf(eType, wkbGeometryCollection))
1851
0
    {
1852
0
        dfArea = poGeom->toGeometryCollection()->get_GeodesicArea();
1853
0
    }
1854
0
    else
1855
0
    {
1856
0
        CPLError(CE_Failure, CPLE_AppDefined,
1857
0
                 "OGR_G_GeodesicArea() called against non-surface geometry "
1858
0
                 "type.");
1859
0
    }
1860
1861
0
    return dfArea;
1862
0
}
1863
1864
/************************************************************************/
1865
/*                         OGR_G_IsClockwise()                          */
1866
/************************************************************************/
1867
/**
1868
 * \brief Returns true if the ring has clockwise winding (or less than 2 points)
1869
 *
1870
 * Assumes that the ring is closed.
1871
 *
1872
 * @param hGeom handle to a curve geometry
1873
 * @since GDAL 3.8
1874
 */
1875
1876
bool OGR_G_IsClockwise(OGRGeometryH hGeom)
1877
1878
0
{
1879
0
    VALIDATE_POINTER1(hGeom, "OGR_G_IsClockwise", false);
1880
1881
0
    auto poGeom = OGRGeometry::FromHandle(hGeom);
1882
0
    const OGRwkbGeometryType eGType = wkbFlatten(poGeom->getGeometryType());
1883
0
    if (OGR_GT_IsCurve(eGType))
1884
0
    {
1885
0
        return poGeom->toCurve()->isClockwise();
1886
0
    }
1887
0
    else
1888
0
    {
1889
0
        CPLError(CE_Failure, CPLE_NotSupported,
1890
0
                 "Incompatible geometry for operation");
1891
0
        return false;
1892
0
    }
1893
0
}
1894
1895
/************************************************************************/
1896
/*                         OGR_G_HasCurveGeometry()                     */
1897
/************************************************************************/
1898
1899
/**
1900
 * \brief Returns if this geometry is or has curve geometry.
1901
 *
1902
 * Returns if a geometry is or has CIRCULARSTRING, COMPOUNDCURVE, CURVEPOLYGON,
1903
 * MULTICURVE or MULTISURFACE in it.
1904
 *
1905
 * If bLookForNonLinear is set to TRUE, it will be actually looked if the
1906
 * geometry or its subgeometries are or contain a non-linear geometry in
1907
 * them. In which case, if the method returns TRUE, it means that
1908
 * OGR_G_GetLinearGeometry() would return an approximate version of the
1909
 * geometry. Otherwise, OGR_G_GetLinearGeometry() would do a conversion, but
1910
 * with just converting container type, like COMPOUNDCURVE -> LINESTRING,
1911
 * MULTICURVE -> MULTILINESTRING or MULTISURFACE -> MULTIPOLYGON, resulting in a
1912
 * "loss-less" conversion.
1913
 *
1914
 * This function is the same as C++ method OGRGeometry::hasCurveGeometry().
1915
 *
1916
 * @param hGeom the geometry to operate on.
1917
 * @param bLookForNonLinear set it to TRUE to check if the geometry is or
1918
 * contains a CIRCULARSTRING.
1919
 * @return TRUE if this geometry is or has curve geometry.
1920
 *
1921
 * @since GDAL 2.0
1922
 */
1923
1924
int OGR_G_HasCurveGeometry(OGRGeometryH hGeom, int bLookForNonLinear)
1925
0
{
1926
0
    VALIDATE_POINTER1(hGeom, "OGR_G_HasCurveGeometry", FALSE);
1927
0
    return ToPointer(hGeom)->hasCurveGeometry(bLookForNonLinear);
1928
0
}
1929
1930
/************************************************************************/
1931
/*                         OGR_G_GetLinearGeometry()                   */
1932
/************************************************************************/
1933
1934
/**
1935
 * \brief Return, possibly approximate, linear version of this geometry.
1936
 *
1937
 * Returns a geometry that has no CIRCULARSTRING, COMPOUNDCURVE, CURVEPOLYGON,
1938
 * MULTICURVE or MULTISURFACE in it, by approximating curve geometries.
1939
 *
1940
 * The ownership of the returned geometry belongs to the caller.
1941
 *
1942
 * The reverse function is OGR_G_GetCurveGeometry().
1943
 *
1944
 * This method relates to the ISO SQL/MM Part 3 ICurve::CurveToLine() and
1945
 * CurvePolygon::CurvePolyToPoly() methods.
1946
 *
1947
 * This function is the same as C++ method OGRGeometry::getLinearGeometry().
1948
 *
1949
 * @param hGeom the geometry to operate on.
1950
 * @param dfMaxAngleStepSizeDegrees the largest step in degrees along the
1951
 * arc, zero to use the default setting.
1952
 * @param papszOptions options as a null-terminated list of strings or NULL.
1953
 * See OGRGeometryFactory::curveToLineString() for valid options.
1954
 *
1955
 * @return a new geometry.
1956
 *
1957
 * @since GDAL 2.0
1958
 */
1959
1960
OGRGeometryH CPL_DLL OGR_G_GetLinearGeometry(OGRGeometryH hGeom,
1961
                                             double dfMaxAngleStepSizeDegrees,
1962
                                             char **papszOptions)
1963
0
{
1964
0
    VALIDATE_POINTER1(hGeom, "OGR_G_GetLinearGeometry", nullptr);
1965
0
    return ToHandle(ToPointer(hGeom)->getLinearGeometry(
1966
0
        dfMaxAngleStepSizeDegrees, papszOptions));
1967
0
}
1968
1969
/************************************************************************/
1970
/*                         OGR_G_GetCurveGeometry()                     */
1971
/************************************************************************/
1972
1973
/**
1974
 * \brief Return curve version of this geometry.
1975
 *
1976
 * Returns a geometry that has possibly CIRCULARSTRING, COMPOUNDCURVE,
1977
 * CURVEPOLYGON, MULTICURVE or MULTISURFACE in it, by de-approximating linear
1978
 * into curve geometries.
1979
 *
1980
 * If the geometry has no curve portion, the returned geometry will be a clone
1981
 * of it.
1982
 *
1983
 * The ownership of the returned geometry belongs to the caller.
1984
 *
1985
 * The reverse function is OGR_G_GetLinearGeometry().
1986
 *
1987
 * This function is the same as C++ method OGRGeometry::getCurveGeometry().
1988
 *
1989
 * @param hGeom the geometry to operate on.
1990
 * @param papszOptions options as a null-terminated list of strings.
1991
 *                     Unused for now. Must be set to NULL.
1992
 *
1993
 * @return a new geometry.
1994
 *
1995
 * @since GDAL 2.0
1996
 */
1997
1998
OGRGeometryH CPL_DLL OGR_G_GetCurveGeometry(OGRGeometryH hGeom,
1999
                                            char **papszOptions)
2000
0
{
2001
0
    VALIDATE_POINTER1(hGeom, "OGR_G_GetCurveGeometry", nullptr);
2002
2003
0
    return ToHandle(ToPointer(hGeom)->getCurveGeometry(papszOptions));
2004
0
}
2005
2006
/************************************************************************/
2007
/*                          OGR_G_Value()                               */
2008
/************************************************************************/
2009
/**
2010
 * \brief Fetch point at given distance along curve.
2011
 *
2012
 * This function relates to the SF COM ICurve::get_Value() method.
2013
 *
2014
 * This function is the same as the C++ method OGRCurve::Value().
2015
 *
2016
 * @param hGeom curve geometry.
2017
 * @param dfDistance distance along the curve at which to sample position.
2018
 *                   This distance should be between zero and get_Length()
2019
 *                   for this curve.
2020
 * @return a point or NULL.
2021
 *
2022
 * @since GDAL 2.0
2023
 */
2024
2025
OGRGeometryH OGR_G_Value(OGRGeometryH hGeom, double dfDistance)
2026
0
{
2027
0
    VALIDATE_POINTER1(hGeom, "OGR_G_Value", nullptr);
2028
2029
0
    const auto poGeom = ToPointer(hGeom);
2030
0
    if (OGR_GT_IsCurve(poGeom->getGeometryType()))
2031
0
    {
2032
0
        OGRPoint *p = new OGRPoint();
2033
0
        poGeom->toCurve()->Value(dfDistance, p);
2034
0
        return ToHandle(p);
2035
0
    }
2036
2037
0
    return nullptr;
2038
0
}
2039
2040
/************************************************************************/
2041
/*                 OGRSetNonLinearGeometriesEnabledFlag()               */
2042
/************************************************************************/
2043
2044
/**
2045
 * \brief Set flag to enable/disable returning non-linear geometries in the C
2046
 * API.
2047
 *
2048
 * This flag has only an effect on the OGR_F_GetGeometryRef(),
2049
 * OGR_F_GetGeomFieldRef(), OGR_L_GetGeomType(), OGR_GFld_GetType() and
2050
 * OGR_FD_GetGeomType() C API, and corresponding methods in the SWIG
2051
 * bindings. It is meant as making it simple for applications using the OGR C
2052
 * API not to have to deal with non-linear geometries, even if such geometries
2053
 * might be returned by drivers. In which case, they will be transformed into
2054
 * their closest linear geometry, by doing linear approximation, with
2055
 * OGR_G_ForceTo().
2056
 *
2057
 * Libraries should generally *not* use that method, since that could interfere
2058
 * with other libraries or applications.
2059
 *
2060
 * Note that it *does* not affect the behavior of the C++ API.
2061
 *
2062
 * @param bFlag TRUE if non-linear geometries might be returned (default value).
2063
 *              FALSE to ask for non-linear geometries to be approximated as
2064
 *              linear geometries.
2065
 *
2066
 * @since GDAL 2.0
2067
 */
2068
2069
void OGRSetNonLinearGeometriesEnabledFlag(int bFlag)
2070
0
{
2071
0
    bNonLinearGeometriesEnabled = bFlag != FALSE;
2072
0
}
2073
2074
/************************************************************************/
2075
/*                 OGRGetNonLinearGeometriesEnabledFlag()               */
2076
/************************************************************************/
2077
2078
/**
2079
 * \brief Get flag to enable/disable returning non-linear geometries in the C
2080
 * API.
2081
 *
2082
 * return TRUE if non-linear geometries might be returned (default value is
2083
 * TRUE).
2084
 *
2085
 * @since GDAL 2.0
2086
 * @see OGRSetNonLinearGeometriesEnabledFlag()
2087
 */
2088
2089
int OGRGetNonLinearGeometriesEnabledFlag(void)
2090
0
{
2091
0
    return bNonLinearGeometriesEnabled;
2092
0
}