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