Coverage Report

Created: 2026-07-14 06:21

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