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