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 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 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 91 int OGRWktOptions::getDefaultPrecision() 92 { 93 return atoi(CPLGetConfigOption("OGR_WKT_PRECISION", "15")); 94 } 95 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 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 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 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 183 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 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 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 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 504 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 551 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 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 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 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 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 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 */ 774 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 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 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 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 881 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 900 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 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 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 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 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 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 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 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 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 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 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 1184 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 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 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 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 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 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 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 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 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 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 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 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 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 */ 1791 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 */ 1829 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 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 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 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 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 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 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 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 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 2145 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 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 2258 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 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 2330 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 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 */ 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 */ 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 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 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 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 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 2910 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 2933 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 2955 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 */ 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 /************************************************************************/ 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 */ 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 */ 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 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 */ 3063 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 3193 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 3226 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 3261 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 3289 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 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 3423 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 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 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 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 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 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 */ 3643 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 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 */ 3759 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 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 3842 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 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 3957 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 */ 3995 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 */ 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 */ 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 4084 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 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 4188 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 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 4307 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 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 4421 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 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 4508 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 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 * 4630 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 * 4678 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 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 */ 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 4770 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 */ 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 4844 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 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 4918 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 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 5026 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 */ 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 5100 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 */ 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 5175 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 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 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 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 5291 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 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 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 5496 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 5545 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 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 5624 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 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 5711 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) 5720 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 5728 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 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 5816 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 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 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 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 */ 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 */ 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 */ 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 */ 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 */ 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 7158 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 7196 void OGRDefaultGeometryVisitor::_visit(OGRSimpleCurve* poGeom) 7197 { 7198 for( auto&& oPoint: *poGeom ) 7199 { 7200 oPoint.accept(this); 7201 } 7202 } 7203 7204 void OGRDefaultGeometryVisitor::visit(OGRLineString* poGeom) 7205 { 7206 _visit(poGeom); 7207 } 7208 7209 void OGRDefaultGeometryVisitor::visit(OGRLinearRing* poGeom) 7210 { 7211 visit(poGeom->toUpperClass()); 7212 } 7213 7214 void OGRDefaultGeometryVisitor::visit(OGRCircularString* poGeom) 7215 { 7216 _visit(poGeom); 7217 } 7218 7219 void OGRDefaultGeometryVisitor::visit(OGRCurvePolygon* poGeom) 7220 { 7221 for( auto&& poSubGeom: *poGeom ) 7222 poSubGeom->accept(this); 7223 } 7224 7225 void OGRDefaultGeometryVisitor::visit(OGRPolygon* poGeom) 7226 { 7227 visit(poGeom->toUpperClass()); 7228 } 7229 7230 void OGRDefaultGeometryVisitor::visit(OGRMultiPoint* poGeom) 7231 { 7232 visit(poGeom->toUpperClass()); 7233 } 7234 7235 void OGRDefaultGeometryVisitor::visit(OGRMultiLineString* poGeom) 7236 { 7237 visit(poGeom->toUpperClass()); 7238 } 7239 7240 void OGRDefaultGeometryVisitor::visit(OGRMultiPolygon* poGeom) 7241 { 7242 visit(poGeom->toUpperClass()); 7243 } 7244 7245 void OGRDefaultGeometryVisitor::visit(OGRGeometryCollection* poGeom) 7246 { 7247 for( auto&& poSubGeom: *poGeom ) 7248 poSubGeom->accept(this); 7249 } 7250 7251 void OGRDefaultGeometryVisitor::visit(OGRCompoundCurve* poGeom) 7252 { 7253 for( auto&& poSubGeom: *poGeom ) 7254 poSubGeom->accept(this); 7255 } 7256 7257 void OGRDefaultGeometryVisitor::visit(OGRMultiCurve* poGeom) 7258 { 7259 visit(poGeom->toUpperClass()); 7260 } 7261 7262 void OGRDefaultGeometryVisitor::visit(OGRMultiSurface* poGeom) 7263 { 7264 visit(poGeom->toUpperClass()); 7265 } 7266 7267 void OGRDefaultGeometryVisitor::visit(OGRTriangle* poGeom) 7268 { 7269 visit(poGeom->toUpperClass()); 7270 } 7271 7272 void OGRDefaultGeometryVisitor::visit(OGRPolyhedralSurface* poGeom) 7273 { 7274 for( auto&& poSubGeom: *poGeom ) 7275 poSubGeom->accept(this); 7276 } 7277 7278 void OGRDefaultGeometryVisitor::visit(OGRTriangulatedSurface* poGeom) 7279 { 7280 visit(poGeom->toUpperClass()); 7281 } 7282 7283 7284 7285 void OGRDefaultConstGeometryVisitor::_visit(const OGRSimpleCurve* poGeom) 7286 { 7287 for( auto&& oPoint: *poGeom ) 7288 { 7289 oPoint.accept(this); 7290 } 7291 } 7292 7293 void OGRDefaultConstGeometryVisitor::visit(const OGRLineString* poGeom) 7294 { 7295 _visit(poGeom); 7296 } 7297 7298 void OGRDefaultConstGeometryVisitor::visit(const OGRLinearRing* poGeom) 7299 { 7300 visit(poGeom->toUpperClass()); 7301 } 7302 7303 void OGRDefaultConstGeometryVisitor::visit(const OGRCircularString* poGeom) 7304 { 7305 _visit(poGeom); 7306 } 7307 7308 void OGRDefaultConstGeometryVisitor::visit(const OGRCurvePolygon* poGeom) 7309 { 7310 for( auto&& poSubGeom: *poGeom ) 7311 poSubGeom->accept(this); 7312 } 7313 7314 void OGRDefaultConstGeometryVisitor::visit(const OGRPolygon* poGeom) 7315 { 7316 visit(poGeom->toUpperClass()); 7317 } 7318 7319 void OGRDefaultConstGeometryVisitor::visit(const OGRMultiPoint* poGeom) 7320 { 7321 visit(poGeom->toUpperClass()); 7322 } 7323 7324 void OGRDefaultConstGeometryVisitor::visit(const OGRMultiLineString* poGeom) 7325 { 7326 visit(poGeom->toUpperClass()); 7327 } 7328 7329 void OGRDefaultConstGeometryVisitor::visit(const OGRMultiPolygon* poGeom) 7330 { 7331 visit(poGeom->toUpperClass()); 7332 } 7333 7334 void OGRDefaultConstGeometryVisitor::visit(const OGRGeometryCollection* poGeom) 7335 { 7336 for( auto&& poSubGeom: *poGeom ) 7337 poSubGeom->accept(this); 7338 } 7339 7340 void OGRDefaultConstGeometryVisitor::visit(const OGRCompoundCurve* poGeom) 7341 { 7342 for( auto&& poSubGeom: *poGeom ) 7343 poSubGeom->accept(this); 7344 } 7345 7346 void OGRDefaultConstGeometryVisitor::visit(const OGRMultiCurve* poGeom) 7347 { 7348 visit(poGeom->toUpperClass()); 7349 } 7350 7351 void OGRDefaultConstGeometryVisitor::visit(const OGRMultiSurface* poGeom) 7352 { 7353 visit(poGeom->toUpperClass()); 7354 } 7355 7356 void OGRDefaultConstGeometryVisitor::visit(const OGRTriangle* poGeom) 7357 { 7358 visit(poGeom->toUpperClass()); 7359 } 7360 7361 void OGRDefaultConstGeometryVisitor::visit(const OGRPolyhedralSurface* poGeom) 7362 { 7363 for( auto&& poSubGeom: *poGeom ) 7364 poSubGeom->accept(this); 7365 } 7366 7367 void OGRDefaultConstGeometryVisitor::visit(const OGRTriangulatedSurface* poGeom) 7368 { 7369 visit(poGeom->toUpperClass()); 7370 } 7371 7372 /************************************************************************/ 7373 /* OGRGeometryUniquePtrDeleter */ 7374 /************************************************************************/ 7375 7376 //! @cond Doxygen_Suppress 7377 void OGRGeometryUniquePtrDeleter::operator()(OGRGeometry* poGeom) const 7378 { 7379 delete poGeom; 7380 } 7381 //! @endcond 7382 7383 /************************************************************************/ 7384 /* OGRPreparedGeometryUniquePtrDeleter */ 7385 /************************************************************************/ 7386 7387 //! @cond Doxygen_Suppress 7388 void OGRPreparedGeometryUniquePtrDeleter::operator()(OGRPreparedGeometry* poPreparedGeom) const 7389 { 7390 OGRDestroyPreparedGeometry(poPreparedGeom); 7391 } 7392 //! @endcond 7393 7394 /************************************************************************/ 7395 /* HomogenizeDimensionalityWith() */ 7396 /************************************************************************/ 7397 7398 //! @cond Doxygen_Suppress 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