Coverage Report

Created: 2026-02-14 06:52

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
53.9k
{
70
53.9k
    return OGRGeometry::FromHandle(hGeom);
71
53.9k
}
72
73
/************************************************************************/
74
/*                              ToHandle()                              */
75
/************************************************************************/
76
77
static inline OGRGeometryH ToHandle(OGRGeometry *poGeom)
78
6.53k
{
79
6.53k
    return OGRGeometry::ToHandle(poGeom);
80
6.53k
}
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
2.61k
{
99
2.61k
    VALIDATE_POINTER1(hGeom, "OGR_G_GetPointCount", 0);
100
101
2.61k
    const OGRwkbGeometryType eGType =
102
2.61k
        wkbFlatten(ToPointer(hGeom)->getGeometryType());
103
2.61k
    if (eGType == wkbPoint)
104
0
    {
105
0
        return 1;
106
0
    }
107
2.61k
    else if (OGR_GT_IsCurve(eGType))
108
2.61k
    {
109
2.61k
        return ToPointer(hGeom)->toCurve()->getNumPoints();
110
2.61k
    }
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
2.61k
}
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
16.8k
{
167
16.8k
    switch (wkbFlatten(ToPointer(hGeom)->getGeometryType()))
168
16.8k
    {
169
7.90k
        case wkbPoint:
170
7.90k
        {
171
7.90k
            if (i == 0)
172
7.90k
            {
173
7.90k
                return Getter::get(ToPointer(hGeom)->toPoint());
174
7.90k
            }
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
7.90k
        }
182
183
8.92k
        case wkbLineString:
184
8.92k
        case wkbCircularString:
185
8.92k
        {
186
8.92k
            OGRSimpleCurve *poSC = ToPointer(hGeom)->toSimpleCurve();
187
8.92k
            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
8.92k
            return Getter::get(poSC, i);
193
8.92k
        }
194
195
0
        default:
196
0
            CPLError(CE_Failure, CPLE_NotSupported,
197
0
                     "Incompatible geometry for operation");
198
0
            return 0.0;
199
16.8k
    }
200
16.8k
}
ogr_api.cpp:double OGR_G_Get_Component<OGR_G_GetX::Getter>(OGRGeometryHS*, int)
Line
Count
Source
166
7.09k
{
167
7.09k
    switch (wkbFlatten(ToPointer(hGeom)->getGeometryType()))
168
7.09k
    {
169
2.63k
        case wkbPoint:
170
2.63k
        {
171
2.63k
            if (i == 0)
172
2.63k
            {
173
2.63k
                return Getter::get(ToPointer(hGeom)->toPoint());
174
2.63k
            }
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
2.63k
        }
182
183
4.46k
        case wkbLineString:
184
4.46k
        case wkbCircularString:
185
4.46k
        {
186
4.46k
            OGRSimpleCurve *poSC = ToPointer(hGeom)->toSimpleCurve();
187
4.46k
            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
4.46k
            return Getter::get(poSC, i);
193
4.46k
        }
194
195
0
        default:
196
0
            CPLError(CE_Failure, CPLE_NotSupported,
197
0
                     "Incompatible geometry for operation");
198
0
            return 0.0;
199
7.09k
    }
200
7.09k
}
ogr_api.cpp:double OGR_G_Get_Component<OGR_G_GetY::Getter>(OGRGeometryHS*, int)
Line
Count
Source
166
7.09k
{
167
7.09k
    switch (wkbFlatten(ToPointer(hGeom)->getGeometryType()))
168
7.09k
    {
169
2.63k
        case wkbPoint:
170
2.63k
        {
171
2.63k
            if (i == 0)
172
2.63k
            {
173
2.63k
                return Getter::get(ToPointer(hGeom)->toPoint());
174
2.63k
            }
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
2.63k
        }
182
183
4.46k
        case wkbLineString:
184
4.46k
        case wkbCircularString:
185
4.46k
        {
186
4.46k
            OGRSimpleCurve *poSC = ToPointer(hGeom)->toSimpleCurve();
187
4.46k
            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
4.46k
            return Getter::get(poSC, i);
193
4.46k
        }
194
195
0
        default:
196
0
            CPLError(CE_Failure, CPLE_NotSupported,
197
0
                     "Incompatible geometry for operation");
198
0
            return 0.0;
199
7.09k
    }
200
7.09k
}
ogr_api.cpp:double OGR_G_Get_Component<OGR_G_GetZ::Getter>(OGRGeometryHS*, int)
Line
Count
Source
166
2.63k
{
167
2.63k
    switch (wkbFlatten(ToPointer(hGeom)->getGeometryType()))
168
2.63k
    {
169
2.63k
        case wkbPoint:
170
2.63k
        {
171
2.63k
            if (i == 0)
172
2.63k
            {
173
2.63k
                return Getter::get(ToPointer(hGeom)->toPoint());
174
2.63k
            }
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
2.63k
        }
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
2.63k
    }
200
2.63k
}
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
7.09k
{
217
7.09k
    VALIDATE_POINTER1(hGeom, "OGR_G_GetX", 0);
218
219
7.09k
    struct Getter
220
7.09k
    {
221
7.09k
        static double get(const OGRPoint *poPoint)
222
7.09k
        {
223
2.63k
            return poPoint->getX();
224
2.63k
        }
225
226
7.09k
        static double get(const OGRSimpleCurve *poSC, int l_i)
227
7.09k
        {
228
4.46k
            return poSC->getX(l_i);
229
4.46k
        }
230
7.09k
    };
231
232
7.09k
    return OGR_G_Get_Component<Getter>(hGeom, i);
233
7.09k
}
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
7.09k
{
250
7.09k
    VALIDATE_POINTER1(hGeom, "OGR_G_GetY", 0);
251
252
7.09k
    struct Getter
253
7.09k
    {
254
7.09k
        static double get(const OGRPoint *poPoint)
255
7.09k
        {
256
2.63k
            return poPoint->getY();
257
2.63k
        }
258
259
7.09k
        static double get(const OGRSimpleCurve *poSC, int l_i)
260
7.09k
        {
261
4.46k
            return poSC->getY(l_i);
262
4.46k
        }
263
7.09k
    };
264
265
7.09k
    return OGR_G_Get_Component<Getter>(hGeom, i);
266
7.09k
}
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
2.63k
{
283
2.63k
    VALIDATE_POINTER1(hGeom, "OGR_G_GetZ", 0);
284
285
2.63k
    struct Getter
286
2.63k
    {
287
2.63k
        static double get(const OGRPoint *poPoint)
288
2.63k
        {
289
2.63k
            return poPoint->getZ();
290
2.63k
        }
291
292
2.63k
        static double get(const OGRSimpleCurve *poSC, int l_i)
293
2.63k
        {
294
0
            return poSC->getZ(l_i);
295
0
        }
296
2.63k
    };
297
298
2.63k
    return OGR_G_Get_Component<Getter>(hGeom, i);
299
2.63k
}
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
862
{
365
862
    VALIDATE_POINTER1(hGeom, "OGR_G_GetPoints", 0);
366
367
862
    int ret = 0;
368
862
    switch (wkbFlatten(ToPointer(hGeom)->getGeometryType()))
369
862
    {
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
862
        case wkbLineString:
384
862
        case wkbCircularString:
385
862
        {
386
862
            OGRSimpleCurve *poSC = ToPointer(hGeom)->toSimpleCurve();
387
862
            poSC->getPoints(pabyX, nXStride, pabyY, nYStride, pabyZ, nZStride);
388
862
            ret = poSC->getNumPoints();
389
862
            break;
390
862
        }
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
862
        }
399
862
    }
400
862
    return ret;
401
862
}
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,
947
0
                                                               dfZ);
948
0
        }
949
950
0
        default:
951
0
            CPLError(CE_Failure, CPLE_NotSupported,
952
0
                     "Incompatible geometry for operation");
953
0
            return OGRERR_FAILURE;
954
0
    }
955
956
0
    return OGRERR_NONE;
957
0
}
958
959
/************************************************************************/
960
/*                         OGR_G_SetPoint_2D()                          */
961
/************************************************************************/
962
/**
963
 * \brief Set the location of a vertex in a point or linestring geometry.
964
 *
965
 * If iPoint is larger than the number of existing
966
 * points in the linestring, the point count will be increased to
967
 * accommodate the request.
968
 *
969
 * @param hGeom handle to the geometry to add a vertex to.
970
 * @param i the index of the vertex to assign (zero based) or
971
 *  zero for a point.
972
 * @param dfX input X coordinate to assign.
973
 * @param dfY input Y coordinate to assign.
974
 *
975
 * @return (since 3.13) OGRERR_NONE in case of success, OGRERR_FAILURE in case
976
 * of error.
977
 */
978
979
OGRErr OGR_G_SetPoint_2D(OGRGeometryH hGeom, int i, double dfX, double dfY)
980
981
0
{
982
0
    VALIDATE_POINTER1(hGeom, "OGR_G_SetPoint_2D", OGRERR_FAILURE);
983
984
0
    switch (wkbFlatten(ToPointer(hGeom)->getGeometryType()))
985
0
    {
986
0
        case wkbPoint:
987
0
        {
988
0
            if (i == 0)
989
0
            {
990
0
                OGRPoint *poPoint = ToPointer(hGeom)->toPoint();
991
0
                poPoint->setX(dfX);
992
0
                poPoint->setY(dfY);
993
0
            }
994
0
            else
995
0
            {
996
0
                CPLError(CE_Failure, CPLE_NotSupported,
997
0
                         "Only i == 0 is supported");
998
0
                return OGRERR_FAILURE;
999
0
            }
1000
0
        }
1001
0
        break;
1002
1003
0
        case wkbLineString:
1004
0
        case wkbCircularString:
1005
0
        {
1006
0
            if (i < 0)
1007
0
            {
1008
0
                CPLError(CE_Failure, CPLE_NotSupported, "Index out of bounds");
1009
0
                return OGRERR_FAILURE;
1010
0
            }
1011
0
            return ToPointer(hGeom)->toSimpleCurve()->setPoint(i, dfX, dfY);
1012
0
        }
1013
1014
0
        default:
1015
0
            CPLError(CE_Failure, CPLE_NotSupported,
1016
0
                     "Incompatible geometry for operation");
1017
0
            return OGRERR_FAILURE;
1018
0
    }
1019
1020
0
    return OGRERR_NONE;
1021
0
}
1022
1023
/************************************************************************/
1024
/*                          OGR_G_SetPointM()                           */
1025
/************************************************************************/
1026
/**
1027
 * \brief Set the location of a vertex in a point or linestring geometry.
1028
 *
1029
 * If iPoint is larger than the number of existing
1030
 * points in the linestring, the point count will be increased to
1031
 * accommodate the request.
1032
 *
1033
 * The geometry is promoted to include a M component, if it does not already
1034
 * have one.
1035
 *
1036
 * @param hGeom handle to the geometry to add a vertex to.
1037
 * @param i the index of the vertex to assign (zero based) or
1038
 *  zero for a point.
1039
 * @param dfX input X coordinate to assign.
1040
 * @param dfY input Y coordinate to assign.
1041
 * @param dfM input M coordinate to assign.
1042
 *
1043
 * @return (since 3.13) OGRERR_NONE in case of success, OGRERR_FAILURE in case
1044
 * of error.
1045
 */
1046
1047
OGRErr OGR_G_SetPointM(OGRGeometryH hGeom, int i, double dfX, double dfY,
1048
                       double dfM)
1049
1050
0
{
1051
0
    VALIDATE_POINTER1(hGeom, "OGR_G_SetPointM", OGRERR_FAILURE);
1052
1053
0
    switch (wkbFlatten(ToPointer(hGeom)->getGeometryType()))
1054
0
    {
1055
0
        case wkbPoint:
1056
0
        {
1057
0
            if (i == 0)
1058
0
            {
1059
0
                OGRPoint *poPoint = ToPointer(hGeom)->toPoint();
1060
0
                poPoint->setX(dfX);
1061
0
                poPoint->setY(dfY);
1062
0
                poPoint->setM(dfM);
1063
0
            }
1064
0
            else
1065
0
            {
1066
0
                CPLError(CE_Failure, CPLE_NotSupported,
1067
0
                         "Only i == 0 is supported");
1068
0
                return OGRERR_FAILURE;
1069
0
            }
1070
0
        }
1071
0
        break;
1072
1073
0
        case wkbLineString:
1074
0
        case wkbCircularString:
1075
0
        {
1076
0
            if (i < 0)
1077
0
            {
1078
0
                CPLError(CE_Failure, CPLE_NotSupported, "Index out of bounds");
1079
0
                return OGRERR_FAILURE;
1080
0
            }
1081
0
            return ToPointer(hGeom)->toSimpleCurve()->setPointM(i, dfX, dfY,
1082
0
                                                                dfM);
1083
0
        }
1084
1085
0
        default:
1086
0
            CPLError(CE_Failure, CPLE_NotSupported,
1087
0
                     "Incompatible geometry for operation");
1088
0
            return OGRERR_FAILURE;
1089
0
    }
1090
1091
0
    return OGRERR_NONE;
1092
0
}
1093
1094
/************************************************************************/
1095
/*                          OGR_G_SetPointZM()                          */
1096
/************************************************************************/
1097
/**
1098
 * \brief Set the location of a vertex in a point or linestring geometry.
1099
 *
1100
 * If iPoint is larger than the number of existing
1101
 * points in the linestring, the point count will be increased to
1102
 * accommodate the request.
1103
 *
1104
 * The geometry is promoted to include a Z and M component, if it does not
1105
 * already have them.
1106
 *
1107
 * @param hGeom handle to the geometry to add a vertex to.
1108
 * @param i the index of the vertex to assign (zero based) or
1109
 *  zero for a point.
1110
 * @param dfX input X coordinate to assign.
1111
 * @param dfY input Y coordinate to assign.
1112
 * @param dfZ input Z coordinate to assign.
1113
 * @param dfM input M coordinate to assign.
1114
 *
1115
 * @return (since 3.13) OGRERR_NONE in case of success, OGRERR_FAILURE in case
1116
 * of error.
1117
 */
1118
1119
OGRErr OGR_G_SetPointZM(OGRGeometryH hGeom, int i, double dfX, double dfY,
1120
                        double dfZ, double dfM)
1121
1122
0
{
1123
0
    VALIDATE_POINTER1(hGeom, "OGR_G_SetPointZM", OGRERR_FAILURE);
1124
1125
0
    switch (wkbFlatten(ToPointer(hGeom)->getGeometryType()))
1126
0
    {
1127
0
        case wkbPoint:
1128
0
        {
1129
0
            if (i == 0)
1130
0
            {
1131
0
                OGRPoint *poPoint = ToPointer(hGeom)->toPoint();
1132
0
                poPoint->setX(dfX);
1133
0
                poPoint->setY(dfY);
1134
0
                poPoint->setZ(dfZ);
1135
0
                poPoint->setM(dfM);
1136
0
            }
1137
0
            else
1138
0
            {
1139
0
                CPLError(CE_Failure, CPLE_NotSupported,
1140
0
                         "Only i == 0 is supported");
1141
0
                return OGRERR_FAILURE;
1142
0
            }
1143
0
        }
1144
0
        break;
1145
1146
0
        case wkbLineString:
1147
0
        case wkbCircularString:
1148
0
        {
1149
0
            if (i < 0)
1150
0
            {
1151
0
                CPLError(CE_Failure, CPLE_NotSupported, "Index out of bounds");
1152
0
                return OGRERR_FAILURE;
1153
0
            }
1154
0
            if (!ToPointer(hGeom)->toSimpleCurve()->setPoint(i, dfX, dfY, dfZ,
1155
0
                                                             dfM))
1156
0
                return OGRERR_FAILURE;
1157
0
            break;
1158
0
        }
1159
1160
0
        default:
1161
0
            CPLError(CE_Failure, CPLE_NotSupported,
1162
0
                     "Incompatible geometry for operation");
1163
0
            return OGRERR_FAILURE;
1164
0
    }
1165
1166
0
    return OGRERR_NONE;
1167
0
}
1168
1169
/************************************************************************/
1170
/*                           OGR_G_AddPoint()                           */
1171
/************************************************************************/
1172
/**
1173
 * \brief Add a point to a geometry (line string or point).
1174
 *
1175
 * The vertex count of the line string is increased by one, and assigned from
1176
 * the passed location value.
1177
 *
1178
 * The geometry is promoted to include a Z component, if it does not already
1179
 * have one.
1180
 *
1181
 * @param hGeom handle to the geometry to add a point to.
1182
 * @param dfX x coordinate of point to add.
1183
 * @param dfY y coordinate of point to add.
1184
 * @param dfZ z coordinate of point to add.
1185
 *
1186
 * @return (since 3.13) OGRERR_NONE in case of success, OGRERR_FAILURE in case
1187
 * of error.
1188
 */
1189
1190
OGRErr OGR_G_AddPoint(OGRGeometryH hGeom, double dfX, double dfY, double dfZ)
1191
1192
0
{
1193
0
    VALIDATE_POINTER1(hGeom, "OGR_G_AddPoint", OGRERR_FAILURE);
1194
1195
0
    switch (wkbFlatten(ToPointer(hGeom)->getGeometryType()))
1196
0
    {
1197
0
        case wkbPoint:
1198
0
        {
1199
0
            OGRPoint *poPoint = ToPointer(hGeom)->toPoint();
1200
0
            poPoint->setX(dfX);
1201
0
            poPoint->setY(dfY);
1202
0
            poPoint->setZ(dfZ);
1203
0
        }
1204
0
        break;
1205
1206
0
        case wkbLineString:
1207
0
        case wkbCircularString:
1208
0
            if (!ToPointer(hGeom)->toSimpleCurve()->addPoint(dfX, dfY, dfZ))
1209
0
                return OGRERR_FAILURE;
1210
0
            break;
1211
1212
0
        default:
1213
0
            CPLError(CE_Failure, CPLE_NotSupported,
1214
0
                     "Incompatible geometry for operation");
1215
0
            return OGRERR_FAILURE;
1216
0
    }
1217
1218
0
    return OGRERR_NONE;
1219
0
}
1220
1221
/************************************************************************/
1222
/*                         OGR_G_AddPoint_2D()                          */
1223
/************************************************************************/
1224
/**
1225
 * \brief Add a point to a geometry (line string or point).
1226
 *
1227
 * The vertex count of the line string is increased by one, and assigned from
1228
 * the passed location value.
1229
 *
1230
 * If the geometry includes a Z or M component, the value for those components
1231
 * for the added point will be 0.
1232
 *
1233
 * @param hGeom handle to the geometry to add a point to.
1234
 * @param dfX x coordinate of point to add.
1235
 * @param dfY y coordinate of point to add.
1236
 *
1237
 * @return (since 3.13) OGRERR_NONE in case of success, OGRERR_FAILURE in case
1238
 * of error.
1239
 */
1240
1241
OGRErr OGR_G_AddPoint_2D(OGRGeometryH hGeom, double dfX, double dfY)
1242
1243
0
{
1244
0
    VALIDATE_POINTER1(hGeom, "OGR_G_AddPoint_2D", OGRERR_FAILURE);
1245
1246
0
    switch (wkbFlatten(ToPointer(hGeom)->getGeometryType()))
1247
0
    {
1248
0
        case wkbPoint:
1249
0
        {
1250
0
            OGRPoint *poPoint = ToPointer(hGeom)->toPoint();
1251
0
            poPoint->setX(dfX);
1252
0
            poPoint->setY(dfY);
1253
0
        }
1254
0
        break;
1255
1256
0
        case wkbLineString:
1257
0
        case wkbCircularString:
1258
0
            if (!ToPointer(hGeom)->toSimpleCurve()->addPoint(dfX, dfY))
1259
0
                return OGRERR_FAILURE;
1260
0
            break;
1261
1262
0
        default:
1263
0
            CPLError(CE_Failure, CPLE_NotSupported,
1264
0
                     "Incompatible geometry for operation");
1265
0
            return OGRERR_FAILURE;
1266
0
    }
1267
1268
0
    return OGRERR_NONE;
1269
0
}
1270
1271
/************************************************************************/
1272
/*                          OGR_G_AddPointM()                           */
1273
/************************************************************************/
1274
/**
1275
 * \brief Add a point to a geometry (line string or point).
1276
 *
1277
 * The vertex count of the line string is increased by one, and assigned from
1278
 * the passed location value.
1279
 *
1280
 * The geometry is promoted to include a M component, if it does not already
1281
 * have one.
1282
 *
1283
 * @param hGeom handle to the geometry to add a point to.
1284
 * @param dfX x coordinate of point to add.
1285
 * @param dfY y coordinate of point to add.
1286
 * @param dfM m coordinate of point to add.
1287
 *
1288
 * @return (since 3.13) OGRERR_NONE in case of success, OGRERR_FAILURE in case
1289
 * of error.
1290
 */
1291
1292
OGRErr OGR_G_AddPointM(OGRGeometryH hGeom, double dfX, double dfY, double dfM)
1293
1294
0
{
1295
0
    VALIDATE_POINTER1(hGeom, "OGR_G_AddPointM", OGRERR_FAILURE);
1296
1297
0
    switch (wkbFlatten(ToPointer(hGeom)->getGeometryType()))
1298
0
    {
1299
0
        case wkbPoint:
1300
0
        {
1301
0
            OGRPoint *poPoint = ToPointer(hGeom)->toPoint();
1302
0
            poPoint->setX(dfX);
1303
0
            poPoint->setY(dfY);
1304
0
            poPoint->setM(dfM);
1305
0
        }
1306
0
        break;
1307
1308
0
        case wkbLineString:
1309
0
        case wkbCircularString:
1310
0
            if (!ToPointer(hGeom)->toSimpleCurve()->addPointM(dfX, dfY, dfM))
1311
0
                return OGRERR_FAILURE;
1312
0
            break;
1313
1314
0
        default:
1315
0
            CPLError(CE_Failure, CPLE_NotSupported,
1316
0
                     "Incompatible geometry for operation");
1317
0
            return OGRERR_FAILURE;
1318
0
    }
1319
1320
0
    return OGRERR_NONE;
1321
0
}
1322
1323
/************************************************************************/
1324
/*                          OGR_G_AddPointZM()                          */
1325
/************************************************************************/
1326
/**
1327
 * \brief Add a point to a geometry (line string or point).
1328
 *
1329
 * The vertex count of the line string is increased by one, and assigned from
1330
 * the passed location value.
1331
 *
1332
 * The geometry is promoted to include a Z and M component, if it does not
1333
 * already have them.
1334
 *
1335
 * @param hGeom handle to the geometry to add a point to.
1336
 * @param dfX x coordinate of point to add.
1337
 * @param dfY y coordinate of point to add.
1338
 * @param dfZ z coordinate of point to add.
1339
 * @param dfM m coordinate of point to add.
1340
 *
1341
 * @return (since 3.13) OGRERR_NONE in case of success, OGRERR_FAILURE in case
1342
 * of error.
1343
 */
1344
1345
OGRErr OGR_G_AddPointZM(OGRGeometryH hGeom, double dfX, double dfY, double dfZ,
1346
                        double dfM)
1347
1348
0
{
1349
0
    VALIDATE_POINTER1(hGeom, "OGR_G_AddPointZM", OGRERR_FAILURE);
1350
1351
0
    switch (wkbFlatten(ToPointer(hGeom)->getGeometryType()))
1352
0
    {
1353
0
        case wkbPoint:
1354
0
        {
1355
0
            OGRPoint *poPoint = ToPointer(hGeom)->toPoint();
1356
0
            poPoint->setX(dfX);
1357
0
            poPoint->setY(dfY);
1358
0
            poPoint->setZ(dfZ);
1359
0
            poPoint->setM(dfM);
1360
0
        }
1361
0
        break;
1362
1363
0
        case wkbLineString:
1364
0
        case wkbCircularString:
1365
0
            if (!ToPointer(hGeom)->toSimpleCurve()->addPoint(dfX, dfY, dfZ,
1366
0
                                                             dfM))
1367
0
                return OGRERR_FAILURE;
1368
0
            break;
1369
1370
0
        default:
1371
0
            CPLError(CE_Failure, CPLE_NotSupported,
1372
0
                     "Incompatible geometry for operation");
1373
0
            return OGRERR_FAILURE;
1374
0
    }
1375
1376
0
    return OGRERR_NONE;
1377
0
}
1378
1379
/************************************************************************/
1380
/*                       OGR_G_GetGeometryCount()                       */
1381
/************************************************************************/
1382
/**
1383
 * \brief Fetch the number of elements in a geometry or number of geometries in
1384
 * container.
1385
 *
1386
 * Only geometries of type wkbPolygon[25D], wkbMultiPoint[25D],
1387
 * wkbMultiLineString[25D], wkbMultiPolygon[25D] or wkbGeometryCollection[25D]
1388
 * may return a valid value.  Other geometry types will silently return 0.
1389
 *
1390
 * For a polygon, the returned number is the number of rings (exterior ring +
1391
 * interior rings).
1392
 *
1393
 * @param hGeom single geometry or geometry container from which to get
1394
 * the number of elements.
1395
 * @return the number of elements.
1396
 */
1397
1398
int OGR_G_GetGeometryCount(OGRGeometryH hGeom)
1399
1400
6.78k
{
1401
6.78k
    VALIDATE_POINTER1(hGeom, "OGR_G_GetGeometryCount", 0);
1402
1403
6.78k
    const auto poGeom = ToPointer(hGeom);
1404
6.78k
    const OGRwkbGeometryType eType = wkbFlatten(poGeom->getGeometryType());
1405
6.78k
    if (OGR_GT_IsSubClassOf(eType, wkbCurvePolygon))
1406
3.90k
    {
1407
3.90k
        if (poGeom->toCurvePolygon()->getExteriorRingCurve() == nullptr)
1408
87
            return 0;
1409
3.81k
        else
1410
3.81k
            return poGeom->toCurvePolygon()->getNumInteriorRings() + 1;
1411
3.90k
    }
1412
2.87k
    else if (OGR_GT_IsSubClassOf(eType, wkbCompoundCurve))
1413
0
    {
1414
0
        return poGeom->toCompoundCurve()->getNumCurves();
1415
0
    }
1416
2.87k
    else if (OGR_GT_IsSubClassOf(eType, wkbGeometryCollection))
1417
2.87k
    {
1418
2.87k
        return poGeom->toGeometryCollection()->getNumGeometries();
1419
2.87k
    }
1420
0
    else if (OGR_GT_IsSubClassOf(eType, wkbPolyhedralSurface))
1421
0
    {
1422
0
        return poGeom->toPolyhedralSurface()->getNumGeometries();
1423
0
    }
1424
0
    else
1425
0
    {
1426
        // autotest/pymod/ogrtest.py calls this method on any geometry. So keep
1427
        // silent.
1428
        // CPLError(CE_Failure, CPLE_NotSupported,
1429
        //          "Incompatible geometry for operation");
1430
0
        return 0;
1431
0
    }
1432
6.78k
}
1433
1434
/************************************************************************/
1435
/*                        OGR_G_GetGeometryRef()                        */
1436
/************************************************************************/
1437
1438
/**
1439
 * \brief Fetch geometry from a geometry container.
1440
 *
1441
 * This function returns a handle to a geometry within the container.
1442
 * The returned geometry remains owned by the container, and should not be
1443
 * modified.  The handle is only valid until the next change to the
1444
 * geometry container.  Use OGR_G_Clone() to make a copy.
1445
 *
1446
 * This function relates to the SFCOM
1447
 * IGeometryCollection::get_Geometry() method.
1448
 *
1449
 * This function is the same as the CPP method
1450
 * OGRGeometryCollection::getGeometryRef().
1451
 *
1452
 * For a polygon, OGR_G_GetGeometryRef(iSubGeom) returns the exterior ring
1453
 * if iSubGeom == 0, and the interior rings for iSubGeom > 0.
1454
 *
1455
 * @param hGeom handle to the geometry container from which to get a
1456
 * geometry from.
1457
 * @param iSubGeom the index of the geometry to fetch, between 0 and
1458
 *          getNumGeometries() - 1.
1459
 * @return handle to the requested geometry.
1460
 */
1461
1462
OGRGeometryH OGR_G_GetGeometryRef(OGRGeometryH hGeom, int iSubGeom)
1463
1464
6.53k
{
1465
6.53k
    VALIDATE_POINTER1(hGeom, "OGR_G_GetGeometryRef", nullptr);
1466
1467
6.53k
    const auto poGeom = ToPointer(hGeom);
1468
6.53k
    const OGRwkbGeometryType eType = wkbFlatten(poGeom->getGeometryType());
1469
6.53k
    if (OGR_GT_IsSubClassOf(eType, wkbCurvePolygon))
1470
2.22k
    {
1471
2.22k
        if (iSubGeom == 0)
1472
1.59k
            return ToHandle(poGeom->toCurvePolygon()->getExteriorRingCurve());
1473
624
        else
1474
624
            return ToHandle(
1475
624
                poGeom->toCurvePolygon()->getInteriorRingCurve(iSubGeom - 1));
1476
2.22k
    }
1477
4.31k
    else if (OGR_GT_IsSubClassOf(eType, wkbCompoundCurve))
1478
0
    {
1479
0
        return ToHandle(poGeom->toCompoundCurve()->getCurve(iSubGeom));
1480
0
    }
1481
4.31k
    else if (OGR_GT_IsSubClassOf(eType, wkbGeometryCollection))
1482
4.31k
    {
1483
4.31k
        return ToHandle(
1484
4.31k
            poGeom->toGeometryCollection()->getGeometryRef(iSubGeom));
1485
4.31k
    }
1486
0
    else if (OGR_GT_IsSubClassOf(eType, wkbPolyhedralSurface))
1487
0
    {
1488
0
        return ToHandle(
1489
0
            poGeom->toPolyhedralSurface()->getGeometryRef(iSubGeom));
1490
0
    }
1491
0
    else
1492
0
    {
1493
0
        CPLError(CE_Failure, CPLE_NotSupported,
1494
0
                 "Incompatible geometry for operation");
1495
0
        return nullptr;
1496
0
    }
1497
6.53k
}
1498
1499
/************************************************************************/
1500
/*                         OGR_G_AddGeometry()                          */
1501
/************************************************************************/
1502
1503
/**
1504
 * \brief Add a geometry to a geometry container.
1505
 *
1506
 * Some subclasses of OGRGeometryCollection restrict the types of geometry
1507
 * that can be added, and may return an error.  The passed geometry is cloned
1508
 * to make an internal copy.
1509
 *
1510
 * There is no SFCOM analog to this method.
1511
 *
1512
 * This function is the same as the CPP method
1513
 * OGRGeometryCollection::addGeometry.
1514
 *
1515
 * For a polygon, hNewSubGeom must be a linearring. If the polygon is empty,
1516
 * the first added subgeometry will be the exterior ring. The next ones will be
1517
 * the interior rings.
1518
 *
1519
 * @param hGeom existing geometry container.
1520
 * @param hNewSubGeom geometry to add to the container.
1521
 *
1522
 * @return OGRERR_NONE if successful, or OGRERR_UNSUPPORTED_GEOMETRY_TYPE if
1523
 * the geometry type is illegal for the type of existing geometry.
1524
 */
1525
1526
OGRErr OGR_G_AddGeometry(OGRGeometryH hGeom, OGRGeometryH hNewSubGeom)
1527
1528
0
{
1529
0
    VALIDATE_POINTER1(hGeom, "OGR_G_AddGeometry", OGRERR_UNSUPPORTED_OPERATION);
1530
0
    VALIDATE_POINTER1(hNewSubGeom, "OGR_G_AddGeometry",
1531
0
                      OGRERR_UNSUPPORTED_OPERATION);
1532
1533
0
    OGRErr eErr = OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
1534
1535
0
    auto poGeom = ToPointer(hGeom);
1536
0
    auto poNewSubGeom = ToPointer(hNewSubGeom);
1537
0
    const OGRwkbGeometryType eType = wkbFlatten(poGeom->getGeometryType());
1538
0
    if (OGR_GT_IsSubClassOf(eType, wkbCurvePolygon))
1539
0
    {
1540
0
        if (OGR_GT_IsCurve(wkbFlatten(poNewSubGeom->getGeometryType())))
1541
0
            eErr = poGeom->toCurvePolygon()->addRing(poNewSubGeom->toCurve());
1542
0
    }
1543
0
    else if (OGR_GT_IsSubClassOf(eType, wkbCompoundCurve))
1544
0
    {
1545
0
        if (OGR_GT_IsCurve(wkbFlatten(poNewSubGeom->getGeometryType())))
1546
0
            eErr = poGeom->toCompoundCurve()->addCurve(poNewSubGeom->toCurve());
1547
0
    }
1548
0
    else if (OGR_GT_IsSubClassOf(eType, wkbGeometryCollection))
1549
0
    {
1550
0
        eErr = poGeom->toGeometryCollection()->addGeometry(poNewSubGeom);
1551
0
    }
1552
0
    else if (OGR_GT_IsSubClassOf(eType, wkbPolyhedralSurface))
1553
0
    {
1554
0
        eErr = poGeom->toPolyhedralSurface()->addGeometry(poNewSubGeom);
1555
0
    }
1556
1557
0
    return eErr;
1558
0
}
1559
1560
/************************************************************************/
1561
/*                     OGR_G_AddGeometryDirectly()                      */
1562
/************************************************************************/
1563
/**
1564
 * \brief Add a geometry directly to an existing geometry container.
1565
 *
1566
 * Some subclasses of OGRGeometryCollection restrict the types of geometry
1567
 * that can be added, and may return an error.  Ownership of the passed
1568
 * geometry is taken by the container rather than cloning as addGeometry()
1569
 * does.
1570
 *
1571
 * This function is the same as the CPP method
1572
 * OGRGeometryCollection::addGeometryDirectly.
1573
 *
1574
 * There is no SFCOM analog to this method.
1575
 *
1576
 * For a polygon, hNewSubGeom must be a linearring. If the polygon is empty,
1577
 * the first added subgeometry will be the exterior ring. The next ones will be
1578
 * the interior rings.
1579
 *
1580
 * @param hGeom existing geometry.
1581
 * @param hNewSubGeom geometry to add to the existing geometry.
1582
 *
1583
 * @return OGRERR_NONE if successful, or OGRERR_UNSUPPORTED_GEOMETRY_TYPE if
1584
 * the geometry type is illegal for the type of geometry container.
1585
 */
1586
1587
OGRErr OGR_G_AddGeometryDirectly(OGRGeometryH hGeom, OGRGeometryH hNewSubGeom)
1588
1589
0
{
1590
0
    VALIDATE_POINTER1(hGeom, "OGR_G_AddGeometryDirectly",
1591
0
                      OGRERR_UNSUPPORTED_OPERATION);
1592
0
    VALIDATE_POINTER1(hNewSubGeom, "OGR_G_AddGeometryDirectly",
1593
0
                      OGRERR_UNSUPPORTED_OPERATION);
1594
1595
0
    OGRErr eErr = OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
1596
1597
0
    auto poGeom = ToPointer(hGeom);
1598
0
    auto poNewSubGeom = ToPointer(hNewSubGeom);
1599
0
    const OGRwkbGeometryType eType = wkbFlatten(poGeom->getGeometryType());
1600
1601
0
    if (OGR_GT_IsSubClassOf(eType, wkbCurvePolygon))
1602
0
    {
1603
0
        if (OGR_GT_IsCurve(wkbFlatten(poNewSubGeom->getGeometryType())))
1604
0
            eErr = poGeom->toCurvePolygon()->addRingDirectly(
1605
0
                poNewSubGeom->toCurve());
1606
0
    }
1607
0
    else if (OGR_GT_IsSubClassOf(eType, wkbCompoundCurve))
1608
0
    {
1609
0
        if (OGR_GT_IsCurve(wkbFlatten(poNewSubGeom->getGeometryType())))
1610
0
            eErr = poGeom->toCompoundCurve()->addCurveDirectly(
1611
0
                poNewSubGeom->toCurve());
1612
0
    }
1613
0
    else if (OGR_GT_IsSubClassOf(eType, wkbGeometryCollection))
1614
0
    {
1615
0
        eErr =
1616
0
            poGeom->toGeometryCollection()->addGeometryDirectly(poNewSubGeom);
1617
0
    }
1618
0
    else if (OGR_GT_IsSubClassOf(eType, wkbPolyhedralSurface))
1619
0
    {
1620
0
        eErr = poGeom->toPolyhedralSurface()->addGeometryDirectly(poNewSubGeom);
1621
0
    }
1622
1623
0
    if (eErr != OGRERR_NONE)
1624
0
        delete poNewSubGeom;
1625
1626
0
    return eErr;
1627
0
}
1628
1629
/************************************************************************/
1630
/*                        OGR_G_RemoveGeometry()                        */
1631
/************************************************************************/
1632
1633
/**
1634
 * \brief Remove a geometry from an exiting geometry container.
1635
 *
1636
 * Removing a geometry will cause the geometry count to drop by one, and all
1637
 * "higher" geometries will shuffle down one in index.
1638
 *
1639
 * There is no SFCOM analog to this method.
1640
 *
1641
 * This function is the same as the CPP method
1642
 * OGRGeometryCollection::removeGeometry() for geometry collections,
1643
 * OGRCurvePolygon::removeRing() for polygons / curve polygons and
1644
 * OGRPolyhedralSurface::removeGeometry() for polyhedral surfaces and TINs.
1645
 *
1646
 * @param hGeom the existing geometry to delete from.
1647
 * @param iGeom the index of the geometry to delete.  A value of -1 is a
1648
 * special flag meaning that all geometries should be removed.
1649
 *
1650
 * @param bDelete if TRUE the geometry will be destroyed, otherwise it will
1651
 * not.  The default is TRUE as the existing geometry is considered to own the
1652
 * geometries in it.
1653
 *
1654
 * @return OGRERR_NONE if successful, or OGRERR_FAILURE if the index is
1655
 * out of range.
1656
 */
1657
1658
OGRErr OGR_G_RemoveGeometry(OGRGeometryH hGeom, int iGeom, int bDelete)
1659
1660
0
{
1661
0
    VALIDATE_POINTER1(hGeom, "OGR_G_RemoveGeometry", OGRERR_FAILURE);
1662
1663
0
    const auto poGeom = ToPointer(hGeom);
1664
0
    const OGRwkbGeometryType eType = wkbFlatten(poGeom->getGeometryType());
1665
0
    if (OGR_GT_IsSubClassOf(eType, wkbCurvePolygon))
1666
0
    {
1667
0
        return poGeom->toCurvePolygon()->removeRing(iGeom,
1668
0
                                                    CPL_TO_BOOL(bDelete));
1669
0
    }
1670
0
    else if (OGR_GT_IsSubClassOf(eType, wkbGeometryCollection))
1671
0
    {
1672
0
        return poGeom->toGeometryCollection()->removeGeometry(iGeom, bDelete);
1673
0
    }
1674
0
    else if (OGR_GT_IsSubClassOf(eType, wkbPolyhedralSurface))
1675
0
    {
1676
0
        return poGeom->toPolyhedralSurface()->removeGeometry(iGeom, bDelete);
1677
0
    }
1678
0
    else
1679
0
    {
1680
0
        return OGRERR_UNSUPPORTED_OPERATION;
1681
0
    }
1682
0
}
1683
1684
/************************************************************************/
1685
/*                            OGR_G_Length()                            */
1686
/************************************************************************/
1687
1688
/**
1689
 * \brief Compute length of a geometry.
1690
 *
1691
 * Computes the length for OGRCurve or MultiCurve objects.
1692
 * For surfaces, compute the sum of the lengths of their exterior
1693
 * and interior rings (since 3.10).
1694
 * Undefined for all other geometry types (returns zero).
1695
 *
1696
 * This function utilizes the C++ get_Length() method.
1697
 *
1698
 * @param hGeom the geometry to operate on.
1699
 * @return the length or 0.0 for unsupported geometry types.
1700
 *
1701
 *
1702
 * @see OGR_G_GeodesicLength() for an alternative method returning lengths
1703
 * computed on the ellipsoid, and in meters.
1704
 */
1705
1706
double OGR_G_Length(OGRGeometryH hGeom)
1707
1708
0
{
1709
0
    VALIDATE_POINTER1(hGeom, "OGR_G_GetLength", 0);
1710
1711
0
    double dfLength = 0.0;
1712
1713
0
    const auto poGeom = ToPointer(hGeom);
1714
0
    const OGRwkbGeometryType eType = wkbFlatten(poGeom->getGeometryType());
1715
0
    if (OGR_GT_IsCurve(eType))
1716
0
    {
1717
0
        dfLength = poGeom->toCurve()->get_Length();
1718
0
    }
1719
0
    else if (OGR_GT_IsSurface(eType))
1720
0
    {
1721
0
        dfLength = poGeom->toSurface()->get_Length();
1722
0
    }
1723
0
    else if (OGR_GT_IsSubClassOf(eType, wkbGeometryCollection))
1724
0
    {
1725
0
        dfLength = poGeom->toGeometryCollection()->get_Length();
1726
0
    }
1727
0
    else
1728
0
    {
1729
0
        CPLError(CE_Warning, CPLE_AppDefined,
1730
0
                 "OGR_G_Length() called against a non-curve geometry type.");
1731
0
        dfLength = 0.0;
1732
0
    }
1733
1734
0
    return dfLength;
1735
0
}
1736
1737
/************************************************************************/
1738
/*                        OGR_G_GeodesicLength()                        */
1739
/************************************************************************/
1740
1741
/**
1742
 * \brief Get the length of the curve, considered as a geodesic line on the
1743
 * underlying ellipsoid of the SRS attached to the geometry.
1744
 *
1745
 * The returned length will always be in meters.
1746
 *
1747
 * <a href="https://geographiclib.sourceforge.io/html/python/geodesics.html">Geodesics</a>
1748
 * follow the shortest route on the surface of the ellipsoid.
1749
 *
1750
 * If the geometry' SRS is not a geographic one, geometries are reprojected to
1751
 * the underlying geographic SRS of the geometry' SRS.
1752
 * OGRSpatialReference::GetDataAxisToSRSAxisMapping() is honored.
1753
 *
1754
 * Note that geometries with circular arcs will be linearized in their original
1755
 * coordinate space first, so the resulting geodesic length will be an
1756
 * approximation.
1757
 *
1758
 * This function utilizes the C++ get_GeodesicLength() method.
1759
 *
1760
 * @param hGeom the geometry to operate on.
1761
 * @return the length or a negative value for unsupported geometry types.
1762
 *
1763
 * @since OGR 3.10
1764
 */
1765
1766
double OGR_G_GeodesicLength(OGRGeometryH hGeom)
1767
1768
0
{
1769
0
    VALIDATE_POINTER1(hGeom, "OGR_G_GeodesicLength", -1);
1770
1771
0
    double dfLength = 0.0;
1772
1773
0
    const auto poGeom = ToPointer(hGeom);
1774
0
    const OGRwkbGeometryType eType = wkbFlatten(poGeom->getGeometryType());
1775
0
    if (OGR_GT_IsCurve(eType))
1776
0
    {
1777
0
        dfLength = poGeom->toCurve()->get_GeodesicLength();
1778
0
    }
1779
0
    else if (OGR_GT_IsSurface(eType))
1780
0
    {
1781
0
        dfLength = poGeom->toSurface()->get_GeodesicLength();
1782
0
    }
1783
0
    else if (OGR_GT_IsSubClassOf(eType, wkbGeometryCollection))
1784
0
    {
1785
0
        dfLength = poGeom->toGeometryCollection()->get_GeodesicLength();
1786
0
    }
1787
0
    else
1788
0
    {
1789
0
        CPLError(
1790
0
            CE_Failure, CPLE_AppDefined,
1791
0
            "OGR_G_GeodesicLength() called against a non-curve geometry type.");
1792
0
        dfLength = -1.0;
1793
0
    }
1794
1795
0
    return dfLength;
1796
0
}
1797
1798
/************************************************************************/
1799
/*                             OGR_G_Area()                             */
1800
/************************************************************************/
1801
1802
/**
1803
 * \brief Compute geometry area.
1804
 *
1805
 * The returned area is a 2D Cartesian (planar) area in square units of the
1806
 * spatial reference system in use, so potentially "square degrees" for a
1807
 * geometry expressed in a geographic SRS.
1808
 *
1809
 * Computes the area for surfaces or closed curves.
1810
 * Undefined for all other geometry types (returns 0.0).
1811
 *
1812
 * This function utilizes the C++ OGRSurface::get_Area() method.
1813
 *
1814
 * @param hGeom the geometry to operate on.
1815
 * @return the area of the geometry in square units of the spatial reference
1816
 * system in use, or 0.0 for unsupported geometry types.
1817
1818
 * @see OGR_G_GeodesicArea() for an alternative function returning areas
1819
 * computed on the ellipsoid, and in square meters.
1820
 *
1821
 */
1822
1823
double OGR_G_Area(OGRGeometryH hGeom)
1824
1825
0
{
1826
0
    VALIDATE_POINTER1(hGeom, "OGR_G_Area", 0);
1827
1828
0
    double dfArea = 0.0;
1829
1830
0
    const auto poGeom = ToPointer(hGeom);
1831
0
    const OGRwkbGeometryType eType = wkbFlatten(poGeom->getGeometryType());
1832
0
    if (OGR_GT_IsSurface(eType))
1833
0
    {
1834
0
        dfArea = poGeom->toSurface()->get_Area();
1835
0
    }
1836
0
    else if (OGR_GT_IsCurve(eType))
1837
0
    {
1838
0
        dfArea = poGeom->toCurve()->get_Area();
1839
0
    }
1840
0
    else if (OGR_GT_IsSubClassOf(eType, wkbGeometryCollection))
1841
0
    {
1842
0
        dfArea = poGeom->toGeometryCollection()->get_Area();
1843
0
    }
1844
0
    else
1845
0
    {
1846
0
        CPLError(CE_Warning, CPLE_AppDefined,
1847
0
                 "OGR_G_Area() called against non-surface geometry type.");
1848
1849
0
        dfArea = 0.0;
1850
0
    }
1851
1852
0
    return dfArea;
1853
0
}
1854
1855
/**
1856
 * \brief Compute geometry area (deprecated)
1857
 *
1858
 * @deprecated
1859
 * @see OGR_G_Area()
1860
 */
1861
double OGR_G_GetArea(OGRGeometryH hGeom)
1862
1863
0
{
1864
0
    return OGR_G_Area(hGeom);
1865
0
}
1866
1867
/************************************************************************/
1868
/*                         OGR_G_GeodesicArea()                         */
1869
/************************************************************************/
1870
1871
/**
1872
 * \brief Compute geometry area, considered as a surface on the underlying
1873
 * ellipsoid of the SRS attached to the geometry.
1874
 *
1875
 * The returned area will always be in square meters, and assumes that
1876
 * polygon edges describe geodesic lines on the ellipsoid.
1877
 *
1878
 * <a href="https://geographiclib.sourceforge.io/html/python/geodesics.html">Geodesics</a>
1879
 * follow the shortest route on the surface of the ellipsoid.
1880
 *
1881
 * If the geometry' SRS is not a geographic one, geometries are reprojected to
1882
 * the underlying geographic SRS of the geometry' SRS.
1883
 * OGRSpatialReference::GetDataAxisToSRSAxisMapping() is honored.
1884
 *
1885
 * Computes the area for surfaces or closed curves.
1886
 * Undefined for all other geometry types (returns a negative value).
1887
 *
1888
 * Note that geometries with circular arcs will be linearized in their original
1889
 * coordinate space first, so the resulting geodesic area will be an
1890
 * approximation.
1891
 *
1892
 * This function utilizes the C++ OGRSurface::get_GeodesicArea() method.
1893
 *
1894
 * @param hGeom the geometry to operate on.
1895
 * @return the area, or a negative value in case of error (unsupported geometry
1896
 * type, no SRS attached, etc.)
1897
 *
1898
 * @see OGR_G_Area() for an alternative method returning areas computed in
1899
 * 2D Cartesian space.
1900
 *
1901
 * @since OGR 3.9.0
1902
 */
1903
1904
double OGR_G_GeodesicArea(OGRGeometryH hGeom)
1905
1906
0
{
1907
0
    VALIDATE_POINTER1(hGeom, "OGR_G_GeodesicArea", -1);
1908
1909
0
    double dfArea = -1;
1910
1911
0
    const auto poGeom = ToPointer(hGeom);
1912
0
    const OGRwkbGeometryType eType = wkbFlatten(poGeom->getGeometryType());
1913
0
    if (OGR_GT_IsSurface(eType))
1914
0
    {
1915
0
        dfArea = poGeom->toSurface()->get_GeodesicArea();
1916
0
    }
1917
0
    else if (OGR_GT_IsCurve(eType))
1918
0
    {
1919
0
        dfArea = poGeom->toCurve()->get_GeodesicArea();
1920
0
    }
1921
0
    else if (OGR_GT_IsSubClassOf(eType, wkbGeometryCollection))
1922
0
    {
1923
0
        dfArea = poGeom->toGeometryCollection()->get_GeodesicArea();
1924
0
    }
1925
0
    else
1926
0
    {
1927
0
        CPLError(CE_Failure, CPLE_AppDefined,
1928
0
                 "OGR_G_GeodesicArea() called against non-surface geometry "
1929
0
                 "type.");
1930
0
    }
1931
1932
0
    return dfArea;
1933
0
}
1934
1935
/************************************************************************/
1936
/*                         OGR_G_IsClockwise()                          */
1937
/************************************************************************/
1938
/**
1939
 * \brief Returns true if the ring has clockwise winding (or less than 2 points)
1940
 *
1941
 * Assumes that the ring is closed.
1942
 *
1943
 * @param hGeom handle to a curve geometry
1944
 * @since GDAL 3.8
1945
 */
1946
1947
bool OGR_G_IsClockwise(OGRGeometryH hGeom)
1948
1949
0
{
1950
0
    VALIDATE_POINTER1(hGeom, "OGR_G_IsClockwise", false);
1951
1952
0
    auto poGeom = OGRGeometry::FromHandle(hGeom);
1953
0
    const OGRwkbGeometryType eGType = wkbFlatten(poGeom->getGeometryType());
1954
0
    if (OGR_GT_IsCurve(eGType))
1955
0
    {
1956
0
        return poGeom->toCurve()->isClockwise();
1957
0
    }
1958
0
    else
1959
0
    {
1960
0
        CPLError(CE_Failure, CPLE_NotSupported,
1961
0
                 "Incompatible geometry for operation");
1962
0
        return false;
1963
0
    }
1964
0
}
1965
1966
/************************************************************************/
1967
/*                       OGR_G_HasCurveGeometry()                       */
1968
/************************************************************************/
1969
1970
/**
1971
 * \brief Returns if this geometry is or has curve geometry.
1972
 *
1973
 * Returns if a geometry is or has CIRCULARSTRING, COMPOUNDCURVE, CURVEPOLYGON,
1974
 * MULTICURVE or MULTISURFACE in it.
1975
 *
1976
 * If bLookForNonLinear is set to TRUE, it will be actually looked if the
1977
 * geometry or its subgeometries are or contain a non-linear geometry in
1978
 * them. In which case, if the method returns TRUE, it means that
1979
 * OGR_G_GetLinearGeometry() would return an approximate version of the
1980
 * geometry. Otherwise, OGR_G_GetLinearGeometry() would do a conversion, but
1981
 * with just converting container type, like COMPOUNDCURVE -> LINESTRING,
1982
 * MULTICURVE -> MULTILINESTRING or MULTISURFACE -> MULTIPOLYGON, resulting in a
1983
 * "loss-less" conversion.
1984
 *
1985
 * This function is the same as C++ method OGRGeometry::hasCurveGeometry().
1986
 *
1987
 * @param hGeom the geometry to operate on.
1988
 * @param bLookForNonLinear set it to TRUE to check if the geometry is or
1989
 * contains a CIRCULARSTRING.
1990
 * @return TRUE if this geometry is or has curve geometry.
1991
 *
1992
 */
1993
1994
int OGR_G_HasCurveGeometry(OGRGeometryH hGeom, int bLookForNonLinear)
1995
0
{
1996
0
    VALIDATE_POINTER1(hGeom, "OGR_G_HasCurveGeometry", FALSE);
1997
0
    return ToPointer(hGeom)->hasCurveGeometry(bLookForNonLinear);
1998
0
}
1999
2000
/************************************************************************/
2001
/*                      OGR_G_GetLinearGeometry()                       */
2002
/************************************************************************/
2003
2004
/**
2005
 * \brief Return, possibly approximate, linear version of this geometry.
2006
 *
2007
 * Returns a geometry that has no CIRCULARSTRING, COMPOUNDCURVE, CURVEPOLYGON,
2008
 * MULTICURVE or MULTISURFACE in it, by approximating curve geometries.
2009
 *
2010
 * The ownership of the returned geometry belongs to the caller.
2011
 *
2012
 * The reverse function is OGR_G_GetCurveGeometry().
2013
 *
2014
 * This method relates to the ISO SQL/MM Part 3 ICurve::CurveToLine() and
2015
 * CurvePolygon::CurvePolyToPoly() methods.
2016
 *
2017
 * This function is the same as C++ method OGRGeometry::getLinearGeometry().
2018
 *
2019
 * @param hGeom the geometry to operate on.
2020
 * @param dfMaxAngleStepSizeDegrees the largest step in degrees along the
2021
 * arc, zero to use the default setting.
2022
 * @param papszOptions options as a null-terminated list of strings or NULL.
2023
 * See OGRGeometryFactory::curveToLineString() for valid options.
2024
 *
2025
 * @return a new geometry.
2026
 *
2027
 */
2028
2029
OGRGeometryH CPL_DLL OGR_G_GetLinearGeometry(OGRGeometryH hGeom,
2030
                                             double dfMaxAngleStepSizeDegrees,
2031
                                             CSLConstList papszOptions)
2032
0
{
2033
0
    VALIDATE_POINTER1(hGeom, "OGR_G_GetLinearGeometry", nullptr);
2034
0
    return ToHandle(ToPointer(hGeom)->getLinearGeometry(
2035
0
        dfMaxAngleStepSizeDegrees, papszOptions));
2036
0
}
2037
2038
/************************************************************************/
2039
/*                       OGR_G_GetCurveGeometry()                       */
2040
/************************************************************************/
2041
2042
/**
2043
 * \brief Return curve version of this geometry.
2044
 *
2045
 * Returns a geometry that has possibly CIRCULARSTRING, COMPOUNDCURVE,
2046
 * CURVEPOLYGON, MULTICURVE or MULTISURFACE in it, by de-approximating linear
2047
 * into curve geometries.
2048
 *
2049
 * If the geometry has no curve portion, the returned geometry will be a clone
2050
 * of it.
2051
 *
2052
 * The ownership of the returned geometry belongs to the caller.
2053
 *
2054
 * The reverse function is OGR_G_GetLinearGeometry().
2055
 *
2056
 * This function is the same as C++ method OGRGeometry::getCurveGeometry().
2057
 *
2058
 * @param hGeom the geometry to operate on.
2059
 * @param papszOptions options as a null-terminated list of strings.
2060
 *                     Unused for now. Must be set to NULL.
2061
 *
2062
 * @return a new geometry.
2063
 *
2064
 */
2065
2066
OGRGeometryH CPL_DLL OGR_G_GetCurveGeometry(OGRGeometryH hGeom,
2067
                                            CSLConstList papszOptions)
2068
0
{
2069
0
    VALIDATE_POINTER1(hGeom, "OGR_G_GetCurveGeometry", nullptr);
2070
2071
0
    return ToHandle(ToPointer(hGeom)->getCurveGeometry(papszOptions));
2072
0
}
2073
2074
/************************************************************************/
2075
/*                            OGR_G_Value()                             */
2076
/************************************************************************/
2077
/**
2078
 * \brief Fetch point at given distance along curve.
2079
 *
2080
 * This function relates to the SF COM ICurve::get_Value() method.
2081
 *
2082
 * This function is the same as the C++ method OGRCurve::Value().
2083
 *
2084
 * @param hGeom curve geometry.
2085
 * @param dfDistance distance along the curve at which to sample position.
2086
 *                   This distance should be between zero and get_Length()
2087
 *                   for this curve.
2088
 * @return a point or NULL.
2089
 *
2090
 */
2091
2092
OGRGeometryH OGR_G_Value(OGRGeometryH hGeom, double dfDistance)
2093
0
{
2094
0
    VALIDATE_POINTER1(hGeom, "OGR_G_Value", nullptr);
2095
2096
0
    const auto poGeom = ToPointer(hGeom);
2097
0
    if (OGR_GT_IsCurve(poGeom->getGeometryType()))
2098
0
    {
2099
0
        OGRPoint *p = new OGRPoint();
2100
0
        poGeom->toCurve()->Value(dfDistance, p);
2101
0
        return ToHandle(p);
2102
0
    }
2103
2104
0
    return nullptr;
2105
0
}
2106
2107
/************************************************************************/
2108
/*                OGRSetNonLinearGeometriesEnabledFlag()                */
2109
/************************************************************************/
2110
2111
/**
2112
 * \brief Set flag to enable/disable returning non-linear geometries in the C
2113
 * API.
2114
 *
2115
 * This flag has only an effect on the OGR_F_GetGeometryRef(),
2116
 * OGR_F_GetGeomFieldRef(), OGR_L_GetGeomType(), OGR_GFld_GetType() and
2117
 * OGR_FD_GetGeomType() C API, and corresponding methods in the SWIG
2118
 * bindings. It is meant as making it simple for applications using the OGR C
2119
 * API not to have to deal with non-linear geometries, even if such geometries
2120
 * might be returned by drivers. In which case, they will be transformed into
2121
 * their closest linear geometry, by doing linear approximation, with
2122
 * OGR_G_ForceTo().
2123
 *
2124
 * Libraries should generally *not* use that method, since that could interfere
2125
 * with other libraries or applications.
2126
 *
2127
 * Note that it *does* not affect the behavior of the C++ API.
2128
 *
2129
 * @param bFlag TRUE if non-linear geometries might be returned (default value).
2130
 *              FALSE to ask for non-linear geometries to be approximated as
2131
 *              linear geometries.
2132
 *
2133
 */
2134
2135
void OGRSetNonLinearGeometriesEnabledFlag(int bFlag)
2136
0
{
2137
0
    bNonLinearGeometriesEnabled = bFlag != FALSE;
2138
0
}
2139
2140
/************************************************************************/
2141
/*                OGRGetNonLinearGeometriesEnabledFlag()                */
2142
/************************************************************************/
2143
2144
/**
2145
 * \brief Get flag to enable/disable returning non-linear geometries in the C
2146
 * API.
2147
 *
2148
 * return TRUE if non-linear geometries might be returned (default value is
2149
 * TRUE).
2150
 *
2151
 * @see OGRSetNonLinearGeometriesEnabledFlag()
2152
 */
2153
2154
int OGRGetNonLinearGeometriesEnabledFlag(void)
2155
0
{
2156
0
    return bNonLinearGeometriesEnabled;
2157
0
}