Coverage Report

Created: 2025-11-16 06:25

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