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