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 );
100 GEOSContextHandle_t ctxt;
104 ctxt = initGEOS_r( printGEOSNotice, throwGEOSException );
109 finishGEOS_r( ctxt );
112 GEOSInit(
const GEOSInit &rh ) =
delete;
113 GEOSInit &operator=(
const GEOSInit &rh ) =
delete;
120 GEOSGeom_destroy_r( geosinit()->ctxt, geom );
125 GEOSPreparedGeom_destroy_r( geosinit()->ctxt, geom );
130 GEOSBufferParams_destroy_r( geosinit()->ctxt, params );
135 GEOSCoordSeq_destroy_r( geosinit()->ctxt, sequence );
170#if GEOS_VERSION_MAJOR==3 && GEOS_VERSION_MINOR<10
172 throw QgsNotSupportedException( QObject::tr(
"The structured method to make geometries valid requires a QGIS build based on GEOS 3.10 or later" ) );
175 throw QgsNotSupportedException( QObject::tr(
"The keep collapsed option for making geometries valid requires a QGIS build based on GEOS 3.10 or later" ) );
179 geos.reset( GEOSMakeValid_r( geosinit()->ctxt, mGeos.get() ) );
184 GEOSMakeValidParams *params = GEOSMakeValidParams_create_r( geosinit()->ctxt );
188 GEOSMakeValidParams_setMethod_r( geosinit()->ctxt, params, GEOS_MAKE_VALID_LINEWORK );
192 GEOSMakeValidParams_setMethod_r( geosinit()->ctxt, params, GEOS_MAKE_VALID_STRUCTURE );
196 GEOSMakeValidParams_setKeepCollapsed_r( geosinit()->ctxt,
198 keepCollapsed ? 1 : 0 );
203 geos.reset( GEOSMakeValidWithParams_r( geosinit()->ctxt, mGeos.get(), params ) );
204 GEOSMakeValidParams_destroy_r( geosinit()->ctxt, params );
206 catch ( GEOSException &e )
210 *errorMsg = e.what();
212 GEOSMakeValidParams_destroy_r( geosinit()->ctxt, params );
241 std::unique_ptr< QgsAbstractGeometry > geom =
fromGeos( newPart );
248 mGeosPrepared.reset();
261 mGeosPrepared.reset( GEOSPrepare_r( geosinit()->ctxt, mGeos.get() ) );
265void QgsGeos::cacheGeos()
const
282 return overlay( geom, OverlayIntersection, errorMsg, parameters ).release();
287 return overlay( geom, OverlayDifference, errorMsg, parameters ).release();
302 catch ( GEOSException &e )
304 logError( QStringLiteral(
"GEOS" ), e.what() );
307 *errorMsg = e.what();
316void QgsGeos::subdivideRecursive(
const GEOSGeometry *currentPart,
int maxNodes,
int depth,
QgsGeometryCollection *parts,
const QgsRectangle &clipRect,
double gridSize )
const
318 int partType = GEOSGeomTypeId_r( geosinit()->ctxt, currentPart );
321 if ( partType == GEOS_POINT )
332 if ( partType == GEOS_MULTILINESTRING || partType == GEOS_MULTIPOLYGON || partType == GEOS_GEOMETRYCOLLECTION )
334 int partCount = GEOSGetNumGeometries_r( geosinit()->ctxt, currentPart );
335 for (
int i = 0; i < partCount; ++i )
337 subdivideRecursive( GEOSGetGeometryN_r( geosinit()->ctxt, currentPart, i ), maxNodes, depth, parts, clipRect, gridSize );
348 int vertexCount = GEOSGetNumCoordinates_r( geosinit()->ctxt, currentPart );
349 if ( vertexCount == 0 )
353 else if ( vertexCount < maxNodes )
360 double width = clipRect.
width();
361 double height = clipRect.
height();
364 if ( width > height )
377 halfClipRect1.
setYMinimum( halfClipRect1.
yMinimum() - std::numeric_limits<double>::epsilon() );
378 halfClipRect2.
setYMinimum( halfClipRect2.
yMinimum() - std::numeric_limits<double>::epsilon() );
379 halfClipRect1.
setYMaximum( halfClipRect1.
yMaximum() + std::numeric_limits<double>::epsilon() );
380 halfClipRect2.
setYMaximum( halfClipRect2.
yMaximum() + std::numeric_limits<double>::epsilon() );
384 halfClipRect1.
setXMinimum( halfClipRect1.
xMinimum() - std::numeric_limits<double>::epsilon() );
385 halfClipRect2.
setXMinimum( halfClipRect2.
xMinimum() - std::numeric_limits<double>::epsilon() );
386 halfClipRect1.
setXMaximum( halfClipRect1.
xMaximum() + std::numeric_limits<double>::epsilon() );
387 halfClipRect2.
setXMaximum( halfClipRect2.
xMaximum() + std::numeric_limits<double>::epsilon() );
399 clipPart1.reset( GEOSIntersectionPrec_r( geosinit()->ctxt, mGeos.get(), clipPart1.get(), gridSize ) );
401 subdivideRecursive( clipPart1.get(), maxNodes, depth, parts, halfClipRect1, gridSize );
407 clipPart2.reset( GEOSIntersectionPrec_r( geosinit()->ctxt, mGeos.get(), clipPart2.get(), gridSize ) );
409 subdivideRecursive( clipPart2.get(), maxNodes, depth, parts, halfClipRect2, gridSize );
421 maxNodes = std::max( maxNodes, 8 );
430 return std::move( parts );
435 return overlay( geom, OverlayUnion, errorMsg, parameters ).release();
440 QVector< GEOSGeometry * > geosGeometries;
441 geosGeometries.reserve( geomList.size() );
447 geosGeometries <<
asGeos( g, mPrecision ).release();
453 geos::unique_ptr geomCollection = createGeosCollection( GEOS_GEOMETRYCOLLECTION, geosGeometries );
456 geomUnion.reset( GEOSUnaryUnionPrec_r( geosinit()->ctxt, geomCollection.get(), parameters.
gridSize() ) );
460 geomUnion.reset( GEOSUnaryUnion_r( geosinit()->ctxt, geomCollection.get() ) );
465 std::unique_ptr< QgsAbstractGeometry > result =
fromGeos( geomUnion.get() );
466 return result.release();
471 QVector< GEOSGeometry * > geosGeometries;
472 geosGeometries.reserve( geomList.size() );
478 geosGeometries <<
asGeos( g.constGet(), mPrecision ).release();
484 geos::unique_ptr geomCollection = createGeosCollection( GEOS_GEOMETRYCOLLECTION, geosGeometries );
488 geomUnion.reset( GEOSUnaryUnionPrec_r( geosinit()->ctxt, geomCollection.get(), parameters.
gridSize() ) );
492 geomUnion.reset( GEOSUnaryUnion_r( geosinit()->ctxt, geomCollection.get() ) );
498 std::unique_ptr< QgsAbstractGeometry > result =
fromGeos( geomUnion.get() );
499 return result.release();
504 return overlay( geom, OverlaySymDifference, errorMsg, parameters ).release();
516 if ( !otherGeosGeom )
525 GEOSPreparedDistance_r( geosinit()->ctxt, mGeosPrepared.get(), otherGeosGeom.get(), &
distance );
529 GEOSDistance_r( geosinit()->ctxt, mGeos.get(), otherGeosGeom.get(), &
distance );
545 geos::unique_ptr point = createGeosPointXY( x, y,
false, 0,
false, 0, 2, 0 );
553 GEOSPreparedDistance_r( geosinit()->ctxt, mGeosPrepared.get(), point.get(), &
distance );
557 GEOSDistance_r( geosinit()->ctxt, mGeos.get(), point.get(), &
distance );
573 if ( !otherGeosGeom )
588#if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=10 )
589 return GEOSPreparedDistanceWithin_r( geosinit()->ctxt, mGeosPrepared.get(), otherGeosGeom.get(), maxdist );
591 GEOSPreparedDistance_r( geosinit()->ctxt, mGeosPrepared.get(), otherGeosGeom.get(), &
distance );
596#if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=10 )
597 return GEOSDistanceWithin_r( geosinit()->ctxt, mGeos.get(), otherGeosGeom.get(), maxdist );
599 GEOSDistance_r( geosinit()->ctxt, mGeos.get(), otherGeosGeom.get(), &
distance );
610 geos::unique_ptr point = createGeosPointXY( x, y,
false, 0,
false, 0, 2, 0 );
619 return GEOSPreparedContains_r( geosinit()->ctxt, mGeosPrepared.get(), point.get() ) == 1;
622 result = ( GEOSContains_r( geosinit()->ctxt, mGeos.get(), point.get() ) == 1 );
624 catch ( GEOSException &e )
626 logError( QStringLiteral(
"GEOS" ), e.what() );
629 *errorMsg = e.what();
646 if ( !otherGeosGeom )
653 GEOSHausdorffDistance_r( geosinit()->ctxt, mGeos.get(), otherGeosGeom.get(), &
distance );
669 if ( !otherGeosGeom )
676 GEOSHausdorffDistanceDensify_r( geosinit()->ctxt, mGeos.get(), otherGeosGeom.get(), densifyFraction, &
distance );
692 if ( !otherGeosGeom )
699 GEOSFrechetDistance_r( geosinit()->ctxt, mGeos.get(), otherGeosGeom.get(), &
distance );
715 if ( !otherGeosGeom )
722 GEOSFrechetDistanceDensify_r( geosinit()->ctxt, mGeos.get(), otherGeosGeom.get(), densifyFraction, &
distance );
731 return relation( geom, RelationIntersects, errorMsg );
736 return relation( geom, RelationTouches, errorMsg );
741 return relation( geom, RelationCrosses, errorMsg );
746 return relation( geom, RelationWithin, errorMsg );
751 return relation( geom, RelationOverlaps, errorMsg );
756 return relation( geom, RelationContains, errorMsg );
761 return relation( geom, RelationDisjoint, errorMsg );
780 char *r = GEOSRelate_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() );
783 result = QString( r );
784 GEOSFree_r( geosinit()->ctxt, r );
787 catch ( GEOSException &e )
789 logError( QStringLiteral(
"GEOS" ), e.what() );
792 *errorMsg = e.what();
801 if ( !mGeos || !geom )
815 result = ( GEOSRelatePattern_r( geosinit()->ctxt, mGeos.get(), geosGeom.get(), pattern.toLocal8Bit().constData() ) == 1 );
817 catch ( GEOSException &e )
819 logError( QStringLiteral(
"GEOS" ), e.what() );
822 *errorMsg = e.what();
839 if ( GEOSArea_r( geosinit()->ctxt, mGeos.get(), &
area ) != 1 )
855 if ( GEOSLength_r( geosinit()->ctxt, mGeos.get(), &
length ) != 1 )
863 QVector<QgsGeometry> &newGeometries,
866 QString *errorMsg,
bool skipIntersectionCheck )
const
881 if ( !GEOSisValid_r( geosinit()->ctxt, mGeos.get() ) )
889 newGeometries.clear();
896 splitLineGeos = createGeosLinestring( &splitLine, mPrecision );
900 splitLineGeos = createGeosPointXY( splitLine.
xAt( 0 ), splitLine.
yAt( 0 ),
false, 0,
false, 0, 2, mPrecision );
907 if ( !GEOSisValid_r( geosinit()->ctxt, splitLineGeos.get() ) || !GEOSisSimple_r( geosinit()->ctxt, splitLineGeos.get() ) )
915 if ( !topologicalTestPointsSplit( splitLineGeos.get(), topologyTestPoints ) )
924 returnCode = splitLinearGeometry( splitLineGeos.get(), newGeometries, skipIntersectionCheck );
928 returnCode = splitPolygonGeometry( splitLineGeos.get(), newGeometries, skipIntersectionCheck );
942bool QgsGeos::topologicalTestPointsSplit(
const GEOSGeometry *splitLine,
QgsPointSequence &testPoints, QString *errorMsg )
const
956 geos::unique_ptr intersectionGeom( GEOSIntersection_r( geosinit()->ctxt, mGeos.get(), splitLine ) );
957 if ( !intersectionGeom )
961 int nIntersectGeoms = 1;
962 if ( GEOSGeomTypeId_r( geosinit()->ctxt, intersectionGeom.get() ) == GEOS_LINESTRING
963 || GEOSGeomTypeId_r( geosinit()->ctxt, intersectionGeom.get() ) == GEOS_POINT )
967 nIntersectGeoms = GEOSGetNumGeometries_r( geosinit()->ctxt, intersectionGeom.get() );
969 for (
int i = 0; i < nIntersectGeoms; ++i )
971 const GEOSGeometry *currentIntersectGeom =
nullptr;
973 currentIntersectGeom = intersectionGeom.get();
975 currentIntersectGeom = GEOSGetGeometryN_r( geosinit()->ctxt, intersectionGeom.get(), i );
977 const GEOSCoordSequence *lineSequence = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, currentIntersectGeom );
978 unsigned int sequenceSize = 0;
980 if ( GEOSCoordSeq_getSize_r( geosinit()->ctxt, lineSequence, &sequenceSize ) != 0 )
982 for (
unsigned int i = 0; i < sequenceSize; ++i )
984 if ( GEOSCoordSeq_getX_r( geosinit()->ctxt, lineSequence, i, &x ) != 0 )
986 if ( GEOSCoordSeq_getY_r( geosinit()->ctxt, lineSequence, i, &y ) != 0 )
988 testPoints.push_back(
QgsPoint( x, y ) );
1002 int type = GEOSGeomTypeId_r( geosinit()->ctxt, mGeos.get() );
1004 std::unique_ptr< QgsMultiCurve > multiCurve;
1005 if ( type == GEOS_MULTILINESTRING )
1007 multiCurve.reset( qgsgeometry_cast<QgsMultiCurve *>(
mGeometry->
clone() ) );
1009 else if ( type == GEOS_LINESTRING )
1027 std::unique_ptr< QgsAbstractGeometry > splitGeom(
fromGeos( GEOSsplitPoint ) );
1028 std::unique_ptr< QgsMultiPoint > splitPoints( qgsgeometry_cast<QgsMultiPoint *>( splitGeom->clone() ) );
1031 QgsPoint *splitPoint = qgsgeometry_cast<QgsPoint *>( splitGeom->clone() );
1037 splitPoints->addGeometry( splitPoint );
1043 for (
int i = 0; i < multiCurve->numGeometries(); ++i )
1045 const QgsLineString *line = qgsgeometry_cast<const QgsLineString *>( multiCurve->geometryN( i ) );
1048 const QgsCurve *curve = qgsgeometry_cast<const QgsCurve *>( multiCurve->geometryN( i ) );
1056 QMap< int, QVector< QPair< double, QgsPoint > > >pointMap;
1057 for (
int p = 0; p < splitPoints->numGeometries(); ++p )
1059 const QgsPoint *intersectionPoint = splitPoints->pointN( p );
1064 line->
closestSegment( *intersectionPoint, segmentPoint2D, nextVertex );
1067 std::unique_ptr< QgsPoint > correctSegmentPoint(
segment.interpolatePoint(
distance ) );
1068 const QPair< double, QgsPoint > pair = qMakePair(
distance, *correctSegmentPoint.get() );
1069 if ( pointMap.contains( nextVertex.
vertex - 1 ) )
1070 pointMap[ nextVertex.
vertex - 1 ].append( pair );
1072 pointMap[ nextVertex.
vertex - 1 ] = QVector< QPair< double, QgsPoint > >() << pair;
1077 for (
auto &p : pointMap )
1079 std::sort( p.begin(), p.end(), [](
const QPair< double, QgsPoint > &a,
const QPair< double, QgsPoint > &b ) { return a.first < b.first; } );
1086 for (
int j = 0; j < nVertices; ++j )
1090 if ( pointMap.contains( j ) )
1093 for (
int k = 0; k < pointMap[ j ].size(); ++k )
1095 splitPoint = pointMap[ j ][k].second;
1096 if ( splitPoint == currentPoint )
1102 else if ( splitPoint == line->
pointN( j + 1 ) )
1121 return asGeos( &lines, mPrecision );
1126 Q_UNUSED( skipIntersectionCheck )
1133 geos::unique_ptr intersectGeom( GEOSIntersection_r( geosinit()->ctxt, splitLine, mGeos.get() ) );
1134 if ( !intersectGeom )
1138 int linearIntersect = GEOSRelatePattern_r( geosinit()->ctxt, mGeos.get(), splitLine,
"1********" );
1139 if ( linearIntersect > 0 )
1143 splitGeom = linePointDifference( intersectGeom.get() );
1148 QVector<GEOSGeometry *> lineGeoms;
1150 int splitType = GEOSGeomTypeId_r( geosinit()->ctxt, splitGeom.get() );
1151 if ( splitType == GEOS_MULTILINESTRING )
1153 int nGeoms = GEOSGetNumGeometries_r( geosinit()->ctxt, splitGeom.get() );
1154 lineGeoms.reserve( nGeoms );
1155 for (
int i = 0; i < nGeoms; ++i )
1156 lineGeoms << GEOSGeom_clone_r( geosinit()->ctxt, GEOSGetGeometryN_r( geosinit()->ctxt, splitGeom.get(), i ) );
1161 lineGeoms << GEOSGeom_clone_r( geosinit()->ctxt, splitGeom.get() );
1164 mergeGeometriesMultiTypeSplit( lineGeoms );
1166 for (
int i = 0; i < lineGeoms.size(); ++i )
1169 GEOSGeom_destroy_r( geosinit()->ctxt, lineGeoms[i] );
1185 if ( !mGeosPrepared )
1189 if ( !skipIntersectionCheck && !GEOSPreparedIntersects_r( geosinit()->ctxt, mGeosPrepared.get(), splitLine ) )
1194 if ( !nodedGeometry )
1197 const GEOSGeometry *noded = nodedGeometry.get();
1198 geos::unique_ptr polygons( GEOSPolygonize_r( geosinit()->ctxt, &noded, 1 ) );
1199 if ( !polygons || numberOfGeometries( polygons.get() ) == 0 )
1206 QVector<GEOSGeometry *> testedGeometries;
1211 for (
int i = 0; i < numberOfGeometries( polygons.get() ); i++ )
1213 const GEOSGeometry *polygon = GEOSGetGeometryN_r( geosinit()->ctxt, polygons.get(), i );
1217 testedGeometries << GEOSGeom_clone_r( geosinit()->ctxt, polygon );
1220 int nGeometriesThis = numberOfGeometries( mGeos.get() );
1221 if ( testedGeometries.empty() || testedGeometries.size() == nGeometriesThis )
1224 for (
int i = 0; i < testedGeometries.size(); ++i )
1226 GEOSGeom_destroy_r( geosinit()->ctxt, testedGeometries[i] );
1235 mergeGeometriesMultiTypeSplit( testedGeometries );
1238 for ( i = 0; i < testedGeometries.size() && GEOSisValid_r( geosinit()->ctxt, testedGeometries[i] ); ++i )
1241 if ( i < testedGeometries.size() )
1243 for ( i = 0; i < testedGeometries.size(); ++i )
1244 GEOSGeom_destroy_r( geosinit()->ctxt, testedGeometries[i] );
1249 for ( i = 0; i < testedGeometries.size(); ++i )
1252 GEOSGeom_destroy_r( geosinit()->ctxt, testedGeometries[i] );
1258geos::unique_ptr QgsGeos::nodeGeometries(
const GEOSGeometry *splitLine,
const GEOSGeometry *geom )
1260 if ( !splitLine || !geom )
1264 if ( GEOSGeomTypeId_r( geosinit()->ctxt, geom ) == GEOS_POLYGON || GEOSGeomTypeId_r( geosinit()->ctxt, geom ) == GEOS_MULTIPOLYGON )
1265 geometryBoundary.reset( GEOSBoundary_r( geosinit()->ctxt, geom ) );
1267 geometryBoundary.reset( GEOSGeom_clone_r( geosinit()->ctxt, geom ) );
1269 geos::unique_ptr splitLineClone( GEOSGeom_clone_r( geosinit()->ctxt, splitLine ) );
1270 geos::unique_ptr unionGeometry( GEOSUnion_r( geosinit()->ctxt, splitLineClone.get(), geometryBoundary.get() ) );
1272 return unionGeometry;
1275int QgsGeos::mergeGeometriesMultiTypeSplit( QVector<GEOSGeometry *> &splitResult )
const
1281 int type = GEOSGeomTypeId_r( geosinit()->ctxt, mGeos.get() );
1282 if ( type != GEOS_GEOMETRYCOLLECTION &&
1283 type != GEOS_MULTILINESTRING &&
1284 type != GEOS_MULTIPOLYGON &&
1285 type != GEOS_MULTIPOINT )
1288 QVector<GEOSGeometry *> copyList = splitResult;
1289 splitResult.clear();
1292 QVector<GEOSGeometry *> unionGeom;
1294 for (
int i = 0; i < copyList.size(); ++i )
1297 bool isPart =
false;
1298 for (
int j = 0; j < GEOSGetNumGeometries_r( geosinit()->ctxt, mGeos.get() ); j++ )
1300 if ( GEOSEquals_r( geosinit()->ctxt, copyList[i], GEOSGetGeometryN_r( geosinit()->ctxt, mGeos.get(), j ) ) )
1309 unionGeom << copyList[i];
1313 QVector<GEOSGeometry *> geomVector;
1314 geomVector << copyList[i];
1316 if ( type == GEOS_MULTILINESTRING )
1317 splitResult << createGeosCollection( GEOS_MULTILINESTRING, geomVector ).release();
1318 else if ( type == GEOS_MULTIPOLYGON )
1319 splitResult << createGeosCollection( GEOS_MULTIPOLYGON, geomVector ).release();
1321 GEOSGeom_destroy_r( geosinit()->ctxt, copyList[i] );
1326 if ( !unionGeom.isEmpty() )
1328 if ( type == GEOS_MULTILINESTRING )
1329 splitResult << createGeosCollection( GEOS_MULTILINESTRING, unionGeom ).release();
1330 else if ( type == GEOS_MULTIPOLYGON )
1331 splitResult << createGeosCollection( GEOS_MULTIPOLYGON, unionGeom ).release();
1341geos::unique_ptr QgsGeos::createGeosCollection(
int typeId,
const QVector<GEOSGeometry *> &geoms )
1343 int nNullGeoms = geoms.count(
nullptr );
1344 int nNotNullGeoms = geoms.size() - nNullGeoms;
1346 GEOSGeometry **geomarr =
new GEOSGeometry*[ nNotNullGeoms ];
1353 QVector<GEOSGeometry *>::const_iterator geomIt = geoms.constBegin();
1354 for ( ; geomIt != geoms.constEnd(); ++geomIt )
1358 if ( GEOSisEmpty_r( geosinit()->ctxt, *geomIt ) )
1363 GEOSGeom_destroy_r( geosinit()->ctxt, *geomIt );
1367 geomarr[i] = *geomIt;
1376 geom.reset( GEOSGeom_createCollection_r( geosinit()->ctxt, typeId, geomarr, nNotNullGeoms ) );
1378 catch ( GEOSException & )
1394 int nCoordDims = GEOSGeom_getCoordinateDimension_r( geosinit()->ctxt,
geos );
1395 int nDims = GEOSGeom_getDimensions_r( geosinit()->ctxt,
geos );
1396 bool hasZ = ( nCoordDims == 3 );
1397 bool hasM = ( ( nDims - nCoordDims ) == 1 );
1399 switch ( GEOSGeomTypeId_r( geosinit()->ctxt,
geos ) )
1403 if ( GEOSisEmpty_r( geosinit()->ctxt,
geos ) )
1406 const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq_r( geosinit()->ctxt,
geos );
1407 unsigned int nPoints = 0;
1408 GEOSCoordSeq_getSize_r( geosinit()->ctxt, cs, &nPoints );
1409 return nPoints > 0 ? std::unique_ptr<QgsAbstractGeometry>(
coordSeqPoint( cs, 0, hasZ, hasM ).clone() ) :
nullptr;
1411 case GEOS_LINESTRING:
1413 return sequenceToLinestring(
geos, hasZ, hasM );
1419 case GEOS_MULTIPOINT:
1421 std::unique_ptr< QgsMultiPoint > multiPoint(
new QgsMultiPoint() );
1422 int nParts = GEOSGetNumGeometries_r( geosinit()->ctxt,
geos );
1423 multiPoint->reserve( nParts );
1424 for (
int i = 0; i < nParts; ++i )
1426 const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, GEOSGetGeometryN_r( geosinit()->ctxt,
geos, i ) );
1429 unsigned int nPoints = 0;
1430 GEOSCoordSeq_getSize_r( geosinit()->ctxt, cs, &nPoints );
1432 multiPoint->addGeometry(
coordSeqPoint( cs, 0, hasZ, hasM ).clone() );
1435 return std::move( multiPoint );
1437 case GEOS_MULTILINESTRING:
1440 int nParts = GEOSGetNumGeometries_r( geosinit()->ctxt,
geos );
1441 multiLineString->reserve( nParts );
1442 for (
int i = 0; i < nParts; ++i )
1444 std::unique_ptr< QgsLineString >line( sequenceToLinestring( GEOSGetGeometryN_r( geosinit()->ctxt,
geos, i ), hasZ, hasM ) );
1447 multiLineString->addGeometry( line.release() );
1450 return std::move( multiLineString );
1452 case GEOS_MULTIPOLYGON:
1454 std::unique_ptr< QgsMultiPolygon > multiPolygon(
new QgsMultiPolygon() );
1456 int nParts = GEOSGetNumGeometries_r( geosinit()->ctxt,
geos );
1457 multiPolygon->reserve( nParts );
1458 for (
int i = 0; i < nParts; ++i )
1460 std::unique_ptr< QgsPolygon > poly =
fromGeosPolygon( GEOSGetGeometryN_r( geosinit()->ctxt,
geos, i ) );
1463 multiPolygon->addGeometry( poly.release() );
1466 return std::move( multiPolygon );
1468 case GEOS_GEOMETRYCOLLECTION:
1471 int nParts = GEOSGetNumGeometries_r( geosinit()->ctxt,
geos );
1472 geomCollection->reserve( nParts );
1473 for (
int i = 0; i < nParts; ++i )
1475 std::unique_ptr< QgsAbstractGeometry > geom(
fromGeos( GEOSGetGeometryN_r( geosinit()->ctxt,
geos, i ) ) );
1478 geomCollection->addGeometry( geom.release() );
1481 return std::move( geomCollection );
1489 if ( GEOSGeomTypeId_r( geosinit()->ctxt,
geos ) != GEOS_POLYGON )
1494 int nCoordDims = GEOSGeom_getCoordinateDimension_r( geosinit()->ctxt,
geos );
1495 int nDims = GEOSGeom_getDimensions_r( geosinit()->ctxt,
geos );
1496 bool hasZ = ( nCoordDims == 3 );
1497 bool hasM = ( ( nDims - nCoordDims ) == 1 );
1499 std::unique_ptr< QgsPolygon > polygon(
new QgsPolygon() );
1501 const GEOSGeometry *ring = GEOSGetExteriorRing_r( geosinit()->ctxt,
geos );
1504 polygon->setExteriorRing( sequenceToLinestring( ring, hasZ, hasM ).release() );
1507 QVector<QgsCurve *> interiorRings;
1508 const int ringCount = GEOSGetNumInteriorRings_r( geosinit()->ctxt,
geos );
1509 interiorRings.reserve( ringCount );
1510 for (
int i = 0; i < ringCount; ++i )
1512 ring = GEOSGetInteriorRingN_r( geosinit()->ctxt,
geos, i );
1515 interiorRings.push_back( sequenceToLinestring( ring, hasZ, hasM ).release() );
1518 polygon->setInteriorRings( interiorRings );
1523std::unique_ptr<QgsLineString> QgsGeos::sequenceToLinestring(
const GEOSGeometry *
geos,
bool hasZ,
bool hasM )
1525 const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq_r( geosinit()->ctxt,
geos );
1527 unsigned int nPoints;
1528 GEOSCoordSeq_getSize_r( geosinit()->ctxt, cs, &nPoints );
1530 QVector< double > xOut( nPoints );
1531 QVector< double > yOut( nPoints );
1532 QVector< double > zOut;
1534 zOut.resize( nPoints );
1535 QVector< double > mOut;
1537 mOut.resize( nPoints );
1539 double *x = xOut.data();
1540 double *y = yOut.data();
1541 double *z = zOut.data();
1542 double *m = mOut.data();
1544#if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=10 )
1545 GEOSCoordSeq_copyToArrays_r( geosinit()->ctxt, cs, x, y, hasZ ? z :
nullptr, hasM ? m :
nullptr );
1547 for (
unsigned int i = 0; i < nPoints; ++i )
1550 GEOSCoordSeq_getXYZ_r( geosinit()->ctxt, cs, i, x++, y++, z++ );
1552 GEOSCoordSeq_getXY_r( geosinit()->ctxt, cs, i, x++, y++ );
1555 GEOSCoordSeq_getOrdinate_r( geosinit()->ctxt, cs, i, 3, m++ );
1559 std::unique_ptr< QgsLineString > line(
new QgsLineString( xOut, yOut, zOut, mOut ) );
1563int QgsGeos::numberOfGeometries( GEOSGeometry *g )
1568 int geometryType = GEOSGeomTypeId_r( geosinit()->ctxt, g );
1569 if ( geometryType == GEOS_POINT || geometryType == GEOS_LINESTRING || geometryType == GEOS_LINEARRING
1570 || geometryType == GEOS_POLYGON )
1574 return GEOSGetNumGeometries_r( geosinit()->ctxt, g );
1588 GEOSCoordSeq_getXYZ_r( geosinit()->ctxt, cs, i, &x, &y, &z );
1590 GEOSCoordSeq_getXY_r( geosinit()->ctxt, cs, i, &x, &y );
1593 GEOSCoordSeq_getOrdinate_r( geosinit()->ctxt, cs, i, 3, &m );
1629 int geosType = GEOS_GEOMETRYCOLLECTION;
1636 geosType = GEOS_MULTIPOINT;
1640 geosType = GEOS_MULTILINESTRING;
1644 geosType = GEOS_MULTIPOLYGON;
1659 QVector< GEOSGeometry * > geomVector(
c->numGeometries() );
1660 for (
int i = 0; i <
c->numGeometries(); ++i )
1664 return createGeosCollection( geosType, geomVector );
1671 return createGeosPoint(
static_cast<const QgsPoint *
>( geom ), coordDims,
precision );
1689 if ( !mGeos || !geom )
1700 const double gridSize = parameters.
gridSize();
1707 case OverlayIntersection:
1710 opGeom.reset( GEOSIntersectionPrec_r( geosinit()->ctxt, mGeos.get(), geosGeom.get(), gridSize ) );
1714 opGeom.reset( GEOSIntersection_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) );
1718 case OverlayDifference:
1721 opGeom.reset( GEOSDifferencePrec_r( geosinit()->ctxt, mGeos.get(), geosGeom.get(), gridSize ) );
1725 opGeom.reset( GEOSDifference_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) );
1734 unionGeometry.reset( GEOSUnionPrec_r( geosinit()->ctxt, mGeos.get(), geosGeom.get(), gridSize ) );
1738 unionGeometry.reset( GEOSUnion_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) );
1741 if ( unionGeometry && GEOSGeomTypeId_r( geosinit()->ctxt, unionGeometry.get() ) == GEOS_MULTILINESTRING )
1743 geos::unique_ptr mergedLines( GEOSLineMerge_r( geosinit()->ctxt, unionGeometry.get() ) );
1746 unionGeometry = std::move( mergedLines );
1750 opGeom = std::move( unionGeometry );
1754 case OverlaySymDifference:
1757 opGeom.reset( GEOSSymDifferencePrec_r( geosinit()->ctxt, mGeos.get(), geosGeom.get(), gridSize ) );
1761 opGeom.reset( GEOSSymDifference_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) );
1767 catch ( GEOSException &e )
1769 logError( QStringLiteral(
"GEOS" ), e.what() );
1772 *errorMsg = e.what();
1778bool QgsGeos::relation(
const QgsAbstractGeometry *geom, Relation r, QString *errorMsg )
const
1780 if ( !mGeos || !geom )
1791 bool result =
false;
1794 if ( mGeosPrepared )
1798 case RelationIntersects:
1799 result = ( GEOSPreparedIntersects_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1801 case RelationTouches:
1802 result = ( GEOSPreparedTouches_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1804 case RelationCrosses:
1805 result = ( GEOSPreparedCrosses_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1807 case RelationWithin:
1808 result = ( GEOSPreparedWithin_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1810 case RelationContains:
1811 result = ( GEOSPreparedContains_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1813 case RelationDisjoint:
1814 result = ( GEOSPreparedDisjoint_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1816 case RelationOverlaps:
1817 result = ( GEOSPreparedOverlaps_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1825 case RelationIntersects:
1826 result = ( GEOSIntersects_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1828 case RelationTouches:
1829 result = ( GEOSTouches_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1831 case RelationCrosses:
1832 result = ( GEOSCrosses_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1834 case RelationWithin:
1835 result = ( GEOSWithin_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1837 case RelationContains:
1838 result = ( GEOSContains_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1840 case RelationDisjoint:
1841 result = ( GEOSDisjoint_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1843 case RelationOverlaps:
1844 result = ( GEOSOverlaps_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1848 catch ( GEOSException &e )
1850 logError( QStringLiteral(
"GEOS" ), e.what() );
1853 *errorMsg = e.what();
1871 geos.reset( GEOSBuffer_r( geosinit()->ctxt, mGeos.get(),
distance, segments ) );
1887 geos.reset( GEOSBufferWithStyle_r( geosinit()->ctxt, mGeos.get(),
distance, segments,
static_cast< int >( endCapStyle ),
static_cast< int >( joinStyle ), miterLimit ) );
1902 geos.reset( GEOSTopologyPreserveSimplify_r( geosinit()->ctxt, mGeos.get(), tolerance ) );
1917 geos.reset( GEOSInterpolate_r( geosinit()->ctxt, mGeos.get(),
distance ) );
1936 geos.reset( GEOSGetCentroid_r( geosinit()->ctxt, mGeos.get() ) );
1941 GEOSGeomGetX_r( geosinit()->ctxt,
geos.get(), &x );
1942 GEOSGeomGetY_r( geosinit()->ctxt,
geos.get(), &y );
1958 geos.reset( GEOSEnvelope_r( geosinit()->ctxt, mGeos.get() ) );
1977 geos.reset( GEOSPointOnSurface_r( geosinit()->ctxt, mGeos.get() ) );
1979 if ( !
geos || GEOSisEmpty_r( geosinit()->ctxt,
geos.get() ) != 0 )
1984 GEOSGeomGetX_r( geosinit()->ctxt,
geos.get(), &x );
1985 GEOSGeomGetY_r( geosinit()->ctxt,
geos.get(), &y );
2001 geos::unique_ptr cHull( GEOSConvexHull_r( geosinit()->ctxt, mGeos.get() ) );
2002 std::unique_ptr< QgsAbstractGeometry > cHullGeom =
fromGeos( cHull.get() );
2003 return cHullGeom.release();
2010#if GEOS_VERSION_MAJOR==3 && GEOS_VERSION_MINOR<11
2012 ( void )targetPercent;
2014 throw QgsNotSupportedException( QObject::tr(
"Calculating concaveHull requires a QGIS build based on GEOS 3.11 or later" ) );
2025 return concaveHullGeom.release();
2040 GEOSGeometry *g1 =
nullptr;
2042 char res = GEOSisValidDetail_r( geosinit()->ctxt, mGeos.get(), allowSelfTouchingHoles ? GEOSVALID_ALLOW_SELFTOUCHING_RING_FORMING_HOLE : 0, &r, &g1 );
2043 const bool invalid = res != 1;
2048 error = QString( r );
2049 GEOSFree_r( geosinit()->ctxt, r );
2052 if ( invalid && errorMsg )
2056 if ( translatedErrors.empty() )
2059 translatedErrors.insert( QStringLiteral(
"topology validation error" ), QObject::tr(
"Topology validation error",
"GEOS Error" ) );
2060 translatedErrors.insert( QStringLiteral(
"repeated point" ), QObject::tr(
"Repeated point",
"GEOS Error" ) );
2061 translatedErrors.insert( QStringLiteral(
"hole lies outside shell" ), QObject::tr(
"Hole lies outside shell",
"GEOS Error" ) );
2062 translatedErrors.insert( QStringLiteral(
"holes are nested" ), QObject::tr(
"Holes are nested",
"GEOS Error" ) );
2063 translatedErrors.insert( QStringLiteral(
"interior is disconnected" ), QObject::tr(
"Interior is disconnected",
"GEOS Error" ) );
2064 translatedErrors.insert( QStringLiteral(
"self-intersection" ), QObject::tr(
"Self-intersection",
"GEOS Error" ) );
2065 translatedErrors.insert( QStringLiteral(
"ring self-intersection" ), QObject::tr(
"Ring self-intersection",
"GEOS Error" ) );
2066 translatedErrors.insert( QStringLiteral(
"nested shells" ), QObject::tr(
"Nested shells",
"GEOS Error" ) );
2067 translatedErrors.insert( QStringLiteral(
"duplicate rings" ), QObject::tr(
"Duplicate rings",
"GEOS Error" ) );
2068 translatedErrors.insert( QStringLiteral(
"too few points in geometry component" ), QObject::tr(
"Too few points in geometry component",
"GEOS Error" ) );
2069 translatedErrors.insert( QStringLiteral(
"invalid coordinate" ), QObject::tr(
"Invalid coordinate",
"GEOS Error" ) );
2070 translatedErrors.insert( QStringLiteral(
"ring is not closed" ), QObject::tr(
"Ring is not closed",
"GEOS Error" ) );
2073 *errorMsg = translatedErrors.value( error.toLower(), error );
2075 if ( g1 && errorLoc )
2081 GEOSGeom_destroy_r( geosinit()->ctxt, g1 );
2091 if ( !mGeos || !geom )
2103 bool equal = GEOSEquals_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() );
2118 return GEOSisEmpty_r( geosinit()->ctxt, mGeos.get() );
2132 return GEOSisSimple_r( geosinit()->ctxt, mGeos.get() );
2137GEOSCoordSequence *QgsGeos::createCoordinateSequence(
const QgsCurve *curve,
double precision,
bool forceClose )
2139 GEOSContextHandle_t ctxt = geosinit()->ctxt;
2141 std::unique_ptr< QgsLineString > segmentized;
2142 const QgsLineString *line = qgsgeometry_cast<const QgsLineString *>( curve );
2147 line = segmentized.get();
2154 GEOSCoordSequence *coordSeq =
nullptr;
2156 const int numPoints = line->
numPoints();
2158 const bool hasZ = line->
is3D();
2160#if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=10 )
2163 if ( !forceClose || ( line->
pointN( 0 ) == line->
pointN( numPoints - 1 ) ) )
2168 coordSeq = GEOSCoordSeq_copyFromArrays_r( ctxt, line->
xData(), line->
yData(), line->
zData(),
nullptr, numPoints );
2171 QgsDebugMsg( QStringLiteral(
"GEOS Exception: Could not create coordinate sequence for %1 points" ).arg( numPoints ) );
2179 QVector< double > x = line->
xVector();
2180 if ( numPoints > 0 )
2181 x.append( x.at( 0 ) );
2182 QVector< double > y = line->
yVector();
2183 if ( numPoints > 0 )
2184 y.append( y.at( 0 ) );
2185 QVector< double > z = line->
zVector();
2186 if ( hasZ && numPoints > 0 )
2187 z.append( z.at( 0 ) );
2190 coordSeq = GEOSCoordSeq_copyFromArrays_r( ctxt, x.constData(), y.constData(), !hasZ ?
nullptr : z.constData(),
nullptr, numPoints + 1 );
2193 QgsDebugMsg( QStringLiteral(
"GEOS Exception: Could not create closed coordinate sequence for %1 points" ).arg( numPoints + 1 ) );
2204 const bool hasM =
false;
2215 int numOutPoints = numPoints;
2216 if ( forceClose && ( line->
pointN( 0 ) != line->
pointN( numPoints - 1 ) ) )
2223 coordSeq = GEOSCoordSeq_create_r( ctxt, numOutPoints, coordDims );
2226 QgsDebugMsg( QStringLiteral(
"GEOS Exception: Could not create coordinate sequence for %1 points in %2 dimensions" ).arg( numPoints ).arg( coordDims ) );
2230 const double *xData = line->
xData();
2231 const double *yData = line->
yData();
2232 const double *zData = hasZ ? line->
zData() :
nullptr;
2233 const double *mData = hasM ? line->
mData() :
nullptr;
2237 for (
int i = 0; i < numOutPoints; ++i )
2239 if ( i >= numPoints )
2242 xData = line->
xData();
2243 yData = line->
yData();
2244 zData = hasZ ? line->
zData() :
nullptr;
2245 mData = hasM ? line->
mData() :
nullptr;
2257 GEOSCoordSeq_setOrdinate_r( ctxt, coordSeq, i, 3, *mData++ );
2263 for (
int i = 0; i < numOutPoints; ++i )
2265 if ( i >= numPoints )
2268 xData = line->
xData();
2269 yData = line->
yData();
2270 zData = hasZ ? line->
zData() :
nullptr;
2271 mData = hasM ? line->
mData() :
nullptr;
2275 GEOSCoordSeq_setXYZ_r( ctxt, coordSeq, i, *xData++, *yData++, *zData++ );
2279 GEOSCoordSeq_setXY_r( ctxt, coordSeq, i, *xData++, *yData++ );
2283 GEOSCoordSeq_setOrdinate_r( ctxt, coordSeq, i, 3, *mData++ );
2295 const QgsPoint *pt = qgsgeometry_cast<const QgsPoint *>( point );
2302geos::unique_ptr QgsGeos::createGeosPointXY(
double x,
double y,
bool hasZ,
double z,
bool hasM,
double m,
int coordDims,
double precision )
2310 if ( coordDims == 2 )
2316 geosPoint.reset( GEOSGeom_createPointFromXY_r( geosinit()->ctxt, x, y ) );
2320 GEOSCoordSequence *coordSeq = GEOSCoordSeq_create_r( geosinit()->ctxt, 1, coordDims );
2323 QgsDebugMsg( QStringLiteral(
"GEOS Exception: Could not create coordinate sequence for point with %1 dimensions" ).arg( coordDims ) );
2328 GEOSCoordSeq_setX_r( geosinit()->ctxt, coordSeq, 0, std::round( x /
precision ) *
precision );
2329 GEOSCoordSeq_setY_r( geosinit()->ctxt, coordSeq, 0, std::round( y /
precision ) *
precision );
2332 GEOSCoordSeq_setOrdinate_r( geosinit()->ctxt, coordSeq, 0, 2, std::round( z /
precision ) *
precision );
2337 GEOSCoordSeq_setX_r( geosinit()->ctxt, coordSeq, 0, x );
2338 GEOSCoordSeq_setY_r( geosinit()->ctxt, coordSeq, 0, y );
2341 GEOSCoordSeq_setOrdinate_r( geosinit()->ctxt, coordSeq, 0, 2, z );
2347 GEOSCoordSeq_setOrdinate_r( geosinit()->ctxt, coordSeq, 0, 3, m );
2350 geosPoint.reset( GEOSGeom_createPoint_r( geosinit()->ctxt, coordSeq ) );
2358 const QgsCurve *
c = qgsgeometry_cast<const QgsCurve *>( curve );
2362 GEOSCoordSequence *coordSeq = createCoordinateSequence(
c,
precision );
2369 geosGeom.reset( GEOSGeom_createLineString_r( geosinit()->ctxt, coordSeq ) );
2377 const QgsCurvePolygon *polygon = qgsgeometry_cast<const QgsCurvePolygon *>( poly );
2382 if ( !exteriorRing )
2390 geos::unique_ptr exteriorRingGeos( GEOSGeom_createLinearRing_r( geosinit()->ctxt, createCoordinateSequence( exteriorRing,
precision,
true ) ) );
2393 GEOSGeometry **holes =
nullptr;
2396 holes =
new GEOSGeometry*[ nHoles ];
2399 for (
int i = 0; i < nHoles; ++i )
2402 holes[i] = GEOSGeom_createLinearRing_r( geosinit()->ctxt, createCoordinateSequence( interiorRing,
precision,
true ) );
2404 geosPolygon.reset( GEOSGeom_createPolygon_r( geosinit()->ctxt, exteriorRingGeos.release(), holes, nHoles ) );
2420 offset.reset( GEOSOffsetCurve_r( geosinit()->ctxt, mGeos.get(),
distance, segments,
static_cast< int >( joinStyle ), miterLimit ) );
2423 std::unique_ptr< QgsAbstractGeometry > offsetGeom =
fromGeos( offset.get() );
2424 return offsetGeom.release();
2438 GEOSBufferParams_setSingleSided_r( geosinit()->ctxt, bp.get(), 1 );
2439 GEOSBufferParams_setQuadrantSegments_r( geosinit()->ctxt, bp.get(), segments );
2440 GEOSBufferParams_setJoinStyle_r( geosinit()->ctxt, bp.get(),
static_cast< int >( joinStyle ) );
2441 GEOSBufferParams_setMitreLimit_r( geosinit()->ctxt, bp.get(), miterLimit );
2443 if ( side == Qgis::BufferSide::Right )
2447 geos.reset( GEOSBufferWithParams_r( geosinit()->ctxt, mGeos.get(), bp.get(),
distance ) );
2463 geos.reset( GEOSMaximumInscribedCircle_r( geosinit()->ctxt, mGeos.get(), tolerance ) );
2481 boundaryGeos =
asGeos( boundary );
2483 geos.reset( GEOSLargestEmptyCircle_r( geosinit()->ctxt, mGeos.get(), boundaryGeos.get(), tolerance ) );
2499 geos.reset( GEOSMinimumWidth_r( geosinit()->ctxt, mGeos.get() ) );
2509 return std::numeric_limits< double >::quiet_NaN();
2516 if ( GEOSMinimumClearance_r( geosinit()->ctxt, mGeos.get(), &res ) != 0 )
2517 return std::numeric_limits< double >::quiet_NaN();
2533 geos.reset( GEOSMinimumClearanceLine_r( geosinit()->ctxt, mGeos.get() ) );
2549 geos.reset( GEOSNode_r( geosinit()->ctxt, mGeos.get() ) );
2557 if ( !mGeos || !other )
2569 geos.reset( GEOSSharedPaths_r( geosinit()->ctxt, mGeos.get(), otherGeos.get() ) );
2589 geos::unique_ptr reshapeLineGeos = createGeosLinestring( &reshapeWithLine, mPrecision );
2592 int numGeoms = GEOSGetNumGeometries_r( geosinit()->ctxt, mGeos.get() );
2593 if ( numGeoms == -1 )
2602 bool isMultiGeom =
false;
2603 int geosTypeId = GEOSGeomTypeId_r( geosinit()->ctxt, mGeos.get() );
2604 if ( geosTypeId == GEOS_MULTILINESTRING || geosTypeId == GEOS_MULTIPOLYGON )
2614 reshapedGeometry = reshapeLine( mGeos.get(), reshapeLineGeos.get(), mPrecision );
2618 reshapedGeometry = reshapePolygon( mGeos.get(), reshapeLineGeos.get(), mPrecision );
2623 std::unique_ptr< QgsAbstractGeometry > reshapeResult =
fromGeos( reshapedGeometry.get() );
2624 return reshapeResult;
2631 bool reshapeTookPlace =
false;
2634 GEOSGeometry **newGeoms =
new GEOSGeometry*[numGeoms];
2636 for (
int i = 0; i < numGeoms; ++i )
2639 currentReshapeGeometry = reshapeLine( GEOSGetGeometryN_r( geosinit()->ctxt, mGeos.get(), i ), reshapeLineGeos.get(), mPrecision );
2641 currentReshapeGeometry = reshapePolygon( GEOSGetGeometryN_r( geosinit()->ctxt, mGeos.get(), i ), reshapeLineGeos.get(), mPrecision );
2643 if ( currentReshapeGeometry )
2645 newGeoms[i] = currentReshapeGeometry.release();
2646 reshapeTookPlace =
true;
2650 newGeoms[i] = GEOSGeom_clone_r( geosinit()->ctxt, GEOSGetGeometryN_r( geosinit()->ctxt, mGeos.get(), i ) );
2657 newMultiGeom.reset( GEOSGeom_createCollection_r( geosinit()->ctxt, GEOS_MULTILINESTRING, newGeoms, numGeoms ) );
2661 newMultiGeom.reset( GEOSGeom_createCollection_r( geosinit()->ctxt, GEOS_MULTIPOLYGON, newGeoms, numGeoms ) );
2665 if ( !newMultiGeom )
2671 if ( reshapeTookPlace )
2675 std::unique_ptr< QgsAbstractGeometry > reshapedMultiGeom =
fromGeos( newMultiGeom.get() );
2676 return reshapedMultiGeom;
2698 if ( GEOSGeomTypeId_r( geosinit()->ctxt, mGeos.get() ) != GEOS_MULTILINESTRING )
2704 geos.reset( GEOSLineMerge_r( geosinit()->ctxt, mGeos.get() ) );
2728 if ( mGeosPrepared )
2730 nearestCoord.reset( GEOSPreparedNearestPoints_r( geosinit()->ctxt, mGeosPrepared.get(), otherGeom.get() ) );
2734 nearestCoord.reset( GEOSNearestPoints_r( geosinit()->ctxt, mGeos.get(), otherGeom.get() ) );
2737 ( void )GEOSCoordSeq_getX_r( geosinit()->ctxt, nearestCoord.get(), 0, &nx );
2738 ( void )GEOSCoordSeq_getY_r( geosinit()->ctxt, nearestCoord.get(), 0, &ny );
2740 catch ( GEOSException &e )
2742 logError( QStringLiteral(
"GEOS" ), e.what() );
2745 *errorMsg = e.what();
2755 if ( !mGeos || other.
isEmpty() )
2765 if ( !other || other->
isEmpty() )
2782 if ( !nearestCoord )
2785 *errorMsg = QStringLiteral(
"GEOS returned no nearest points" );
2789 ( void )GEOSCoordSeq_getX_r( geosinit()->ctxt, nearestCoord.get(), 0, &nx1 );
2790 ( void )GEOSCoordSeq_getY_r( geosinit()->ctxt, nearestCoord.get(), 0, &ny1 );
2791 ( void )GEOSCoordSeq_getX_r( geosinit()->ctxt, nearestCoord.get(), 1, &nx2 );
2792 ( void )GEOSCoordSeq_getY_r( geosinit()->ctxt, nearestCoord.get(), 1, &ny2 );
2794 catch ( GEOSException &e )
2796 logError( QStringLiteral(
"GEOS" ), e.what() );
2799 *errorMsg = e.what();
2826 distance = GEOSProject_r( geosinit()->ctxt, mGeos.get(), otherGeom.get() );
2828 catch ( GEOSException &e )
2830 logError( QStringLiteral(
"GEOS" ), e.what() );
2833 *errorMsg = e.what();
2848 geos::unique_ptr point = createGeosPointXY( x, y,
false, 0,
false, 0, 2, 0 );
2855 distance = GEOSProject_r( geosinit()->ctxt, mGeos.get(), point.get() );
2857 catch ( GEOSException &e )
2859 logError( QStringLiteral(
"GEOS" ), e.what() );
2862 *errorMsg = e.what();
2872 GEOSGeometry **
const lineGeosGeometries =
new GEOSGeometry*[ geometries.size()];
2879 lineGeosGeometries[validLines] = l.release();
2886 geos::unique_ptr result( GEOSPolygonize_r( geosinit()->ctxt, lineGeosGeometries, validLines ) );
2887 for (
int i = 0; i < validLines; ++i )
2889 GEOSGeom_destroy_r( geosinit()->ctxt, lineGeosGeometries[i] );
2891 delete[] lineGeosGeometries;
2894 catch ( GEOSException &e )
2898 *errorMsg = e.what();
2900 for (
int i = 0; i < validLines; ++i )
2902 GEOSGeom_destroy_r( geosinit()->ctxt, lineGeosGeometries[i] );
2904 delete[] lineGeosGeometries;
2919 extentGeosGeom =
asGeos( extent, mPrecision );
2920 if ( !extentGeosGeom )
2929 geos.reset( GEOSVoronoiDiagram_r( geosinit()->ctxt, mGeos.get(), extentGeosGeom.get(), tolerance, edgesOnly ) );
2931 if ( !
geos || GEOSisEmpty_r( geosinit()->ctxt,
geos.get() ) != 0 )
2951 geos.reset( GEOSDelaunayTriangulation_r( geosinit()->ctxt, mGeos.get(), tolerance, edgesOnly ) );
2953 if ( !
geos || GEOSisEmpty_r( geosinit()->ctxt,
geos.get() ) != 0 )
2965static bool _linestringEndpoints(
const GEOSGeometry *linestring,
double &x1,
double &y1,
double &x2,
double &y2 )
2967 const GEOSCoordSequence *coordSeq = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, linestring );
2971 unsigned int coordSeqSize;
2972 if ( GEOSCoordSeq_getSize_r( geosinit()->ctxt, coordSeq, &coordSeqSize ) == 0 )
2975 if ( coordSeqSize < 2 )
2978 GEOSCoordSeq_getX_r( geosinit()->ctxt, coordSeq, 0, &x1 );
2979 GEOSCoordSeq_getY_r( geosinit()->ctxt, coordSeq, 0, &y1 );
2980 GEOSCoordSeq_getX_r( geosinit()->ctxt, coordSeq, coordSeqSize - 1, &x2 );
2981 GEOSCoordSeq_getY_r( geosinit()->ctxt, coordSeq, coordSeqSize - 1, &y2 );
2987static geos::unique_ptr _mergeLinestrings(
const GEOSGeometry *line1,
const GEOSGeometry *line2,
const QgsPointXY &intersectionPoint )
2989 double x1, y1, x2, y2;
2990 if ( !_linestringEndpoints( line1, x1, y1, x2, y2 ) )
2993 double rx1, ry1, rx2, ry2;
2994 if ( !_linestringEndpoints( line2, rx1, ry1, rx2, ry2 ) )
2997 bool intersectionAtOrigLineEndpoint =
2998 ( intersectionPoint.
x() == x1 && intersectionPoint.
y() == y1 ) !=
2999 ( intersectionPoint.
x() == x2 && intersectionPoint.
y() == y2 );
3000 bool intersectionAtReshapeLineEndpoint =
3001 ( intersectionPoint.
x() == rx1 && intersectionPoint.
y() == ry1 ) ||
3002 ( intersectionPoint.
x() == rx2 && intersectionPoint.
y() == ry2 );
3005 if ( intersectionAtOrigLineEndpoint && intersectionAtReshapeLineEndpoint )
3009 GEOSGeometry *geoms[2] = { g1.release(), g2.release() };
3010 geos::unique_ptr multiGeom( GEOSGeom_createCollection_r( geosinit()->ctxt, GEOS_MULTILINESTRING, geoms, 2 ) );
3011 geos::unique_ptr res( GEOSLineMerge_r( geosinit()->ctxt, multiGeom.get() ) );
3021 if ( !line || !reshapeLineGeos )
3024 bool atLeastTwoIntersections =
false;
3025 bool oneIntersection =
false;
3031 geos::unique_ptr intersectGeom( GEOSIntersection_r( geosinit()->ctxt, line, reshapeLineGeos ) );
3032 if ( intersectGeom )
3034 const int geomType = GEOSGeomTypeId_r( geosinit()->ctxt, intersectGeom.get() );
3035 atLeastTwoIntersections = ( geomType == GEOS_MULTIPOINT && GEOSGetNumGeometries_r( geosinit()->ctxt, intersectGeom.get() ) > 1 )
3036 || ( geomType == GEOS_GEOMETRYCOLLECTION && GEOSGetNumGeometries_r( geosinit()->ctxt, intersectGeom.get() ) > 0 )
3037 || ( geomType == GEOS_MULTILINESTRING && GEOSGetNumGeometries_r( geosinit()->ctxt, intersectGeom.get() ) > 0 );
3039 if ( GEOSGeomTypeId_r( geosinit()->ctxt, intersectGeom.get() ) == GEOS_POINT )
3041 const GEOSCoordSequence *intersectionCoordSeq = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, intersectGeom.get() );
3043 GEOSCoordSeq_getX_r( geosinit()->ctxt, intersectionCoordSeq, 0, &xi );
3044 GEOSCoordSeq_getY_r( geosinit()->ctxt, intersectionCoordSeq, 0, &yi );
3045 oneIntersection =
true;
3050 catch ( GEOSException & )
3052 atLeastTwoIntersections =
false;
3056 if ( oneIntersection )
3057 return _mergeLinestrings( line, reshapeLineGeos, oneIntersectionPoint );
3059 if ( !atLeastTwoIntersections )
3063 double x1, y1, x2, y2;
3064 if ( !_linestringEndpoints( line, x1, y1, x2, y2 ) )
3070 bool isRing =
false;
3071 if ( GEOSGeomTypeId_r( geosinit()->ctxt, line ) == GEOS_LINEARRING
3072 || GEOSEquals_r( geosinit()->ctxt, beginLineVertex.get(), endLineVertex.get() ) == 1 )
3077 if ( !nodedGeometry )
3083 geos::unique_ptr mergedLines( GEOSLineMerge_r( geosinit()->ctxt, nodedGeometry.get() ) );
3089 int numMergedLines = GEOSGetNumGeometries_r( geosinit()->ctxt, mergedLines.get() );
3090 if ( numMergedLines < 2 )
3092 if ( numMergedLines == 1 )
3094 geos::unique_ptr result( GEOSGeom_clone_r( geosinit()->ctxt, reshapeLineGeos ) );
3101 QVector<GEOSGeometry *> resultLineParts;
3102 QVector<GEOSGeometry *> probableParts;
3104 for (
int i = 0; i < numMergedLines; ++i )
3106 const GEOSGeometry *currentGeom = GEOSGetGeometryN_r( geosinit()->ctxt, mergedLines.get(), i );
3109 bool alreadyAdded =
false;
3111 double bufferDistance = std::pow( 10.0L, geomDigits( currentGeom ) - 11 );
3112 for (
const GEOSGeometry *other : std::as_const( resultLineParts ) )
3114 GEOSHausdorffDistance_r( geosinit()->ctxt, currentGeom, other, &
distance );
3117 alreadyAdded =
true;
3124 const GEOSCoordSequence *currentCoordSeq = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, currentGeom );
3125 unsigned int currentCoordSeqSize;
3126 GEOSCoordSeq_getSize_r( geosinit()->ctxt, currentCoordSeq, ¤tCoordSeqSize );
3127 if ( currentCoordSeqSize < 2 )
3131 double xBegin, xEnd, yBegin, yEnd;
3132 GEOSCoordSeq_getX_r( geosinit()->ctxt, currentCoordSeq, 0, &xBegin );
3133 GEOSCoordSeq_getY_r( geosinit()->ctxt, currentCoordSeq, 0, &yBegin );
3134 GEOSCoordSeq_getX_r( geosinit()->ctxt, currentCoordSeq, currentCoordSeqSize - 1, &xEnd );
3135 GEOSCoordSeq_getY_r( geosinit()->ctxt, currentCoordSeq, currentCoordSeqSize - 1, &yEnd );
3140 int nEndpointsOnOriginalLine = 0;
3141 if ( pointContainedInLine( beginCurrentGeomVertex.get(), line ) == 1 )
3142 nEndpointsOnOriginalLine += 1;
3144 if ( pointContainedInLine( endCurrentGeomVertex.get(), line ) == 1 )
3145 nEndpointsOnOriginalLine += 1;
3148 int nEndpointsSameAsOriginalLine = 0;
3149 if ( GEOSEquals_r( geosinit()->ctxt, beginCurrentGeomVertex.get(), beginLineVertex.get() ) == 1
3150 || GEOSEquals_r( geosinit()->ctxt, beginCurrentGeomVertex.get(), endLineVertex.get() ) == 1 )
3151 nEndpointsSameAsOriginalLine += 1;
3153 if ( GEOSEquals_r( geosinit()->ctxt, endCurrentGeomVertex.get(), beginLineVertex.get() ) == 1
3154 || GEOSEquals_r( geosinit()->ctxt, endCurrentGeomVertex.get(), endLineVertex.get() ) == 1 )
3155 nEndpointsSameAsOriginalLine += 1;
3158 bool currentGeomOverlapsOriginalGeom =
false;
3159 bool currentGeomOverlapsReshapeLine =
false;
3160 if ( lineContainedInLine( currentGeom, line ) == 1 )
3161 currentGeomOverlapsOriginalGeom =
true;
3163 if ( lineContainedInLine( currentGeom, reshapeLineGeos ) == 1 )
3164 currentGeomOverlapsReshapeLine =
true;
3167 if ( !isRing && nEndpointsSameAsOriginalLine == 1 && nEndpointsOnOriginalLine == 2 && currentGeomOverlapsOriginalGeom )
3169 resultLineParts.push_back( GEOSGeom_clone_r( geosinit()->ctxt, currentGeom ) );
3172 else if ( isRing && nEndpointsOnOriginalLine == 2 && currentGeomOverlapsOriginalGeom )
3174 probableParts.push_back( GEOSGeom_clone_r( geosinit()->ctxt, currentGeom ) );
3176 else if ( nEndpointsOnOriginalLine == 2 && !currentGeomOverlapsOriginalGeom )
3178 resultLineParts.push_back( GEOSGeom_clone_r( geosinit()->ctxt, currentGeom ) );
3180 else if ( nEndpointsSameAsOriginalLine == 2 && !currentGeomOverlapsOriginalGeom )
3182 resultLineParts.push_back( GEOSGeom_clone_r( geosinit()->ctxt, currentGeom ) );
3184 else if ( currentGeomOverlapsOriginalGeom && currentGeomOverlapsReshapeLine )
3186 resultLineParts.push_back( GEOSGeom_clone_r( geosinit()->ctxt, currentGeom ) );
3191 if ( isRing && !probableParts.isEmpty() )
3194 GEOSGeometry *currentGeom =
nullptr;
3195 double maxLength = -std::numeric_limits<double>::max();
3196 double currentLength = 0;
3197 for (
int i = 0; i < probableParts.size(); ++i )
3199 currentGeom = probableParts.at( i );
3200 GEOSLength_r( geosinit()->ctxt, currentGeom, ¤tLength );
3201 if ( currentLength > maxLength )
3203 maxLength = currentLength;
3204 maxGeom.reset( currentGeom );
3208 GEOSGeom_destroy_r( geosinit()->ctxt, currentGeom );
3211 resultLineParts.push_back( maxGeom.release() );
3215 if ( resultLineParts.empty() )
3218 if ( resultLineParts.size() == 1 )
3220 result.reset( resultLineParts[0] );
3224 GEOSGeometry **lineArray =
new GEOSGeometry*[resultLineParts.size()];
3225 for (
int i = 0; i < resultLineParts.size(); ++i )
3227 lineArray[i] = resultLineParts[i];
3231 geos::unique_ptr multiLineGeom( GEOSGeom_createCollection_r( geosinit()->ctxt, GEOS_MULTILINESTRING, lineArray, resultLineParts.size() ) );
3232 delete [] lineArray;
3235 result.reset( GEOSLineMerge_r( geosinit()->ctxt, multiLineGeom.get() ) );
3239 if ( GEOSGeomTypeId_r( geosinit()->ctxt, result.get() ) != GEOS_LINESTRING )
3247geos::unique_ptr QgsGeos::reshapePolygon(
const GEOSGeometry *polygon,
const GEOSGeometry *reshapeLineGeos,
double precision )
3250 int nIntersections = 0;
3251 int lastIntersectingRing = -2;
3252 const GEOSGeometry *lastIntersectingGeom =
nullptr;
3254 int nRings = GEOSGetNumInteriorRings_r( geosinit()->ctxt, polygon );
3259 const GEOSGeometry *outerRing = GEOSGetExteriorRing_r( geosinit()->ctxt, polygon );
3260 if ( GEOSIntersects_r( geosinit()->ctxt, outerRing, reshapeLineGeos ) == 1 )
3263 lastIntersectingRing = -1;
3264 lastIntersectingGeom = outerRing;
3268 const GEOSGeometry **innerRings =
new const GEOSGeometry*[nRings];
3272 for (
int i = 0; i < nRings; ++i )
3274 innerRings[i] = GEOSGetInteriorRingN_r( geosinit()->ctxt, polygon, i );
3275 if ( GEOSIntersects_r( geosinit()->ctxt, innerRings[i], reshapeLineGeos ) == 1 )
3278 lastIntersectingRing = i;
3279 lastIntersectingGeom = innerRings[i];
3283 catch ( GEOSException & )
3288 if ( nIntersections != 1 )
3290 delete [] innerRings;
3296 if ( !reshapeResult )
3298 delete [] innerRings;
3303 GEOSGeometry *newRing =
nullptr;
3304 const GEOSCoordSequence *reshapeSequence = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, reshapeResult.get() );
3305 GEOSCoordSequence *newCoordSequence = GEOSCoordSeq_clone_r( geosinit()->ctxt, reshapeSequence );
3307 reshapeResult.reset();
3309 newRing = GEOSGeom_createLinearRing_r( geosinit()->ctxt, newCoordSequence );
3312 delete [] innerRings;
3316 GEOSGeometry *newOuterRing =
nullptr;
3317 if ( lastIntersectingRing == -1 )
3318 newOuterRing = newRing;
3320 newOuterRing = GEOSGeom_clone_r( geosinit()->ctxt, outerRing );
3323 QVector<GEOSGeometry *> ringList;
3326 GEOSGeometry *outerRingPoly = GEOSGeom_createPolygon_r( geosinit()->ctxt, GEOSGeom_clone_r( geosinit()->ctxt, newOuterRing ),
nullptr, 0 );
3327 if ( outerRingPoly )
3329 ringList.reserve( nRings );
3330 GEOSGeometry *currentRing =
nullptr;
3331 for (
int i = 0; i < nRings; ++i )
3333 if ( lastIntersectingRing == i )
3334 currentRing = newRing;
3336 currentRing = GEOSGeom_clone_r( geosinit()->ctxt, innerRings[i] );
3339 if ( GEOSContains_r( geosinit()->ctxt, outerRingPoly, currentRing ) == 1 )
3340 ringList.push_back( currentRing );
3342 GEOSGeom_destroy_r( geosinit()->ctxt, currentRing );
3345 GEOSGeom_destroy_r( geosinit()->ctxt, outerRingPoly );
3348 GEOSGeometry **newInnerRings =
new GEOSGeometry*[ringList.size()];
3349 for (
int i = 0; i < ringList.size(); ++i )
3350 newInnerRings[i] = ringList.at( i );
3352 delete [] innerRings;
3354 geos::unique_ptr reshapedPolygon( GEOSGeom_createPolygon_r( geosinit()->ctxt, newOuterRing, newInnerRings, ringList.size() ) );
3355 delete[] newInnerRings;
3357 return reshapedPolygon;
3360int QgsGeos::lineContainedInLine(
const GEOSGeometry *line1,
const GEOSGeometry *line2 )
3362 if ( !line1 || !line2 )
3367 double bufferDistance = std::pow( 10.0L, geomDigits( line2 ) - 11 );
3373 geos::unique_ptr intersectionGeom( GEOSIntersection_r( geosinit()->ctxt, bufferGeom.get(), line1 ) );
3376 double intersectGeomLength;
3379 GEOSLength_r( geosinit()->ctxt, intersectionGeom.get(), &intersectGeomLength );
3380 GEOSLength_r( geosinit()->ctxt, line1, &line1Length );
3382 double intersectRatio = line1Length / intersectGeomLength;
3383 if ( intersectRatio > 0.9 && intersectRatio < 1.1 )
3389int QgsGeos::pointContainedInLine(
const GEOSGeometry *point,
const GEOSGeometry *line )
3391 if ( !point || !line )
3394 double bufferDistance = std::pow( 10.0L, geomDigits( line ) - 11 );
3396 geos::unique_ptr lineBuffer( GEOSBuffer_r( geosinit()->ctxt, line, bufferDistance, 8 ) );
3400 bool contained =
false;
3401 if ( GEOSContains_r( geosinit()->ctxt, lineBuffer.get(), point ) == 1 )
3407int QgsGeos::geomDigits(
const GEOSGeometry *geom )
3413 const GEOSGeometry *bBoxRing = GEOSGetExteriorRing_r( geosinit()->ctxt, bbox.get() );
3417 const GEOSCoordSequence *bBoxCoordSeq = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, bBoxRing );
3419 if ( !bBoxCoordSeq )
3422 unsigned int nCoords = 0;
3423 if ( !GEOSCoordSeq_getSize_r( geosinit()->ctxt, bBoxCoordSeq, &nCoords ) )
3427 for (
unsigned int i = 0; i < nCoords - 1; ++i )
3430 GEOSCoordSeq_getX_r( geosinit()->ctxt, bBoxCoordSeq, i, &t );
3433 digits = std::ceil( std::log10( std::fabs( t ) ) );
3434 if ( digits > maxDigits )
3437 GEOSCoordSeq_getY_r( geosinit()->ctxt, bBoxCoordSeq, i, &t );
3438 digits = std::ceil( std::log10( std::fabs( t ) ) );
3439 if ( digits > maxDigits )
3448 return geosinit()->ctxt;
The Qgis class provides global constants for use throughout the application.
BufferSide
Side of line to buffer.
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.
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...
Abstract base class for all geometries.
bool is3D() const SIP_HOLDGIL
Returns true if the geometry is 3D and contains a z-value.
virtual QgsRectangle boundingBox() const =0
Returns the minimal bounding box for the geometry.
virtual bool isEmpty() const
Returns true if the geometry is empty.
QgsWkbTypes::Type wkbType() const SIP_HOLDGIL
Returns the WKB type of the geometry.
virtual int dimension() const =0
Returns the inherent dimension of the geometry.
bool isMeasure() const SIP_HOLDGIL
Returns true if the geometry contains m values.
virtual QgsAbstractGeometry * clone() const =0
Clones the geometry by performing a deep copy.
Curve polygon geometry type.
const QgsCurve * interiorRing(int i) const SIP_HOLDGIL
Retrieves an interior ring from the curve polygon.
const QgsCurve * exteriorRing() const SIP_HOLDGIL
Returns the curve polygon's exterior ring.
int numInteriorRings() const SIP_HOLDGIL
Returns the number of interior rings contained with 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(QgsWkbTypes::Type 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.
const QgsAbstractGeometry * constGet() const SIP_HOLDGIL
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
QgsAbstractGeometry * get()
Returns a modifiable (non-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...
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.
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.
QgsGeos(const QgsAbstractGeometry *geometry, double precision=0)
GEOS geometry engine constructor.
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
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.
static GEOSContextHandle_t getGEOSHandler()
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...
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.
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 SIP_HOLDGIL
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 SIP_HOLDGIL
Returns the Cartesian 2D distance between this point and a specified x, y coordinate.
A rectangle specified with double values.
double yMaximum() const SIP_HOLDGIL
Returns the y maximum value (top side of rectangle).
double xMaximum() const SIP_HOLDGIL
Returns the x maximum value (right side of rectangle).
double xMinimum() const SIP_HOLDGIL
Returns the x minimum value (left side of rectangle).
double yMinimum() const SIP_HOLDGIL
Returns the y minimum value (bottom side of rectangle).
void setYMinimum(double y) SIP_HOLDGIL
Set the minimum y value.
bool isNull() const
Test if the rectangle is null (all coordinates zero or after call to setMinimal()).
void setXMaximum(double x) SIP_HOLDGIL
Set the maximum x value.
void setXMinimum(double x) SIP_HOLDGIL
Set the minimum x value.
double height() const SIP_HOLDGIL
Returns the height of the rectangle.
void setYMaximum(double y) SIP_HOLDGIL
Set the maximum y value.
double width() const SIP_HOLDGIL
Returns the width of the rectangle.
bool isEmpty() const
Returns true if the rectangle is empty.
static GeometryType geometryType(Type type) SIP_HOLDGIL
Returns the geometry type for a WKB type, e.g., both MultiPolygon and CurvePolygon would have a Polyg...
static bool isMultiType(Type type) SIP_HOLDGIL
Returns true if the WKB type is a multi type.
Type
The WKB type describes the number of dimensions a geometry has.
static Type flatType(Type type) SIP_HOLDGIL
Returns the flat type for a WKB type.
Contains geos related utilities and functions.
std::unique_ptr< GEOSGeometry, GeosDeleter > unique_ptr
Scoped GEOS pointer.
std::unique_ptr< GEOSCoordSequence, GeosDeleter > coord_sequence_unique_ptr
Scoped GEOS coordinate sequence pointer.
std::unique_ptr< GEOSBufferParams, GeosDeleter > buffer_params_unique_ptr
Scoped GEOS buffer params pointer.
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
Q_GLOBAL_STATIC(QReadWriteLock, sDefinitionCacheLock)
#define DEFAULT_QUADRANT_SEGMENTS
#define CATCH_GEOS_WITH_ERRMSG(r)
QLineF segment(int index, QRectF rect, double radius)
Utility class for identifying a unique vertex within a geometry.
void CORE_EXPORT operator()(GEOSGeometry *geom) const
Destroys the GEOS geometry geom, using the static QGIS geos context.