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