32#define DEFAULT_QUADRANT_SEGMENTS 8
34#define CATCH_GEOS(r) \
35 catch (GEOSException &) \
40#define CATCH_GEOS_WITH_ERRMSG(r) \
41 catch (GEOSException &e) \
45 *errorMsg = e.what(); \
52static void throwGEOSException(
const char *fmt, ... )
58 vsnprintf( buffer,
sizeof buffer, fmt, ap );
61 QString message = QString::fromUtf8( buffer );
71 throw GEOSException( message );
79 throw GEOSException( message );
84static void printGEOSNotice(
const char *fmt, ... )
91 vsnprintf( buffer,
sizeof buffer, fmt, ap );
102#if defined(USE_THREAD_LOCAL) && !defined(Q_OS_WIN)
105QThreadStorage< QgsGeosContext * > QgsGeosContext::sGeosContext;
111#if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=5 )
112 mContext = GEOS_init_r();
113 GEOSContext_setNoticeHandler_r( mContext, printGEOSNotice );
114 GEOSContext_setErrorHandler_r( mContext, throwGEOSException );
116 mContext = initGEOS_r( printGEOSNotice, throwGEOSException );
122#if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=5 )
123 GEOS_finish_r( mContext );
125 finishGEOS_r( mContext );
131#if defined(USE_THREAD_LOCAL) && !defined(Q_OS_WIN)
132 return sGeosContext.mContext;
134 GEOSContextHandle_t gContext =
nullptr;
135 if ( sGeosContext.hasLocalData() )
137 gContext = sGeosContext.localData()->mContext;
142 gContext = sGeosContext.localData()->mContext;
152void geos::GeosDeleter::operator()(
GEOSGeometry *geom )
const
157void geos::GeosDeleter::operator()(
const GEOSPreparedGeometry *geom )
const
162void geos::GeosDeleter::operator()( GEOSBufferParams *params )
const
167void geos::GeosDeleter::operator()( GEOSCoordSequence *sequence )
const
206#if GEOS_VERSION_MAJOR==3 && GEOS_VERSION_MINOR<10
208 throw QgsNotSupportedException( QObject::tr(
"The structured method to make geometries valid requires a QGIS build based on GEOS 3.10 or later" ) );
211 throw QgsNotSupportedException( QObject::tr(
"The keep collapsed option for making geometries valid requires a QGIS build based on GEOS 3.10 or later" ) );
212 geos::unique_ptr
geos;
215 geos.reset( GEOSMakeValid_r( context, mGeos.get() ) );
220 GEOSMakeValidParams *params = GEOSMakeValidParams_create_r( context );
224 GEOSMakeValidParams_setMethod_r( context, params, GEOS_MAKE_VALID_LINEWORK );
228 GEOSMakeValidParams_setMethod_r( context, params, GEOS_MAKE_VALID_STRUCTURE );
232 GEOSMakeValidParams_setKeepCollapsed_r( context,
234 keepCollapsed ? 1 : 0 );
236 geos::unique_ptr
geos;
239 geos.reset( GEOSMakeValidWithParams_r( context, mGeos.get(), params ) );
240 GEOSMakeValidParams_destroy_r( context, params );
242 catch ( GEOSException &e )
246 *errorMsg = e.what();
248 GEOSMakeValidParams_destroy_r( context, params );
277 std::unique_ptr< QgsAbstractGeometry > geom =
fromGeos( newPart );
284 mGeosPrepared.reset();
318 return overlay( geom, OverlayIntersection, errorMsg, parameters ).release();
323 return overlay( geom, OverlayDifference, errorMsg, parameters ).release();
338 catch ( GEOSException &e )
340 logError( QStringLiteral(
"GEOS" ), e.what() );
343 *errorMsg = e.what();
352 int partType = GEOSGeomTypeId_r( context, currentPart );
355 if ( partType == GEOS_POINT )
366 if ( partType == GEOS_MULTILINESTRING || partType == GEOS_MULTIPOLYGON || partType == GEOS_GEOMETRYCOLLECTION )
368 int partCount = GEOSGetNumGeometries_r( context, currentPart );
369 for (
int i = 0; i < partCount; ++i )
371 subdivideRecursive( GEOSGetGeometryN_r( context, currentPart, i ), maxNodes, depth, parts, clipRect, gridSize );
382 int vertexCount = GEOSGetNumCoordinates_r( context, currentPart );
383 if ( vertexCount == 0 )
387 else if ( vertexCount < maxNodes )
394 double width = clipRect.
width();
395 double height = clipRect.
height();
398 if ( width > height )
411 halfClipRect1.
setYMinimum( halfClipRect1.
yMinimum() - std::numeric_limits<double>::epsilon() );
412 halfClipRect2.
setYMinimum( halfClipRect2.
yMinimum() - std::numeric_limits<double>::epsilon() );
413 halfClipRect1.
setYMaximum( halfClipRect1.
yMaximum() + std::numeric_limits<double>::epsilon() );
414 halfClipRect2.
setYMaximum( halfClipRect2.
yMaximum() + std::numeric_limits<double>::epsilon() );
418 halfClipRect1.
setXMinimum( halfClipRect1.
xMinimum() - std::numeric_limits<double>::epsilon() );
419 halfClipRect2.
setXMinimum( halfClipRect2.
xMinimum() - std::numeric_limits<double>::epsilon() );
420 halfClipRect1.
setXMaximum( halfClipRect1.
xMaximum() + std::numeric_limits<double>::epsilon() );
421 halfClipRect2.
setXMaximum( halfClipRect2.
xMaximum() + std::numeric_limits<double>::epsilon() );
424 geos::unique_ptr clipPart1( GEOSClipByRect_r( context, currentPart, halfClipRect1.
xMinimum(), halfClipRect1.
yMinimum(), halfClipRect1.
xMaximum(), halfClipRect1.
yMaximum() ) );
425 geos::unique_ptr clipPart2( GEOSClipByRect_r( context, currentPart, halfClipRect2.
xMinimum(), halfClipRect2.
yMinimum(), halfClipRect2.
xMaximum(), halfClipRect2.
yMaximum() ) );
433 clipPart1.reset( GEOSIntersectionPrec_r( context, mGeos.get(), clipPart1.get(), gridSize ) );
435 subdivideRecursive( clipPart1.get(), maxNodes, depth, parts, halfClipRect1, gridSize );
441 clipPart2.reset( GEOSIntersectionPrec_r( context, mGeos.get(), clipPart2.get(), gridSize ) );
443 subdivideRecursive( clipPart2.get(), maxNodes, depth, parts, halfClipRect2, gridSize );
455 maxNodes = std::max( maxNodes, 8 );
464 return std::move( parts );
469 return overlay( geom, OverlayUnion, errorMsg, parameters ).release();
474 std::vector<geos::unique_ptr> geosGeometries;
475 geosGeometries.reserve( geomList.size() );
481 geosGeometries.emplace_back(
asGeos( g, mPrecision ) );
485 geos::unique_ptr geomUnion;
488 geos::unique_ptr geomCollection = createGeosCollection( GEOS_GEOMETRYCOLLECTION, geosGeometries );
491 geomUnion.reset( GEOSUnaryUnionPrec_r( context, geomCollection.get(), parameters.
gridSize() ) );
495 geomUnion.reset( GEOSUnaryUnion_r( context, geomCollection.get() ) );
500 std::unique_ptr< QgsAbstractGeometry > result =
fromGeos( geomUnion.get() );
501 return result.release();
506 std::vector<geos::unique_ptr> geosGeometries;
507 geosGeometries.reserve( geomList.size() );
513 geosGeometries.emplace_back(
asGeos( g.constGet(), mPrecision ) );
517 geos::unique_ptr geomUnion;
520 geos::unique_ptr geomCollection = createGeosCollection( GEOS_GEOMETRYCOLLECTION, geosGeometries );
524 geomUnion.reset( GEOSUnaryUnionPrec_r( context, geomCollection.get(), parameters.
gridSize() ) );
528 geomUnion.reset( GEOSUnaryUnion_r( context, geomCollection.get() ) );
534 std::unique_ptr< QgsAbstractGeometry > result =
fromGeos( geomUnion.get() );
535 return result.release();
540 return overlay( geom, OverlaySymDifference, errorMsg, parameters ).release();
551 geos::unique_ptr otherGeosGeom(
asGeos( geom, mPrecision ) );
552 if ( !otherGeosGeom )
562 GEOSPreparedDistance_r( context, mGeosPrepared.get(), otherGeosGeom.get(), &
distance );
566 GEOSDistance_r( context, mGeos.get(), otherGeosGeom.get(), &
distance );
582 geos::unique_ptr point = createGeosPointXY( x, y,
false, 0,
false, 0, 2, 0 );
591 GEOSPreparedDistance_r( context, mGeosPrepared.get(), point.get(), &
distance );
595 GEOSDistance_r( context, mGeos.get(), point.get(), &
distance );
610 geos::unique_ptr otherGeosGeom(
asGeos( geom, mPrecision ) );
611 if ( !otherGeosGeom )
626#if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=10 )
627 return GEOSPreparedDistanceWithin_r( context, mGeosPrepared.get(), otherGeosGeom.get(), maxdist );
629 GEOSPreparedDistance_r( context, mGeosPrepared.get(), otherGeosGeom.get(), &
distance );
634#if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=10 )
635 return GEOSDistanceWithin_r( context, mGeos.get(), otherGeosGeom.get(), maxdist );
637 GEOSDistance_r( context, mGeos.get(), otherGeosGeom.get(), &
distance );
652#if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=12 )
655 geos::unique_ptr point = createGeosPointXY( x, y,
false, 0,
false, 0, 2, 0 );
661#if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=12 )
662 return GEOSPreparedContainsXY_r( context, mGeosPrepared.get(), x, y ) == 1;
664 return GEOSPreparedContains_r( context, mGeosPrepared.get(), point.get() ) == 1;
668#if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=12 )
669 geos::unique_ptr point = createGeosPointXY( x, y,
false, 0,
false, 0, 2, 0 );
674 result = ( GEOSContains_r( context, mGeos.get(), point.get() ) == 1 );
676 catch ( GEOSException &e )
678 logError( QStringLiteral(
"GEOS" ), e.what() );
681 *errorMsg = e.what();
697 geos::unique_ptr otherGeosGeom(
asGeos( geom, mPrecision ) );
698 if ( !otherGeosGeom )
720 geos::unique_ptr otherGeosGeom(
asGeos( geom, mPrecision ) );
721 if ( !otherGeosGeom )
743 geos::unique_ptr otherGeosGeom(
asGeos( geom, mPrecision ) );
744 if ( !otherGeosGeom )
766 geos::unique_ptr otherGeosGeom(
asGeos( geom, mPrecision ) );
767 if ( !otherGeosGeom )
783 if ( !mGeos || !geom )
788#if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=12 )
796 return GEOSPreparedIntersectsXY_r(
QgsGeosContext::get(), mGeosPrepared.get(), point->x(), point->y() ) == 1;
798 catch ( GEOSException &e )
800 logError( QStringLiteral(
"GEOS" ), e.what() );
803 *errorMsg = e.what();
811 return relation( geom, RelationIntersects, errorMsg );
816 return relation( geom, RelationTouches, errorMsg );
821 return relation( geom, RelationCrosses, errorMsg );
826 return relation( geom, RelationWithin, errorMsg );
831 return relation( geom, RelationOverlaps, errorMsg );
836 if ( !mGeos || !geom )
841#if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=12 )
849 return GEOSPreparedContainsXY_r(
QgsGeosContext::get(), mGeosPrepared.get(), point->x(), point->y() ) == 1;
851 catch ( GEOSException &e )
853 logError( QStringLiteral(
"GEOS" ), e.what() );
856 *errorMsg = e.what();
864 return relation( geom, RelationContains, errorMsg );
869 return relation( geom, RelationDisjoint, errorMsg );
879 geos::unique_ptr geosGeom(
asGeos( geom, mPrecision ) );
889 char *r = GEOSRelate_r( context, mGeos.get(), geosGeom.get() );
892 result = QString( r );
893 GEOSFree_r( context, r );
896 catch ( GEOSException &e )
898 logError( QStringLiteral(
"GEOS" ), e.what() );
901 *errorMsg = e.what();
910 if ( !mGeos || !geom )
915 geos::unique_ptr geosGeom(
asGeos( geom, mPrecision ) );
925 result = ( GEOSRelatePattern_r( context, mGeos.get(), geosGeom.get(), pattern.toLocal8Bit().constData() ) == 1 );
927 catch ( GEOSException &e )
929 logError( QStringLiteral(
"GEOS" ), e.what() );
932 *errorMsg = e.what();
973 QVector<QgsGeometry> &newGeometries,
976 QString *errorMsg,
bool skipIntersectionCheck )
const
992 if ( !GEOSisValid_r( context, mGeos.get() ) )
1000 newGeometries.clear();
1001 geos::unique_ptr splitLineGeos;
1007 splitLineGeos = createGeosLinestring( &splitLine, mPrecision );
1011 splitLineGeos = createGeosPointXY( splitLine.
xAt( 0 ), splitLine.
yAt( 0 ),
false, 0,
false, 0, 2, mPrecision );
1018 if ( !GEOSisValid_r( context, splitLineGeos.get() ) || !GEOSisSimple_r( context, splitLineGeos.get() ) )
1026 if ( !topologicalTestPointsSplit( splitLineGeos.get(), topologyTestPoints ) )
1035 returnCode = splitLinearGeometry( splitLineGeos.get(), newGeometries, skipIntersectionCheck );
1039 returnCode = splitPolygonGeometry( splitLineGeos.get(), newGeometries, skipIntersectionCheck );
1068 geos::unique_ptr intersectionGeom( GEOSIntersection_r( context, mGeos.get(), splitLine ) );
1069 if ( !intersectionGeom )
1072 bool simple =
false;
1073 int nIntersectGeoms = 1;
1074 if ( GEOSGeomTypeId_r( context, intersectionGeom.get() ) == GEOS_LINESTRING
1075 || GEOSGeomTypeId_r( context, intersectionGeom.get() ) == GEOS_POINT )
1079 nIntersectGeoms = GEOSGetNumGeometries_r( context, intersectionGeom.get() );
1081 for (
int i = 0; i < nIntersectGeoms; ++i )
1085 currentIntersectGeom = intersectionGeom.get();
1087 currentIntersectGeom = GEOSGetGeometryN_r( context, intersectionGeom.get(), i );
1089 const GEOSCoordSequence *lineSequence = GEOSGeom_getCoordSeq_r( context, currentIntersectGeom );
1090 unsigned int sequenceSize = 0;
1092 if ( GEOSCoordSeq_getSize_r( context, lineSequence, &sequenceSize ) != 0 )
1094 for (
unsigned int i = 0; i < sequenceSize; ++i )
1096 if ( GEOSCoordSeq_getXYZ_r( context, lineSequence, i, &x, &y, &z ) )
1098 testPoints.push_back(
QgsPoint( x, y, z ) );
1112 int type = GEOSGeomTypeId_r( context, mGeos.get() );
1114 std::unique_ptr< QgsMultiCurve > multiCurve;
1115 if ( type == GEOS_MULTILINESTRING )
1117 multiCurve.reset( qgsgeometry_cast<QgsMultiCurve *>(
mGeometry->
clone() ) );
1119 else if ( type == GEOS_LINESTRING )
1137 std::unique_ptr< QgsMultiPoint > splitPoints;
1139 std::unique_ptr< QgsAbstractGeometry > splitGeom(
fromGeos( GEOSsplitPoint ) );
1141 if ( qgsgeometry_cast<QgsMultiPoint *>( splitGeom.get() ) )
1143 splitPoints.reset( qgsgeometry_cast<QgsMultiPoint *>( splitGeom.release() ) );
1145 else if ( qgsgeometry_cast<QgsPoint *>( splitGeom.get() ) )
1147 splitPoints = std::make_unique< QgsMultiPoint >();
1148 if ( qgsgeometry_cast<QgsPoint *>( splitGeom.get() ) )
1150 splitPoints->addGeometry( qgsgeometry_cast<QgsPoint *>( splitGeom.release() ) );
1158 for (
int geometryIndex = 0; geometryIndex < multiCurve->numGeometries(); ++geometryIndex )
1160 const QgsLineString *line = qgsgeometry_cast<const QgsLineString *>( multiCurve->geometryN( geometryIndex ) );
1163 const QgsCurve *curve = qgsgeometry_cast<const QgsCurve *>( multiCurve->geometryN( geometryIndex ) );
1171 QMap< int, QVector< QPair< double, QgsPoint > > >pointMap;
1172 for (
int splitPointIndex = 0; splitPointIndex < splitPoints->numGeometries(); ++splitPointIndex )
1174 const QgsPoint *intersectionPoint = splitPoints->pointN( splitPointIndex );
1180 line->
closestSegment( *intersectionPoint, segmentPoint2D, nextVertex );
1196 const QPair< double, QgsPoint > pair = qMakePair(
distance, *correctSegmentPoint.get() );
1197 if ( pointMap.contains( nextVertex.
vertex - 1 ) )
1198 pointMap[ nextVertex.
vertex - 1 ].append( pair );
1200 pointMap[ nextVertex.
vertex - 1 ] = QVector< QPair< double, QgsPoint > >() << pair;
1205 for (
auto &p : pointMap )
1207 std::sort( p.begin(), p.end(), [](
const QPair< double, QgsPoint > &a,
const QPair< double, QgsPoint > &b ) { return a.first < b.first; } );
1214 for (
int vertexIndex = 0; vertexIndex < nVertices; ++vertexIndex )
1218 if ( pointMap.contains( vertexIndex ) )
1221 for (
int k = 0; k < pointMap[ vertexIndex ].size(); ++k )
1223 splitPoint = pointMap[ vertexIndex ][k].second;
1224 if ( splitPoint == currentPoint )
1230 else if ( splitPoint == line->
pointN( vertexIndex + 1 ) )
1249 return asGeos( &lines, mPrecision );
1254 Q_UNUSED( skipIntersectionCheck )
1263 geos::unique_ptr intersectGeom( GEOSIntersection_r( context, splitLine, mGeos.get() ) );
1264 if ( !intersectGeom || GEOSisEmpty_r( context, intersectGeom.get() ) )
1268 const int linearIntersect = GEOSRelatePattern_r( context, mGeos.get(), splitLine,
"1********" );
1269 if ( linearIntersect > 0 )
1272 geos::unique_ptr splitGeom = linePointDifference( intersectGeom.get() );
1277 std::vector<geos::unique_ptr> lineGeoms;
1279 const int splitType = GEOSGeomTypeId_r( context, splitGeom.get() );
1280 if ( splitType == GEOS_MULTILINESTRING )
1282 const int nGeoms = GEOSGetNumGeometries_r( context, splitGeom.get() );
1283 lineGeoms.reserve( nGeoms );
1284 for (
int i = 0; i < nGeoms; ++i )
1285 lineGeoms.emplace_back( GEOSGeom_clone_r( context, GEOSGetGeometryN_r( context, splitGeom.get(), i ) ) );
1290 lineGeoms.emplace_back( GEOSGeom_clone_r( context, splitGeom.get() ) );
1293 mergeGeometriesMultiTypeSplit( lineGeoms );
1295 for ( geos::unique_ptr &lineGeom : lineGeoms )
1313 if ( !mGeosPrepared )
1319 if ( !skipIntersectionCheck && !GEOSPreparedIntersects_r( context, mGeosPrepared.get(), splitLine ) )
1323 geos::unique_ptr nodedGeometry = nodeGeometries( splitLine, mGeos.get() );
1324 if ( !nodedGeometry )
1328 geos::unique_ptr polygons( GEOSPolygonize_r( context, &noded, 1 ) );
1333 const int numberOfGeometriesPolygon = numberOfGeometries( polygons.get() );
1334 if ( numberOfGeometriesPolygon == 0 )
1341 std::vector<geos::unique_ptr> testedGeometries;
1346 for (
int i = 0; i < numberOfGeometriesPolygon; i++ )
1348 const GEOSGeometry *polygon = GEOSGetGeometryN_r( context, polygons.get(), i );
1350 geos::unique_ptr
pointOnSurface( GEOSPointOnSurface_r( context, polygon ) );
1352 testedGeometries.emplace_back( GEOSGeom_clone_r( context, polygon ) );
1355 const size_t nGeometriesThis = numberOfGeometries( mGeos.get() );
1356 if ( testedGeometries.empty() || testedGeometries.size() == nGeometriesThis )
1366 mergeGeometriesMultiTypeSplit( testedGeometries );
1369 for ( i = 0; i < testedGeometries.size() && GEOSisValid_r( context, testedGeometries[i].get() ); ++i )
1372 if ( i < testedGeometries.size() )
1377 for ( geos::unique_ptr &testedGeometry : testedGeometries )
1387 if ( !splitLine || !geom )
1390 geos::unique_ptr geometryBoundary;
1392 if ( GEOSGeomTypeId_r( context, geom ) == GEOS_POLYGON || GEOSGeomTypeId_r( context, geom ) == GEOS_MULTIPOLYGON )
1393 geometryBoundary.reset( GEOSBoundary_r( context, geom ) );
1395 geometryBoundary.reset( GEOSGeom_clone_r( context, geom ) );
1397 geos::unique_ptr splitLineClone( GEOSGeom_clone_r( context, splitLine ) );
1398 geos::unique_ptr unionGeometry( GEOSUnion_r( context, splitLineClone.get(), geometryBoundary.get() ) );
1400 return unionGeometry;
1403int QgsGeos::mergeGeometriesMultiTypeSplit( std::vector<geos::unique_ptr> &splitResult )
const
1410 int type = GEOSGeomTypeId_r( context, mGeos.get() );
1411 if ( type != GEOS_GEOMETRYCOLLECTION &&
1412 type != GEOS_MULTILINESTRING &&
1413 type != GEOS_MULTIPOLYGON &&
1414 type != GEOS_MULTIPOINT )
1418 std::vector<geos::unique_ptr> unionGeom;
1420 std::vector<geos::unique_ptr> newSplitResult;
1422 for (
size_t i = 0; i < splitResult.size(); ++i )
1425 bool isPart =
false;
1426 for (
int j = 0; j < GEOSGetNumGeometries_r( context, mGeos.get() ); j++ )
1428 if ( GEOSEquals_r( context, splitResult[i].get(), GEOSGetGeometryN_r( context, mGeos.get(), j ) ) )
1437 unionGeom.emplace_back( std::move( splitResult[i] ) );
1441 std::vector<geos::unique_ptr> geomVector;
1442 geomVector.emplace_back( std::move( splitResult[i] ) );
1444 if ( type == GEOS_MULTILINESTRING )
1445 newSplitResult.emplace_back( createGeosCollection( GEOS_MULTILINESTRING, geomVector ) );
1446 else if ( type == GEOS_MULTIPOLYGON )
1447 newSplitResult.emplace_back( createGeosCollection( GEOS_MULTIPOLYGON, geomVector ) );
1451 splitResult = std::move( newSplitResult );
1454 if ( !unionGeom.empty() )
1456 if ( type == GEOS_MULTILINESTRING )
1457 splitResult.emplace_back( createGeosCollection( GEOS_MULTILINESTRING, unionGeom ) );
1458 else if ( type == GEOS_MULTIPOLYGON )
1459 splitResult.emplace_back( createGeosCollection( GEOS_MULTIPOLYGON, unionGeom ) );
1465geos::unique_ptr QgsGeos::createGeosCollection(
int typeId, std::vector<geos::unique_ptr> &geoms )
1467 std::vector<GEOSGeometry *> geomarr;
1468 geomarr.reserve( geoms.size() );
1471 for ( geos::unique_ptr &geomUniquePtr : geoms )
1473 if ( geomUniquePtr )
1475 if ( !GEOSisEmpty_r( context, geomUniquePtr.get() ) )
1479 geomarr.emplace_back( geomUniquePtr.release() );
1483 geos::unique_ptr geomRes;
1487 geomRes.reset( GEOSGeom_createCollection_r( context, typeId, geomarr.data(), geomarr.size() ) );
1489 catch ( GEOSException & )
1493 GEOSGeom_destroy_r( context, geom );
1508 int nCoordDims = GEOSGeom_getCoordinateDimension_r( context,
geos );
1509 int nDims = GEOSGeom_getDimensions_r( context,
geos );
1510 bool hasZ = ( nCoordDims == 3 );
1511 bool hasM = ( ( nDims - nCoordDims ) == 1 );
1513 switch ( GEOSGeomTypeId_r( context,
geos ) )
1517 if ( GEOSisEmpty_r( context,
geos ) )
1520 const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq_r( context,
geos );
1521 unsigned int nPoints = 0;
1522 GEOSCoordSeq_getSize_r( context, cs, &nPoints );
1523 return nPoints > 0 ? std::unique_ptr<QgsAbstractGeometry>(
coordSeqPoint( cs, 0, hasZ, hasM ).clone() ) :
nullptr;
1525 case GEOS_LINESTRING:
1527 return sequenceToLinestring(
geos, hasZ, hasM );
1533 case GEOS_MULTIPOINT:
1535 std::unique_ptr< QgsMultiPoint > multiPoint(
new QgsMultiPoint() );
1536 int nParts = GEOSGetNumGeometries_r( context,
geos );
1537 multiPoint->reserve( nParts );
1538 for (
int i = 0; i < nParts; ++i )
1540 const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq_r( context, GEOSGetGeometryN_r( context,
geos, i ) );
1543 unsigned int nPoints = 0;
1544 GEOSCoordSeq_getSize_r( context, cs, &nPoints );
1546 multiPoint->addGeometry(
coordSeqPoint( cs, 0, hasZ, hasM ).clone() );
1549 return std::move( multiPoint );
1551 case GEOS_MULTILINESTRING:
1554 int nParts = GEOSGetNumGeometries_r( context,
geos );
1555 multiLineString->reserve( nParts );
1556 for (
int i = 0; i < nParts; ++i )
1558 std::unique_ptr< QgsLineString >line( sequenceToLinestring( GEOSGetGeometryN_r( context,
geos, i ), hasZ, hasM ) );
1561 multiLineString->addGeometry( line.release() );
1564 return std::move( multiLineString );
1566 case GEOS_MULTIPOLYGON:
1568 std::unique_ptr< QgsMultiPolygon > multiPolygon(
new QgsMultiPolygon() );
1570 int nParts = GEOSGetNumGeometries_r( context,
geos );
1571 multiPolygon->reserve( nParts );
1572 for (
int i = 0; i < nParts; ++i )
1574 std::unique_ptr< QgsPolygon > poly =
fromGeosPolygon( GEOSGetGeometryN_r( context,
geos, i ) );
1577 multiPolygon->addGeometry( poly.release() );
1580 return std::move( multiPolygon );
1582 case GEOS_GEOMETRYCOLLECTION:
1585 int nParts = GEOSGetNumGeometries_r( context,
geos );
1586 geomCollection->reserve( nParts );
1587 for (
int i = 0; i < nParts; ++i )
1589 std::unique_ptr< QgsAbstractGeometry > geom(
fromGeos( GEOSGetGeometryN_r( context,
geos, i ) ) );
1592 geomCollection->addGeometry( geom.release() );
1595 return std::move( geomCollection );
1604 if ( GEOSGeomTypeId_r( context,
geos ) != GEOS_POLYGON )
1609 int nCoordDims = GEOSGeom_getCoordinateDimension_r( context,
geos );
1610 int nDims = GEOSGeom_getDimensions_r( context,
geos );
1611 bool hasZ = ( nCoordDims == 3 );
1612 bool hasM = ( ( nDims - nCoordDims ) == 1 );
1614 std::unique_ptr< QgsPolygon > polygon(
new QgsPolygon() );
1619 polygon->setExteriorRing( sequenceToLinestring( ring, hasZ, hasM ).release() );
1622 QVector<QgsCurve *> interiorRings;
1623 const int ringCount = GEOSGetNumInteriorRings_r( context,
geos );
1624 interiorRings.reserve( ringCount );
1625 for (
int i = 0; i < ringCount; ++i )
1627 ring = GEOSGetInteriorRingN_r( context,
geos, i );
1630 interiorRings.push_back( sequenceToLinestring( ring, hasZ, hasM ).release() );
1633 polygon->setInteriorRings( interiorRings );
1638std::unique_ptr<QgsLineString> QgsGeos::sequenceToLinestring(
const GEOSGeometry *
geos,
bool hasZ,
bool hasM )
1641 const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq_r( context,
geos );
1643 unsigned int nPoints;
1644 GEOSCoordSeq_getSize_r( context, cs, &nPoints );
1646 QVector< double > xOut( nPoints );
1647 QVector< double > yOut( nPoints );
1648 QVector< double > zOut;
1650 zOut.resize( nPoints );
1651 QVector< double > mOut;
1653 mOut.resize( nPoints );
1655 double *x = xOut.data();
1656 double *y = yOut.data();
1657 double *z = zOut.data();
1658 double *m = mOut.data();
1660#if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=10 )
1661 GEOSCoordSeq_copyToArrays_r( context, cs, x, y, hasZ ? z : nullptr, hasM ? m : nullptr );
1663 for (
unsigned int i = 0; i < nPoints; ++i )
1666 GEOSCoordSeq_getXYZ_r( context, cs, i, x++, y++, z++ );
1668 GEOSCoordSeq_getXY_r( context, cs, i, x++, y++ );
1671 GEOSCoordSeq_getOrdinate_r( context, cs, i, 3, m++ );
1675 std::unique_ptr< QgsLineString > line(
new QgsLineString( xOut, yOut, zOut, mOut ) );
1685 int geometryType = GEOSGeomTypeId_r( context, g );
1686 if ( geometryType == GEOS_POINT || geometryType == GEOS_LINESTRING || geometryType == GEOS_LINEARRING
1687 || geometryType == GEOS_POLYGON )
1691 return GEOSGetNumGeometries_r( context, g );
1707 GEOSCoordSeq_getXYZ_r( context, cs, i, &x, &y, &z );
1709 GEOSCoordSeq_getXY_r( context, cs, i, &x, &y );
1712 GEOSCoordSeq_getOrdinate_r( context, cs, i, 3, &m );
1748 int geosType = GEOS_GEOMETRYCOLLECTION;
1755 geosType = GEOS_MULTIPOINT;
1759 geosType = GEOS_MULTILINESTRING;
1763 geosType = GEOS_MULTIPOLYGON;
1778 std::vector<geos::unique_ptr> geomVector;
1779 geomVector.reserve(
c->numGeometries() );
1780 for (
int i = 0; i <
c->numGeometries(); ++i )
1787 geomVector.emplace_back( std::move( geosGeom ) );
1789 return createGeosCollection( geosType, geomVector );
1796 const QgsPolyhedralSurface *polyhedralSurface = qgsgeometry_cast<const QgsPolyhedralSurface *>( geom );
1797 if ( !polyhedralSurface )
1800 std::vector<geos::unique_ptr> geomVector;
1801 geomVector.reserve( polyhedralSurface->
numPatches() );
1802 for (
int i = 0; i < polyhedralSurface->
numPatches(); ++i )
1804 geos::unique_ptr geosPolygon = createGeosPolygon( polyhedralSurface->
patchN( i ),
precision );
1809 geomVector.emplace_back( std::move( geosPolygon ) );
1812 return createGeosCollection( GEOS_MULTIPOLYGON, geomVector );
1819 return createGeosPoint(
static_cast<const QgsPoint *
>( geom ), coordDims,
precision, flags );
1837 if ( !mGeos || !geom )
1842 geos::unique_ptr geosGeom(
asGeos( geom, mPrecision ) );
1848 const double gridSize = parameters.
gridSize();
1853 geos::unique_ptr opGeom;
1856 case OverlayIntersection:
1859 opGeom.reset( GEOSIntersectionPrec_r( context, mGeos.get(), geosGeom.get(), gridSize ) );
1863 opGeom.reset( GEOSIntersection_r( context, mGeos.get(), geosGeom.get() ) );
1867 case OverlayDifference:
1870 opGeom.reset( GEOSDifferencePrec_r( context, mGeos.get(), geosGeom.get(), gridSize ) );
1874 opGeom.reset( GEOSDifference_r( context, mGeos.get(), geosGeom.get() ) );
1880 geos::unique_ptr unionGeometry;
1883 unionGeometry.reset( GEOSUnionPrec_r( context, mGeos.get(), geosGeom.get(), gridSize ) );
1887 unionGeometry.reset( GEOSUnion_r( context, mGeos.get(), geosGeom.get() ) );
1890 if ( unionGeometry && GEOSGeomTypeId_r( context, unionGeometry.get() ) == GEOS_MULTILINESTRING )
1892 geos::unique_ptr mergedLines( GEOSLineMerge_r( context, unionGeometry.get() ) );
1895 unionGeometry = std::move( mergedLines );
1899 opGeom = std::move( unionGeometry );
1903 case OverlaySymDifference:
1906 opGeom.reset( GEOSSymDifferencePrec_r( context, mGeos.get(), geosGeom.get(), gridSize ) );
1910 opGeom.reset( GEOSSymDifference_r( context, mGeos.get(), geosGeom.get() ) );
1916 catch ( GEOSException &e )
1918 logError( QStringLiteral(
"GEOS" ), e.what() );
1921 *errorMsg = e.what();
1927bool QgsGeos::relation(
const QgsAbstractGeometry *geom, Relation r, QString *errorMsg )
const
1929 if ( !mGeos || !geom )
1934 geos::unique_ptr geosGeom(
asGeos( geom, mPrecision ) );
1941 bool result =
false;
1944 if ( mGeosPrepared )
1948 case RelationIntersects:
1949 result = ( GEOSPreparedIntersects_r( context, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1951 case RelationTouches:
1952 result = ( GEOSPreparedTouches_r( context, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1954 case RelationCrosses:
1955 result = ( GEOSPreparedCrosses_r( context, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1957 case RelationWithin:
1958 result = ( GEOSPreparedWithin_r( context, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1960 case RelationContains:
1961 result = ( GEOSPreparedContains_r( context, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1963 case RelationDisjoint:
1964 result = ( GEOSPreparedDisjoint_r( context, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1966 case RelationOverlaps:
1967 result = ( GEOSPreparedOverlaps_r( context, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1975 case RelationIntersects:
1976 result = ( GEOSIntersects_r( context, mGeos.get(), geosGeom.get() ) == 1 );
1978 case RelationTouches:
1979 result = ( GEOSTouches_r( context, mGeos.get(), geosGeom.get() ) == 1 );
1981 case RelationCrosses:
1982 result = ( GEOSCrosses_r( context, mGeos.get(), geosGeom.get() ) == 1 );
1984 case RelationWithin:
1985 result = ( GEOSWithin_r( context, mGeos.get(), geosGeom.get() ) == 1 );
1987 case RelationContains:
1988 result = ( GEOSContains_r( context, mGeos.get(), geosGeom.get() ) == 1 );
1990 case RelationDisjoint:
1991 result = ( GEOSDisjoint_r( context, mGeos.get(), geosGeom.get() ) == 1 );
1993 case RelationOverlaps:
1994 result = ( GEOSOverlaps_r( context, mGeos.get(), geosGeom.get() ) == 1 );
1998 catch ( GEOSException &e )
2000 logError( QStringLiteral(
"GEOS" ), e.what() );
2003 *errorMsg = e.what();
2018 geos::unique_ptr
geos;
2034 geos::unique_ptr
geos;
2037 geos.reset( GEOSBufferWithStyle_r(
QgsGeosContext::get(), mGeos.get(),
distance, segments,
static_cast< int >( endCapStyle ),
static_cast< int >( joinStyle ), miterLimit ) );
2049 geos::unique_ptr
geos;
2064 geos::unique_ptr
geos;
2080 geos::unique_ptr
geos;
2087 geos.reset( GEOSGetCentroid_r( context, mGeos.get() ) );
2092 GEOSGeomGetX_r( context,
geos.get(), &x );
2093 GEOSGeomGetY_r( context,
geos.get(), &y );
2106 geos::unique_ptr
geos;
2126 geos::unique_ptr
geos;
2129 geos.reset( GEOSPointOnSurface_r( context, mGeos.get() ) );
2131 if ( !
geos || GEOSisEmpty_r( context,
geos.get() ) != 0 )
2136 GEOSGeomGetX_r( context,
geos.get(), &x );
2137 GEOSGeomGetY_r( context,
geos.get(), &y );
2154 std::unique_ptr< QgsAbstractGeometry > cHullGeom =
fromGeos( cHull.get() );
2155 return cHullGeom.release();
2162#if GEOS_VERSION_MAJOR==3 && GEOS_VERSION_MINOR<11
2164 ( void )targetPercent;
2166 throw QgsNotSupportedException( QObject::tr(
"Calculating concaveHull requires a QGIS build based on GEOS 3.11 or later" ) );
2177 return concaveHullGeom.release();
2185#if GEOS_VERSION_MAJOR==3 && GEOS_VERSION_MINOR<12
2187 ( void )invalidEdges;
2189 throw QgsNotSupportedException( QObject::tr(
"Validating coverages requires a QGIS build based on GEOS 3.12 or later" ) );
2194 *errorMsg = QStringLiteral(
"Input geometry was not set" );
2202 const int result = GEOSCoverageIsValid_r( context, mGeos.get(), gapWidth, invalidEdges ? &invalidEdgesGeos : nullptr );
2203 if ( invalidEdges && invalidEdgesGeos )
2205 *invalidEdges =
fromGeos( invalidEdgesGeos );
2207 if ( invalidEdgesGeos )
2209 GEOSGeom_destroy_r( context, invalidEdgesGeos );
2210 invalidEdgesGeos =
nullptr;
2230#if GEOS_VERSION_MAJOR==3 && GEOS_VERSION_MINOR<12
2232 ( void )preserveBoundary;
2234 throw QgsNotSupportedException( QObject::tr(
"Simplifying coverages requires a QGIS build based on GEOS 3.12 or later" ) );
2239 *errorMsg = QStringLiteral(
"Input geometry was not set" );
2245 geos::unique_ptr simplified( GEOSCoverageSimplifyVW_r(
QgsGeosContext::get(), mGeos.get(), tolerance, preserveBoundary ? 1 : 0 ) );
2246 std::unique_ptr< QgsAbstractGeometry > simplifiedGeom =
fromGeos( simplified.get() );
2247 return simplifiedGeom;
2258 *errorMsg = QStringLiteral(
"Input geometry was not set" );
2265 std::unique_ptr< QgsAbstractGeometry > result =
fromGeos( unioned.get() );
2276 *errorMsg = QObject::tr(
"QGIS geometry cannot be converted to a GEOS geometry",
"GEOS Error" );
2285 char res = GEOSisValidDetail_r( context, mGeos.get(), allowSelfTouchingHoles ? GEOSVALID_ALLOW_SELFTOUCHING_RING_FORMING_HOLE : 0, &r, &g1 );
2286 const bool invalid = res != 1;
2291 error = QString( r );
2292 GEOSFree_r( context, r );
2295 if ( invalid && errorMsg )
2298 static const std::map< QString, QString > sTranslatedErrors
2300 { QStringLiteral(
"topology validation error" ), QObject::tr(
"Topology validation error",
"GEOS Error" ) },
2301 { QStringLiteral(
"repeated point" ), QObject::tr(
"Repeated point",
"GEOS Error" ) },
2302 { QStringLiteral(
"hole lies outside shell" ), QObject::tr(
"Hole lies outside shell",
"GEOS Error" ) },
2303 { QStringLiteral(
"holes are nested" ), QObject::tr(
"Holes are nested",
"GEOS Error" ) },
2304 { QStringLiteral(
"interior is disconnected" ), QObject::tr(
"Interior is disconnected",
"GEOS Error" ) },
2305 { QStringLiteral(
"self-intersection" ), QObject::tr(
"Self-intersection",
"GEOS Error" ) },
2306 { QStringLiteral(
"ring self-intersection" ), QObject::tr(
"Ring self-intersection",
"GEOS Error" ) },
2307 { QStringLiteral(
"nested shells" ), QObject::tr(
"Nested shells",
"GEOS Error" ) },
2308 { QStringLiteral(
"duplicate rings" ), QObject::tr(
"Duplicate rings",
"GEOS Error" ) },
2309 { QStringLiteral(
"too few points in geometry component" ), QObject::tr(
"Too few points in geometry component",
"GEOS Error" ) },
2310 { QStringLiteral(
"invalid coordinate" ), QObject::tr(
"Invalid coordinate",
"GEOS Error" ) },
2311 { QStringLiteral(
"ring is not closed" ), QObject::tr(
"Ring is not closed",
"GEOS Error" ) },
2314 const auto translatedError = sTranslatedErrors.find( error.toLower() );
2315 if ( translatedError != sTranslatedErrors.end() )
2316 *errorMsg = translatedError->second;
2320 if ( g1 && errorLoc )
2326 GEOSGeom_destroy_r( context, g1 );
2336 if ( !mGeos || !geom )
2343 geos::unique_ptr geosGeom(
asGeos( geom, mPrecision ) );
2382GEOSCoordSequence *QgsGeos::createCoordinateSequence(
const QgsCurve *curve,
double precision,
bool forceClose )
2386 std::unique_ptr< QgsLineString > segmentized;
2387 const QgsLineString *line = qgsgeometry_cast<const QgsLineString *>( curve );
2392 line = segmentized.get();
2399 GEOSCoordSequence *coordSeq =
nullptr;
2401 const int numPoints = line->
numPoints();
2403 const bool hasZ = line->
is3D();
2405#if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=10 )
2408 if ( !forceClose || ( line->
pointN( 0 ) == line->
pointN( numPoints - 1 ) ) )
2413 coordSeq = GEOSCoordSeq_copyFromArrays_r( context, line->
xData(), line->
yData(), line->
zData(),
nullptr, numPoints );
2416 QgsDebugError( QStringLiteral(
"GEOS Exception: Could not create coordinate sequence for %1 points" ).arg( numPoints ) );
2424 QVector< double > x = line->
xVector();
2425 if ( numPoints > 0 )
2426 x.append( x.at( 0 ) );
2427 QVector< double > y = line->
yVector();
2428 if ( numPoints > 0 )
2429 y.append( y.at( 0 ) );
2430 QVector< double > z = line->
zVector();
2431 if ( hasZ && numPoints > 0 )
2432 z.append( z.at( 0 ) );
2435 coordSeq = GEOSCoordSeq_copyFromArrays_r( context, x.constData(), y.constData(), !hasZ ?
nullptr : z.constData(), nullptr, numPoints + 1 );
2438 QgsDebugError( QStringLiteral(
"GEOS Exception: Could not create closed coordinate sequence for %1 points" ).arg( numPoints + 1 ) );
2449 const bool hasM =
false;
2460 int numOutPoints = numPoints;
2461 if ( forceClose && ( line->
pointN( 0 ) != line->
pointN( numPoints - 1 ) ) )
2468 coordSeq = GEOSCoordSeq_create_r( context, numOutPoints, coordDims );
2471 QgsDebugError( QStringLiteral(
"GEOS Exception: Could not create coordinate sequence for %1 points in %2 dimensions" ).arg( numPoints ).arg( coordDims ) );
2475 const double *xData = line->
xData();
2476 const double *yData = line->
yData();
2477 const double *zData = hasZ ? line->
zData() :
nullptr;
2478 const double *mData = hasM ? line->
mData() :
nullptr;
2482 for (
int i = 0; i < numOutPoints; ++i )
2484 if ( i >= numPoints )
2487 xData = line->
xData();
2488 yData = line->
yData();
2489 zData = hasZ ? line->
zData() :
nullptr;
2490 mData = hasM ? line->
mData() :
nullptr;
2502 GEOSCoordSeq_setOrdinate_r( context, coordSeq, i, 3, *mData++ );
2508 for (
int i = 0; i < numOutPoints; ++i )
2510 if ( i >= numPoints )
2513 xData = line->
xData();
2514 yData = line->
yData();
2515 zData = hasZ ? line->
zData() :
nullptr;
2516 mData = hasM ? line->
mData() :
nullptr;
2520 GEOSCoordSeq_setXYZ_r( context, coordSeq, i, *xData++, *yData++, *zData++ );
2524 GEOSCoordSeq_setXY_r( context, coordSeq, i, *xData++, *yData++ );
2528 GEOSCoordSeq_setOrdinate_r( context, coordSeq, i, 3, *mData++ );
2540 const QgsPoint *pt = qgsgeometry_cast<const QgsPoint *>( point );
2547geos::unique_ptr QgsGeos::createGeosPointXY(
double x,
double y,
bool hasZ,
double z,
bool hasM,
double m,
int coordDims,
double precision,
Qgis::GeosCreationFlags )
2552 geos::unique_ptr geosPoint;
2556 if ( coordDims == 2 )
2562 geosPoint.reset( GEOSGeom_createPointFromXY_r( context, x, y ) );
2566 GEOSCoordSequence *coordSeq = GEOSCoordSeq_create_r( context, 1, coordDims );
2569 QgsDebugError( QStringLiteral(
"GEOS Exception: Could not create coordinate sequence for point with %1 dimensions" ).arg( coordDims ) );
2574 GEOSCoordSeq_setX_r( context, coordSeq, 0, std::round( x /
precision ) *
precision );
2575 GEOSCoordSeq_setY_r( context, coordSeq, 0, std::round( y /
precision ) *
precision );
2578 GEOSCoordSeq_setOrdinate_r( context, coordSeq, 0, 2, std::round( z /
precision ) *
precision );
2583 GEOSCoordSeq_setX_r( context, coordSeq, 0, x );
2584 GEOSCoordSeq_setY_r( context, coordSeq, 0, y );
2587 GEOSCoordSeq_setOrdinate_r( context, coordSeq, 0, 2, z );
2593 GEOSCoordSeq_setOrdinate_r( context, coordSeq, 0, 3, m );
2596 geosPoint.reset( GEOSGeom_createPoint_r( context, coordSeq ) );
2604 const QgsCurve *
c = qgsgeometry_cast<const QgsCurve *>( curve );
2608 GEOSCoordSequence *coordSeq = createCoordinateSequence(
c,
precision );
2612 geos::unique_ptr geosGeom;
2623 const QgsCurvePolygon *polygon = qgsgeometry_cast<const QgsCurvePolygon *>( poly );
2628 if ( !exteriorRing )
2634 geos::unique_ptr geosPolygon;
2637 geos::unique_ptr exteriorRingGeos( GEOSGeom_createLinearRing_r( context, createCoordinateSequence( exteriorRing,
precision,
true ) ) );
2643 for (
int i = 0; i < nInteriorRings; ++i )
2646 if ( !interiorRing->
isEmpty() )
2654 nHoles = nInteriorRings;
2662 for (
int i = 0; i < nInteriorRings; ++i )
2667 holes[i] = GEOSGeom_createLinearRing_r( context, createCoordinateSequence( interiorRing,
precision,
true ) );
2670 geosPolygon.reset( GEOSGeom_createPolygon_r( context, exteriorRingGeos.release(), holes, nHoles ) );
2683 geos::unique_ptr offset;
2690 offset.reset( GEOSOffsetCurve_r(
QgsGeosContext::get(), mGeos.get(),
distance, segments,
static_cast< int >( joinStyle ), miterLimit ) );
2693 std::unique_ptr< QgsAbstractGeometry > offsetGeom =
fromGeos( offset.get() );
2694 return offsetGeom.release();
2704 geos::unique_ptr
geos;
2708 geos::buffer_params_unique_ptr bp( GEOSBufferParams_create_r( context ) );
2709 GEOSBufferParams_setSingleSided_r( context, bp.get(), 1 );
2710 GEOSBufferParams_setQuadrantSegments_r( context, bp.get(), segments );
2711 GEOSBufferParams_setJoinStyle_r( context, bp.get(),
static_cast< int >( joinStyle ) );
2712 GEOSBufferParams_setMitreLimit_r( context, bp.get(), miterLimit );
2718 geos.reset( GEOSBufferWithParams_r( context, mGeos.get(), bp.get(),
distance ) );
2731 geos::unique_ptr
geos;
2747 geos::unique_ptr
geos;
2750 geos::unique_ptr boundaryGeos;
2752 boundaryGeos =
asGeos( boundary );
2767 geos::unique_ptr
geos;
2780 return std::numeric_limits< double >::quiet_NaN();
2783 geos::unique_ptr
geos;
2788 return std::numeric_limits< double >::quiet_NaN();
2801 geos::unique_ptr
geos;
2817 geos::unique_ptr
geos;
2828 if ( !mGeos || !other )
2833 geos::unique_ptr
geos;
2836 geos::unique_ptr otherGeos =
asGeos( other );
2860 geos::unique_ptr reshapeLineGeos = createGeosLinestring( &reshapeWithLine, mPrecision );
2864 int numGeoms = GEOSGetNumGeometries_r( context, mGeos.get() );
2865 if ( numGeoms == -1 )
2874 bool isMultiGeom =
false;
2875 int geosTypeId = GEOSGeomTypeId_r( context, mGeos.get() );
2876 if ( geosTypeId == GEOS_MULTILINESTRING || geosTypeId == GEOS_MULTIPOLYGON )
2883 geos::unique_ptr reshapedGeometry;
2886 reshapedGeometry = reshapeLine( mGeos.get(), reshapeLineGeos.get(), mPrecision );
2890 reshapedGeometry = reshapePolygon( mGeos.get(), reshapeLineGeos.get(), mPrecision );
2895 std::unique_ptr< QgsAbstractGeometry > reshapeResult =
fromGeos( reshapedGeometry.get() );
2896 return reshapeResult;
2903 bool reshapeTookPlace =
false;
2905 geos::unique_ptr currentReshapeGeometry;
2908 for (
int i = 0; i < numGeoms; ++i )
2911 currentReshapeGeometry = reshapeLine( GEOSGetGeometryN_r( context, mGeos.get(), i ), reshapeLineGeos.get(), mPrecision );
2913 currentReshapeGeometry = reshapePolygon( GEOSGetGeometryN_r( context, mGeos.get(), i ), reshapeLineGeos.get(), mPrecision );
2915 if ( currentReshapeGeometry )
2917 newGeoms[i] = currentReshapeGeometry.release();
2918 reshapeTookPlace =
true;
2922 newGeoms[i] = GEOSGeom_clone_r( context, GEOSGetGeometryN_r( context, mGeos.get(), i ) );
2926 geos::unique_ptr newMultiGeom;
2929 newMultiGeom.reset( GEOSGeom_createCollection_r( context, GEOS_MULTILINESTRING, newGeoms, numGeoms ) );
2933 newMultiGeom.reset( GEOSGeom_createCollection_r( context, GEOS_MULTIPOLYGON, newGeoms, numGeoms ) );
2937 if ( !newMultiGeom )
2943 if ( reshapeTookPlace )
2947 std::unique_ptr< QgsAbstractGeometry > reshapedMultiGeom =
fromGeos( newMultiGeom.get() );
2948 return reshapedMultiGeom;
2971 if ( GEOSGeomTypeId_r( context, mGeos.get() ) != GEOS_MULTILINESTRING )
2974 geos::unique_ptr
geos;
2977 geos.reset( GEOSLineMerge_r( context, mGeos.get() ) );
2990 geos::unique_ptr otherGeom(
asGeos( other.
constGet(), mPrecision ) );
3001 geos::coord_sequence_unique_ptr nearestCoord;
3002 if ( mGeosPrepared )
3004 nearestCoord.reset( GEOSPreparedNearestPoints_r( context, mGeosPrepared.get(), otherGeom.get() ) );
3008 nearestCoord.reset( GEOSNearestPoints_r( context, mGeos.get(), otherGeom.get() ) );
3011 ( void )GEOSCoordSeq_getX_r( context, nearestCoord.get(), 0, &nx );
3012 ( void )GEOSCoordSeq_getY_r( context, nearestCoord.get(), 0, &ny );
3014 catch ( GEOSException &e )
3016 logError( QStringLiteral(
"GEOS" ), e.what() );
3019 *errorMsg = e.what();
3029 if ( !mGeos || other.
isEmpty() )
3039 if ( !other || other->
isEmpty() )
3042 geos::unique_ptr otherGeom(
asGeos( other, mPrecision ) );
3055 geos::coord_sequence_unique_ptr nearestCoord( GEOSNearestPoints_r( context, mGeos.get(), otherGeom.get() ) );
3057 if ( !nearestCoord )
3060 *errorMsg = QStringLiteral(
"GEOS returned no nearest points" );
3064 ( void )GEOSCoordSeq_getX_r( context, nearestCoord.get(), 0, &nx1 );
3065 ( void )GEOSCoordSeq_getY_r( context, nearestCoord.get(), 0, &ny1 );
3066 ( void )GEOSCoordSeq_getX_r( context, nearestCoord.get(), 1, &nx2 );
3067 ( void )GEOSCoordSeq_getY_r( context, nearestCoord.get(), 1, &ny2 );
3069 catch ( GEOSException &e )
3071 logError( QStringLiteral(
"GEOS" ), e.what() );
3074 *errorMsg = e.what();
3092 geos::unique_ptr otherGeom(
asGeos( &point, mPrecision ) );
3103 catch ( GEOSException &e )
3105 logError( QStringLiteral(
"GEOS" ), e.what() );
3108 *errorMsg = e.what();
3123 geos::unique_ptr point = createGeosPointXY( x, y,
false, 0,
false, 0, 2, 0 );
3132 catch ( GEOSException &e )
3134 logError( QStringLiteral(
"GEOS" ), e.what() );
3137 *errorMsg = e.what();
3151 geos::unique_ptr l =
asGeos( g );
3154 lineGeosGeometries[validLines] = l.release();
3162 geos::unique_ptr result( GEOSPolygonize_r( context, lineGeosGeometries, validLines ) );
3163 for (
int i = 0; i < validLines; ++i )
3165 GEOSGeom_destroy_r( context, lineGeosGeometries[i] );
3167 delete[] lineGeosGeometries;
3170 catch ( GEOSException &e )
3174 *errorMsg = e.what();
3176 for (
int i = 0; i < validLines; ++i )
3178 GEOSGeom_destroy_r( context, lineGeosGeometries[i] );
3180 delete[] lineGeosGeometries;
3192 geos::unique_ptr extentGeosGeom;
3195 extentGeosGeom =
asGeos( extent, mPrecision );
3196 if ( !extentGeosGeom )
3202 geos::unique_ptr
geos;
3206 geos.reset( GEOSVoronoiDiagram_r( context, mGeos.get(), extentGeosGeom.get(), tolerance, edgesOnly ) );
3208 if ( !
geos || GEOSisEmpty_r( context,
geos.get() ) != 0 )
3226 geos::unique_ptr
geos;
3229 geos.reset( GEOSDelaunayTriangulation_r( context, mGeos.get(), tolerance, edgesOnly ) );
3231 if ( !
geos || GEOSisEmpty_r( context,
geos.get() ) != 0 )
3243#if GEOS_VERSION_MAJOR==3 && GEOS_VERSION_MINOR<11
3245 throw QgsNotSupportedException( QObject::tr(
"Calculating constrainedDelaunayTriangulation requires a QGIS build based on GEOS 3.11 or later" ) );
3252 geos::unique_ptr
geos;
3256 geos.reset( GEOSConstrainedDelaunayTriangulation_r( context, mGeos.get() ) );
3258 if ( !
geos || GEOSisEmpty_r( context,
geos.get() ) != 0 )
3263 std::unique_ptr< QgsAbstractGeometry > res =
fromGeos(
geos.get() );
3264 if (
const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( res.get() ) )
3266 return std::unique_ptr< QgsAbstractGeometry >( collection->extractPartsByType(
Qgis::WkbType::Polygon,
true ) );
3278static bool _linestringEndpoints(
const GEOSGeometry *linestring,
double &x1,
double &y1,
double &x2,
double &y2 )
3281 const GEOSCoordSequence *coordSeq = GEOSGeom_getCoordSeq_r( context, linestring );
3285 unsigned int coordSeqSize;
3286 if ( GEOSCoordSeq_getSize_r( context, coordSeq, &coordSeqSize ) == 0 )
3289 if ( coordSeqSize < 2 )
3292 GEOSCoordSeq_getX_r( context, coordSeq, 0, &x1 );
3293 GEOSCoordSeq_getY_r( context, coordSeq, 0, &y1 );
3294 GEOSCoordSeq_getX_r( context, coordSeq, coordSeqSize - 1, &x2 );
3295 GEOSCoordSeq_getY_r( context, coordSeq, coordSeqSize - 1, &y2 );
3303 double x1, y1, x2, y2;
3304 if ( !_linestringEndpoints( line1, x1, y1, x2, y2 ) )
3307 double rx1, ry1, rx2, ry2;
3308 if ( !_linestringEndpoints( line2, rx1, ry1, rx2, ry2 ) )
3311 bool intersectionAtOrigLineEndpoint =
3312 ( intersectionPoint.
x() == x1 && intersectionPoint.
y() == y1 ) !=
3313 ( intersectionPoint.
x() == x2 && intersectionPoint.
y() == y2 );
3314 bool intersectionAtReshapeLineEndpoint =
3315 ( intersectionPoint.
x() == rx1 && intersectionPoint.
y() == ry1 ) ||
3316 ( intersectionPoint.
x() == rx2 && intersectionPoint.
y() == ry2 );
3320 if ( intersectionAtOrigLineEndpoint && intersectionAtReshapeLineEndpoint )
3322 geos::unique_ptr g1( GEOSGeom_clone_r( context, line1 ) );
3323 geos::unique_ptr g2( GEOSGeom_clone_r( context, line2 ) );
3324 GEOSGeometry *geoms[2] = { g1.release(), g2.release() };
3325 geos::unique_ptr multiGeom( GEOSGeom_createCollection_r( context, GEOS_MULTILINESTRING, geoms, 2 ) );
3326 geos::unique_ptr res( GEOSLineMerge_r( context, multiGeom.get() ) );
3336 if ( !line || !reshapeLineGeos )
3339 bool atLeastTwoIntersections =
false;
3340 bool oneIntersection =
false;
3347 geos::unique_ptr intersectGeom( GEOSIntersection_r( context, line, reshapeLineGeos ) );
3348 if ( intersectGeom )
3350 const int geomType = GEOSGeomTypeId_r( context, intersectGeom.get() );
3351 atLeastTwoIntersections = ( geomType == GEOS_MULTIPOINT && GEOSGetNumGeometries_r( context, intersectGeom.get() ) > 1 )
3352 || ( geomType == GEOS_GEOMETRYCOLLECTION && GEOSGetNumGeometries_r( context, intersectGeom.get() ) > 0 )
3353 || ( geomType == GEOS_MULTILINESTRING && GEOSGetNumGeometries_r( context, intersectGeom.get() ) > 0 );
3355 if ( GEOSGeomTypeId_r( context, intersectGeom.get() ) == GEOS_POINT )
3357 const GEOSCoordSequence *intersectionCoordSeq = GEOSGeom_getCoordSeq_r( context, intersectGeom.get() );
3359 GEOSCoordSeq_getX_r( context, intersectionCoordSeq, 0, &xi );
3360 GEOSCoordSeq_getY_r( context, intersectionCoordSeq, 0, &yi );
3361 oneIntersection =
true;
3366 catch ( GEOSException & )
3368 atLeastTwoIntersections =
false;
3372 if ( oneIntersection )
3373 return _mergeLinestrings( line, reshapeLineGeos, oneIntersectionPoint );
3375 if ( !atLeastTwoIntersections )
3379 double x1, y1, x2, y2;
3380 if ( !_linestringEndpoints( line, x1, y1, x2, y2 ) )
3383 geos::unique_ptr beginLineVertex = createGeosPointXY( x1, y1,
false, 0,
false, 0, 2,
precision );
3384 geos::unique_ptr endLineVertex = createGeosPointXY( x2, y2,
false, 0,
false, 0, 2,
precision );
3386 bool isRing =
false;
3387 if ( GEOSGeomTypeId_r( context, line ) == GEOS_LINEARRING
3388 || GEOSEquals_r( context, beginLineVertex.get(), endLineVertex.get() ) == 1 )
3392 geos::unique_ptr nodedGeometry = nodeGeometries( reshapeLineGeos, line );
3393 if ( !nodedGeometry )
3399 geos::unique_ptr mergedLines( GEOSLineMerge_r( context, nodedGeometry.get() ) );
3405 int numMergedLines = GEOSGetNumGeometries_r( context, mergedLines.get() );
3406 if ( numMergedLines < 2 )
3408 if ( numMergedLines == 1 )
3410 geos::unique_ptr result( GEOSGeom_clone_r( context, reshapeLineGeos ) );
3417 QVector<GEOSGeometry *> resultLineParts;
3418 QVector<GEOSGeometry *> probableParts;
3420 for (
int i = 0; i < numMergedLines; ++i )
3422 const GEOSGeometry *currentGeom = GEOSGetGeometryN_r( context, mergedLines.get(), i );
3425 bool alreadyAdded =
false;
3427 double bufferDistance = std::pow( 10.0L, geomDigits( currentGeom ) - 11 );
3428 for (
const GEOSGeometry *other : std::as_const( resultLineParts ) )
3430 GEOSHausdorffDistance_r( context, currentGeom, other, &
distance );
3433 alreadyAdded =
true;
3440 const GEOSCoordSequence *currentCoordSeq = GEOSGeom_getCoordSeq_r( context, currentGeom );
3441 unsigned int currentCoordSeqSize;
3442 GEOSCoordSeq_getSize_r( context, currentCoordSeq, ¤tCoordSeqSize );
3443 if ( currentCoordSeqSize < 2 )
3447 double xBegin, xEnd, yBegin, yEnd;
3448 GEOSCoordSeq_getX_r( context, currentCoordSeq, 0, &xBegin );
3449 GEOSCoordSeq_getY_r( context, currentCoordSeq, 0, &yBegin );
3450 GEOSCoordSeq_getX_r( context, currentCoordSeq, currentCoordSeqSize - 1, &xEnd );
3451 GEOSCoordSeq_getY_r( context, currentCoordSeq, currentCoordSeqSize - 1, &yEnd );
3452 geos::unique_ptr beginCurrentGeomVertex = createGeosPointXY( xBegin, yBegin,
false, 0,
false, 0, 2,
precision );
3453 geos::unique_ptr endCurrentGeomVertex = createGeosPointXY( xEnd, yEnd,
false, 0,
false, 0, 2,
precision );
3456 int nEndpointsOnOriginalLine = 0;
3457 if ( pointContainedInLine( beginCurrentGeomVertex.get(), line ) == 1 )
3458 nEndpointsOnOriginalLine += 1;
3460 if ( pointContainedInLine( endCurrentGeomVertex.get(), line ) == 1 )
3461 nEndpointsOnOriginalLine += 1;
3464 int nEndpointsSameAsOriginalLine = 0;
3465 if ( GEOSEquals_r( context, beginCurrentGeomVertex.get(), beginLineVertex.get() ) == 1
3466 || GEOSEquals_r( context, beginCurrentGeomVertex.get(), endLineVertex.get() ) == 1 )
3467 nEndpointsSameAsOriginalLine += 1;
3469 if ( GEOSEquals_r( context, endCurrentGeomVertex.get(), beginLineVertex.get() ) == 1
3470 || GEOSEquals_r( context, endCurrentGeomVertex.get(), endLineVertex.get() ) == 1 )
3471 nEndpointsSameAsOriginalLine += 1;
3474 bool currentGeomOverlapsOriginalGeom =
false;
3475 bool currentGeomOverlapsReshapeLine =
false;
3476 if ( lineContainedInLine( currentGeom, line ) == 1 )
3477 currentGeomOverlapsOriginalGeom =
true;
3479 if ( lineContainedInLine( currentGeom, reshapeLineGeos ) == 1 )
3480 currentGeomOverlapsReshapeLine =
true;
3483 if ( !isRing && nEndpointsSameAsOriginalLine == 1 && nEndpointsOnOriginalLine == 2 && currentGeomOverlapsOriginalGeom )
3485 resultLineParts.push_back( GEOSGeom_clone_r( context, currentGeom ) );
3488 else if ( isRing && nEndpointsOnOriginalLine == 2 && currentGeomOverlapsOriginalGeom )
3490 probableParts.push_back( GEOSGeom_clone_r( context, currentGeom ) );
3492 else if ( nEndpointsOnOriginalLine == 2 && !currentGeomOverlapsOriginalGeom )
3494 resultLineParts.push_back( GEOSGeom_clone_r( context, currentGeom ) );
3496 else if ( nEndpointsSameAsOriginalLine == 2 && !currentGeomOverlapsOriginalGeom )
3498 resultLineParts.push_back( GEOSGeom_clone_r( context, currentGeom ) );
3500 else if ( currentGeomOverlapsOriginalGeom && currentGeomOverlapsReshapeLine )
3502 resultLineParts.push_back( GEOSGeom_clone_r( context, currentGeom ) );
3507 if ( isRing && !probableParts.isEmpty() )
3509 geos::unique_ptr maxGeom;
3511 double maxLength = -std::numeric_limits<double>::max();
3512 double currentLength = 0;
3513 for (
int i = 0; i < probableParts.size(); ++i )
3515 currentGeom = probableParts.at( i );
3516 GEOSLength_r( context, currentGeom, ¤tLength );
3517 if ( currentLength > maxLength )
3519 maxLength = currentLength;
3520 maxGeom.reset( currentGeom );
3524 GEOSGeom_destroy_r( context, currentGeom );
3527 resultLineParts.push_back( maxGeom.release() );
3530 geos::unique_ptr result;
3531 if ( resultLineParts.empty() )
3534 if ( resultLineParts.size() == 1 )
3536 result.reset( resultLineParts[0] );
3541 for (
int i = 0; i < resultLineParts.size(); ++i )
3543 lineArray[i] = resultLineParts[i];
3547 geos::unique_ptr multiLineGeom( GEOSGeom_createCollection_r( context, GEOS_MULTILINESTRING, lineArray, resultLineParts.size() ) );
3548 delete [] lineArray;
3551 result.reset( GEOSLineMerge_r( context, multiLineGeom.get() ) );
3555 if ( GEOSGeomTypeId_r( context, result.get() ) != GEOS_LINESTRING )
3566 int nIntersections = 0;
3567 int lastIntersectingRing = -2;
3571 int nRings = GEOSGetNumInteriorRings_r( context, polygon );
3576 const GEOSGeometry *outerRing = GEOSGetExteriorRing_r( context, polygon );
3577 if ( GEOSIntersects_r( context, outerRing, reshapeLineGeos ) == 1 )
3580 lastIntersectingRing = -1;
3581 lastIntersectingGeom = outerRing;
3589 for (
int i = 0; i < nRings; ++i )
3591 innerRings[i] = GEOSGetInteriorRingN_r( context, polygon, i );
3592 if ( GEOSIntersects_r( context, innerRings[i], reshapeLineGeos ) == 1 )
3595 lastIntersectingRing = i;
3596 lastIntersectingGeom = innerRings[i];
3600 catch ( GEOSException & )
3605 if ( nIntersections != 1 )
3607 delete [] innerRings;
3612 geos::unique_ptr reshapeResult = reshapeLine( lastIntersectingGeom, reshapeLineGeos,
precision );
3613 if ( !reshapeResult )
3615 delete [] innerRings;
3621 const GEOSCoordSequence *reshapeSequence = GEOSGeom_getCoordSeq_r( context, reshapeResult.get() );
3622 GEOSCoordSequence *newCoordSequence = GEOSCoordSeq_clone_r( context, reshapeSequence );
3624 reshapeResult.reset();
3626 newRing = GEOSGeom_createLinearRing_r( context, newCoordSequence );
3629 delete [] innerRings;
3634 if ( lastIntersectingRing == -1 )
3635 newOuterRing = newRing;
3637 newOuterRing = GEOSGeom_clone_r( context, outerRing );
3640 QVector<GEOSGeometry *> ringList;
3643 GEOSGeometry *outerRingPoly = GEOSGeom_createPolygon_r( context, GEOSGeom_clone_r( context, newOuterRing ),
nullptr, 0 );
3644 if ( outerRingPoly )
3646 ringList.reserve( nRings );
3648 for (
int i = 0; i < nRings; ++i )
3650 if ( lastIntersectingRing == i )
3651 currentRing = newRing;
3653 currentRing = GEOSGeom_clone_r( context, innerRings[i] );
3656 if ( GEOSContains_r( context, outerRingPoly, currentRing ) == 1 )
3657 ringList.push_back( currentRing );
3659 GEOSGeom_destroy_r( context, currentRing );
3662 GEOSGeom_destroy_r( context, outerRingPoly );
3666 for (
int i = 0; i < ringList.size(); ++i )
3667 newInnerRings[i] = ringList.at( i );
3669 delete [] innerRings;
3671 geos::unique_ptr reshapedPolygon( GEOSGeom_createPolygon_r( context, newOuterRing, newInnerRings, ringList.size() ) );
3672 delete[] newInnerRings;
3674 return reshapedPolygon;
3679 if ( !line1 || !line2 )
3684 double bufferDistance = std::pow( 10.0L, geomDigits( line2 ) - 11 );
3691 geos::unique_ptr intersectionGeom( GEOSIntersection_r( context, bufferGeom.get(), line1 ) );
3694 double intersectGeomLength;
3697 GEOSLength_r( context, intersectionGeom.get(), &intersectGeomLength );
3698 GEOSLength_r( context, line1, &line1Length );
3700 double intersectRatio = line1Length / intersectGeomLength;
3701 if ( intersectRatio > 0.9 && intersectRatio < 1.1 )
3709 if ( !point || !line )
3712 double bufferDistance = std::pow( 10.0L, geomDigits( line ) - 11 );
3715 geos::unique_ptr lineBuffer( GEOSBuffer_r( context, line, bufferDistance, 8 ) );
3719 bool contained =
false;
3720 if ( GEOSContains_r( context, lineBuffer.get(), point ) == 1 )
3729 geos::unique_ptr bbox( GEOSEnvelope_r( context, geom ) );
3733 const GEOSGeometry *bBoxRing = GEOSGetExteriorRing_r( context, bbox.get() );
3737 const GEOSCoordSequence *bBoxCoordSeq = GEOSGeom_getCoordSeq_r( context, bBoxRing );
3739 if ( !bBoxCoordSeq )
3742 unsigned int nCoords = 0;
3743 if ( !GEOSCoordSeq_getSize_r( context, bBoxCoordSeq, &nCoords ) )
3747 for (
unsigned int i = 0; i < nCoords - 1; ++i )
3750 GEOSCoordSeq_getX_r( context, bBoxCoordSeq, i, &t );
3753 digits = std::ceil( std::log10( std::fabs( t ) ) );
3754 if ( digits > maxDigits )
3757 GEOSCoordSeq_getY_r( context, bBoxCoordSeq, i, &t );
3758 digits = std::ceil( std::log10( std::fabs( t ) ) );
3759 if ( digits > maxDigits )
The Qgis class provides global constants for use throughout the application.
BufferSide
Side of line to buffer.
@ Right
Buffer to right of line.
GeometryOperationResult
Success or failure of a geometry operation.
@ AddPartNotMultiGeometry
The source geometry is not multi.
@ InvalidBaseGeometry
The base geometry on which the operation is done is invalid or empty.
@ RejectOnInvalidSubGeometry
Don't allow geometries with invalid sub-geometries to be created.
@ SkipEmptyInteriorRings
Skip any empty polygon interior ring.
QFlags< GeosCreationFlag > GeosCreationFlags
Geos geometry creation behavior flags.
JoinStyle
Join styles for buffers.
EndCapStyle
End cap styles for buffers.
CoverageValidityResult
Coverage validity results.
@ Valid
Coverage is valid.
@ Invalid
Coverage is invalid. Invalidity includes polygons that overlap, that have gaps smaller than the gap w...
@ Error
An exception occurred while determining validity.
MakeValidMethod
Algorithms to use when repairing invalid geometries.
@ Linework
Combines all rings into a set of noded lines and then extracts valid polygons from that linework.
@ Structure
Structured method, first makes all rings valid and then merges shells and subtracts holes from shells...
WkbType
The WKB type describes the number of dimensions a geometry has.
@ GeometryCollection
GeometryCollection.
@ PolyhedralSurface
PolyhedralSurface.
Abstract base class for all geometries.
virtual const QgsAbstractGeometry * simplifiedTypeRef() const
Returns a reference to the simplest lossless representation of this geometry, e.g.
bool isMeasure() const
Returns true if the geometry contains m values.
virtual QgsRectangle boundingBox() const
Returns the minimal bounding box for the geometry.
bool is3D() const
Returns true if the geometry is 3D and contains a z-value.
Qgis::WkbType wkbType() const
Returns the WKB type of the geometry.
virtual bool isEmpty() const
Returns true if the geometry is empty.
virtual int dimension() const =0
Returns the inherent dimension of the geometry.
virtual QgsAbstractGeometry * clone() const =0
Clones the geometry by performing a deep copy.
Curve polygon geometry type.
int numInteriorRings() const
Returns the number of interior rings contained with the curve polygon.
const QgsCurve * exteriorRing() const
Returns the curve polygon's exterior ring.
const QgsCurve * interiorRing(int i) const
Retrieves an interior ring from the curve polygon.
Abstract base class for curved geometry type.
virtual QgsLineString * curveToLine(double tolerance=M_PI_2/90, SegmentationToleranceType toleranceType=MaximumAngle) const =0
Returns a new line string geometry corresponding to a segmentized approximation of the curve.
virtual bool addGeometry(QgsAbstractGeometry *g)
Adds a geometry and takes ownership. Returns true in case of success.
static Qgis::GeometryOperationResult addPart(QgsAbstractGeometry *geometry, std::unique_ptr< QgsAbstractGeometry > part)
Add a part to multi type geometry.
A geometry engine is a low-level representation of a QgsAbstractGeometry object, optimised for use wi...
const QgsAbstractGeometry * mGeometry
EngineOperationResult
Success or failure of a geometry operation.
@ NothingHappened
Nothing happened, without any error.
@ InvalidBaseGeometry
The geometry on which the operation occurs is not valid.
@ InvalidInput
The input is not valid.
@ NodedGeometryError
Error occurred while creating a noded geometry.
@ EngineError
Error occurred in the geometry engine.
@ SplitCannotSplitPoint
Points cannot be split.
@ Success
Operation succeeded.
void logError(const QString &engineName, const QString &message) const
Logs an error message encountered during an operation.
static std::unique_ptr< QgsGeometryCollection > createCollectionOfType(Qgis::WkbType type)
Returns a new geometry collection matching a specified WKB type.
Encapsulates parameters under which a geometry operation is performed.
double gridSize() const
Returns the grid size which will be used to snap vertices of a geometry.
A geometry is the spatial representation of a feature.
QgsAbstractGeometry * get()
Returns a modifiable (non-const) reference to the underlying abstract geometry primitive.
const QgsAbstractGeometry * constGet() const
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
bool isEmpty() const
Returns true if the geometry is empty (eg a linestring with no vertices, or a collection with no geom...
Used to create and store a proj context object, correctly freeing the context upon destruction.
static GEOSContextHandle_t get()
Returns a thread local instance of a GEOS context, safe for use in the current thread.
Does vector analysis using the geos library and handles import, export, exception handling*.
QgsGeometry delaunayTriangulation(double tolerance=0.0, bool edgesOnly=false, QString *errorMsg=nullptr) const
Returns the Delaunay triangulation for the vertices of the geometry.
bool touches(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Checks if geom touches this.
QgsAbstractGeometry * symDifference(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr, const QgsGeometryParameters ¶meters=QgsGeometryParameters()) const override
Calculate the symmetric difference of this and geom.
double hausdorffDistanceDensify(const QgsAbstractGeometry *geom, double densifyFraction, QString *errorMsg=nullptr) const
Returns the Hausdorff distance between this geometry and geom.
bool isValid(QString *errorMsg=nullptr, bool allowSelfTouchingHoles=false, QgsGeometry *errorLoc=nullptr) const override
Returns true if the geometry is valid.
std::unique_ptr< QgsAbstractGeometry > subdivide(int maxNodes, QString *errorMsg=nullptr, const QgsGeometryParameters ¶meters=QgsGeometryParameters()) const
Subdivides the geometry.
QgsAbstractGeometry * intersection(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr, const QgsGeometryParameters ¶meters=QgsGeometryParameters()) const override
Calculate the intersection of this and geom.
double hausdorffDistance(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const
Returns the Hausdorff distance between this geometry and geom.
std::unique_ptr< QgsAbstractGeometry > constrainedDelaunayTriangulation(QString *errorMsg=nullptr) const
Returns a constrained Delaunay triangulation for the vertices of the geometry.
QgsAbstractGeometry * buffer(double distance, int segments, QString *errorMsg=nullptr) const override
QgsAbstractGeometry * concaveHull(double targetPercent, bool allowHoles=false, QString *errorMsg=nullptr) const
Returns a possibly concave geometry that encloses the input geometry.
std::unique_ptr< QgsAbstractGeometry > reshapeGeometry(const QgsLineString &reshapeWithLine, EngineOperationResult *errorCode, QString *errorMsg=nullptr) const
Reshapes the geometry using a line.
std::unique_ptr< QgsAbstractGeometry > maximumInscribedCircle(double tolerance, QString *errorMsg=nullptr) const
Returns the maximum inscribed circle.
static geos::unique_ptr asGeos(const QgsGeometry &geometry, double precision=0, Qgis::GeosCreationFlags flags=Qgis::GeosCreationFlags())
Returns a geos geometry - caller takes ownership of the object (should be deleted with GEOSGeom_destr...
QgsAbstractGeometry * difference(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr, const QgsGeometryParameters ¶meters=QgsGeometryParameters()) const override
Calculate the difference of this and geom.
EngineOperationResult splitGeometry(const QgsLineString &splitLine, QVector< QgsGeometry > &newGeometries, bool topological, QgsPointSequence &topologyTestPoints, QString *errorMsg=nullptr, bool skipIntersectionCheck=false) const override
Splits this geometry according to a given line.
std::unique_ptr< QgsAbstractGeometry > sharedPaths(const QgsAbstractGeometry *other, QString *errorMsg=nullptr) const
Find paths shared between the two given lineal geometries (this and other).
std::unique_ptr< QgsAbstractGeometry > clip(const QgsRectangle &rectangle, QString *errorMsg=nullptr) const
Performs a fast, non-robust intersection between the geometry and a rectangle.
std::unique_ptr< QgsAbstractGeometry > node(QString *errorMsg=nullptr) const
Returns a (Multi)LineString representing the fully noded version of a collection of linestrings.
double minimumClearance(QString *errorMsg=nullptr) const
Computes the minimum clearance of a geometry.
std::unique_ptr< QgsAbstractGeometry > singleSidedBuffer(double distance, int segments, Qgis::BufferSide side, Qgis::JoinStyle joinStyle, double miterLimit, QString *errorMsg=nullptr) const
Returns a single sided buffer for a geometry.
bool disjoint(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Checks if geom is disjoint from this.
std::unique_ptr< QgsAbstractGeometry > makeValid(Qgis::MakeValidMethod method=Qgis::MakeValidMethod::Linework, bool keepCollapsed=false, QString *errorMsg=nullptr) const
Repairs the geometry using GEOS make valid routine.
QgsGeometry shortestLine(const QgsGeometry &other, QString *errorMsg=nullptr) const
Returns the shortest line joining this geometry to the other geometry.
QgsAbstractGeometry * simplify(double tolerance, QString *errorMsg=nullptr) const override
std::unique_ptr< QgsAbstractGeometry > unionCoverage(QString *errorMsg=nullptr) const
Optimized union algorithm for polygonal inputs that are correctly noded and do not overlap.
QgsGeometry closestPoint(const QgsGeometry &other, QString *errorMsg=nullptr) const
Returns the closest point on the geometry to the other geometry.
static std::unique_ptr< QgsPolygon > fromGeosPolygon(const GEOSGeometry *geos)
std::unique_ptr< QgsAbstractGeometry > minimumClearanceLine(QString *errorMsg=nullptr) const
Returns a LineString whose endpoints define the minimum clearance of a geometry.
QgsAbstractGeometry * envelope(QString *errorMsg=nullptr) const override
QString relate(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Returns the Dimensional Extended 9 Intersection Model (DE-9IM) representation of the relationship bet...
bool crosses(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Checks if geom crosses this.
QgsAbstractGeometry * convexHull(QString *errorMsg=nullptr) const override
Calculate the convex hull of this.
double distance(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Calculates the distance between this and geom.
std::unique_ptr< QgsAbstractGeometry > minimumWidth(QString *errorMsg=nullptr) const
Returns a linestring geometry which represents the minimum diameter of the geometry.
bool isSimple(QString *errorMsg=nullptr) const override
Determines whether the geometry is simple (according to OGC definition).
QgsAbstractGeometry * combine(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr, const QgsGeometryParameters ¶meters=QgsGeometryParameters()) const override
Calculate the combination of this and geom.
bool within(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Checks if geom is within this.
void prepareGeometry() override
Prepares the geometry, so that subsequent calls to spatial relation methods are much faster.
static std::unique_ptr< QgsAbstractGeometry > fromGeos(const GEOSGeometry *geos)
Create a geometry from a GEOSGeometry.
QgsAbstractGeometry * interpolate(double distance, QString *errorMsg=nullptr) const override
bool distanceWithin(const QgsAbstractGeometry *geom, double maxdistance, QString *errorMsg=nullptr) const override
Checks if geom is within maxdistance distance from this geometry.
bool isEqual(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Checks if this is equal to geom.
bool contains(double x, double y, QString *errorMsg=nullptr) const
Returns true if the geometry contains the point at (x, y).
QgsGeometry mergeLines(QString *errorMsg=nullptr) const
Merges any connected lines in a LineString/MultiLineString geometry and converts them to single line ...
static QgsGeometry polygonize(const QVector< const QgsAbstractGeometry * > &geometries, QString *errorMsg=nullptr)
Creates a GeometryCollection geometry containing possible polygons formed from the constituent linewo...
bool relatePattern(const QgsAbstractGeometry *geom, const QString &pattern, QString *errorMsg=nullptr) const override
Tests whether two geometries are related by a specified Dimensional Extended 9 Intersection Model (DE...
QgsAbstractGeometry * offsetCurve(double distance, int segments, Qgis::JoinStyle joinStyle, double miterLimit, QString *errorMsg=nullptr) const override
Offsets a curve.
QgsPoint * centroid(QString *errorMsg=nullptr) const override
Calculates the centroid of this.
double lineLocatePoint(const QgsPoint &point, QString *errorMsg=nullptr) const
Returns a distance representing the location along this linestring of the closest point on this lines...
std::unique_ptr< QgsAbstractGeometry > simplifyCoverageVW(double tolerance, bool preserveBoundary, QString *errorMsg=nullptr) const
Operates on a coverage (represented as a list of polygonal geometry with exactly matching edge geomet...
bool isEmpty(QString *errorMsg=nullptr) const override
static Qgis::GeometryOperationResult addPart(QgsGeometry &geometry, GEOSGeometry *newPart)
Adds a new island polygon to a multipolygon feature.
double frechetDistance(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const
Returns the Fréchet distance between this geometry and geom, restricted to discrete points for both g...
QgsGeos(const QgsAbstractGeometry *geometry, double precision=0, Qgis::GeosCreationFlags flags=Qgis::GeosCreationFlags())
GEOS geometry engine constructor.
QgsGeometry voronoiDiagram(const QgsAbstractGeometry *extent=nullptr, double tolerance=0.0, bool edgesOnly=false, QString *errorMsg=nullptr) const
Creates a Voronoi diagram for the nodes contained within the geometry.
bool intersects(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Checks if geom intersects this.
void geometryChanged() override
Should be called whenever the geometry associated with the engine has been modified and the engine mu...
bool overlaps(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Checks if geom overlaps this.
double area(QString *errorMsg=nullptr) const override
double length(QString *errorMsg=nullptr) const override
std::unique_ptr< QgsAbstractGeometry > largestEmptyCircle(double tolerance, const QgsAbstractGeometry *boundary=nullptr, QString *errorMsg=nullptr) const
Constructs the Largest Empty Circle for a set of obstacle geometries, up to a specified tolerance.
Qgis::CoverageValidityResult validateCoverage(double gapWidth, std::unique_ptr< QgsAbstractGeometry > *invalidEdges, QString *errorMsg=nullptr) const
Analyze a coverage (represented as a collection of polygonal geometry with exactly matching edge geom...
double frechetDistanceDensify(const QgsAbstractGeometry *geom, double densifyFraction, QString *errorMsg=nullptr) const
Returns the Fréchet distance between this geometry and geom, restricted to discrete points for both g...
static QgsPoint coordSeqPoint(const GEOSCoordSequence *cs, int i, bool hasZ, bool hasM)
QgsPoint * pointOnSurface(QString *errorMsg=nullptr) const override
Calculate a point that is guaranteed to be on the surface of this.
static QgsGeometry geometryFromGeos(GEOSGeometry *geos)
Creates a new QgsGeometry object, feeding in a geometry in GEOS format.
Line string geometry type, with support for z-dimension and m-values.
const double * yData() const
Returns a const pointer to the y vertex data.
const double * xData() const
Returns a const pointer to the x vertex data.
QVector< double > xVector() const
Returns the x vertex values as a vector.
const double * zData() const
Returns a const pointer to the z vertex data, or nullptr if the linestring does not have z values.
int numPoints() const override
Returns the number of points in the curve.
QgsPoint pointN(int i) const
Returns the specified point from inside the line string.
QVector< double > yVector() const
Returns the y vertex values as a vector.
double yAt(int index) const override
Returns the y-coordinate of the specified node in the line string.
QVector< double > zVector() const
Returns the z vertex values as a vector.
double closestSegment(const QgsPoint &pt, QgsPoint &segmentPt, QgsVertexId &vertexAfter, int *leftOf=nullptr, double epsilon=4 *std::numeric_limits< double >::epsilon()) const override
Searches for the closest segment of the geometry to a given point.
const double * mData() const
Returns a const pointer to the m vertex data, or nullptr if the linestring does not have m values.
void addVertex(const QgsPoint &pt)
Adds a new vertex to the end of the line string.
QgsLineString * clone() const override
Clones the geometry by performing a deep copy.
double xAt(int index) const override
Returns the x-coordinate of the specified node in the line string.
Multi curve geometry collection.
bool addGeometry(QgsAbstractGeometry *g) override
Adds a geometry and takes ownership. Returns true in case of success.
Multi line string geometry collection.
Multi point geometry collection.
Multi polygon geometry collection.
Custom exception class which is raised when an operation is not supported.
A class to represent a 2D point.
Point geometry type, with support for z-dimension and m-values.
double distance(double x, double y) const
Returns the Cartesian 2D distance between this point and a specified x, y coordinate.
Polyhedral surface geometry type.
int numPatches() const
Returns the number of patches contained with the polyhedral surface.
const QgsPolygon * patchN(int i) const
Retrieves a patch from the polyhedral surface.
A rectangle specified with double values.
double xMinimum() const
Returns the x minimum value (left side of rectangle).
void setYMinimum(double y)
Set the minimum y value.
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
void setXMinimum(double x)
Set the minimum x value.
double width() const
Returns the width of the rectangle.
double xMaximum() const
Returns the x maximum value (right side of rectangle).
bool isNull() const
Test if the rectangle is null (holding no spatial information).
double yMaximum() const
Returns the y maximum value (top side of rectangle).
void setYMaximum(double y)
Set the maximum y value.
void setXMaximum(double x)
Set the maximum x value.
bool isEmpty() const
Returns true if the rectangle has no area.
double height() const
Returns the height of the rectangle.
static Qgis::GeometryType geometryType(Qgis::WkbType type)
Returns the geometry type for a WKB type, e.g., both MultiPolygon and CurvePolygon would have a Polyg...
static bool isMultiType(Qgis::WkbType type)
Returns true if the WKB type is a multi type.
static Qgis::WkbType flatType(Qgis::WkbType type)
Returns the flat type for a WKB type.
Contains geos related utilities and functions.
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
QVector< QgsPoint > QgsPointSequence
#define DEFAULT_QUADRANT_SEGMENTS
#define CATCH_GEOS_WITH_ERRMSG(r)
#define QgsDebugError(str)
QLineF segment(int index, QRectF rect, double radius)
Utility class for identifying a unique vertex within a geometry.
struct GEOSGeom_t GEOSGeometry