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