Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: OpenGIS Simple Features Reference Implementation
4 : * Purpose: Implements a few base methods on OGRGeometry.
5 : * Author: Frank Warmerdam, warmerdam@pobox.com
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 1999, Frank Warmerdam
9 : * Copyright (c) 2008-2013, Even Rouault <even dot rouault at spatialys.com>
10 : *
11 : * SPDX-License-Identifier: MIT
12 : ****************************************************************************/
13 :
14 : #include "cpl_port.h"
15 : #include "ogr_geometry.h"
16 :
17 : #include <climits>
18 : #include <cstdarg>
19 : #include <cstddef>
20 : #include <cstdio>
21 : #include <cstdlib>
22 : #include <cstring>
23 : #include <limits>
24 : #include <memory>
25 : #include <stdexcept>
26 : #include <string>
27 :
28 : #include "cpl_conv.h"
29 : #include "cpl_error.h"
30 : #include "cpl_multiproc.h"
31 : #include "cpl_string.h"
32 : #include "ogr_api.h"
33 : #include "ogr_core.h"
34 : #include "ogr_geos.h"
35 : #include "ogr_sfcgal.h"
36 : #include "ogr_libs.h"
37 : #include "ogr_p.h"
38 : #include "ogr_spatialref.h"
39 : #include "ogr_srs_api.h"
40 : #include "ogr_wkb.h"
41 :
42 : #ifndef HAVE_GEOS
43 : #define UNUSED_IF_NO_GEOS CPL_UNUSED
44 : #else
45 : #define UNUSED_IF_NO_GEOS
46 : #endif
47 :
48 : //! @cond Doxygen_Suppress
49 : int OGRGeometry::bGenerate_DB2_V72_BYTE_ORDER = FALSE;
50 : //! @endcond
51 :
52 : #ifdef HAVE_GEOS
53 122 : static void OGRGEOSErrorHandler(const char *fmt, ...)
54 : {
55 : va_list args;
56 :
57 122 : va_start(args, fmt);
58 122 : CPLErrorV(CE_Failure, CPLE_AppDefined, fmt, args);
59 122 : va_end(args);
60 122 : }
61 :
62 91 : static void OGRGEOSWarningHandler(const char *fmt, ...)
63 : {
64 : va_list args;
65 :
66 91 : va_start(args, fmt);
67 91 : CPLErrorV(CE_Warning, CPLE_AppDefined, fmt, args);
68 91 : va_end(args);
69 91 : }
70 : #endif
71 :
72 : /************************************************************************/
73 : /* OGRWktOptions() */
74 : /************************************************************************/
75 :
76 34233 : int OGRWktOptions::getDefaultPrecision()
77 : {
78 34233 : return atoi(CPLGetConfigOption("OGR_WKT_PRECISION", "15"));
79 : }
80 :
81 34233 : bool OGRWktOptions::getDefaultRound()
82 : {
83 34233 : return CPLTestBool(CPLGetConfigOption("OGR_WKT_ROUND", "TRUE"));
84 : }
85 :
86 : /************************************************************************/
87 : /* OGRGeometry() */
88 : /************************************************************************/
89 :
90 : OGRGeometry::OGRGeometry() = default;
91 :
92 : /************************************************************************/
93 : /* OGRGeometry( const OGRGeometry& ) */
94 : /************************************************************************/
95 :
96 : /**
97 : * \brief Copy constructor.
98 : *
99 : * Note: before GDAL 2.1, only the default implementation of the constructor
100 : * existed, which could be unsafe to use.
101 : *
102 : * @since GDAL 2.1
103 : */
104 :
105 2132700 : OGRGeometry::OGRGeometry(const OGRGeometry &other)
106 2132700 : : poSRS(other.poSRS), flags(other.flags)
107 : {
108 2132700 : if (poSRS != nullptr)
109 484767 : const_cast<OGRSpatialReference *>(poSRS)->Reference();
110 2132700 : }
111 :
112 : /************************************************************************/
113 : /* OGRGeometry( OGRGeometry&& ) */
114 : /************************************************************************/
115 :
116 : /**
117 : * \brief Move constructor.
118 : *
119 : * @since GDAL 3.11
120 : */
121 :
122 112347 : OGRGeometry::OGRGeometry(OGRGeometry &&other)
123 112347 : : poSRS(other.poSRS), flags(other.flags)
124 : {
125 112347 : other.poSRS = nullptr;
126 112347 : }
127 :
128 : /************************************************************************/
129 : /* ~OGRGeometry() */
130 : /************************************************************************/
131 :
132 25632500 : OGRGeometry::~OGRGeometry()
133 :
134 : {
135 12816300 : if (poSRS != nullptr)
136 3971770 : const_cast<OGRSpatialReference *>(poSRS)->Release();
137 12816300 : }
138 :
139 : /************************************************************************/
140 : /* operator=( const OGRGeometry&) */
141 : /************************************************************************/
142 :
143 : /**
144 : * \brief Assignment operator.
145 : *
146 : * Note: before GDAL 2.1, only the default implementation of the operator
147 : * existed, which could be unsafe to use.
148 : *
149 : * @since GDAL 2.1
150 : */
151 :
152 1575 : OGRGeometry &OGRGeometry::operator=(const OGRGeometry &other)
153 : {
154 1575 : if (this != &other)
155 : {
156 1575 : empty();
157 1575 : assignSpatialReference(other.getSpatialReference());
158 1575 : flags = other.flags;
159 : }
160 1575 : return *this;
161 : }
162 :
163 : /************************************************************************/
164 : /* operator=( OGRGeometry&&) */
165 : /************************************************************************/
166 :
167 : /**
168 : * \brief Move assignment operator.
169 : *
170 : * @since GDAL 3.11
171 : */
172 :
173 85461 : OGRGeometry &OGRGeometry::operator=(OGRGeometry &&other)
174 : {
175 85461 : if (this != &other)
176 : {
177 85461 : poSRS = other.poSRS;
178 85461 : other.poSRS = nullptr;
179 85461 : flags = other.flags;
180 : }
181 85461 : return *this;
182 : }
183 :
184 : /************************************************************************/
185 : /* dumpReadable() */
186 : /************************************************************************/
187 :
188 : /**
189 : * \brief Dump geometry in well known text format to indicated output file.
190 : *
191 : * A few options can be defined to change the default dump :
192 : * <ul>
193 : * <li>DISPLAY_GEOMETRY=NO : to hide the dump of the geometry</li>
194 : * <li>DISPLAY_GEOMETRY=WKT or YES (default) : dump the geometry as a WKT</li>
195 : * <li>DISPLAY_GEOMETRY=SUMMARY : to get only a summary of the geometry</li>
196 : * </ul>
197 : *
198 : * This method is the same as the C function OGR_G_DumpReadable().
199 : *
200 : * @param fp the text file to write the geometry to.
201 : * @param pszPrefix the prefix to put on each line of output.
202 : * @param papszOptions NULL terminated list of options (may be NULL)
203 : */
204 :
205 0 : void OGRGeometry::dumpReadable(FILE *fp, const char *pszPrefix,
206 : CSLConstList papszOptions) const
207 :
208 : {
209 0 : if (fp == nullptr)
210 0 : fp = stdout;
211 :
212 0 : const auto osStr = dumpReadable(pszPrefix, papszOptions);
213 0 : fprintf(fp, "%s", osStr.c_str());
214 0 : }
215 :
216 : /************************************************************************/
217 : /* dumpReadable() */
218 : /************************************************************************/
219 :
220 : /**
221 : * \brief Dump geometry in well known text format to indicated output file.
222 : *
223 : * A few options can be defined to change the default dump :
224 : * <ul>
225 : * <li>DISPLAY_GEOMETRY=NO : to hide the dump of the geometry</li>
226 : * <li>DISPLAY_GEOMETRY=WKT or YES (default) : dump the geometry as a WKT</li>
227 : * <li>DISPLAY_GEOMETRY=SUMMARY : to get only a summary of the geometry</li>
228 : * <li>XY_COORD_PRECISION=integer: number of decimal figures for X,Y coordinates
229 : * in WKT (added in GDAL 3.9)</li>
230 : * <li>Z_COORD_PRECISION=integer: number of decimal figures for Z coordinates in
231 : * WKT (added in GDAL 3.9)</li>
232 : * </ul>
233 : *
234 : * @param pszPrefix the prefix to put on each line of output.
235 : * @param papszOptions NULL terminated list of options (may be NULL)
236 : * @return a string with the geometry representation.
237 : * @since GDAL 3.7
238 : */
239 :
240 223 : std::string OGRGeometry::dumpReadable(const char *pszPrefix,
241 : CSLConstList papszOptions) const
242 :
243 : {
244 223 : if (pszPrefix == nullptr)
245 223 : pszPrefix = "";
246 :
247 223 : std::string osRet;
248 :
249 : const auto exportToWktWithOpts =
250 1484 : [this, pszPrefix, papszOptions, &osRet](bool bIso)
251 : {
252 212 : OGRErr err(OGRERR_NONE);
253 212 : OGRWktOptions opts;
254 212 : if (const char *pszXYPrecision =
255 212 : CSLFetchNameValue(papszOptions, "XY_COORD_PRECISION"))
256 : {
257 1 : opts.format = OGRWktFormat::F;
258 1 : opts.xyPrecision = atoi(pszXYPrecision);
259 : }
260 212 : if (const char *pszZPrecision =
261 212 : CSLFetchNameValue(papszOptions, "Z_COORD_PRECISION"))
262 : {
263 1 : opts.format = OGRWktFormat::F;
264 1 : opts.zPrecision = atoi(pszZPrecision);
265 : }
266 212 : if (bIso)
267 212 : opts.variant = wkbVariantIso;
268 424 : std::string wkt = exportToWkt(opts, &err);
269 212 : if (err == OGRERR_NONE)
270 : {
271 212 : osRet = pszPrefix;
272 212 : osRet += wkt.data();
273 212 : osRet += '\n';
274 : }
275 212 : };
276 :
277 : const char *pszDisplayGeometry =
278 223 : CSLFetchNameValue(papszOptions, "DISPLAY_GEOMETRY");
279 223 : if (pszDisplayGeometry != nullptr && EQUAL(pszDisplayGeometry, "SUMMARY"))
280 : {
281 11 : osRet += CPLOPrintf("%s%s : ", pszPrefix, getGeometryName());
282 11 : switch (getGeometryType())
283 : {
284 1 : case wkbUnknown:
285 : case wkbNone:
286 : case wkbPoint:
287 : case wkbPoint25D:
288 : case wkbPointM:
289 : case wkbPointZM:
290 1 : break;
291 0 : case wkbPolyhedralSurface:
292 : case wkbTIN:
293 : case wkbPolyhedralSurfaceZ:
294 : case wkbTINZ:
295 : case wkbPolyhedralSurfaceM:
296 : case wkbTINM:
297 : case wkbPolyhedralSurfaceZM:
298 : case wkbTINZM:
299 : {
300 0 : const OGRPolyhedralSurface *poPS = toPolyhedralSurface();
301 : osRet +=
302 0 : CPLOPrintf("%d geometries:\n", poPS->getNumGeometries());
303 0 : for (auto &&poSubGeom : *poPS)
304 : {
305 0 : osRet += pszPrefix;
306 0 : osRet += poSubGeom->dumpReadable(pszPrefix, papszOptions);
307 : }
308 0 : break;
309 : }
310 0 : case wkbLineString:
311 : case wkbLineString25D:
312 : case wkbLineStringM:
313 : case wkbLineStringZM:
314 : case wkbCircularString:
315 : case wkbCircularStringZ:
316 : case wkbCircularStringM:
317 : case wkbCircularStringZM:
318 : {
319 0 : const OGRSimpleCurve *poSC = toSimpleCurve();
320 0 : osRet += CPLOPrintf("%d points\n", poSC->getNumPoints());
321 0 : break;
322 : }
323 10 : case wkbPolygon:
324 : case wkbTriangle:
325 : case wkbTriangleZ:
326 : case wkbTriangleM:
327 : case wkbTriangleZM:
328 : case wkbPolygon25D:
329 : case wkbPolygonM:
330 : case wkbPolygonZM:
331 : case wkbCurvePolygon:
332 : case wkbCurvePolygonZ:
333 : case wkbCurvePolygonM:
334 : case wkbCurvePolygonZM:
335 : {
336 10 : const OGRCurvePolygon *poPoly = toCurvePolygon();
337 10 : const OGRCurve *poRing = poPoly->getExteriorRingCurve();
338 10 : const int nRings = poPoly->getNumInteriorRings();
339 10 : if (poRing == nullptr)
340 : {
341 0 : osRet += "empty";
342 : }
343 : else
344 : {
345 10 : osRet += CPLOPrintf("%d points", poRing->getNumPoints());
346 10 : if (wkbFlatten(poRing->getGeometryType()) ==
347 : wkbCompoundCurve)
348 : {
349 0 : osRet += " (";
350 0 : osRet += poRing->dumpReadable(nullptr, papszOptions);
351 0 : osRet += ")";
352 : }
353 10 : if (nRings)
354 : {
355 0 : osRet += CPLOPrintf(", %d inner rings (", nRings);
356 0 : for (int ir = 0; ir < nRings; ir++)
357 : {
358 0 : poRing = poPoly->getInteriorRingCurve(ir);
359 0 : if (ir)
360 0 : osRet += ", ";
361 : osRet +=
362 0 : CPLOPrintf("%d points", poRing->getNumPoints());
363 0 : if (wkbFlatten(poRing->getGeometryType()) ==
364 : wkbCompoundCurve)
365 : {
366 0 : osRet += " (";
367 : osRet +=
368 0 : poRing->dumpReadable(nullptr, papszOptions);
369 0 : osRet += ")";
370 : }
371 : }
372 0 : osRet += ")";
373 : }
374 : }
375 10 : osRet += "\n";
376 10 : break;
377 : }
378 0 : case wkbCompoundCurve:
379 : case wkbCompoundCurveZ:
380 : case wkbCompoundCurveM:
381 : case wkbCompoundCurveZM:
382 : {
383 0 : const OGRCompoundCurve *poCC = toCompoundCurve();
384 0 : if (poCC->getNumCurves() == 0)
385 : {
386 0 : osRet += "empty";
387 : }
388 : else
389 : {
390 0 : for (int i = 0; i < poCC->getNumCurves(); i++)
391 : {
392 0 : if (i)
393 0 : osRet += ", ";
394 : osRet +=
395 0 : CPLOPrintf("%s (%d points)",
396 0 : poCC->getCurve(i)->getGeometryName(),
397 0 : poCC->getCurve(i)->getNumPoints());
398 : }
399 : }
400 0 : break;
401 : }
402 :
403 0 : case wkbMultiPoint:
404 : case wkbMultiLineString:
405 : case wkbMultiPolygon:
406 : case wkbMultiCurve:
407 : case wkbMultiSurface:
408 : case wkbGeometryCollection:
409 : case wkbMultiPoint25D:
410 : case wkbMultiLineString25D:
411 : case wkbMultiPolygon25D:
412 : case wkbMultiCurveZ:
413 : case wkbMultiSurfaceZ:
414 : case wkbGeometryCollection25D:
415 : case wkbMultiPointM:
416 : case wkbMultiLineStringM:
417 : case wkbMultiPolygonM:
418 : case wkbMultiCurveM:
419 : case wkbMultiSurfaceM:
420 : case wkbGeometryCollectionM:
421 : case wkbMultiPointZM:
422 : case wkbMultiLineStringZM:
423 : case wkbMultiPolygonZM:
424 : case wkbMultiCurveZM:
425 : case wkbMultiSurfaceZM:
426 : case wkbGeometryCollectionZM:
427 : {
428 0 : const OGRGeometryCollection *poColl = toGeometryCollection();
429 : osRet +=
430 0 : CPLOPrintf("%d geometries:\n", poColl->getNumGeometries());
431 0 : for (auto &&poSubGeom : *poColl)
432 : {
433 0 : osRet += pszPrefix;
434 0 : osRet += poSubGeom->dumpReadable(pszPrefix, papszOptions);
435 : }
436 0 : break;
437 : }
438 0 : case wkbLinearRing:
439 : case wkbCurve:
440 : case wkbSurface:
441 : case wkbCurveZ:
442 : case wkbSurfaceZ:
443 : case wkbCurveM:
444 : case wkbSurfaceM:
445 : case wkbCurveZM:
446 : case wkbSurfaceZM:
447 0 : break;
448 11 : }
449 : }
450 212 : else if (pszDisplayGeometry != nullptr && EQUAL(pszDisplayGeometry, "WKT"))
451 : {
452 0 : exportToWktWithOpts(/* bIso=*/false);
453 : }
454 212 : else if (pszDisplayGeometry == nullptr || CPLTestBool(pszDisplayGeometry) ||
455 0 : EQUAL(pszDisplayGeometry, "ISO_WKT"))
456 : {
457 212 : exportToWktWithOpts(/* bIso=*/true);
458 : }
459 :
460 446 : return osRet;
461 : }
462 :
463 : /************************************************************************/
464 : /* OGR_G_DumpReadable() */
465 : /************************************************************************/
466 : /**
467 : * \brief Dump geometry in well known text format to indicated output file.
468 : *
469 : * This method is the same as the CPP method OGRGeometry::dumpReadable.
470 : *
471 : * @param hGeom handle on the geometry to dump.
472 : * @param fp the text file to write the geometry to.
473 : * @param pszPrefix the prefix to put on each line of output.
474 : */
475 :
476 0 : void OGR_G_DumpReadable(OGRGeometryH hGeom, FILE *fp, const char *pszPrefix)
477 :
478 : {
479 0 : VALIDATE_POINTER0(hGeom, "OGR_G_DumpReadable");
480 :
481 0 : OGRGeometry::FromHandle(hGeom)->dumpReadable(fp, pszPrefix);
482 : }
483 :
484 : /************************************************************************/
485 : /* assignSpatialReference() */
486 : /************************************************************************/
487 :
488 : /**
489 : * \brief Assign spatial reference to this object.
490 : *
491 : * Any existing spatial reference
492 : * is replaced, but under no circumstances does this result in the object
493 : * being reprojected. It is just changing the interpretation of the existing
494 : * geometry. Note that assigning a spatial reference increments the
495 : * reference count on the OGRSpatialReference, but does not copy it.
496 : *
497 : * Starting with GDAL 2.3, this will also assign the spatial reference to
498 : * potential sub-geometries of the geometry (OGRGeometryCollection,
499 : * OGRCurvePolygon/OGRPolygon, OGRCompoundCurve, OGRPolyhedralSurface and their
500 : * derived classes).
501 : *
502 : * This is similar to the SFCOM IGeometry::put_SpatialReference() method.
503 : *
504 : * This method is the same as the C function OGR_G_AssignSpatialReference().
505 : *
506 : * @param poSR new spatial reference system to apply.
507 : */
508 :
509 5488300 : void OGRGeometry::assignSpatialReference(const OGRSpatialReference *poSR)
510 :
511 : {
512 : // Do in that order to properly handle poSR == poSRS
513 5488300 : if (poSR != nullptr)
514 3511170 : const_cast<OGRSpatialReference *>(poSR)->Reference();
515 5488300 : if (poSRS != nullptr)
516 24165 : const_cast<OGRSpatialReference *>(poSRS)->Release();
517 :
518 5488300 : poSRS = poSR;
519 5488300 : }
520 :
521 : /************************************************************************/
522 : /* OGR_G_AssignSpatialReference() */
523 : /************************************************************************/
524 : /**
525 : * \brief Assign spatial reference to this object.
526 : *
527 : * Any existing spatial reference
528 : * is replaced, but under no circumstances does this result in the object
529 : * being reprojected. It is just changing the interpretation of the existing
530 : * geometry. Note that assigning a spatial reference increments the
531 : * reference count on the OGRSpatialReference, but does not copy it.
532 : *
533 : * Starting with GDAL 2.3, this will also assign the spatial reference to
534 : * potential sub-geometries of the geometry (OGRGeometryCollection,
535 : * OGRCurvePolygon/OGRPolygon, OGRCompoundCurve, OGRPolyhedralSurface and their
536 : * derived classes).
537 : *
538 : * This is similar to the SFCOM IGeometry::put_SpatialReference() method.
539 : *
540 : * This function is the same as the CPP method
541 : * OGRGeometry::assignSpatialReference.
542 : *
543 : * @param hGeom handle on the geometry to apply the new spatial reference
544 : * system.
545 : * @param hSRS handle on the new spatial reference system to apply.
546 : */
547 :
548 146 : void OGR_G_AssignSpatialReference(OGRGeometryH hGeom, OGRSpatialReferenceH hSRS)
549 :
550 : {
551 146 : VALIDATE_POINTER0(hGeom, "OGR_G_AssignSpatialReference");
552 :
553 292 : OGRGeometry::FromHandle(hGeom)->assignSpatialReference(
554 146 : OGRSpatialReference::FromHandle(hSRS));
555 : }
556 :
557 : /************************************************************************/
558 : /* Intersects() */
559 : /************************************************************************/
560 :
561 : /**
562 : * \brief Do these features intersect?
563 : *
564 : * Determines whether two geometries intersect. If GEOS is enabled, then
565 : * this is done in rigorous fashion otherwise TRUE is returned if the
566 : * envelopes (bounding boxes) of the two geometries overlap.
567 : *
568 : * The poOtherGeom argument may be safely NULL, but in this case the method
569 : * will always return TRUE. That is, a NULL geometry is treated as being
570 : * everywhere.
571 : *
572 : * This method is the same as the C function OGR_G_Intersects().
573 : *
574 : * @param poOtherGeom the other geometry to test against.
575 : *
576 : * @return TRUE if the geometries intersect, otherwise FALSE.
577 : */
578 :
579 34 : OGRBoolean OGRGeometry::Intersects(const OGRGeometry *poOtherGeom) const
580 :
581 : {
582 34 : if (poOtherGeom == nullptr)
583 0 : return TRUE;
584 :
585 34 : OGREnvelope oEnv1;
586 34 : getEnvelope(&oEnv1);
587 :
588 34 : OGREnvelope oEnv2;
589 34 : poOtherGeom->getEnvelope(&oEnv2);
590 :
591 34 : if (oEnv1.MaxX < oEnv2.MinX || oEnv1.MaxY < oEnv2.MinY ||
592 18 : oEnv2.MaxX < oEnv1.MinX || oEnv2.MaxY < oEnv1.MinY)
593 16 : return FALSE;
594 :
595 : #ifndef HAVE_GEOS
596 : // Without GEOS we assume that envelope overlap is equivalent to
597 : // actual intersection.
598 : return TRUE;
599 : #else
600 :
601 18 : GEOSContextHandle_t hGEOSCtxt = createGEOSContext();
602 18 : GEOSGeom hThisGeosGeom = exportToGEOS(hGEOSCtxt);
603 18 : GEOSGeom hOtherGeosGeom = poOtherGeom->exportToGEOS(hGEOSCtxt);
604 :
605 18 : OGRBoolean bResult = FALSE;
606 18 : if (hThisGeosGeom != nullptr && hOtherGeosGeom != nullptr)
607 : {
608 18 : bResult =
609 18 : GEOSIntersects_r(hGEOSCtxt, hThisGeosGeom, hOtherGeosGeom) != 0;
610 : }
611 :
612 18 : GEOSGeom_destroy_r(hGEOSCtxt, hThisGeosGeom);
613 18 : GEOSGeom_destroy_r(hGEOSCtxt, hOtherGeosGeom);
614 18 : freeGEOSContext(hGEOSCtxt);
615 :
616 18 : return bResult;
617 : #endif // HAVE_GEOS
618 : }
619 :
620 : // Old API compatibility function.
621 :
622 : //! @cond Doxygen_Suppress
623 0 : OGRBoolean OGRGeometry::Intersect(OGRGeometry *poOtherGeom) const
624 :
625 : {
626 0 : return Intersects(poOtherGeom);
627 : }
628 :
629 : //! @endcond
630 :
631 : /************************************************************************/
632 : /* OGR_G_Intersects() */
633 : /************************************************************************/
634 : /**
635 : * \brief Do these features intersect?
636 : *
637 : * Determines whether two geometries intersect. If GEOS is enabled, then
638 : * this is done in rigorous fashion otherwise TRUE is returned if the
639 : * envelopes (bounding boxes) of the two geometries overlap.
640 : *
641 : * This function is the same as the CPP method OGRGeometry::Intersects.
642 : *
643 : * @param hGeom handle on the first geometry.
644 : * @param hOtherGeom handle on the other geometry to test against.
645 : *
646 : * @return TRUE if the geometries intersect, otherwise FALSE.
647 : */
648 :
649 11 : int OGR_G_Intersects(OGRGeometryH hGeom, OGRGeometryH hOtherGeom)
650 :
651 : {
652 11 : VALIDATE_POINTER1(hGeom, "OGR_G_Intersects", FALSE);
653 11 : VALIDATE_POINTER1(hOtherGeom, "OGR_G_Intersects", FALSE);
654 :
655 22 : return OGRGeometry::FromHandle(hGeom)->Intersects(
656 11 : OGRGeometry::FromHandle(hOtherGeom));
657 : }
658 :
659 : //! @cond Doxygen_Suppress
660 0 : int OGR_G_Intersect(OGRGeometryH hGeom, OGRGeometryH hOtherGeom)
661 :
662 : {
663 0 : VALIDATE_POINTER1(hGeom, "OGR_G_Intersect", FALSE);
664 0 : VALIDATE_POINTER1(hOtherGeom, "OGR_G_Intersect", FALSE);
665 :
666 0 : return OGRGeometry::FromHandle(hGeom)->Intersects(
667 0 : OGRGeometry::FromHandle(hOtherGeom));
668 : }
669 :
670 : //! @endcond
671 :
672 : /************************************************************************/
673 : /* transformTo() */
674 : /************************************************************************/
675 :
676 : /**
677 : * \brief Transform geometry to new spatial reference system.
678 : *
679 : * This method will transform the coordinates of a geometry from
680 : * their current spatial reference system to a new target spatial
681 : * reference system. Normally this means reprojecting the vectors,
682 : * but it could include datum shifts, and changes of units.
683 : *
684 : * This method will only work if the geometry already has an assigned
685 : * spatial reference system, and if it is transformable to the target
686 : * coordinate system.
687 : *
688 : * Because this method requires internal creation and initialization of an
689 : * OGRCoordinateTransformation object it is significantly more expensive to
690 : * use this method to transform many geometries than it is to create the
691 : * OGRCoordinateTransformation in advance, and call transform() with that
692 : * transformation. This method exists primarily for convenience when only
693 : * transforming a single geometry.
694 : *
695 : * This method is the same as the C function OGR_G_TransformTo().
696 : *
697 : * @param poSR spatial reference system to transform to.
698 : *
699 : * @return OGRERR_NONE on success, or an error code.
700 : */
701 :
702 19 : OGRErr OGRGeometry::transformTo(const OGRSpatialReference *poSR)
703 :
704 : {
705 19 : if (getSpatialReference() == nullptr)
706 : {
707 1 : CPLError(CE_Failure, CPLE_AppDefined, "Geometry has no SRS");
708 1 : return OGRERR_FAILURE;
709 : }
710 :
711 18 : if (poSR == nullptr)
712 : {
713 0 : CPLError(CE_Failure, CPLE_AppDefined, "Target SRS is NULL");
714 0 : return OGRERR_FAILURE;
715 : }
716 :
717 : OGRCoordinateTransformation *poCT =
718 18 : OGRCreateCoordinateTransformation(getSpatialReference(), poSR);
719 18 : if (poCT == nullptr)
720 0 : return OGRERR_FAILURE;
721 :
722 18 : const OGRErr eErr = transform(poCT);
723 :
724 18 : delete poCT;
725 :
726 18 : return eErr;
727 : }
728 :
729 : /************************************************************************/
730 : /* OGR_G_TransformTo() */
731 : /************************************************************************/
732 : /**
733 : * \brief Transform geometry to new spatial reference system.
734 : *
735 : * This function will transform the coordinates of a geometry from
736 : * their current spatial reference system to a new target spatial
737 : * reference system. Normally this means reprojecting the vectors,
738 : * but it could include datum shifts, and changes of units.
739 : *
740 : * This function will only work if the geometry already has an assigned
741 : * spatial reference system, and if it is transformable to the target
742 : * coordinate system.
743 : *
744 : * Because this function requires internal creation and initialization of an
745 : * OGRCoordinateTransformation object it is significantly more expensive to
746 : * use this function to transform many geometries than it is to create the
747 : * OGRCoordinateTransformation in advance, and call transform() with that
748 : * transformation. This function exists primarily for convenience when only
749 : * transforming a single geometry.
750 : *
751 : * This function is the same as the CPP method OGRGeometry::transformTo.
752 : *
753 : * @param hGeom handle on the geometry to apply the transform to.
754 : * @param hSRS handle on the spatial reference system to apply.
755 : *
756 : * @return OGRERR_NONE on success, or an error code.
757 : */
758 :
759 9 : OGRErr OGR_G_TransformTo(OGRGeometryH hGeom, OGRSpatialReferenceH hSRS)
760 :
761 : {
762 9 : VALIDATE_POINTER1(hGeom, "OGR_G_TransformTo", OGRERR_FAILURE);
763 :
764 18 : return OGRGeometry::FromHandle(hGeom)->transformTo(
765 18 : OGRSpatialReference::FromHandle(hSRS));
766 : }
767 :
768 : /**
769 : * \fn OGRErr OGRGeometry::transform( OGRCoordinateTransformation *poCT );
770 : *
771 : * \brief Apply arbitrary coordinate transformation to geometry.
772 : *
773 : * This method will transform the coordinates of a geometry from
774 : * their current spatial reference system to a new target spatial
775 : * reference system. Normally this means reprojecting the vectors,
776 : * but it could include datum shifts, and changes of units.
777 : *
778 : * Note that this method does not require that the geometry already
779 : * have a spatial reference system. It will be assumed that they can
780 : * be treated as having the source spatial reference system of the
781 : * OGRCoordinateTransformation object, and the actual SRS of the geometry
782 : * will be ignored. On successful completion the output OGRSpatialReference
783 : * of the OGRCoordinateTransformation will be assigned to the geometry.
784 : *
785 : * This method only does reprojection on a point-by-point basis. It does not
786 : * include advanced logic to deal with discontinuities at poles or antimeridian.
787 : * For that, use the OGRGeometryFactory::transformWithOptions() method.
788 : *
789 : * This method is the same as the C function OGR_G_Transform().
790 : *
791 : * @param poCT the transformation to apply.
792 : *
793 : * @return OGRERR_NONE on success or an error code.
794 : */
795 :
796 : /************************************************************************/
797 : /* OGR_G_Transform() */
798 : /************************************************************************/
799 : /**
800 : * \brief Apply arbitrary coordinate transformation to geometry.
801 : *
802 : * This function will transform the coordinates of a geometry from
803 : * their current spatial reference system to a new target spatial
804 : * reference system. Normally this means reprojecting the vectors,
805 : * but it could include datum shifts, and changes of units.
806 : *
807 : * Note that this function does not require that the geometry already
808 : * have a spatial reference system. It will be assumed that they can
809 : * be treated as having the source spatial reference system of the
810 : * OGRCoordinateTransformation object, and the actual SRS of the geometry
811 : * will be ignored. On successful completion the output OGRSpatialReference
812 : * of the OGRCoordinateTransformation will be assigned to the geometry.
813 : *
814 : * This function only does reprojection on a point-by-point basis. It does not
815 : * include advanced logic to deal with discontinuities at poles or antimeridian.
816 : * For that, use the OGR_GeomTransformer_Create() and
817 : * OGR_GeomTransformer_Transform() functions.
818 : *
819 : * This function is the same as the CPP method OGRGeometry::transform.
820 : *
821 : * @param hGeom handle on the geometry to apply the transform to.
822 : * @param hTransform handle on the transformation to apply.
823 : *
824 : * @return OGRERR_NONE on success or an error code.
825 : */
826 :
827 17 : OGRErr OGR_G_Transform(OGRGeometryH hGeom,
828 : OGRCoordinateTransformationH hTransform)
829 :
830 : {
831 17 : VALIDATE_POINTER1(hGeom, "OGR_G_Transform", OGRERR_FAILURE);
832 :
833 34 : return OGRGeometry::FromHandle(hGeom)->transform(
834 17 : OGRCoordinateTransformation::FromHandle(hTransform));
835 : }
836 :
837 : /**
838 : * \fn int OGRGeometry::getDimension() const;
839 : *
840 : * \brief Get the dimension of this object.
841 : *
842 : * This method corresponds to the SFCOM IGeometry::GetDimension() method.
843 : * It indicates the dimension of the object, but does not indicate the
844 : * dimension of the underlying space (as indicated by
845 : * OGRGeometry::getCoordinateDimension()).
846 : *
847 : * This method is the same as the C function OGR_G_GetDimension().
848 : *
849 : * @return 0 for points, 1 for lines and 2 for surfaces.
850 : */
851 :
852 : /**
853 : * \brief Get the geometry type that conforms with ISO SQL/MM Part3
854 : *
855 : * @return the geometry type that conforms with ISO SQL/MM Part3
856 : */
857 401093 : OGRwkbGeometryType OGRGeometry::getIsoGeometryType() const
858 : {
859 401093 : OGRwkbGeometryType nGType = wkbFlatten(getGeometryType());
860 :
861 401093 : if (flags & OGR_G_3D)
862 137131 : nGType = static_cast<OGRwkbGeometryType>(nGType + 1000);
863 401093 : if (flags & OGR_G_MEASURED)
864 25512 : nGType = static_cast<OGRwkbGeometryType>(nGType + 2000);
865 :
866 401093 : return nGType;
867 : }
868 :
869 : /************************************************************************/
870 : /* OGRGeometry::segmentize() */
871 : /************************************************************************/
872 : /**
873 : *
874 : * \brief Modify the geometry such it has no segment longer then the
875 : * given distance.
876 : *
877 : * This method modifies the geometry to add intermediate vertices if necessary
878 : * so that the maximum length between 2 consecutive vertices is lower than
879 : * dfMaxLength.
880 : *
881 : * Interpolated points will have Z and M values (if needed) set to 0.
882 : * Distance computation is performed in 2d only
883 : *
884 : * This function is the same as the C function OGR_G_Segmentize()
885 : *
886 : * @param dfMaxLength the maximum distance between 2 points after segmentization
887 : * @return (since 3.10) true in case of success, false in case of error.
888 : */
889 :
890 0 : bool OGRGeometry::segmentize(CPL_UNUSED double dfMaxLength)
891 : {
892 : // Do nothing.
893 0 : return true;
894 : }
895 :
896 : /************************************************************************/
897 : /* OGR_G_Segmentize() */
898 : /************************************************************************/
899 :
900 : /**
901 : *
902 : * \brief Modify the geometry such it has no segment longer then the given
903 : * distance.
904 : *
905 : * Interpolated points will have Z and M values (if needed) set to 0.
906 : * Distance computation is performed in 2d only.
907 : *
908 : * This function is the same as the CPP method OGRGeometry::segmentize().
909 : *
910 : * @param hGeom handle on the geometry to segmentize
911 : * @param dfMaxLength the maximum distance between 2 points after segmentization
912 : */
913 :
914 21 : void CPL_DLL OGR_G_Segmentize(OGRGeometryH hGeom, double dfMaxLength)
915 : {
916 21 : VALIDATE_POINTER0(hGeom, "OGR_G_Segmentize");
917 :
918 21 : if (dfMaxLength <= 0)
919 : {
920 0 : CPLError(CE_Failure, CPLE_AppDefined,
921 : "dfMaxLength must be strictly positive");
922 0 : return;
923 : }
924 21 : OGRGeometry::FromHandle(hGeom)->segmentize(dfMaxLength);
925 : }
926 :
927 : /************************************************************************/
928 : /* OGR_G_GetDimension() */
929 : /************************************************************************/
930 : /**
931 : *
932 : * \brief Get the dimension of this geometry.
933 : *
934 : * This function corresponds to the SFCOM IGeometry::GetDimension() method.
935 : * It indicates the dimension of the geometry, but does not indicate the
936 : * dimension of the underlying space (as indicated by
937 : * OGR_G_GetCoordinateDimension() function).
938 : *
939 : * This function is the same as the CPP method OGRGeometry::getDimension().
940 : *
941 : * @param hGeom handle on the geometry to get the dimension from.
942 : * @return 0 for points, 1 for lines and 2 for surfaces.
943 : */
944 :
945 21 : int OGR_G_GetDimension(OGRGeometryH hGeom)
946 :
947 : {
948 21 : VALIDATE_POINTER1(hGeom, "OGR_G_GetDimension", 0);
949 :
950 21 : return OGRGeometry::FromHandle(hGeom)->getDimension();
951 : }
952 :
953 : /************************************************************************/
954 : /* getCoordinateDimension() */
955 : /************************************************************************/
956 : /**
957 : * \brief Get the dimension of the coordinates in this object.
958 : *
959 : * This method is the same as the C function OGR_G_GetCoordinateDimension().
960 : *
961 : * @deprecated use CoordinateDimension().
962 : *
963 : * @return this will return 2 or 3.
964 : */
965 :
966 1061810 : int OGRGeometry::getCoordinateDimension() const
967 :
968 : {
969 1061810 : return (flags & OGR_G_3D) ? 3 : 2;
970 : }
971 :
972 : /************************************************************************/
973 : /* CoordinateDimension() */
974 : /************************************************************************/
975 : /**
976 : * \brief Get the dimension of the coordinates in this object.
977 : *
978 : * This method is the same as the C function OGR_G_CoordinateDimension().
979 : *
980 : * @return this will return 2 for XY, 3 for XYZ and XYM, and 4 for XYZM data.
981 : *
982 : * @since GDAL 2.1
983 : */
984 :
985 21773 : int OGRGeometry::CoordinateDimension() const
986 :
987 : {
988 21773 : if ((flags & OGR_G_3D) && (flags & OGR_G_MEASURED))
989 7093 : return 4;
990 14680 : else if ((flags & OGR_G_3D) || (flags & OGR_G_MEASURED))
991 5357 : return 3;
992 : else
993 9323 : return 2;
994 : }
995 :
996 : /************************************************************************/
997 : /* OGR_G_GetCoordinateDimension() */
998 : /************************************************************************/
999 : /**
1000 : *
1001 : * \brief Get the dimension of the coordinates in this geometry.
1002 : *
1003 : * This function is the same as the CPP method
1004 : * OGRGeometry::getCoordinateDimension().
1005 : *
1006 : * @param hGeom handle on the geometry to get the dimension of the
1007 : * coordinates from.
1008 : *
1009 : * @deprecated use OGR_G_CoordinateDimension(), OGR_G_Is3D(), or
1010 : * OGR_G_IsMeasured().
1011 : *
1012 : * @return this will return 2 or 3.
1013 : */
1014 :
1015 870 : int OGR_G_GetCoordinateDimension(OGRGeometryH hGeom)
1016 :
1017 : {
1018 870 : VALIDATE_POINTER1(hGeom, "OGR_G_GetCoordinateDimension", 0);
1019 :
1020 870 : return OGRGeometry::FromHandle(hGeom)->getCoordinateDimension();
1021 : }
1022 :
1023 : /************************************************************************/
1024 : /* OGR_G_CoordinateDimension() */
1025 : /************************************************************************/
1026 : /**
1027 : *
1028 : * \brief Get the dimension of the coordinates in this geometry.
1029 : *
1030 : * This function is the same as the CPP method
1031 : * OGRGeometry::CoordinateDimension().
1032 : *
1033 : * @param hGeom handle on the geometry to get the dimension of the
1034 : * coordinates from.
1035 : *
1036 : * @return this will return 2 for XY, 3 for XYZ and XYM, and 4 for XYZM data.
1037 : *
1038 : * @since GDAL 2.1
1039 : */
1040 :
1041 4 : int OGR_G_CoordinateDimension(OGRGeometryH hGeom)
1042 :
1043 : {
1044 4 : VALIDATE_POINTER1(hGeom, "OGR_G_CoordinateDimension", 0);
1045 :
1046 4 : return OGRGeometry::FromHandle(hGeom)->CoordinateDimension();
1047 : }
1048 :
1049 : /**
1050 : *
1051 : * \brief See whether this geometry has Z coordinates.
1052 : *
1053 : * This function is the same as the CPP method
1054 : * OGRGeometry::Is3D().
1055 : *
1056 : * @param hGeom handle on the geometry to check whether it has Z coordinates.
1057 : *
1058 : * @return TRUE if the geometry has Z coordinates.
1059 : * @since GDAL 2.1
1060 : */
1061 :
1062 34632 : int OGR_G_Is3D(OGRGeometryH hGeom)
1063 :
1064 : {
1065 34632 : VALIDATE_POINTER1(hGeom, "OGR_G_Is3D", 0);
1066 :
1067 34632 : return OGRGeometry::FromHandle(hGeom)->Is3D();
1068 : }
1069 :
1070 : /**
1071 : *
1072 : * \brief See whether this geometry is measured.
1073 : *
1074 : * This function is the same as the CPP method
1075 : * OGRGeometry::IsMeasured().
1076 : *
1077 : * @param hGeom handle on the geometry to check whether it is measured.
1078 : *
1079 : * @return TRUE if the geometry has M coordinates.
1080 : * @since GDAL 2.1
1081 : */
1082 :
1083 37547 : int OGR_G_IsMeasured(OGRGeometryH hGeom)
1084 :
1085 : {
1086 37547 : VALIDATE_POINTER1(hGeom, "OGR_G_IsMeasured", 0);
1087 :
1088 37547 : return OGRGeometry::FromHandle(hGeom)->IsMeasured();
1089 : }
1090 :
1091 : /************************************************************************/
1092 : /* setCoordinateDimension() */
1093 : /************************************************************************/
1094 :
1095 : /**
1096 : * \brief Set the coordinate dimension.
1097 : *
1098 : * This method sets the explicit coordinate dimension. Setting the coordinate
1099 : * dimension of a geometry to 2 should zero out any existing Z values. Setting
1100 : * the dimension of a geometry collection, a compound curve, a polygon, etc.
1101 : * will affect the children geometries.
1102 : * This will also remove the M dimension if present before this call.
1103 : *
1104 : * @deprecated use set3D() or setMeasured().
1105 : *
1106 : * @param nNewDimension New coordinate dimension value, either 2 or 3.
1107 : * @return (since 3.10) true in case of success, false in case of memory allocation error
1108 : */
1109 :
1110 63427 : bool OGRGeometry::setCoordinateDimension(int nNewDimension)
1111 :
1112 : {
1113 63427 : if (nNewDimension == 2)
1114 62958 : flags &= ~OGR_G_3D;
1115 : else
1116 469 : flags |= OGR_G_3D;
1117 63427 : return setMeasured(FALSE);
1118 : }
1119 :
1120 : /**
1121 : * \brief Add or remove the Z coordinate dimension.
1122 : *
1123 : * This method adds or removes the explicit Z coordinate dimension.
1124 : * Removing the Z coordinate dimension of a geometry will remove any
1125 : * existing Z values. Adding the Z dimension to a geometry
1126 : * collection, a compound curve, a polygon, etc. will affect the
1127 : * children geometries.
1128 : *
1129 : * @param bIs3D Should the geometry have a Z dimension, either TRUE or FALSE.
1130 : * @return (since 3.10) true in case of success, false in case of memory allocation error
1131 : * @since GDAL 2.1
1132 : */
1133 :
1134 1581590 : bool OGRGeometry::set3D(OGRBoolean bIs3D)
1135 :
1136 : {
1137 1581590 : if (bIs3D)
1138 1577000 : flags |= OGR_G_3D;
1139 : else
1140 4592 : flags &= ~OGR_G_3D;
1141 1581590 : return true;
1142 : }
1143 :
1144 : /**
1145 : * \brief Add or remove the M coordinate dimension.
1146 : *
1147 : * This method adds or removes the explicit M coordinate dimension.
1148 : * Removing the M coordinate dimension of a geometry will remove any
1149 : * existing M values. Adding the M dimension to a geometry
1150 : * collection, a compound curve, a polygon, etc. will affect the
1151 : * children geometries.
1152 : *
1153 : * @param bIsMeasured Should the geometry have a M dimension, either
1154 : * TRUE or FALSE.
1155 : * @return (since 3.10) true in case of success, false in case of memory allocation error
1156 : * @since GDAL 2.1
1157 : */
1158 :
1159 407684 : bool OGRGeometry::setMeasured(OGRBoolean bIsMeasured)
1160 :
1161 : {
1162 407684 : if (bIsMeasured)
1163 137604 : flags |= OGR_G_MEASURED;
1164 : else
1165 270080 : flags &= ~OGR_G_MEASURED;
1166 407684 : return true;
1167 : }
1168 :
1169 : /************************************************************************/
1170 : /* OGR_G_SetCoordinateDimension() */
1171 : /************************************************************************/
1172 :
1173 : /**
1174 : * \brief Set the coordinate dimension.
1175 : *
1176 : * This method sets the explicit coordinate dimension. Setting the coordinate
1177 : * dimension of a geometry to 2 should zero out any existing Z values. Setting
1178 : * the dimension of a geometry collection, a compound curve, a polygon, etc.
1179 : * will affect the children geometries.
1180 : * This will also remove the M dimension if present before this call.
1181 : *
1182 : * @deprecated use OGR_G_Set3D() or OGR_G_SetMeasured().
1183 : *
1184 : * @param hGeom handle on the geometry to set the dimension of the
1185 : * coordinates.
1186 : * @param nNewDimension New coordinate dimension value, either 2 or 3.
1187 : */
1188 :
1189 131 : void OGR_G_SetCoordinateDimension(OGRGeometryH hGeom, int nNewDimension)
1190 :
1191 : {
1192 131 : VALIDATE_POINTER0(hGeom, "OGR_G_SetCoordinateDimension");
1193 :
1194 131 : OGRGeometry::FromHandle(hGeom)->setCoordinateDimension(nNewDimension);
1195 : }
1196 :
1197 : /************************************************************************/
1198 : /* OGR_G_Set3D() */
1199 : /************************************************************************/
1200 :
1201 : /**
1202 : * \brief Add or remove the Z coordinate dimension.
1203 : *
1204 : * This method adds or removes the explicit Z coordinate dimension.
1205 : * Removing the Z coordinate dimension of a geometry will remove any
1206 : * existing Z values. Adding the Z dimension to a geometry
1207 : * collection, a compound curve, a polygon, etc. will affect the
1208 : * children geometries.
1209 : *
1210 : * @param hGeom handle on the geometry to set or unset the Z dimension.
1211 : * @param bIs3D Should the geometry have a Z dimension, either TRUE or FALSE.
1212 : * @since GDAL 2.1
1213 : */
1214 :
1215 154 : void OGR_G_Set3D(OGRGeometryH hGeom, int bIs3D)
1216 :
1217 : {
1218 154 : VALIDATE_POINTER0(hGeom, "OGR_G_Set3D");
1219 :
1220 154 : OGRGeometry::FromHandle(hGeom)->set3D(bIs3D);
1221 : }
1222 :
1223 : /************************************************************************/
1224 : /* OGR_G_SetMeasured() */
1225 : /************************************************************************/
1226 :
1227 : /**
1228 : * \brief Add or remove the M coordinate dimension.
1229 : *
1230 : * This method adds or removes the explicit M coordinate dimension.
1231 : * Removing the M coordinate dimension of a geometry will remove any
1232 : * existing M values. Adding the M dimension to a geometry
1233 : * collection, a compound curve, a polygon, etc. will affect the
1234 : * children geometries.
1235 : *
1236 : * @param hGeom handle on the geometry to set or unset the M dimension.
1237 : * @param bIsMeasured Should the geometry have a M dimension, either
1238 : * TRUE or FALSE.
1239 : * @since GDAL 2.1
1240 : */
1241 :
1242 154 : void OGR_G_SetMeasured(OGRGeometryH hGeom, int bIsMeasured)
1243 :
1244 : {
1245 154 : VALIDATE_POINTER0(hGeom, "OGR_G_SetMeasured");
1246 :
1247 154 : OGRGeometry::FromHandle(hGeom)->setMeasured(bIsMeasured);
1248 : }
1249 :
1250 : /**
1251 : * \fn int OGRGeometry::Equals( OGRGeometry *poOtherGeom ) const;
1252 : *
1253 : * \brief Returns TRUE if two geometries are equivalent.
1254 : *
1255 : * This operation implements the SQL/MM ST_OrderingEquals() operation.
1256 : *
1257 : * The comparison is done in a structural way, that is to say that the geometry
1258 : * types must be identical, as well as the number and ordering of sub-geometries
1259 : * and vertices.
1260 : * Or equivalently, two geometries are considered equal by this method if their
1261 : * WKT/WKB representation is equal.
1262 : * Note: this must be distinguished for equality in a spatial way (which is
1263 : * the purpose of the ST_Equals() operation).
1264 : *
1265 : * This method is the same as the C function OGR_G_Equals().
1266 : *
1267 : * @return TRUE if equivalent or FALSE otherwise.
1268 : */
1269 :
1270 : // Backward compatibility method.
1271 :
1272 : //! @cond Doxygen_Suppress
1273 0 : int OGRGeometry::Equal(OGRGeometry *poOtherGeom) const
1274 : {
1275 0 : return Equals(poOtherGeom);
1276 : }
1277 :
1278 : //! @endcond
1279 :
1280 : /************************************************************************/
1281 : /* OGR_G_Equals() */
1282 : /************************************************************************/
1283 :
1284 : /**
1285 : * \brief Returns TRUE if two geometries are equivalent.
1286 : *
1287 : * This operation implements the SQL/MM ST_OrderingEquals() operation.
1288 : *
1289 : * The comparison is done in a structural way, that is to say that the geometry
1290 : * types must be identical, as well as the number and ordering of sub-geometries
1291 : * and vertices.
1292 : * Or equivalently, two geometries are considered equal by this method if their
1293 : * WKT/WKB representation is equal.
1294 : * Note: this must be distinguished for equality in a spatial way (which is
1295 : * the purpose of the ST_Equals() operation).
1296 : *
1297 : * This function is the same as the CPP method OGRGeometry::Equals() method.
1298 : *
1299 : * @param hGeom handle on the first geometry.
1300 : * @param hOther handle on the other geometry to test against.
1301 : * @return TRUE if equivalent or FALSE otherwise.
1302 : */
1303 :
1304 28245 : int OGR_G_Equals(OGRGeometryH hGeom, OGRGeometryH hOther)
1305 :
1306 : {
1307 28245 : VALIDATE_POINTER1(hGeom, "OGR_G_Equals", FALSE);
1308 :
1309 28245 : if (hOther == nullptr)
1310 : {
1311 0 : CPLError(CE_Failure, CPLE_ObjectNull,
1312 : "hOther was NULL in OGR_G_Equals");
1313 0 : return 0;
1314 : }
1315 :
1316 56490 : return OGRGeometry::FromHandle(hGeom)->Equals(
1317 28245 : OGRGeometry::FromHandle(hOther));
1318 : }
1319 :
1320 : //! @cond Doxygen_Suppress
1321 0 : int OGR_G_Equal(OGRGeometryH hGeom, OGRGeometryH hOther)
1322 :
1323 : {
1324 0 : if (hGeom == nullptr)
1325 : {
1326 0 : CPLError(CE_Failure, CPLE_ObjectNull, "hGeom was NULL in OGR_G_Equal");
1327 0 : return 0;
1328 : }
1329 :
1330 0 : if (hOther == nullptr)
1331 : {
1332 0 : CPLError(CE_Failure, CPLE_ObjectNull, "hOther was NULL in OGR_G_Equal");
1333 0 : return 0;
1334 : }
1335 :
1336 0 : return OGRGeometry::FromHandle(hGeom)->Equals(
1337 0 : OGRGeometry::FromHandle(hOther));
1338 : }
1339 :
1340 : //! @endcond
1341 :
1342 : /**
1343 : * \fn int OGRGeometry::WkbSize() const;
1344 : *
1345 : * \brief Returns size of related binary representation.
1346 : *
1347 : * This method returns the exact number of bytes required to hold the
1348 : * well known binary representation of this geometry object. Its computation
1349 : * may be slightly expensive for complex geometries.
1350 : *
1351 : * This method relates to the SFCOM IWks::WkbSize() method.
1352 : *
1353 : * This method is the same as the C function OGR_G_WkbSize().
1354 : *
1355 : * @return size of binary representation in bytes.
1356 : */
1357 :
1358 : /************************************************************************/
1359 : /* OGR_G_WkbSize() */
1360 : /************************************************************************/
1361 : /**
1362 : * \brief Returns size of related binary representation.
1363 : *
1364 : * This function returns the exact number of bytes required to hold the
1365 : * well known binary representation of this geometry object. Its computation
1366 : * may be slightly expensive for complex geometries.
1367 : *
1368 : * This function relates to the SFCOM IWks::WkbSize() method.
1369 : *
1370 : * This function is the same as the CPP method OGRGeometry::WkbSize().
1371 : *
1372 : * Use OGR_G_WkbSizeEx() if called on huge geometries (> 2 GB serialized)
1373 : *
1374 : * @param hGeom handle on the geometry to get the binary size from.
1375 : * @return size of binary representation in bytes.
1376 : */
1377 :
1378 1 : int OGR_G_WkbSize(OGRGeometryH hGeom)
1379 :
1380 : {
1381 1 : VALIDATE_POINTER1(hGeom, "OGR_G_WkbSize", 0);
1382 :
1383 1 : const size_t nSize = OGRGeometry::FromHandle(hGeom)->WkbSize();
1384 1 : if (nSize > static_cast<size_t>(std::numeric_limits<int>::max()))
1385 : {
1386 0 : CPLError(CE_Failure, CPLE_AppDefined,
1387 : "OGR_G_WkbSize() would return a value beyond int range. "
1388 : "Use OGR_G_WkbSizeEx() instead");
1389 0 : return 0;
1390 : }
1391 1 : return static_cast<int>(nSize);
1392 : }
1393 :
1394 : /************************************************************************/
1395 : /* OGR_G_WkbSizeEx() */
1396 : /************************************************************************/
1397 : /**
1398 : * \brief Returns size of related binary representation.
1399 : *
1400 : * This function returns the exact number of bytes required to hold the
1401 : * well known binary representation of this geometry object. Its computation
1402 : * may be slightly expensive for complex geometries.
1403 : *
1404 : * This function relates to the SFCOM IWks::WkbSize() method.
1405 : *
1406 : * This function is the same as the CPP method OGRGeometry::WkbSize().
1407 : *
1408 : * @param hGeom handle on the geometry to get the binary size from.
1409 : * @return size of binary representation in bytes.
1410 : * @since GDAL 3.3
1411 : */
1412 :
1413 10675 : size_t OGR_G_WkbSizeEx(OGRGeometryH hGeom)
1414 :
1415 : {
1416 10675 : VALIDATE_POINTER1(hGeom, "OGR_G_WkbSizeEx", 0);
1417 :
1418 10675 : return OGRGeometry::FromHandle(hGeom)->WkbSize();
1419 : }
1420 :
1421 : /**
1422 : * \fn void OGRGeometry::getEnvelope(OGREnvelope *psEnvelope) const;
1423 : *
1424 : * \brief Computes and returns the bounding envelope for this geometry
1425 : * in the passed psEnvelope structure.
1426 : *
1427 : * This method is the same as the C function OGR_G_GetEnvelope().
1428 : *
1429 : * @param psEnvelope the structure in which to place the results.
1430 : */
1431 :
1432 : /************************************************************************/
1433 : /* OGR_G_GetEnvelope() */
1434 : /************************************************************************/
1435 : /**
1436 : * \brief Computes and returns the bounding envelope for this geometry
1437 : * in the passed psEnvelope structure.
1438 : *
1439 : * This function is the same as the CPP method OGRGeometry::getEnvelope().
1440 : *
1441 : * @param hGeom handle of the geometry to get envelope from.
1442 : * @param psEnvelope the structure in which to place the results.
1443 : */
1444 :
1445 13352 : void OGR_G_GetEnvelope(OGRGeometryH hGeom, OGREnvelope *psEnvelope)
1446 :
1447 : {
1448 13352 : VALIDATE_POINTER0(hGeom, "OGR_G_GetEnvelope");
1449 :
1450 13352 : OGRGeometry::FromHandle(hGeom)->getEnvelope(psEnvelope);
1451 : }
1452 :
1453 : /**
1454 : * \fn void OGRGeometry::getEnvelope(OGREnvelope3D *psEnvelope) const;
1455 : *
1456 : * \brief Computes and returns the bounding envelope (3D) for this
1457 : * geometry in the passed psEnvelope structure.
1458 : *
1459 : * This method is the same as the C function OGR_G_GetEnvelope3D().
1460 : *
1461 : * @param psEnvelope the structure in which to place the results.
1462 : *
1463 : * @since OGR 1.9.0
1464 : */
1465 :
1466 : /************************************************************************/
1467 : /* OGR_G_GetEnvelope3D() */
1468 : /************************************************************************/
1469 : /**
1470 : * \brief Computes and returns the bounding envelope (3D) for this
1471 : * geometry in the passed psEnvelope structure.
1472 : *
1473 : * This function is the same as the CPP method OGRGeometry::getEnvelope().
1474 : *
1475 : * @param hGeom handle of the geometry to get envelope from.
1476 : * @param psEnvelope the structure in which to place the results.
1477 : *
1478 : * @since OGR 1.9.0
1479 : */
1480 :
1481 10 : void OGR_G_GetEnvelope3D(OGRGeometryH hGeom, OGREnvelope3D *psEnvelope)
1482 :
1483 : {
1484 10 : VALIDATE_POINTER0(hGeom, "OGR_G_GetEnvelope3D");
1485 :
1486 10 : OGRGeometry::FromHandle(hGeom)->getEnvelope(psEnvelope);
1487 : }
1488 :
1489 : /************************************************************************/
1490 : /* importFromWkb() */
1491 : /************************************************************************/
1492 :
1493 : /**
1494 : * \brief Assign geometry from well known binary data.
1495 : *
1496 : * The object must have already been instantiated as the correct derived
1497 : * type of geometry object to match the binaries type. This method is used
1498 : * by the OGRGeometryFactory class, but not normally called by application
1499 : * code.
1500 : *
1501 : * This method relates to the SFCOM IWks::ImportFromWKB() method.
1502 : *
1503 : * This method is the same as the C function OGR_G_ImportFromWkb().
1504 : *
1505 : * @param pabyData the binary input data.
1506 : * @param nSize the size of pabyData in bytes, or -1 if not known.
1507 : * @param eWkbVariant if wkbVariantPostGIS1, special interpretation is
1508 : * done for curve geometries code
1509 : *
1510 : * @return OGRERR_NONE if all goes well, otherwise any of
1511 : * OGRERR_NOT_ENOUGH_DATA, OGRERR_UNSUPPORTED_GEOMETRY_TYPE, or
1512 : * OGRERR_CORRUPT_DATA may be returned.
1513 : */
1514 :
1515 492 : OGRErr OGRGeometry::importFromWkb(const GByte *pabyData, size_t nSize,
1516 : OGRwkbVariant eWkbVariant)
1517 : {
1518 492 : size_t nBytesConsumedOutIgnored = 0;
1519 492 : return importFromWkb(pabyData, nSize, eWkbVariant,
1520 984 : nBytesConsumedOutIgnored);
1521 : }
1522 :
1523 : /**
1524 : * \fn OGRErr OGRGeometry::importFromWkb( const unsigned char * pabyData,
1525 : * size_t nSize, OGRwkbVariant eWkbVariant, size_t& nBytesConsumedOut );
1526 : *
1527 : * \brief Assign geometry from well known binary data.
1528 : *
1529 : * The object must have already been instantiated as the correct derived
1530 : * type of geometry object to match the binaries type. This method is used
1531 : * by the OGRGeometryFactory class, but not normally called by application
1532 : * code.
1533 : *
1534 : * This method relates to the SFCOM IWks::ImportFromWKB() method.
1535 : *
1536 : * This method is the same as the C function OGR_G_ImportFromWkb().
1537 : *
1538 : * @param pabyData the binary input data.
1539 : * @param nSize the size of pabyData in bytes, or -1 if not known.
1540 : * @param eWkbVariant if wkbVariantPostGIS1, special interpretation is
1541 : * done for curve geometries code
1542 : * @param nBytesConsumedOut output parameter. Number of bytes consumed.
1543 : *
1544 : * @return OGRERR_NONE if all goes well, otherwise any of
1545 : * OGRERR_NOT_ENOUGH_DATA, OGRERR_UNSUPPORTED_GEOMETRY_TYPE, or
1546 : * OGRERR_CORRUPT_DATA may be returned.
1547 : *
1548 : * @since GDAL 2.3
1549 : */
1550 :
1551 : /************************************************************************/
1552 : /* OGR_G_ImportFromWkb() */
1553 : /************************************************************************/
1554 : /**
1555 : * \brief Assign geometry from well known binary data.
1556 : *
1557 : * The object must have already been instantiated as the correct derived
1558 : * type of geometry object to match the binaries type.
1559 : *
1560 : * This function relates to the SFCOM IWks::ImportFromWKB() method.
1561 : *
1562 : * This function is the same as the CPP method OGRGeometry::importFromWkb().
1563 : *
1564 : * @param hGeom handle on the geometry to assign the well know binary data to.
1565 : * @param pabyData the binary input data.
1566 : * @param nSize the size of pabyData in bytes, or -1 if not known.
1567 : *
1568 : * @return OGRERR_NONE if all goes well, otherwise any of
1569 : * OGRERR_NOT_ENOUGH_DATA, OGRERR_UNSUPPORTED_GEOMETRY_TYPE, or
1570 : * OGRERR_CORRUPT_DATA may be returned.
1571 : */
1572 :
1573 0 : OGRErr OGR_G_ImportFromWkb(OGRGeometryH hGeom, const void *pabyData, int nSize)
1574 :
1575 : {
1576 0 : VALIDATE_POINTER1(hGeom, "OGR_G_ImportFromWkb", OGRERR_FAILURE);
1577 :
1578 0 : return OGRGeometry::FromHandle(hGeom)->importFromWkb(
1579 0 : static_cast<const GByte *>(pabyData), nSize);
1580 : }
1581 :
1582 : /************************************************************************/
1583 : /* OGRGeometry::exportToWkb() */
1584 : /************************************************************************/
1585 :
1586 : /* clang-format off */
1587 : /**
1588 : * \brief Convert a geometry into well known binary format.
1589 : *
1590 : * This method relates to the SFCOM IWks::ExportToWKB() method.
1591 : *
1592 : * This method is the same as the C function OGR_G_ExportToWkb() or
1593 : * OGR_G_ExportToIsoWkb(), depending on the value of eWkbVariant.
1594 : *
1595 : * @param eByteOrder One of wkbXDR or wkbNDR indicating MSB or LSB byte order
1596 : * respectively.
1597 : * @param pabyData a buffer into which the binary representation is
1598 : * written. This buffer must be at least
1599 : * OGRGeometry::WkbSize() byte in size.
1600 : * @param eWkbVariant What standard to use when exporting geometries
1601 : * with three dimensions (or more). The default
1602 : * wkbVariantOldOgc is the historical OGR
1603 : * variant. wkbVariantIso is the variant defined
1604 : * in ISO SQL/MM and adopted by OGC for SFSQL
1605 : * 1.2.
1606 : *
1607 : * @return Currently OGRERR_NONE is always returned.
1608 : */
1609 : /* clang-format on */
1610 251645 : OGRErr OGRGeometry::exportToWkb(OGRwkbByteOrder eByteOrder,
1611 : unsigned char *pabyData,
1612 : OGRwkbVariant eWkbVariant) const
1613 : {
1614 251645 : OGRwkbExportOptions sOptions;
1615 251645 : sOptions.eByteOrder = eByteOrder;
1616 251645 : sOptions.eWkbVariant = eWkbVariant;
1617 503286 : return exportToWkb(pabyData, &sOptions);
1618 : }
1619 :
1620 : /************************************************************************/
1621 : /* OGR_G_ExportToWkb() */
1622 : /************************************************************************/
1623 : /**
1624 : * \brief Convert a geometry well known binary format
1625 : *
1626 : * This function relates to the SFCOM IWks::ExportToWKB() method.
1627 : *
1628 : * For backward compatibility purposes, it exports the Old-style 99-402
1629 : * extended dimension (Z) WKB types for types Point, LineString, Polygon,
1630 : * MultiPoint, MultiLineString, MultiPolygon and GeometryCollection.
1631 : * For other geometry types, it is equivalent to OGR_G_ExportToIsoWkb().
1632 : *
1633 : * This function is the same as the CPP method
1634 : * OGRGeometry::exportToWkb(OGRwkbByteOrder, unsigned char *,
1635 : * OGRwkbVariant) with eWkbVariant = wkbVariantOldOgc.
1636 : *
1637 : * @param hGeom handle on the geometry to convert to a well know binary
1638 : * data from.
1639 : * @param eOrder One of wkbXDR or wkbNDR indicating MSB or LSB byte order
1640 : * respectively.
1641 : * @param pabyDstBuffer a buffer into which the binary representation is
1642 : * written. This buffer must be at least
1643 : * OGR_G_WkbSize() byte in size.
1644 : *
1645 : * @return Currently OGRERR_NONE is always returned.
1646 : */
1647 :
1648 105 : OGRErr OGR_G_ExportToWkb(OGRGeometryH hGeom, OGRwkbByteOrder eOrder,
1649 : unsigned char *pabyDstBuffer)
1650 :
1651 : {
1652 105 : VALIDATE_POINTER1(hGeom, "OGR_G_ExportToWkb", OGRERR_FAILURE);
1653 :
1654 105 : return OGRGeometry::FromHandle(hGeom)->exportToWkb(eOrder, pabyDstBuffer);
1655 : }
1656 :
1657 : /************************************************************************/
1658 : /* OGR_G_ExportToIsoWkb() */
1659 : /************************************************************************/
1660 : /**
1661 : * \brief Convert a geometry into SFSQL 1.2 / ISO SQL/MM Part 3 well known
1662 : * binary format
1663 : *
1664 : * This function relates to the SFCOM IWks::ExportToWKB() method.
1665 : * It exports the SFSQL 1.2 and ISO SQL/MM Part 3 extended dimension (Z&M) WKB
1666 : * types.
1667 : *
1668 : * This function is the same as the CPP method
1669 : * OGRGeometry::exportToWkb(OGRwkbByteOrder, unsigned char *, OGRwkbVariant)
1670 : * with eWkbVariant = wkbVariantIso.
1671 : *
1672 : * @param hGeom handle on the geometry to convert to a well know binary
1673 : * data from.
1674 : * @param eOrder One of wkbXDR or wkbNDR indicating MSB or LSB byte order
1675 : * respectively.
1676 : * @param pabyDstBuffer a buffer into which the binary representation is
1677 : * written. This buffer must be at least
1678 : * OGR_G_WkbSize() byte in size.
1679 : *
1680 : * @return Currently OGRERR_NONE is always returned.
1681 : *
1682 : * @since GDAL 2.0
1683 : */
1684 :
1685 10571 : OGRErr OGR_G_ExportToIsoWkb(OGRGeometryH hGeom, OGRwkbByteOrder eOrder,
1686 : unsigned char *pabyDstBuffer)
1687 :
1688 : {
1689 10571 : VALIDATE_POINTER1(hGeom, "OGR_G_ExportToIsoWkb", OGRERR_FAILURE);
1690 :
1691 10571 : return OGRGeometry::FromHandle(hGeom)->exportToWkb(eOrder, pabyDstBuffer,
1692 10571 : wkbVariantIso);
1693 : }
1694 :
1695 : /************************************************************************/
1696 : /* OGR_G_ExportToWkbEx() */
1697 : /************************************************************************/
1698 :
1699 : /* clang-format off */
1700 : /**
1701 : * \fn OGRErr OGRGeometry::exportToWkb(unsigned char *pabyDstBuffer, const OGRwkbExportOptions *psOptions=nullptr) const
1702 : *
1703 : * \brief Convert a geometry into well known binary format
1704 : *
1705 : * This function relates to the SFCOM IWks::ExportToWKB() method.
1706 : *
1707 : * This function is the same as the C function OGR_G_ExportToWkbEx().
1708 : *
1709 : * @param pabyDstBuffer a buffer into which the binary representation is
1710 : * written. This buffer must be at least
1711 : * OGR_G_WkbSize() byte in size.
1712 : * @param psOptions WKB export options.
1713 :
1714 : * @return Currently OGRERR_NONE is always returned.
1715 : *
1716 : * @since GDAL 3.9
1717 : */
1718 : /* clang-format on */
1719 :
1720 : /**
1721 : * \brief Convert a geometry into well known binary format
1722 : *
1723 : * This function relates to the SFCOM IWks::ExportToWKB() method.
1724 : *
1725 : * This function is the same as the CPP method
1726 : * OGRGeometry::exportToWkb(unsigned char *, const OGRwkbExportOptions*)
1727 : *
1728 : * @param hGeom handle on the geometry to convert to a well know binary
1729 : * data from.
1730 : * @param pabyDstBuffer a buffer into which the binary representation is
1731 : * written. This buffer must be at least
1732 : * OGR_G_WkbSize() byte in size.
1733 : * @param psOptions WKB export options.
1734 :
1735 : * @return Currently OGRERR_NONE is always returned.
1736 : *
1737 : * @since GDAL 3.9
1738 : */
1739 :
1740 2 : OGRErr OGR_G_ExportToWkbEx(OGRGeometryH hGeom, unsigned char *pabyDstBuffer,
1741 : const OGRwkbExportOptions *psOptions)
1742 : {
1743 2 : VALIDATE_POINTER1(hGeom, "OGR_G_ExportToWkbEx", OGRERR_FAILURE);
1744 :
1745 4 : return OGRGeometry::FromHandle(hGeom)->exportToWkb(pabyDstBuffer,
1746 2 : psOptions);
1747 : }
1748 :
1749 : /**
1750 : * \fn OGRErr OGRGeometry::importFromWkt( const char ** ppszInput );
1751 : *
1752 : * \brief Assign geometry from well known text data.
1753 : *
1754 : * The object must have already been instantiated as the correct derived
1755 : * type of geometry object to match the text type. This method is used
1756 : * by the OGRGeometryFactory class, but not normally called by application
1757 : * code.
1758 : *
1759 : * This method relates to the SFCOM IWks::ImportFromWKT() method.
1760 : *
1761 : * This method is the same as the C function OGR_G_ImportFromWkt().
1762 : *
1763 : * @param ppszInput pointer to a pointer to the source text. The pointer is
1764 : * updated to pointer after the consumed text.
1765 : *
1766 : * @return OGRERR_NONE if all goes well, otherwise any of
1767 : * OGRERR_NOT_ENOUGH_DATA, OGRERR_UNSUPPORTED_GEOMETRY_TYPE, or
1768 : * OGRERR_CORRUPT_DATA may be returned.
1769 : */
1770 :
1771 : /************************************************************************/
1772 : /* OGR_G_ImportFromWkt() */
1773 : /************************************************************************/
1774 : /**
1775 : * \brief Assign geometry from well known text data.
1776 : *
1777 : * The object must have already been instantiated as the correct derived
1778 : * type of geometry object to match the text type.
1779 : *
1780 : * This function relates to the SFCOM IWks::ImportFromWKT() method.
1781 : *
1782 : * This function is the same as the CPP method OGRGeometry::importFromWkt().
1783 : *
1784 : * @param hGeom handle on the geometry to assign well know text data to.
1785 : * @param ppszSrcText pointer to a pointer to the source text. The pointer is
1786 : * updated to pointer after the consumed text.
1787 : *
1788 : * @return OGRERR_NONE if all goes well, otherwise any of
1789 : * OGRERR_NOT_ENOUGH_DATA, OGRERR_UNSUPPORTED_GEOMETRY_TYPE, or
1790 : * OGRERR_CORRUPT_DATA may be returned.
1791 : */
1792 :
1793 0 : OGRErr OGR_G_ImportFromWkt(OGRGeometryH hGeom, char **ppszSrcText)
1794 :
1795 : {
1796 0 : VALIDATE_POINTER1(hGeom, "OGR_G_ImportFromWkt", OGRERR_FAILURE);
1797 :
1798 0 : return OGRGeometry::FromHandle(hGeom)->importFromWkt(
1799 0 : const_cast<const char **>(ppszSrcText));
1800 : }
1801 :
1802 : /************************************************************************/
1803 : /* importPreambleFromWkt() */
1804 : /************************************************************************/
1805 :
1806 : // Returns -1 if processing must continue.
1807 : //! @cond Doxygen_Suppress
1808 123231 : OGRErr OGRGeometry::importPreambleFromWkt(const char **ppszInput, int *pbHasZ,
1809 : int *pbHasM, bool *pbIsEmpty)
1810 : {
1811 123231 : const char *pszInput = *ppszInput;
1812 :
1813 : /* -------------------------------------------------------------------- */
1814 : /* Clear existing Geoms. */
1815 : /* -------------------------------------------------------------------- */
1816 123231 : empty();
1817 123231 : *pbIsEmpty = false;
1818 :
1819 : /* -------------------------------------------------------------------- */
1820 : /* Read and verify the type keyword, and ensure it matches the */
1821 : /* actual type of this container. */
1822 : /* -------------------------------------------------------------------- */
1823 123231 : bool bHasM = false;
1824 123231 : bool bHasZ = false;
1825 123231 : bool bAlreadyGotDimension = false;
1826 :
1827 123231 : char szToken[OGR_WKT_TOKEN_MAX] = {};
1828 123231 : pszInput = OGRWktReadToken(pszInput, szToken);
1829 123231 : if (szToken[0] != '\0')
1830 : {
1831 : // Postgis EWKT: POINTM instead of POINT M.
1832 : // Current QGIS versions (at least <= 3.38) also export POINTZ.
1833 123231 : const size_t nTokenLen = strlen(szToken);
1834 123231 : if (szToken[nTokenLen - 1] == 'M' || szToken[nTokenLen - 1] == 'm')
1835 : {
1836 11 : szToken[nTokenLen - 1] = '\0';
1837 11 : bHasM = true;
1838 11 : bAlreadyGotDimension = true;
1839 :
1840 11 : if (nTokenLen > 2 && (szToken[nTokenLen - 2] == 'Z' ||
1841 9 : szToken[nTokenLen - 2] == 'z'))
1842 : {
1843 4 : bHasZ = true;
1844 4 : szToken[nTokenLen - 2] = '\0';
1845 : }
1846 : }
1847 123220 : else if (szToken[nTokenLen - 1] == 'Z' || szToken[nTokenLen - 1] == 'z')
1848 : {
1849 5 : szToken[nTokenLen - 1] = '\0';
1850 5 : bHasZ = true;
1851 5 : bAlreadyGotDimension = true;
1852 : }
1853 : }
1854 :
1855 123231 : if (!EQUAL(szToken, getGeometryName()))
1856 0 : return OGRERR_CORRUPT_DATA;
1857 :
1858 : /* -------------------------------------------------------------------- */
1859 : /* Check for Z, M or ZM */
1860 : /* -------------------------------------------------------------------- */
1861 123231 : if (!bAlreadyGotDimension)
1862 : {
1863 123215 : const char *pszNewInput = OGRWktReadToken(pszInput, szToken);
1864 123215 : if (EQUAL(szToken, "Z"))
1865 : {
1866 1041 : pszInput = pszNewInput;
1867 1041 : bHasZ = true;
1868 : }
1869 122174 : else if (EQUAL(szToken, "M"))
1870 : {
1871 320 : pszInput = pszNewInput;
1872 320 : bHasM = true;
1873 : }
1874 121854 : else if (EQUAL(szToken, "ZM"))
1875 : {
1876 473 : pszInput = pszNewInput;
1877 473 : bHasZ = true;
1878 473 : bHasM = true;
1879 : }
1880 : }
1881 123231 : *pbHasZ = bHasZ;
1882 123231 : *pbHasM = bHasM;
1883 :
1884 : /* -------------------------------------------------------------------- */
1885 : /* Check for EMPTY ... */
1886 : /* -------------------------------------------------------------------- */
1887 123231 : const char *pszNewInput = OGRWktReadToken(pszInput, szToken);
1888 123231 : if (EQUAL(szToken, "EMPTY"))
1889 : {
1890 1559 : *ppszInput = pszNewInput;
1891 1559 : *pbIsEmpty = true;
1892 1559 : if (bHasZ)
1893 129 : set3D(TRUE);
1894 1559 : if (bHasM)
1895 83 : setMeasured(TRUE);
1896 1559 : return OGRERR_NONE;
1897 : }
1898 :
1899 121672 : if (!EQUAL(szToken, "("))
1900 35 : return OGRERR_CORRUPT_DATA;
1901 :
1902 121637 : if (!bHasZ && !bHasM)
1903 : {
1904 : // Test for old-style XXXXXXXXX(EMPTY).
1905 119959 : pszNewInput = OGRWktReadToken(pszNewInput, szToken);
1906 119959 : if (EQUAL(szToken, "EMPTY"))
1907 : {
1908 69 : pszNewInput = OGRWktReadToken(pszNewInput, szToken);
1909 :
1910 69 : if (EQUAL(szToken, ","))
1911 : {
1912 : // This is OK according to SFSQL SPEC.
1913 : }
1914 44 : else if (!EQUAL(szToken, ")"))
1915 : {
1916 9 : return OGRERR_CORRUPT_DATA;
1917 : }
1918 : else
1919 : {
1920 35 : *ppszInput = pszNewInput;
1921 35 : empty();
1922 35 : *pbIsEmpty = true;
1923 35 : return OGRERR_NONE;
1924 : }
1925 : }
1926 : }
1927 :
1928 121593 : *ppszInput = pszInput;
1929 :
1930 121593 : return OGRERR_NONE;
1931 : }
1932 :
1933 : //! @endcond
1934 :
1935 : /************************************************************************/
1936 : /* wktTypeString() */
1937 : /************************************************************************/
1938 :
1939 : //! @cond Doxygen_Suppress
1940 : /** Get a type string for WKT, padded with a space at the end.
1941 : *
1942 : * @param variant OGR type variant
1943 : * @return "Z " for 3D, "M " for measured, "ZM " for both, or the empty string.
1944 : */
1945 13844 : std::string OGRGeometry::wktTypeString(OGRwkbVariant variant) const
1946 : {
1947 13844 : std::string s(" ");
1948 :
1949 13844 : if (variant == wkbVariantIso)
1950 : {
1951 8922 : if (flags & OGR_G_3D)
1952 1845 : s += "Z";
1953 8922 : if (flags & OGR_G_MEASURED)
1954 1087 : s += "M";
1955 : }
1956 13844 : if (s.size() > 1)
1957 2352 : s += " ";
1958 13844 : return s;
1959 : }
1960 :
1961 : //! @endcond
1962 :
1963 : /**
1964 : * \fn OGRErr OGRGeometry::exportToWkt( char ** ppszDstText,
1965 : * OGRwkbVariant variant = wkbVariantOldOgc ) const;
1966 : *
1967 : * \brief Convert a geometry into well known text format.
1968 : *
1969 : * This method relates to the SFCOM IWks::ExportToWKT() method.
1970 : *
1971 : * This method is the same as the C function OGR_G_ExportToWkt().
1972 : *
1973 : * @param ppszDstText a text buffer is allocated by the program, and assigned
1974 : * to the passed pointer. After use, *ppszDstText should be
1975 : * freed with CPLFree().
1976 : * @param variant the specification that must be conformed too :
1977 : * - wkbVariantOgc for old-style 99-402 extended
1978 : * dimension (Z) WKB types
1979 : * - wkbVariantIso for SFSQL 1.2 and ISO SQL/MM Part 3
1980 : *
1981 : * @return Currently OGRERR_NONE is always returned.
1982 : */
1983 8783 : OGRErr OGRGeometry::exportToWkt(char **ppszDstText, OGRwkbVariant variant) const
1984 : {
1985 8783 : OGRWktOptions opts;
1986 8783 : opts.variant = variant;
1987 8783 : OGRErr err(OGRERR_NONE);
1988 :
1989 8783 : std::string wkt = exportToWkt(opts, &err);
1990 8783 : *ppszDstText = CPLStrdup(wkt.data());
1991 17566 : return err;
1992 : }
1993 :
1994 : /************************************************************************/
1995 : /* OGR_G_ExportToWkt() */
1996 : /************************************************************************/
1997 :
1998 : /**
1999 : * \brief Convert a geometry into well known text format.
2000 : *
2001 : * This function relates to the SFCOM IWks::ExportToWKT() method.
2002 : *
2003 : * For backward compatibility purposes, it exports the Old-style 99-402
2004 : * extended dimension (Z) WKB types for types Point, LineString, Polygon,
2005 : * MultiPoint, MultiLineString, MultiPolygon and GeometryCollection.
2006 : * For other geometry types, it is equivalent to OGR_G_ExportToIsoWkt().
2007 : *
2008 : * This function is the same as the CPP method OGRGeometry::exportToWkt().
2009 : *
2010 : * @param hGeom handle on the geometry to convert to a text format from.
2011 : * @param ppszSrcText a text buffer is allocated by the program, and assigned
2012 : * to the passed pointer. After use, *ppszDstText should be
2013 : * freed with CPLFree().
2014 : *
2015 : * @return Currently OGRERR_NONE is always returned.
2016 : */
2017 :
2018 2397 : OGRErr OGR_G_ExportToWkt(OGRGeometryH hGeom, char **ppszSrcText)
2019 :
2020 : {
2021 2397 : VALIDATE_POINTER1(hGeom, "OGR_G_ExportToWkt", OGRERR_FAILURE);
2022 :
2023 2397 : return OGRGeometry::FromHandle(hGeom)->exportToWkt(ppszSrcText);
2024 : }
2025 :
2026 : /************************************************************************/
2027 : /* OGR_G_ExportToIsoWkt() */
2028 : /************************************************************************/
2029 :
2030 : /**
2031 : * \brief Convert a geometry into SFSQL 1.2 / ISO SQL/MM Part 3 well
2032 : * known text format.
2033 : *
2034 : * This function relates to the SFCOM IWks::ExportToWKT() method.
2035 : * It exports the SFSQL 1.2 and ISO SQL/MM Part 3 extended dimension
2036 : * (Z&M) WKB types.
2037 : *
2038 : * This function is the same as the CPP method
2039 : * OGRGeometry::exportToWkt(wkbVariantIso).
2040 : *
2041 : * @param hGeom handle on the geometry to convert to a text format from.
2042 : * @param ppszSrcText a text buffer is allocated by the program, and assigned
2043 : * to the passed pointer. After use, *ppszDstText should be
2044 : * freed with CPLFree().
2045 : *
2046 : * @return Currently OGRERR_NONE is always returned.
2047 : *
2048 : * @since GDAL 2.0
2049 : */
2050 :
2051 5408 : OGRErr OGR_G_ExportToIsoWkt(OGRGeometryH hGeom, char **ppszSrcText)
2052 :
2053 : {
2054 5408 : VALIDATE_POINTER1(hGeom, "OGR_G_ExportToIsoWkt", OGRERR_FAILURE);
2055 :
2056 5408 : return OGRGeometry::FromHandle(hGeom)->exportToWkt(ppszSrcText,
2057 5408 : wkbVariantIso);
2058 : }
2059 :
2060 : /**
2061 : * \fn OGRwkbGeometryType OGRGeometry::getGeometryType() const;
2062 : *
2063 : * \brief Fetch geometry type.
2064 : *
2065 : * Note that the geometry type may include the 2.5D flag. To get a 2D
2066 : * flattened version of the geometry type apply the wkbFlatten() macro
2067 : * to the return result.
2068 : *
2069 : * This method is the same as the C function OGR_G_GetGeometryType().
2070 : *
2071 : * @return the geometry type code.
2072 : */
2073 :
2074 : /************************************************************************/
2075 : /* OGR_G_GetGeometryType() */
2076 : /************************************************************************/
2077 : /**
2078 : * \brief Fetch geometry type.
2079 : *
2080 : * Note that the geometry type may include the 2.5D flag. To get a 2D
2081 : * flattened version of the geometry type apply the wkbFlatten() macro
2082 : * to the return result.
2083 : *
2084 : * This function is the same as the CPP method OGRGeometry::getGeometryType().
2085 : *
2086 : * @param hGeom handle on the geometry to get type from.
2087 : * @return the geometry type code.
2088 : */
2089 :
2090 5158 : OGRwkbGeometryType OGR_G_GetGeometryType(OGRGeometryH hGeom)
2091 :
2092 : {
2093 5158 : VALIDATE_POINTER1(hGeom, "OGR_G_GetGeometryType", wkbUnknown);
2094 :
2095 5158 : return OGRGeometry::FromHandle(hGeom)->getGeometryType();
2096 : }
2097 :
2098 : /**
2099 : * \fn const char * OGRGeometry::getGeometryName() const;
2100 : *
2101 : * \brief Fetch WKT name for geometry type.
2102 : *
2103 : * There is no SFCOM analog to this method.
2104 : *
2105 : * This method is the same as the C function OGR_G_GetGeometryName().
2106 : *
2107 : * @return name used for this geometry type in well known text format. The
2108 : * returned pointer is to a static internal string and should not be modified
2109 : * or freed.
2110 : */
2111 :
2112 : /************************************************************************/
2113 : /* OGR_G_GetGeometryName() */
2114 : /************************************************************************/
2115 : /**
2116 : * \brief Fetch WKT name for geometry type.
2117 : *
2118 : * There is no SFCOM analog to this function.
2119 : *
2120 : * This function is the same as the CPP method OGRGeometry::getGeometryName().
2121 : *
2122 : * @param hGeom handle on the geometry to get name from.
2123 : * @return name used for this geometry type in well known text format.
2124 : */
2125 :
2126 16154 : const char *OGR_G_GetGeometryName(OGRGeometryH hGeom)
2127 :
2128 : {
2129 16154 : VALIDATE_POINTER1(hGeom, "OGR_G_GetGeometryName", "");
2130 :
2131 16154 : return OGRGeometry::FromHandle(hGeom)->getGeometryName();
2132 : }
2133 :
2134 : /**
2135 : * \fn OGRGeometry *OGRGeometry::clone() const;
2136 : *
2137 : * \brief Make a copy of this object.
2138 : *
2139 : * This method relates to the SFCOM IGeometry::clone() method.
2140 : *
2141 : * This method is the same as the C function OGR_G_Clone().
2142 : *
2143 : * @return a new object instance with the same geometry, and spatial
2144 : * reference system as the original.
2145 : */
2146 :
2147 : /************************************************************************/
2148 : /* OGR_G_Clone() */
2149 : /************************************************************************/
2150 : /**
2151 : * \brief Make a copy of this object.
2152 : *
2153 : * This function relates to the SFCOM IGeometry::clone() method.
2154 : *
2155 : * This function is the same as the CPP method OGRGeometry::clone().
2156 : *
2157 : * @param hGeom handle on the geometry to clone from.
2158 : * @return a handle on the copy of the geometry with the spatial
2159 : * reference system as the original.
2160 : */
2161 :
2162 13516 : OGRGeometryH OGR_G_Clone(OGRGeometryH hGeom)
2163 :
2164 : {
2165 13516 : VALIDATE_POINTER1(hGeom, "OGR_G_Clone", nullptr);
2166 :
2167 13516 : return OGRGeometry::ToHandle(OGRGeometry::FromHandle(hGeom)->clone());
2168 : }
2169 :
2170 : /**
2171 : * \fn OGRSpatialReference *OGRGeometry::getSpatialReference();
2172 : *
2173 : * \brief Returns spatial reference system for object.
2174 : *
2175 : * This method relates to the SFCOM IGeometry::get_SpatialReference() method.
2176 : *
2177 : * This method is the same as the C function OGR_G_GetSpatialReference().
2178 : *
2179 : * @return a reference to the spatial reference object. The object may be
2180 : * shared with many geometry objects, and should not be modified.
2181 : */
2182 :
2183 : /************************************************************************/
2184 : /* OGR_G_GetSpatialReference() */
2185 : /************************************************************************/
2186 : /**
2187 : * \brief Returns spatial reference system for geometry.
2188 : *
2189 : * This function relates to the SFCOM IGeometry::get_SpatialReference() method.
2190 : *
2191 : * This function is the same as the CPP method
2192 : * OGRGeometry::getSpatialReference().
2193 : *
2194 : * @param hGeom handle on the geometry to get spatial reference from.
2195 : * @return a reference to the spatial reference geometry, which should not be
2196 : * modified.
2197 : */
2198 :
2199 49 : OGRSpatialReferenceH OGR_G_GetSpatialReference(OGRGeometryH hGeom)
2200 :
2201 : {
2202 49 : VALIDATE_POINTER1(hGeom, "OGR_G_GetSpatialReference", nullptr);
2203 :
2204 49 : return OGRSpatialReference::ToHandle(const_cast<OGRSpatialReference *>(
2205 98 : OGRGeometry::FromHandle(hGeom)->getSpatialReference()));
2206 : }
2207 :
2208 : /**
2209 : * \fn void OGRGeometry::empty();
2210 : *
2211 : * \brief Clear geometry information.
2212 : * This restores the geometry to its initial
2213 : * state after construction, and before assignment of actual geometry.
2214 : *
2215 : * This method relates to the SFCOM IGeometry::Empty() method.
2216 : *
2217 : * This method is the same as the C function OGR_G_Empty().
2218 : */
2219 :
2220 : /************************************************************************/
2221 : /* OGR_G_Empty() */
2222 : /************************************************************************/
2223 : /**
2224 : * \brief Clear geometry information.
2225 : * This restores the geometry to its initial
2226 : * state after construction, and before assignment of actual geometry.
2227 : *
2228 : * This function relates to the SFCOM IGeometry::Empty() method.
2229 : *
2230 : * This function is the same as the CPP method OGRGeometry::empty().
2231 : *
2232 : * @param hGeom handle on the geometry to empty.
2233 : */
2234 :
2235 4 : void OGR_G_Empty(OGRGeometryH hGeom)
2236 :
2237 : {
2238 4 : VALIDATE_POINTER0(hGeom, "OGR_G_Empty");
2239 :
2240 4 : OGRGeometry::FromHandle(hGeom)->empty();
2241 : }
2242 :
2243 : /**
2244 : * \fn OGRBoolean OGRGeometry::IsEmpty() const;
2245 : *
2246 : * \brief Returns TRUE (non-zero) if the object has no points.
2247 : *
2248 : * Normally this
2249 : * returns FALSE except between when an object is instantiated and points
2250 : * have been assigned.
2251 : *
2252 : * This method relates to the SFCOM IGeometry::IsEmpty() method.
2253 : *
2254 : * @return TRUE if object is empty, otherwise FALSE.
2255 : */
2256 :
2257 : /************************************************************************/
2258 : /* OGR_G_IsEmpty() */
2259 : /************************************************************************/
2260 :
2261 : /**
2262 : * \brief Test if the geometry is empty.
2263 : *
2264 : * This method is the same as the CPP method OGRGeometry::IsEmpty().
2265 : *
2266 : * @param hGeom The Geometry to test.
2267 : *
2268 : * @return TRUE if the geometry has no points, otherwise FALSE.
2269 : */
2270 :
2271 2139 : int OGR_G_IsEmpty(OGRGeometryH hGeom)
2272 :
2273 : {
2274 2139 : VALIDATE_POINTER1(hGeom, "OGR_G_IsEmpty", TRUE);
2275 :
2276 2139 : return OGRGeometry::FromHandle(hGeom)->IsEmpty();
2277 : }
2278 :
2279 : /************************************************************************/
2280 : /* IsValid() */
2281 : /************************************************************************/
2282 :
2283 : /**
2284 : * \brief Test if the geometry is valid.
2285 : *
2286 : * This method is the same as the C function OGR_G_IsValid().
2287 : *
2288 : * This method is built on the GEOS library, check it for the definition
2289 : * of the geometry operation.
2290 : * If OGR is built without the GEOS library, this method will always return
2291 : * FALSE.
2292 : *
2293 : *
2294 : * @return TRUE if the geometry has no points, otherwise FALSE.
2295 : */
2296 :
2297 1682 : OGRBoolean OGRGeometry::IsValid() const
2298 :
2299 : {
2300 1682 : if (IsSFCGALCompatible())
2301 : {
2302 : #ifndef HAVE_SFCGAL
2303 :
2304 : #ifdef HAVE_GEOS
2305 2 : if (wkbFlatten(getGeometryType()) == wkbTriangle)
2306 : {
2307 : // go on
2308 : }
2309 : else
2310 : #endif
2311 : {
2312 1 : CPLError(CE_Failure, CPLE_NotSupported,
2313 : "SFCGAL support not enabled.");
2314 1 : return FALSE;
2315 : }
2316 : #else
2317 : sfcgal_init();
2318 : sfcgal_geometry_t *poThis = OGRGeometry::OGRexportToSFCGAL(this);
2319 : if (poThis == nullptr)
2320 : {
2321 : CPLError(CE_Failure, CPLE_IllegalArg,
2322 : "SFCGAL geometry returned is NULL");
2323 : return FALSE;
2324 : }
2325 :
2326 : const int res = sfcgal_geometry_is_valid(poThis);
2327 : sfcgal_geometry_delete(poThis);
2328 : return res == 1;
2329 : #endif
2330 : }
2331 :
2332 : {
2333 : #ifndef HAVE_GEOS
2334 : CPLError(CE_Failure, CPLE_NotSupported, "GEOS support not enabled.");
2335 : return FALSE;
2336 :
2337 : #else
2338 1676 : OGRBoolean bResult = FALSE;
2339 :
2340 : // Some invalid geometries, such as lines with one point, or
2341 : // rings that do not close, cannot be converted to GEOS.
2342 : // For validity checking we initialize the GEOS context with
2343 : // the warning handler as the error handler to avoid emitting
2344 : // CE_Failure when a geometry cannot be converted to GEOS.
2345 : GEOSContextHandle_t hGEOSCtxt =
2346 1676 : initGEOS_r(OGRGEOSWarningHandler, OGRGEOSWarningHandler);
2347 :
2348 1679 : GEOSGeom hThisGeosGeom = exportToGEOS(hGEOSCtxt);
2349 :
2350 1677 : if (hThisGeosGeom != nullptr)
2351 : {
2352 1675 : bResult = GEOSisValid_r(hGEOSCtxt, hThisGeosGeom);
2353 : #ifdef DEBUG_VERBOSE
2354 : if (!bResult)
2355 : {
2356 : char *pszReason = GEOSisValidReason_r(hGEOSCtxt, hThisGeosGeom);
2357 : CPLDebug("OGR", "%s", pszReason);
2358 : GEOSFree_r(hGEOSCtxt, pszReason);
2359 : }
2360 : #endif
2361 1677 : GEOSGeom_destroy_r(hGEOSCtxt, hThisGeosGeom);
2362 : }
2363 1681 : freeGEOSContext(hGEOSCtxt);
2364 :
2365 1678 : return bResult;
2366 :
2367 : #endif // HAVE_GEOS
2368 : }
2369 : }
2370 :
2371 : /************************************************************************/
2372 : /* OGR_G_IsValid() */
2373 : /************************************************************************/
2374 :
2375 : /**
2376 : * \brief Test if the geometry is valid.
2377 : *
2378 : * This function is the same as the C++ method OGRGeometry::IsValid().
2379 : *
2380 : * This function is built on the GEOS library, check it for the definition
2381 : * of the geometry operation.
2382 : * If OGR is built without the GEOS library, this function will always return
2383 : * FALSE.
2384 : *
2385 : * @param hGeom The Geometry to test.
2386 : *
2387 : * @return TRUE if the geometry has no points, otherwise FALSE.
2388 : */
2389 :
2390 19 : int OGR_G_IsValid(OGRGeometryH hGeom)
2391 :
2392 : {
2393 19 : VALIDATE_POINTER1(hGeom, "OGR_G_IsValid", FALSE);
2394 :
2395 19 : return OGRGeometry::FromHandle(hGeom)->IsValid();
2396 : }
2397 :
2398 : /************************************************************************/
2399 : /* IsSimple() */
2400 : /************************************************************************/
2401 :
2402 : /**
2403 : * \brief Test if the geometry is simple.
2404 : *
2405 : * This method is the same as the C function OGR_G_IsSimple().
2406 : *
2407 : * This method is built on the GEOS library, check it for the definition
2408 : * of the geometry operation.
2409 : * If OGR is built without the GEOS library, this method will always return
2410 : * FALSE.
2411 : *
2412 : *
2413 : * @return TRUE if the geometry has no points, otherwise FALSE.
2414 : */
2415 :
2416 5 : OGRBoolean OGRGeometry::IsSimple() const
2417 :
2418 : {
2419 : #ifndef HAVE_GEOS
2420 : CPLError(CE_Failure, CPLE_NotSupported, "GEOS support not enabled.");
2421 : return FALSE;
2422 :
2423 : #else
2424 :
2425 5 : OGRBoolean bResult = FALSE;
2426 :
2427 5 : GEOSContextHandle_t hGEOSCtxt = createGEOSContext();
2428 5 : GEOSGeom hThisGeosGeom = exportToGEOS(hGEOSCtxt);
2429 :
2430 5 : if (hThisGeosGeom != nullptr)
2431 : {
2432 5 : bResult = GEOSisSimple_r(hGEOSCtxt, hThisGeosGeom);
2433 5 : GEOSGeom_destroy_r(hGEOSCtxt, hThisGeosGeom);
2434 : }
2435 5 : freeGEOSContext(hGEOSCtxt);
2436 :
2437 5 : return bResult;
2438 :
2439 : #endif // HAVE_GEOS
2440 : }
2441 :
2442 : /**
2443 : * \brief Returns TRUE if the geometry is simple.
2444 : *
2445 : * Returns TRUE if the geometry has no anomalous geometric points, such
2446 : * as self intersection or self tangency. The description of each
2447 : * instantiable geometric class will include the specific conditions that
2448 : * cause an instance of that class to be classified as not simple.
2449 : *
2450 : * This function is the same as the C++ method OGRGeometry::IsSimple() method.
2451 : *
2452 : * If OGR is built without the GEOS library, this function will always return
2453 : * FALSE.
2454 : *
2455 : * @param hGeom The Geometry to test.
2456 : *
2457 : * @return TRUE if object is simple, otherwise FALSE.
2458 : */
2459 :
2460 5 : int OGR_G_IsSimple(OGRGeometryH hGeom)
2461 :
2462 : {
2463 5 : VALIDATE_POINTER1(hGeom, "OGR_G_IsSimple", TRUE);
2464 :
2465 5 : return OGRGeometry::FromHandle(hGeom)->IsSimple();
2466 : }
2467 :
2468 : /************************************************************************/
2469 : /* IsRing() */
2470 : /************************************************************************/
2471 :
2472 : /**
2473 : * \brief Test if the geometry is a ring
2474 : *
2475 : * This method is the same as the C function OGR_G_IsRing().
2476 : *
2477 : * This method is built on the GEOS library, check it for the definition
2478 : * of the geometry operation.
2479 : * If OGR is built without the GEOS library, this method will always return
2480 : * FALSE.
2481 : *
2482 : *
2483 : * @return TRUE if the geometry has no points, otherwise FALSE.
2484 : */
2485 :
2486 1 : OGRBoolean OGRGeometry::IsRing() const
2487 :
2488 : {
2489 : #ifndef HAVE_GEOS
2490 : CPLError(CE_Failure, CPLE_NotSupported, "GEOS support not enabled.");
2491 : return FALSE;
2492 :
2493 : #else
2494 :
2495 1 : OGRBoolean bResult = FALSE;
2496 :
2497 1 : GEOSContextHandle_t hGEOSCtxt = createGEOSContext();
2498 1 : GEOSGeom hThisGeosGeom = exportToGEOS(hGEOSCtxt);
2499 :
2500 1 : if (hThisGeosGeom != nullptr)
2501 : {
2502 1 : bResult = GEOSisRing_r(hGEOSCtxt, hThisGeosGeom);
2503 1 : GEOSGeom_destroy_r(hGEOSCtxt, hThisGeosGeom);
2504 : }
2505 1 : freeGEOSContext(hGEOSCtxt);
2506 :
2507 1 : return bResult;
2508 :
2509 : #endif // HAVE_GEOS
2510 : }
2511 :
2512 : /************************************************************************/
2513 : /* OGR_G_IsRing() */
2514 : /************************************************************************/
2515 :
2516 : /**
2517 : * \brief Test if the geometry is a ring
2518 : *
2519 : * This function is the same as the C++ method OGRGeometry::IsRing().
2520 : *
2521 : * This function is built on the GEOS library, check it for the definition
2522 : * of the geometry operation.
2523 : * If OGR is built without the GEOS library, this function will always return
2524 : * FALSE.
2525 : *
2526 : * @param hGeom The Geometry to test.
2527 : *
2528 : * @return TRUE if the geometry has no points, otherwise FALSE.
2529 : */
2530 :
2531 1 : int OGR_G_IsRing(OGRGeometryH hGeom)
2532 :
2533 : {
2534 1 : VALIDATE_POINTER1(hGeom, "OGR_G_IsRing", FALSE);
2535 :
2536 1 : return OGRGeometry::FromHandle(hGeom)->IsRing();
2537 : }
2538 :
2539 : /************************************************************************/
2540 : /* OGRFromOGCGeomType() */
2541 : /************************************************************************/
2542 :
2543 : /** Map OGCgeometry format type to corresponding OGR constants.
2544 : * @param pszGeomType POINT[ ][Z][M], LINESTRING[ ][Z][M], etc...
2545 : * @return OGR constant.
2546 : */
2547 2287 : OGRwkbGeometryType OGRFromOGCGeomType(const char *pszGeomType)
2548 : {
2549 2287 : OGRwkbGeometryType eType = wkbUnknown;
2550 2287 : bool bConvertTo3D = false;
2551 2287 : bool bIsMeasured = false;
2552 2287 : if (*pszGeomType != '\0')
2553 : {
2554 2281 : char ch = pszGeomType[strlen(pszGeomType) - 1];
2555 2281 : if (ch == 'm' || ch == 'M')
2556 : {
2557 2 : bIsMeasured = true;
2558 2 : if (strlen(pszGeomType) > 1)
2559 2 : ch = pszGeomType[strlen(pszGeomType) - 2];
2560 : }
2561 2281 : if (ch == 'z' || ch == 'Z')
2562 : {
2563 16 : bConvertTo3D = true;
2564 : }
2565 : }
2566 :
2567 2287 : if (STARTS_WITH_CI(pszGeomType, "POINT"))
2568 553 : eType = wkbPoint;
2569 1734 : else if (STARTS_WITH_CI(pszGeomType, "LINESTRING"))
2570 164 : eType = wkbLineString;
2571 1570 : else if (STARTS_WITH_CI(pszGeomType, "POLYGON"))
2572 463 : eType = wkbPolygon;
2573 1107 : else if (STARTS_WITH_CI(pszGeomType, "MULTIPOINT"))
2574 21 : eType = wkbMultiPoint;
2575 1086 : else if (STARTS_WITH_CI(pszGeomType, "MULTILINESTRING"))
2576 13 : eType = wkbMultiLineString;
2577 1073 : else if (STARTS_WITH_CI(pszGeomType, "MULTIPOLYGON"))
2578 64 : eType = wkbMultiPolygon;
2579 1009 : else if (STARTS_WITH_CI(pszGeomType, "GEOMETRYCOLLECTION"))
2580 4 : eType = wkbGeometryCollection;
2581 1005 : else if (STARTS_WITH_CI(pszGeomType, "CIRCULARSTRING"))
2582 331 : eType = wkbCircularString;
2583 674 : else if (STARTS_WITH_CI(pszGeomType, "COMPOUNDCURVE"))
2584 0 : eType = wkbCompoundCurve;
2585 674 : else if (STARTS_WITH_CI(pszGeomType, "CURVEPOLYGON"))
2586 16 : eType = wkbCurvePolygon;
2587 658 : else if (STARTS_WITH_CI(pszGeomType, "MULTICURVE"))
2588 2 : eType = wkbMultiCurve;
2589 656 : else if (STARTS_WITH_CI(pszGeomType, "MULTISURFACE"))
2590 0 : eType = wkbMultiSurface;
2591 656 : else if (STARTS_WITH_CI(pszGeomType, "TRIANGLE"))
2592 0 : eType = wkbTriangle;
2593 656 : else if (STARTS_WITH_CI(pszGeomType, "POLYHEDRALSURFACE"))
2594 1 : eType = wkbPolyhedralSurface;
2595 655 : else if (STARTS_WITH_CI(pszGeomType, "TIN"))
2596 5 : eType = wkbTIN;
2597 650 : else if (STARTS_WITH_CI(pszGeomType, "CURVE"))
2598 3 : eType = wkbCurve;
2599 647 : else if (STARTS_WITH_CI(pszGeomType, "SURFACE"))
2600 3 : eType = wkbSurface;
2601 : else
2602 644 : eType = wkbUnknown;
2603 :
2604 2287 : if (bConvertTo3D)
2605 16 : eType = wkbSetZ(eType);
2606 2287 : if (bIsMeasured)
2607 2 : eType = wkbSetM(eType);
2608 :
2609 2287 : return eType;
2610 : }
2611 :
2612 : /************************************************************************/
2613 : /* OGRToOGCGeomType() */
2614 : /************************************************************************/
2615 :
2616 : /** Map OGR geometry format constants to corresponding OGC geometry type.
2617 : * @param eGeomType OGR geometry type
2618 : * @param bCamelCase Whether the return should be like "MultiPoint"
2619 : * (bCamelCase=true) or "MULTIPOINT" (bCamelCase=false, default)
2620 : * @param bAddZM Whether to include Z, M or ZM suffix for non-2D geometries.
2621 : * Default is false.
2622 : * @param bSpaceBeforeZM Whether to include a space character before the Z/M/ZM
2623 : * suffix. Default is false.
2624 : * @return string with OGC geometry type (without dimensionality)
2625 : */
2626 2379 : const char *OGRToOGCGeomType(OGRwkbGeometryType eGeomType, bool bCamelCase,
2627 : bool bAddZM, bool bSpaceBeforeZM)
2628 : {
2629 2379 : const char *pszRet = "";
2630 2379 : switch (wkbFlatten(eGeomType))
2631 : {
2632 1347 : case wkbUnknown:
2633 1347 : pszRet = "Geometry";
2634 1347 : break;
2635 341 : case wkbPoint:
2636 341 : pszRet = "Point";
2637 341 : break;
2638 128 : case wkbLineString:
2639 128 : pszRet = "LineString";
2640 128 : break;
2641 237 : case wkbPolygon:
2642 237 : pszRet = "Polygon";
2643 237 : break;
2644 50 : case wkbMultiPoint:
2645 50 : pszRet = "MultiPoint";
2646 50 : break;
2647 53 : case wkbMultiLineString:
2648 53 : pszRet = "MultiLineString";
2649 53 : break;
2650 68 : case wkbMultiPolygon:
2651 68 : pszRet = "MultiPolygon";
2652 68 : break;
2653 54 : case wkbGeometryCollection:
2654 54 : pszRet = "GeometryCollection";
2655 54 : break;
2656 9 : case wkbCircularString:
2657 9 : pszRet = "CircularString";
2658 9 : break;
2659 3 : case wkbCompoundCurve:
2660 3 : pszRet = "CompoundCurve";
2661 3 : break;
2662 12 : case wkbCurvePolygon:
2663 12 : pszRet = "CurvePolygon";
2664 12 : break;
2665 2 : case wkbMultiCurve:
2666 2 : pszRet = "MultiCurve";
2667 2 : break;
2668 3 : case wkbMultiSurface:
2669 3 : pszRet = "MultiSurface";
2670 3 : break;
2671 3 : case wkbTriangle:
2672 3 : pszRet = "Triangle";
2673 3 : break;
2674 3 : case wkbPolyhedralSurface:
2675 3 : pszRet = "PolyhedralSurface";
2676 3 : break;
2677 1 : case wkbTIN:
2678 1 : pszRet = "Tin";
2679 1 : break;
2680 3 : case wkbCurve:
2681 3 : pszRet = "Curve";
2682 3 : break;
2683 3 : case wkbSurface:
2684 3 : pszRet = "Surface";
2685 3 : break;
2686 59 : default:
2687 59 : break;
2688 : }
2689 2379 : if (bAddZM)
2690 : {
2691 35 : const bool bHasZ = CPL_TO_BOOL(OGR_GT_HasZ(eGeomType));
2692 35 : const bool bHasM = CPL_TO_BOOL(OGR_GT_HasM(eGeomType));
2693 35 : if (bHasZ || bHasM)
2694 : {
2695 11 : if (bSpaceBeforeZM)
2696 1 : pszRet = CPLSPrintf("%s ", pszRet);
2697 11 : if (bHasZ)
2698 10 : pszRet = CPLSPrintf("%sZ", pszRet);
2699 11 : if (bHasM)
2700 6 : pszRet = CPLSPrintf("%sM", pszRet);
2701 : }
2702 : }
2703 2379 : if (!bCamelCase)
2704 2343 : pszRet = CPLSPrintf("%s", CPLString(pszRet).toupper().c_str());
2705 2379 : return pszRet;
2706 : }
2707 :
2708 : /************************************************************************/
2709 : /* OGRGeometryTypeToName() */
2710 : /************************************************************************/
2711 :
2712 : /**
2713 : * \brief Fetch a human readable name corresponding to an OGRwkbGeometryType
2714 : * value. The returned value should not be modified, or freed by the
2715 : * application.
2716 : *
2717 : * This function is C callable.
2718 : *
2719 : * @param eType the geometry type.
2720 : *
2721 : * @return internal human readable string, or NULL on failure.
2722 : */
2723 :
2724 363 : const char *OGRGeometryTypeToName(OGRwkbGeometryType eType)
2725 :
2726 : {
2727 363 : bool b3D = wkbHasZ(eType);
2728 363 : bool bMeasured = wkbHasM(eType);
2729 :
2730 363 : switch (wkbFlatten(eType))
2731 : {
2732 34 : case wkbUnknown:
2733 34 : if (b3D && bMeasured)
2734 0 : return "3D Measured Unknown (any)";
2735 34 : else if (b3D)
2736 1 : return "3D Unknown (any)";
2737 33 : else if (bMeasured)
2738 0 : return "Measured Unknown (any)";
2739 : else
2740 33 : return "Unknown (any)";
2741 :
2742 50 : case wkbPoint:
2743 50 : if (b3D && bMeasured)
2744 2 : return "3D Measured Point";
2745 48 : else if (b3D)
2746 11 : return "3D Point";
2747 37 : else if (bMeasured)
2748 2 : return "Measured Point";
2749 : else
2750 35 : return "Point";
2751 :
2752 22 : case wkbLineString:
2753 22 : if (b3D && bMeasured)
2754 0 : return "3D Measured Line String";
2755 22 : else if (b3D)
2756 9 : return "3D Line String";
2757 13 : else if (bMeasured)
2758 0 : return "Measured Line String";
2759 : else
2760 13 : return "Line String";
2761 :
2762 53 : case wkbPolygon:
2763 53 : if (b3D && bMeasured)
2764 0 : return "3D Measured Polygon";
2765 53 : else if (b3D)
2766 8 : return "3D Polygon";
2767 45 : else if (bMeasured)
2768 0 : return "Measured Polygon";
2769 : else
2770 45 : return "Polygon";
2771 :
2772 23 : case wkbMultiPoint:
2773 23 : if (b3D && bMeasured)
2774 0 : return "3D Measured Multi Point";
2775 23 : else if (b3D)
2776 9 : return "3D Multi Point";
2777 14 : else if (bMeasured)
2778 0 : return "Measured Multi Point";
2779 : else
2780 14 : return "Multi Point";
2781 :
2782 14 : case wkbMultiLineString:
2783 14 : if (b3D && bMeasured)
2784 0 : return "3D Measured Multi Line String";
2785 14 : else if (b3D)
2786 6 : return "3D Multi Line String";
2787 8 : else if (bMeasured)
2788 0 : return "Measured Multi Line String";
2789 : else
2790 8 : return "Multi Line String";
2791 :
2792 19 : case wkbMultiPolygon:
2793 19 : if (b3D && bMeasured)
2794 0 : return "3D Measured Multi Polygon";
2795 19 : else if (b3D)
2796 8 : return "3D Multi Polygon";
2797 11 : else if (bMeasured)
2798 0 : return "Measured Multi Polygon";
2799 : else
2800 11 : return "Multi Polygon";
2801 :
2802 25 : case wkbGeometryCollection:
2803 25 : if (b3D && bMeasured)
2804 0 : return "3D Measured Geometry Collection";
2805 25 : else if (b3D)
2806 10 : return "3D Geometry Collection";
2807 15 : else if (bMeasured)
2808 0 : return "Measured Geometry Collection";
2809 : else
2810 15 : return "Geometry Collection";
2811 :
2812 0 : case wkbCircularString:
2813 0 : if (b3D && bMeasured)
2814 0 : return "3D Measured Circular String";
2815 0 : else if (b3D)
2816 0 : return "3D Circular String";
2817 0 : else if (bMeasured)
2818 0 : return "Measured Circular String";
2819 : else
2820 0 : return "Circular String";
2821 :
2822 1 : case wkbCompoundCurve:
2823 1 : if (b3D && bMeasured)
2824 0 : return "3D Measured Compound Curve";
2825 1 : else if (b3D)
2826 0 : return "3D Compound Curve";
2827 1 : else if (bMeasured)
2828 0 : return "Measured Compound Curve";
2829 : else
2830 1 : return "Compound Curve";
2831 :
2832 0 : case wkbCurvePolygon:
2833 0 : if (b3D && bMeasured)
2834 0 : return "3D Measured Curve Polygon";
2835 0 : else if (b3D)
2836 0 : return "3D Curve Polygon";
2837 0 : else if (bMeasured)
2838 0 : return "Measured Curve Polygon";
2839 : else
2840 0 : return "Curve Polygon";
2841 :
2842 0 : case wkbMultiCurve:
2843 0 : if (b3D && bMeasured)
2844 0 : return "3D Measured Multi Curve";
2845 0 : else if (b3D)
2846 0 : return "3D Multi Curve";
2847 0 : else if (bMeasured)
2848 0 : return "Measured Multi Curve";
2849 : else
2850 0 : return "Multi Curve";
2851 :
2852 0 : case wkbMultiSurface:
2853 0 : if (b3D && bMeasured)
2854 0 : return "3D Measured Multi Surface";
2855 0 : else if (b3D)
2856 0 : return "3D Multi Surface";
2857 0 : else if (bMeasured)
2858 0 : return "Measured Multi Surface";
2859 : else
2860 0 : return "Multi Surface";
2861 :
2862 4 : case wkbCurve:
2863 4 : if (b3D && bMeasured)
2864 1 : return "3D Measured Curve";
2865 3 : else if (b3D)
2866 1 : return "3D Curve";
2867 2 : else if (bMeasured)
2868 1 : return "Measured Curve";
2869 : else
2870 1 : return "Curve";
2871 :
2872 4 : case wkbSurface:
2873 4 : if (b3D && bMeasured)
2874 1 : return "3D Measured Surface";
2875 3 : else if (b3D)
2876 1 : return "3D Surface";
2877 2 : else if (bMeasured)
2878 1 : return "Measured Surface";
2879 : else
2880 1 : return "Surface";
2881 :
2882 0 : case wkbTriangle:
2883 0 : if (b3D && bMeasured)
2884 0 : return "3D Measured Triangle";
2885 0 : else if (b3D)
2886 0 : return "3D Triangle";
2887 0 : else if (bMeasured)
2888 0 : return "Measured Triangle";
2889 : else
2890 0 : return "Triangle";
2891 :
2892 0 : case wkbPolyhedralSurface:
2893 0 : if (b3D && bMeasured)
2894 0 : return "3D Measured PolyhedralSurface";
2895 0 : else if (b3D)
2896 0 : return "3D PolyhedralSurface";
2897 0 : else if (bMeasured)
2898 0 : return "Measured PolyhedralSurface";
2899 : else
2900 0 : return "PolyhedralSurface";
2901 :
2902 2 : case wkbTIN:
2903 2 : if (b3D && bMeasured)
2904 0 : return "3D Measured TIN";
2905 2 : else if (b3D)
2906 0 : return "3D TIN";
2907 2 : else if (bMeasured)
2908 0 : return "Measured TIN";
2909 : else
2910 2 : return "TIN";
2911 :
2912 111 : case wkbNone:
2913 111 : return "None";
2914 :
2915 1 : default:
2916 : {
2917 1 : return CPLSPrintf("Unrecognized: %d", static_cast<int>(eType));
2918 : }
2919 : }
2920 : }
2921 :
2922 : /************************************************************************/
2923 : /* OGRMergeGeometryTypes() */
2924 : /************************************************************************/
2925 :
2926 : /**
2927 : * \brief Find common geometry type.
2928 : *
2929 : * Given two geometry types, find the most specific common
2930 : * type. Normally used repeatedly with the geometries in a
2931 : * layer to try and establish the most specific geometry type
2932 : * that can be reported for the layer.
2933 : *
2934 : * NOTE: wkbUnknown is the "worst case" indicating a mixture of
2935 : * geometry types with nothing in common but the base geometry
2936 : * type. wkbNone should be used to indicate that no geometries
2937 : * have been encountered yet, and means the first geometry
2938 : * encountered will establish the preliminary type.
2939 : *
2940 : * @param eMain the first input geometry type.
2941 : * @param eExtra the second input geometry type.
2942 : *
2943 : * @return the merged geometry type.
2944 : */
2945 :
2946 0 : OGRwkbGeometryType OGRMergeGeometryTypes(OGRwkbGeometryType eMain,
2947 : OGRwkbGeometryType eExtra)
2948 :
2949 : {
2950 0 : return OGRMergeGeometryTypesEx(eMain, eExtra, FALSE);
2951 : }
2952 :
2953 : /**
2954 : * \brief Find common geometry type.
2955 : *
2956 : * Given two geometry types, find the most specific common
2957 : * type. Normally used repeatedly with the geometries in a
2958 : * layer to try and establish the most specific geometry type
2959 : * that can be reported for the layer.
2960 : *
2961 : * NOTE: wkbUnknown is the "worst case" indicating a mixture of
2962 : * geometry types with nothing in common but the base geometry
2963 : * type. wkbNone should be used to indicate that no geometries
2964 : * have been encountered yet, and means the first geometry
2965 : * encountered will establish the preliminary type.
2966 : *
2967 : * If bAllowPromotingToCurves is set to TRUE, mixing Polygon and CurvePolygon
2968 : * will return CurvePolygon. Mixing LineString, CircularString, CompoundCurve
2969 : * will return CompoundCurve. Mixing MultiPolygon and MultiSurface will return
2970 : * MultiSurface. Mixing MultiCurve and MultiLineString will return MultiCurve.
2971 : *
2972 : * @param eMain the first input geometry type.
2973 : * @param eExtra the second input geometry type.
2974 : * @param bAllowPromotingToCurves determine if promotion to curve type
2975 : * must be done.
2976 : *
2977 : * @return the merged geometry type.
2978 : *
2979 : * @since GDAL 2.0
2980 : */
2981 :
2982 373 : OGRwkbGeometryType OGRMergeGeometryTypesEx(OGRwkbGeometryType eMain,
2983 : OGRwkbGeometryType eExtra,
2984 : int bAllowPromotingToCurves)
2985 :
2986 : {
2987 373 : OGRwkbGeometryType eFMain = wkbFlatten(eMain);
2988 373 : OGRwkbGeometryType eFExtra = wkbFlatten(eExtra);
2989 :
2990 373 : const bool bHasZ = (wkbHasZ(eMain) || wkbHasZ(eExtra));
2991 373 : const bool bHasM = (wkbHasM(eMain) || wkbHasM(eExtra));
2992 :
2993 373 : if (eFMain == wkbUnknown || eFExtra == wkbUnknown)
2994 17 : return OGR_GT_SetModifier(wkbUnknown, bHasZ, bHasM);
2995 :
2996 356 : if (eFMain == wkbNone)
2997 2 : return eExtra;
2998 :
2999 354 : if (eFExtra == wkbNone)
3000 0 : return eMain;
3001 :
3002 354 : if (eFMain == eFExtra)
3003 : {
3004 338 : return OGR_GT_SetModifier(eFMain, bHasZ, bHasM);
3005 : }
3006 :
3007 16 : if (bAllowPromotingToCurves)
3008 : {
3009 16 : if (OGR_GT_IsCurve(eFMain) && OGR_GT_IsCurve(eFExtra))
3010 4 : return OGR_GT_SetModifier(wkbCompoundCurve, bHasZ, bHasM);
3011 :
3012 12 : if (OGR_GT_IsSubClassOf(eFMain, eFExtra))
3013 3 : return OGR_GT_SetModifier(eFExtra, bHasZ, bHasM);
3014 :
3015 9 : if (OGR_GT_IsSubClassOf(eFExtra, eFMain))
3016 6 : return OGR_GT_SetModifier(eFMain, bHasZ, bHasM);
3017 : }
3018 :
3019 : // One is subclass of the other one
3020 3 : if (OGR_GT_IsSubClassOf(eFMain, eFExtra))
3021 : {
3022 0 : return OGR_GT_SetModifier(eFExtra, bHasZ, bHasM);
3023 : }
3024 3 : else if (OGR_GT_IsSubClassOf(eFExtra, eFMain))
3025 : {
3026 0 : return OGR_GT_SetModifier(eFMain, bHasZ, bHasM);
3027 : }
3028 :
3029 : // Nothing apparently in common.
3030 3 : return OGR_GT_SetModifier(wkbUnknown, bHasZ, bHasM);
3031 : }
3032 :
3033 : /**
3034 : * \fn void OGRGeometry::flattenTo2D();
3035 : *
3036 : * \brief Convert geometry to strictly 2D.
3037 : * In a sense this converts all Z coordinates
3038 : * to 0.0.
3039 : *
3040 : * This method is the same as the C function OGR_G_FlattenTo2D().
3041 : */
3042 :
3043 : /************************************************************************/
3044 : /* OGR_G_FlattenTo2D() */
3045 : /************************************************************************/
3046 : /**
3047 : * \brief Convert geometry to strictly 2D.
3048 : * In a sense this converts all Z coordinates
3049 : * to 0.0.
3050 : *
3051 : * This function is the same as the CPP method OGRGeometry::flattenTo2D().
3052 : *
3053 : * @param hGeom handle on the geometry to convert.
3054 : */
3055 :
3056 31 : void OGR_G_FlattenTo2D(OGRGeometryH hGeom)
3057 :
3058 : {
3059 31 : OGRGeometry::FromHandle(hGeom)->flattenTo2D();
3060 31 : }
3061 :
3062 : /************************************************************************/
3063 : /* exportToGML() */
3064 : /************************************************************************/
3065 :
3066 : /**
3067 : * \fn char *OGRGeometry::exportToGML( const char* const *
3068 : * papszOptions = NULL ) const;
3069 : *
3070 : * \brief Convert a geometry into GML format.
3071 : *
3072 : * The GML geometry is expressed directly in terms of GML basic data
3073 : * types assuming the this is available in the gml namespace. The returned
3074 : * string should be freed with CPLFree() when no longer required.
3075 : *
3076 : * The supported options are :
3077 : * <ul>
3078 : * <li> FORMAT=GML2/GML3/GML32 (GML2 or GML32 added in GDAL 2.1).
3079 : * If not set, it will default to GML 2.1.2 output.
3080 : * </li>
3081 : * <li> GML3_LINESTRING_ELEMENT=curve. (Only valid for FORMAT=GML3)
3082 : * To use gml:Curve element for linestrings.
3083 : * Otherwise gml:LineString will be used .
3084 : * </li>
3085 : * <li> GML3_LONGSRS=YES/NO. (Only valid for FORMAT=GML3, deprecated by
3086 : * SRSNAME_FORMAT in GDAL >=2.2). Defaults to YES.
3087 : * If YES, SRS with EPSG authority will be written with the
3088 : * "urn:ogc:def:crs:EPSG::" prefix.
3089 : * In the case the SRS should be treated as lat/long or
3090 : * northing/easting, then the function will take care of coordinate order
3091 : * swapping if the data axis to CRS axis mapping indicates it.
3092 : * If set to NO, SRS with EPSG authority will be written with the "EPSG:"
3093 : * prefix, even if they are in lat/long order.
3094 : * </li>
3095 : * <li> SRSNAME_FORMAT=SHORT/OGC_URN/OGC_URL (Only valid for FORMAT=GML3, added
3096 : * in GDAL 2.2). Defaults to OGC_URN. If SHORT, then srsName will be in
3097 : * the form AUTHORITY_NAME:AUTHORITY_CODE. If OGC_URN, then srsName will be
3098 : * in the form urn:ogc:def:crs:AUTHORITY_NAME::AUTHORITY_CODE. If OGC_URL,
3099 : * then srsName will be in the form
3100 : * http://www.opengis.net/def/crs/AUTHORITY_NAME/0/AUTHORITY_CODE. For
3101 : * OGC_URN and OGC_URL, in the case the SRS should be treated as lat/long
3102 : * or northing/easting, then the function will take care of coordinate
3103 : * order swapping if the data axis to CRS axis mapping indicates it.
3104 : * </li>
3105 : * <li> GMLID=astring. If specified, a gml:id attribute will be written in the
3106 : * top-level geometry element with the provided value.
3107 : * Required for GML 3.2 compatibility.
3108 : * </li>
3109 : * <li> SRSDIMENSION_LOC=POSLIST/GEOMETRY/GEOMETRY,POSLIST. (Only valid for
3110 : * FORMAT=GML3/GML32, GDAL >= 2.0) Default to POSLIST.
3111 : * For 2.5D geometries, define the location where to attach the
3112 : * srsDimension attribute.
3113 : * There are diverging implementations. Some put in on the
3114 : * <gml:posList> element, other on the top geometry element.
3115 : * </li>
3116 : * <li> NAMESPACE_DECL=YES/NO. If set to YES,
3117 : * xmlns:gml="http://www.opengis.net/gml" will be added to the root node
3118 : * for GML < 3.2 or xmlns:gml="http://www.opengis.net/gml/3.2" for GML 3.2
3119 : * </li>
3120 : * <li> XY_COORD_RESOLUTION=double (added in GDAL 3.9):
3121 : * Resolution for the coordinate precision of the X and Y coordinates.
3122 : * Expressed in the units of the X and Y axis of the SRS. eg 1e-5 for up
3123 : * to 5 decimal digits. 0 for the default behavior.
3124 : * </li>
3125 : * <li> Z_COORD_RESOLUTION=double (added in GDAL 3.9):
3126 : * Resolution for the coordinate precision of the Z coordinates.
3127 : * Expressed in the units of the Z axis of the SRS.
3128 : * 0 for the default behavior.
3129 : * </li>
3130 : * </ul>
3131 : *
3132 : * This method is the same as the C function OGR_G_ExportToGMLEx().
3133 : *
3134 : * @param papszOptions NULL-terminated list of options.
3135 : * @return A GML fragment to be freed with CPLFree() or NULL in case of error.
3136 : */
3137 :
3138 251 : char *OGRGeometry::exportToGML(const char *const *papszOptions) const
3139 : {
3140 251 : return OGR_G_ExportToGMLEx(
3141 : OGRGeometry::ToHandle(const_cast<OGRGeometry *>(this)),
3142 251 : const_cast<char **>(papszOptions));
3143 : }
3144 :
3145 : /************************************************************************/
3146 : /* exportToKML() */
3147 : /************************************************************************/
3148 :
3149 : /**
3150 : * \fn char *OGRGeometry::exportToKML() const;
3151 : *
3152 : * \brief Convert a geometry into KML format.
3153 : *
3154 : * The returned string should be freed with CPLFree() when no longer required.
3155 : *
3156 : * This method is the same as the C function OGR_G_ExportToKML().
3157 : *
3158 : * @return A KML fragment to be freed with CPLFree() or NULL in case of error.
3159 : */
3160 :
3161 0 : char *OGRGeometry::exportToKML() const
3162 : {
3163 0 : return OGR_G_ExportToKML(
3164 0 : OGRGeometry::ToHandle(const_cast<OGRGeometry *>(this)), nullptr);
3165 : }
3166 :
3167 : /************************************************************************/
3168 : /* exportToJson() */
3169 : /************************************************************************/
3170 :
3171 : /**
3172 : * \fn char *OGRGeometry::exportToJson() const;
3173 : *
3174 : * \brief Convert a geometry into GeoJSON format.
3175 : *
3176 : * The returned string should be freed with CPLFree() when no longer required.
3177 : *
3178 : * The following options are supported :
3179 : * <ul>
3180 : * <li>XY_COORD_PRECISION=integer: number of decimal figures for X,Y coordinates
3181 : * (added in GDAL 3.9)</li>
3182 : * <li>Z_COORD_PRECISION=integer: number of decimal figures for Z coordinates
3183 : * (added in GDAL 3.9)</li>
3184 : * </ul>
3185 : *
3186 : * This method is the same as the C function OGR_G_ExportToJson().
3187 : *
3188 : * @param papszOptions Null terminated list of options, or null (added in 3.9)
3189 : * @return A GeoJSON fragment to be freed with CPLFree() or NULL in case of error.
3190 : */
3191 :
3192 39 : char *OGRGeometry::exportToJson(CSLConstList papszOptions) const
3193 : {
3194 39 : OGRGeometry *poGeometry = const_cast<OGRGeometry *>(this);
3195 39 : return OGR_G_ExportToJsonEx(OGRGeometry::ToHandle(poGeometry),
3196 39 : const_cast<char **>(papszOptions));
3197 : }
3198 :
3199 : /************************************************************************/
3200 : /* OGRSetGenerate_DB2_V72_BYTE_ORDER() */
3201 : /************************************************************************/
3202 :
3203 : /**
3204 : * \brief Special entry point to enable the hack for generating DB2 V7.2 style
3205 : * WKB.
3206 : *
3207 : * DB2 seems to have placed (and require) an extra 0x30 or'ed with the byte
3208 : * order in WKB. This entry point is used to turn on or off the generation of
3209 : * such WKB.
3210 : */
3211 4 : OGRErr OGRSetGenerate_DB2_V72_BYTE_ORDER(int bGenerate_DB2_V72_BYTE_ORDER)
3212 :
3213 : {
3214 : #if defined(HACK_FOR_IBM_DB2_V72)
3215 4 : OGRGeometry::bGenerate_DB2_V72_BYTE_ORDER = bGenerate_DB2_V72_BYTE_ORDER;
3216 4 : return OGRERR_NONE;
3217 : #else
3218 : if (bGenerate_DB2_V72_BYTE_ORDER)
3219 : return OGRERR_FAILURE;
3220 : else
3221 : return OGRERR_NONE;
3222 : #endif
3223 : }
3224 :
3225 : /************************************************************************/
3226 : /* OGRGetGenerate_DB2_V72_BYTE_ORDER() */
3227 : /* */
3228 : /* This is a special entry point to get the value of static flag */
3229 : /* OGRGeometry::bGenerate_DB2_V72_BYTE_ORDER. */
3230 : /************************************************************************/
3231 0 : int OGRGetGenerate_DB2_V72_BYTE_ORDER()
3232 : {
3233 0 : return OGRGeometry::bGenerate_DB2_V72_BYTE_ORDER;
3234 : }
3235 :
3236 : /************************************************************************/
3237 : /* createGEOSContext() */
3238 : /************************************************************************/
3239 :
3240 : /** Create a new GEOS context.
3241 : * @return a new GEOS context (to be freed with freeGEOSContext())
3242 : */
3243 75284 : GEOSContextHandle_t OGRGeometry::createGEOSContext()
3244 : {
3245 : #ifndef HAVE_GEOS
3246 : CPLError(CE_Failure, CPLE_NotSupported, "GEOS support not enabled.");
3247 : return nullptr;
3248 : #else
3249 75284 : return initGEOS_r(OGRGEOSWarningHandler, OGRGEOSErrorHandler);
3250 : #endif
3251 : }
3252 :
3253 : /************************************************************************/
3254 : /* freeGEOSContext() */
3255 : /************************************************************************/
3256 :
3257 : /** Destroy a GEOS context.
3258 : * @param hGEOSCtxt GEOS context
3259 : */
3260 76962 : void OGRGeometry::freeGEOSContext(
3261 : UNUSED_IF_NO_GEOS GEOSContextHandle_t hGEOSCtxt)
3262 : {
3263 : #ifdef HAVE_GEOS
3264 76962 : if (hGEOSCtxt != nullptr)
3265 : {
3266 76962 : finishGEOS_r(hGEOSCtxt);
3267 : }
3268 : #endif
3269 76963 : }
3270 :
3271 : #ifdef HAVE_GEOS
3272 :
3273 : /************************************************************************/
3274 : /* convertToGEOSGeom() */
3275 : /************************************************************************/
3276 :
3277 222601 : static GEOSGeom convertToGEOSGeom(GEOSContextHandle_t hGEOSCtxt,
3278 : OGRGeometry *poGeom)
3279 : {
3280 222601 : GEOSGeom hGeom = nullptr;
3281 222601 : const size_t nDataSize = poGeom->WkbSize();
3282 : unsigned char *pabyData =
3283 222598 : static_cast<unsigned char *>(CPLMalloc(nDataSize));
3284 : #if GEOS_VERSION_MAJOR > 3 || \
3285 : (GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR >= 12)
3286 : OGRwkbVariant eWkbVariant = wkbVariantIso;
3287 : #else
3288 222602 : OGRwkbVariant eWkbVariant = wkbVariantOldOgc;
3289 : #endif
3290 222602 : if (poGeom->exportToWkb(wkbNDR, pabyData, eWkbVariant) == OGRERR_NONE)
3291 221699 : hGeom = GEOSGeomFromWKB_buf_r(hGEOSCtxt, pabyData, nDataSize);
3292 222600 : CPLFree(pabyData);
3293 222603 : return hGeom;
3294 : }
3295 : #endif
3296 :
3297 : /************************************************************************/
3298 : /* exportToGEOS() */
3299 : /************************************************************************/
3300 :
3301 : /** Returns a GEOSGeom object corresponding to the geometry.
3302 : *
3303 : * @param hGEOSCtxt GEOS context
3304 : * @param bRemoveEmptyParts Whether empty parts of the geometry should be
3305 : * removed before exporting to GEOS (GDAL >= 3.10)
3306 : * @return a GEOSGeom object corresponding to the geometry (to be freed with
3307 : * GEOSGeom_destroy_r()), or NULL in case of error
3308 : */
3309 : GEOSGeom
3310 222699 : OGRGeometry::exportToGEOS(UNUSED_IF_NO_GEOS GEOSContextHandle_t hGEOSCtxt,
3311 : UNUSED_IF_NO_GEOS bool bRemoveEmptyParts) const
3312 :
3313 : {
3314 : #ifndef HAVE_GEOS
3315 :
3316 : CPLError(CE_Failure, CPLE_NotSupported, "GEOS support not enabled.");
3317 : return nullptr;
3318 :
3319 : #else
3320 :
3321 222699 : if (hGEOSCtxt == nullptr)
3322 0 : return nullptr;
3323 :
3324 222699 : const OGRwkbGeometryType eType = wkbFlatten(getGeometryType());
3325 : #if (GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR < 12)
3326 : // POINT EMPTY is exported to WKB as if it were POINT(0 0),
3327 : // so that particular case is necessary.
3328 222695 : if (eType == wkbPoint && IsEmpty())
3329 : {
3330 96 : return GEOSGeomFromWKT_r(hGEOSCtxt, "POINT EMPTY");
3331 : }
3332 : #endif
3333 :
3334 222599 : GEOSGeom hGeom = nullptr;
3335 :
3336 222599 : OGRGeometry *poLinearGeom = nullptr;
3337 222599 : if (hasCurveGeometry())
3338 : {
3339 828 : poLinearGeom = getLinearGeometry();
3340 828 : if (bRemoveEmptyParts)
3341 0 : poLinearGeom->removeEmptyParts();
3342 : #if (GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR < 12)
3343 : // GEOS < 3.12 doesn't support M dimension
3344 828 : if (poLinearGeom->IsMeasured())
3345 64 : poLinearGeom->setMeasured(FALSE);
3346 : #endif
3347 : }
3348 : else
3349 : {
3350 221773 : poLinearGeom = const_cast<OGRGeometry *>(this);
3351 : #if (GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR < 12)
3352 : // GEOS < 3.12 doesn't support M dimension
3353 221773 : if (IsMeasured())
3354 : {
3355 297 : poLinearGeom = clone();
3356 295 : if (bRemoveEmptyParts)
3357 0 : poLinearGeom->removeEmptyParts();
3358 295 : poLinearGeom->setMeasured(FALSE);
3359 : }
3360 : else
3361 : #endif
3362 221478 : if (bRemoveEmptyParts && hasEmptyParts())
3363 : {
3364 1 : poLinearGeom = clone();
3365 1 : poLinearGeom->removeEmptyParts();
3366 : }
3367 : }
3368 222600 : if (eType == wkbTriangle)
3369 : {
3370 85 : OGRPolygon oPolygon(*(poLinearGeom->toPolygon()));
3371 85 : hGeom = convertToGEOSGeom(hGEOSCtxt, &oPolygon);
3372 : }
3373 222515 : else if (eType == wkbPolyhedralSurface || eType == wkbTIN)
3374 : {
3375 1698 : OGRGeometry *poGC = OGRGeometryFactory::forceTo(
3376 848 : poLinearGeom->clone(),
3377 : OGR_GT_SetModifier(wkbGeometryCollection, poLinearGeom->Is3D(),
3378 : poLinearGeom->IsMeasured()),
3379 : nullptr);
3380 848 : hGeom = convertToGEOSGeom(hGEOSCtxt, poGC);
3381 848 : delete poGC;
3382 : }
3383 221665 : else if (eType == wkbGeometryCollection)
3384 : {
3385 122 : bool bCanConvertToMultiPoly = true;
3386 : // bool bMustConvertToMultiPoly = true;
3387 : const OGRGeometryCollection *poGC =
3388 122 : poLinearGeom->toGeometryCollection();
3389 270 : for (int iGeom = 0; iGeom < poGC->getNumGeometries(); iGeom++)
3390 : {
3391 : const OGRwkbGeometryType eSubGeomType =
3392 218 : wkbFlatten(poGC->getGeometryRef(iGeom)->getGeometryType());
3393 218 : if (eSubGeomType == wkbPolyhedralSurface || eSubGeomType == wkbTIN)
3394 : {
3395 : // bMustConvertToMultiPoly = true;
3396 : }
3397 133 : else if (eSubGeomType != wkbMultiPolygon &&
3398 : eSubGeomType != wkbPolygon)
3399 : {
3400 70 : bCanConvertToMultiPoly = false;
3401 70 : break;
3402 : }
3403 : }
3404 122 : if (bCanConvertToMultiPoly /* && bMustConvertToMultiPoly */)
3405 : {
3406 104 : OGRGeometry *poMultiPolygon = OGRGeometryFactory::forceTo(
3407 52 : poLinearGeom->clone(),
3408 : OGR_GT_SetModifier(wkbMultiPolygon, poLinearGeom->Is3D(),
3409 : poLinearGeom->IsMeasured()),
3410 : nullptr);
3411 52 : OGRGeometry *poGCDest = OGRGeometryFactory::forceTo(
3412 : poMultiPolygon,
3413 : OGR_GT_SetModifier(wkbGeometryCollection, poLinearGeom->Is3D(),
3414 : poLinearGeom->IsMeasured()),
3415 : nullptr);
3416 52 : hGeom = convertToGEOSGeom(hGEOSCtxt, poGCDest);
3417 52 : delete poGCDest;
3418 : }
3419 : else
3420 : {
3421 70 : hGeom = convertToGEOSGeom(hGEOSCtxt, poLinearGeom);
3422 : }
3423 : }
3424 : else
3425 : {
3426 221543 : hGeom = convertToGEOSGeom(hGEOSCtxt, poLinearGeom);
3427 : }
3428 :
3429 222595 : if (poLinearGeom != this)
3430 1124 : delete poLinearGeom;
3431 :
3432 222597 : return hGeom;
3433 :
3434 : #endif // HAVE_GEOS
3435 : }
3436 :
3437 : /************************************************************************/
3438 : /* hasCurveGeometry() */
3439 : /************************************************************************/
3440 :
3441 : /**
3442 : * \brief Returns if this geometry is or has curve geometry.
3443 : *
3444 : * Returns if a geometry is, contains or may contain a CIRCULARSTRING,
3445 : * COMPOUNDCURVE, CURVEPOLYGON, MULTICURVE or MULTISURFACE.
3446 : *
3447 : * If bLookForNonLinear is set to TRUE, it will be actually looked if
3448 : * the geometry or its subgeometries are or contain a non-linear
3449 : * geometry in them. In which case, if the method returns TRUE, it
3450 : * means that getLinearGeometry() would return an approximate version
3451 : * of the geometry. Otherwise, getLinearGeometry() would do a
3452 : * conversion, but with just converting container type, like
3453 : * COMPOUNDCURVE -> LINESTRING, MULTICURVE -> MULTILINESTRING or
3454 : * MULTISURFACE -> MULTIPOLYGON, resulting in a "loss-less"
3455 : * conversion.
3456 : *
3457 : * This method is the same as the C function OGR_G_HasCurveGeometry().
3458 : *
3459 : * @param bLookForNonLinear set it to TRUE to check if the geometry is
3460 : * or contains a CIRCULARSTRING.
3461 : *
3462 : * @return TRUE if this geometry is or has curve geometry.
3463 : *
3464 : * @since GDAL 2.0
3465 : */
3466 :
3467 273609 : OGRBoolean OGRGeometry::hasCurveGeometry(CPL_UNUSED int bLookForNonLinear) const
3468 : {
3469 273609 : return FALSE;
3470 : }
3471 :
3472 : /************************************************************************/
3473 : /* getLinearGeometry() */
3474 : /************************************************************************/
3475 :
3476 : /**
3477 : * \brief Return, possibly approximate, non-curve version of this geometry.
3478 : *
3479 : * Returns a geometry that has no CIRCULARSTRING, COMPOUNDCURVE, CURVEPOLYGON,
3480 : * MULTICURVE or MULTISURFACE in it, by approximating curve geometries.
3481 : *
3482 : * The ownership of the returned geometry belongs to the caller.
3483 : *
3484 : * The reverse method is OGRGeometry::getCurveGeometry().
3485 : *
3486 : * This method is the same as the C function OGR_G_GetLinearGeometry().
3487 : *
3488 : * @param dfMaxAngleStepSizeDegrees the largest step in degrees along the
3489 : * arc, zero to use the default setting.
3490 : * @param papszOptions options as a null-terminated list of strings.
3491 : * See OGRGeometryFactory::curveToLineString() for
3492 : * valid options.
3493 : *
3494 : * @return a new geometry to be freed by the caller, or NULL if an error occurs.
3495 : *
3496 : * @since GDAL 2.0
3497 : */
3498 :
3499 : OGRGeometry *
3500 79 : OGRGeometry::getLinearGeometry(CPL_UNUSED double dfMaxAngleStepSizeDegrees,
3501 : CPL_UNUSED const char *const *papszOptions) const
3502 : {
3503 79 : return clone();
3504 : }
3505 :
3506 : /************************************************************************/
3507 : /* getCurveGeometry() */
3508 : /************************************************************************/
3509 :
3510 : /**
3511 : * \brief Return curve version of this geometry.
3512 : *
3513 : * Returns a geometry that has possibly CIRCULARSTRING, COMPOUNDCURVE,
3514 : * CURVEPOLYGON, MULTICURVE or MULTISURFACE in it, by de-approximating
3515 : * curve geometries.
3516 : *
3517 : * If the geometry has no curve portion, the returned geometry will be a clone
3518 : * of it.
3519 : *
3520 : * The ownership of the returned geometry belongs to the caller.
3521 : *
3522 : * The reverse method is OGRGeometry::getLinearGeometry().
3523 : *
3524 : * This function is the same as C function OGR_G_GetCurveGeometry().
3525 : *
3526 : * @param papszOptions options as a null-terminated list of strings.
3527 : * Unused for now. Must be set to NULL.
3528 : *
3529 : * @return a new geometry to be freed by the caller, or NULL if an error occurs.
3530 : *
3531 : * @since GDAL 2.0
3532 : */
3533 :
3534 : OGRGeometry *
3535 5 : OGRGeometry::getCurveGeometry(CPL_UNUSED const char *const *papszOptions) const
3536 : {
3537 5 : return clone();
3538 : }
3539 :
3540 : /************************************************************************/
3541 : /* Distance() */
3542 : /************************************************************************/
3543 :
3544 : /**
3545 : * \brief Compute distance between two geometries.
3546 : *
3547 : * Returns the shortest distance between the two geometries. The distance is
3548 : * expressed into the same unit as the coordinates of the geometries.
3549 : *
3550 : * This method is the same as the C function OGR_G_Distance().
3551 : *
3552 : * This method is built on the GEOS library, check it for the definition
3553 : * of the geometry operation.
3554 : * If OGR is built without the GEOS library, this method will always fail,
3555 : * issuing a CPLE_NotSupported error.
3556 : *
3557 : * @param poOtherGeom the other geometry to compare against.
3558 : *
3559 : * @return the distance between the geometries or -1 if an error occurs.
3560 : */
3561 :
3562 24 : double OGRGeometry::Distance(const OGRGeometry *poOtherGeom) const
3563 :
3564 : {
3565 24 : if (nullptr == poOtherGeom)
3566 : {
3567 0 : CPLDebug("OGR",
3568 : "OGRGeometry::Distance called with NULL geometry pointer");
3569 0 : return -1.0;
3570 : }
3571 :
3572 24 : if (IsSFCGALCompatible() || poOtherGeom->IsSFCGALCompatible())
3573 : {
3574 : #ifndef HAVE_SFCGAL
3575 :
3576 0 : CPLError(CE_Failure, CPLE_NotSupported, "SFCGAL support not enabled.");
3577 0 : return -1.0;
3578 :
3579 : #else
3580 :
3581 : sfcgal_geometry_t *poThis = OGRGeometry::OGRexportToSFCGAL(this);
3582 : if (poThis == nullptr)
3583 : return -1.0;
3584 :
3585 : sfcgal_geometry_t *poOther =
3586 : OGRGeometry::OGRexportToSFCGAL(poOtherGeom);
3587 : if (poOther == nullptr)
3588 : {
3589 : sfcgal_geometry_delete(poThis);
3590 : return -1.0;
3591 : }
3592 :
3593 : const double dfDistance = sfcgal_geometry_distance(poThis, poOther);
3594 :
3595 : sfcgal_geometry_delete(poThis);
3596 : sfcgal_geometry_delete(poOther);
3597 :
3598 : return dfDistance > 0.0 ? dfDistance : -1.0;
3599 :
3600 : #endif
3601 : }
3602 :
3603 : else
3604 : {
3605 : #ifndef HAVE_GEOS
3606 :
3607 : CPLError(CE_Failure, CPLE_NotSupported, "GEOS support not enabled.");
3608 : return -1.0;
3609 :
3610 : #else
3611 :
3612 24 : GEOSContextHandle_t hGEOSCtxt = createGEOSContext();
3613 : // GEOSGeom is a pointer
3614 24 : GEOSGeom hOther = poOtherGeom->exportToGEOS(hGEOSCtxt);
3615 24 : GEOSGeom hThis = exportToGEOS(hGEOSCtxt);
3616 :
3617 24 : int bIsErr = 0;
3618 24 : double dfDistance = 0.0;
3619 :
3620 24 : if (hThis != nullptr && hOther != nullptr)
3621 : {
3622 24 : bIsErr = GEOSDistance_r(hGEOSCtxt, hThis, hOther, &dfDistance);
3623 : }
3624 :
3625 24 : GEOSGeom_destroy_r(hGEOSCtxt, hThis);
3626 24 : GEOSGeom_destroy_r(hGEOSCtxt, hOther);
3627 24 : freeGEOSContext(hGEOSCtxt);
3628 :
3629 24 : if (bIsErr > 0)
3630 : {
3631 24 : return dfDistance;
3632 : }
3633 :
3634 : /* Calculations error */
3635 0 : return -1.0;
3636 :
3637 : #endif /* HAVE_GEOS */
3638 : }
3639 : }
3640 :
3641 : /************************************************************************/
3642 : /* OGR_G_Distance() */
3643 : /************************************************************************/
3644 : /**
3645 : * \brief Compute distance between two geometries.
3646 : *
3647 : * Returns the shortest distance between the two geometries. The distance is
3648 : * expressed into the same unit as the coordinates of the geometries.
3649 : *
3650 : * This function is the same as the C++ method OGRGeometry::Distance().
3651 : *
3652 : * This function is built on the GEOS library, check it for the definition
3653 : * of the geometry operation.
3654 : * If OGR is built without the GEOS library, this function will always fail,
3655 : * issuing a CPLE_NotSupported error.
3656 : *
3657 : * @param hFirst the first geometry to compare against.
3658 : * @param hOther the other geometry to compare against.
3659 : *
3660 : * @return the distance between the geometries or -1 if an error occurs.
3661 : */
3662 :
3663 1 : double OGR_G_Distance(OGRGeometryH hFirst, OGRGeometryH hOther)
3664 :
3665 : {
3666 1 : VALIDATE_POINTER1(hFirst, "OGR_G_Distance", 0.0);
3667 :
3668 2 : return OGRGeometry::FromHandle(hFirst)->Distance(
3669 1 : OGRGeometry::FromHandle(hOther));
3670 : }
3671 :
3672 : /************************************************************************/
3673 : /* Distance3D() */
3674 : /************************************************************************/
3675 :
3676 : /**
3677 : * \brief Returns the 3D distance between two geometries
3678 : *
3679 : * The distance is expressed into the same unit as the coordinates of the
3680 : * geometries.
3681 : *
3682 : * This method is built on the SFCGAL library, check it for the definition
3683 : * of the geometry operation.
3684 : * If OGR is built without the SFCGAL library, this method will always return
3685 : * -1.0
3686 : *
3687 : * This function is the same as the C function OGR_G_Distance3D().
3688 : *
3689 : * @return distance between the two geometries
3690 : * @since GDAL 2.2
3691 : */
3692 :
3693 1 : double OGRGeometry::Distance3D(
3694 : UNUSED_IF_NO_SFCGAL const OGRGeometry *poOtherGeom) const
3695 : {
3696 1 : if (poOtherGeom == nullptr)
3697 : {
3698 0 : CPLDebug("OGR",
3699 : "OGRTriangle::Distance3D called with NULL geometry pointer");
3700 0 : return -1.0;
3701 : }
3702 :
3703 1 : if (!(poOtherGeom->Is3D() && Is3D()))
3704 : {
3705 0 : CPLDebug("OGR", "OGRGeometry::Distance3D called with two dimensional "
3706 : "geometry(geometries)");
3707 0 : return -1.0;
3708 : }
3709 :
3710 : #ifndef HAVE_SFCGAL
3711 :
3712 1 : CPLError(CE_Failure, CPLE_NotSupported, "SFCGAL support not enabled.");
3713 1 : return -1.0;
3714 :
3715 : #else
3716 :
3717 : sfcgal_init();
3718 : sfcgal_geometry_t *poThis = OGRGeometry::OGRexportToSFCGAL(this);
3719 : if (poThis == nullptr)
3720 : return -1.0;
3721 :
3722 : sfcgal_geometry_t *poOther = OGRGeometry::OGRexportToSFCGAL(poOtherGeom);
3723 : if (poOther == nullptr)
3724 : {
3725 : sfcgal_geometry_delete(poThis);
3726 : return -1.0;
3727 : }
3728 :
3729 : const double dfDistance = sfcgal_geometry_distance_3d(poThis, poOther);
3730 :
3731 : sfcgal_geometry_delete(poThis);
3732 : sfcgal_geometry_delete(poOther);
3733 :
3734 : return dfDistance > 0 ? dfDistance : -1.0;
3735 :
3736 : #endif
3737 : }
3738 :
3739 : /************************************************************************/
3740 : /* OGR_G_Distance3D() */
3741 : /************************************************************************/
3742 : /**
3743 : * \brief Returns the 3D distance between two geometries
3744 : *
3745 : * The distance is expressed into the same unit as the coordinates of the
3746 : * geometries.
3747 : *
3748 : * This method is built on the SFCGAL library, check it for the definition
3749 : * of the geometry operation.
3750 : * If OGR is built without the SFCGAL library, this method will always return
3751 : * -1.0
3752 : *
3753 : * This function is the same as the C++ method OGRGeometry::Distance3D().
3754 : *
3755 : * @param hFirst the first geometry to compare against.
3756 : * @param hOther the other geometry to compare against.
3757 : * @return distance between the two geometries
3758 : * @since GDAL 2.2
3759 : *
3760 : * @return the distance between the geometries or -1 if an error occurs.
3761 : */
3762 :
3763 1 : double OGR_G_Distance3D(OGRGeometryH hFirst, OGRGeometryH hOther)
3764 :
3765 : {
3766 1 : VALIDATE_POINTER1(hFirst, "OGR_G_Distance3D", 0.0);
3767 :
3768 2 : return OGRGeometry::FromHandle(hFirst)->Distance3D(
3769 1 : OGRGeometry::FromHandle(hOther));
3770 : }
3771 :
3772 : /************************************************************************/
3773 : /* OGRGeometryRebuildCurves() */
3774 : /************************************************************************/
3775 :
3776 : #ifdef HAVE_GEOS
3777 1923 : static OGRGeometry *OGRGeometryRebuildCurves(const OGRGeometry *poGeom,
3778 : const OGRGeometry *poOtherGeom,
3779 : OGRGeometry *poOGRProduct)
3780 : {
3781 3844 : if (poOGRProduct != nullptr &&
3782 3800 : wkbFlatten(poOGRProduct->getGeometryType()) != wkbPoint &&
3783 1875 : (poGeom->hasCurveGeometry(true) ||
3784 1008 : (poOtherGeom && poOtherGeom->hasCurveGeometry(true))))
3785 : {
3786 8 : OGRGeometry *poCurveGeom = poOGRProduct->getCurveGeometry();
3787 8 : delete poOGRProduct;
3788 8 : return poCurveGeom;
3789 : }
3790 1915 : return poOGRProduct;
3791 : }
3792 :
3793 : /************************************************************************/
3794 : /* BuildGeometryFromGEOS() */
3795 : /************************************************************************/
3796 :
3797 1840 : static OGRGeometry *BuildGeometryFromGEOS(GEOSContextHandle_t hGEOSCtxt,
3798 : GEOSGeom hGeosProduct,
3799 : const OGRGeometry *poSelf,
3800 : const OGRGeometry *poOtherGeom)
3801 : {
3802 1840 : OGRGeometry *poOGRProduct = nullptr;
3803 1840 : if (hGeosProduct != nullptr)
3804 : {
3805 : poOGRProduct =
3806 1839 : OGRGeometryFactory::createFromGEOS(hGEOSCtxt, hGeosProduct);
3807 1838 : if (poOGRProduct != nullptr &&
3808 3749 : poSelf->getSpatialReference() != nullptr &&
3809 72 : (poOtherGeom == nullptr ||
3810 72 : (poOtherGeom->getSpatialReference() != nullptr &&
3811 3 : poOtherGeom->getSpatialReference()->IsSame(
3812 : poSelf->getSpatialReference()))))
3813 : {
3814 6 : poOGRProduct->assignSpatialReference(poSelf->getSpatialReference());
3815 : }
3816 : poOGRProduct =
3817 1839 : OGRGeometryRebuildCurves(poSelf, poOtherGeom, poOGRProduct);
3818 1839 : GEOSGeom_destroy_r(hGEOSCtxt, hGeosProduct);
3819 : }
3820 1840 : return poOGRProduct;
3821 : }
3822 :
3823 : /************************************************************************/
3824 : /* BuildGeometryFromTwoGeoms() */
3825 : /************************************************************************/
3826 :
3827 1056 : static OGRGeometry *BuildGeometryFromTwoGeoms(
3828 : const OGRGeometry *poSelf, const OGRGeometry *poOtherGeom,
3829 : GEOSGeometry *(*pfnGEOSFunction_r)(GEOSContextHandle_t,
3830 : const GEOSGeometry *,
3831 : const GEOSGeometry *))
3832 : {
3833 1056 : OGRGeometry *poOGRProduct = nullptr;
3834 :
3835 1056 : GEOSContextHandle_t hGEOSCtxt = poSelf->createGEOSContext();
3836 1055 : GEOSGeom hThisGeosGeom = poSelf->exportToGEOS(hGEOSCtxt);
3837 1055 : GEOSGeom hOtherGeosGeom = poOtherGeom->exportToGEOS(hGEOSCtxt);
3838 1056 : if (hThisGeosGeom != nullptr && hOtherGeosGeom != nullptr)
3839 : {
3840 : GEOSGeom hGeosProduct =
3841 1054 : pfnGEOSFunction_r(hGEOSCtxt, hThisGeosGeom, hOtherGeosGeom);
3842 :
3843 : poOGRProduct =
3844 1054 : BuildGeometryFromGEOS(hGEOSCtxt, hGeosProduct, poSelf, poOtherGeom);
3845 : }
3846 1057 : GEOSGeom_destroy_r(hGEOSCtxt, hThisGeosGeom);
3847 1056 : GEOSGeom_destroy_r(hGEOSCtxt, hOtherGeosGeom);
3848 1055 : poSelf->freeGEOSContext(hGEOSCtxt);
3849 :
3850 1055 : return poOGRProduct;
3851 : }
3852 :
3853 : /************************************************************************/
3854 : /* OGRGEOSBooleanPredicate() */
3855 : /************************************************************************/
3856 :
3857 21281 : static OGRBoolean OGRGEOSBooleanPredicate(
3858 : const OGRGeometry *poSelf, const OGRGeometry *poOtherGeom,
3859 : char (*pfnGEOSFunction_r)(GEOSContextHandle_t, const GEOSGeometry *,
3860 : const GEOSGeometry *))
3861 : {
3862 21281 : OGRBoolean bResult = FALSE;
3863 :
3864 21281 : GEOSContextHandle_t hGEOSCtxt = poSelf->createGEOSContext();
3865 21281 : GEOSGeom hThisGeosGeom = poSelf->exportToGEOS(hGEOSCtxt);
3866 21281 : GEOSGeom hOtherGeosGeom = poOtherGeom->exportToGEOS(hGEOSCtxt);
3867 21281 : if (hThisGeosGeom != nullptr && hOtherGeosGeom != nullptr)
3868 : {
3869 20783 : bResult = pfnGEOSFunction_r(hGEOSCtxt, hThisGeosGeom, hOtherGeosGeom);
3870 : }
3871 21281 : GEOSGeom_destroy_r(hGEOSCtxt, hThisGeosGeom);
3872 21281 : GEOSGeom_destroy_r(hGEOSCtxt, hOtherGeosGeom);
3873 21281 : poSelf->freeGEOSContext(hGEOSCtxt);
3874 :
3875 21281 : return bResult;
3876 : }
3877 :
3878 : #endif // HAVE_GEOS
3879 :
3880 : /************************************************************************/
3881 : /* MakeValid() */
3882 : /************************************************************************/
3883 :
3884 : /**
3885 : * \brief Attempts to make an invalid geometry valid without losing vertices.
3886 : *
3887 : * Already-valid geometries are cloned without further intervention
3888 : * for default MODE=LINEWORK. Already-valid geometries with MODE=STRUCTURE
3889 : * may be subject to non-significant transformations, such as duplicated point
3890 : * removal, change in ring winding order, etc. (before GDAL 3.10, single-part
3891 : * geometry collections could be returned a single geometry. GDAL 3.10
3892 : * returns the same type of geometry).
3893 : *
3894 : * Running OGRGeometryFactory::removeLowerDimensionSubGeoms() as a
3895 : * post-processing step is often desired.
3896 : *
3897 : * This method is the same as the C function OGR_G_MakeValid().
3898 : *
3899 : * This function is built on the GEOS >= 3.8 library, check it for the
3900 : * definition of the geometry operation. If OGR is built without the GEOS >= 3.8
3901 : * library, this function will return a clone of the input geometry if it is
3902 : * valid, or NULL if it is invalid
3903 : *
3904 : * @param papszOptions NULL terminated list of options, or NULL. The following
3905 : * options are available:
3906 : * <ul>
3907 : * <li>METHOD=LINEWORK/STRUCTURE.
3908 : * LINEWORK is the default method, which combines all rings into a set of
3909 : * noded lines and then extracts valid polygons from that linework.
3910 : * The STRUCTURE method (requires GEOS >= 3.10 and GDAL >= 3.4) first makes
3911 : * all rings valid, then merges shells and
3912 : * subtracts holes from shells to generate valid result. Assumes that
3913 : * holes and shells are correctly categorized.</li>
3914 : * <li>KEEP_COLLAPSED=YES/NO. Only for METHOD=STRUCTURE.
3915 : * NO (default): collapses are converted to empty geometries
3916 : * YES: collapses are converted to a valid geometry of lower dimension.</li>
3917 : * </ul>
3918 : * @return a new geometry to be freed by the caller, or NULL if an error occurs.
3919 : *
3920 : * @since GDAL 3.0
3921 : */
3922 86 : OGRGeometry *OGRGeometry::MakeValid(CSLConstList papszOptions) const
3923 : {
3924 : (void)papszOptions;
3925 : #ifndef HAVE_GEOS
3926 : if (IsValid())
3927 : return clone();
3928 :
3929 : CPLError(CE_Failure, CPLE_NotSupported, "GEOS support not enabled.");
3930 : return nullptr;
3931 : #else
3932 86 : if (IsSFCGALCompatible())
3933 : {
3934 0 : if (IsValid())
3935 0 : return clone();
3936 : }
3937 86 : else if (wkbFlatten(getGeometryType()) == wkbCurvePolygon)
3938 : {
3939 2 : GEOSContextHandle_t hGEOSCtxt = initGEOS_r(nullptr, nullptr);
3940 2 : OGRBoolean bIsValid = FALSE;
3941 2 : GEOSGeom hGeosGeom = exportToGEOS(hGEOSCtxt);
3942 2 : if (hGeosGeom)
3943 : {
3944 2 : bIsValid = GEOSisValid_r(hGEOSCtxt, hGeosGeom);
3945 2 : GEOSGeom_destroy_r(hGEOSCtxt, hGeosGeom);
3946 : }
3947 2 : freeGEOSContext(hGEOSCtxt);
3948 2 : if (bIsValid)
3949 1 : return clone();
3950 : }
3951 :
3952 84 : const bool bStructureMethod = EQUAL(
3953 : CSLFetchNameValueDef(papszOptions, "METHOD", "LINEWORK"), "STRUCTURE");
3954 85 : CPL_IGNORE_RET_VAL(bStructureMethod);
3955 : #if !(GEOS_VERSION_MAJOR > 3 || \
3956 : (GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR >= 10))
3957 : if (bStructureMethod)
3958 : {
3959 : CPLError(CE_Failure, CPLE_NotSupported,
3960 : "GEOS 3.10 or later needed for METHOD=STRUCTURE.");
3961 : return nullptr;
3962 : }
3963 : #endif
3964 :
3965 84 : OGRGeometry *poOGRProduct = nullptr;
3966 :
3967 84 : GEOSContextHandle_t hGEOSCtxt = createGEOSContext();
3968 85 : GEOSGeom hGeosGeom = exportToGEOS(hGEOSCtxt);
3969 85 : if (hGeosGeom != nullptr)
3970 : {
3971 : GEOSGeom hGEOSRet;
3972 : #if GEOS_VERSION_MAJOR > 3 || \
3973 : (GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR >= 10)
3974 83 : if (bStructureMethod)
3975 : {
3976 : GEOSMakeValidParams *params =
3977 5 : GEOSMakeValidParams_create_r(hGEOSCtxt);
3978 5 : CPLAssert(params);
3979 5 : GEOSMakeValidParams_setMethod_r(hGEOSCtxt, params,
3980 : GEOS_MAKE_VALID_STRUCTURE);
3981 5 : GEOSMakeValidParams_setKeepCollapsed_r(
3982 : hGEOSCtxt, params,
3983 5 : CPLFetchBool(papszOptions, "KEEP_COLLAPSED", false));
3984 5 : hGEOSRet = GEOSMakeValidWithParams_r(hGEOSCtxt, hGeosGeom, params);
3985 5 : GEOSMakeValidParams_destroy_r(hGEOSCtxt, params);
3986 : }
3987 : else
3988 : #endif
3989 : {
3990 78 : hGEOSRet = GEOSMakeValid_r(hGEOSCtxt, hGeosGeom);
3991 : }
3992 84 : GEOSGeom_destroy_r(hGEOSCtxt, hGeosGeom);
3993 :
3994 84 : if (hGEOSRet != nullptr)
3995 : {
3996 : poOGRProduct =
3997 84 : OGRGeometryFactory::createFromGEOS(hGEOSCtxt, hGEOSRet);
3998 84 : if (poOGRProduct != nullptr && getSpatialReference() != nullptr)
3999 5 : poOGRProduct->assignSpatialReference(getSpatialReference());
4000 : poOGRProduct =
4001 84 : OGRGeometryRebuildCurves(this, nullptr, poOGRProduct);
4002 84 : GEOSGeom_destroy_r(hGEOSCtxt, hGEOSRet);
4003 :
4004 : #if GEOS_VERSION_MAJOR > 3 || \
4005 : (GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR >= 10)
4006 : // METHOD=STRUCTURE is not guaranteed to return a multiple geometry
4007 : // if the input is a multiple geometry
4008 84 : if (poOGRProduct && bStructureMethod &&
4009 172 : OGR_GT_IsSubClassOf(getGeometryType(), wkbGeometryCollection) &&
4010 4 : !OGR_GT_IsSubClassOf(poOGRProduct->getGeometryType(),
4011 : wkbGeometryCollection))
4012 : {
4013 3 : poOGRProduct = OGRGeometryFactory::forceTo(poOGRProduct,
4014 3 : getGeometryType());
4015 : }
4016 : #endif
4017 : }
4018 : }
4019 86 : freeGEOSContext(hGEOSCtxt);
4020 :
4021 85 : return poOGRProduct;
4022 : #endif
4023 : }
4024 :
4025 : /************************************************************************/
4026 : /* OGR_G_MakeValid() */
4027 : /************************************************************************/
4028 :
4029 : /**
4030 : * \brief Attempts to make an invalid geometry valid without losing vertices.
4031 : *
4032 : * Already-valid geometries are cloned without further intervention.
4033 : *
4034 : * This function is the same as the C++ method OGRGeometry::MakeValid().
4035 : *
4036 : * This function is built on the GEOS >= 3.8 library, check it for the
4037 : * definition of the geometry operation. If OGR is built without the GEOS >= 3.8
4038 : * library, this function will return a clone of the input geometry if it is
4039 : * valid, or NULL if it is invalid
4040 : *
4041 : * @param hGeom The Geometry to make valid.
4042 : *
4043 : * @return a new geometry to be freed by the caller with OGR_G_DestroyGeometry,
4044 : * or NULL if an error occurs.
4045 : *
4046 : * @since GDAL 3.0
4047 : */
4048 :
4049 0 : OGRGeometryH OGR_G_MakeValid(OGRGeometryH hGeom)
4050 :
4051 : {
4052 0 : VALIDATE_POINTER1(hGeom, "OGR_G_MakeValid", nullptr);
4053 :
4054 0 : return OGRGeometry::ToHandle(OGRGeometry::FromHandle(hGeom)->MakeValid());
4055 : }
4056 :
4057 : /************************************************************************/
4058 : /* OGR_G_MakeValidEx() */
4059 : /************************************************************************/
4060 :
4061 : /**
4062 : * \brief Attempts to make an invalid geometry valid without losing vertices.
4063 : *
4064 : * Already-valid geometries are cloned without further intervention.
4065 : *
4066 : * This function is the same as the C++ method OGRGeometry::MakeValid().
4067 : *
4068 : * See documentation of that method for possible options.
4069 : *
4070 : * @param hGeom The Geometry to make valid.
4071 : * @param papszOptions Options.
4072 : *
4073 : * @return a new geometry to be freed by the caller with OGR_G_DestroyGeometry,
4074 : * or NULL if an error occurs.
4075 : *
4076 : * @since GDAL 3.4
4077 : */
4078 :
4079 11 : OGRGeometryH OGR_G_MakeValidEx(OGRGeometryH hGeom, CSLConstList papszOptions)
4080 :
4081 : {
4082 11 : VALIDATE_POINTER1(hGeom, "OGR_G_MakeValidEx", nullptr);
4083 :
4084 11 : return OGRGeometry::ToHandle(
4085 22 : OGRGeometry::FromHandle(hGeom)->MakeValid(papszOptions));
4086 : }
4087 :
4088 : /************************************************************************/
4089 : /* Normalize() */
4090 : /************************************************************************/
4091 :
4092 : /**
4093 : * \brief Attempts to bring geometry into normalized/canonical form.
4094 : *
4095 : * This method is the same as the C function OGR_G_Normalize().
4096 : *
4097 : * This function is built on the GEOS library; check it for the definition
4098 : * of the geometry operation.
4099 : * If OGR is built without the GEOS library, this function will always fail,
4100 : * issuing a CPLE_NotSupported error.
4101 : *
4102 : * @return a new geometry to be freed by the caller, or NULL if an error occurs.
4103 : *
4104 : * @since GDAL 3.3
4105 : */
4106 35 : OGRGeometry *OGRGeometry::Normalize() const
4107 : {
4108 : #ifndef HAVE_GEOS
4109 : CPLError(CE_Failure, CPLE_NotSupported, "GEOS support not enabled.");
4110 : return nullptr;
4111 : #else
4112 35 : OGRGeometry *poOGRProduct = nullptr;
4113 :
4114 35 : GEOSContextHandle_t hGEOSCtxt = createGEOSContext();
4115 35 : GEOSGeom hGeosGeom = exportToGEOS(hGEOSCtxt);
4116 35 : if (hGeosGeom != nullptr)
4117 : {
4118 :
4119 35 : int hGEOSRet = GEOSNormalize_r(hGEOSCtxt, hGeosGeom);
4120 :
4121 35 : if (hGEOSRet == 0)
4122 : {
4123 : poOGRProduct =
4124 35 : BuildGeometryFromGEOS(hGEOSCtxt, hGeosGeom, this, nullptr);
4125 : }
4126 : else
4127 : {
4128 0 : GEOSGeom_destroy_r(hGEOSCtxt, hGeosGeom);
4129 : }
4130 : }
4131 35 : freeGEOSContext(hGEOSCtxt);
4132 :
4133 35 : return poOGRProduct;
4134 : #endif
4135 : }
4136 :
4137 : /************************************************************************/
4138 : /* OGR_G_Normalize() */
4139 : /************************************************************************/
4140 :
4141 : /**
4142 : * \brief Attempts to bring geometry into normalized/canonical form.
4143 : *
4144 : * This function is the same as the C++ method OGRGeometry::Normalize().
4145 : *
4146 : * This function is built on the GEOS library; check it for the definition
4147 : * of the geometry operation.
4148 : * If OGR is built without the GEOS library, this function will always fail,
4149 : * issuing a CPLE_NotSupported error.
4150 : * @param hGeom The Geometry to normalize.
4151 : *
4152 : * @return a new geometry to be freed by the caller with OGR_G_DestroyGeometry,
4153 : * or NULL if an error occurs.
4154 : *
4155 : * @since GDAL 3.3
4156 : */
4157 :
4158 5 : OGRGeometryH OGR_G_Normalize(OGRGeometryH hGeom)
4159 :
4160 : {
4161 5 : VALIDATE_POINTER1(hGeom, "OGR_G_Normalize", nullptr);
4162 :
4163 5 : return OGRGeometry::ToHandle(OGRGeometry::FromHandle(hGeom)->Normalize());
4164 : }
4165 :
4166 : /************************************************************************/
4167 : /* ConvexHull() */
4168 : /************************************************************************/
4169 :
4170 : /**
4171 : * \brief Compute convex hull.
4172 : *
4173 : * A new geometry object is created and returned containing the convex
4174 : * hull of the geometry on which the method is invoked.
4175 : *
4176 : * This method is the same as the C function OGR_G_ConvexHull().
4177 : *
4178 : * This method is built on the GEOS library, check it for the definition
4179 : * of the geometry operation.
4180 : * If OGR is built without the GEOS library, this method will always fail,
4181 : * issuing a CPLE_NotSupported error.
4182 : *
4183 : * @return a new geometry to be freed by the caller, or NULL if an error occurs.
4184 : */
4185 :
4186 2 : OGRGeometry *OGRGeometry::ConvexHull() const
4187 :
4188 : {
4189 2 : if (IsSFCGALCompatible())
4190 : {
4191 : #ifndef HAVE_SFCGAL
4192 :
4193 0 : CPLError(CE_Failure, CPLE_NotSupported, "SFCGAL support not enabled.");
4194 0 : return nullptr;
4195 :
4196 : #else
4197 :
4198 : sfcgal_geometry_t *poThis = OGRGeometry::OGRexportToSFCGAL(this);
4199 : if (poThis == nullptr)
4200 : return nullptr;
4201 :
4202 : sfcgal_geometry_t *poRes = sfcgal_geometry_convexhull_3d(poThis);
4203 : OGRGeometry *h_prodGeom = SFCGALexportToOGR(poRes);
4204 : if (h_prodGeom)
4205 : h_prodGeom->assignSpatialReference(getSpatialReference());
4206 :
4207 : sfcgal_geometry_delete(poThis);
4208 : sfcgal_geometry_delete(poRes);
4209 :
4210 : return h_prodGeom;
4211 :
4212 : #endif
4213 : }
4214 :
4215 : else
4216 : {
4217 : #ifndef HAVE_GEOS
4218 :
4219 : CPLError(CE_Failure, CPLE_NotSupported, "GEOS support not enabled.");
4220 : return nullptr;
4221 :
4222 : #else
4223 :
4224 2 : OGRGeometry *poOGRProduct = nullptr;
4225 :
4226 2 : GEOSContextHandle_t hGEOSCtxt = createGEOSContext();
4227 2 : GEOSGeom hGeosGeom = exportToGEOS(hGEOSCtxt);
4228 2 : if (hGeosGeom != nullptr)
4229 : {
4230 2 : GEOSGeom hGeosHull = GEOSConvexHull_r(hGEOSCtxt, hGeosGeom);
4231 2 : GEOSGeom_destroy_r(hGEOSCtxt, hGeosGeom);
4232 :
4233 : poOGRProduct =
4234 2 : BuildGeometryFromGEOS(hGEOSCtxt, hGeosHull, this, nullptr);
4235 : }
4236 2 : freeGEOSContext(hGEOSCtxt);
4237 :
4238 2 : return poOGRProduct;
4239 :
4240 : #endif /* HAVE_GEOS */
4241 : }
4242 : }
4243 :
4244 : /************************************************************************/
4245 : /* OGR_G_ConvexHull() */
4246 : /************************************************************************/
4247 : /**
4248 : * \brief Compute convex hull.
4249 : *
4250 : * A new geometry object is created and returned containing the convex
4251 : * hull of the geometry on which the method is invoked.
4252 : *
4253 : * This function is the same as the C++ method OGRGeometry::ConvexHull().
4254 : *
4255 : * This function is built on the GEOS library, check it for the definition
4256 : * of the geometry operation.
4257 : * If OGR is built without the GEOS library, this function will always fail,
4258 : * issuing a CPLE_NotSupported error.
4259 : *
4260 : * @param hTarget The Geometry to calculate the convex hull of.
4261 : *
4262 : * @return a new geometry to be freed by the caller with OGR_G_DestroyGeometry,
4263 : * or NULL if an error occurs.
4264 : */
4265 :
4266 1 : OGRGeometryH OGR_G_ConvexHull(OGRGeometryH hTarget)
4267 :
4268 : {
4269 1 : VALIDATE_POINTER1(hTarget, "OGR_G_ConvexHull", nullptr);
4270 :
4271 1 : return OGRGeometry::ToHandle(
4272 2 : OGRGeometry::FromHandle(hTarget)->ConvexHull());
4273 : }
4274 :
4275 : /************************************************************************/
4276 : /* ConcaveHull() */
4277 : /************************************************************************/
4278 :
4279 : /**
4280 : * \brief Compute "concave hull" of a geometry.
4281 : *
4282 : * The concave hull is fully contained within the convex hull and also
4283 : * contains all the points of the input, but in a smaller area.
4284 : * The area ratio is the ratio of the area of the convex hull and the concave
4285 : * hull. Frequently used to convert a multi-point into a polygonal area.
4286 : * that contains all the points in the input Geometry.
4287 : *
4288 : * A new geometry object is created and returned containing the concave
4289 : * hull of the geometry on which the method is invoked.
4290 : *
4291 : * This method is the same as the C function OGR_G_ConcaveHull().
4292 : *
4293 : * This method is built on the GEOS >= 3.11 library
4294 : * If OGR is built without the GEOS >= 3.11 librray, this method will always
4295 : * fail, issuing a CPLE_NotSupported error.
4296 : *
4297 : * @param dfRatio Ratio of the area of the convex hull and the concave hull.
4298 : * @param bAllowHoles Whether holes are allowed.
4299 : *
4300 : * @return a new geometry to be freed by the caller, or NULL if an error occurs.
4301 : *
4302 : * @since GDAL 3.6
4303 : */
4304 :
4305 2 : OGRGeometry *OGRGeometry::ConcaveHull(double dfRatio, bool bAllowHoles) const
4306 : {
4307 : #ifndef HAVE_GEOS
4308 : (void)dfRatio;
4309 : (void)bAllowHoles;
4310 : CPLError(CE_Failure, CPLE_NotSupported, "GEOS support not enabled.");
4311 : return nullptr;
4312 : #elif GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR < 11
4313 : (void)dfRatio;
4314 : (void)bAllowHoles;
4315 : CPLError(CE_Failure, CPLE_NotSupported,
4316 : "GEOS 3.11 or later needed for ConcaveHull.");
4317 : return nullptr;
4318 : #else
4319 2 : OGRGeometry *poOGRProduct = nullptr;
4320 :
4321 2 : GEOSContextHandle_t hGEOSCtxt = createGEOSContext();
4322 2 : GEOSGeom hGeosGeom = exportToGEOS(hGEOSCtxt);
4323 2 : if (hGeosGeom != nullptr)
4324 : {
4325 : GEOSGeom hGeosHull =
4326 2 : GEOSConcaveHull_r(hGEOSCtxt, hGeosGeom, dfRatio, bAllowHoles);
4327 2 : GEOSGeom_destroy_r(hGEOSCtxt, hGeosGeom);
4328 :
4329 : poOGRProduct =
4330 2 : BuildGeometryFromGEOS(hGEOSCtxt, hGeosHull, this, nullptr);
4331 : }
4332 2 : freeGEOSContext(hGEOSCtxt);
4333 :
4334 2 : return poOGRProduct;
4335 : #endif /* HAVE_GEOS */
4336 : }
4337 :
4338 : /************************************************************************/
4339 : /* OGR_G_ConcaveHull() */
4340 : /************************************************************************/
4341 : /**
4342 : * \brief Compute "concave hull" of a geometry.
4343 : *
4344 : * The concave hull is fully contained within the convex hull and also
4345 : * contains all the points of the input, but in a smaller area.
4346 : * The area ratio is the ratio of the area of the convex hull and the concave
4347 : * hull. Frequently used to convert a multi-point into a polygonal area.
4348 : * that contains all the points in the input Geometry.
4349 : *
4350 : * A new geometry object is created and returned containing the convex
4351 : * hull of the geometry on which the function is invoked.
4352 : *
4353 : * This function is the same as the C++ method OGRGeometry::ConcaveHull().
4354 : *
4355 : * This function is built on the GEOS >= 3.11 library
4356 : * If OGR is built without the GEOS >= 3.11 librray, this function will always
4357 : * fail, issuing a CPLE_NotSupported error.
4358 : *
4359 : * @param hTarget The Geometry to calculate the concave hull of.
4360 : * @param dfRatio Ratio of the area of the convex hull and the concave hull.
4361 : * @param bAllowHoles Whether holes are allowed.
4362 : *
4363 : * @return a new geometry to be freed by the caller with OGR_G_DestroyGeometry,
4364 : * or NULL if an error occurs.
4365 : *
4366 : * @since GDAL 3.6
4367 : */
4368 :
4369 2 : OGRGeometryH OGR_G_ConcaveHull(OGRGeometryH hTarget, double dfRatio,
4370 : bool bAllowHoles)
4371 :
4372 : {
4373 2 : VALIDATE_POINTER1(hTarget, "OGR_G_ConcaveHull", nullptr);
4374 :
4375 2 : return OGRGeometry::ToHandle(
4376 4 : OGRGeometry::FromHandle(hTarget)->ConcaveHull(dfRatio, bAllowHoles));
4377 : }
4378 :
4379 : /************************************************************************/
4380 : /* Boundary() */
4381 : /************************************************************************/
4382 :
4383 : /**
4384 : * \brief Compute boundary.
4385 : *
4386 : * A new geometry object is created and returned containing the boundary
4387 : * of the geometry on which the method is invoked.
4388 : *
4389 : * This method is the same as the C function OGR_G_Boundary().
4390 : *
4391 : * This method is built on the GEOS library, check it for the definition
4392 : * of the geometry operation.
4393 : * If OGR is built without the GEOS library, this method will always fail,
4394 : * issuing a CPLE_NotSupported error.
4395 : *
4396 : * @return a new geometry to be freed by the caller, or NULL if an error occurs.
4397 : *
4398 : * @since OGR 1.8.0
4399 : */
4400 :
4401 6 : OGRGeometry *OGRGeometry::Boundary() const
4402 :
4403 : {
4404 : #ifndef HAVE_GEOS
4405 :
4406 : CPLError(CE_Failure, CPLE_NotSupported, "GEOS support not enabled.");
4407 : return nullptr;
4408 :
4409 : #else
4410 :
4411 6 : OGRGeometry *poOGRProduct = nullptr;
4412 :
4413 6 : GEOSContextHandle_t hGEOSCtxt = createGEOSContext();
4414 6 : GEOSGeom hGeosGeom = exportToGEOS(hGEOSCtxt);
4415 6 : if (hGeosGeom != nullptr)
4416 : {
4417 6 : GEOSGeom hGeosProduct = GEOSBoundary_r(hGEOSCtxt, hGeosGeom);
4418 6 : GEOSGeom_destroy_r(hGEOSCtxt, hGeosGeom);
4419 :
4420 : poOGRProduct =
4421 6 : BuildGeometryFromGEOS(hGEOSCtxt, hGeosProduct, this, nullptr);
4422 : }
4423 6 : freeGEOSContext(hGEOSCtxt);
4424 :
4425 6 : return poOGRProduct;
4426 :
4427 : #endif // HAVE_GEOS
4428 : }
4429 :
4430 : //! @cond Doxygen_Suppress
4431 : /**
4432 : * \brief Compute boundary (deprecated)
4433 : *
4434 : * @deprecated
4435 : *
4436 : * @see Boundary()
4437 : */
4438 0 : OGRGeometry *OGRGeometry::getBoundary() const
4439 :
4440 : {
4441 0 : return Boundary();
4442 : }
4443 :
4444 : //! @endcond
4445 :
4446 : /************************************************************************/
4447 : /* OGR_G_Boundary() */
4448 : /************************************************************************/
4449 : /**
4450 : * \brief Compute boundary.
4451 : *
4452 : * A new geometry object is created and returned containing the boundary
4453 : * of the geometry on which the method is invoked.
4454 : *
4455 : * This function is the same as the C++ method OGR_G_Boundary().
4456 : *
4457 : * This function is built on the GEOS library, check it for the definition
4458 : * of the geometry operation.
4459 : * If OGR is built without the GEOS library, this function will always fail,
4460 : * issuing a CPLE_NotSupported error.
4461 : *
4462 : * @param hTarget The Geometry to calculate the boundary of.
4463 : *
4464 : * @return a new geometry to be freed by the caller with OGR_G_DestroyGeometry,
4465 : * or NULL if an error occurs.
4466 : *
4467 : * @since OGR 1.8.0
4468 : */
4469 6 : OGRGeometryH OGR_G_Boundary(OGRGeometryH hTarget)
4470 :
4471 : {
4472 6 : VALIDATE_POINTER1(hTarget, "OGR_G_Boundary", nullptr);
4473 :
4474 6 : return OGRGeometry::ToHandle(OGRGeometry::FromHandle(hTarget)->Boundary());
4475 : }
4476 :
4477 : /**
4478 : * \brief Compute boundary (deprecated)
4479 : *
4480 : * @deprecated
4481 : *
4482 : * @see OGR_G_Boundary()
4483 : */
4484 0 : OGRGeometryH OGR_G_GetBoundary(OGRGeometryH hTarget)
4485 :
4486 : {
4487 0 : VALIDATE_POINTER1(hTarget, "OGR_G_GetBoundary", nullptr);
4488 :
4489 0 : return OGRGeometry::ToHandle(OGRGeometry::FromHandle(hTarget)->Boundary());
4490 : }
4491 :
4492 : /************************************************************************/
4493 : /* Buffer() */
4494 : /************************************************************************/
4495 :
4496 : /**
4497 : * \brief Compute buffer of geometry.
4498 : *
4499 : * Builds a new geometry containing the buffer region around the geometry
4500 : * on which it is invoked. The buffer is a polygon containing the region within
4501 : * the buffer distance of the original geometry.
4502 : *
4503 : * Some buffer sections are properly described as curves, but are converted to
4504 : * approximate polygons. The nQuadSegs parameter can be used to control how
4505 : * many segments should be used to define a 90 degree curve - a quadrant of a
4506 : * circle. A value of 30 is a reasonable default. Large values result in
4507 : * large numbers of vertices in the resulting buffer geometry while small
4508 : * numbers reduce the accuracy of the result.
4509 : *
4510 : * This method is the same as the C function OGR_G_Buffer().
4511 : *
4512 : * This method is built on the GEOS library, check it for the definition
4513 : * of the geometry operation.
4514 : * If OGR is built without the GEOS library, this method will always fail,
4515 : * issuing a CPLE_NotSupported error.
4516 : *
4517 : * @param dfDist the buffer distance to be applied. Should be expressed into
4518 : * the same unit as the coordinates of the geometry.
4519 : *
4520 : * @param nQuadSegs the number of segments used to approximate a 90
4521 : * degree (quadrant) of curvature.
4522 : *
4523 : * @return a new geometry to be freed by the caller, or NULL if an error occurs.
4524 : */
4525 :
4526 4 : OGRGeometry *OGRGeometry::Buffer(UNUSED_IF_NO_GEOS double dfDist,
4527 : UNUSED_IF_NO_GEOS int nQuadSegs) const
4528 :
4529 : {
4530 : #ifndef HAVE_GEOS
4531 :
4532 : CPLError(CE_Failure, CPLE_NotSupported, "GEOS support not enabled.");
4533 : return nullptr;
4534 :
4535 : #else
4536 :
4537 4 : OGRGeometry *poOGRProduct = nullptr;
4538 :
4539 4 : GEOSContextHandle_t hGEOSCtxt = createGEOSContext();
4540 4 : GEOSGeom hGeosGeom = exportToGEOS(hGEOSCtxt);
4541 4 : if (hGeosGeom != nullptr)
4542 : {
4543 : GEOSGeom hGeosProduct =
4544 4 : GEOSBuffer_r(hGEOSCtxt, hGeosGeom, dfDist, nQuadSegs);
4545 4 : GEOSGeom_destroy_r(hGEOSCtxt, hGeosGeom);
4546 :
4547 : poOGRProduct =
4548 4 : BuildGeometryFromGEOS(hGEOSCtxt, hGeosProduct, this, nullptr);
4549 : }
4550 4 : freeGEOSContext(hGEOSCtxt);
4551 :
4552 4 : return poOGRProduct;
4553 :
4554 : #endif // HAVE_GEOS
4555 : }
4556 :
4557 : /************************************************************************/
4558 : /* OGR_G_Buffer() */
4559 : /************************************************************************/
4560 :
4561 : /**
4562 : * \brief Compute buffer of geometry.
4563 : *
4564 : * Builds a new geometry containing the buffer region around the geometry
4565 : * on which it is invoked. The buffer is a polygon containing the region within
4566 : * the buffer distance of the original geometry.
4567 : *
4568 : * Some buffer sections are properly described as curves, but are converted to
4569 : * approximate polygons. The nQuadSegs parameter can be used to control how
4570 : * many segments should be used to define a 90 degree curve - a quadrant of a
4571 : * circle. A value of 30 is a reasonable default. Large values result in
4572 : * large numbers of vertices in the resulting buffer geometry while small
4573 : * numbers reduce the accuracy of the result.
4574 : *
4575 : * This function is the same as the C++ method OGRGeometry::Buffer().
4576 : *
4577 : * This function is built on the GEOS library, check it for the definition
4578 : * of the geometry operation.
4579 : * If OGR is built without the GEOS library, this function will always fail,
4580 : * issuing a CPLE_NotSupported error.
4581 : *
4582 : * @param hTarget the geometry.
4583 : * @param dfDist the buffer distance to be applied. Should be expressed into
4584 : * the same unit as the coordinates of the geometry.
4585 : *
4586 : * @param nQuadSegs the number of segments used to approximate a 90 degree
4587 : * (quadrant) of curvature.
4588 : *
4589 : * @return a new geometry to be freed by the caller with OGR_G_DestroyGeometry,
4590 : * or NULL if an error occurs.
4591 : */
4592 :
4593 4 : OGRGeometryH OGR_G_Buffer(OGRGeometryH hTarget, double dfDist, int nQuadSegs)
4594 :
4595 : {
4596 4 : VALIDATE_POINTER1(hTarget, "OGR_G_Buffer", nullptr);
4597 :
4598 4 : return OGRGeometry::ToHandle(
4599 8 : OGRGeometry::FromHandle(hTarget)->Buffer(dfDist, nQuadSegs));
4600 : }
4601 :
4602 : /**
4603 : * \brief Compute buffer of geometry.
4604 : *
4605 : * Builds a new geometry containing the buffer region around the geometry
4606 : * on which it is invoked. The buffer is a polygon containing the region within
4607 : * the buffer distance of the original geometry.
4608 : *
4609 : * This function is built on the GEOS library, check it for the definition
4610 : * of the geometry operation.
4611 : * If OGR is built without the GEOS library, this function will always fail,
4612 : * issuing a CPLE_NotSupported error.
4613 : *
4614 : * The following options are supported. See the GEOS library for more detailed
4615 : * descriptions.
4616 : *
4617 : * <ul>
4618 : * <li>ENDCAP_STYLE=ROUND/FLAT/SQUARE</li>
4619 : * <li>JOIN_STYLE=ROUND/MITRE/BEVEL</li>
4620 : * <li>MITRE_LIMIT=double</li>
4621 : * <li>QUADRANT_SEGMENTS=double</li>
4622 : * <li>SINGLE_SIDED=YES/NO</li>
4623 : * </ul>
4624 : *
4625 : * This function is the same as the C function OGR_G_BufferEx().
4626 : *
4627 : * @param dfDist the buffer distance to be applied. Should be expressed into
4628 : * the same unit as the coordinates of the geometry.
4629 : * @param papszOptions NULL terminated list of options (may be NULL)
4630 : *
4631 : * @return a new geometry to be freed by the caller, or NULL if an error occurs.
4632 : *
4633 : * @since GDAL 3.10
4634 : */
4635 :
4636 : OGRGeometry *
4637 12 : OGRGeometry::BufferEx(UNUSED_IF_NO_GEOS double dfDist,
4638 : UNUSED_IF_NO_GEOS CSLConstList papszOptions) const
4639 : {
4640 : #ifndef HAVE_GEOS
4641 :
4642 : CPLError(CE_Failure, CPLE_NotSupported, "GEOS support not enabled.");
4643 : return nullptr;
4644 :
4645 : #else
4646 12 : OGRGeometry *poOGRProduct = nullptr;
4647 12 : GEOSContextHandle_t hGEOSCtxt = createGEOSContext();
4648 :
4649 12 : auto hParams = GEOSBufferParams_create_r(hGEOSCtxt);
4650 12 : bool bParamsAreValid = true;
4651 :
4652 28 : for (const auto &[pszParam, pszValue] : cpl::IterateNameValue(papszOptions))
4653 : {
4654 16 : if (EQUAL(pszParam, "ENDCAP_STYLE"))
4655 : {
4656 : int nStyle;
4657 2 : if (EQUAL(pszValue, "ROUND"))
4658 : {
4659 0 : nStyle = GEOSBUF_CAP_ROUND;
4660 : }
4661 2 : else if (EQUAL(pszValue, "FLAT"))
4662 : {
4663 1 : nStyle = GEOSBUF_CAP_FLAT;
4664 : }
4665 1 : else if (EQUAL(pszValue, "SQUARE"))
4666 : {
4667 0 : nStyle = GEOSBUF_CAP_SQUARE;
4668 : }
4669 : else
4670 : {
4671 1 : bParamsAreValid = false;
4672 1 : CPLError(CE_Failure, CPLE_NotSupported,
4673 : "Invalid value for ENDCAP_STYLE: %s", pszValue);
4674 2 : break;
4675 : }
4676 :
4677 1 : if (!GEOSBufferParams_setEndCapStyle_r(hGEOSCtxt, hParams, nStyle))
4678 : {
4679 0 : bParamsAreValid = false;
4680 : }
4681 : }
4682 14 : else if (EQUAL(pszParam, "JOIN_STYLE"))
4683 : {
4684 : int nStyle;
4685 2 : if (EQUAL(pszValue, "ROUND"))
4686 : {
4687 0 : nStyle = GEOSBUF_JOIN_ROUND;
4688 : }
4689 2 : else if (EQUAL(pszValue, "MITRE"))
4690 : {
4691 1 : nStyle = GEOSBUF_JOIN_MITRE;
4692 : }
4693 1 : else if (EQUAL(pszValue, "BEVEL"))
4694 : {
4695 0 : nStyle = GEOSBUF_JOIN_BEVEL;
4696 : }
4697 : else
4698 : {
4699 1 : bParamsAreValid = false;
4700 1 : CPLError(CE_Failure, CPLE_NotSupported,
4701 : "Invalid value for JOIN_STYLE: %s", pszValue);
4702 1 : break;
4703 : }
4704 :
4705 1 : if (!GEOSBufferParams_setJoinStyle_r(hGEOSCtxt, hParams, nStyle))
4706 : {
4707 0 : bParamsAreValid = false;
4708 0 : break;
4709 : }
4710 : }
4711 12 : else if (EQUAL(pszParam, "MITRE_LIMIT"))
4712 : {
4713 : try
4714 : {
4715 : std::size_t end;
4716 7 : double dfLimit = std::stod(pszValue, &end);
4717 :
4718 1 : if (end != strlen(pszValue))
4719 : {
4720 0 : throw std::invalid_argument("");
4721 : }
4722 :
4723 1 : if (!GEOSBufferParams_setMitreLimit_r(hGEOSCtxt, hParams,
4724 : dfLimit))
4725 : {
4726 0 : bParamsAreValid = false;
4727 0 : break;
4728 : }
4729 : }
4730 4 : catch (const std::invalid_argument &)
4731 : {
4732 2 : bParamsAreValid = false;
4733 2 : CPLError(CE_Failure, CPLE_IllegalArg,
4734 : "Invalid value for MITRE_LIMIT: %s", pszValue);
4735 : }
4736 0 : catch (const std::out_of_range &)
4737 : {
4738 0 : bParamsAreValid = false;
4739 0 : CPLError(CE_Failure, CPLE_IllegalArg,
4740 : "Invalid value for MITRE_LIMIT: %s", pszValue);
4741 : }
4742 : }
4743 9 : else if (EQUAL(pszParam, "QUADRANT_SEGMENTS"))
4744 : {
4745 : try
4746 : {
4747 : std::size_t end;
4748 15 : int nQuadSegs = std::stoi(pszValue, &end, 10);
4749 :
4750 3 : if (end != strlen(pszValue))
4751 : {
4752 0 : throw std::invalid_argument("");
4753 : }
4754 :
4755 3 : if (!GEOSBufferParams_setQuadrantSegments_r(hGEOSCtxt, hParams,
4756 : nQuadSegs))
4757 : {
4758 0 : bParamsAreValid = false;
4759 0 : break;
4760 : }
4761 : }
4762 6 : catch (const std::invalid_argument &)
4763 : {
4764 3 : bParamsAreValid = false;
4765 3 : CPLError(CE_Failure, CPLE_IllegalArg,
4766 : "Invalid value for QUADRANT_SEGMENTS: %s", pszValue);
4767 : }
4768 2 : catch (const std::out_of_range &)
4769 : {
4770 1 : bParamsAreValid = false;
4771 1 : CPLError(CE_Failure, CPLE_IllegalArg,
4772 : "Invalid value for QUADRANT_SEGMENTS: %s", pszValue);
4773 : }
4774 : }
4775 2 : else if (EQUAL(pszParam, "SINGLE_SIDED"))
4776 : {
4777 1 : bool bSingleSided = CPLTestBool(pszValue);
4778 :
4779 1 : if (!GEOSBufferParams_setSingleSided_r(hGEOSCtxt, hParams,
4780 : bSingleSided))
4781 : {
4782 0 : bParamsAreValid = false;
4783 0 : break;
4784 : }
4785 : }
4786 : else
4787 : {
4788 1 : bParamsAreValid = false;
4789 1 : CPLError(CE_Failure, CPLE_NotSupported,
4790 : "Unsupported buffer option: %s", pszValue);
4791 : }
4792 : }
4793 :
4794 12 : if (bParamsAreValid)
4795 : {
4796 3 : GEOSGeom hGeosGeom = exportToGEOS(hGEOSCtxt);
4797 3 : if (hGeosGeom != nullptr)
4798 : {
4799 : GEOSGeom hGeosProduct =
4800 3 : GEOSBufferWithParams_r(hGEOSCtxt, hGeosGeom, hParams, dfDist);
4801 3 : GEOSGeom_destroy_r(hGEOSCtxt, hGeosGeom);
4802 :
4803 3 : if (hGeosProduct != nullptr)
4804 : {
4805 3 : poOGRProduct = BuildGeometryFromGEOS(hGEOSCtxt, hGeosProduct,
4806 : this, nullptr);
4807 : }
4808 : }
4809 : }
4810 :
4811 12 : GEOSBufferParams_destroy_r(hGEOSCtxt, hParams);
4812 12 : freeGEOSContext(hGEOSCtxt);
4813 12 : return poOGRProduct;
4814 : #endif
4815 : }
4816 :
4817 : /**
4818 : * \brief Compute buffer of geometry.
4819 : *
4820 : * Builds a new geometry containing the buffer region around the geometry
4821 : * on which it is invoked. The buffer is a polygon containing the region within
4822 : * the buffer distance of the original geometry.
4823 : *
4824 : * This function is built on the GEOS library, check it for the definition
4825 : * of the geometry operation.
4826 : * If OGR is built without the GEOS library, this function will always fail,
4827 : * issuing a CPLE_NotSupported error.
4828 : *
4829 : * The following options are supported. See the GEOS library for more detailed
4830 : * descriptions.
4831 : *
4832 : * <ul>
4833 : * <li>ENDCAP_STYLE=ROUND/FLAT/SQUARE</li>
4834 : * <li>JOIN_STYLE=ROUND/MITRE/BEVEL</li>
4835 : * <li>MITRE_LIMIT=double</li>
4836 : * <li>QUADRANT_SEGMENTS=double</li>
4837 : * <li>SINGLE_SIDED=YES/NO</li>
4838 : * </ul>
4839 : *
4840 : * This function is the same as the C++ method OGRGeometry::BufferEx().
4841 : *
4842 : * @param hTarget the geometry.
4843 : * @param dfDist the buffer distance to be applied. Should be expressed into
4844 : * the same unit as the coordinates of the geometry.
4845 : * @param papszOptions NULL terminated list of options (may be NULL)
4846 : *
4847 : * @return a new geometry to be freed by the caller with OGR_G_DestroyGeometry,
4848 : * or NULL if an error occurs.
4849 : *
4850 : * @since GDAL 3.10
4851 : */
4852 :
4853 12 : OGRGeometryH OGR_G_BufferEx(OGRGeometryH hTarget, double dfDist,
4854 : CSLConstList papszOptions)
4855 :
4856 : {
4857 12 : VALIDATE_POINTER1(hTarget, "OGR_G_BufferEx", nullptr);
4858 :
4859 12 : return OGRGeometry::ToHandle(
4860 24 : OGRGeometry::FromHandle(hTarget)->BufferEx(dfDist, papszOptions));
4861 : }
4862 :
4863 : /************************************************************************/
4864 : /* Intersection() */
4865 : /************************************************************************/
4866 :
4867 : /**
4868 : * \brief Compute intersection.
4869 : *
4870 : * Generates a new geometry which is the region of intersection of the
4871 : * two geometries operated on. The Intersects() method can be used to test if
4872 : * two geometries intersect.
4873 : *
4874 : * Geometry validity is not checked. In case you are unsure of the validity
4875 : * of the input geometries, call IsValid() before, otherwise the result might
4876 : * be wrong.
4877 : *
4878 : * This method is the same as the C function OGR_G_Intersection().
4879 : *
4880 : * This method is built on the GEOS library, check it for the definition
4881 : * of the geometry operation.
4882 : * If OGR is built without the GEOS library, this method will always fail,
4883 : * issuing a CPLE_NotSupported error.
4884 : *
4885 : * @param poOtherGeom the other geometry intersected with "this" geometry.
4886 : *
4887 : * @return a new geometry to be freed by the caller, or NULL if there is no
4888 : * intersection or if an error occurs.
4889 : *
4890 : */
4891 :
4892 : OGRGeometry *
4893 883 : OGRGeometry::Intersection(UNUSED_PARAMETER const OGRGeometry *poOtherGeom) const
4894 :
4895 : {
4896 883 : if (IsSFCGALCompatible() || poOtherGeom->IsSFCGALCompatible())
4897 : {
4898 : #ifndef HAVE_SFCGAL
4899 :
4900 0 : CPLError(CE_Failure, CPLE_NotSupported, "SFCGAL support not enabled.");
4901 0 : return nullptr;
4902 :
4903 : #else
4904 :
4905 : sfcgal_geometry_t *poThis = OGRGeometry::OGRexportToSFCGAL(this);
4906 : if (poThis == nullptr)
4907 : return nullptr;
4908 :
4909 : sfcgal_geometry_t *poOther =
4910 : OGRGeometry::OGRexportToSFCGAL(poOtherGeom);
4911 : if (poOther == nullptr)
4912 : {
4913 : sfcgal_geometry_delete(poThis);
4914 : return nullptr;
4915 : }
4916 :
4917 : sfcgal_geometry_t *poRes =
4918 : sfcgal_geometry_intersection_3d(poThis, poOther);
4919 : OGRGeometry *h_prodGeom = SFCGALexportToOGR(poRes);
4920 : if (h_prodGeom != nullptr && getSpatialReference() != nullptr &&
4921 : poOtherGeom->getSpatialReference() != nullptr &&
4922 : poOtherGeom->getSpatialReference()->IsSame(getSpatialReference()))
4923 : h_prodGeom->assignSpatialReference(getSpatialReference());
4924 :
4925 : sfcgal_geometry_delete(poThis);
4926 : sfcgal_geometry_delete(poOther);
4927 : sfcgal_geometry_delete(poRes);
4928 :
4929 : return h_prodGeom;
4930 :
4931 : #endif
4932 : }
4933 :
4934 : else
4935 : {
4936 : #ifndef HAVE_GEOS
4937 :
4938 : CPLError(CE_Failure, CPLE_NotSupported, "GEOS support not enabled.");
4939 : return nullptr;
4940 :
4941 : #else
4942 882 : return BuildGeometryFromTwoGeoms(this, poOtherGeom, GEOSIntersection_r);
4943 : #endif /* HAVE_GEOS */
4944 : }
4945 : }
4946 :
4947 : /************************************************************************/
4948 : /* OGR_G_Intersection() */
4949 : /************************************************************************/
4950 :
4951 : /**
4952 : * \brief Compute intersection.
4953 : *
4954 : * Generates a new geometry which is the region of intersection of the
4955 : * two geometries operated on. The OGR_G_Intersects() function can be used to
4956 : * test if two geometries intersect.
4957 : *
4958 : * Geometry validity is not checked. In case you are unsure of the validity
4959 : * of the input geometries, call IsValid() before, otherwise the result might
4960 : * be wrong.
4961 : *
4962 : * This function is the same as the C++ method OGRGeometry::Intersection().
4963 : *
4964 : * This function is built on the GEOS library, check it for the definition
4965 : * of the geometry operation.
4966 : * If OGR is built without the GEOS library, this function will always fail,
4967 : * issuing a CPLE_NotSupported error.
4968 : *
4969 : * @param hThis the geometry.
4970 : * @param hOther the other geometry.
4971 : *
4972 : * @return a new geometry to be freed by the caller with OGR_G_DestroyGeometry,
4973 : * or NULL if there is not intersection of if an error occurs.
4974 : */
4975 :
4976 12 : OGRGeometryH OGR_G_Intersection(OGRGeometryH hThis, OGRGeometryH hOther)
4977 :
4978 : {
4979 12 : VALIDATE_POINTER1(hThis, "OGR_G_Intersection", nullptr);
4980 :
4981 24 : return OGRGeometry::ToHandle(OGRGeometry::FromHandle(hThis)->Intersection(
4982 24 : OGRGeometry::FromHandle(hOther)));
4983 : }
4984 :
4985 : /************************************************************************/
4986 : /* Union() */
4987 : /************************************************************************/
4988 :
4989 : /**
4990 : * \brief Compute union.
4991 : *
4992 : * Generates a new geometry which is the region of union of the
4993 : * two geometries operated on.
4994 : *
4995 : * Geometry validity is not checked. In case you are unsure of the validity
4996 : * of the input geometries, call IsValid() before, otherwise the result might
4997 : * be wrong.
4998 : *
4999 : * This method is the same as the C function OGR_G_Union().
5000 : *
5001 : * This method is built on the GEOS library, check it for the definition
5002 : * of the geometry operation.
5003 : * If OGR is built without the GEOS library, this method will always fail,
5004 : * issuing a CPLE_NotSupported error.
5005 : *
5006 : * @param poOtherGeom the other geometry unioned with "this" geometry.
5007 : *
5008 : * @return a new geometry to be freed by the caller, or NULL if an error occurs.
5009 : */
5010 :
5011 : OGRGeometry *
5012 43 : OGRGeometry::Union(UNUSED_PARAMETER const OGRGeometry *poOtherGeom) const
5013 :
5014 : {
5015 43 : if (IsSFCGALCompatible() || poOtherGeom->IsSFCGALCompatible())
5016 : {
5017 : #ifndef HAVE_SFCGAL
5018 :
5019 0 : CPLError(CE_Failure, CPLE_NotSupported, "SFCGAL support not enabled.");
5020 0 : return nullptr;
5021 :
5022 : #else
5023 :
5024 : sfcgal_geometry_t *poThis = OGRGeometry::OGRexportToSFCGAL(this);
5025 : if (poThis == nullptr)
5026 : return nullptr;
5027 :
5028 : sfcgal_geometry_t *poOther =
5029 : OGRGeometry::OGRexportToSFCGAL(poOtherGeom);
5030 : if (poOther == nullptr)
5031 : {
5032 : sfcgal_geometry_delete(poThis);
5033 : return nullptr;
5034 : }
5035 :
5036 : sfcgal_geometry_t *poRes = sfcgal_geometry_union_3d(poThis, poOther);
5037 : OGRGeometry *h_prodGeom = OGRGeometry::SFCGALexportToOGR(poRes);
5038 : if (h_prodGeom != nullptr && getSpatialReference() != nullptr &&
5039 : poOtherGeom->getSpatialReference() != nullptr &&
5040 : poOtherGeom->getSpatialReference()->IsSame(getSpatialReference()))
5041 : h_prodGeom->assignSpatialReference(getSpatialReference());
5042 :
5043 : sfcgal_geometry_delete(poThis);
5044 : sfcgal_geometry_delete(poOther);
5045 : sfcgal_geometry_delete(poRes);
5046 :
5047 : return h_prodGeom;
5048 :
5049 : #endif
5050 : }
5051 :
5052 : else
5053 : {
5054 : #ifndef HAVE_GEOS
5055 :
5056 : CPLError(CE_Failure, CPLE_NotSupported, "GEOS support not enabled.");
5057 : return nullptr;
5058 :
5059 : #else
5060 43 : return BuildGeometryFromTwoGeoms(this, poOtherGeom, GEOSUnion_r);
5061 : #endif /* HAVE_GEOS */
5062 : }
5063 : }
5064 :
5065 : /************************************************************************/
5066 : /* OGR_G_Union() */
5067 : /************************************************************************/
5068 :
5069 : /**
5070 : * \brief Compute union.
5071 : *
5072 : * Generates a new geometry which is the region of union of the
5073 : * two geometries operated on.
5074 : *
5075 : * Geometry validity is not checked. In case you are unsure of the validity
5076 : * of the input geometries, call IsValid() before, otherwise the result might
5077 : * be wrong.
5078 : *
5079 : * This function is the same as the C++ method OGRGeometry::Union().
5080 : *
5081 : * This function is built on the GEOS library, check it for the definition
5082 : * of the geometry operation.
5083 : * If OGR is built without the GEOS library, this function will always fail,
5084 : * issuing a CPLE_NotSupported error.
5085 : *
5086 : * @param hThis the geometry.
5087 : * @param hOther the other geometry.
5088 : *
5089 : * @return a new geometry to be freed by the caller with OGR_G_DestroyGeometry,
5090 : * or NULL if an error occurs.
5091 : */
5092 :
5093 8 : OGRGeometryH OGR_G_Union(OGRGeometryH hThis, OGRGeometryH hOther)
5094 :
5095 : {
5096 8 : VALIDATE_POINTER1(hThis, "OGR_G_Union", nullptr);
5097 :
5098 8 : return OGRGeometry::ToHandle(
5099 16 : OGRGeometry::FromHandle(hThis)->Union(OGRGeometry::FromHandle(hOther)));
5100 : }
5101 :
5102 : /************************************************************************/
5103 : /* UnionCascaded() */
5104 : /************************************************************************/
5105 :
5106 : /**
5107 : * \brief Compute union using cascading.
5108 : *
5109 : * Geometry validity is not checked. In case you are unsure of the validity
5110 : * of the input geometries, call IsValid() before, otherwise the result might
5111 : * be wrong.
5112 : *
5113 : * The input geometry must be a MultiPolygon.
5114 : *
5115 : * This method is the same as the C function OGR_G_UnionCascaded().
5116 : *
5117 : * This method is built on the GEOS library, check it for the definition
5118 : * of the geometry operation.
5119 : * If OGR is built without the GEOS library, this method will always fail,
5120 : * issuing a CPLE_NotSupported error.
5121 : *
5122 : * @return a new geometry to be freed by the caller, or NULL if an error occurs.
5123 : *
5124 : * @since OGR 1.8.0
5125 : *
5126 : * @deprecated Use UnaryUnion() instead
5127 : */
5128 :
5129 2 : OGRGeometry *OGRGeometry::UnionCascaded() const
5130 :
5131 : {
5132 : #ifndef HAVE_GEOS
5133 :
5134 : CPLError(CE_Failure, CPLE_NotSupported, "GEOS support not enabled.");
5135 : return nullptr;
5136 : #else
5137 :
5138 : #if GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR < 11
5139 : if (wkbFlatten(getGeometryType()) == wkbMultiPolygon && IsEmpty())
5140 : {
5141 : // GEOS < 3.11 crashes on an empty multipolygon input
5142 : auto poRet = new OGRGeometryCollection();
5143 : poRet->assignSpatialReference(getSpatialReference());
5144 : return poRet;
5145 : }
5146 : #endif
5147 2 : OGRGeometry *poOGRProduct = nullptr;
5148 :
5149 2 : GEOSContextHandle_t hGEOSCtxt = createGEOSContext();
5150 2 : GEOSGeom hThisGeosGeom = exportToGEOS(hGEOSCtxt);
5151 2 : if (hThisGeosGeom != nullptr)
5152 : {
5153 2 : GEOSGeom hGeosProduct = GEOSUnionCascaded_r(hGEOSCtxt, hThisGeosGeom);
5154 2 : GEOSGeom_destroy_r(hGEOSCtxt, hThisGeosGeom);
5155 :
5156 : poOGRProduct =
5157 2 : BuildGeometryFromGEOS(hGEOSCtxt, hGeosProduct, this, nullptr);
5158 : }
5159 2 : freeGEOSContext(hGEOSCtxt);
5160 :
5161 2 : return poOGRProduct;
5162 :
5163 : #endif // HAVE_GEOS
5164 : }
5165 :
5166 : /************************************************************************/
5167 : /* OGR_G_UnionCascaded() */
5168 : /************************************************************************/
5169 :
5170 : /**
5171 : * \brief Compute union using cascading.
5172 : *
5173 : * Geometry validity is not checked. In case you are unsure of the validity
5174 : * of the input geometries, call IsValid() before, otherwise the result might
5175 : * be wrong.
5176 : *
5177 : * The input geometry must be a MultiPolygon.
5178 : *
5179 : * This function is the same as the C++ method OGRGeometry::UnionCascaded().
5180 : *
5181 : * This function is built on the GEOS library, check it for the definition
5182 : * of the geometry operation.
5183 : * If OGR is built without the GEOS library, this function will always fail,
5184 : * issuing a CPLE_NotSupported error.
5185 : *
5186 : * @param hThis the geometry.
5187 : *
5188 : * @return a new geometry to be freed by the caller with OGR_G_DestroyGeometry,
5189 : * or NULL if an error occurs.
5190 : *
5191 : * @deprecated Use OGR_G_UnaryUnion() instead
5192 : */
5193 :
5194 2 : OGRGeometryH OGR_G_UnionCascaded(OGRGeometryH hThis)
5195 :
5196 : {
5197 2 : VALIDATE_POINTER1(hThis, "OGR_G_UnionCascaded", nullptr);
5198 :
5199 2 : return OGRGeometry::ToHandle(
5200 4 : OGRGeometry::FromHandle(hThis)->UnionCascaded());
5201 : }
5202 :
5203 : /************************************************************************/
5204 : /* UnaryUnion() */
5205 : /************************************************************************/
5206 :
5207 : /**
5208 : * \brief Returns the union of all components of a single geometry.
5209 : *
5210 : * Usually used to convert a collection into the smallest set of polygons that
5211 : * cover the same area.
5212 : *
5213 : * See https://postgis.net/docs/ST_UnaryUnion.html for more details.
5214 : *
5215 : * This method is the same as the C function OGR_G_UnaryUnion().
5216 : *
5217 : * This method is built on the GEOS library, check it for the definition
5218 : * of the geometry operation.
5219 : * If OGR is built without the GEOS library, this method will always fail,
5220 : * issuing a CPLE_NotSupported error.
5221 : *
5222 : * @return a new geometry to be freed by the caller, or NULL if an error occurs.
5223 : *
5224 : * @since GDAL 3.7
5225 : */
5226 :
5227 616 : OGRGeometry *OGRGeometry::UnaryUnion() const
5228 :
5229 : {
5230 : #ifndef HAVE_GEOS
5231 :
5232 : CPLError(CE_Failure, CPLE_NotSupported, "GEOS support not enabled.");
5233 : return nullptr;
5234 : #else
5235 :
5236 : #if GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR < 11
5237 : if (IsEmpty())
5238 : {
5239 : // GEOS < 3.11 crashes on an empty geometry
5240 : auto poRet = new OGRGeometryCollection();
5241 : poRet->assignSpatialReference(getSpatialReference());
5242 : return poRet;
5243 : }
5244 : #endif
5245 616 : OGRGeometry *poOGRProduct = nullptr;
5246 :
5247 616 : GEOSContextHandle_t hGEOSCtxt = createGEOSContext();
5248 616 : GEOSGeom hThisGeosGeom = exportToGEOS(hGEOSCtxt);
5249 616 : if (hThisGeosGeom != nullptr)
5250 : {
5251 616 : GEOSGeom hGeosProduct = GEOSUnaryUnion_r(hGEOSCtxt, hThisGeosGeom);
5252 616 : GEOSGeom_destroy_r(hGEOSCtxt, hThisGeosGeom);
5253 :
5254 : poOGRProduct =
5255 616 : BuildGeometryFromGEOS(hGEOSCtxt, hGeosProduct, this, nullptr);
5256 : }
5257 616 : freeGEOSContext(hGEOSCtxt);
5258 :
5259 616 : return poOGRProduct;
5260 :
5261 : #endif // HAVE_GEOS
5262 : }
5263 :
5264 : /************************************************************************/
5265 : /* OGR_G_UnaryUnion() */
5266 : /************************************************************************/
5267 :
5268 : /**
5269 : * \brief Returns the union of all components of a single geometry.
5270 : *
5271 : * Usually used to convert a collection into the smallest set of polygons that
5272 : * cover the same area.
5273 : *
5274 : * See https://postgis.net/docs/ST_UnaryUnion.html for more details.
5275 : *
5276 : * Geometry validity is not checked. In case you are unsure of the validity
5277 : * of the input geometries, call IsValid() before, otherwise the result might
5278 : * be wrong.
5279 : *
5280 : * This function is the same as the C++ method OGRGeometry::UnaryUnion().
5281 : *
5282 : * This function is built on the GEOS library, check it for the definition
5283 : * of the geometry operation.
5284 : * If OGR is built without the GEOS library, this function will always fail,
5285 : * issuing a CPLE_NotSupported error.
5286 : *
5287 : * @param hThis the geometry.
5288 : *
5289 : * @return a new geometry to be freed by the caller with OGR_G_DestroyGeometry,
5290 : * or NULL if an error occurs.
5291 : *
5292 : * @since GDAL 3.7
5293 : */
5294 :
5295 3 : OGRGeometryH OGR_G_UnaryUnion(OGRGeometryH hThis)
5296 :
5297 : {
5298 3 : VALIDATE_POINTER1(hThis, "OGR_G_UnaryUnion", nullptr);
5299 :
5300 3 : return OGRGeometry::ToHandle(OGRGeometry::FromHandle(hThis)->UnaryUnion());
5301 : }
5302 :
5303 : /************************************************************************/
5304 : /* Difference() */
5305 : /************************************************************************/
5306 :
5307 : /**
5308 : * \brief Compute difference.
5309 : *
5310 : * Generates a new geometry which is the region of this geometry with the
5311 : * region of the second geometry removed.
5312 : *
5313 : * Geometry validity is not checked. In case you are unsure of the validity
5314 : * of the input geometries, call IsValid() before, otherwise the result might
5315 : * be wrong.
5316 : *
5317 : * This method is the same as the C function OGR_G_Difference().
5318 : *
5319 : * This method is built on the GEOS library, check it for the definition
5320 : * of the geometry operation.
5321 : * If OGR is built without the GEOS library, this method will always fail,
5322 : * issuing a CPLE_NotSupported error.
5323 : *
5324 : * @param poOtherGeom the other geometry removed from "this" geometry.
5325 : *
5326 : * @return a new geometry to be freed by the caller, or NULL if the difference
5327 : * is empty or if an error occurs.
5328 : */
5329 :
5330 : OGRGeometry *
5331 123 : OGRGeometry::Difference(UNUSED_PARAMETER const OGRGeometry *poOtherGeom) const
5332 :
5333 : {
5334 123 : if (IsSFCGALCompatible() || poOtherGeom->IsSFCGALCompatible())
5335 : {
5336 : #ifndef HAVE_SFCGAL
5337 :
5338 0 : CPLError(CE_Failure, CPLE_NotSupported, "SFCGAL support not enabled.");
5339 0 : return nullptr;
5340 :
5341 : #else
5342 :
5343 : sfcgal_geometry_t *poThis = OGRGeometry::OGRexportToSFCGAL(this);
5344 : if (poThis == nullptr)
5345 : return nullptr;
5346 :
5347 : sfcgal_geometry_t *poOther =
5348 : OGRGeometry::OGRexportToSFCGAL(poOtherGeom);
5349 : if (poOther == nullptr)
5350 : {
5351 : sfcgal_geometry_delete(poThis);
5352 : return nullptr;
5353 : }
5354 :
5355 : sfcgal_geometry_t *poRes =
5356 : sfcgal_geometry_difference_3d(poThis, poOther);
5357 : OGRGeometry *h_prodGeom = OGRGeometry::SFCGALexportToOGR(poRes);
5358 : if (h_prodGeom != nullptr && getSpatialReference() != nullptr &&
5359 : poOtherGeom->getSpatialReference() != nullptr &&
5360 : poOtherGeom->getSpatialReference()->IsSame(getSpatialReference()))
5361 : h_prodGeom->assignSpatialReference(getSpatialReference());
5362 :
5363 : sfcgal_geometry_delete(poThis);
5364 : sfcgal_geometry_delete(poOther);
5365 : sfcgal_geometry_delete(poRes);
5366 :
5367 : return h_prodGeom;
5368 :
5369 : #endif
5370 : }
5371 :
5372 : else
5373 : {
5374 : #ifndef HAVE_GEOS
5375 :
5376 : CPLError(CE_Failure, CPLE_NotSupported, "GEOS support not enabled.");
5377 : return nullptr;
5378 :
5379 : #else
5380 123 : return BuildGeometryFromTwoGeoms(this, poOtherGeom, GEOSDifference_r);
5381 : #endif /* HAVE_GEOS */
5382 : }
5383 : }
5384 :
5385 : /************************************************************************/
5386 : /* OGR_G_Difference() */
5387 : /************************************************************************/
5388 :
5389 : /**
5390 : * \brief Compute difference.
5391 : *
5392 : * Generates a new geometry which is the region of this geometry with the
5393 : * region of the other geometry removed.
5394 : *
5395 : * Geometry validity is not checked. In case you are unsure of the validity
5396 : * of the input geometries, call IsValid() before, otherwise the result might
5397 : * be wrong.
5398 : *
5399 : * This function is the same as the C++ method OGRGeometry::Difference().
5400 : *
5401 : * This function is built on the GEOS library, check it for the definition
5402 : * of the geometry operation.
5403 : * If OGR is built without the GEOS library, this function will always fail,
5404 : * issuing a CPLE_NotSupported error.
5405 : *
5406 : * @param hThis the geometry.
5407 : * @param hOther the other geometry.
5408 : *
5409 : * @return a new geometry to be freed by the caller with OGR_G_DestroyGeometry,
5410 : * or NULL if the difference is empty or if an error occurs.
5411 : */
5412 :
5413 6 : OGRGeometryH OGR_G_Difference(OGRGeometryH hThis, OGRGeometryH hOther)
5414 :
5415 : {
5416 6 : VALIDATE_POINTER1(hThis, "OGR_G_Difference", nullptr);
5417 :
5418 12 : return OGRGeometry::ToHandle(OGRGeometry::FromHandle(hThis)->Difference(
5419 12 : OGRGeometry::FromHandle(hOther)));
5420 : }
5421 :
5422 : /************************************************************************/
5423 : /* SymDifference() */
5424 : /************************************************************************/
5425 :
5426 : /**
5427 : * \brief Compute symmetric difference.
5428 : *
5429 : * Generates a new geometry which is the symmetric difference of this
5430 : * geometry and the second geometry passed into the method.
5431 : *
5432 : * Geometry validity is not checked. In case you are unsure of the validity
5433 : * of the input geometries, call IsValid() before, otherwise the result might
5434 : * be wrong.
5435 : *
5436 : * This method is the same as the C function OGR_G_SymDifference().
5437 : *
5438 : * This method is built on the GEOS library, check it for the definition
5439 : * of the geometry operation.
5440 : * If OGR is built without the GEOS library, this method will always fail,
5441 : * issuing a CPLE_NotSupported error.
5442 : *
5443 : * @param poOtherGeom the other geometry.
5444 : *
5445 : * @return a new geometry to be freed by the caller, or NULL if the difference
5446 : * is empty or if an error occurs.
5447 : *
5448 : * @since OGR 1.8.0
5449 : */
5450 :
5451 7 : OGRGeometry *OGRGeometry::SymDifference(
5452 : UNUSED_IF_NO_GEOS const OGRGeometry *poOtherGeom) const
5453 :
5454 : {
5455 7 : if (IsSFCGALCompatible() || poOtherGeom->IsSFCGALCompatible())
5456 : {
5457 : #ifndef HAVE_SFCGAL
5458 0 : CPLError(CE_Failure, CPLE_NotSupported, "SFCGAL support not enabled.");
5459 0 : return nullptr;
5460 : #else
5461 : OGRGeometry *poFirstDifference = Difference(poOtherGeom);
5462 : if (poFirstDifference == nullptr)
5463 : return nullptr;
5464 :
5465 : OGRGeometry *poOtherDifference = poOtherGeom->Difference(this);
5466 : if (poOtherDifference == nullptr)
5467 : {
5468 : delete poFirstDifference;
5469 : return nullptr;
5470 : }
5471 :
5472 : OGRGeometry *poSymDiff = poFirstDifference->Union(poOtherDifference);
5473 : delete poFirstDifference;
5474 : delete poOtherDifference;
5475 : return poSymDiff;
5476 : #endif
5477 : }
5478 :
5479 : #ifndef HAVE_GEOS
5480 :
5481 : CPLError(CE_Failure, CPLE_NotSupported, "GEOS support not enabled.");
5482 : return nullptr;
5483 :
5484 : #else
5485 7 : return BuildGeometryFromTwoGeoms(this, poOtherGeom, GEOSSymDifference_r);
5486 : #endif // HAVE_GEOS
5487 : }
5488 :
5489 : //! @cond Doxygen_Suppress
5490 : /**
5491 : * \brief Compute symmetric difference (deprecated)
5492 : *
5493 : * @deprecated
5494 : *
5495 : * @see OGRGeometry::SymDifference()
5496 : */
5497 : OGRGeometry *
5498 0 : OGRGeometry::SymmetricDifference(const OGRGeometry *poOtherGeom) const
5499 :
5500 : {
5501 0 : return SymDifference(poOtherGeom);
5502 : }
5503 :
5504 : //! @endcond
5505 :
5506 : /************************************************************************/
5507 : /* OGR_G_SymDifference() */
5508 : /************************************************************************/
5509 :
5510 : /**
5511 : * \brief Compute symmetric difference.
5512 : *
5513 : * Generates a new geometry which is the symmetric difference of this
5514 : * geometry and the other geometry.
5515 : *
5516 : * Geometry validity is not checked. In case you are unsure of the validity
5517 : * of the input geometries, call IsValid() before, otherwise the result might
5518 : * be wrong.
5519 : *
5520 : * This function is the same as the C++ method
5521 : * OGRGeometry::SymmetricDifference().
5522 : *
5523 : * This function is built on the GEOS library, check it for the definition
5524 : * of the geometry operation.
5525 : * If OGR is built without the GEOS library, this function will always fail,
5526 : * issuing a CPLE_NotSupported error.
5527 : *
5528 : * @param hThis the geometry.
5529 : * @param hOther the other geometry.
5530 : *
5531 : * @return a new geometry to be freed by the caller with OGR_G_DestroyGeometry,
5532 : * or NULL if the difference is empty or if an error occurs.
5533 : *
5534 : * @since OGR 1.8.0
5535 : */
5536 :
5537 7 : OGRGeometryH OGR_G_SymDifference(OGRGeometryH hThis, OGRGeometryH hOther)
5538 :
5539 : {
5540 7 : VALIDATE_POINTER1(hThis, "OGR_G_SymDifference", nullptr);
5541 :
5542 14 : return OGRGeometry::ToHandle(OGRGeometry::FromHandle(hThis)->SymDifference(
5543 14 : OGRGeometry::FromHandle(hOther)));
5544 : }
5545 :
5546 : /**
5547 : * \brief Compute symmetric difference (deprecated)
5548 : *
5549 : * @deprecated
5550 : *
5551 : * @see OGR_G_SymmetricDifference()
5552 : */
5553 0 : OGRGeometryH OGR_G_SymmetricDifference(OGRGeometryH hThis, OGRGeometryH hOther)
5554 :
5555 : {
5556 0 : VALIDATE_POINTER1(hThis, "OGR_G_SymmetricDifference", nullptr);
5557 :
5558 0 : return OGRGeometry::ToHandle(OGRGeometry::FromHandle(hThis)->SymDifference(
5559 0 : OGRGeometry::FromHandle(hOther)));
5560 : }
5561 :
5562 : /************************************************************************/
5563 : /* Disjoint() */
5564 : /************************************************************************/
5565 :
5566 : /**
5567 : * \brief Test for disjointness.
5568 : *
5569 : * Tests if this geometry and the other passed into the method are disjoint.
5570 : *
5571 : * Geometry validity is not checked. In case you are unsure of the validity
5572 : * of the input geometries, call IsValid() before, otherwise the result might
5573 : * be wrong.
5574 : *
5575 : * This method is the same as the C function OGR_G_Disjoint().
5576 : *
5577 : * This method is built on the GEOS library, check it for the definition
5578 : * of the geometry operation.
5579 : * If OGR is built without the GEOS library, this method will always fail,
5580 : * issuing a CPLE_NotSupported error.
5581 : *
5582 : * @param poOtherGeom the geometry to compare to this geometry.
5583 : *
5584 : * @return TRUE if they are disjoint, otherwise FALSE.
5585 : */
5586 :
5587 : OGRBoolean
5588 8 : OGRGeometry::Disjoint(UNUSED_IF_NO_GEOS const OGRGeometry *poOtherGeom) const
5589 :
5590 : {
5591 : #ifndef HAVE_GEOS
5592 :
5593 : CPLError(CE_Failure, CPLE_NotSupported, "GEOS support not enabled.");
5594 : return FALSE;
5595 :
5596 : #else
5597 8 : return OGRGEOSBooleanPredicate(this, poOtherGeom, GEOSDisjoint_r);
5598 : #endif // HAVE_GEOS
5599 : }
5600 :
5601 : /************************************************************************/
5602 : /* OGR_G_Disjoint() */
5603 : /************************************************************************/
5604 :
5605 : /**
5606 : * \brief Test for disjointness.
5607 : *
5608 : * Tests if this geometry and the other geometry are disjoint.
5609 : *
5610 : * Geometry validity is not checked. In case you are unsure of the validity
5611 : * of the input geometries, call IsValid() before, otherwise the result might
5612 : * be wrong.
5613 : *
5614 : * This function is the same as the C++ method OGRGeometry::Disjoint().
5615 : *
5616 : * This function is built on the GEOS library, check it for the definition
5617 : * of the geometry operation.
5618 : * If OGR is built without the GEOS library, this function will always fail,
5619 : * issuing a CPLE_NotSupported error.
5620 : *
5621 : * @param hThis the geometry to compare.
5622 : * @param hOther the other geometry to compare.
5623 : *
5624 : * @return TRUE if they are disjoint, otherwise FALSE.
5625 : */
5626 8 : int OGR_G_Disjoint(OGRGeometryH hThis, OGRGeometryH hOther)
5627 :
5628 : {
5629 8 : VALIDATE_POINTER1(hThis, "OGR_G_Disjoint", FALSE);
5630 :
5631 16 : return OGRGeometry::FromHandle(hThis)->Disjoint(
5632 8 : OGRGeometry::FromHandle(hOther));
5633 : }
5634 :
5635 : /************************************************************************/
5636 : /* Touches() */
5637 : /************************************************************************/
5638 :
5639 : /**
5640 : * \brief Test for touching.
5641 : *
5642 : * Tests if this geometry and the other passed into the method are touching.
5643 : *
5644 : * Geometry validity is not checked. In case you are unsure of the validity
5645 : * of the input geometries, call IsValid() before, otherwise the result might
5646 : * be wrong.
5647 : *
5648 : * This method is the same as the C function OGR_G_Touches().
5649 : *
5650 : * This method is built on the GEOS library, check it for the definition
5651 : * of the geometry operation.
5652 : * If OGR is built without the GEOS library, this method will always fail,
5653 : * issuing a CPLE_NotSupported error.
5654 : *
5655 : * @param poOtherGeom the geometry to compare to this geometry.
5656 : *
5657 : * @return TRUE if they are touching, otherwise FALSE.
5658 : */
5659 :
5660 : OGRBoolean
5661 11 : OGRGeometry::Touches(UNUSED_IF_NO_GEOS const OGRGeometry *poOtherGeom) const
5662 :
5663 : {
5664 : #ifndef HAVE_GEOS
5665 :
5666 : CPLError(CE_Failure, CPLE_NotSupported, "GEOS support not enabled.");
5667 : return FALSE;
5668 :
5669 : #else
5670 11 : return OGRGEOSBooleanPredicate(this, poOtherGeom, GEOSTouches_r);
5671 : #endif // HAVE_GEOS
5672 : }
5673 :
5674 : /************************************************************************/
5675 : /* OGR_G_Touches() */
5676 : /************************************************************************/
5677 : /**
5678 : * \brief Test for touching.
5679 : *
5680 : * Tests if this geometry and the other geometry are touching.
5681 : *
5682 : * Geometry validity is not checked. In case you are unsure of the validity
5683 : * of the input geometries, call IsValid() before, otherwise the result might
5684 : * be wrong.
5685 : *
5686 : * This function is the same as the C++ method OGRGeometry::Touches().
5687 : *
5688 : * This function is built on the GEOS library, check it for the definition
5689 : * of the geometry operation.
5690 : * If OGR is built without the GEOS library, this function will always fail,
5691 : * issuing a CPLE_NotSupported error.
5692 : *
5693 : * @param hThis the geometry to compare.
5694 : * @param hOther the other geometry to compare.
5695 : *
5696 : * @return TRUE if they are touching, otherwise FALSE.
5697 : */
5698 :
5699 8 : int OGR_G_Touches(OGRGeometryH hThis, OGRGeometryH hOther)
5700 :
5701 : {
5702 8 : VALIDATE_POINTER1(hThis, "OGR_G_Touches", FALSE);
5703 :
5704 16 : return OGRGeometry::FromHandle(hThis)->Touches(
5705 8 : OGRGeometry::FromHandle(hOther));
5706 : }
5707 :
5708 : /************************************************************************/
5709 : /* Crosses() */
5710 : /************************************************************************/
5711 :
5712 : /**
5713 : * \brief Test for crossing.
5714 : *
5715 : * Tests if this geometry and the other passed into the method are crossing.
5716 : *
5717 : * Geometry validity is not checked. In case you are unsure of the validity
5718 : * of the input geometries, call IsValid() before, otherwise the result might
5719 : * be wrong.
5720 : *
5721 : * This method is the same as the C function OGR_G_Crosses().
5722 : *
5723 : * This method is built on the GEOS library, check it for the definition
5724 : * of the geometry operation.
5725 : * If OGR is built without the GEOS library, this method will always fail,
5726 : * issuing a CPLE_NotSupported error.
5727 : *
5728 : * @param poOtherGeom the geometry to compare to this geometry.
5729 : *
5730 : * @return TRUE if they are crossing, otherwise FALSE.
5731 : */
5732 :
5733 : OGRBoolean
5734 8 : OGRGeometry::Crosses(UNUSED_PARAMETER const OGRGeometry *poOtherGeom) const
5735 :
5736 : {
5737 8 : if (IsSFCGALCompatible() || poOtherGeom->IsSFCGALCompatible())
5738 : {
5739 : #ifndef HAVE_SFCGAL
5740 :
5741 0 : CPLError(CE_Failure, CPLE_NotSupported, "SFCGAL support not enabled.");
5742 0 : return FALSE;
5743 :
5744 : #else
5745 :
5746 : sfcgal_geometry_t *poThis = OGRGeometry::OGRexportToSFCGAL(this);
5747 : if (poThis == nullptr)
5748 : return FALSE;
5749 :
5750 : sfcgal_geometry_t *poOther =
5751 : OGRGeometry::OGRexportToSFCGAL(poOtherGeom);
5752 : if (poOther == nullptr)
5753 : {
5754 : sfcgal_geometry_delete(poThis);
5755 : return FALSE;
5756 : }
5757 :
5758 : int res = sfcgal_geometry_intersects_3d(poThis, poOther);
5759 :
5760 : sfcgal_geometry_delete(poThis);
5761 : sfcgal_geometry_delete(poOther);
5762 :
5763 : return (res == 1) ? TRUE : FALSE;
5764 :
5765 : #endif
5766 : }
5767 :
5768 : else
5769 : {
5770 :
5771 : #ifndef HAVE_GEOS
5772 :
5773 : CPLError(CE_Failure, CPLE_NotSupported, "GEOS support not enabled.");
5774 : return FALSE;
5775 :
5776 : #else
5777 8 : return OGRGEOSBooleanPredicate(this, poOtherGeom, GEOSCrosses_r);
5778 : #endif /* HAVE_GEOS */
5779 : }
5780 : }
5781 :
5782 : /************************************************************************/
5783 : /* OGR_G_Crosses() */
5784 : /************************************************************************/
5785 : /**
5786 : * \brief Test for crossing.
5787 : *
5788 : * Tests if this geometry and the other geometry are crossing.
5789 : *
5790 : * Geometry validity is not checked. In case you are unsure of the validity
5791 : * of the input geometries, call IsValid() before, otherwise the result might
5792 : * be wrong.
5793 : *
5794 : * This function is the same as the C++ method OGRGeometry::Crosses().
5795 : *
5796 : * This function is built on the GEOS library, check it for the definition
5797 : * of the geometry operation.
5798 : * If OGR is built without the GEOS library, this function will always fail,
5799 : * issuing a CPLE_NotSupported error.
5800 : *
5801 : * @param hThis the geometry to compare.
5802 : * @param hOther the other geometry to compare.
5803 : *
5804 : * @return TRUE if they are crossing, otherwise FALSE.
5805 : */
5806 :
5807 8 : int OGR_G_Crosses(OGRGeometryH hThis, OGRGeometryH hOther)
5808 :
5809 : {
5810 8 : VALIDATE_POINTER1(hThis, "OGR_G_Crosses", FALSE);
5811 :
5812 16 : return OGRGeometry::FromHandle(hThis)->Crosses(
5813 8 : OGRGeometry::FromHandle(hOther));
5814 : }
5815 :
5816 : /************************************************************************/
5817 : /* Within() */
5818 : /************************************************************************/
5819 :
5820 : /**
5821 : * \brief Test for containment.
5822 : *
5823 : * Tests if actual geometry object is within the passed geometry.
5824 : *
5825 : * Geometry validity is not checked. In case you are unsure of the validity
5826 : * of the input geometries, call IsValid() before, otherwise the result might
5827 : * be wrong.
5828 : *
5829 : * This method is the same as the C function OGR_G_Within().
5830 : *
5831 : * This method is built on the GEOS library, check it for the definition
5832 : * of the geometry operation.
5833 : * If OGR is built without the GEOS library, this method will always fail,
5834 : * issuing a CPLE_NotSupported error.
5835 : *
5836 : * @param poOtherGeom the geometry to compare to this geometry.
5837 : *
5838 : * @return TRUE if poOtherGeom is within this geometry, otherwise FALSE.
5839 : */
5840 :
5841 : OGRBoolean
5842 21203 : OGRGeometry::Within(UNUSED_IF_NO_GEOS const OGRGeometry *poOtherGeom) const
5843 :
5844 : {
5845 : #ifndef HAVE_GEOS
5846 :
5847 : CPLError(CE_Failure, CPLE_NotSupported, "GEOS support not enabled.");
5848 : return FALSE;
5849 :
5850 : #else
5851 21203 : return OGRGEOSBooleanPredicate(this, poOtherGeom, GEOSWithin_r);
5852 : #endif // HAVE_GEOS
5853 : }
5854 :
5855 : /************************************************************************/
5856 : /* OGR_G_Within() */
5857 : /************************************************************************/
5858 :
5859 : /**
5860 : * \brief Test for containment.
5861 : *
5862 : * Tests if this geometry is within the other geometry.
5863 : *
5864 : * Geometry validity is not checked. In case you are unsure of the validity
5865 : * of the input geometries, call IsValid() before, otherwise the result might
5866 : * be wrong.
5867 : *
5868 : * This function is the same as the C++ method OGRGeometry::Within().
5869 : *
5870 : * This function is built on the GEOS library, check it for the definition
5871 : * of the geometry operation.
5872 : * If OGR is built without the GEOS library, this function will always fail,
5873 : * issuing a CPLE_NotSupported error.
5874 : *
5875 : * @param hThis the geometry to compare.
5876 : * @param hOther the other geometry to compare.
5877 : *
5878 : * @return TRUE if hThis is within hOther, otherwise FALSE.
5879 : */
5880 6167 : int OGR_G_Within(OGRGeometryH hThis, OGRGeometryH hOther)
5881 :
5882 : {
5883 6167 : VALIDATE_POINTER1(hThis, "OGR_G_Within", FALSE);
5884 :
5885 12334 : return OGRGeometry::FromHandle(hThis)->Within(
5886 6167 : OGRGeometry::FromHandle(hOther));
5887 : }
5888 :
5889 : /************************************************************************/
5890 : /* Contains() */
5891 : /************************************************************************/
5892 :
5893 : /**
5894 : * \brief Test for containment.
5895 : *
5896 : * Tests if actual geometry object contains the passed geometry.
5897 : *
5898 : * Geometry validity is not checked. In case you are unsure of the validity
5899 : * of the input geometries, call IsValid() before, otherwise the result might
5900 : * be wrong.
5901 : *
5902 : * This method is the same as the C function OGR_G_Contains().
5903 : *
5904 : * This method is built on the GEOS library, check it for the definition
5905 : * of the geometry operation.
5906 : * If OGR is built without the GEOS library, this method will always fail,
5907 : * issuing a CPLE_NotSupported error.
5908 : *
5909 : * @param poOtherGeom the geometry to compare to this geometry.
5910 : *
5911 : * @return TRUE if poOtherGeom contains this geometry, otherwise FALSE.
5912 : */
5913 :
5914 : OGRBoolean
5915 44 : OGRGeometry::Contains(UNUSED_IF_NO_GEOS const OGRGeometry *poOtherGeom) const
5916 :
5917 : {
5918 : #ifndef HAVE_GEOS
5919 :
5920 : CPLError(CE_Failure, CPLE_NotSupported, "GEOS support not enabled.");
5921 : return FALSE;
5922 :
5923 : #else
5924 44 : return OGRGEOSBooleanPredicate(this, poOtherGeom, GEOSContains_r);
5925 : #endif // HAVE_GEOS
5926 : }
5927 :
5928 : /************************************************************************/
5929 : /* OGR_G_Contains() */
5930 : /************************************************************************/
5931 :
5932 : /**
5933 : * \brief Test for containment.
5934 : *
5935 : * Tests if this geometry contains the other geometry.
5936 : *
5937 : * Geometry validity is not checked. In case you are unsure of the validity
5938 : * of the input geometries, call IsValid() before, otherwise the result might
5939 : * be wrong.
5940 : *
5941 : * This function is the same as the C++ method OGRGeometry::Contains().
5942 : *
5943 : * This function is built on the GEOS library, check it for the definition
5944 : * of the geometry operation.
5945 : * If OGR is built without the GEOS library, this function will always fail,
5946 : * issuing a CPLE_NotSupported error.
5947 : *
5948 : * @param hThis the geometry to compare.
5949 : * @param hOther the other geometry to compare.
5950 : *
5951 : * @return TRUE if hThis contains hOther geometry, otherwise FALSE.
5952 : */
5953 15 : int OGR_G_Contains(OGRGeometryH hThis, OGRGeometryH hOther)
5954 :
5955 : {
5956 15 : VALIDATE_POINTER1(hThis, "OGR_G_Contains", FALSE);
5957 :
5958 30 : return OGRGeometry::FromHandle(hThis)->Contains(
5959 15 : OGRGeometry::FromHandle(hOther));
5960 : }
5961 :
5962 : /************************************************************************/
5963 : /* Overlaps() */
5964 : /************************************************************************/
5965 :
5966 : /**
5967 : * \brief Test for overlap.
5968 : *
5969 : * Tests if this geometry and the other passed into the method overlap, that is
5970 : * their intersection has a non-zero area.
5971 : *
5972 : * Geometry validity is not checked. In case you are unsure of the validity
5973 : * of the input geometries, call IsValid() before, otherwise the result might
5974 : * be wrong.
5975 : *
5976 : * This method is the same as the C function OGR_G_Overlaps().
5977 : *
5978 : * This method is built on the GEOS library, check it for the definition
5979 : * of the geometry operation.
5980 : * If OGR is built without the GEOS library, this method will always fail,
5981 : * issuing a CPLE_NotSupported error.
5982 : *
5983 : * @param poOtherGeom the geometry to compare to this geometry.
5984 : *
5985 : * @return TRUE if they are overlapping, otherwise FALSE.
5986 : */
5987 :
5988 : OGRBoolean
5989 7 : OGRGeometry::Overlaps(UNUSED_IF_NO_GEOS const OGRGeometry *poOtherGeom) const
5990 :
5991 : {
5992 : #ifndef HAVE_GEOS
5993 :
5994 : CPLError(CE_Failure, CPLE_NotSupported, "GEOS support not enabled.");
5995 : return FALSE;
5996 :
5997 : #else
5998 7 : return OGRGEOSBooleanPredicate(this, poOtherGeom, GEOSOverlaps_r);
5999 : #endif // HAVE_GEOS
6000 : }
6001 :
6002 : /************************************************************************/
6003 : /* OGR_G_Overlaps() */
6004 : /************************************************************************/
6005 : /**
6006 : * \brief Test for overlap.
6007 : *
6008 : * Tests if this geometry and the other geometry overlap, that is their
6009 : * intersection has a non-zero area.
6010 : *
6011 : * Geometry validity is not checked. In case you are unsure of the validity
6012 : * of the input geometries, call IsValid() before, otherwise the result might
6013 : * be wrong.
6014 : *
6015 : * This function is the same as the C++ method OGRGeometry::Overlaps().
6016 : *
6017 : * This function is built on the GEOS library, check it for the definition
6018 : * of the geometry operation.
6019 : * If OGR is built without the GEOS library, this function will always fail,
6020 : * issuing a CPLE_NotSupported error.
6021 : *
6022 : * @param hThis the geometry to compare.
6023 : * @param hOther the other geometry to compare.
6024 : *
6025 : * @return TRUE if they are overlapping, otherwise FALSE.
6026 : */
6027 :
6028 7 : int OGR_G_Overlaps(OGRGeometryH hThis, OGRGeometryH hOther)
6029 :
6030 : {
6031 7 : VALIDATE_POINTER1(hThis, "OGR_G_Overlaps", FALSE);
6032 :
6033 14 : return OGRGeometry::FromHandle(hThis)->Overlaps(
6034 7 : OGRGeometry::FromHandle(hOther));
6035 : }
6036 :
6037 : /************************************************************************/
6038 : /* closeRings() */
6039 : /************************************************************************/
6040 :
6041 : /**
6042 : * \brief Force rings to be closed.
6043 : *
6044 : * If this geometry, or any contained geometries has polygon rings that
6045 : * are not closed, they will be closed by adding the starting point at
6046 : * the end.
6047 : */
6048 :
6049 1265 : void OGRGeometry::closeRings()
6050 : {
6051 1265 : }
6052 :
6053 : /************************************************************************/
6054 : /* OGR_G_CloseRings() */
6055 : /************************************************************************/
6056 :
6057 : /**
6058 : * \brief Force rings to be closed.
6059 : *
6060 : * If this geometry, or any contained geometries has polygon rings that
6061 : * are not closed, they will be closed by adding the starting point at
6062 : * the end.
6063 : *
6064 : * @param hGeom handle to the geometry.
6065 : */
6066 :
6067 6 : void OGR_G_CloseRings(OGRGeometryH hGeom)
6068 :
6069 : {
6070 6 : VALIDATE_POINTER0(hGeom, "OGR_G_CloseRings");
6071 :
6072 6 : OGRGeometry::FromHandle(hGeom)->closeRings();
6073 : }
6074 :
6075 : /************************************************************************/
6076 : /* Centroid() */
6077 : /************************************************************************/
6078 :
6079 : /**
6080 : * \brief Compute the geometry centroid.
6081 : *
6082 : * The centroid location is applied to the passed in OGRPoint object.
6083 : * The centroid is not necessarily within the geometry.
6084 : *
6085 : * This method relates to the SFCOM ISurface::get_Centroid() method
6086 : * however the current implementation based on GEOS can operate on other
6087 : * geometry types such as multipoint, linestring, geometrycollection such as
6088 : * multipolygons.
6089 : * OGC SF SQL 1.1 defines the operation for surfaces (polygons).
6090 : * SQL/MM-Part 3 defines the operation for surfaces and multisurfaces
6091 : * (multipolygons).
6092 : *
6093 : * This function is the same as the C function OGR_G_Centroid().
6094 : *
6095 : * This function is built on the GEOS library, check it for the definition
6096 : * of the geometry operation.
6097 : * If OGR is built without the GEOS library, this function will always fail,
6098 : * issuing a CPLE_NotSupported error.
6099 : *
6100 : * @return OGRERR_NONE on success or OGRERR_FAILURE on error.
6101 : *
6102 : * @since OGR 1.8.0 as a OGRGeometry method (previously was restricted
6103 : * to OGRPolygon)
6104 : */
6105 :
6106 5 : OGRErr OGRGeometry::Centroid(OGRPoint *poPoint) const
6107 :
6108 : {
6109 5 : if (poPoint == nullptr)
6110 0 : return OGRERR_FAILURE;
6111 :
6112 : #ifndef HAVE_GEOS
6113 : CPLError(CE_Failure, CPLE_NotSupported, "GEOS support not enabled.");
6114 : return OGRERR_FAILURE;
6115 :
6116 : #else
6117 :
6118 5 : GEOSContextHandle_t hGEOSCtxt = createGEOSContext();
6119 : GEOSGeom hThisGeosGeom =
6120 5 : exportToGEOS(hGEOSCtxt, /* bRemoveEmptyParts = */ true);
6121 :
6122 5 : if (hThisGeosGeom != nullptr)
6123 : {
6124 5 : GEOSGeom hOtherGeosGeom = GEOSGetCentroid_r(hGEOSCtxt, hThisGeosGeom);
6125 5 : GEOSGeom_destroy_r(hGEOSCtxt, hThisGeosGeom);
6126 :
6127 5 : if (hOtherGeosGeom == nullptr)
6128 : {
6129 0 : freeGEOSContext(hGEOSCtxt);
6130 0 : return OGRERR_FAILURE;
6131 : }
6132 :
6133 : OGRGeometry *poCentroidGeom =
6134 5 : OGRGeometryFactory::createFromGEOS(hGEOSCtxt, hOtherGeosGeom);
6135 :
6136 5 : GEOSGeom_destroy_r(hGEOSCtxt, hOtherGeosGeom);
6137 :
6138 5 : if (poCentroidGeom == nullptr)
6139 : {
6140 0 : freeGEOSContext(hGEOSCtxt);
6141 0 : return OGRERR_FAILURE;
6142 : }
6143 5 : if (wkbFlatten(poCentroidGeom->getGeometryType()) != wkbPoint)
6144 : {
6145 0 : delete poCentroidGeom;
6146 0 : freeGEOSContext(hGEOSCtxt);
6147 0 : return OGRERR_FAILURE;
6148 : }
6149 :
6150 5 : if (getSpatialReference() != nullptr)
6151 0 : poCentroidGeom->assignSpatialReference(getSpatialReference());
6152 :
6153 5 : OGRPoint *poCentroid = poCentroidGeom->toPoint();
6154 :
6155 5 : if (!poCentroid->IsEmpty())
6156 : {
6157 4 : poPoint->setX(poCentroid->getX());
6158 4 : poPoint->setY(poCentroid->getY());
6159 : }
6160 : else
6161 : {
6162 1 : poPoint->empty();
6163 : }
6164 :
6165 5 : delete poCentroidGeom;
6166 :
6167 5 : freeGEOSContext(hGEOSCtxt);
6168 5 : return OGRERR_NONE;
6169 : }
6170 : else
6171 : {
6172 0 : freeGEOSContext(hGEOSCtxt);
6173 0 : return OGRERR_FAILURE;
6174 : }
6175 :
6176 : #endif // HAVE_GEOS
6177 : }
6178 :
6179 : /************************************************************************/
6180 : /* OGR_G_Centroid() */
6181 : /************************************************************************/
6182 :
6183 : /**
6184 : * \brief Compute the geometry centroid.
6185 : *
6186 : * The centroid location is applied to the passed in OGRPoint object.
6187 : * The centroid is not necessarily within the geometry.
6188 : *
6189 : * This method relates to the SFCOM ISurface::get_Centroid() method
6190 : * however the current implementation based on GEOS can operate on other
6191 : * geometry types such as multipoint, linestring, geometrycollection such as
6192 : * multipolygons.
6193 : * OGC SF SQL 1.1 defines the operation for surfaces (polygons).
6194 : * SQL/MM-Part 3 defines the operation for surfaces and multisurfaces
6195 : * (multipolygons).
6196 : *
6197 : * This function is the same as the C++ method OGRGeometry::Centroid().
6198 : *
6199 : * This function is built on the GEOS library, check it for the definition
6200 : * of the geometry operation.
6201 : * If OGR is built without the GEOS library, this function will always fail,
6202 : * issuing a CPLE_NotSupported error.
6203 : *
6204 : * @return OGRERR_NONE on success or OGRERR_FAILURE on error.
6205 : */
6206 :
6207 5 : int OGR_G_Centroid(OGRGeometryH hGeom, OGRGeometryH hCentroidPoint)
6208 :
6209 : {
6210 5 : VALIDATE_POINTER1(hGeom, "OGR_G_Centroid", OGRERR_FAILURE);
6211 :
6212 5 : OGRGeometry *poCentroidGeom = OGRGeometry::FromHandle(hCentroidPoint);
6213 5 : if (poCentroidGeom == nullptr)
6214 0 : return OGRERR_FAILURE;
6215 5 : if (wkbFlatten(poCentroidGeom->getGeometryType()) != wkbPoint)
6216 : {
6217 0 : CPLError(CE_Failure, CPLE_AppDefined,
6218 : "Passed wrong geometry type as centroid argument.");
6219 0 : return OGRERR_FAILURE;
6220 : }
6221 :
6222 5 : return OGRGeometry::FromHandle(hGeom)->Centroid(poCentroidGeom->toPoint());
6223 : }
6224 :
6225 : /************************************************************************/
6226 : /* OGR_G_PointOnSurface() */
6227 : /************************************************************************/
6228 :
6229 : /**
6230 : * \brief Returns a point guaranteed to lie on the surface.
6231 : *
6232 : * This method relates to the SFCOM ISurface::get_PointOnSurface() method
6233 : * however the current implementation based on GEOS can operate on other
6234 : * geometry types than the types that are supported by SQL/MM-Part 3 :
6235 : * surfaces (polygons) and multisurfaces (multipolygons).
6236 : *
6237 : * This method is built on the GEOS library, check it for the definition
6238 : * of the geometry operation.
6239 : * If OGR is built without the GEOS library, this method will always fail,
6240 : * issuing a CPLE_NotSupported error.
6241 : *
6242 : * @param hGeom the geometry to operate on.
6243 : * @return a new geometry to be freed by the caller with OGR_G_DestroyGeometry,
6244 : * or NULL if an error occurs.
6245 : *
6246 : * @since OGR 1.10
6247 : */
6248 :
6249 4 : OGRGeometryH OGR_G_PointOnSurface(OGRGeometryH hGeom)
6250 :
6251 : {
6252 4 : VALIDATE_POINTER1(hGeom, "OGR_G_PointOnSurface", nullptr);
6253 :
6254 : #ifndef HAVE_GEOS
6255 : CPLError(CE_Failure, CPLE_NotSupported, "GEOS support not enabled.");
6256 : return nullptr;
6257 : #else
6258 :
6259 4 : OGRGeometry *poThis = OGRGeometry::FromHandle(hGeom);
6260 :
6261 4 : GEOSContextHandle_t hGEOSCtxt = OGRGeometry::createGEOSContext();
6262 4 : GEOSGeom hThisGeosGeom = poThis->exportToGEOS(hGEOSCtxt);
6263 :
6264 4 : if (hThisGeosGeom != nullptr)
6265 : {
6266 : GEOSGeom hOtherGeosGeom =
6267 4 : GEOSPointOnSurface_r(hGEOSCtxt, hThisGeosGeom);
6268 4 : GEOSGeom_destroy_r(hGEOSCtxt, hThisGeosGeom);
6269 :
6270 4 : if (hOtherGeosGeom == nullptr)
6271 : {
6272 0 : OGRGeometry::freeGEOSContext(hGEOSCtxt);
6273 0 : return nullptr;
6274 : }
6275 :
6276 : OGRGeometry *poInsidePointGeom =
6277 4 : OGRGeometryFactory::createFromGEOS(hGEOSCtxt, hOtherGeosGeom);
6278 :
6279 4 : GEOSGeom_destroy_r(hGEOSCtxt, hOtherGeosGeom);
6280 :
6281 4 : if (poInsidePointGeom == nullptr)
6282 : {
6283 0 : OGRGeometry::freeGEOSContext(hGEOSCtxt);
6284 0 : return nullptr;
6285 : }
6286 4 : if (wkbFlatten(poInsidePointGeom->getGeometryType()) != wkbPoint)
6287 : {
6288 0 : delete poInsidePointGeom;
6289 0 : OGRGeometry::freeGEOSContext(hGEOSCtxt);
6290 0 : return nullptr;
6291 : }
6292 :
6293 4 : if (poThis->getSpatialReference() != nullptr)
6294 0 : poInsidePointGeom->assignSpatialReference(
6295 0 : poThis->getSpatialReference());
6296 :
6297 4 : OGRGeometry::freeGEOSContext(hGEOSCtxt);
6298 4 : return OGRGeometry::ToHandle(poInsidePointGeom);
6299 : }
6300 :
6301 0 : OGRGeometry::freeGEOSContext(hGEOSCtxt);
6302 0 : return nullptr;
6303 : #endif
6304 : }
6305 :
6306 : /************************************************************************/
6307 : /* PointOnSurfaceInternal() */
6308 : /************************************************************************/
6309 :
6310 : //! @cond Doxygen_Suppress
6311 0 : OGRErr OGRGeometry::PointOnSurfaceInternal(OGRPoint *poPoint) const
6312 : {
6313 0 : if (poPoint == nullptr || poPoint->IsEmpty())
6314 0 : return OGRERR_FAILURE;
6315 :
6316 0 : OGRGeometryH hInsidePoint = OGR_G_PointOnSurface(
6317 : OGRGeometry::ToHandle(const_cast<OGRGeometry *>(this)));
6318 0 : if (hInsidePoint == nullptr)
6319 0 : return OGRERR_FAILURE;
6320 :
6321 0 : OGRPoint *poInsidePoint = OGRGeometry::FromHandle(hInsidePoint)->toPoint();
6322 0 : if (poInsidePoint->IsEmpty())
6323 : {
6324 0 : poPoint->empty();
6325 : }
6326 : else
6327 : {
6328 0 : poPoint->setX(poInsidePoint->getX());
6329 0 : poPoint->setY(poInsidePoint->getY());
6330 : }
6331 :
6332 0 : OGR_G_DestroyGeometry(hInsidePoint);
6333 :
6334 0 : return OGRERR_NONE;
6335 : }
6336 :
6337 : //! @endcond
6338 :
6339 : /************************************************************************/
6340 : /* Simplify() */
6341 : /************************************************************************/
6342 :
6343 : /**
6344 : * \brief Simplify the geometry.
6345 : *
6346 : * This function is the same as the C function OGR_G_Simplify().
6347 : *
6348 : * This function is built on the GEOS library, check it for the definition
6349 : * of the geometry operation.
6350 : * If OGR is built without the GEOS library, this function will always fail,
6351 : * issuing a CPLE_NotSupported error.
6352 : *
6353 : * @param dTolerance the distance tolerance for the simplification.
6354 : *
6355 : * @return a new geometry to be freed by the caller, or NULL if an error occurs.
6356 : *
6357 : * @since OGR 1.8.0
6358 : */
6359 :
6360 33 : OGRGeometry *OGRGeometry::Simplify(UNUSED_IF_NO_GEOS double dTolerance) const
6361 :
6362 : {
6363 : #ifndef HAVE_GEOS
6364 :
6365 : CPLError(CE_Failure, CPLE_NotSupported, "GEOS support not enabled.");
6366 : return nullptr;
6367 :
6368 : #else
6369 33 : OGRGeometry *poOGRProduct = nullptr;
6370 :
6371 33 : GEOSContextHandle_t hGEOSCtxt = createGEOSContext();
6372 33 : GEOSGeom hThisGeosGeom = exportToGEOS(hGEOSCtxt);
6373 33 : if (hThisGeosGeom != nullptr)
6374 : {
6375 : GEOSGeom hGeosProduct =
6376 33 : GEOSSimplify_r(hGEOSCtxt, hThisGeosGeom, dTolerance);
6377 33 : GEOSGeom_destroy_r(hGEOSCtxt, hThisGeosGeom);
6378 : poOGRProduct =
6379 33 : BuildGeometryFromGEOS(hGEOSCtxt, hGeosProduct, this, nullptr);
6380 : }
6381 33 : freeGEOSContext(hGEOSCtxt);
6382 33 : return poOGRProduct;
6383 :
6384 : #endif // HAVE_GEOS
6385 : }
6386 :
6387 : /************************************************************************/
6388 : /* OGR_G_Simplify() */
6389 : /************************************************************************/
6390 :
6391 : /**
6392 : * \brief Compute a simplified geometry.
6393 : *
6394 : * This function is the same as the C++ method OGRGeometry::Simplify().
6395 : *
6396 : * This function is built on the GEOS library, check it for the definition
6397 : * of the geometry operation.
6398 : * If OGR is built without the GEOS library, this function will always fail,
6399 : * issuing a CPLE_NotSupported error.
6400 : *
6401 : * @param hThis the geometry.
6402 : * @param dTolerance the distance tolerance for the simplification.
6403 : *
6404 : * @return a new geometry to be freed by the caller with OGR_G_DestroyGeometry,
6405 : * or NULL if an error occurs.
6406 : *
6407 : * @since OGR 1.8.0
6408 : */
6409 :
6410 1 : OGRGeometryH OGR_G_Simplify(OGRGeometryH hThis, double dTolerance)
6411 :
6412 : {
6413 1 : VALIDATE_POINTER1(hThis, "OGR_G_Simplify", nullptr);
6414 1 : return OGRGeometry::ToHandle(
6415 2 : OGRGeometry::FromHandle(hThis)->Simplify(dTolerance));
6416 : }
6417 :
6418 : /************************************************************************/
6419 : /* SimplifyPreserveTopology() */
6420 : /************************************************************************/
6421 :
6422 : /**
6423 : * \brief Simplify the geometry while preserving topology.
6424 : *
6425 : * This function is the same as the C function OGR_G_SimplifyPreserveTopology().
6426 : *
6427 : * This function is built on the GEOS library, check it for the definition
6428 : * of the geometry operation.
6429 : * If OGR is built without the GEOS library, this function will always fail,
6430 : * issuing a CPLE_NotSupported error.
6431 : *
6432 : * @param dTolerance the distance tolerance for the simplification.
6433 : *
6434 : * @return a new geometry to be freed by the caller, or NULL if an error occurs.
6435 : *
6436 : * @since OGR 1.9.0
6437 : */
6438 :
6439 : OGRGeometry *
6440 8 : OGRGeometry::SimplifyPreserveTopology(UNUSED_IF_NO_GEOS double dTolerance) const
6441 :
6442 : {
6443 : #ifndef HAVE_GEOS
6444 :
6445 : CPLError(CE_Failure, CPLE_NotSupported, "GEOS support not enabled.");
6446 : return nullptr;
6447 :
6448 : #else
6449 8 : OGRGeometry *poOGRProduct = nullptr;
6450 :
6451 8 : GEOSContextHandle_t hGEOSCtxt = createGEOSContext();
6452 8 : GEOSGeom hThisGeosGeom = exportToGEOS(hGEOSCtxt);
6453 8 : if (hThisGeosGeom != nullptr)
6454 : {
6455 8 : GEOSGeom hGeosProduct = GEOSTopologyPreserveSimplify_r(
6456 : hGEOSCtxt, hThisGeosGeom, dTolerance);
6457 8 : GEOSGeom_destroy_r(hGEOSCtxt, hThisGeosGeom);
6458 : poOGRProduct =
6459 8 : BuildGeometryFromGEOS(hGEOSCtxt, hGeosProduct, this, nullptr);
6460 : }
6461 8 : freeGEOSContext(hGEOSCtxt);
6462 8 : return poOGRProduct;
6463 :
6464 : #endif // HAVE_GEOS
6465 : }
6466 :
6467 : /************************************************************************/
6468 : /* OGR_G_SimplifyPreserveTopology() */
6469 : /************************************************************************/
6470 :
6471 : /**
6472 : * \brief Simplify the geometry while preserving topology.
6473 : *
6474 : * This function is the same as the C++ method
6475 : * OGRGeometry::SimplifyPreserveTopology().
6476 : *
6477 : * This function is built on the GEOS library, check it for the definition
6478 : * of the geometry operation.
6479 : * If OGR is built without the GEOS library, this function will always fail,
6480 : * issuing a CPLE_NotSupported error.
6481 : *
6482 : * @param hThis the geometry.
6483 : * @param dTolerance the distance tolerance for the simplification.
6484 : *
6485 : * @return a new geometry to be freed by the caller with OGR_G_DestroyGeometry,
6486 : * or NULL if an error occurs.
6487 : *
6488 : * @since OGR 1.9.0
6489 : */
6490 :
6491 1 : OGRGeometryH OGR_G_SimplifyPreserveTopology(OGRGeometryH hThis,
6492 : double dTolerance)
6493 :
6494 : {
6495 1 : VALIDATE_POINTER1(hThis, "OGR_G_SimplifyPreserveTopology", nullptr);
6496 1 : return OGRGeometry::ToHandle(
6497 1 : OGRGeometry::FromHandle(hThis)->SimplifyPreserveTopology(dTolerance));
6498 : }
6499 :
6500 : /************************************************************************/
6501 : /* roundCoordinates() */
6502 : /************************************************************************/
6503 :
6504 : /** Round coordinates of the geometry to the specified precision.
6505 : *
6506 : * Note that this is not the same as OGRGeometry::SetPrecision(). The later
6507 : * will return valid geometries, whereas roundCoordinates() does not make
6508 : * such guarantee and may return geometries with invalidities, if they are
6509 : * not compatible of the specified precision. roundCoordinates() supports
6510 : * curve geometries, whereas SetPrecision() does not currently.
6511 : *
6512 : * One use case for roundCoordinates() is to undo the effect of
6513 : * quantizeCoordinates().
6514 : *
6515 : * @param sPrecision Contains the precision requirements.
6516 : * @since GDAL 3.9
6517 : */
6518 39 : void OGRGeometry::roundCoordinates(const OGRGeomCoordinatePrecision &sPrecision)
6519 : {
6520 : struct Rounder : public OGRDefaultGeometryVisitor
6521 : {
6522 : const OGRGeomCoordinatePrecision &m_precision;
6523 : const double m_invXYResolution;
6524 : const double m_invZResolution;
6525 : const double m_invMResolution;
6526 :
6527 39 : explicit Rounder(const OGRGeomCoordinatePrecision &sPrecisionIn)
6528 39 : : m_precision(sPrecisionIn),
6529 39 : m_invXYResolution(m_precision.dfXYResolution !=
6530 : OGRGeomCoordinatePrecision::UNKNOWN
6531 39 : ? 1.0 / m_precision.dfXYResolution
6532 : : 0.0),
6533 39 : m_invZResolution(m_precision.dfZResolution !=
6534 : OGRGeomCoordinatePrecision::UNKNOWN
6535 39 : ? 1.0 / m_precision.dfZResolution
6536 : : 0.0),
6537 39 : m_invMResolution(m_precision.dfMResolution !=
6538 : OGRGeomCoordinatePrecision::UNKNOWN
6539 39 : ? 1.0 / m_precision.dfMResolution
6540 117 : : 0.0)
6541 : {
6542 39 : }
6543 :
6544 : using OGRDefaultGeometryVisitor::visit;
6545 :
6546 379 : void visit(OGRPoint *poPoint) override
6547 : {
6548 379 : if (m_precision.dfXYResolution !=
6549 : OGRGeomCoordinatePrecision::UNKNOWN)
6550 : {
6551 379 : poPoint->setX(std::round(poPoint->getX() * m_invXYResolution) *
6552 379 : m_precision.dfXYResolution);
6553 379 : poPoint->setY(std::round(poPoint->getY() * m_invXYResolution) *
6554 379 : m_precision.dfXYResolution);
6555 : }
6556 758 : if (m_precision.dfZResolution !=
6557 383 : OGRGeomCoordinatePrecision::UNKNOWN &&
6558 4 : poPoint->Is3D())
6559 : {
6560 4 : poPoint->setZ(std::round(poPoint->getZ() * m_invZResolution) *
6561 4 : m_precision.dfZResolution);
6562 : }
6563 758 : if (m_precision.dfMResolution !=
6564 383 : OGRGeomCoordinatePrecision::UNKNOWN &&
6565 4 : poPoint->IsMeasured())
6566 : {
6567 4 : poPoint->setM(std::round(poPoint->getM() * m_invMResolution) *
6568 4 : m_precision.dfMResolution);
6569 : }
6570 379 : }
6571 : };
6572 :
6573 78 : Rounder rounder(sPrecision);
6574 39 : accept(&rounder);
6575 39 : }
6576 :
6577 : /************************************************************************/
6578 : /* SetPrecision() */
6579 : /************************************************************************/
6580 :
6581 : /** Set the geometry's precision, rounding all its coordinates to the precision
6582 : * grid, and making sure the geometry is still valid.
6583 : *
6584 : * This is a stronger version of roundCoordinates().
6585 : *
6586 : * Note that at time of writing GEOS does no supported curve geometries. So
6587 : * currently if this function is called on such a geometry, OGR will first call
6588 : * getLinearGeometry() on the input and getCurveGeometry() on the output, but
6589 : * that it is unlikely to yield to the expected result.
6590 : *
6591 : * This function is the same as the C function OGR_G_SetPrecision().
6592 : *
6593 : * This function is built on the GEOSGeom_setPrecision_r() function of the
6594 : * GEOS library. Check it for the definition of the geometry operation.
6595 : * If OGR is built without the GEOS library, this function will always fail,
6596 : * issuing a CPLE_NotSupported error.
6597 : *
6598 : * @param dfGridSize size of the precision grid, or 0 for FLOATING
6599 : * precision.
6600 : * @param nFlags The bitwise OR of zero, one or several of OGR_GEOS_PREC_NO_TOPO
6601 : * and OGR_GEOS_PREC_KEEP_COLLAPSED
6602 : *
6603 : * @return a new geometry to be freed by the caller, or NULL if an error occurs.
6604 : *
6605 : * @since GDAL 3.9
6606 : */
6607 :
6608 6 : OGRGeometry *OGRGeometry::SetPrecision(UNUSED_IF_NO_GEOS double dfGridSize,
6609 : UNUSED_IF_NO_GEOS int nFlags) const
6610 : {
6611 : #ifndef HAVE_GEOS
6612 : CPLError(CE_Failure, CPLE_NotSupported, "GEOS support not enabled.");
6613 : return nullptr;
6614 :
6615 : #else
6616 6 : OGRGeometry *poOGRProduct = nullptr;
6617 :
6618 6 : GEOSContextHandle_t hGEOSCtxt = createGEOSContext();
6619 6 : GEOSGeom hThisGeosGeom = exportToGEOS(hGEOSCtxt);
6620 6 : if (hThisGeosGeom != nullptr)
6621 : {
6622 6 : GEOSGeom hGeosProduct = GEOSGeom_setPrecision_r(
6623 : hGEOSCtxt, hThisGeosGeom, dfGridSize, nFlags);
6624 6 : GEOSGeom_destroy_r(hGEOSCtxt, hThisGeosGeom);
6625 : poOGRProduct =
6626 6 : BuildGeometryFromGEOS(hGEOSCtxt, hGeosProduct, this, nullptr);
6627 : }
6628 6 : freeGEOSContext(hGEOSCtxt);
6629 6 : return poOGRProduct;
6630 :
6631 : #endif // HAVE_GEOS
6632 : }
6633 :
6634 : /************************************************************************/
6635 : /* OGR_G_SetPrecision() */
6636 : /************************************************************************/
6637 :
6638 : /** Set the geometry's precision, rounding all its coordinates to the precision
6639 : * grid, and making sure the geometry is still valid.
6640 : *
6641 : * This is a stronger version of roundCoordinates().
6642 : *
6643 : * Note that at time of writing GEOS does no supported curve geometries. So
6644 : * currently if this function is called on such a geometry, OGR will first call
6645 : * getLinearGeometry() on the input and getCurveGeometry() on the output, but
6646 : * that it is unlikely to yield to the expected result.
6647 : *
6648 : * This function is the same as the C++ method OGRGeometry::SetPrecision().
6649 : *
6650 : * This function is built on the GEOSGeom_setPrecision_r() function of the
6651 : * GEOS library. Check it for the definition of the geometry operation.
6652 : * If OGR is built without the GEOS library, this function will always fail,
6653 : * issuing a CPLE_NotSupported error.
6654 : *
6655 : * @param hThis the geometry.
6656 : * @param dfGridSize size of the precision grid, or 0 for FLOATING
6657 : * precision.
6658 : * @param nFlags The bitwise OR of zero, one or several of OGR_GEOS_PREC_NO_TOPO
6659 : * and OGR_GEOS_PREC_KEEP_COLLAPSED
6660 : *
6661 : * @return a new geometry to be freed by the caller with OGR_G_DestroyGeometry,
6662 : * or NULL if an error occurs.
6663 : *
6664 : * @since GDAL 3.9
6665 : */
6666 1 : OGRGeometryH OGR_G_SetPrecision(OGRGeometryH hThis, double dfGridSize,
6667 : int nFlags)
6668 : {
6669 1 : VALIDATE_POINTER1(hThis, "OGR_G_SetPrecision", nullptr);
6670 1 : return OGRGeometry::ToHandle(
6671 1 : OGRGeometry::FromHandle(hThis)->SetPrecision(dfGridSize, nFlags));
6672 : }
6673 :
6674 : /************************************************************************/
6675 : /* DelaunayTriangulation() */
6676 : /************************************************************************/
6677 :
6678 : /**
6679 : * \brief Return a Delaunay triangulation of the vertices of the geometry.
6680 : *
6681 : * This function is the same as the C function OGR_G_DelaunayTriangulation().
6682 : *
6683 : * This function is built on the GEOS library, v3.4 or above.
6684 : * If OGR is built without the GEOS library, this function will always fail,
6685 : * issuing a CPLE_NotSupported error.
6686 : *
6687 : * @param dfTolerance optional snapping tolerance to use for improved robustness
6688 : * @param bOnlyEdges if TRUE, will return a MULTILINESTRING, otherwise it will
6689 : * return a GEOMETRYCOLLECTION containing triangular POLYGONs.
6690 : *
6691 : * @return a new geometry to be freed by the caller, or NULL if an error occurs.
6692 : *
6693 : * @since OGR 2.1
6694 : */
6695 :
6696 : #ifndef HAVE_GEOS
6697 : OGRGeometry *OGRGeometry::DelaunayTriangulation(double /*dfTolerance*/,
6698 : int /*bOnlyEdges*/) const
6699 : {
6700 : CPLError(CE_Failure, CPLE_NotSupported, "GEOS support not enabled.");
6701 : return nullptr;
6702 : }
6703 : #else
6704 1 : OGRGeometry *OGRGeometry::DelaunayTriangulation(double dfTolerance,
6705 : int bOnlyEdges) const
6706 : {
6707 1 : OGRGeometry *poOGRProduct = nullptr;
6708 :
6709 1 : GEOSContextHandle_t hGEOSCtxt = createGEOSContext();
6710 1 : GEOSGeom hThisGeosGeom = exportToGEOS(hGEOSCtxt);
6711 1 : if (hThisGeosGeom != nullptr)
6712 : {
6713 1 : GEOSGeom hGeosProduct = GEOSDelaunayTriangulation_r(
6714 : hGEOSCtxt, hThisGeosGeom, dfTolerance, bOnlyEdges);
6715 1 : GEOSGeom_destroy_r(hGEOSCtxt, hThisGeosGeom);
6716 : poOGRProduct =
6717 1 : BuildGeometryFromGEOS(hGEOSCtxt, hGeosProduct, this, nullptr);
6718 : }
6719 1 : freeGEOSContext(hGEOSCtxt);
6720 1 : return poOGRProduct;
6721 : }
6722 : #endif
6723 :
6724 : /************************************************************************/
6725 : /* OGR_G_DelaunayTriangulation() */
6726 : /************************************************************************/
6727 :
6728 : /**
6729 : * \brief Return a Delaunay triangulation of the vertices of the geometry.
6730 : *
6731 : * This function is the same as the C++ method
6732 : * OGRGeometry::DelaunayTriangulation().
6733 : *
6734 : * This function is built on the GEOS library, v3.4 or above.
6735 : * If OGR is built without the GEOS library, this function will always fail,
6736 : * issuing a CPLE_NotSupported error.
6737 : *
6738 : * @param hThis the geometry.
6739 : * @param dfTolerance optional snapping tolerance to use for improved robustness
6740 : * @param bOnlyEdges if TRUE, will return a MULTILINESTRING, otherwise it will
6741 : * return a GEOMETRYCOLLECTION containing triangular POLYGONs.
6742 : *
6743 : * @return a new geometry to be freed by the caller with OGR_G_DestroyGeometry,
6744 : * or NULL if an error occurs.
6745 : *
6746 : * @since OGR 2.1
6747 : */
6748 :
6749 1 : OGRGeometryH OGR_G_DelaunayTriangulation(OGRGeometryH hThis, double dfTolerance,
6750 : int bOnlyEdges)
6751 :
6752 : {
6753 1 : VALIDATE_POINTER1(hThis, "OGR_G_DelaunayTriangulation", nullptr);
6754 :
6755 1 : return OGRGeometry::ToHandle(
6756 1 : OGRGeometry::FromHandle(hThis)->DelaunayTriangulation(dfTolerance,
6757 2 : bOnlyEdges));
6758 : }
6759 :
6760 : /************************************************************************/
6761 : /* Polygonize() */
6762 : /************************************************************************/
6763 : /* Contributor: Alessandro Furieri, a.furieri@lqt.it */
6764 : /* Developed for Faunalia (http://www.faunalia.it) with funding from */
6765 : /* Regione Toscana - Settore SISTEMA INFORMATIVO TERRITORIALE ED */
6766 : /* AMBIENTALE */
6767 : /************************************************************************/
6768 :
6769 : /**
6770 : * \brief Polygonizes a set of sparse edges.
6771 : *
6772 : * A new geometry object is created and returned containing a collection
6773 : * of reassembled Polygons: NULL will be returned if the input collection
6774 : * doesn't corresponds to a MultiLinestring, or when reassembling Edges
6775 : * into Polygons is impossible due to topological inconsistencies.
6776 : *
6777 : * This method is the same as the C function OGR_G_Polygonize().
6778 : *
6779 : * This method is built on the GEOS library, check it for the definition
6780 : * of the geometry operation.
6781 : * If OGR is built without the GEOS library, this method will always fail,
6782 : * issuing a CPLE_NotSupported error.
6783 : *
6784 : * @return a new geometry to be freed by the caller, or NULL if an error occurs.
6785 : *
6786 : * @since OGR 1.9.0
6787 : */
6788 :
6789 69 : OGRGeometry *OGRGeometry::Polygonize() const
6790 :
6791 : {
6792 : #ifndef HAVE_GEOS
6793 :
6794 : CPLError(CE_Failure, CPLE_NotSupported, "GEOS support not enabled.");
6795 : return nullptr;
6796 :
6797 : #else
6798 :
6799 69 : const OGRGeometryCollection *poColl = nullptr;
6800 137 : if (wkbFlatten(getGeometryType()) == wkbGeometryCollection ||
6801 68 : wkbFlatten(getGeometryType()) == wkbMultiLineString)
6802 68 : poColl = toGeometryCollection();
6803 : else
6804 1 : return nullptr;
6805 :
6806 68 : const int nCount = poColl->getNumGeometries();
6807 :
6808 68 : OGRGeometry *poPolygsOGRGeom = nullptr;
6809 68 : bool bError = false;
6810 :
6811 68 : GEOSContextHandle_t hGEOSCtxt = createGEOSContext();
6812 :
6813 68 : GEOSGeom *pahGeosGeomList = new GEOSGeom[nCount];
6814 425 : for (int ig = 0; ig < nCount; ig++)
6815 : {
6816 357 : GEOSGeom hGeosGeom = nullptr;
6817 357 : const OGRGeometry *poChild = poColl->getGeometryRef(ig);
6818 714 : if (poChild == nullptr ||
6819 357 : wkbFlatten(poChild->getGeometryType()) != wkbLineString)
6820 1 : bError = true;
6821 : else
6822 : {
6823 356 : hGeosGeom = poChild->exportToGEOS(hGEOSCtxt);
6824 356 : if (hGeosGeom == nullptr)
6825 0 : bError = true;
6826 : }
6827 357 : pahGeosGeomList[ig] = hGeosGeom;
6828 : }
6829 :
6830 68 : if (!bError)
6831 : {
6832 : GEOSGeom hGeosPolygs =
6833 67 : GEOSPolygonize_r(hGEOSCtxt, pahGeosGeomList, nCount);
6834 :
6835 : poPolygsOGRGeom =
6836 67 : BuildGeometryFromGEOS(hGEOSCtxt, hGeosPolygs, this, nullptr);
6837 : }
6838 :
6839 425 : for (int ig = 0; ig < nCount; ig++)
6840 : {
6841 357 : GEOSGeom hGeosGeom = pahGeosGeomList[ig];
6842 357 : if (hGeosGeom != nullptr)
6843 356 : GEOSGeom_destroy_r(hGEOSCtxt, hGeosGeom);
6844 : }
6845 68 : delete[] pahGeosGeomList;
6846 68 : freeGEOSContext(hGEOSCtxt);
6847 :
6848 68 : return poPolygsOGRGeom;
6849 :
6850 : #endif // HAVE_GEOS
6851 : }
6852 :
6853 : /************************************************************************/
6854 : /* OGR_G_Polygonize() */
6855 : /************************************************************************/
6856 : /**
6857 : * \brief Polygonizes a set of sparse edges.
6858 : *
6859 : * A new geometry object is created and returned containing a collection
6860 : * of reassembled Polygons: NULL will be returned if the input collection
6861 : * doesn't corresponds to a MultiLinestring, or when reassembling Edges
6862 : * into Polygons is impossible due to topological inconsistencies.
6863 : *
6864 : * This function is the same as the C++ method OGRGeometry::Polygonize().
6865 : *
6866 : * This function is built on the GEOS library, check it for the definition
6867 : * of the geometry operation.
6868 : * If OGR is built without the GEOS library, this function will always fail,
6869 : * issuing a CPLE_NotSupported error.
6870 : *
6871 : * @param hTarget The Geometry to be polygonized.
6872 : *
6873 : * @return a new geometry to be freed by the caller with OGR_G_DestroyGeometry,
6874 : * or NULL if an error occurs.
6875 : *
6876 : * @since OGR 1.9.0
6877 : */
6878 :
6879 3 : OGRGeometryH OGR_G_Polygonize(OGRGeometryH hTarget)
6880 :
6881 : {
6882 3 : VALIDATE_POINTER1(hTarget, "OGR_G_Polygonize", nullptr);
6883 :
6884 3 : return OGRGeometry::ToHandle(
6885 6 : OGRGeometry::FromHandle(hTarget)->Polygonize());
6886 : }
6887 :
6888 : /************************************************************************/
6889 : /* swapXY() */
6890 : /************************************************************************/
6891 :
6892 : /**
6893 : * \brief Swap x and y coordinates.
6894 : *
6895 : * @since OGR 1.8.0
6896 : */
6897 :
6898 0 : void OGRGeometry::swapXY()
6899 :
6900 : {
6901 0 : }
6902 :
6903 : /************************************************************************/
6904 : /* swapXY() */
6905 : /************************************************************************/
6906 :
6907 : /**
6908 : * \brief Swap x and y coordinates.
6909 : *
6910 : * @param hGeom geometry.
6911 : * @since OGR 2.3.0
6912 : */
6913 :
6914 2 : void OGR_G_SwapXY(OGRGeometryH hGeom)
6915 : {
6916 2 : VALIDATE_POINTER0(hGeom, "OGR_G_SwapXY");
6917 :
6918 2 : OGRGeometry::FromHandle(hGeom)->swapXY();
6919 : }
6920 :
6921 : /************************************************************************/
6922 : /* Prepared geometry API */
6923 : /************************************************************************/
6924 :
6925 : #if defined(HAVE_GEOS)
6926 : struct _OGRPreparedGeometry
6927 : {
6928 : GEOSContextHandle_t hGEOSCtxt;
6929 : GEOSGeom hGEOSGeom;
6930 : const GEOSPreparedGeometry *poPreparedGEOSGeom;
6931 : };
6932 : #endif
6933 :
6934 : /************************************************************************/
6935 : /* OGRHasPreparedGeometrySupport() */
6936 : /************************************************************************/
6937 :
6938 : /** Returns if GEOS has prepared geometry support.
6939 : * @return TRUE or FALSE
6940 : */
6941 1 : int OGRHasPreparedGeometrySupport()
6942 : {
6943 : #if defined(HAVE_GEOS)
6944 1 : return TRUE;
6945 : #else
6946 : return FALSE;
6947 : #endif
6948 : }
6949 :
6950 : /************************************************************************/
6951 : /* OGRCreatePreparedGeometry() */
6952 : /************************************************************************/
6953 :
6954 : /** Creates a prepared geometry.
6955 : *
6956 : * To free with OGRDestroyPreparedGeometry()
6957 : *
6958 : * @param hGeom input geometry to prepare.
6959 : * @return handle to a prepared geometry.
6960 : * @since GDAL 3.3
6961 : */
6962 : OGRPreparedGeometryH
6963 51942 : OGRCreatePreparedGeometry(UNUSED_IF_NO_GEOS OGRGeometryH hGeom)
6964 : {
6965 : #if defined(HAVE_GEOS)
6966 51942 : OGRGeometry *poGeom = OGRGeometry::FromHandle(hGeom);
6967 51942 : GEOSContextHandle_t hGEOSCtxt = OGRGeometry::createGEOSContext();
6968 51942 : GEOSGeom hGEOSGeom = poGeom->exportToGEOS(hGEOSCtxt);
6969 51942 : if (hGEOSGeom == nullptr)
6970 : {
6971 0 : OGRGeometry::freeGEOSContext(hGEOSCtxt);
6972 0 : return nullptr;
6973 : }
6974 : const GEOSPreparedGeometry *poPreparedGEOSGeom =
6975 51942 : GEOSPrepare_r(hGEOSCtxt, hGEOSGeom);
6976 51942 : if (poPreparedGEOSGeom == nullptr)
6977 : {
6978 0 : GEOSGeom_destroy_r(hGEOSCtxt, hGEOSGeom);
6979 0 : OGRGeometry::freeGEOSContext(hGEOSCtxt);
6980 0 : return nullptr;
6981 : }
6982 :
6983 51942 : OGRPreparedGeometry *poPreparedGeom = new OGRPreparedGeometry;
6984 51942 : poPreparedGeom->hGEOSCtxt = hGEOSCtxt;
6985 51942 : poPreparedGeom->hGEOSGeom = hGEOSGeom;
6986 51942 : poPreparedGeom->poPreparedGEOSGeom = poPreparedGEOSGeom;
6987 :
6988 51942 : return poPreparedGeom;
6989 : #else
6990 : return nullptr;
6991 : #endif
6992 : }
6993 :
6994 : /************************************************************************/
6995 : /* OGRDestroyPreparedGeometry() */
6996 : /************************************************************************/
6997 :
6998 : /** Destroys a prepared geometry.
6999 : * @param hPreparedGeom prepared geometry.
7000 : * @since GDAL 3.3
7001 : */
7002 51987 : void OGRDestroyPreparedGeometry(
7003 : UNUSED_IF_NO_GEOS OGRPreparedGeometryH hPreparedGeom)
7004 : {
7005 : #if defined(HAVE_GEOS)
7006 51987 : if (hPreparedGeom != nullptr)
7007 : {
7008 51942 : GEOSPreparedGeom_destroy_r(hPreparedGeom->hGEOSCtxt,
7009 : hPreparedGeom->poPreparedGEOSGeom);
7010 51942 : GEOSGeom_destroy_r(hPreparedGeom->hGEOSCtxt, hPreparedGeom->hGEOSGeom);
7011 51942 : OGRGeometry::freeGEOSContext(hPreparedGeom->hGEOSCtxt);
7012 51942 : delete hPreparedGeom;
7013 : }
7014 : #endif
7015 51987 : }
7016 :
7017 : /************************************************************************/
7018 : /* OGRPreparedGeometryIntersects() */
7019 : /************************************************************************/
7020 :
7021 : /** Returns whether a prepared geometry intersects with a geometry.
7022 : * @param hPreparedGeom prepared geometry.
7023 : * @param hOtherGeom other geometry.
7024 : * @return TRUE or FALSE.
7025 : * @since GDAL 3.3
7026 : */
7027 2884 : int OGRPreparedGeometryIntersects(
7028 : UNUSED_IF_NO_GEOS const OGRPreparedGeometryH hPreparedGeom,
7029 : UNUSED_IF_NO_GEOS const OGRGeometryH hOtherGeom)
7030 : {
7031 : #if defined(HAVE_GEOS)
7032 2884 : OGRGeometry *poOtherGeom = OGRGeometry::FromHandle(hOtherGeom);
7033 2884 : if (hPreparedGeom == nullptr ||
7034 : poOtherGeom == nullptr
7035 : // The check for IsEmpty() is for buggy GEOS versions.
7036 : // See https://github.com/libgeos/geos/pull/423
7037 5768 : || poOtherGeom->IsEmpty())
7038 : {
7039 1 : return FALSE;
7040 : }
7041 :
7042 : GEOSGeom hGEOSOtherGeom =
7043 2883 : poOtherGeom->exportToGEOS(hPreparedGeom->hGEOSCtxt);
7044 2883 : if (hGEOSOtherGeom == nullptr)
7045 0 : return FALSE;
7046 :
7047 2883 : const bool bRet = CPL_TO_BOOL(GEOSPreparedIntersects_r(
7048 : hPreparedGeom->hGEOSCtxt, hPreparedGeom->poPreparedGEOSGeom,
7049 : hGEOSOtherGeom));
7050 2883 : GEOSGeom_destroy_r(hPreparedGeom->hGEOSCtxt, hGEOSOtherGeom);
7051 :
7052 2883 : return bRet;
7053 : #else
7054 : return FALSE;
7055 : #endif
7056 : }
7057 :
7058 : /** Returns whether a prepared geometry contains a geometry.
7059 : * @param hPreparedGeom prepared geometry.
7060 : * @param hOtherGeom other geometry.
7061 : * @return TRUE or FALSE.
7062 : */
7063 120116 : int OGRPreparedGeometryContains(UNUSED_IF_NO_GEOS const OGRPreparedGeometryH
7064 : hPreparedGeom,
7065 : UNUSED_IF_NO_GEOS const OGRGeometryH hOtherGeom)
7066 : {
7067 : #if defined(HAVE_GEOS)
7068 120116 : OGRGeometry *poOtherGeom = OGRGeometry::FromHandle(hOtherGeom);
7069 120116 : if (hPreparedGeom == nullptr ||
7070 : poOtherGeom == nullptr
7071 : // The check for IsEmpty() is for buggy GEOS versions.
7072 : // See https://github.com/libgeos/geos/pull/423
7073 240232 : || poOtherGeom->IsEmpty())
7074 : {
7075 1 : return FALSE;
7076 : }
7077 :
7078 : GEOSGeom hGEOSOtherGeom =
7079 120115 : poOtherGeom->exportToGEOS(hPreparedGeom->hGEOSCtxt);
7080 120115 : if (hGEOSOtherGeom == nullptr)
7081 0 : return FALSE;
7082 :
7083 120115 : const bool bRet = CPL_TO_BOOL(GEOSPreparedContains_r(
7084 : hPreparedGeom->hGEOSCtxt, hPreparedGeom->poPreparedGEOSGeom,
7085 : hGEOSOtherGeom));
7086 120115 : GEOSGeom_destroy_r(hPreparedGeom->hGEOSCtxt, hGEOSOtherGeom);
7087 :
7088 120115 : return bRet;
7089 : #else
7090 : return FALSE;
7091 : #endif
7092 : }
7093 :
7094 : /************************************************************************/
7095 : /* OGRGeometryFromEWKB() */
7096 : /************************************************************************/
7097 :
7098 1429 : OGRGeometry *OGRGeometryFromEWKB(GByte *pabyEWKB, int nLength, int *pnSRID,
7099 : int bIsPostGIS1_EWKB)
7100 :
7101 : {
7102 1429 : OGRGeometry *poGeometry = nullptr;
7103 :
7104 1429 : size_t nWKBSize = 0;
7105 1429 : const GByte *pabyWKB = WKBFromEWKB(pabyEWKB, nLength, nWKBSize, pnSRID);
7106 1429 : if (pabyWKB == nullptr)
7107 0 : return nullptr;
7108 :
7109 : /* -------------------------------------------------------------------- */
7110 : /* Try to ingest the geometry. */
7111 : /* -------------------------------------------------------------------- */
7112 1429 : (void)OGRGeometryFactory::createFromWkb(
7113 : pabyWKB, nullptr, &poGeometry, nWKBSize,
7114 : (bIsPostGIS1_EWKB) ? wkbVariantPostGIS1 : wkbVariantOldOgc);
7115 :
7116 1429 : return poGeometry;
7117 : }
7118 :
7119 : /************************************************************************/
7120 : /* OGRGeometryFromHexEWKB() */
7121 : /************************************************************************/
7122 :
7123 1427 : OGRGeometry *OGRGeometryFromHexEWKB(const char *pszBytea, int *pnSRID,
7124 : int bIsPostGIS1_EWKB)
7125 :
7126 : {
7127 1427 : if (pszBytea == nullptr)
7128 0 : return nullptr;
7129 :
7130 1427 : int nWKBLength = 0;
7131 1427 : GByte *pabyWKB = CPLHexToBinary(pszBytea, &nWKBLength);
7132 :
7133 : OGRGeometry *poGeometry =
7134 1427 : OGRGeometryFromEWKB(pabyWKB, nWKBLength, pnSRID, bIsPostGIS1_EWKB);
7135 :
7136 1427 : CPLFree(pabyWKB);
7137 :
7138 1427 : return poGeometry;
7139 : }
7140 :
7141 : /************************************************************************/
7142 : /* OGRGeometryToHexEWKB() */
7143 : /************************************************************************/
7144 :
7145 1056 : char *OGRGeometryToHexEWKB(OGRGeometry *poGeometry, int nSRSId,
7146 : int nPostGISMajor, int nPostGISMinor)
7147 : {
7148 1056 : const size_t nWkbSize = poGeometry->WkbSize();
7149 1056 : GByte *pabyWKB = static_cast<GByte *>(VSI_MALLOC_VERBOSE(nWkbSize));
7150 1056 : if (pabyWKB == nullptr)
7151 0 : return CPLStrdup("");
7152 :
7153 115 : if ((nPostGISMajor > 2 || (nPostGISMajor == 2 && nPostGISMinor >= 2)) &&
7154 1786 : wkbFlatten(poGeometry->getGeometryType()) == wkbPoint &&
7155 615 : poGeometry->IsEmpty())
7156 : {
7157 2 : if (poGeometry->exportToWkb(wkbNDR, pabyWKB, wkbVariantIso) !=
7158 : OGRERR_NONE)
7159 : {
7160 0 : CPLFree(pabyWKB);
7161 0 : return CPLStrdup("");
7162 : }
7163 : }
7164 1054 : else if (poGeometry->exportToWkb(wkbNDR, pabyWKB,
7165 : (nPostGISMajor < 2)
7166 : ? wkbVariantPostGIS1
7167 1054 : : wkbVariantOldOgc) != OGRERR_NONE)
7168 : {
7169 0 : CPLFree(pabyWKB);
7170 0 : return CPLStrdup("");
7171 : }
7172 :
7173 : // When converting to hex, each byte takes 2 hex characters. In addition
7174 : // we add in 8 characters to represent the SRID integer in hex, and
7175 : // one for a null terminator.
7176 :
7177 1056 : const size_t nTextSize = nWkbSize * 2 + 8 + 1;
7178 1056 : if (nTextSize > static_cast<size_t>(std::numeric_limits<int>::max()))
7179 : {
7180 : // FIXME: artificial limitation
7181 0 : CPLFree(pabyWKB);
7182 0 : return CPLStrdup("");
7183 : }
7184 1056 : char *pszTextBuf = static_cast<char *>(VSI_MALLOC_VERBOSE(nTextSize));
7185 1056 : if (pszTextBuf == nullptr)
7186 : {
7187 0 : CPLFree(pabyWKB);
7188 0 : return CPLStrdup("");
7189 : }
7190 1056 : char *pszTextBufCurrent = pszTextBuf;
7191 :
7192 : // Convert the 1st byte, which is the endianness flag, to hex.
7193 1056 : char *pszHex = CPLBinaryToHex(1, pabyWKB);
7194 1056 : strcpy(pszTextBufCurrent, pszHex);
7195 1056 : CPLFree(pszHex);
7196 1056 : pszTextBufCurrent += 2;
7197 :
7198 : // Next, get the geom type which is bytes 2 through 5.
7199 : GUInt32 geomType;
7200 1056 : memcpy(&geomType, pabyWKB + 1, 4);
7201 :
7202 : // Now add the SRID flag if an SRID is provided.
7203 1056 : if (nSRSId > 0)
7204 : {
7205 : // Change the flag to wkbNDR (little) endianness.
7206 529 : constexpr GUInt32 WKBSRIDFLAG = 0x20000000;
7207 529 : GUInt32 nGSrsFlag = CPL_LSBWORD32(WKBSRIDFLAG);
7208 : // Apply the flag.
7209 529 : geomType = geomType | nGSrsFlag;
7210 : }
7211 :
7212 : // Now write the geom type which is 4 bytes.
7213 1056 : pszHex = CPLBinaryToHex(4, reinterpret_cast<const GByte *>(&geomType));
7214 1056 : strcpy(pszTextBufCurrent, pszHex);
7215 1056 : CPLFree(pszHex);
7216 1056 : pszTextBufCurrent += 8;
7217 :
7218 : // Now include SRID if provided.
7219 1056 : if (nSRSId > 0)
7220 : {
7221 : // Force the srsid to wkbNDR (little) endianness.
7222 529 : const GUInt32 nGSRSId = CPL_LSBWORD32(nSRSId);
7223 529 : pszHex = CPLBinaryToHex(sizeof(nGSRSId),
7224 : reinterpret_cast<const GByte *>(&nGSRSId));
7225 529 : strcpy(pszTextBufCurrent, pszHex);
7226 529 : CPLFree(pszHex);
7227 529 : pszTextBufCurrent += 8;
7228 : }
7229 :
7230 : // Copy the rest of the data over - subtract
7231 : // 5 since we already copied 5 bytes above.
7232 1056 : pszHex = CPLBinaryToHex(static_cast<int>(nWkbSize - 5), pabyWKB + 5);
7233 1056 : strcpy(pszTextBufCurrent, pszHex);
7234 1056 : CPLFree(pszHex);
7235 :
7236 1056 : CPLFree(pabyWKB);
7237 :
7238 1056 : return pszTextBuf;
7239 : }
7240 :
7241 : /************************************************************************/
7242 : /* importPreambleFromWkb() */
7243 : /************************************************************************/
7244 :
7245 : //! @cond Doxygen_Suppress
7246 153342 : OGRErr OGRGeometry::importPreambleFromWkb(const unsigned char *pabyData,
7247 : size_t nSize,
7248 : OGRwkbByteOrder &eByteOrder,
7249 : OGRwkbVariant eWkbVariant)
7250 : {
7251 153342 : if (nSize < 9 && nSize != static_cast<size_t>(-1))
7252 0 : return OGRERR_NOT_ENOUGH_DATA;
7253 :
7254 : /* -------------------------------------------------------------------- */
7255 : /* Get the byte order byte. */
7256 : /* -------------------------------------------------------------------- */
7257 153342 : int nByteOrder = DB2_V72_FIX_BYTE_ORDER(*pabyData);
7258 153342 : if (!(nByteOrder == wkbXDR || nByteOrder == wkbNDR))
7259 0 : return OGRERR_CORRUPT_DATA;
7260 153342 : eByteOrder = static_cast<OGRwkbByteOrder>(nByteOrder);
7261 :
7262 : /* -------------------------------------------------------------------- */
7263 : /* Get the geometry feature type. */
7264 : /* -------------------------------------------------------------------- */
7265 : OGRwkbGeometryType eGeometryType;
7266 : const OGRErr err =
7267 153342 : OGRReadWKBGeometryType(pabyData, eWkbVariant, &eGeometryType);
7268 153342 : if (wkbHasZ(eGeometryType))
7269 62302 : flags |= OGR_G_3D;
7270 153342 : if (wkbHasM(eGeometryType))
7271 59689 : flags |= OGR_G_MEASURED;
7272 :
7273 153341 : if (err != OGRERR_NONE || eGeometryType != getGeometryType())
7274 0 : return OGRERR_CORRUPT_DATA;
7275 :
7276 153343 : return OGRERR_NONE;
7277 : }
7278 :
7279 : /************************************************************************/
7280 : /* importPreambleOfCollectionFromWkb() */
7281 : /* */
7282 : /* Utility method for OGRSimpleCurve, OGRCompoundCurve, */
7283 : /* OGRCurvePolygon and OGRGeometryCollection. */
7284 : /************************************************************************/
7285 :
7286 70762 : OGRErr OGRGeometry::importPreambleOfCollectionFromWkb(
7287 : const unsigned char *pabyData, size_t &nSize, size_t &nDataOffset,
7288 : OGRwkbByteOrder &eByteOrder, size_t nMinSubGeomSize, int &nGeomCount,
7289 : OGRwkbVariant eWkbVariant)
7290 : {
7291 70762 : nGeomCount = 0;
7292 :
7293 : OGRErr eErr =
7294 70762 : importPreambleFromWkb(pabyData, nSize, eByteOrder, eWkbVariant);
7295 70759 : if (eErr != OGRERR_NONE)
7296 0 : return eErr;
7297 :
7298 : /* -------------------------------------------------------------------- */
7299 : /* Clear existing Geoms. */
7300 : /* -------------------------------------------------------------------- */
7301 70759 : int _flags = flags; // flags set in importPreambleFromWkb
7302 70759 : empty(); // may reset flags etc.
7303 :
7304 : // restore
7305 70759 : if (_flags & OGR_G_3D)
7306 59261 : set3D(TRUE);
7307 70759 : if (_flags & OGR_G_MEASURED)
7308 56768 : setMeasured(TRUE);
7309 :
7310 : /* -------------------------------------------------------------------- */
7311 : /* Get the sub-geometry count. */
7312 : /* -------------------------------------------------------------------- */
7313 70761 : memcpy(&nGeomCount, pabyData + 5, 4);
7314 :
7315 70761 : if (OGR_SWAP(eByteOrder))
7316 383 : nGeomCount = CPL_SWAP32(nGeomCount);
7317 :
7318 141389 : if (nGeomCount < 0 ||
7319 70627 : static_cast<size_t>(nGeomCount) >
7320 70627 : std::numeric_limits<size_t>::max() / nMinSubGeomSize)
7321 : {
7322 134 : nGeomCount = 0;
7323 134 : return OGRERR_CORRUPT_DATA;
7324 : }
7325 70628 : const size_t nBufferMinSize = nGeomCount * nMinSubGeomSize;
7326 :
7327 : // Each ring has a minimum of nMinSubGeomSize bytes.
7328 70628 : if (nSize != static_cast<size_t>(-1) && nSize - 9 < nBufferMinSize)
7329 : {
7330 910 : CPLError(CE_Failure, CPLE_AppDefined,
7331 : "Length of input WKB is too small");
7332 910 : nGeomCount = 0;
7333 910 : return OGRERR_NOT_ENOUGH_DATA;
7334 : }
7335 :
7336 69718 : nDataOffset = 9;
7337 69718 : if (nSize != static_cast<size_t>(-1))
7338 : {
7339 69696 : CPLAssert(nSize >= nDataOffset);
7340 69696 : nSize -= nDataOffset;
7341 : }
7342 :
7343 69718 : return OGRERR_NONE;
7344 : }
7345 :
7346 : /************************************************************************/
7347 : /* importCurveCollectionFromWkt() */
7348 : /* */
7349 : /* Utility method for OGRCompoundCurve, OGRCurvePolygon and */
7350 : /* OGRMultiCurve. */
7351 : /************************************************************************/
7352 :
7353 1430 : OGRErr OGRGeometry::importCurveCollectionFromWkt(
7354 : const char **ppszInput, int bAllowEmptyComponent, int bAllowLineString,
7355 : int bAllowCurve, int bAllowCompoundCurve,
7356 : OGRErr (*pfnAddCurveDirectly)(OGRGeometry *poSelf, OGRCurve *poCurve))
7357 :
7358 : {
7359 1430 : int bHasZ = FALSE;
7360 1430 : int bHasM = FALSE;
7361 1430 : bool bIsEmpty = false;
7362 1430 : OGRErr eErr = importPreambleFromWkt(ppszInput, &bHasZ, &bHasM, &bIsEmpty);
7363 1430 : flags = 0;
7364 1430 : if (eErr != OGRERR_NONE)
7365 14 : return eErr;
7366 1416 : if (bHasZ)
7367 189 : flags |= OGR_G_3D;
7368 1416 : if (bHasM)
7369 120 : flags |= OGR_G_MEASURED;
7370 1416 : if (bIsEmpty)
7371 109 : return OGRERR_NONE;
7372 :
7373 : char szToken[OGR_WKT_TOKEN_MAX];
7374 1307 : const char *pszInput = *ppszInput;
7375 1307 : eErr = OGRERR_NONE;
7376 :
7377 : // Skip first '('.
7378 1307 : pszInput = OGRWktReadToken(pszInput, szToken);
7379 :
7380 : /* ==================================================================== */
7381 : /* Read each curve in turn. Note that we try to reuse the same */
7382 : /* point list buffer from curve to curve to cut down on */
7383 : /* allocate/deallocate overhead. */
7384 : /* ==================================================================== */
7385 1307 : OGRRawPoint *paoPoints = nullptr;
7386 1307 : int nMaxPoints = 0;
7387 1307 : double *padfZ = nullptr;
7388 :
7389 624 : do
7390 : {
7391 :
7392 : /* --------------------------------------------------------------------
7393 : */
7394 : /* Get the first token, which should be the geometry type. */
7395 : /* --------------------------------------------------------------------
7396 : */
7397 1931 : const char *pszInputBefore = pszInput;
7398 1931 : pszInput = OGRWktReadToken(pszInput, szToken);
7399 :
7400 : /* --------------------------------------------------------------------
7401 : */
7402 : /* Do the import. */
7403 : /* --------------------------------------------------------------------
7404 : */
7405 1931 : OGRCurve *poCurve = nullptr;
7406 1931 : if (EQUAL(szToken, "("))
7407 : {
7408 1412 : OGRLineString *poLine = new OGRLineString();
7409 1412 : poCurve = poLine;
7410 1412 : pszInput = pszInputBefore;
7411 1412 : eErr = poLine->importFromWKTListOnly(&pszInput, bHasZ, bHasM,
7412 : paoPoints, nMaxPoints, padfZ);
7413 : }
7414 519 : else if (bAllowEmptyComponent && EQUAL(szToken, "EMPTY"))
7415 : {
7416 16 : poCurve = new OGRLineString();
7417 : }
7418 : // Accept LINESTRING(), but this is an extension to the BNF, also
7419 : // accepted by PostGIS.
7420 503 : else if ((bAllowLineString && STARTS_WITH_CI(szToken, "LINESTRING")) ||
7421 488 : (bAllowCurve && !STARTS_WITH_CI(szToken, "LINESTRING") &&
7422 488 : !STARTS_WITH_CI(szToken, "COMPOUNDCURVE") &&
7423 1155 : OGR_GT_IsCurve(OGRFromOGCGeomType(szToken))) ||
7424 149 : (bAllowCompoundCurve &&
7425 149 : STARTS_WITH_CI(szToken, "COMPOUNDCURVE")))
7426 : {
7427 465 : OGRGeometry *poGeom = nullptr;
7428 465 : pszInput = pszInputBefore;
7429 : eErr =
7430 465 : OGRGeometryFactory::createFromWkt(&pszInput, nullptr, &poGeom);
7431 465 : if (poGeom == nullptr)
7432 : {
7433 1 : eErr = OGRERR_CORRUPT_DATA;
7434 : }
7435 : else
7436 : {
7437 464 : poCurve = poGeom->toCurve();
7438 : }
7439 : }
7440 : else
7441 : {
7442 38 : CPLError(CE_Failure, CPLE_AppDefined, "Unexpected token : %s",
7443 : szToken);
7444 38 : eErr = OGRERR_CORRUPT_DATA;
7445 : }
7446 :
7447 : // If this has M it is an error if poGeom does not have M.
7448 1931 : if (poCurve && !Is3D() && IsMeasured() && !poCurve->IsMeasured())
7449 0 : eErr = OGRERR_CORRUPT_DATA;
7450 :
7451 1931 : if (eErr == OGRERR_NONE)
7452 1886 : eErr = pfnAddCurveDirectly(this, poCurve);
7453 1931 : if (eErr != OGRERR_NONE)
7454 : {
7455 55 : delete poCurve;
7456 55 : break;
7457 : }
7458 :
7459 : /* --------------------------------------------------------------------
7460 : */
7461 : /* Read the delimiter following the surface. */
7462 : /* --------------------------------------------------------------------
7463 : */
7464 1876 : pszInput = OGRWktReadToken(pszInput, szToken);
7465 1876 : } while (szToken[0] == ',' && eErr == OGRERR_NONE);
7466 :
7467 1307 : CPLFree(paoPoints);
7468 1307 : CPLFree(padfZ);
7469 :
7470 : /* -------------------------------------------------------------------- */
7471 : /* freak if we don't get a closing bracket. */
7472 : /* -------------------------------------------------------------------- */
7473 :
7474 1307 : if (eErr != OGRERR_NONE)
7475 55 : return eErr;
7476 :
7477 1252 : if (szToken[0] != ')')
7478 9 : return OGRERR_CORRUPT_DATA;
7479 :
7480 1243 : *ppszInput = pszInput;
7481 1243 : return OGRERR_NONE;
7482 : }
7483 :
7484 : //! @endcond
7485 :
7486 : /************************************************************************/
7487 : /* OGR_GT_Flatten() */
7488 : /************************************************************************/
7489 : /**
7490 : * \brief Returns the 2D geometry type corresponding to the passed geometry
7491 : * type.
7492 : *
7493 : * This function is intended to work with geometry types as old-style 99-402
7494 : * extended dimension (Z) WKB types, as well as with newer SFSQL 1.2 and
7495 : * ISO SQL/MM Part 3 extended dimension (Z&M) WKB types.
7496 : *
7497 : * @param eType Input geometry type
7498 : *
7499 : * @return 2D geometry type corresponding to the passed geometry type.
7500 : *
7501 : * @since GDAL 2.0
7502 : */
7503 :
7504 7116210 : OGRwkbGeometryType OGR_GT_Flatten(OGRwkbGeometryType eType)
7505 : {
7506 7116210 : eType = static_cast<OGRwkbGeometryType>(eType & (~wkb25DBitInternalUse));
7507 7116210 : if (eType >= 1000 && eType < 2000) // ISO Z.
7508 2710510 : return static_cast<OGRwkbGeometryType>(eType - 1000);
7509 4405700 : if (eType >= 2000 && eType < 3000) // ISO M.
7510 5560 : return static_cast<OGRwkbGeometryType>(eType - 2000);
7511 4400140 : if (eType >= 3000 && eType < 4000) // ISO ZM.
7512 135257 : return static_cast<OGRwkbGeometryType>(eType - 3000);
7513 4264880 : return eType;
7514 : }
7515 :
7516 : /************************************************************************/
7517 : /* OGR_GT_HasZ() */
7518 : /************************************************************************/
7519 : /**
7520 : * \brief Return if the geometry type is a 3D geometry type.
7521 : *
7522 : * @param eType Input geometry type
7523 : *
7524 : * @return TRUE if the geometry type is a 3D geometry type.
7525 : *
7526 : * @since GDAL 2.0
7527 : */
7528 :
7529 1978930 : int OGR_GT_HasZ(OGRwkbGeometryType eType)
7530 : {
7531 1978930 : if (eType & wkb25DBitInternalUse)
7532 156296 : return TRUE;
7533 1822630 : if (eType >= 1000 && eType < 2000) // Accept 1000 for wkbUnknownZ.
7534 221 : return TRUE;
7535 1822410 : if (eType >= 3000 && eType < 4000) // Accept 3000 for wkbUnknownZM.
7536 121221 : return TRUE;
7537 1701190 : return FALSE;
7538 : }
7539 :
7540 : /************************************************************************/
7541 : /* OGR_GT_HasM() */
7542 : /************************************************************************/
7543 : /**
7544 : * \brief Return if the geometry type is a measured type.
7545 : *
7546 : * @param eType Input geometry type
7547 : *
7548 : * @return TRUE if the geometry type is a measured type.
7549 : *
7550 : * @since GDAL 2.1
7551 : */
7552 :
7553 2034450 : int OGR_GT_HasM(OGRwkbGeometryType eType)
7554 : {
7555 2034450 : if (eType >= 2000 && eType < 3000) // Accept 2000 for wkbUnknownM.
7556 2542 : return TRUE;
7557 2031910 : if (eType >= 3000 && eType < 4000) // Accept 3000 for wkbUnknownZM.
7558 120882 : return TRUE;
7559 1911020 : return FALSE;
7560 : }
7561 :
7562 : /************************************************************************/
7563 : /* OGR_GT_SetZ() */
7564 : /************************************************************************/
7565 : /**
7566 : * \brief Returns the 3D geometry type corresponding to the passed geometry
7567 : * type.
7568 : *
7569 : * @param eType Input geometry type
7570 : *
7571 : * @return 3D geometry type corresponding to the passed geometry type.
7572 : *
7573 : * @since GDAL 2.0
7574 : */
7575 :
7576 5271 : OGRwkbGeometryType OGR_GT_SetZ(OGRwkbGeometryType eType)
7577 : {
7578 5271 : if (OGR_GT_HasZ(eType) || eType == wkbNone)
7579 476 : return eType;
7580 4795 : if (eType <= wkbGeometryCollection)
7581 4740 : return static_cast<OGRwkbGeometryType>(eType | wkb25DBitInternalUse);
7582 : else
7583 55 : return static_cast<OGRwkbGeometryType>(eType + 1000);
7584 : }
7585 :
7586 : /************************************************************************/
7587 : /* OGR_GT_SetM() */
7588 : /************************************************************************/
7589 : /**
7590 : * \brief Returns the measured geometry type corresponding to the passed
7591 : * geometry type.
7592 : *
7593 : * @param eType Input geometry type
7594 : *
7595 : * @return measured geometry type corresponding to the passed geometry type.
7596 : *
7597 : * @since GDAL 2.1
7598 : */
7599 :
7600 1913 : OGRwkbGeometryType OGR_GT_SetM(OGRwkbGeometryType eType)
7601 : {
7602 1913 : if (OGR_GT_HasM(eType) || eType == wkbNone)
7603 257 : return eType;
7604 1656 : if (eType & wkb25DBitInternalUse)
7605 : {
7606 699 : eType = static_cast<OGRwkbGeometryType>(eType & ~wkb25DBitInternalUse);
7607 699 : eType = static_cast<OGRwkbGeometryType>(eType + 1000);
7608 : }
7609 1656 : return static_cast<OGRwkbGeometryType>(eType + 2000);
7610 : }
7611 :
7612 : /************************************************************************/
7613 : /* OGR_GT_SetModifier() */
7614 : /************************************************************************/
7615 : /**
7616 : * \brief Returns a XY, XYZ, XYM or XYZM geometry type depending on parameter.
7617 : *
7618 : * @param eType Input geometry type
7619 : * @param bHasZ TRUE if the output geometry type must be 3D.
7620 : * @param bHasM TRUE if the output geometry type must be measured.
7621 : *
7622 : * @return Output geometry type.
7623 : *
7624 : * @since GDAL 2.0
7625 : */
7626 :
7627 4783 : OGRwkbGeometryType OGR_GT_SetModifier(OGRwkbGeometryType eType, int bHasZ,
7628 : int bHasM)
7629 : {
7630 4783 : if (bHasZ && bHasM)
7631 342 : return OGR_GT_SetM(OGR_GT_SetZ(eType));
7632 4441 : else if (bHasM)
7633 331 : return OGR_GT_SetM(wkbFlatten(eType));
7634 4110 : else if (bHasZ)
7635 1747 : return OGR_GT_SetZ(wkbFlatten(eType));
7636 : else
7637 2363 : return wkbFlatten(eType);
7638 : }
7639 :
7640 : /************************************************************************/
7641 : /* OGR_GT_IsSubClassOf) */
7642 : /************************************************************************/
7643 : /**
7644 : * \brief Returns if a type is a subclass of another one
7645 : *
7646 : * @param eType Type.
7647 : * @param eSuperType Super type
7648 : *
7649 : * @return TRUE if eType is a subclass of eSuperType.
7650 : *
7651 : * @since GDAL 2.0
7652 : */
7653 :
7654 105323 : int OGR_GT_IsSubClassOf(OGRwkbGeometryType eType, OGRwkbGeometryType eSuperType)
7655 : {
7656 105323 : eSuperType = wkbFlatten(eSuperType);
7657 105323 : eType = wkbFlatten(eType);
7658 :
7659 105323 : if (eSuperType == eType || eSuperType == wkbUnknown)
7660 7469 : return TRUE;
7661 :
7662 97854 : if (eSuperType == wkbGeometryCollection)
7663 25712 : return eType == wkbMultiPoint || eType == wkbMultiLineString ||
7664 52847 : eType == wkbMultiPolygon || eType == wkbMultiCurve ||
7665 27135 : eType == wkbMultiSurface;
7666 :
7667 70719 : if (eSuperType == wkbCurvePolygon)
7668 19387 : return eType == wkbPolygon || eType == wkbTriangle;
7669 :
7670 51332 : if (eSuperType == wkbMultiCurve)
7671 210 : return eType == wkbMultiLineString;
7672 :
7673 51122 : if (eSuperType == wkbMultiSurface)
7674 264 : return eType == wkbMultiPolygon;
7675 :
7676 50858 : if (eSuperType == wkbCurve)
7677 21058 : return eType == wkbLineString || eType == wkbCircularString ||
7678 21058 : eType == wkbCompoundCurve;
7679 :
7680 29800 : if (eSuperType == wkbSurface)
7681 3350 : return eType == wkbCurvePolygon || eType == wkbPolygon ||
7682 6838 : eType == wkbTriangle || eType == wkbPolyhedralSurface ||
7683 3488 : eType == wkbTIN;
7684 :
7685 26312 : if (eSuperType == wkbPolygon)
7686 216 : return eType == wkbTriangle;
7687 :
7688 26096 : if (eSuperType == wkbPolyhedralSurface)
7689 13333 : return eType == wkbTIN;
7690 :
7691 12763 : return FALSE;
7692 : }
7693 :
7694 : /************************************************************************/
7695 : /* OGR_GT_GetCollection() */
7696 : /************************************************************************/
7697 : /**
7698 : * \brief Returns the collection type that can contain the passed geometry type
7699 : *
7700 : * Handled conversions are : wkbNone->wkbNone, wkbPoint -> wkbMultiPoint,
7701 : * wkbLineString->wkbMultiLineString,
7702 : * wkbPolygon/wkbTriangle/wkbPolyhedralSurface/wkbTIN->wkbMultiPolygon,
7703 : * wkbCircularString->wkbMultiCurve, wkbCompoundCurve->wkbMultiCurve,
7704 : * wkbCurvePolygon->wkbMultiSurface.
7705 : * In other cases, wkbUnknown is returned
7706 : *
7707 : * Passed Z, M, ZM flag is preserved.
7708 : *
7709 : *
7710 : * @param eType Input geometry type
7711 : *
7712 : * @return the collection type that can contain the passed geometry type or
7713 : * wkbUnknown
7714 : *
7715 : * @since GDAL 2.0
7716 : */
7717 :
7718 2229 : OGRwkbGeometryType OGR_GT_GetCollection(OGRwkbGeometryType eType)
7719 : {
7720 2229 : const bool bHasZ = wkbHasZ(eType);
7721 2229 : const bool bHasM = wkbHasM(eType);
7722 2229 : if (eType == wkbNone)
7723 0 : return wkbNone;
7724 2229 : OGRwkbGeometryType eFGType = wkbFlatten(eType);
7725 2229 : if (eFGType == wkbPoint)
7726 41 : eType = wkbMultiPoint;
7727 :
7728 2188 : else if (eFGType == wkbLineString)
7729 152 : eType = wkbMultiLineString;
7730 :
7731 2036 : else if (eFGType == wkbPolygon)
7732 632 : eType = wkbMultiPolygon;
7733 :
7734 1404 : else if (eFGType == wkbTriangle)
7735 7 : eType = wkbTIN;
7736 :
7737 1397 : else if (OGR_GT_IsCurve(eFGType))
7738 165 : eType = wkbMultiCurve;
7739 :
7740 1232 : else if (OGR_GT_IsSurface(eFGType))
7741 951 : eType = wkbMultiSurface;
7742 :
7743 : else
7744 281 : return wkbUnknown;
7745 :
7746 1948 : if (bHasZ)
7747 2 : eType = wkbSetZ(eType);
7748 1948 : if (bHasM)
7749 2 : eType = wkbSetM(eType);
7750 :
7751 1948 : return eType;
7752 : }
7753 :
7754 : /************************************************************************/
7755 : /* OGR_GT_GetCurve() */
7756 : /************************************************************************/
7757 : /**
7758 : * \brief Returns the curve geometry type that can contain the passed geometry
7759 : * type
7760 : *
7761 : * Handled conversions are : wkbPolygon -> wkbCurvePolygon,
7762 : * wkbLineString->wkbCompoundCurve, wkbMultiPolygon->wkbMultiSurface
7763 : * and wkbMultiLineString->wkbMultiCurve.
7764 : * In other cases, the passed geometry is returned.
7765 : *
7766 : * Passed Z, M, ZM flag is preserved.
7767 : *
7768 : * @param eType Input geometry type
7769 : *
7770 : * @return the curve type that can contain the passed geometry type
7771 : *
7772 : * @since GDAL 2.0
7773 : */
7774 :
7775 33 : OGRwkbGeometryType OGR_GT_GetCurve(OGRwkbGeometryType eType)
7776 : {
7777 33 : const bool bHasZ = wkbHasZ(eType);
7778 33 : const bool bHasM = wkbHasM(eType);
7779 33 : OGRwkbGeometryType eFGType = wkbFlatten(eType);
7780 :
7781 33 : if (eFGType == wkbLineString)
7782 2 : eType = wkbCompoundCurve;
7783 :
7784 31 : else if (eFGType == wkbPolygon)
7785 1 : eType = wkbCurvePolygon;
7786 :
7787 30 : else if (eFGType == wkbTriangle)
7788 0 : eType = wkbCurvePolygon;
7789 :
7790 30 : else if (eFGType == wkbMultiLineString)
7791 6 : eType = wkbMultiCurve;
7792 :
7793 24 : else if (eFGType == wkbMultiPolygon)
7794 4 : eType = wkbMultiSurface;
7795 :
7796 33 : if (bHasZ)
7797 4 : eType = wkbSetZ(eType);
7798 33 : if (bHasM)
7799 4 : eType = wkbSetM(eType);
7800 :
7801 33 : return eType;
7802 : }
7803 :
7804 : /************************************************************************/
7805 : /* OGR_GT_GetLinear() */
7806 : /************************************************************************/
7807 : /**
7808 : * \brief Returns the non-curve geometry type that can contain the passed
7809 : * geometry type
7810 : *
7811 : * Handled conversions are : wkbCurvePolygon -> wkbPolygon,
7812 : * wkbCircularString->wkbLineString, wkbCompoundCurve->wkbLineString,
7813 : * wkbMultiSurface->wkbMultiPolygon and wkbMultiCurve->wkbMultiLineString.
7814 : * In other cases, the passed geometry is returned.
7815 : *
7816 : * Passed Z, M, ZM flag is preserved.
7817 : *
7818 : * @param eType Input geometry type
7819 : *
7820 : * @return the non-curve type that can contain the passed geometry type
7821 : *
7822 : * @since GDAL 2.0
7823 : */
7824 :
7825 680 : OGRwkbGeometryType OGR_GT_GetLinear(OGRwkbGeometryType eType)
7826 : {
7827 680 : const bool bHasZ = wkbHasZ(eType);
7828 680 : const bool bHasM = wkbHasM(eType);
7829 680 : OGRwkbGeometryType eFGType = wkbFlatten(eType);
7830 :
7831 680 : if (OGR_GT_IsCurve(eFGType))
7832 36 : eType = wkbLineString;
7833 :
7834 644 : else if (OGR_GT_IsSurface(eFGType))
7835 36 : eType = wkbPolygon;
7836 :
7837 608 : else if (eFGType == wkbMultiCurve)
7838 177 : eType = wkbMultiLineString;
7839 :
7840 431 : else if (eFGType == wkbMultiSurface)
7841 156 : eType = wkbMultiPolygon;
7842 :
7843 680 : if (bHasZ)
7844 121 : eType = wkbSetZ(eType);
7845 680 : if (bHasM)
7846 85 : eType = wkbSetM(eType);
7847 :
7848 680 : return eType;
7849 : }
7850 :
7851 : /************************************************************************/
7852 : /* OGR_GT_IsCurve() */
7853 : /************************************************************************/
7854 :
7855 : /**
7856 : * \brief Return if a geometry type is an instance of Curve
7857 : *
7858 : * Such geometry type are wkbLineString, wkbCircularString, wkbCompoundCurve
7859 : * and their Z/M/ZM variant.
7860 : *
7861 : * @param eGeomType the geometry type
7862 : * @return TRUE if the geometry type is an instance of Curve
7863 : *
7864 : * @since GDAL 2.0
7865 : */
7866 :
7867 21049 : int OGR_GT_IsCurve(OGRwkbGeometryType eGeomType)
7868 : {
7869 21049 : return OGR_GT_IsSubClassOf(eGeomType, wkbCurve);
7870 : }
7871 :
7872 : /************************************************************************/
7873 : /* OGR_GT_IsSurface() */
7874 : /************************************************************************/
7875 :
7876 : /**
7877 : * \brief Return if a geometry type is an instance of Surface
7878 : *
7879 : * Such geometry type are wkbCurvePolygon and wkbPolygon
7880 : * and their Z/M/ZM variant.
7881 : *
7882 : * @param eGeomType the geometry type
7883 : * @return TRUE if the geometry type is an instance of Surface
7884 : *
7885 : * @since GDAL 2.0
7886 : */
7887 :
7888 3482 : int OGR_GT_IsSurface(OGRwkbGeometryType eGeomType)
7889 : {
7890 3482 : return OGR_GT_IsSubClassOf(eGeomType, wkbSurface);
7891 : }
7892 :
7893 : /************************************************************************/
7894 : /* OGR_GT_IsNonLinear() */
7895 : /************************************************************************/
7896 :
7897 : /**
7898 : * \brief Return if a geometry type is a non-linear geometry type.
7899 : *
7900 : * Such geometry type are wkbCurve, wkbCircularString, wkbCompoundCurve,
7901 : * wkbSurface, wkbCurvePolygon, wkbMultiCurve, wkbMultiSurface and their
7902 : * Z/M variants.
7903 : *
7904 : * @param eGeomType the geometry type
7905 : * @return TRUE if the geometry type is a non-linear geometry type.
7906 : *
7907 : * @since GDAL 2.0
7908 : */
7909 :
7910 106680 : int OGR_GT_IsNonLinear(OGRwkbGeometryType eGeomType)
7911 : {
7912 106680 : OGRwkbGeometryType eFGeomType = wkbFlatten(eGeomType);
7913 106672 : return eFGeomType == wkbCurve || eFGeomType == wkbSurface ||
7914 106618 : eFGeomType == wkbCircularString || eFGeomType == wkbCompoundCurve ||
7915 213352 : eFGeomType == wkbCurvePolygon || eFGeomType == wkbMultiCurve ||
7916 106680 : eFGeomType == wkbMultiSurface;
7917 : }
7918 :
7919 : /************************************************************************/
7920 : /* CastToError() */
7921 : /************************************************************************/
7922 :
7923 : //! @cond Doxygen_Suppress
7924 0 : OGRGeometry *OGRGeometry::CastToError(OGRGeometry *poGeom)
7925 : {
7926 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s found. Conversion impossible",
7927 0 : poGeom->getGeometryName());
7928 0 : delete poGeom;
7929 0 : return nullptr;
7930 : }
7931 :
7932 : //! @endcond
7933 :
7934 : /************************************************************************/
7935 : /* OGRexportToSFCGAL() */
7936 : /************************************************************************/
7937 :
7938 : //! @cond Doxygen_Suppress
7939 : sfcgal_geometry_t *
7940 0 : OGRGeometry::OGRexportToSFCGAL(UNUSED_IF_NO_SFCGAL const OGRGeometry *poGeom)
7941 : {
7942 : #ifdef HAVE_SFCGAL
7943 : sfcgal_init();
7944 : char *buffer = nullptr;
7945 :
7946 : // special cases - LinearRing, Circular String, Compound Curve, Curve
7947 : // Polygon
7948 :
7949 : if (EQUAL(poGeom->getGeometryName(), "LINEARRING"))
7950 : {
7951 : // cast it to LineString and get the WKT
7952 : std::unique_ptr<OGRLineString> poLS(
7953 : OGRCurve::CastToLineString(poGeom->clone()->toCurve()));
7954 : if (poLS->exportToWkt(&buffer) == OGRERR_NONE)
7955 : {
7956 : sfcgal_geometry_t *_geometry =
7957 : sfcgal_io_read_wkt(buffer, strlen(buffer));
7958 : CPLFree(buffer);
7959 : return _geometry;
7960 : }
7961 : else
7962 : {
7963 : CPLFree(buffer);
7964 : return nullptr;
7965 : }
7966 : }
7967 : else if (EQUAL(poGeom->getGeometryName(), "CIRCULARSTRING") ||
7968 : EQUAL(poGeom->getGeometryName(), "COMPOUNDCURVE"))
7969 : {
7970 : // convert it to LineString and get the WKT
7971 : std::unique_ptr<OGRLineString> poLS(
7972 : OGRGeometryFactory::forceToLineString(poGeom->clone())
7973 : ->toLineString());
7974 : if (poLS->exportToWkt(&buffer) == OGRERR_NONE)
7975 : {
7976 : sfcgal_geometry_t *_geometry =
7977 : sfcgal_io_read_wkt(buffer, strlen(buffer));
7978 : CPLFree(buffer);
7979 : return _geometry;
7980 : }
7981 : else
7982 : {
7983 : CPLFree(buffer);
7984 : return nullptr;
7985 : }
7986 : }
7987 : else if (EQUAL(poGeom->getGeometryName(), "CURVEPOLYGON"))
7988 : {
7989 : // convert it to Polygon and get the WKT
7990 : std::unique_ptr<OGRPolygon> poPolygon(
7991 : OGRGeometryFactory::forceToPolygon(
7992 : poGeom->clone()->toCurvePolygon())
7993 : ->toPolygon());
7994 : if (poPolygon->exportToWkt(&buffer) == OGRERR_NONE)
7995 : {
7996 : sfcgal_geometry_t *_geometry =
7997 : sfcgal_io_read_wkt(buffer, strlen(buffer));
7998 : CPLFree(buffer);
7999 : return _geometry;
8000 : }
8001 : else
8002 : {
8003 : CPLFree(buffer);
8004 : return nullptr;
8005 : }
8006 : }
8007 : else if (poGeom->exportToWkt(&buffer) == OGRERR_NONE)
8008 : {
8009 : sfcgal_geometry_t *_geometry =
8010 : sfcgal_io_read_wkt(buffer, strlen(buffer));
8011 : CPLFree(buffer);
8012 : return _geometry;
8013 : }
8014 : else
8015 : {
8016 : CPLFree(buffer);
8017 : return nullptr;
8018 : }
8019 : #else
8020 0 : CPLError(CE_Failure, CPLE_NotSupported, "SFCGAL support not enabled.");
8021 0 : return nullptr;
8022 : #endif
8023 : }
8024 :
8025 : //! @endcond
8026 :
8027 : /************************************************************************/
8028 : /* SFCGALexportToOGR() */
8029 : /************************************************************************/
8030 :
8031 : //! @cond Doxygen_Suppress
8032 0 : OGRGeometry *OGRGeometry::SFCGALexportToOGR(
8033 : UNUSED_IF_NO_SFCGAL const sfcgal_geometry_t *geometry)
8034 : {
8035 : #ifdef HAVE_SFCGAL
8036 : if (geometry == nullptr)
8037 : return nullptr;
8038 :
8039 : sfcgal_init();
8040 : char *pabySFCGALWKT = nullptr;
8041 : size_t nLength = 0;
8042 : sfcgal_geometry_as_text_decim(geometry, 19, &pabySFCGALWKT, &nLength);
8043 : char *pszWKT = static_cast<char *>(CPLMalloc(nLength + 1));
8044 : memcpy(pszWKT, pabySFCGALWKT, nLength);
8045 : pszWKT[nLength] = 0;
8046 : free(pabySFCGALWKT);
8047 :
8048 : sfcgal_geometry_type_t geom_type = sfcgal_geometry_type_id(geometry);
8049 :
8050 : OGRGeometry *poGeom = nullptr;
8051 : if (geom_type == SFCGAL_TYPE_POINT)
8052 : {
8053 : poGeom = new OGRPoint();
8054 : }
8055 : else if (geom_type == SFCGAL_TYPE_LINESTRING)
8056 : {
8057 : poGeom = new OGRLineString();
8058 : }
8059 : else if (geom_type == SFCGAL_TYPE_POLYGON)
8060 : {
8061 : poGeom = new OGRPolygon();
8062 : }
8063 : else if (geom_type == SFCGAL_TYPE_MULTIPOINT)
8064 : {
8065 : poGeom = new OGRMultiPoint();
8066 : }
8067 : else if (geom_type == SFCGAL_TYPE_MULTILINESTRING)
8068 : {
8069 : poGeom = new OGRMultiLineString();
8070 : }
8071 : else if (geom_type == SFCGAL_TYPE_MULTIPOLYGON)
8072 : {
8073 : poGeom = new OGRMultiPolygon();
8074 : }
8075 : else if (geom_type == SFCGAL_TYPE_GEOMETRYCOLLECTION)
8076 : {
8077 : poGeom = new OGRGeometryCollection();
8078 : }
8079 : else if (geom_type == SFCGAL_TYPE_TRIANGLE)
8080 : {
8081 : poGeom = new OGRTriangle();
8082 : }
8083 : else if (geom_type == SFCGAL_TYPE_POLYHEDRALSURFACE)
8084 : {
8085 : poGeom = new OGRPolyhedralSurface();
8086 : }
8087 : else if (geom_type == SFCGAL_TYPE_TRIANGULATEDSURFACE)
8088 : {
8089 : poGeom = new OGRTriangulatedSurface();
8090 : }
8091 : else
8092 : {
8093 : CPLFree(pszWKT);
8094 : return nullptr;
8095 : }
8096 :
8097 : const char *pszWKTTmp = pszWKT;
8098 : if (poGeom->importFromWkt(&pszWKTTmp) == OGRERR_NONE)
8099 : {
8100 : CPLFree(pszWKT);
8101 : return poGeom;
8102 : }
8103 : else
8104 : {
8105 : delete poGeom;
8106 : CPLFree(pszWKT);
8107 : return nullptr;
8108 : }
8109 :
8110 : #else
8111 0 : CPLError(CE_Failure, CPLE_NotSupported, "SFCGAL support not enabled.");
8112 0 : return nullptr;
8113 : #endif
8114 : }
8115 :
8116 : //! @endcond
8117 :
8118 : //! @cond Doxygen_Suppress
8119 3945 : OGRBoolean OGRGeometry::IsSFCGALCompatible() const
8120 : {
8121 3945 : const OGRwkbGeometryType eGType = wkbFlatten(getGeometryType());
8122 3939 : if (eGType == wkbTriangle || eGType == wkbPolyhedralSurface ||
8123 : eGType == wkbTIN)
8124 : {
8125 2 : return TRUE;
8126 : }
8127 3937 : if (eGType == wkbGeometryCollection || eGType == wkbMultiSurface)
8128 : {
8129 6 : const OGRGeometryCollection *poGC = toGeometryCollection();
8130 8 : bool bIsSFCGALCompatible = false;
8131 8 : for (auto &&poSubGeom : *poGC)
8132 : {
8133 : OGRwkbGeometryType eSubGeomType =
8134 8 : wkbFlatten(poSubGeom->getGeometryType());
8135 8 : if (eSubGeomType == wkbTIN || eSubGeomType == wkbPolyhedralSurface)
8136 : {
8137 0 : bIsSFCGALCompatible = true;
8138 : }
8139 8 : else if (eSubGeomType != wkbMultiPolygon)
8140 : {
8141 8 : bIsSFCGALCompatible = false;
8142 8 : break;
8143 : }
8144 : }
8145 8 : return bIsSFCGALCompatible;
8146 : }
8147 3931 : return FALSE;
8148 : }
8149 :
8150 : //! @endcond
8151 :
8152 : /************************************************************************/
8153 : /* roundCoordinatesIEEE754() */
8154 : /************************************************************************/
8155 :
8156 : /** Round coordinates of a geometry, exploiting characteristics of the IEEE-754
8157 : * double-precision binary representation.
8158 : *
8159 : * Determines the number of bits (N) required to represent a coordinate value
8160 : * with a specified number of digits after the decimal point, and then sets all
8161 : * but the N most significant bits to zero. The resulting coordinate value will
8162 : * still round to the original value (e.g. after roundCoordinates()), but will
8163 : * have improved compressiblity.
8164 : *
8165 : * @param options Contains the precision requirements.
8166 : * @since GDAL 3.9
8167 : */
8168 1 : void OGRGeometry::roundCoordinatesIEEE754(
8169 : const OGRGeomCoordinateBinaryPrecision &options)
8170 : {
8171 : struct Quantizer : public OGRDefaultGeometryVisitor
8172 : {
8173 : const OGRGeomCoordinateBinaryPrecision &m_options;
8174 :
8175 1 : explicit Quantizer(const OGRGeomCoordinateBinaryPrecision &optionsIn)
8176 1 : : m_options(optionsIn)
8177 : {
8178 1 : }
8179 :
8180 : using OGRDefaultGeometryVisitor::visit;
8181 :
8182 3 : void visit(OGRPoint *poPoint) override
8183 : {
8184 3 : if (m_options.nXYBitPrecision != INT_MIN)
8185 : {
8186 : uint64_t i;
8187 : double d;
8188 3 : d = poPoint->getX();
8189 3 : memcpy(&i, &d, sizeof(i));
8190 3 : i = OGRRoundValueIEEE754(i, m_options.nXYBitPrecision);
8191 3 : memcpy(&d, &i, sizeof(i));
8192 3 : poPoint->setX(d);
8193 3 : d = poPoint->getY();
8194 3 : memcpy(&i, &d, sizeof(i));
8195 3 : i = OGRRoundValueIEEE754(i, m_options.nXYBitPrecision);
8196 3 : memcpy(&d, &i, sizeof(i));
8197 3 : poPoint->setY(d);
8198 : }
8199 3 : if (m_options.nZBitPrecision != INT_MIN && poPoint->Is3D())
8200 : {
8201 : uint64_t i;
8202 : double d;
8203 3 : d = poPoint->getZ();
8204 3 : memcpy(&i, &d, sizeof(i));
8205 3 : i = OGRRoundValueIEEE754(i, m_options.nZBitPrecision);
8206 3 : memcpy(&d, &i, sizeof(i));
8207 3 : poPoint->setZ(d);
8208 : }
8209 3 : if (m_options.nMBitPrecision != INT_MIN && poPoint->IsMeasured())
8210 : {
8211 : uint64_t i;
8212 : double d;
8213 3 : d = poPoint->getM();
8214 3 : memcpy(&i, &d, sizeof(i));
8215 3 : i = OGRRoundValueIEEE754(i, m_options.nMBitPrecision);
8216 3 : memcpy(&d, &i, sizeof(i));
8217 3 : poPoint->setM(d);
8218 : }
8219 3 : }
8220 : };
8221 :
8222 2 : Quantizer quantizer(options);
8223 1 : accept(&quantizer);
8224 1 : }
8225 :
8226 : /************************************************************************/
8227 : /* visit() */
8228 : /************************************************************************/
8229 :
8230 105 : void OGRDefaultGeometryVisitor::_visit(OGRSimpleCurve *poGeom)
8231 : {
8232 1248 : for (auto &&oPoint : *poGeom)
8233 : {
8234 1143 : oPoint.accept(this);
8235 : }
8236 105 : }
8237 :
8238 104 : void OGRDefaultGeometryVisitor::visit(OGRLineString *poGeom)
8239 : {
8240 104 : _visit(poGeom);
8241 104 : }
8242 :
8243 80 : void OGRDefaultGeometryVisitor::visit(OGRLinearRing *poGeom)
8244 : {
8245 80 : visit(poGeom->toUpperClass());
8246 80 : }
8247 :
8248 1 : void OGRDefaultGeometryVisitor::visit(OGRCircularString *poGeom)
8249 : {
8250 1 : _visit(poGeom);
8251 1 : }
8252 :
8253 78 : void OGRDefaultGeometryVisitor::visit(OGRCurvePolygon *poGeom)
8254 : {
8255 159 : for (auto &&poSubGeom : *poGeom)
8256 81 : poSubGeom->accept(this);
8257 78 : }
8258 :
8259 77 : void OGRDefaultGeometryVisitor::visit(OGRPolygon *poGeom)
8260 : {
8261 77 : visit(poGeom->toUpperClass());
8262 77 : }
8263 :
8264 1 : void OGRDefaultGeometryVisitor::visit(OGRMultiPoint *poGeom)
8265 : {
8266 1 : visit(poGeom->toUpperClass());
8267 1 : }
8268 :
8269 8 : void OGRDefaultGeometryVisitor::visit(OGRMultiLineString *poGeom)
8270 : {
8271 8 : visit(poGeom->toUpperClass());
8272 8 : }
8273 :
8274 14 : void OGRDefaultGeometryVisitor::visit(OGRMultiPolygon *poGeom)
8275 : {
8276 14 : visit(poGeom->toUpperClass());
8277 14 : }
8278 :
8279 26 : void OGRDefaultGeometryVisitor::visit(OGRGeometryCollection *poGeom)
8280 : {
8281 75 : for (auto &&poSubGeom : *poGeom)
8282 49 : poSubGeom->accept(this);
8283 26 : }
8284 :
8285 1 : void OGRDefaultGeometryVisitor::visit(OGRCompoundCurve *poGeom)
8286 : {
8287 2 : for (auto &&poSubGeom : *poGeom)
8288 1 : poSubGeom->accept(this);
8289 1 : }
8290 :
8291 1 : void OGRDefaultGeometryVisitor::visit(OGRMultiCurve *poGeom)
8292 : {
8293 1 : visit(poGeom->toUpperClass());
8294 1 : }
8295 :
8296 1 : void OGRDefaultGeometryVisitor::visit(OGRMultiSurface *poGeom)
8297 : {
8298 1 : visit(poGeom->toUpperClass());
8299 1 : }
8300 :
8301 2 : void OGRDefaultGeometryVisitor::visit(OGRTriangle *poGeom)
8302 : {
8303 2 : visit(poGeom->toUpperClass());
8304 2 : }
8305 :
8306 2 : void OGRDefaultGeometryVisitor::visit(OGRPolyhedralSurface *poGeom)
8307 : {
8308 4 : for (auto &&poSubGeom : *poGeom)
8309 2 : poSubGeom->accept(this);
8310 2 : }
8311 :
8312 1 : void OGRDefaultGeometryVisitor::visit(OGRTriangulatedSurface *poGeom)
8313 : {
8314 1 : visit(poGeom->toUpperClass());
8315 1 : }
8316 :
8317 14 : void OGRDefaultConstGeometryVisitor::_visit(const OGRSimpleCurve *poGeom)
8318 : {
8319 66 : for (auto &&oPoint : *poGeom)
8320 : {
8321 52 : oPoint.accept(this);
8322 : }
8323 14 : }
8324 :
8325 13 : void OGRDefaultConstGeometryVisitor::visit(const OGRLineString *poGeom)
8326 : {
8327 13 : _visit(poGeom);
8328 13 : }
8329 :
8330 8 : void OGRDefaultConstGeometryVisitor::visit(const OGRLinearRing *poGeom)
8331 : {
8332 8 : visit(poGeom->toUpperClass());
8333 8 : }
8334 :
8335 1 : void OGRDefaultConstGeometryVisitor::visit(const OGRCircularString *poGeom)
8336 : {
8337 1 : _visit(poGeom);
8338 1 : }
8339 :
8340 8 : void OGRDefaultConstGeometryVisitor::visit(const OGRCurvePolygon *poGeom)
8341 : {
8342 17 : for (auto &&poSubGeom : *poGeom)
8343 9 : poSubGeom->accept(this);
8344 8 : }
8345 :
8346 7 : void OGRDefaultConstGeometryVisitor::visit(const OGRPolygon *poGeom)
8347 : {
8348 7 : visit(poGeom->toUpperClass());
8349 7 : }
8350 :
8351 40 : void OGRDefaultConstGeometryVisitor::visit(const OGRMultiPoint *poGeom)
8352 : {
8353 40 : visit(poGeom->toUpperClass());
8354 40 : }
8355 :
8356 1 : void OGRDefaultConstGeometryVisitor::visit(const OGRMultiLineString *poGeom)
8357 : {
8358 1 : visit(poGeom->toUpperClass());
8359 1 : }
8360 :
8361 1 : void OGRDefaultConstGeometryVisitor::visit(const OGRMultiPolygon *poGeom)
8362 : {
8363 1 : visit(poGeom->toUpperClass());
8364 1 : }
8365 :
8366 45 : void OGRDefaultConstGeometryVisitor::visit(const OGRGeometryCollection *poGeom)
8367 : {
8368 217 : for (auto &&poSubGeom : *poGeom)
8369 172 : poSubGeom->accept(this);
8370 45 : }
8371 :
8372 1 : void OGRDefaultConstGeometryVisitor::visit(const OGRCompoundCurve *poGeom)
8373 : {
8374 2 : for (auto &&poSubGeom : *poGeom)
8375 1 : poSubGeom->accept(this);
8376 1 : }
8377 :
8378 1 : void OGRDefaultConstGeometryVisitor::visit(const OGRMultiCurve *poGeom)
8379 : {
8380 1 : visit(poGeom->toUpperClass());
8381 1 : }
8382 :
8383 1 : void OGRDefaultConstGeometryVisitor::visit(const OGRMultiSurface *poGeom)
8384 : {
8385 1 : visit(poGeom->toUpperClass());
8386 1 : }
8387 :
8388 2 : void OGRDefaultConstGeometryVisitor::visit(const OGRTriangle *poGeom)
8389 : {
8390 2 : visit(poGeom->toUpperClass());
8391 2 : }
8392 :
8393 2 : void OGRDefaultConstGeometryVisitor::visit(const OGRPolyhedralSurface *poGeom)
8394 : {
8395 4 : for (auto &&poSubGeom : *poGeom)
8396 2 : poSubGeom->accept(this);
8397 2 : }
8398 :
8399 1 : void OGRDefaultConstGeometryVisitor::visit(const OGRTriangulatedSurface *poGeom)
8400 : {
8401 1 : visit(poGeom->toUpperClass());
8402 1 : }
8403 :
8404 : /************************************************************************/
8405 : /* OGRGeometryUniquePtrDeleter */
8406 : /************************************************************************/
8407 :
8408 : //! @cond Doxygen_Suppress
8409 112 : void OGRGeometryUniquePtrDeleter::operator()(OGRGeometry *poGeom) const
8410 : {
8411 112 : delete poGeom;
8412 112 : }
8413 :
8414 : //! @endcond
8415 :
8416 : /************************************************************************/
8417 : /* OGRPreparedGeometryUniquePtrDeleter */
8418 : /************************************************************************/
8419 :
8420 : //! @cond Doxygen_Suppress
8421 38 : void OGRPreparedGeometryUniquePtrDeleter::operator()(
8422 : OGRPreparedGeometry *poPreparedGeom) const
8423 : {
8424 38 : OGRDestroyPreparedGeometry(poPreparedGeom);
8425 38 : }
8426 :
8427 : //! @endcond
8428 :
8429 : /************************************************************************/
8430 : /* HomogenizeDimensionalityWith() */
8431 : /************************************************************************/
8432 :
8433 : //! @cond Doxygen_Suppress
8434 3136530 : void OGRGeometry::HomogenizeDimensionalityWith(OGRGeometry *poOtherGeom)
8435 : {
8436 3136530 : if (poOtherGeom->Is3D() && !Is3D())
8437 1293900 : set3D(TRUE);
8438 :
8439 3136520 : if (poOtherGeom->IsMeasured() && !IsMeasured())
8440 792 : setMeasured(TRUE);
8441 :
8442 3136530 : if (!poOtherGeom->Is3D() && Is3D())
8443 295 : poOtherGeom->set3D(TRUE);
8444 :
8445 3136530 : if (!poOtherGeom->IsMeasured() && IsMeasured())
8446 28 : poOtherGeom->setMeasured(TRUE);
8447 3136520 : }
8448 :
8449 : //! @endcond
8450 :
8451 : /************************************************************************/
8452 : /* OGRGeomCoordinateBinaryPrecision::SetFrom() */
8453 : /************************************************************************/
8454 :
8455 : /** Set binary precision options from resolution.
8456 : *
8457 : * @since GDAL 3.9
8458 : */
8459 16 : void OGRGeomCoordinateBinaryPrecision::SetFrom(
8460 : const OGRGeomCoordinatePrecision &prec)
8461 : {
8462 16 : if (prec.dfXYResolution != 0)
8463 : {
8464 16 : nXYBitPrecision =
8465 16 : static_cast<int>(ceil(log2(1. / prec.dfXYResolution)));
8466 : }
8467 16 : if (prec.dfZResolution != 0)
8468 : {
8469 12 : nZBitPrecision = static_cast<int>(ceil(log2(1. / prec.dfZResolution)));
8470 : }
8471 16 : if (prec.dfMResolution != 0)
8472 : {
8473 12 : nMBitPrecision = static_cast<int>(ceil(log2(1. / prec.dfMResolution)));
8474 : }
8475 16 : }
8476 :
8477 : /************************************************************************/
8478 : /* OGRwkbExportOptionsCreate() */
8479 : /************************************************************************/
8480 :
8481 : /**
8482 : * \brief Create geometry WKB export options.
8483 : *
8484 : * The default is Intel order, old-OGC wkb variant and 0 discarded lsb bits.
8485 : *
8486 : * @return object to be freed with OGRwkbExportOptionsDestroy().
8487 : * @since GDAL 3.9
8488 : */
8489 2 : OGRwkbExportOptions *OGRwkbExportOptionsCreate()
8490 : {
8491 2 : return new OGRwkbExportOptions;
8492 : }
8493 :
8494 : /************************************************************************/
8495 : /* OGRwkbExportOptionsDestroy() */
8496 : /************************************************************************/
8497 :
8498 : /**
8499 : * \brief Destroy object returned by OGRwkbExportOptionsCreate()
8500 : *
8501 : * @param psOptions WKB export options
8502 : * @since GDAL 3.9
8503 : */
8504 :
8505 2 : void OGRwkbExportOptionsDestroy(OGRwkbExportOptions *psOptions)
8506 : {
8507 2 : delete psOptions;
8508 2 : }
8509 :
8510 : /************************************************************************/
8511 : /* OGRwkbExportOptionsSetByteOrder() */
8512 : /************************************************************************/
8513 :
8514 : /**
8515 : * \brief Set the WKB byte order.
8516 : *
8517 : * @param psOptions WKB export options
8518 : * @param eByteOrder Byte order: wkbXDR (big-endian) or wkbNDR (little-endian,
8519 : * Intel)
8520 : * @since GDAL 3.9
8521 : */
8522 :
8523 1 : void OGRwkbExportOptionsSetByteOrder(OGRwkbExportOptions *psOptions,
8524 : OGRwkbByteOrder eByteOrder)
8525 : {
8526 1 : psOptions->eByteOrder = eByteOrder;
8527 1 : }
8528 :
8529 : /************************************************************************/
8530 : /* OGRwkbExportOptionsSetVariant() */
8531 : /************************************************************************/
8532 :
8533 : /**
8534 : * \brief Set the WKB variant
8535 : *
8536 : * @param psOptions WKB export options
8537 : * @param eWkbVariant variant: wkbVariantOldOgc, wkbVariantIso,
8538 : * wkbVariantPostGIS1
8539 : * @since GDAL 3.9
8540 : */
8541 :
8542 1 : void OGRwkbExportOptionsSetVariant(OGRwkbExportOptions *psOptions,
8543 : OGRwkbVariant eWkbVariant)
8544 : {
8545 1 : psOptions->eWkbVariant = eWkbVariant;
8546 1 : }
8547 :
8548 : /************************************************************************/
8549 : /* OGRwkbExportOptionsSetPrecision() */
8550 : /************************************************************************/
8551 :
8552 : /**
8553 : * \brief Set precision options
8554 : *
8555 : * @param psOptions WKB export options
8556 : * @param hPrecisionOptions Precision options (might be null to reset them)
8557 : * @since GDAL 3.9
8558 : */
8559 :
8560 1 : void OGRwkbExportOptionsSetPrecision(
8561 : OGRwkbExportOptions *psOptions,
8562 : OGRGeomCoordinatePrecisionH hPrecisionOptions)
8563 : {
8564 1 : psOptions->sPrecision = OGRGeomCoordinateBinaryPrecision();
8565 1 : if (hPrecisionOptions)
8566 1 : psOptions->sPrecision.SetFrom(*hPrecisionOptions);
8567 1 : }
8568 :
8569 : /************************************************************************/
8570 : /* IsRectangle() */
8571 : /************************************************************************/
8572 :
8573 : /**
8574 : * \brief Returns whether the geometry is a polygon with 4 corners forming
8575 : * a rectangle.
8576 : *
8577 : * @since GDAL 3.10
8578 : */
8579 51943 : bool OGRGeometry::IsRectangle() const
8580 : {
8581 51943 : if (wkbFlatten(getGeometryType()) != wkbPolygon)
8582 237 : return false;
8583 :
8584 51706 : const OGRPolygon *poPoly = toPolygon();
8585 :
8586 51706 : if (poPoly->getNumInteriorRings() != 0)
8587 19 : return false;
8588 :
8589 51687 : const OGRLinearRing *poRing = poPoly->getExteriorRing();
8590 51687 : if (!poRing)
8591 4 : return false;
8592 :
8593 51683 : if (poRing->getNumPoints() > 5 || poRing->getNumPoints() < 4)
8594 4 : return false;
8595 :
8596 : // If the ring has 5 points, the last should be the first.
8597 103321 : if (poRing->getNumPoints() == 5 && (poRing->getX(0) != poRing->getX(4) ||
8598 51642 : poRing->getY(0) != poRing->getY(4)))
8599 1 : return false;
8600 :
8601 : // Polygon with first segment in "y" direction.
8602 102730 : if (poRing->getX(0) == poRing->getX(1) &&
8603 102103 : poRing->getY(1) == poRing->getY(2) &&
8604 153781 : poRing->getX(2) == poRing->getX(3) &&
8605 51051 : poRing->getY(3) == poRing->getY(0))
8606 51051 : return true;
8607 :
8608 : // Polygon with first segment in "x" direction.
8609 1215 : if (poRing->getY(0) == poRing->getY(1) &&
8610 1176 : poRing->getX(1) == poRing->getX(2) &&
8611 1803 : poRing->getY(2) == poRing->getY(3) &&
8612 588 : poRing->getX(3) == poRing->getX(0))
8613 588 : return true;
8614 :
8615 39 : return false;
8616 : }
8617 :
8618 : /************************************************************************/
8619 : /* hasEmptyParts() */
8620 : /************************************************************************/
8621 :
8622 : /**
8623 : * \brief Returns whether a geometry has empty parts/rings.
8624 : *
8625 : * Returns true if removeEmptyParts() will modify the geometry.
8626 : *
8627 : * This is different from IsEmpty().
8628 : *
8629 : * @since GDAL 3.10
8630 : */
8631 19 : bool OGRGeometry::hasEmptyParts() const
8632 : {
8633 19 : return false;
8634 : }
8635 :
8636 : /************************************************************************/
8637 : /* removeEmptyParts() */
8638 : /************************************************************************/
8639 :
8640 : /**
8641 : * \brief Remove empty parts/rings from this geometry.
8642 : *
8643 : * @since GDAL 3.10
8644 : */
8645 17 : void OGRGeometry::removeEmptyParts()
8646 : {
8647 17 : }
|