Line data Source code
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 6354 : bool OGRGetGEOSVersion(int *pnMajor, int *pnMinor, int *pnPatch)
40 : {
41 6354 : CPLStringList aosTokens(CSLTokenizeString2(GEOSversion(), ".", 0));
42 :
43 6354 : if (pnMajor && aosTokens.size() > 0)
44 5557 : *pnMajor = std::stoi(aosTokens[0]);
45 6354 : if (pnMinor && aosTokens.size() > 1)
46 405 : *pnMinor = std::stoi(aosTokens[1]);
47 6354 : if (pnPatch && aosTokens.size() > 2)
48 392 : *pnPatch = std::stoi(aosTokens[2]);
49 12708 : return TRUE;
50 : }
51 : #else
52 : bool OGRGetGEOSVersion(int *pnMajor, int *pnMinor, int *pnPatch)
53 : {
54 : if (pnMajor)
55 : *pnMajor = 0;
56 : if (pnMinor)
57 : *pnMinor = 0;
58 : if (pnPatch)
59 : *pnPatch = 0;
60 : return FALSE;
61 : }
62 : #endif
63 :
64 : /************************************************************************/
65 : /* ToPointer() */
66 : /************************************************************************/
67 :
68 818306 : static inline OGRGeometry *ToPointer(OGRGeometryH hGeom)
69 : {
70 818306 : return OGRGeometry::FromHandle(hGeom);
71 : }
72 :
73 : /************************************************************************/
74 : /* ToHandle() */
75 : /************************************************************************/
76 :
77 9823 : static inline OGRGeometryH ToHandle(OGRGeometry *poGeom)
78 : {
79 9823 : return OGRGeometry::ToHandle(poGeom);
80 : }
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 14903 : int OGR_G_GetPointCount(OGRGeometryH hGeom)
97 :
98 : {
99 14903 : VALIDATE_POINTER1(hGeom, "OGR_G_GetPointCount", 0);
100 :
101 : const OGRwkbGeometryType eGType =
102 14903 : wkbFlatten(ToPointer(hGeom)->getGeometryType());
103 14903 : if (eGType == wkbPoint)
104 : {
105 2241 : return 1;
106 : }
107 12662 : else if (OGR_GT_IsCurve(eGType))
108 : {
109 7684 : return ToPointer(hGeom)->toCurve()->getNumPoints();
110 : }
111 : else
112 : {
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 4978 : return 0;
118 : }
119 : }
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 0 : OGRErr OGR_G_SetPointCount(OGRGeometryH hGeom, int nNewPointCount)
138 :
139 : {
140 0 : VALIDATE_POINTER1(hGeom, "OGR_G_SetPointCount", OGRERR_FAILURE);
141 :
142 0 : switch (wkbFlatten(ToPointer(hGeom)->getGeometryType()))
143 : {
144 0 : case wkbLineString:
145 : case wkbCircularString:
146 : {
147 0 : OGRSimpleCurve *poSC = ToPointer(hGeom)->toSimpleCurve();
148 0 : if (!poSC->setNumPoints(nNewPointCount))
149 0 : return OGRERR_FAILURE;
150 0 : break;
151 : }
152 0 : default:
153 0 : CPLError(CE_Failure, CPLE_NotSupported,
154 : "Incompatible geometry for operation");
155 0 : return OGRERR_FAILURE;
156 : }
157 :
158 0 : return OGRERR_NONE;
159 : }
160 :
161 : /************************************************************************/
162 : /* OGR_G_Get_Component() */
163 : /************************************************************************/
164 : template <typename Getter>
165 86833 : static double OGR_G_Get_Component(OGRGeometryH hGeom, int i)
166 : {
167 86833 : switch (wkbFlatten(ToPointer(hGeom)->getGeometryType()))
168 : {
169 4897 : case wkbPoint:
170 : {
171 4897 : if (i == 0)
172 : {
173 4894 : return Getter::get(ToPointer(hGeom)->toPoint());
174 : }
175 : else
176 : {
177 3 : CPLError(CE_Failure, CPLE_NotSupported,
178 : "Only i == 0 is supported");
179 3 : return 0.0;
180 : }
181 : }
182 :
183 81933 : case wkbLineString:
184 : case wkbCircularString:
185 : {
186 81933 : OGRSimpleCurve *poSC = ToPointer(hGeom)->toSimpleCurve();
187 81933 : if (i < 0 || i >= poSC->getNumPoints())
188 : {
189 3 : CPLError(CE_Failure, CPLE_NotSupported, "Index out of bounds");
190 3 : return 0.0;
191 : }
192 81930 : return Getter::get(poSC, i);
193 : }
194 :
195 3 : default:
196 3 : CPLError(CE_Failure, CPLE_NotSupported,
197 : "Incompatible geometry for operation");
198 3 : return 0.0;
199 : }
200 : }
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 34493 : double OGR_G_GetX(OGRGeometryH hGeom, int i)
215 :
216 : {
217 34493 : VALIDATE_POINTER1(hGeom, "OGR_G_GetX", 0);
218 :
219 : struct Getter
220 : {
221 2516 : static double get(const OGRPoint *poPoint)
222 : {
223 2516 : return poPoint->getX();
224 : }
225 :
226 31974 : static double get(const OGRSimpleCurve *poSC, int l_i)
227 : {
228 31974 : return poSC->getX(l_i);
229 : }
230 : };
231 :
232 34493 : return OGR_G_Get_Component<Getter>(hGeom, i);
233 : }
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 33284 : double OGR_G_GetY(OGRGeometryH hGeom, int i)
248 :
249 : {
250 33284 : VALIDATE_POINTER1(hGeom, "OGR_G_GetY", 0);
251 :
252 : struct Getter
253 : {
254 1307 : static double get(const OGRPoint *poPoint)
255 : {
256 1307 : return poPoint->getY();
257 : }
258 :
259 31974 : static double get(const OGRSimpleCurve *poSC, int l_i)
260 : {
261 31974 : return poSC->getY(l_i);
262 : }
263 : };
264 :
265 33284 : return OGR_G_Get_Component<Getter>(hGeom, i);
266 : }
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 16760 : double OGR_G_GetZ(OGRGeometryH hGeom, int i)
281 :
282 : {
283 16760 : VALIDATE_POINTER1(hGeom, "OGR_G_GetZ", 0);
284 :
285 : struct Getter
286 : {
287 951 : static double get(const OGRPoint *poPoint)
288 : {
289 951 : return poPoint->getZ();
290 : }
291 :
292 15806 : static double get(const OGRSimpleCurve *poSC, int l_i)
293 : {
294 15806 : return poSC->getZ(l_i);
295 : }
296 : };
297 :
298 16760 : return OGR_G_Get_Component<Getter>(hGeom, i);
299 : }
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 2296 : double OGR_G_GetM(OGRGeometryH hGeom, int i)
313 :
314 : {
315 2296 : VALIDATE_POINTER1(hGeom, "OGR_G_GetM", 0);
316 :
317 : struct Getter
318 : {
319 120 : static double get(const OGRPoint *poPoint)
320 : {
321 120 : return poPoint->getM();
322 : }
323 :
324 2176 : static double get(const OGRSimpleCurve *poSC, int l_i)
325 : {
326 2176 : return poSC->getM(l_i);
327 : }
328 : };
329 :
330 2296 : return OGR_G_Get_Component<Getter>(hGeom, i);
331 : }
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 17 : int OGR_G_GetPoints(OGRGeometryH hGeom, void *pabyX, int nXStride, void *pabyY,
363 : int nYStride, void *pabyZ, int nZStride)
364 : {
365 17 : VALIDATE_POINTER1(hGeom, "OGR_G_GetPoints", 0);
366 :
367 17 : int ret = 0;
368 17 : switch (wkbFlatten(ToPointer(hGeom)->getGeometryType()))
369 : {
370 4 : case wkbPoint:
371 : {
372 4 : OGRPoint *poPoint = ToPointer(hGeom)->toPoint();
373 4 : if (pabyX)
374 4 : *(static_cast<double *>(pabyX)) = poPoint->getX();
375 4 : if (pabyY)
376 4 : *(static_cast<double *>(pabyY)) = poPoint->getY();
377 4 : if (pabyZ)
378 2 : *(static_cast<double *>(pabyZ)) = poPoint->getZ();
379 4 : ret = 1;
380 4 : break;
381 : }
382 :
383 10 : case wkbLineString:
384 : case wkbCircularString:
385 : {
386 10 : OGRSimpleCurve *poSC = ToPointer(hGeom)->toSimpleCurve();
387 10 : poSC->getPoints(pabyX, nXStride, pabyY, nYStride, pabyZ, nZStride);
388 10 : ret = poSC->getNumPoints();
389 10 : break;
390 : }
391 :
392 3 : default:
393 : {
394 3 : CPLError(CE_Failure, CPLE_NotSupported,
395 : "Incompatible geometry for operation");
396 3 : ret = -1;
397 3 : break;
398 : }
399 : }
400 17 : return ret;
401 : }
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 0 : 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 : {
438 0 : VALIDATE_POINTER1(hGeom, "OGR_G_GetPointsZM", 0);
439 :
440 0 : int ret = 0;
441 0 : switch (wkbFlatten(ToPointer(hGeom)->getGeometryType()))
442 : {
443 0 : case wkbPoint:
444 : {
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 : }
457 :
458 0 : case wkbLineString:
459 : case wkbCircularString:
460 : {
461 0 : OGRSimpleCurve *poSC = ToPointer(hGeom)->toSimpleCurve();
462 0 : poSC->getPoints(pabyX, nXStride, pabyY, nYStride, pabyZ, nZStride,
463 : pabyM, nMStride);
464 0 : ret = poSC->getNumPoints();
465 0 : break;
466 : }
467 :
468 0 : default:
469 : {
470 0 : CPLError(CE_Failure, CPLE_NotSupported,
471 : "Incompatible geometry for operation");
472 0 : break;
473 : }
474 : }
475 :
476 0 : return ret;
477 : }
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 1012 : void OGR_G_GetPoint(OGRGeometryH hGeom, int i, double *pdfX, double *pdfY,
494 : double *pdfZ)
495 :
496 : {
497 1012 : VALIDATE_POINTER0(hGeom, "OGR_G_GetPoint");
498 :
499 1012 : switch (wkbFlatten(ToPointer(hGeom)->getGeometryType()))
500 : {
501 277 : case wkbPoint:
502 : {
503 277 : if (i == 0)
504 : {
505 276 : OGRPoint *poPoint = ToPointer(hGeom)->toPoint();
506 276 : *pdfX = poPoint->getX();
507 276 : *pdfY = poPoint->getY();
508 276 : if (pdfZ != nullptr)
509 20 : *pdfZ = poPoint->getZ();
510 : }
511 : else
512 : {
513 1 : CPLError(CE_Failure, CPLE_NotSupported,
514 : "Only i == 0 is supported");
515 : }
516 : }
517 277 : break;
518 :
519 734 : case wkbLineString:
520 : case wkbCircularString:
521 : {
522 734 : OGRSimpleCurve *poSC = ToPointer(hGeom)->toSimpleCurve();
523 734 : if (i < 0 || i >= poSC->getNumPoints())
524 : {
525 5 : CPLError(CE_Failure, CPLE_NotSupported, "Index out of bounds");
526 5 : *pdfX = 0.0;
527 5 : *pdfY = 0.0;
528 5 : if (pdfZ != nullptr)
529 3 : *pdfZ = 0.0;
530 : }
531 : else
532 : {
533 729 : *pdfX = poSC->getX(i);
534 729 : *pdfY = poSC->getY(i);
535 729 : if (pdfZ != nullptr)
536 728 : *pdfZ = poSC->getZ(i);
537 : }
538 : }
539 734 : break;
540 :
541 1 : default:
542 1 : CPLError(CE_Failure, CPLE_NotSupported,
543 : "Incompatible geometry for operation");
544 1 : break;
545 : }
546 : }
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 1 : void OGR_G_GetPointZM(OGRGeometryH hGeom, int i, double *pdfX, double *pdfY,
564 : double *pdfZ, double *pdfM)
565 :
566 : {
567 1 : VALIDATE_POINTER0(hGeom, "OGR_G_GetPointZM");
568 :
569 1 : switch (wkbFlatten(ToPointer(hGeom)->getGeometryType()))
570 : {
571 1 : case wkbPoint:
572 : {
573 1 : if (i == 0)
574 : {
575 1 : OGRPoint *poPoint = ToPointer(hGeom)->toPoint();
576 1 : *pdfX = poPoint->getX();
577 1 : *pdfY = poPoint->getY();
578 1 : if (pdfZ != nullptr)
579 1 : *pdfZ = poPoint->getZ();
580 1 : if (pdfM != nullptr)
581 1 : *pdfM = poPoint->getM();
582 : }
583 : else
584 : {
585 0 : CPLError(CE_Failure, CPLE_NotSupported,
586 : "Only i == 0 is supported");
587 : }
588 : }
589 1 : break;
590 :
591 0 : case wkbLineString:
592 : case wkbCircularString:
593 : {
594 0 : OGRSimpleCurve *poSC = ToPointer(hGeom)->toSimpleCurve();
595 0 : if (i < 0 || i >= poSC->getNumPoints())
596 : {
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 : }
605 : else
606 : {
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 : }
614 : }
615 0 : break;
616 :
617 0 : default:
618 0 : CPLError(CE_Failure, CPLE_NotSupported,
619 : "Incompatible geometry for operation");
620 0 : break;
621 : }
622 : }
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 9 : 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 : {
653 9 : VALIDATE_POINTER1(hGeom, "OGR_G_SetPoints", OGRERR_FAILURE);
654 :
655 9 : if (pabyX == nullptr || pabyY == nullptr)
656 : {
657 2 : CPLError(CE_Failure, CPLE_NotSupported,
658 : "pabyX == NULL || pabyY == NULL");
659 2 : return OGRERR_FAILURE;
660 : }
661 :
662 7 : const double *const padfX = static_cast<const double *>(pabyX);
663 7 : const double *const padfY = static_cast<const double *>(pabyY);
664 7 : const double *const padfZ = static_cast<const double *>(pabyZ);
665 :
666 7 : switch (wkbFlatten(ToPointer(hGeom)->getGeometryType()))
667 : {
668 2 : case wkbPoint:
669 : {
670 2 : OGRPoint *poPoint = ToPointer(hGeom)->toPoint();
671 2 : poPoint->setX(*padfX);
672 2 : poPoint->setY(*padfY);
673 2 : if (pabyZ != nullptr)
674 1 : poPoint->setZ(*(padfZ));
675 2 : break;
676 : }
677 5 : case wkbLineString:
678 : case wkbCircularString:
679 : {
680 5 : OGRSimpleCurve *poSC = ToPointer(hGeom)->toSimpleCurve();
681 :
682 5 : const int nSizeDouble = static_cast<int>(sizeof(double));
683 5 : if (nXStride == nSizeDouble && nYStride == nSizeDouble &&
684 2 : ((nZStride == 0 && pabyZ == nullptr) ||
685 1 : (nZStride == nSizeDouble && pabyZ != nullptr)))
686 : {
687 2 : return poSC->setPoints(nPointsIn, padfX, padfY, padfZ)
688 2 : ? OGRERR_NONE
689 2 : : OGRERR_FAILURE;
690 : }
691 : else
692 : {
693 3 : if (!poSC->setNumPoints(nPointsIn))
694 0 : return OGRERR_FAILURE;
695 :
696 : // TODO(schwehr): Create pasX and pasY.
697 6 : for (int i = 0; i < nPointsIn; ++i)
698 : {
699 3 : const double x = *reinterpret_cast<const double *>(
700 3 : static_cast<const char *>(pabyX) + i * nXStride);
701 3 : const double y = *reinterpret_cast<const double *>(
702 3 : static_cast<const char *>(pabyY) + i * nYStride);
703 3 : if (pabyZ)
704 : {
705 1 : const double z = *reinterpret_cast<const double *>(
706 1 : static_cast<const char *>(pabyZ) + i * nZStride);
707 1 : poSC->setPoint(i, x, y, z);
708 : }
709 : else
710 : {
711 2 : poSC->setPoint(i, x, y);
712 : }
713 : }
714 : }
715 3 : break;
716 : }
717 0 : default:
718 0 : CPLError(CE_Failure, CPLE_NotSupported,
719 : "Incompatible geometry for operation");
720 0 : return OGRERR_FAILURE;
721 : }
722 :
723 5 : return OGRERR_NONE;
724 : }
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 0 : 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 : {
758 0 : VALIDATE_POINTER1(hGeom, "OGR_G_SetPointsZM", OGRERR_FAILURE);
759 :
760 0 : if (pX == nullptr || pY == nullptr)
761 : {
762 0 : CPLError(CE_Failure, CPLE_NotSupported,
763 : "pabyX == NULL || pabyY == NULL");
764 0 : return OGRERR_FAILURE;
765 : }
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 : {
778 0 : case wkbPoint:
779 : {
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 : }
789 0 : case wkbLineString:
790 : case wkbCircularString:
791 : {
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 : {
801 : 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 : else
809 : bRes =
810 0 : poSC->setPoints(nPointsIn, padfX, padfY, padfZ, padfM);
811 0 : return bRes ? OGRERR_NONE : OGRERR_FAILURE;
812 : }
813 : else
814 : {
815 0 : if (!poSC->setNumPoints(nPointsIn))
816 0 : return OGRERR_FAILURE;
817 :
818 0 : if (!pabyM)
819 : {
820 0 : if (!pabyZ)
821 : {
822 0 : for (int i = 0; i < nPointsIn; ++i)
823 : {
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 : }
830 : }
831 : else
832 : {
833 0 : for (int i = 0; i < nPointsIn; ++i)
834 : {
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 : }
843 : }
844 : }
845 : else
846 : {
847 0 : if (!pabyZ)
848 : {
849 0 : for (int i = 0; i < nPointsIn; ++i)
850 : {
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 : }
859 : }
860 : else
861 : {
862 0 : for (int i = 0; i < nPointsIn; ++i)
863 : {
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 : }
874 : }
875 : }
876 : }
877 0 : break;
878 : }
879 0 : default:
880 0 : CPLError(CE_Failure, CPLE_NotSupported,
881 : "Incompatible geometry for operation");
882 0 : return OGRERR_FAILURE;
883 : }
884 :
885 0 : return OGRERR_NONE;
886 : }
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 49927 : OGRErr OGR_G_SetPoint(OGRGeometryH hGeom, int i, double dfX, double dfY,
913 : double dfZ)
914 :
915 : {
916 49927 : VALIDATE_POINTER1(hGeom, "OGR_G_SetPoint", OGRERR_FAILURE);
917 :
918 49927 : switch (wkbFlatten(ToPointer(hGeom)->getGeometryType()))
919 : {
920 164 : case wkbPoint:
921 : {
922 164 : if (i == 0)
923 : {
924 163 : OGRPoint *poPoint = ToPointer(hGeom)->toPoint();
925 163 : poPoint->setX(dfX);
926 163 : poPoint->setY(dfY);
927 163 : poPoint->setZ(dfZ);
928 : }
929 : else
930 : {
931 1 : CPLError(CE_Failure, CPLE_NotSupported,
932 : "Only i == 0 is supported");
933 1 : return OGRERR_FAILURE;
934 : }
935 : }
936 163 : break;
937 :
938 49762 : case wkbLineString:
939 : case wkbCircularString:
940 : {
941 49762 : if (i < 0)
942 : {
943 2 : CPLError(CE_Failure, CPLE_NotSupported, "Index out of bounds");
944 2 : return OGRERR_FAILURE;
945 : }
946 49760 : return ToPointer(hGeom)->toSimpleCurve()->setPoint(i, dfX, dfY,
947 49760 : dfZ);
948 : }
949 :
950 1 : default:
951 1 : CPLError(CE_Failure, CPLE_NotSupported,
952 : "Incompatible geometry for operation");
953 1 : return OGRERR_FAILURE;
954 : }
955 :
956 163 : return OGRERR_NONE;
957 : }
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 244080 : OGRErr OGR_G_SetPoint_2D(OGRGeometryH hGeom, int i, double dfX, double dfY)
980 :
981 : {
982 244080 : VALIDATE_POINTER1(hGeom, "OGR_G_SetPoint_2D", OGRERR_FAILURE);
983 :
984 244080 : switch (wkbFlatten(ToPointer(hGeom)->getGeometryType()))
985 : {
986 160005 : case wkbPoint:
987 : {
988 160005 : if (i == 0)
989 : {
990 160004 : OGRPoint *poPoint = ToPointer(hGeom)->toPoint();
991 160004 : poPoint->setX(dfX);
992 160004 : poPoint->setY(dfY);
993 : }
994 : else
995 : {
996 1 : CPLError(CE_Failure, CPLE_NotSupported,
997 : "Only i == 0 is supported");
998 1 : return OGRERR_FAILURE;
999 : }
1000 : }
1001 160004 : break;
1002 :
1003 84074 : case wkbLineString:
1004 : case wkbCircularString:
1005 : {
1006 84074 : if (i < 0)
1007 : {
1008 2 : CPLError(CE_Failure, CPLE_NotSupported, "Index out of bounds");
1009 2 : return OGRERR_FAILURE;
1010 : }
1011 84072 : return ToPointer(hGeom)->toSimpleCurve()->setPoint(i, dfX, dfY);
1012 : }
1013 :
1014 1 : default:
1015 1 : CPLError(CE_Failure, CPLE_NotSupported,
1016 : "Incompatible geometry for operation");
1017 1 : return OGRERR_FAILURE;
1018 : }
1019 :
1020 160004 : return OGRERR_NONE;
1021 : }
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 4 : OGRErr OGR_G_SetPointM(OGRGeometryH hGeom, int i, double dfX, double dfY,
1048 : double dfM)
1049 :
1050 : {
1051 4 : VALIDATE_POINTER1(hGeom, "OGR_G_SetPointM", OGRERR_FAILURE);
1052 :
1053 4 : switch (wkbFlatten(ToPointer(hGeom)->getGeometryType()))
1054 : {
1055 1 : case wkbPoint:
1056 : {
1057 1 : if (i == 0)
1058 : {
1059 0 : OGRPoint *poPoint = ToPointer(hGeom)->toPoint();
1060 0 : poPoint->setX(dfX);
1061 0 : poPoint->setY(dfY);
1062 0 : poPoint->setM(dfM);
1063 : }
1064 : else
1065 : {
1066 1 : CPLError(CE_Failure, CPLE_NotSupported,
1067 : "Only i == 0 is supported");
1068 1 : return OGRERR_FAILURE;
1069 : }
1070 : }
1071 0 : break;
1072 :
1073 2 : case wkbLineString:
1074 : case wkbCircularString:
1075 : {
1076 2 : if (i < 0)
1077 : {
1078 1 : CPLError(CE_Failure, CPLE_NotSupported, "Index out of bounds");
1079 1 : return OGRERR_FAILURE;
1080 : }
1081 1 : return ToPointer(hGeom)->toSimpleCurve()->setPointM(i, dfX, dfY,
1082 1 : dfM);
1083 : }
1084 :
1085 1 : default:
1086 1 : CPLError(CE_Failure, CPLE_NotSupported,
1087 : "Incompatible geometry for operation");
1088 1 : return OGRERR_FAILURE;
1089 : }
1090 :
1091 0 : return OGRERR_NONE;
1092 : }
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 4 : OGRErr OGR_G_SetPointZM(OGRGeometryH hGeom, int i, double dfX, double dfY,
1120 : double dfZ, double dfM)
1121 :
1122 : {
1123 4 : VALIDATE_POINTER1(hGeom, "OGR_G_SetPointZM", OGRERR_FAILURE);
1124 :
1125 4 : switch (wkbFlatten(ToPointer(hGeom)->getGeometryType()))
1126 : {
1127 1 : case wkbPoint:
1128 : {
1129 1 : if (i == 0)
1130 : {
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 : }
1137 : else
1138 : {
1139 1 : CPLError(CE_Failure, CPLE_NotSupported,
1140 : "Only i == 0 is supported");
1141 1 : return OGRERR_FAILURE;
1142 : }
1143 : }
1144 0 : break;
1145 :
1146 2 : case wkbLineString:
1147 : case wkbCircularString:
1148 : {
1149 2 : if (i < 0)
1150 : {
1151 1 : CPLError(CE_Failure, CPLE_NotSupported, "Index out of bounds");
1152 1 : return OGRERR_FAILURE;
1153 : }
1154 1 : if (!ToPointer(hGeom)->toSimpleCurve()->setPoint(i, dfX, dfY, dfZ,
1155 : dfM))
1156 1 : return OGRERR_FAILURE;
1157 0 : break;
1158 : }
1159 :
1160 1 : default:
1161 1 : CPLError(CE_Failure, CPLE_NotSupported,
1162 : "Incompatible geometry for operation");
1163 1 : return OGRERR_FAILURE;
1164 : }
1165 :
1166 0 : return OGRERR_NONE;
1167 : }
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 282 : OGRErr OGR_G_AddPoint(OGRGeometryH hGeom, double dfX, double dfY, double dfZ)
1191 :
1192 : {
1193 282 : VALIDATE_POINTER1(hGeom, "OGR_G_AddPoint", OGRERR_FAILURE);
1194 :
1195 282 : switch (wkbFlatten(ToPointer(hGeom)->getGeometryType()))
1196 : {
1197 28 : case wkbPoint:
1198 : {
1199 28 : OGRPoint *poPoint = ToPointer(hGeom)->toPoint();
1200 28 : poPoint->setX(dfX);
1201 28 : poPoint->setY(dfY);
1202 28 : poPoint->setZ(dfZ);
1203 : }
1204 28 : break;
1205 :
1206 253 : case wkbLineString:
1207 : case wkbCircularString:
1208 253 : if (!ToPointer(hGeom)->toSimpleCurve()->addPoint(dfX, dfY, dfZ))
1209 0 : return OGRERR_FAILURE;
1210 253 : break;
1211 :
1212 1 : default:
1213 1 : CPLError(CE_Failure, CPLE_NotSupported,
1214 : "Incompatible geometry for operation");
1215 1 : return OGRERR_FAILURE;
1216 : }
1217 :
1218 281 : return OGRERR_NONE;
1219 : }
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 2019 : OGRErr OGR_G_AddPoint_2D(OGRGeometryH hGeom, double dfX, double dfY)
1242 :
1243 : {
1244 2019 : VALIDATE_POINTER1(hGeom, "OGR_G_AddPoint_2D", OGRERR_FAILURE);
1245 :
1246 2019 : switch (wkbFlatten(ToPointer(hGeom)->getGeometryType()))
1247 : {
1248 834 : case wkbPoint:
1249 : {
1250 834 : OGRPoint *poPoint = ToPointer(hGeom)->toPoint();
1251 834 : poPoint->setX(dfX);
1252 834 : poPoint->setY(dfY);
1253 : }
1254 834 : break;
1255 :
1256 1184 : case wkbLineString:
1257 : case wkbCircularString:
1258 1184 : if (!ToPointer(hGeom)->toSimpleCurve()->addPoint(dfX, dfY))
1259 0 : return OGRERR_FAILURE;
1260 1184 : break;
1261 :
1262 1 : default:
1263 1 : CPLError(CE_Failure, CPLE_NotSupported,
1264 : "Incompatible geometry for operation");
1265 1 : return OGRERR_FAILURE;
1266 : }
1267 :
1268 2018 : return OGRERR_NONE;
1269 : }
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 1 : OGRErr OGR_G_AddPointM(OGRGeometryH hGeom, double dfX, double dfY, double dfM)
1293 :
1294 : {
1295 1 : VALIDATE_POINTER1(hGeom, "OGR_G_AddPointM", OGRERR_FAILURE);
1296 :
1297 1 : switch (wkbFlatten(ToPointer(hGeom)->getGeometryType()))
1298 : {
1299 0 : case wkbPoint:
1300 : {
1301 0 : OGRPoint *poPoint = ToPointer(hGeom)->toPoint();
1302 0 : poPoint->setX(dfX);
1303 0 : poPoint->setY(dfY);
1304 0 : poPoint->setM(dfM);
1305 : }
1306 0 : break;
1307 :
1308 0 : case wkbLineString:
1309 : case wkbCircularString:
1310 0 : if (!ToPointer(hGeom)->toSimpleCurve()->addPointM(dfX, dfY, dfM))
1311 0 : return OGRERR_FAILURE;
1312 0 : break;
1313 :
1314 1 : default:
1315 1 : CPLError(CE_Failure, CPLE_NotSupported,
1316 : "Incompatible geometry for operation");
1317 1 : return OGRERR_FAILURE;
1318 : }
1319 :
1320 0 : return OGRERR_NONE;
1321 : }
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 0 : OGRErr OGR_G_AddPointZM(OGRGeometryH hGeom, double dfX, double dfY, double dfZ,
1346 : double dfM)
1347 :
1348 : {
1349 0 : VALIDATE_POINTER1(hGeom, "OGR_G_AddPointZM", OGRERR_FAILURE);
1350 :
1351 0 : switch (wkbFlatten(ToPointer(hGeom)->getGeometryType()))
1352 : {
1353 0 : case wkbPoint:
1354 : {
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 : }
1361 0 : break;
1362 :
1363 0 : case wkbLineString:
1364 : case wkbCircularString:
1365 0 : if (!ToPointer(hGeom)->toSimpleCurve()->addPoint(dfX, dfY, dfZ,
1366 : dfM))
1367 0 : return OGRERR_FAILURE;
1368 0 : break;
1369 :
1370 0 : default:
1371 0 : CPLError(CE_Failure, CPLE_NotSupported,
1372 : "Incompatible geometry for operation");
1373 0 : return OGRERR_FAILURE;
1374 : }
1375 :
1376 0 : return OGRERR_NONE;
1377 : }
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 14913 : int OGR_G_GetGeometryCount(OGRGeometryH hGeom)
1399 :
1400 : {
1401 14913 : VALIDATE_POINTER1(hGeom, "OGR_G_GetGeometryCount", 0);
1402 :
1403 14913 : const auto poGeom = ToPointer(hGeom);
1404 14913 : const OGRwkbGeometryType eType = wkbFlatten(poGeom->getGeometryType());
1405 14913 : if (OGR_GT_IsSubClassOf(eType, wkbCurvePolygon))
1406 : {
1407 3607 : if (poGeom->toCurvePolygon()->getExteriorRingCurve() == nullptr)
1408 255 : return 0;
1409 : else
1410 3352 : return poGeom->toCurvePolygon()->getNumInteriorRings() + 1;
1411 : }
1412 11306 : else if (OGR_GT_IsSubClassOf(eType, wkbCompoundCurve))
1413 : {
1414 237 : return poGeom->toCompoundCurve()->getNumCurves();
1415 : }
1416 11069 : else if (OGR_GT_IsSubClassOf(eType, wkbGeometryCollection))
1417 : {
1418 4229 : return poGeom->toGeometryCollection()->getNumGeometries();
1419 : }
1420 6840 : else if (OGR_GT_IsSubClassOf(eType, wkbPolyhedralSurface))
1421 : {
1422 86 : return poGeom->toPolyhedralSurface()->getNumGeometries();
1423 : }
1424 : else
1425 : {
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 6754 : return 0;
1431 : }
1432 : }
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 3647 : OGRGeometryH OGR_G_GetGeometryRef(OGRGeometryH hGeom, int iSubGeom)
1463 :
1464 : {
1465 3647 : VALIDATE_POINTER1(hGeom, "OGR_G_GetGeometryRef", nullptr);
1466 :
1467 3647 : const auto poGeom = ToPointer(hGeom);
1468 3647 : const OGRwkbGeometryType eType = wkbFlatten(poGeom->getGeometryType());
1469 3647 : if (OGR_GT_IsSubClassOf(eType, wkbCurvePolygon))
1470 : {
1471 1359 : if (iSubGeom == 0)
1472 1264 : return ToHandle(poGeom->toCurvePolygon()->getExteriorRingCurve());
1473 : else
1474 95 : return ToHandle(
1475 95 : poGeom->toCurvePolygon()->getInteriorRingCurve(iSubGeom - 1));
1476 : }
1477 2288 : else if (OGR_GT_IsSubClassOf(eType, wkbCompoundCurve))
1478 : {
1479 232 : return ToHandle(poGeom->toCompoundCurve()->getCurve(iSubGeom));
1480 : }
1481 2056 : else if (OGR_GT_IsSubClassOf(eType, wkbGeometryCollection))
1482 : {
1483 1924 : return ToHandle(
1484 1924 : poGeom->toGeometryCollection()->getGeometryRef(iSubGeom));
1485 : }
1486 132 : else if (OGR_GT_IsSubClassOf(eType, wkbPolyhedralSurface))
1487 : {
1488 131 : return ToHandle(
1489 131 : poGeom->toPolyhedralSurface()->getGeometryRef(iSubGeom));
1490 : }
1491 : else
1492 : {
1493 1 : CPLError(CE_Failure, CPLE_NotSupported,
1494 : "Incompatible geometry for operation");
1495 1 : return nullptr;
1496 : }
1497 : }
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 106 : OGRErr OGR_G_AddGeometry(OGRGeometryH hGeom, OGRGeometryH hNewSubGeom)
1527 :
1528 : {
1529 106 : VALIDATE_POINTER1(hGeom, "OGR_G_AddGeometry", OGRERR_UNSUPPORTED_OPERATION);
1530 106 : VALIDATE_POINTER1(hNewSubGeom, "OGR_G_AddGeometry",
1531 : OGRERR_UNSUPPORTED_OPERATION);
1532 :
1533 106 : OGRErr eErr = OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
1534 :
1535 106 : auto poGeom = ToPointer(hGeom);
1536 106 : auto poNewSubGeom = ToPointer(hNewSubGeom);
1537 106 : const OGRwkbGeometryType eType = wkbFlatten(poGeom->getGeometryType());
1538 106 : if (OGR_GT_IsSubClassOf(eType, wkbCurvePolygon))
1539 : {
1540 57 : if (OGR_GT_IsCurve(wkbFlatten(poNewSubGeom->getGeometryType())))
1541 57 : eErr = poGeom->toCurvePolygon()->addRing(poNewSubGeom->toCurve());
1542 : }
1543 49 : else if (OGR_GT_IsSubClassOf(eType, wkbCompoundCurve))
1544 : {
1545 2 : if (OGR_GT_IsCurve(wkbFlatten(poNewSubGeom->getGeometryType())))
1546 2 : eErr = poGeom->toCompoundCurve()->addCurve(poNewSubGeom->toCurve());
1547 : }
1548 47 : else if (OGR_GT_IsSubClassOf(eType, wkbGeometryCollection))
1549 : {
1550 41 : eErr = poGeom->toGeometryCollection()->addGeometry(poNewSubGeom);
1551 : }
1552 6 : else if (OGR_GT_IsSubClassOf(eType, wkbPolyhedralSurface))
1553 : {
1554 5 : eErr = poGeom->toPolyhedralSurface()->addGeometry(poNewSubGeom);
1555 : }
1556 :
1557 106 : return eErr;
1558 : }
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 357 : OGRErr OGR_G_AddGeometryDirectly(OGRGeometryH hGeom, OGRGeometryH hNewSubGeom)
1588 :
1589 : {
1590 357 : VALIDATE_POINTER1(hGeom, "OGR_G_AddGeometryDirectly",
1591 : OGRERR_UNSUPPORTED_OPERATION);
1592 357 : VALIDATE_POINTER1(hNewSubGeom, "OGR_G_AddGeometryDirectly",
1593 : OGRERR_UNSUPPORTED_OPERATION);
1594 :
1595 357 : OGRErr eErr = OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
1596 :
1597 357 : auto poGeom = ToPointer(hGeom);
1598 357 : auto poNewSubGeom = ToPointer(hNewSubGeom);
1599 357 : const OGRwkbGeometryType eType = wkbFlatten(poGeom->getGeometryType());
1600 :
1601 357 : if (OGR_GT_IsSubClassOf(eType, wkbCurvePolygon))
1602 : {
1603 2 : if (OGR_GT_IsCurve(wkbFlatten(poNewSubGeom->getGeometryType())))
1604 4 : eErr = poGeom->toCurvePolygon()->addRingDirectly(
1605 2 : poNewSubGeom->toCurve());
1606 : }
1607 355 : else if (OGR_GT_IsSubClassOf(eType, wkbCompoundCurve))
1608 : {
1609 3 : if (OGR_GT_IsCurve(wkbFlatten(poNewSubGeom->getGeometryType())))
1610 3 : eErr = poGeom->toCompoundCurve()->addCurveDirectly(
1611 : poNewSubGeom->toCurve());
1612 : }
1613 352 : else if (OGR_GT_IsSubClassOf(eType, wkbGeometryCollection))
1614 : {
1615 : eErr =
1616 348 : poGeom->toGeometryCollection()->addGeometryDirectly(poNewSubGeom);
1617 : }
1618 4 : else if (OGR_GT_IsSubClassOf(eType, wkbPolyhedralSurface))
1619 : {
1620 3 : eErr = poGeom->toPolyhedralSurface()->addGeometryDirectly(poNewSubGeom);
1621 : }
1622 :
1623 357 : if (eErr != OGRERR_NONE)
1624 3 : delete poNewSubGeom;
1625 :
1626 357 : return eErr;
1627 : }
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 115 : OGRErr OGR_G_RemoveGeometry(OGRGeometryH hGeom, int iGeom, int bDelete)
1659 :
1660 : {
1661 115 : VALIDATE_POINTER1(hGeom, "OGR_G_RemoveGeometry", OGRERR_FAILURE);
1662 :
1663 115 : const auto poGeom = ToPointer(hGeom);
1664 115 : const OGRwkbGeometryType eType = wkbFlatten(poGeom->getGeometryType());
1665 115 : if (OGR_GT_IsSubClassOf(eType, wkbCurvePolygon))
1666 : {
1667 38 : return poGeom->toCurvePolygon()->removeRing(iGeom,
1668 38 : CPL_TO_BOOL(bDelete));
1669 : }
1670 96 : else if (OGR_GT_IsSubClassOf(eType, wkbGeometryCollection))
1671 : {
1672 90 : return poGeom->toGeometryCollection()->removeGeometry(iGeom, bDelete);
1673 : }
1674 6 : else if (OGR_GT_IsSubClassOf(eType, wkbPolyhedralSurface))
1675 : {
1676 5 : return poGeom->toPolyhedralSurface()->removeGeometry(iGeom, bDelete);
1677 : }
1678 : else
1679 : {
1680 1 : return OGRERR_UNSUPPORTED_OPERATION;
1681 : }
1682 : }
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 29 : double OGR_G_Length(OGRGeometryH hGeom)
1707 :
1708 : {
1709 29 : VALIDATE_POINTER1(hGeom, "OGR_G_GetLength", 0);
1710 :
1711 29 : double dfLength = 0.0;
1712 :
1713 29 : const auto poGeom = ToPointer(hGeom);
1714 29 : const OGRwkbGeometryType eType = wkbFlatten(poGeom->getGeometryType());
1715 29 : if (OGR_GT_IsCurve(eType))
1716 : {
1717 21 : dfLength = poGeom->toCurve()->get_Length();
1718 : }
1719 8 : else if (OGR_GT_IsSurface(eType))
1720 : {
1721 2 : dfLength = poGeom->toSurface()->get_Length();
1722 : }
1723 6 : else if (OGR_GT_IsSubClassOf(eType, wkbGeometryCollection))
1724 : {
1725 5 : dfLength = poGeom->toGeometryCollection()->get_Length();
1726 : }
1727 : else
1728 : {
1729 1 : CPLError(CE_Warning, CPLE_AppDefined,
1730 : "OGR_G_Length() called against a non-curve geometry type.");
1731 1 : dfLength = 0.0;
1732 : }
1733 :
1734 29 : return dfLength;
1735 : }
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 29 : double OGR_G_GeodesicLength(OGRGeometryH hGeom)
1767 :
1768 : {
1769 29 : VALIDATE_POINTER1(hGeom, "OGR_G_GeodesicLength", -1);
1770 :
1771 29 : double dfLength = 0.0;
1772 :
1773 29 : const auto poGeom = ToPointer(hGeom);
1774 29 : const OGRwkbGeometryType eType = wkbFlatten(poGeom->getGeometryType());
1775 29 : if (OGR_GT_IsCurve(eType))
1776 : {
1777 12 : dfLength = poGeom->toCurve()->get_GeodesicLength();
1778 : }
1779 17 : else if (OGR_GT_IsSurface(eType))
1780 : {
1781 13 : dfLength = poGeom->toSurface()->get_GeodesicLength();
1782 : }
1783 4 : else if (OGR_GT_IsSubClassOf(eType, wkbGeometryCollection))
1784 : {
1785 3 : dfLength = poGeom->toGeometryCollection()->get_GeodesicLength();
1786 : }
1787 : else
1788 : {
1789 1 : CPLError(
1790 : CE_Failure, CPLE_AppDefined,
1791 : "OGR_G_GeodesicLength() called against a non-curve geometry type.");
1792 1 : dfLength = -1.0;
1793 : }
1794 :
1795 29 : return dfLength;
1796 : }
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 1475 : double OGR_G_Area(OGRGeometryH hGeom)
1824 :
1825 : {
1826 1475 : VALIDATE_POINTER1(hGeom, "OGR_G_Area", 0);
1827 :
1828 1475 : double dfArea = 0.0;
1829 :
1830 1475 : const auto poGeom = ToPointer(hGeom);
1831 1475 : const OGRwkbGeometryType eType = wkbFlatten(poGeom->getGeometryType());
1832 1475 : if (OGR_GT_IsSurface(eType))
1833 : {
1834 1466 : dfArea = poGeom->toSurface()->get_Area();
1835 : }
1836 9 : else if (OGR_GT_IsCurve(eType))
1837 : {
1838 3 : dfArea = poGeom->toCurve()->get_Area();
1839 : }
1840 6 : else if (OGR_GT_IsSubClassOf(eType, wkbGeometryCollection))
1841 : {
1842 5 : dfArea = poGeom->toGeometryCollection()->get_Area();
1843 : }
1844 : else
1845 : {
1846 1 : CPLError(CE_Warning, CPLE_AppDefined,
1847 : "OGR_G_Area() called against non-surface geometry type.");
1848 :
1849 1 : dfArea = 0.0;
1850 : }
1851 :
1852 1475 : return dfArea;
1853 : }
1854 :
1855 : /**
1856 : * \brief Compute geometry area (deprecated)
1857 : *
1858 : * @deprecated
1859 : * @see OGR_G_Area()
1860 : */
1861 0 : double OGR_G_GetArea(OGRGeometryH hGeom)
1862 :
1863 : {
1864 0 : return OGR_G_Area(hGeom);
1865 : }
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 33 : double OGR_G_GeodesicArea(OGRGeometryH hGeom)
1905 :
1906 : {
1907 33 : VALIDATE_POINTER1(hGeom, "OGR_G_GeodesicArea", -1);
1908 :
1909 33 : double dfArea = -1;
1910 :
1911 33 : const auto poGeom = ToPointer(hGeom);
1912 33 : const OGRwkbGeometryType eType = wkbFlatten(poGeom->getGeometryType());
1913 33 : if (OGR_GT_IsSurface(eType))
1914 : {
1915 20 : dfArea = poGeom->toSurface()->get_GeodesicArea();
1916 : }
1917 13 : else if (OGR_GT_IsCurve(eType))
1918 : {
1919 8 : dfArea = poGeom->toCurve()->get_GeodesicArea();
1920 : }
1921 5 : else if (OGR_GT_IsSubClassOf(eType, wkbGeometryCollection))
1922 : {
1923 4 : dfArea = poGeom->toGeometryCollection()->get_GeodesicArea();
1924 : }
1925 : else
1926 : {
1927 1 : CPLError(CE_Failure, CPLE_AppDefined,
1928 : "OGR_G_GeodesicArea() called against non-surface geometry "
1929 : "type.");
1930 : }
1931 :
1932 33 : return dfArea;
1933 : }
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 33 : bool OGR_G_IsClockwise(OGRGeometryH hGeom)
1948 :
1949 : {
1950 33 : VALIDATE_POINTER1(hGeom, "OGR_G_IsClockwise", false);
1951 :
1952 33 : auto poGeom = OGRGeometry::FromHandle(hGeom);
1953 33 : const OGRwkbGeometryType eGType = wkbFlatten(poGeom->getGeometryType());
1954 33 : if (OGR_GT_IsCurve(eGType))
1955 : {
1956 32 : return poGeom->toCurve()->isClockwise();
1957 : }
1958 : else
1959 : {
1960 1 : CPLError(CE_Failure, CPLE_NotSupported,
1961 : "Incompatible geometry for operation");
1962 1 : return false;
1963 : }
1964 : }
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 29 : int OGR_G_HasCurveGeometry(OGRGeometryH hGeom, int bLookForNonLinear)
1995 : {
1996 29 : VALIDATE_POINTER1(hGeom, "OGR_G_HasCurveGeometry", FALSE);
1997 29 : return ToPointer(hGeom)->hasCurveGeometry(bLookForNonLinear);
1998 : }
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 3088 : OGRGeometryH CPL_DLL OGR_G_GetLinearGeometry(OGRGeometryH hGeom,
2030 : double dfMaxAngleStepSizeDegrees,
2031 : CSLConstList papszOptions)
2032 : {
2033 3088 : VALIDATE_POINTER1(hGeom, "OGR_G_GetLinearGeometry", nullptr);
2034 6176 : return ToHandle(ToPointer(hGeom)->getLinearGeometry(
2035 6176 : dfMaxAngleStepSizeDegrees, papszOptions));
2036 : }
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 3067 : OGRGeometryH CPL_DLL OGR_G_GetCurveGeometry(OGRGeometryH hGeom,
2067 : CSLConstList papszOptions)
2068 : {
2069 3067 : VALIDATE_POINTER1(hGeom, "OGR_G_GetCurveGeometry", nullptr);
2070 :
2071 3067 : return ToHandle(ToPointer(hGeom)->getCurveGeometry(papszOptions));
2072 : }
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 22 : OGRGeometryH OGR_G_Value(OGRGeometryH hGeom, double dfDistance)
2093 : {
2094 22 : VALIDATE_POINTER1(hGeom, "OGR_G_Value", nullptr);
2095 :
2096 22 : const auto poGeom = ToPointer(hGeom);
2097 22 : if (OGR_GT_IsCurve(poGeom->getGeometryType()))
2098 : {
2099 22 : OGRPoint *p = new OGRPoint();
2100 22 : poGeom->toCurve()->Value(dfDistance, p);
2101 22 : return ToHandle(p);
2102 : }
2103 :
2104 0 : return nullptr;
2105 : }
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 2 : void OGRSetNonLinearGeometriesEnabledFlag(int bFlag)
2136 : {
2137 2 : bNonLinearGeometriesEnabled = bFlag != FALSE;
2138 2 : }
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 40390 : int OGRGetNonLinearGeometriesEnabledFlag(void)
2155 : {
2156 40390 : return bNonLinearGeometriesEnabled;
2157 : }
|