31#define DEFAULT_QUADRANT_SEGMENTS 8
33#define CATCH_GEOS(r) \
34 catch (GEOSException &) \
39#define CATCH_GEOS_WITH_ERRMSG(r) \
40 catch (GEOSException &e) \
44 *errorMsg = e.what(); \
51static void throwGEOSException(
const char *fmt, ... )
57 vsnprintf( buffer,
sizeof buffer, fmt, ap );
60 QString message = QString::fromUtf8( buffer );
70 throw GEOSException( message );
78 throw GEOSException( message );
83static void printGEOSNotice(
const char *fmt, ... )
90 vsnprintf( buffer,
sizeof buffer, fmt, ap );
101#if defined(USE_THREAD_LOCAL) && !defined(Q_OS_WIN)
104QThreadStorage< QgsGeosContext * > QgsGeosContext::sGeosContext;
110#if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=5 )
111 mContext = GEOS_init_r();
112 GEOSContext_setNoticeHandler_r( mContext, printGEOSNotice );
113 GEOSContext_setErrorHandler_r( mContext, throwGEOSException );
115 mContext = initGEOS_r( printGEOSNotice, throwGEOSException );
121#if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=5 )
122 GEOS_finish_r( mContext );
124 finishGEOS_r( mContext );
130#if defined(USE_THREAD_LOCAL) && !defined(Q_OS_WIN)
131 return sGeosContext.mContext;
133 GEOSContextHandle_t gContext =
nullptr;
134 if ( sGeosContext.hasLocalData() )
136 gContext = sGeosContext.localData()->mContext;
141 gContext = sGeosContext.localData()->mContext;
151void geos::GeosDeleter::operator()(
GEOSGeometry *geom )
const
156void geos::GeosDeleter::operator()(
const GEOSPreparedGeometry *geom )
const
161void geos::GeosDeleter::operator()( GEOSBufferParams *params )
const
166void geos::GeosDeleter::operator()( GEOSCoordSequence *sequence )
const
180 cacheGeos( allowInvalidSubGeom );
205#if GEOS_VERSION_MAJOR==3 && GEOS_VERSION_MINOR<10
207 throw QgsNotSupportedException( QObject::tr(
"The structured method to make geometries valid requires a QGIS build based on GEOS 3.10 or later" ) );
210 throw QgsNotSupportedException( QObject::tr(
"The keep collapsed option for making geometries valid requires a QGIS build based on GEOS 3.10 or later" ) );
211 geos::unique_ptr
geos;
214 geos.reset( GEOSMakeValid_r( context, mGeos.get() ) );
219 GEOSMakeValidParams *params = GEOSMakeValidParams_create_r( context );
223 GEOSMakeValidParams_setMethod_r( context, params, GEOS_MAKE_VALID_LINEWORK );
227 GEOSMakeValidParams_setMethod_r( context, params, GEOS_MAKE_VALID_STRUCTURE );
231 GEOSMakeValidParams_setKeepCollapsed_r( context,
233 keepCollapsed ? 1 : 0 );
235 geos::unique_ptr
geos;
238 geos.reset( GEOSMakeValidWithParams_r( context, mGeos.get(), params ) );
239 GEOSMakeValidParams_destroy_r( context, params );
241 catch ( GEOSException &e )
245 *errorMsg = e.what();
247 GEOSMakeValidParams_destroy_r( context, params );
276 std::unique_ptr< QgsAbstractGeometry > geom =
fromGeos( newPart );
283 mGeosPrepared.reset();
300void QgsGeos::cacheGeos(
bool allowInvalidSubGeom )
const
317 return overlay( geom, OverlayIntersection, errorMsg, parameters ).release();
322 return overlay( geom, OverlayDifference, errorMsg, parameters ).release();
337 catch ( GEOSException &e )
339 logError( QStringLiteral(
"GEOS" ), e.what() );
342 *errorMsg = e.what();
351 int partType = GEOSGeomTypeId_r( context, currentPart );
354 if ( partType == GEOS_POINT )
365 if ( partType == GEOS_MULTILINESTRING || partType == GEOS_MULTIPOLYGON || partType == GEOS_GEOMETRYCOLLECTION )
367 int partCount = GEOSGetNumGeometries_r( context, currentPart );
368 for (
int i = 0; i < partCount; ++i )
370 subdivideRecursive( GEOSGetGeometryN_r( context, currentPart, i ), maxNodes, depth, parts, clipRect, gridSize );
381 int vertexCount = GEOSGetNumCoordinates_r( context, currentPart );
382 if ( vertexCount == 0 )
386 else if ( vertexCount < maxNodes )
393 double width = clipRect.
width();
394 double height = clipRect.
height();
397 if ( width > height )
410 halfClipRect1.
setYMinimum( halfClipRect1.
yMinimum() - std::numeric_limits<double>::epsilon() );
411 halfClipRect2.
setYMinimum( halfClipRect2.
yMinimum() - std::numeric_limits<double>::epsilon() );
412 halfClipRect1.
setYMaximum( halfClipRect1.
yMaximum() + std::numeric_limits<double>::epsilon() );
413 halfClipRect2.
setYMaximum( halfClipRect2.
yMaximum() + std::numeric_limits<double>::epsilon() );
417 halfClipRect1.
setXMinimum( halfClipRect1.
xMinimum() - std::numeric_limits<double>::epsilon() );
418 halfClipRect2.
setXMinimum( halfClipRect2.
xMinimum() - std::numeric_limits<double>::epsilon() );
419 halfClipRect1.
setXMaximum( halfClipRect1.
xMaximum() + std::numeric_limits<double>::epsilon() );
420 halfClipRect2.
setXMaximum( halfClipRect2.
xMaximum() + std::numeric_limits<double>::epsilon() );
423 geos::unique_ptr clipPart1( GEOSClipByRect_r( context, currentPart, halfClipRect1.
xMinimum(), halfClipRect1.
yMinimum(), halfClipRect1.
xMaximum(), halfClipRect1.
yMaximum() ) );
424 geos::unique_ptr clipPart2( GEOSClipByRect_r( context, currentPart, halfClipRect2.
xMinimum(), halfClipRect2.
yMinimum(), halfClipRect2.
xMaximum(), halfClipRect2.
yMaximum() ) );
432 clipPart1.reset( GEOSIntersectionPrec_r( context, mGeos.get(), clipPart1.get(), gridSize ) );
434 subdivideRecursive( clipPart1.get(), maxNodes, depth, parts, halfClipRect1, gridSize );
440 clipPart2.reset( GEOSIntersectionPrec_r( context, mGeos.get(), clipPart2.get(), gridSize ) );
442 subdivideRecursive( clipPart2.get(), maxNodes, depth, parts, halfClipRect2, gridSize );
454 maxNodes = std::max( maxNodes, 8 );
463 return std::move( parts );
468 return overlay( geom, OverlayUnion, errorMsg, parameters ).release();
473 std::vector<geos::unique_ptr> geosGeometries;
474 geosGeometries.reserve( geomList.size() );
480 geosGeometries.emplace_back(
asGeos( g, mPrecision ) );
484 geos::unique_ptr geomUnion;
487 geos::unique_ptr geomCollection = createGeosCollection( GEOS_GEOMETRYCOLLECTION, geosGeometries );
490 geomUnion.reset( GEOSUnaryUnionPrec_r( context, geomCollection.get(), parameters.
gridSize() ) );
494 geomUnion.reset( GEOSUnaryUnion_r( context, geomCollection.get() ) );
499 std::unique_ptr< QgsAbstractGeometry > result =
fromGeos( geomUnion.get() );
500 return result.release();
505 std::vector<geos::unique_ptr> geosGeometries;
506 geosGeometries.reserve( geomList.size() );
512 geosGeometries.emplace_back(
asGeos( g.constGet(), mPrecision ) );
516 geos::unique_ptr geomUnion;
519 geos::unique_ptr geomCollection = createGeosCollection( GEOS_GEOMETRYCOLLECTION, geosGeometries );
523 geomUnion.reset( GEOSUnaryUnionPrec_r( context, geomCollection.get(), parameters.
gridSize() ) );
527 geomUnion.reset( GEOSUnaryUnion_r( context, geomCollection.get() ) );
533 std::unique_ptr< QgsAbstractGeometry > result =
fromGeos( geomUnion.get() );
534 return result.release();
539 return overlay( geom, OverlaySymDifference, errorMsg, parameters ).release();
550 geos::unique_ptr otherGeosGeom(
asGeos( geom, mPrecision ) );
551 if ( !otherGeosGeom )
561 GEOSPreparedDistance_r( context, mGeosPrepared.get(), otherGeosGeom.get(), &
distance );
565 GEOSDistance_r( context, mGeos.get(), otherGeosGeom.get(), &
distance );
581 geos::unique_ptr point = createGeosPointXY( x, y,
false, 0,
false, 0, 2, 0 );
590 GEOSPreparedDistance_r( context, mGeosPrepared.get(), point.get(), &
distance );
594 GEOSDistance_r( context, mGeos.get(), point.get(), &
distance );
609 geos::unique_ptr otherGeosGeom(
asGeos( geom, mPrecision ) );
610 if ( !otherGeosGeom )
625#if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=10 )
626 return GEOSPreparedDistanceWithin_r( context, mGeosPrepared.get(), otherGeosGeom.get(), maxdist );
628 GEOSPreparedDistance_r( context, mGeosPrepared.get(), otherGeosGeom.get(), &
distance );
633#if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=10 )
634 return GEOSDistanceWithin_r( context, mGeos.get(), otherGeosGeom.get(), maxdist );
636 GEOSDistance_r( context, mGeos.get(), otherGeosGeom.get(), &
distance );
651#if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=12 )
654 geos::unique_ptr point = createGeosPointXY( x, y,
false, 0,
false, 0, 2, 0 );
660#if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=12 )
661 return GEOSPreparedContainsXY_r( context, mGeosPrepared.get(), x, y ) == 1;
663 return GEOSPreparedContains_r( context, mGeosPrepared.get(), point.get() ) == 1;
667#if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=12 )
668 geos::unique_ptr point = createGeosPointXY( x, y,
false, 0,
false, 0, 2, 0 );
673 result = ( GEOSContains_r( context, mGeos.get(), point.get() ) == 1 );
675 catch ( GEOSException &e )
677 logError( QStringLiteral(
"GEOS" ), e.what() );
680 *errorMsg = e.what();
696 geos::unique_ptr otherGeosGeom(
asGeos( geom, mPrecision ) );
697 if ( !otherGeosGeom )
719 geos::unique_ptr otherGeosGeom(
asGeos( geom, mPrecision ) );
720 if ( !otherGeosGeom )
742 geos::unique_ptr otherGeosGeom(
asGeos( geom, mPrecision ) );
743 if ( !otherGeosGeom )
765 geos::unique_ptr otherGeosGeom(
asGeos( geom, mPrecision ) );
766 if ( !otherGeosGeom )
782 if ( !mGeos || !geom )
787#if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=12 )
795 return GEOSPreparedIntersectsXY_r(
QgsGeosContext::get(), mGeosPrepared.get(), point->x(), point->y() ) == 1;
797 catch ( GEOSException &e )
799 logError( QStringLiteral(
"GEOS" ), e.what() );
802 *errorMsg = e.what();
810 return relation( geom, RelationIntersects, errorMsg );
815 return relation( geom, RelationTouches, errorMsg );
820 return relation( geom, RelationCrosses, errorMsg );
825 return relation( geom, RelationWithin, errorMsg );
830 return relation( geom, RelationOverlaps, errorMsg );
835 if ( !mGeos || !geom )
840#if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=12 )
848 return GEOSPreparedContainsXY_r(
QgsGeosContext::get(), mGeosPrepared.get(), point->x(), point->y() ) == 1;
850 catch ( GEOSException &e )
852 logError( QStringLiteral(
"GEOS" ), e.what() );
855 *errorMsg = e.what();
863 return relation( geom, RelationContains, errorMsg );
868 return relation( geom, RelationDisjoint, errorMsg );
878 geos::unique_ptr geosGeom(
asGeos( geom, mPrecision ) );
888 char *r = GEOSRelate_r( context, mGeos.get(), geosGeom.get() );
891 result = QString( r );
892 GEOSFree_r( context, r );
895 catch ( GEOSException &e )
897 logError( QStringLiteral(
"GEOS" ), e.what() );
900 *errorMsg = e.what();
909 if ( !mGeos || !geom )
914 geos::unique_ptr geosGeom(
asGeos( geom, mPrecision ) );
924 result = ( GEOSRelatePattern_r( context, mGeos.get(), geosGeom.get(), pattern.toLocal8Bit().constData() ) == 1 );
926 catch ( GEOSException &e )
928 logError( QStringLiteral(
"GEOS" ), e.what() );
931 *errorMsg = e.what();
972 QVector<QgsGeometry> &newGeometries,
975 QString *errorMsg,
bool skipIntersectionCheck )
const
991 if ( !GEOSisValid_r( context, mGeos.get() ) )
999 newGeometries.clear();
1000 geos::unique_ptr splitLineGeos;
1006 splitLineGeos = createGeosLinestring( &splitLine, mPrecision );
1010 splitLineGeos = createGeosPointXY( splitLine.
xAt( 0 ), splitLine.
yAt( 0 ),
false, 0,
false, 0, 2, mPrecision );
1017 if ( !GEOSisValid_r( context, splitLineGeos.get() ) || !GEOSisSimple_r( context, splitLineGeos.get() ) )
1025 if ( !topologicalTestPointsSplit( splitLineGeos.get(), topologyTestPoints ) )
1034 returnCode = splitLinearGeometry( splitLineGeos.get(), newGeometries, skipIntersectionCheck );
1038 returnCode = splitPolygonGeometry( splitLineGeos.get(), newGeometries, skipIntersectionCheck );
1067 geos::unique_ptr intersectionGeom( GEOSIntersection_r( context, mGeos.get(), splitLine ) );
1068 if ( !intersectionGeom )
1071 bool simple =
false;
1072 int nIntersectGeoms = 1;
1073 if ( GEOSGeomTypeId_r( context, intersectionGeom.get() ) == GEOS_LINESTRING
1074 || GEOSGeomTypeId_r( context, intersectionGeom.get() ) == GEOS_POINT )
1078 nIntersectGeoms = GEOSGetNumGeometries_r( context, intersectionGeom.get() );
1080 for (
int i = 0; i < nIntersectGeoms; ++i )
1084 currentIntersectGeom = intersectionGeom.get();
1086 currentIntersectGeom = GEOSGetGeometryN_r( context, intersectionGeom.get(), i );
1088 const GEOSCoordSequence *lineSequence = GEOSGeom_getCoordSeq_r( context, currentIntersectGeom );
1089 unsigned int sequenceSize = 0;
1091 if ( GEOSCoordSeq_getSize_r( context, lineSequence, &sequenceSize ) != 0 )
1093 for (
unsigned int i = 0; i < sequenceSize; ++i )
1095 if ( GEOSCoordSeq_getXYZ_r( context, lineSequence, i, &x, &y, &z ) )
1097 testPoints.push_back(
QgsPoint( x, y, z ) );
1111 int type = GEOSGeomTypeId_r( context, mGeos.get() );
1113 std::unique_ptr< QgsMultiCurve > multiCurve;
1114 if ( type == GEOS_MULTILINESTRING )
1116 multiCurve.reset( qgsgeometry_cast<QgsMultiCurve *>(
mGeometry->
clone() ) );
1118 else if ( type == GEOS_LINESTRING )
1136 std::unique_ptr< QgsMultiPoint > splitPoints;
1138 std::unique_ptr< QgsAbstractGeometry > splitGeom(
fromGeos( GEOSsplitPoint ) );
1140 if ( qgsgeometry_cast<QgsMultiPoint *>( splitGeom.get() ) )
1142 splitPoints.reset( qgsgeometry_cast<QgsMultiPoint *>( splitGeom.release() ) );
1144 else if ( qgsgeometry_cast<QgsPoint *>( splitGeom.get() ) )
1146 splitPoints = std::make_unique< QgsMultiPoint >();
1147 if ( qgsgeometry_cast<QgsPoint *>( splitGeom.get() ) )
1149 splitPoints->addGeometry( qgsgeometry_cast<QgsPoint *>( splitGeom.release() ) );
1157 for (
int geometryIndex = 0; geometryIndex < multiCurve->numGeometries(); ++geometryIndex )
1159 const QgsLineString *line = qgsgeometry_cast<const QgsLineString *>( multiCurve->geometryN( geometryIndex ) );
1162 const QgsCurve *curve = qgsgeometry_cast<const QgsCurve *>( multiCurve->geometryN( geometryIndex ) );
1170 QMap< int, QVector< QPair< double, QgsPoint > > >pointMap;
1171 for (
int splitPointIndex = 0; splitPointIndex < splitPoints->numGeometries(); ++splitPointIndex )
1173 const QgsPoint *intersectionPoint = splitPoints->pointN( splitPointIndex );
1179 line->
closestSegment( *intersectionPoint, segmentPoint2D, nextVertex );
1195 const QPair< double, QgsPoint > pair = qMakePair(
distance, *correctSegmentPoint.get() );
1196 if ( pointMap.contains( nextVertex.
vertex - 1 ) )
1197 pointMap[ nextVertex.
vertex - 1 ].append( pair );
1199 pointMap[ nextVertex.
vertex - 1 ] = QVector< QPair< double, QgsPoint > >() << pair;
1204 for (
auto &p : pointMap )
1206 std::sort( p.begin(), p.end(), [](
const QPair< double, QgsPoint > &a,
const QPair< double, QgsPoint > &b ) { return a.first < b.first; } );
1213 for (
int vertexIndex = 0; vertexIndex < nVertices; ++vertexIndex )
1217 if ( pointMap.contains( vertexIndex ) )
1220 for (
int k = 0; k < pointMap[ vertexIndex ].size(); ++k )
1222 splitPoint = pointMap[ vertexIndex ][k].second;
1223 if ( splitPoint == currentPoint )
1229 else if ( splitPoint == line->
pointN( vertexIndex + 1 ) )
1248 return asGeos( &lines, mPrecision );
1253 Q_UNUSED( skipIntersectionCheck )
1262 geos::unique_ptr intersectGeom( GEOSIntersection_r( context, splitLine, mGeos.get() ) );
1263 if ( !intersectGeom || GEOSisEmpty_r( context, intersectGeom.get() ) )
1267 const int linearIntersect = GEOSRelatePattern_r( context, mGeos.get(), splitLine,
"1********" );
1268 if ( linearIntersect > 0 )
1271 geos::unique_ptr splitGeom = linePointDifference( intersectGeom.get() );
1276 std::vector<geos::unique_ptr> lineGeoms;
1278 const int splitType = GEOSGeomTypeId_r( context, splitGeom.get() );
1279 if ( splitType == GEOS_MULTILINESTRING )
1281 const int nGeoms = GEOSGetNumGeometries_r( context, splitGeom.get() );
1282 lineGeoms.reserve( nGeoms );
1283 for (
int i = 0; i < nGeoms; ++i )
1284 lineGeoms.emplace_back( GEOSGeom_clone_r( context, GEOSGetGeometryN_r( context, splitGeom.get(), i ) ) );
1289 lineGeoms.emplace_back( GEOSGeom_clone_r( context, splitGeom.get() ) );
1292 mergeGeometriesMultiTypeSplit( lineGeoms );
1294 for ( geos::unique_ptr &lineGeom : lineGeoms )
1312 if ( !mGeosPrepared )
1318 if ( !skipIntersectionCheck && !GEOSPreparedIntersects_r( context, mGeosPrepared.get(), splitLine ) )
1322 geos::unique_ptr nodedGeometry = nodeGeometries( splitLine, mGeos.get() );
1323 if ( !nodedGeometry )
1327 geos::unique_ptr polygons( GEOSPolygonize_r( context, &noded, 1 ) );
1332 const int numberOfGeometriesPolygon = numberOfGeometries( polygons.get() );
1333 if ( numberOfGeometriesPolygon == 0 )
1340 std::vector<geos::unique_ptr> testedGeometries;
1345 for (
int i = 0; i < numberOfGeometriesPolygon; i++ )
1347 const GEOSGeometry *polygon = GEOSGetGeometryN_r( context, polygons.get(), i );
1349 geos::unique_ptr
pointOnSurface( GEOSPointOnSurface_r( context, polygon ) );
1351 testedGeometries.emplace_back( GEOSGeom_clone_r( context, polygon ) );
1354 const size_t nGeometriesThis = numberOfGeometries( mGeos.get() );
1355 if ( testedGeometries.empty() || testedGeometries.size() == nGeometriesThis )
1365 mergeGeometriesMultiTypeSplit( testedGeometries );
1368 for ( i = 0; i < testedGeometries.size() && GEOSisValid_r( context, testedGeometries[i].get() ); ++i )
1371 if ( i < testedGeometries.size() )
1376 for ( geos::unique_ptr &testedGeometry : testedGeometries )
1386 if ( !splitLine || !geom )
1389 geos::unique_ptr geometryBoundary;
1391 if ( GEOSGeomTypeId_r( context, geom ) == GEOS_POLYGON || GEOSGeomTypeId_r( context, geom ) == GEOS_MULTIPOLYGON )
1392 geometryBoundary.reset( GEOSBoundary_r( context, geom ) );
1394 geometryBoundary.reset( GEOSGeom_clone_r( context, geom ) );
1396 geos::unique_ptr splitLineClone( GEOSGeom_clone_r( context, splitLine ) );
1397 geos::unique_ptr unionGeometry( GEOSUnion_r( context, splitLineClone.get(), geometryBoundary.get() ) );
1399 return unionGeometry;
1402int QgsGeos::mergeGeometriesMultiTypeSplit( std::vector<geos::unique_ptr> &splitResult )
const
1409 int type = GEOSGeomTypeId_r( context, mGeos.get() );
1410 if ( type != GEOS_GEOMETRYCOLLECTION &&
1411 type != GEOS_MULTILINESTRING &&
1412 type != GEOS_MULTIPOLYGON &&
1413 type != GEOS_MULTIPOINT )
1417 std::vector<geos::unique_ptr> unionGeom;
1419 std::vector<geos::unique_ptr> newSplitResult;
1421 for (
size_t i = 0; i < splitResult.size(); ++i )
1424 bool isPart =
false;
1425 for (
int j = 0; j < GEOSGetNumGeometries_r( context, mGeos.get() ); j++ )
1427 if ( GEOSEquals_r( context, splitResult[i].get(), GEOSGetGeometryN_r( context, mGeos.get(), j ) ) )
1436 unionGeom.emplace_back( std::move( splitResult[i] ) );
1440 std::vector<geos::unique_ptr> geomVector;
1441 geomVector.emplace_back( std::move( splitResult[i] ) );
1443 if ( type == GEOS_MULTILINESTRING )
1444 newSplitResult.emplace_back( createGeosCollection( GEOS_MULTILINESTRING, geomVector ) );
1445 else if ( type == GEOS_MULTIPOLYGON )
1446 newSplitResult.emplace_back( createGeosCollection( GEOS_MULTIPOLYGON, geomVector ) );
1450 splitResult = std::move( newSplitResult );
1453 if ( !unionGeom.empty() )
1455 if ( type == GEOS_MULTILINESTRING )
1456 splitResult.emplace_back( createGeosCollection( GEOS_MULTILINESTRING, unionGeom ) );
1457 else if ( type == GEOS_MULTIPOLYGON )
1458 splitResult.emplace_back( createGeosCollection( GEOS_MULTIPOLYGON, unionGeom ) );
1464geos::unique_ptr QgsGeos::createGeosCollection(
int typeId, std::vector<geos::unique_ptr> &geoms )
1466 std::vector<GEOSGeometry *> geomarr;
1467 geomarr.reserve( geoms.size() );
1470 for ( geos::unique_ptr &geomUniquePtr : geoms )
1472 if ( geomUniquePtr )
1474 if ( !GEOSisEmpty_r( context, geomUniquePtr.get() ) )
1478 geomarr.emplace_back( geomUniquePtr.release() );
1482 geos::unique_ptr geomRes;
1486 geomRes.reset( GEOSGeom_createCollection_r( context, typeId, geomarr.data(), geomarr.size() ) );
1488 catch ( GEOSException & )
1492 GEOSGeom_destroy_r( context, geom );
1507 int nCoordDims = GEOSGeom_getCoordinateDimension_r( context,
geos );
1508 int nDims = GEOSGeom_getDimensions_r( context,
geos );
1509 bool hasZ = ( nCoordDims == 3 );
1510 bool hasM = ( ( nDims - nCoordDims ) == 1 );
1512 switch ( GEOSGeomTypeId_r( context,
geos ) )
1516 if ( GEOSisEmpty_r( context,
geos ) )
1519 const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq_r( context,
geos );
1520 unsigned int nPoints = 0;
1521 GEOSCoordSeq_getSize_r( context, cs, &nPoints );
1522 return nPoints > 0 ? std::unique_ptr<QgsAbstractGeometry>(
coordSeqPoint( cs, 0, hasZ, hasM ).clone() ) :
nullptr;
1524 case GEOS_LINESTRING:
1526 return sequenceToLinestring(
geos, hasZ, hasM );
1532 case GEOS_MULTIPOINT:
1534 std::unique_ptr< QgsMultiPoint > multiPoint(
new QgsMultiPoint() );
1535 int nParts = GEOSGetNumGeometries_r( context,
geos );
1536 multiPoint->reserve( nParts );
1537 for (
int i = 0; i < nParts; ++i )
1539 const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq_r( context, GEOSGetGeometryN_r( context,
geos, i ) );
1542 unsigned int nPoints = 0;
1543 GEOSCoordSeq_getSize_r( context, cs, &nPoints );
1545 multiPoint->addGeometry(
coordSeqPoint( cs, 0, hasZ, hasM ).clone() );
1548 return std::move( multiPoint );
1550 case GEOS_MULTILINESTRING:
1553 int nParts = GEOSGetNumGeometries_r( context,
geos );
1554 multiLineString->reserve( nParts );
1555 for (
int i = 0; i < nParts; ++i )
1557 std::unique_ptr< QgsLineString >line( sequenceToLinestring( GEOSGetGeometryN_r( context,
geos, i ), hasZ, hasM ) );
1560 multiLineString->addGeometry( line.release() );
1563 return std::move( multiLineString );
1565 case GEOS_MULTIPOLYGON:
1567 std::unique_ptr< QgsMultiPolygon > multiPolygon(
new QgsMultiPolygon() );
1569 int nParts = GEOSGetNumGeometries_r( context,
geos );
1570 multiPolygon->reserve( nParts );
1571 for (
int i = 0; i < nParts; ++i )
1573 std::unique_ptr< QgsPolygon > poly =
fromGeosPolygon( GEOSGetGeometryN_r( context,
geos, i ) );
1576 multiPolygon->addGeometry( poly.release() );
1579 return std::move( multiPolygon );
1581 case GEOS_GEOMETRYCOLLECTION:
1584 int nParts = GEOSGetNumGeometries_r( context,
geos );
1585 geomCollection->reserve( nParts );
1586 for (
int i = 0; i < nParts; ++i )
1588 std::unique_ptr< QgsAbstractGeometry > geom(
fromGeos( GEOSGetGeometryN_r( context,
geos, i ) ) );
1591 geomCollection->addGeometry( geom.release() );
1594 return std::move( geomCollection );
1603 if ( GEOSGeomTypeId_r( context,
geos ) != GEOS_POLYGON )
1608 int nCoordDims = GEOSGeom_getCoordinateDimension_r( context,
geos );
1609 int nDims = GEOSGeom_getDimensions_r( context,
geos );
1610 bool hasZ = ( nCoordDims == 3 );
1611 bool hasM = ( ( nDims - nCoordDims ) == 1 );
1613 std::unique_ptr< QgsPolygon > polygon(
new QgsPolygon() );
1618 polygon->setExteriorRing( sequenceToLinestring( ring, hasZ, hasM ).release() );
1621 QVector<QgsCurve *> interiorRings;
1622 const int ringCount = GEOSGetNumInteriorRings_r( context,
geos );
1623 interiorRings.reserve( ringCount );
1624 for (
int i = 0; i < ringCount; ++i )
1626 ring = GEOSGetInteriorRingN_r( context,
geos, i );
1629 interiorRings.push_back( sequenceToLinestring( ring, hasZ, hasM ).release() );
1632 polygon->setInteriorRings( interiorRings );
1637std::unique_ptr<QgsLineString> QgsGeos::sequenceToLinestring(
const GEOSGeometry *
geos,
bool hasZ,
bool hasM )
1640 const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq_r( context,
geos );
1642 unsigned int nPoints;
1643 GEOSCoordSeq_getSize_r( context, cs, &nPoints );
1645 QVector< double > xOut( nPoints );
1646 QVector< double > yOut( nPoints );
1647 QVector< double > zOut;
1649 zOut.resize( nPoints );
1650 QVector< double > mOut;
1652 mOut.resize( nPoints );
1654 double *x = xOut.data();
1655 double *y = yOut.data();
1656 double *z = zOut.data();
1657 double *m = mOut.data();
1659#if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=10 )
1660 GEOSCoordSeq_copyToArrays_r( context, cs, x, y, hasZ ? z : nullptr, hasM ? m : nullptr );
1662 for (
unsigned int i = 0; i < nPoints; ++i )
1665 GEOSCoordSeq_getXYZ_r( context, cs, i, x++, y++, z++ );
1667 GEOSCoordSeq_getXY_r( context, cs, i, x++, y++ );
1670 GEOSCoordSeq_getOrdinate_r( context, cs, i, 3, m++ );
1674 std::unique_ptr< QgsLineString > line(
new QgsLineString( xOut, yOut, zOut, mOut ) );
1684 int geometryType = GEOSGeomTypeId_r( context, g );
1685 if ( geometryType == GEOS_POINT || geometryType == GEOS_LINESTRING || geometryType == GEOS_LINEARRING
1686 || geometryType == GEOS_POLYGON )
1690 return GEOSGetNumGeometries_r( context, g );
1706 GEOSCoordSeq_getXYZ_r( context, cs, i, &x, &y, &z );
1708 GEOSCoordSeq_getXY_r( context, cs, i, &x, &y );
1711 GEOSCoordSeq_getOrdinate_r( context, cs, i, 3, &m );
1747 int geosType = GEOS_GEOMETRYCOLLECTION;
1754 geosType = GEOS_MULTIPOINT;
1758 geosType = GEOS_MULTILINESTRING;
1762 geosType = GEOS_MULTIPOLYGON;
1777 std::vector<geos::unique_ptr> geomVector;
1778 geomVector.reserve(
c->numGeometries() );
1779 for (
int i = 0; i <
c->numGeometries(); ++i )
1782 if ( !allowInvalidSubGeom && !geosGeom )
1786 geomVector.emplace_back( std::move( geosGeom ) );
1788 return createGeosCollection( geosType, geomVector );
1795 return createGeosPoint(
static_cast<const QgsPoint *
>( geom ), coordDims,
precision );
1813 if ( !mGeos || !geom )
1818 geos::unique_ptr geosGeom(
asGeos( geom, mPrecision ) );
1824 const double gridSize = parameters.
gridSize();
1829 geos::unique_ptr opGeom;
1832 case OverlayIntersection:
1835 opGeom.reset( GEOSIntersectionPrec_r( context, mGeos.get(), geosGeom.get(), gridSize ) );
1839 opGeom.reset( GEOSIntersection_r( context, mGeos.get(), geosGeom.get() ) );
1843 case OverlayDifference:
1846 opGeom.reset( GEOSDifferencePrec_r( context, mGeos.get(), geosGeom.get(), gridSize ) );
1850 opGeom.reset( GEOSDifference_r( context, mGeos.get(), geosGeom.get() ) );
1856 geos::unique_ptr unionGeometry;
1859 unionGeometry.reset( GEOSUnionPrec_r( context, mGeos.get(), geosGeom.get(), gridSize ) );
1863 unionGeometry.reset( GEOSUnion_r( context, mGeos.get(), geosGeom.get() ) );
1866 if ( unionGeometry && GEOSGeomTypeId_r( context, unionGeometry.get() ) == GEOS_MULTILINESTRING )
1868 geos::unique_ptr mergedLines( GEOSLineMerge_r( context, unionGeometry.get() ) );
1871 unionGeometry = std::move( mergedLines );
1875 opGeom = std::move( unionGeometry );
1879 case OverlaySymDifference:
1882 opGeom.reset( GEOSSymDifferencePrec_r( context, mGeos.get(), geosGeom.get(), gridSize ) );
1886 opGeom.reset( GEOSSymDifference_r( context, mGeos.get(), geosGeom.get() ) );
1892 catch ( GEOSException &e )
1894 logError( QStringLiteral(
"GEOS" ), e.what() );
1897 *errorMsg = e.what();
1903bool QgsGeos::relation(
const QgsAbstractGeometry *geom, Relation r, QString *errorMsg )
const
1905 if ( !mGeos || !geom )
1910 geos::unique_ptr geosGeom(
asGeos( geom, mPrecision ) );
1917 bool result =
false;
1920 if ( mGeosPrepared )
1924 case RelationIntersects:
1925 result = ( GEOSPreparedIntersects_r( context, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1927 case RelationTouches:
1928 result = ( GEOSPreparedTouches_r( context, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1930 case RelationCrosses:
1931 result = ( GEOSPreparedCrosses_r( context, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1933 case RelationWithin:
1934 result = ( GEOSPreparedWithin_r( context, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1936 case RelationContains:
1937 result = ( GEOSPreparedContains_r( context, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1939 case RelationDisjoint:
1940 result = ( GEOSPreparedDisjoint_r( context, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1942 case RelationOverlaps:
1943 result = ( GEOSPreparedOverlaps_r( context, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1951 case RelationIntersects:
1952 result = ( GEOSIntersects_r( context, mGeos.get(), geosGeom.get() ) == 1 );
1954 case RelationTouches:
1955 result = ( GEOSTouches_r( context, mGeos.get(), geosGeom.get() ) == 1 );
1957 case RelationCrosses:
1958 result = ( GEOSCrosses_r( context, mGeos.get(), geosGeom.get() ) == 1 );
1960 case RelationWithin:
1961 result = ( GEOSWithin_r( context, mGeos.get(), geosGeom.get() ) == 1 );
1963 case RelationContains:
1964 result = ( GEOSContains_r( context, mGeos.get(), geosGeom.get() ) == 1 );
1966 case RelationDisjoint:
1967 result = ( GEOSDisjoint_r( context, mGeos.get(), geosGeom.get() ) == 1 );
1969 case RelationOverlaps:
1970 result = ( GEOSOverlaps_r( context, mGeos.get(), geosGeom.get() ) == 1 );
1974 catch ( GEOSException &e )
1976 logError( QStringLiteral(
"GEOS" ), e.what() );
1979 *errorMsg = e.what();
1994 geos::unique_ptr
geos;
2010 geos::unique_ptr
geos;
2013 geos.reset( GEOSBufferWithStyle_r(
QgsGeosContext::get(), mGeos.get(),
distance, segments,
static_cast< int >( endCapStyle ),
static_cast< int >( joinStyle ), miterLimit ) );
2025 geos::unique_ptr
geos;
2040 geos::unique_ptr
geos;
2056 geos::unique_ptr
geos;
2063 geos.reset( GEOSGetCentroid_r( context, mGeos.get() ) );
2068 GEOSGeomGetX_r( context,
geos.get(), &x );
2069 GEOSGeomGetY_r( context,
geos.get(), &y );
2082 geos::unique_ptr
geos;
2102 geos::unique_ptr
geos;
2105 geos.reset( GEOSPointOnSurface_r( context, mGeos.get() ) );
2107 if ( !
geos || GEOSisEmpty_r( context,
geos.get() ) != 0 )
2112 GEOSGeomGetX_r( context,
geos.get(), &x );
2113 GEOSGeomGetY_r( context,
geos.get(), &y );
2130 std::unique_ptr< QgsAbstractGeometry > cHullGeom =
fromGeos( cHull.get() );
2131 return cHullGeom.release();
2138#if GEOS_VERSION_MAJOR==3 && GEOS_VERSION_MINOR<11
2140 ( void )targetPercent;
2142 throw QgsNotSupportedException( QObject::tr(
"Calculating concaveHull requires a QGIS build based on GEOS 3.11 or later" ) );
2153 return concaveHullGeom.release();
2161#if GEOS_VERSION_MAJOR==3 && GEOS_VERSION_MINOR<12
2163 ( void )invalidEdges;
2165 throw QgsNotSupportedException( QObject::tr(
"Validating coverages requires a QGIS build based on GEOS 3.12 or later" ) );
2170 *errorMsg = QStringLiteral(
"Input geometry was not set" );
2178 const int result = GEOSCoverageIsValid_r( context, mGeos.get(), gapWidth, invalidEdges ? &invalidEdgesGeos : nullptr );
2179 if ( invalidEdges && invalidEdgesGeos )
2181 *invalidEdges =
fromGeos( invalidEdgesGeos );
2183 if ( invalidEdgesGeos )
2185 GEOSGeom_destroy_r( context, invalidEdgesGeos );
2186 invalidEdgesGeos =
nullptr;
2206#if GEOS_VERSION_MAJOR==3 && GEOS_VERSION_MINOR<12
2208 ( void )preserveBoundary;
2210 throw QgsNotSupportedException( QObject::tr(
"Simplifying coverages requires a QGIS build based on GEOS 3.12 or later" ) );
2215 *errorMsg = QStringLiteral(
"Input geometry was not set" );
2221 geos::unique_ptr simplified( GEOSCoverageSimplifyVW_r(
QgsGeosContext::get(), mGeos.get(), tolerance, preserveBoundary ? 1 : 0 ) );
2222 std::unique_ptr< QgsAbstractGeometry > simplifiedGeom =
fromGeos( simplified.get() );
2223 return simplifiedGeom;
2234 *errorMsg = QStringLiteral(
"Input geometry was not set" );
2241 std::unique_ptr< QgsAbstractGeometry > result =
fromGeos( unioned.get() );
2252 *errorMsg = QObject::tr(
"QGIS geometry cannot be converted to a GEOS geometry",
"GEOS Error" );
2261 char res = GEOSisValidDetail_r( context, mGeos.get(), allowSelfTouchingHoles ? GEOSVALID_ALLOW_SELFTOUCHING_RING_FORMING_HOLE : 0, &r, &g1 );
2262 const bool invalid = res != 1;
2267 error = QString( r );
2268 GEOSFree_r( context, r );
2271 if ( invalid && errorMsg )
2275 if ( translatedErrors.empty() )
2278 translatedErrors.insert( QStringLiteral(
"topology validation error" ), QObject::tr(
"Topology validation error",
"GEOS Error" ) );
2279 translatedErrors.insert( QStringLiteral(
"repeated point" ), QObject::tr(
"Repeated point",
"GEOS Error" ) );
2280 translatedErrors.insert( QStringLiteral(
"hole lies outside shell" ), QObject::tr(
"Hole lies outside shell",
"GEOS Error" ) );
2281 translatedErrors.insert( QStringLiteral(
"holes are nested" ), QObject::tr(
"Holes are nested",
"GEOS Error" ) );
2282 translatedErrors.insert( QStringLiteral(
"interior is disconnected" ), QObject::tr(
"Interior is disconnected",
"GEOS Error" ) );
2283 translatedErrors.insert( QStringLiteral(
"self-intersection" ), QObject::tr(
"Self-intersection",
"GEOS Error" ) );
2284 translatedErrors.insert( QStringLiteral(
"ring self-intersection" ), QObject::tr(
"Ring self-intersection",
"GEOS Error" ) );
2285 translatedErrors.insert( QStringLiteral(
"nested shells" ), QObject::tr(
"Nested shells",
"GEOS Error" ) );
2286 translatedErrors.insert( QStringLiteral(
"duplicate rings" ), QObject::tr(
"Duplicate rings",
"GEOS Error" ) );
2287 translatedErrors.insert( QStringLiteral(
"too few points in geometry component" ), QObject::tr(
"Too few points in geometry component",
"GEOS Error" ) );
2288 translatedErrors.insert( QStringLiteral(
"invalid coordinate" ), QObject::tr(
"Invalid coordinate",
"GEOS Error" ) );
2289 translatedErrors.insert( QStringLiteral(
"ring is not closed" ), QObject::tr(
"Ring is not closed",
"GEOS Error" ) );
2292 *errorMsg = translatedErrors.value( error.toLower(), error );
2294 if ( g1 && errorLoc )
2300 GEOSGeom_destroy_r( context, g1 );
2310 if ( !mGeos || !geom )
2317 geos::unique_ptr geosGeom(
asGeos( geom, mPrecision ) );
2356GEOSCoordSequence *QgsGeos::createCoordinateSequence(
const QgsCurve *curve,
double precision,
bool forceClose )
2360 std::unique_ptr< QgsLineString > segmentized;
2361 const QgsLineString *line = qgsgeometry_cast<const QgsLineString *>( curve );
2366 line = segmentized.get();
2373 GEOSCoordSequence *coordSeq =
nullptr;
2375 const int numPoints = line->
numPoints();
2377 const bool hasZ = line->
is3D();
2379#if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=10 )
2382 if ( !forceClose || ( line->
pointN( 0 ) == line->
pointN( numPoints - 1 ) ) )
2387 coordSeq = GEOSCoordSeq_copyFromArrays_r( context, line->
xData(), line->
yData(), line->
zData(),
nullptr, numPoints );
2390 QgsDebugError( QStringLiteral(
"GEOS Exception: Could not create coordinate sequence for %1 points" ).arg( numPoints ) );
2398 QVector< double > x = line->
xVector();
2399 if ( numPoints > 0 )
2400 x.append( x.at( 0 ) );
2401 QVector< double > y = line->
yVector();
2402 if ( numPoints > 0 )
2403 y.append( y.at( 0 ) );
2404 QVector< double > z = line->
zVector();
2405 if ( hasZ && numPoints > 0 )
2406 z.append( z.at( 0 ) );
2409 coordSeq = GEOSCoordSeq_copyFromArrays_r( context, x.constData(), y.constData(), !hasZ ?
nullptr : z.constData(), nullptr, numPoints + 1 );
2412 QgsDebugError( QStringLiteral(
"GEOS Exception: Could not create closed coordinate sequence for %1 points" ).arg( numPoints + 1 ) );
2423 const bool hasM =
false;
2434 int numOutPoints = numPoints;
2435 if ( forceClose && ( line->
pointN( 0 ) != line->
pointN( numPoints - 1 ) ) )
2442 coordSeq = GEOSCoordSeq_create_r( context, numOutPoints, coordDims );
2445 QgsDebugError( QStringLiteral(
"GEOS Exception: Could not create coordinate sequence for %1 points in %2 dimensions" ).arg( numPoints ).arg( coordDims ) );
2449 const double *xData = line->
xData();
2450 const double *yData = line->
yData();
2451 const double *zData = hasZ ? line->
zData() :
nullptr;
2452 const double *mData = hasM ? line->
mData() :
nullptr;
2456 for (
int i = 0; i < numOutPoints; ++i )
2458 if ( i >= numPoints )
2461 xData = line->
xData();
2462 yData = line->
yData();
2463 zData = hasZ ? line->
zData() :
nullptr;
2464 mData = hasM ? line->
mData() :
nullptr;
2476 GEOSCoordSeq_setOrdinate_r( context, coordSeq, i, 3, *mData++ );
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;
2494 GEOSCoordSeq_setXYZ_r( context, coordSeq, i, *xData++, *yData++, *zData++ );
2498 GEOSCoordSeq_setXY_r( context, coordSeq, i, *xData++, *yData++ );
2502 GEOSCoordSeq_setOrdinate_r( context, coordSeq, i, 3, *mData++ );
2514 const QgsPoint *pt = qgsgeometry_cast<const QgsPoint *>( point );
2521geos::unique_ptr QgsGeos::createGeosPointXY(
double x,
double y,
bool hasZ,
double z,
bool hasM,
double m,
int coordDims,
double precision )
2526 geos::unique_ptr geosPoint;
2530 if ( coordDims == 2 )
2536 geosPoint.reset( GEOSGeom_createPointFromXY_r( context, x, y ) );
2540 GEOSCoordSequence *coordSeq = GEOSCoordSeq_create_r( context, 1, coordDims );
2543 QgsDebugError( QStringLiteral(
"GEOS Exception: Could not create coordinate sequence for point with %1 dimensions" ).arg( coordDims ) );
2548 GEOSCoordSeq_setX_r( context, coordSeq, 0, std::round( x /
precision ) *
precision );
2549 GEOSCoordSeq_setY_r( context, coordSeq, 0, std::round( y /
precision ) *
precision );
2552 GEOSCoordSeq_setOrdinate_r( context, coordSeq, 0, 2, std::round( z /
precision ) *
precision );
2557 GEOSCoordSeq_setX_r( context, coordSeq, 0, x );
2558 GEOSCoordSeq_setY_r( context, coordSeq, 0, y );
2561 GEOSCoordSeq_setOrdinate_r( context, coordSeq, 0, 2, z );
2567 GEOSCoordSeq_setOrdinate_r( context, coordSeq, 0, 3, m );
2570 geosPoint.reset( GEOSGeom_createPoint_r( context, coordSeq ) );
2578 const QgsCurve *
c = qgsgeometry_cast<const QgsCurve *>( curve );
2582 GEOSCoordSequence *coordSeq = createCoordinateSequence(
c,
precision );
2586 geos::unique_ptr geosGeom;
2597 const QgsCurvePolygon *polygon = qgsgeometry_cast<const QgsCurvePolygon *>( poly );
2602 if ( !exteriorRing )
2608 geos::unique_ptr geosPolygon;
2611 geos::unique_ptr exteriorRingGeos( GEOSGeom_createLinearRing_r( context, createCoordinateSequence( exteriorRing,
precision,
true ) ) );
2620 for (
int i = 0; i < nHoles; ++i )
2623 holes[i] = GEOSGeom_createLinearRing_r( context, createCoordinateSequence( interiorRing,
precision,
true ) );
2625 geosPolygon.reset( GEOSGeom_createPolygon_r( context, exteriorRingGeos.release(), holes, nHoles ) );
2638 geos::unique_ptr offset;
2645 offset.reset( GEOSOffsetCurve_r(
QgsGeosContext::get(), mGeos.get(),
distance, segments,
static_cast< int >( joinStyle ), miterLimit ) );
2648 std::unique_ptr< QgsAbstractGeometry > offsetGeom =
fromGeos( offset.get() );
2649 return offsetGeom.release();
2659 geos::unique_ptr
geos;
2663 geos::buffer_params_unique_ptr bp( GEOSBufferParams_create_r( context ) );
2664 GEOSBufferParams_setSingleSided_r( context, bp.get(), 1 );
2665 GEOSBufferParams_setQuadrantSegments_r( context, bp.get(), segments );
2666 GEOSBufferParams_setJoinStyle_r( context, bp.get(),
static_cast< int >( joinStyle ) );
2667 GEOSBufferParams_setMitreLimit_r( context, bp.get(), miterLimit );
2673 geos.reset( GEOSBufferWithParams_r( context, mGeos.get(), bp.get(),
distance ) );
2686 geos::unique_ptr
geos;
2702 geos::unique_ptr
geos;
2705 geos::unique_ptr boundaryGeos;
2707 boundaryGeos =
asGeos( boundary );
2722 geos::unique_ptr
geos;
2735 return std::numeric_limits< double >::quiet_NaN();
2738 geos::unique_ptr
geos;
2743 return std::numeric_limits< double >::quiet_NaN();
2756 geos::unique_ptr
geos;
2772 geos::unique_ptr
geos;
2783 if ( !mGeos || !other )
2788 geos::unique_ptr
geos;
2791 geos::unique_ptr otherGeos =
asGeos( other );
2815 geos::unique_ptr reshapeLineGeos = createGeosLinestring( &reshapeWithLine, mPrecision );
2819 int numGeoms = GEOSGetNumGeometries_r( context, mGeos.get() );
2820 if ( numGeoms == -1 )
2829 bool isMultiGeom =
false;
2830 int geosTypeId = GEOSGeomTypeId_r( context, mGeos.get() );
2831 if ( geosTypeId == GEOS_MULTILINESTRING || geosTypeId == GEOS_MULTIPOLYGON )
2838 geos::unique_ptr reshapedGeometry;
2841 reshapedGeometry = reshapeLine( mGeos.get(), reshapeLineGeos.get(), mPrecision );
2845 reshapedGeometry = reshapePolygon( mGeos.get(), reshapeLineGeos.get(), mPrecision );
2850 std::unique_ptr< QgsAbstractGeometry > reshapeResult =
fromGeos( reshapedGeometry.get() );
2851 return reshapeResult;
2858 bool reshapeTookPlace =
false;
2860 geos::unique_ptr currentReshapeGeometry;
2863 for (
int i = 0; i < numGeoms; ++i )
2866 currentReshapeGeometry = reshapeLine( GEOSGetGeometryN_r( context, mGeos.get(), i ), reshapeLineGeos.get(), mPrecision );
2868 currentReshapeGeometry = reshapePolygon( GEOSGetGeometryN_r( context, mGeos.get(), i ), reshapeLineGeos.get(), mPrecision );
2870 if ( currentReshapeGeometry )
2872 newGeoms[i] = currentReshapeGeometry.release();
2873 reshapeTookPlace =
true;
2877 newGeoms[i] = GEOSGeom_clone_r( context, GEOSGetGeometryN_r( context, mGeos.get(), i ) );
2881 geos::unique_ptr newMultiGeom;
2884 newMultiGeom.reset( GEOSGeom_createCollection_r( context, GEOS_MULTILINESTRING, newGeoms, numGeoms ) );
2888 newMultiGeom.reset( GEOSGeom_createCollection_r( context, GEOS_MULTIPOLYGON, newGeoms, numGeoms ) );
2892 if ( !newMultiGeom )
2898 if ( reshapeTookPlace )
2902 std::unique_ptr< QgsAbstractGeometry > reshapedMultiGeom =
fromGeos( newMultiGeom.get() );
2903 return reshapedMultiGeom;
2926 if ( GEOSGeomTypeId_r( context, mGeos.get() ) != GEOS_MULTILINESTRING )
2929 geos::unique_ptr
geos;
2932 geos.reset( GEOSLineMerge_r( context, mGeos.get() ) );
2945 geos::unique_ptr otherGeom(
asGeos( other.
constGet(), mPrecision ) );
2956 geos::coord_sequence_unique_ptr nearestCoord;
2957 if ( mGeosPrepared )
2959 nearestCoord.reset( GEOSPreparedNearestPoints_r( context, mGeosPrepared.get(), otherGeom.get() ) );
2963 nearestCoord.reset( GEOSNearestPoints_r( context, mGeos.get(), otherGeom.get() ) );
2966 ( void )GEOSCoordSeq_getX_r( context, nearestCoord.get(), 0, &nx );
2967 ( void )GEOSCoordSeq_getY_r( context, nearestCoord.get(), 0, &ny );
2969 catch ( GEOSException &e )
2971 logError( QStringLiteral(
"GEOS" ), e.what() );
2974 *errorMsg = e.what();
2984 if ( !mGeos || other.
isEmpty() )
2994 if ( !other || other->
isEmpty() )
2997 geos::unique_ptr otherGeom(
asGeos( other, mPrecision ) );
3010 geos::coord_sequence_unique_ptr nearestCoord( GEOSNearestPoints_r( context, mGeos.get(), otherGeom.get() ) );
3012 if ( !nearestCoord )
3015 *errorMsg = QStringLiteral(
"GEOS returned no nearest points" );
3019 ( void )GEOSCoordSeq_getX_r( context, nearestCoord.get(), 0, &nx1 );
3020 ( void )GEOSCoordSeq_getY_r( context, nearestCoord.get(), 0, &ny1 );
3021 ( void )GEOSCoordSeq_getX_r( context, nearestCoord.get(), 1, &nx2 );
3022 ( void )GEOSCoordSeq_getY_r( context, nearestCoord.get(), 1, &ny2 );
3024 catch ( GEOSException &e )
3026 logError( QStringLiteral(
"GEOS" ), e.what() );
3029 *errorMsg = e.what();
3047 geos::unique_ptr otherGeom(
asGeos( &point, mPrecision ) );
3058 catch ( GEOSException &e )
3060 logError( QStringLiteral(
"GEOS" ), e.what() );
3063 *errorMsg = e.what();
3078 geos::unique_ptr point = createGeosPointXY( x, y,
false, 0,
false, 0, 2, 0 );
3087 catch ( GEOSException &e )
3089 logError( QStringLiteral(
"GEOS" ), e.what() );
3092 *errorMsg = e.what();
3106 geos::unique_ptr l =
asGeos( g );
3109 lineGeosGeometries[validLines] = l.release();
3117 geos::unique_ptr result( GEOSPolygonize_r( context, lineGeosGeometries, validLines ) );
3118 for (
int i = 0; i < validLines; ++i )
3120 GEOSGeom_destroy_r( context, lineGeosGeometries[i] );
3122 delete[] lineGeosGeometries;
3125 catch ( GEOSException &e )
3129 *errorMsg = e.what();
3131 for (
int i = 0; i < validLines; ++i )
3133 GEOSGeom_destroy_r( context, lineGeosGeometries[i] );
3135 delete[] lineGeosGeometries;
3147 geos::unique_ptr extentGeosGeom;
3150 extentGeosGeom =
asGeos( extent, mPrecision );
3151 if ( !extentGeosGeom )
3157 geos::unique_ptr
geos;
3161 geos.reset( GEOSVoronoiDiagram_r( context, mGeos.get(), extentGeosGeom.get(), tolerance, edgesOnly ) );
3163 if ( !
geos || GEOSisEmpty_r( context,
geos.get() ) != 0 )
3181 geos::unique_ptr
geos;
3184 geos.reset( GEOSDelaunayTriangulation_r( context, mGeos.get(), tolerance, edgesOnly ) );
3186 if ( !
geos || GEOSisEmpty_r( context,
geos.get() ) != 0 )
3198#if GEOS_VERSION_MAJOR==3 && GEOS_VERSION_MINOR<11
3200 throw QgsNotSupportedException( QObject::tr(
"Calculating constrainedDelaunayTriangulation requires a QGIS build based on GEOS 3.11 or later" ) );
3207 geos::unique_ptr
geos;
3211 geos.reset( GEOSConstrainedDelaunayTriangulation_r( context, mGeos.get() ) );
3213 if ( !
geos || GEOSisEmpty_r( context,
geos.get() ) != 0 )
3218 std::unique_ptr< QgsAbstractGeometry > res =
fromGeos(
geos.get() );
3219 if (
const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( res.get() ) )
3221 return std::unique_ptr< QgsAbstractGeometry >( collection->extractPartsByType(
Qgis::WkbType::Polygon,
true ) );
3233static bool _linestringEndpoints(
const GEOSGeometry *linestring,
double &x1,
double &y1,
double &x2,
double &y2 )
3236 const GEOSCoordSequence *coordSeq = GEOSGeom_getCoordSeq_r( context, linestring );
3240 unsigned int coordSeqSize;
3241 if ( GEOSCoordSeq_getSize_r( context, coordSeq, &coordSeqSize ) == 0 )
3244 if ( coordSeqSize < 2 )
3247 GEOSCoordSeq_getX_r( context, coordSeq, 0, &x1 );
3248 GEOSCoordSeq_getY_r( context, coordSeq, 0, &y1 );
3249 GEOSCoordSeq_getX_r( context, coordSeq, coordSeqSize - 1, &x2 );
3250 GEOSCoordSeq_getY_r( context, coordSeq, coordSeqSize - 1, &y2 );
3258 double x1, y1, x2, y2;
3259 if ( !_linestringEndpoints( line1, x1, y1, x2, y2 ) )
3262 double rx1, ry1, rx2, ry2;
3263 if ( !_linestringEndpoints( line2, rx1, ry1, rx2, ry2 ) )
3266 bool intersectionAtOrigLineEndpoint =
3267 ( intersectionPoint.
x() == x1 && intersectionPoint.
y() == y1 ) !=
3268 ( intersectionPoint.
x() == x2 && intersectionPoint.
y() == y2 );
3269 bool intersectionAtReshapeLineEndpoint =
3270 ( intersectionPoint.
x() == rx1 && intersectionPoint.
y() == ry1 ) ||
3271 ( intersectionPoint.
x() == rx2 && intersectionPoint.
y() == ry2 );
3275 if ( intersectionAtOrigLineEndpoint && intersectionAtReshapeLineEndpoint )
3277 geos::unique_ptr g1( GEOSGeom_clone_r( context, line1 ) );
3278 geos::unique_ptr g2( GEOSGeom_clone_r( context, line2 ) );
3279 GEOSGeometry *geoms[2] = { g1.release(), g2.release() };
3280 geos::unique_ptr multiGeom( GEOSGeom_createCollection_r( context, GEOS_MULTILINESTRING, geoms, 2 ) );
3281 geos::unique_ptr res( GEOSLineMerge_r( context, multiGeom.get() ) );
3291 if ( !line || !reshapeLineGeos )
3294 bool atLeastTwoIntersections =
false;
3295 bool oneIntersection =
false;
3302 geos::unique_ptr intersectGeom( GEOSIntersection_r( context, line, reshapeLineGeos ) );
3303 if ( intersectGeom )
3305 const int geomType = GEOSGeomTypeId_r( context, intersectGeom.get() );
3306 atLeastTwoIntersections = ( geomType == GEOS_MULTIPOINT && GEOSGetNumGeometries_r( context, intersectGeom.get() ) > 1 )
3307 || ( geomType == GEOS_GEOMETRYCOLLECTION && GEOSGetNumGeometries_r( context, intersectGeom.get() ) > 0 )
3308 || ( geomType == GEOS_MULTILINESTRING && GEOSGetNumGeometries_r( context, intersectGeom.get() ) > 0 );
3310 if ( GEOSGeomTypeId_r( context, intersectGeom.get() ) == GEOS_POINT )
3312 const GEOSCoordSequence *intersectionCoordSeq = GEOSGeom_getCoordSeq_r( context, intersectGeom.get() );
3314 GEOSCoordSeq_getX_r( context, intersectionCoordSeq, 0, &xi );
3315 GEOSCoordSeq_getY_r( context, intersectionCoordSeq, 0, &yi );
3316 oneIntersection =
true;
3321 catch ( GEOSException & )
3323 atLeastTwoIntersections =
false;
3327 if ( oneIntersection )
3328 return _mergeLinestrings( line, reshapeLineGeos, oneIntersectionPoint );
3330 if ( !atLeastTwoIntersections )
3334 double x1, y1, x2, y2;
3335 if ( !_linestringEndpoints( line, x1, y1, x2, y2 ) )
3338 geos::unique_ptr beginLineVertex = createGeosPointXY( x1, y1,
false, 0,
false, 0, 2,
precision );
3339 geos::unique_ptr endLineVertex = createGeosPointXY( x2, y2,
false, 0,
false, 0, 2,
precision );
3341 bool isRing =
false;
3342 if ( GEOSGeomTypeId_r( context, line ) == GEOS_LINEARRING
3343 || GEOSEquals_r( context, beginLineVertex.get(), endLineVertex.get() ) == 1 )
3347 geos::unique_ptr nodedGeometry = nodeGeometries( reshapeLineGeos, line );
3348 if ( !nodedGeometry )
3354 geos::unique_ptr mergedLines( GEOSLineMerge_r( context, nodedGeometry.get() ) );
3360 int numMergedLines = GEOSGetNumGeometries_r( context, mergedLines.get() );
3361 if ( numMergedLines < 2 )
3363 if ( numMergedLines == 1 )
3365 geos::unique_ptr result( GEOSGeom_clone_r( context, reshapeLineGeos ) );
3372 QVector<GEOSGeometry *> resultLineParts;
3373 QVector<GEOSGeometry *> probableParts;
3375 for (
int i = 0; i < numMergedLines; ++i )
3377 const GEOSGeometry *currentGeom = GEOSGetGeometryN_r( context, mergedLines.get(), i );
3380 bool alreadyAdded =
false;
3382 double bufferDistance = std::pow( 10.0L, geomDigits( currentGeom ) - 11 );
3383 for (
const GEOSGeometry *other : std::as_const( resultLineParts ) )
3385 GEOSHausdorffDistance_r( context, currentGeom, other, &
distance );
3388 alreadyAdded =
true;
3395 const GEOSCoordSequence *currentCoordSeq = GEOSGeom_getCoordSeq_r( context, currentGeom );
3396 unsigned int currentCoordSeqSize;
3397 GEOSCoordSeq_getSize_r( context, currentCoordSeq, ¤tCoordSeqSize );
3398 if ( currentCoordSeqSize < 2 )
3402 double xBegin, xEnd, yBegin, yEnd;
3403 GEOSCoordSeq_getX_r( context, currentCoordSeq, 0, &xBegin );
3404 GEOSCoordSeq_getY_r( context, currentCoordSeq, 0, &yBegin );
3405 GEOSCoordSeq_getX_r( context, currentCoordSeq, currentCoordSeqSize - 1, &xEnd );
3406 GEOSCoordSeq_getY_r( context, currentCoordSeq, currentCoordSeqSize - 1, &yEnd );
3407 geos::unique_ptr beginCurrentGeomVertex = createGeosPointXY( xBegin, yBegin,
false, 0,
false, 0, 2,
precision );
3408 geos::unique_ptr endCurrentGeomVertex = createGeosPointXY( xEnd, yEnd,
false, 0,
false, 0, 2,
precision );
3411 int nEndpointsOnOriginalLine = 0;
3412 if ( pointContainedInLine( beginCurrentGeomVertex.get(), line ) == 1 )
3413 nEndpointsOnOriginalLine += 1;
3415 if ( pointContainedInLine( endCurrentGeomVertex.get(), line ) == 1 )
3416 nEndpointsOnOriginalLine += 1;
3419 int nEndpointsSameAsOriginalLine = 0;
3420 if ( GEOSEquals_r( context, beginCurrentGeomVertex.get(), beginLineVertex.get() ) == 1
3421 || GEOSEquals_r( context, beginCurrentGeomVertex.get(), endLineVertex.get() ) == 1 )
3422 nEndpointsSameAsOriginalLine += 1;
3424 if ( GEOSEquals_r( context, endCurrentGeomVertex.get(), beginLineVertex.get() ) == 1
3425 || GEOSEquals_r( context, endCurrentGeomVertex.get(), endLineVertex.get() ) == 1 )
3426 nEndpointsSameAsOriginalLine += 1;
3429 bool currentGeomOverlapsOriginalGeom =
false;
3430 bool currentGeomOverlapsReshapeLine =
false;
3431 if ( lineContainedInLine( currentGeom, line ) == 1 )
3432 currentGeomOverlapsOriginalGeom =
true;
3434 if ( lineContainedInLine( currentGeom, reshapeLineGeos ) == 1 )
3435 currentGeomOverlapsReshapeLine =
true;
3438 if ( !isRing && nEndpointsSameAsOriginalLine == 1 && nEndpointsOnOriginalLine == 2 && currentGeomOverlapsOriginalGeom )
3440 resultLineParts.push_back( GEOSGeom_clone_r( context, currentGeom ) );
3443 else if ( isRing && nEndpointsOnOriginalLine == 2 && currentGeomOverlapsOriginalGeom )
3445 probableParts.push_back( GEOSGeom_clone_r( context, currentGeom ) );
3447 else if ( nEndpointsOnOriginalLine == 2 && !currentGeomOverlapsOriginalGeom )
3449 resultLineParts.push_back( GEOSGeom_clone_r( context, currentGeom ) );
3451 else if ( nEndpointsSameAsOriginalLine == 2 && !currentGeomOverlapsOriginalGeom )
3453 resultLineParts.push_back( GEOSGeom_clone_r( context, currentGeom ) );
3455 else if ( currentGeomOverlapsOriginalGeom && currentGeomOverlapsReshapeLine )
3457 resultLineParts.push_back( GEOSGeom_clone_r( context, currentGeom ) );
3462 if ( isRing && !probableParts.isEmpty() )
3464 geos::unique_ptr maxGeom;
3466 double maxLength = -std::numeric_limits<double>::max();
3467 double currentLength = 0;
3468 for (
int i = 0; i < probableParts.size(); ++i )
3470 currentGeom = probableParts.at( i );
3471 GEOSLength_r( context, currentGeom, ¤tLength );
3472 if ( currentLength > maxLength )
3474 maxLength = currentLength;
3475 maxGeom.reset( currentGeom );
3479 GEOSGeom_destroy_r( context, currentGeom );
3482 resultLineParts.push_back( maxGeom.release() );
3485 geos::unique_ptr result;
3486 if ( resultLineParts.empty() )
3489 if ( resultLineParts.size() == 1 )
3491 result.reset( resultLineParts[0] );
3496 for (
int i = 0; i < resultLineParts.size(); ++i )
3498 lineArray[i] = resultLineParts[i];
3502 geos::unique_ptr multiLineGeom( GEOSGeom_createCollection_r( context, GEOS_MULTILINESTRING, lineArray, resultLineParts.size() ) );
3503 delete [] lineArray;
3506 result.reset( GEOSLineMerge_r( context, multiLineGeom.get() ) );
3510 if ( GEOSGeomTypeId_r( context, result.get() ) != GEOS_LINESTRING )
3521 int nIntersections = 0;
3522 int lastIntersectingRing = -2;
3526 int nRings = GEOSGetNumInteriorRings_r( context, polygon );
3531 const GEOSGeometry *outerRing = GEOSGetExteriorRing_r( context, polygon );
3532 if ( GEOSIntersects_r( context, outerRing, reshapeLineGeos ) == 1 )
3535 lastIntersectingRing = -1;
3536 lastIntersectingGeom = outerRing;
3544 for (
int i = 0; i < nRings; ++i )
3546 innerRings[i] = GEOSGetInteriorRingN_r( context, polygon, i );
3547 if ( GEOSIntersects_r( context, innerRings[i], reshapeLineGeos ) == 1 )
3550 lastIntersectingRing = i;
3551 lastIntersectingGeom = innerRings[i];
3555 catch ( GEOSException & )
3560 if ( nIntersections != 1 )
3562 delete [] innerRings;
3567 geos::unique_ptr reshapeResult = reshapeLine( lastIntersectingGeom, reshapeLineGeos,
precision );
3568 if ( !reshapeResult )
3570 delete [] innerRings;
3576 const GEOSCoordSequence *reshapeSequence = GEOSGeom_getCoordSeq_r( context, reshapeResult.get() );
3577 GEOSCoordSequence *newCoordSequence = GEOSCoordSeq_clone_r( context, reshapeSequence );
3579 reshapeResult.reset();
3581 newRing = GEOSGeom_createLinearRing_r( context, newCoordSequence );
3584 delete [] innerRings;
3589 if ( lastIntersectingRing == -1 )
3590 newOuterRing = newRing;
3592 newOuterRing = GEOSGeom_clone_r( context, outerRing );
3595 QVector<GEOSGeometry *> ringList;
3598 GEOSGeometry *outerRingPoly = GEOSGeom_createPolygon_r( context, GEOSGeom_clone_r( context, newOuterRing ),
nullptr, 0 );
3599 if ( outerRingPoly )
3601 ringList.reserve( nRings );
3603 for (
int i = 0; i < nRings; ++i )
3605 if ( lastIntersectingRing == i )
3606 currentRing = newRing;
3608 currentRing = GEOSGeom_clone_r( context, innerRings[i] );
3611 if ( GEOSContains_r( context, outerRingPoly, currentRing ) == 1 )
3612 ringList.push_back( currentRing );
3614 GEOSGeom_destroy_r( context, currentRing );
3617 GEOSGeom_destroy_r( context, outerRingPoly );
3621 for (
int i = 0; i < ringList.size(); ++i )
3622 newInnerRings[i] = ringList.at( i );
3624 delete [] innerRings;
3626 geos::unique_ptr reshapedPolygon( GEOSGeom_createPolygon_r( context, newOuterRing, newInnerRings, ringList.size() ) );
3627 delete[] newInnerRings;
3629 return reshapedPolygon;
3634 if ( !line1 || !line2 )
3639 double bufferDistance = std::pow( 10.0L, geomDigits( line2 ) - 11 );
3646 geos::unique_ptr intersectionGeom( GEOSIntersection_r( context, bufferGeom.get(), line1 ) );
3649 double intersectGeomLength;
3652 GEOSLength_r( context, intersectionGeom.get(), &intersectGeomLength );
3653 GEOSLength_r( context, line1, &line1Length );
3655 double intersectRatio = line1Length / intersectGeomLength;
3656 if ( intersectRatio > 0.9 && intersectRatio < 1.1 )
3664 if ( !point || !line )
3667 double bufferDistance = std::pow( 10.0L, geomDigits( line ) - 11 );
3670 geos::unique_ptr lineBuffer( GEOSBuffer_r( context, line, bufferDistance, 8 ) );
3674 bool contained =
false;
3675 if ( GEOSContains_r( context, lineBuffer.get(), point ) == 1 )
3684 geos::unique_ptr bbox( GEOSEnvelope_r( context, geom ) );
3688 const GEOSGeometry *bBoxRing = GEOSGetExteriorRing_r( context, bbox.get() );
3692 const GEOSCoordSequence *bBoxCoordSeq = GEOSGeom_getCoordSeq_r( context, bBoxRing );
3694 if ( !bBoxCoordSeq )
3697 unsigned int nCoords = 0;
3698 if ( !GEOSCoordSeq_getSize_r( context, bBoxCoordSeq, &nCoords ) )
3702 for (
unsigned int i = 0; i < nCoords - 1; ++i )
3705 GEOSCoordSeq_getX_r( context, bBoxCoordSeq, i, &t );
3708 digits = std::ceil( std::log10( std::fabs( t ) ) );
3709 if ( digits > maxDigits )
3712 GEOSCoordSeq_getY_r( context, bBoxCoordSeq, i, &t );
3713 digits = std::ceil( std::log10( std::fabs( t ) ) );
3714 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.
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.
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.
static geos::unique_ptr asGeos(const QgsGeometry &geometry, double precision=0)
Returns a geos geometry - caller takes ownership of the object (should be deleted with GEOSGeom_destr...
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.
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).
QgsGeos(const QgsAbstractGeometry *geometry, double precision=0, bool allowInvalidSubGeom=true)
GEOS geometry engine constructor.
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...
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.
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)
QMap< QString, QString > QgsStringMap
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