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