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