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 );
1072 const QPair< double, QgsPoint > pair = qMakePair(
distance, *correctSegmentPoint.get() );
1073 if ( pointMap.contains( nextVertex.
vertex - 1 ) )
1074 pointMap[ nextVertex.
vertex - 1 ].append( pair );
1076 pointMap[ nextVertex.
vertex - 1 ] = QVector< QPair< double, QgsPoint > >() << pair;
1081 for (
auto &p : pointMap )
1083 std::sort( p.begin(), p.end(), [](
const QPair< double, QgsPoint > &a,
const QPair< double, QgsPoint > &b ) { return a.first < b.first; } );
1090 for (
int j = 0; j < nVertices; ++j )
1094 if ( pointMap.contains( j ) )
1097 for (
int k = 0; k < pointMap[ j ].size(); ++k )
1099 splitPoint = pointMap[ j ][k].second;
1100 if ( splitPoint == currentPoint )
1106 else if ( splitPoint == line->
pointN( j + 1 ) )
1125 return asGeos( &lines, mPrecision );
1130 Q_UNUSED( skipIntersectionCheck )
1137 geos::unique_ptr intersectGeom( GEOSIntersection_r( geosinit()->ctxt, splitLine, mGeos.get() ) );
1138 if ( !intersectGeom || GEOSisEmpty_r( geosinit()->ctxt, intersectGeom.get() ) )
1142 int linearIntersect = GEOSRelatePattern_r( geosinit()->ctxt, mGeos.get(), splitLine,
"1********" );
1143 if ( linearIntersect > 0 )
1147 splitGeom = linePointDifference( intersectGeom.get() );
1152 QVector<GEOSGeometry *> lineGeoms;
1154 int splitType = GEOSGeomTypeId_r( geosinit()->ctxt, splitGeom.get() );
1155 if ( splitType == GEOS_MULTILINESTRING )
1157 int nGeoms = GEOSGetNumGeometries_r( geosinit()->ctxt, splitGeom.get() );
1158 lineGeoms.reserve( nGeoms );
1159 for (
int i = 0; i < nGeoms; ++i )
1160 lineGeoms << GEOSGeom_clone_r( geosinit()->ctxt, GEOSGetGeometryN_r( geosinit()->ctxt, splitGeom.get(), i ) );
1165 lineGeoms << GEOSGeom_clone_r( geosinit()->ctxt, splitGeom.get() );
1168 mergeGeometriesMultiTypeSplit( lineGeoms );
1170 for (
int i = 0; i < lineGeoms.size(); ++i )
1173 GEOSGeom_destroy_r( geosinit()->ctxt, lineGeoms[i] );
1189 if ( !mGeosPrepared )
1193 if ( !skipIntersectionCheck && !GEOSPreparedIntersects_r( geosinit()->ctxt, mGeosPrepared.get(), splitLine ) )
1198 if ( !nodedGeometry )
1201 const GEOSGeometry *noded = nodedGeometry.get();
1202 geos::unique_ptr polygons( GEOSPolygonize_r( geosinit()->ctxt, &noded, 1 ) );
1203 if ( !polygons || numberOfGeometries( polygons.get() ) == 0 )
1210 QVector<GEOSGeometry *> testedGeometries;
1215 for (
int i = 0; i < numberOfGeometries( polygons.get() ); i++ )
1217 const GEOSGeometry *polygon = GEOSGetGeometryN_r( geosinit()->ctxt, polygons.get(), i );
1221 testedGeometries << GEOSGeom_clone_r( geosinit()->ctxt, polygon );
1224 int nGeometriesThis = numberOfGeometries( mGeos.get() );
1225 if ( testedGeometries.empty() || testedGeometries.size() == nGeometriesThis )
1228 for (
int i = 0; i < testedGeometries.size(); ++i )
1230 GEOSGeom_destroy_r( geosinit()->ctxt, testedGeometries[i] );
1239 mergeGeometriesMultiTypeSplit( testedGeometries );
1242 for ( i = 0; i < testedGeometries.size() && GEOSisValid_r( geosinit()->ctxt, testedGeometries[i] ); ++i )
1245 if ( i < testedGeometries.size() )
1247 for ( i = 0; i < testedGeometries.size(); ++i )
1248 GEOSGeom_destroy_r( geosinit()->ctxt, testedGeometries[i] );
1253 for ( i = 0; i < testedGeometries.size(); ++i )
1256 GEOSGeom_destroy_r( geosinit()->ctxt, testedGeometries[i] );
1262geos::unique_ptr QgsGeos::nodeGeometries(
const GEOSGeometry *splitLine,
const GEOSGeometry *geom )
1264 if ( !splitLine || !geom )
1268 if ( GEOSGeomTypeId_r( geosinit()->ctxt, geom ) == GEOS_POLYGON || GEOSGeomTypeId_r( geosinit()->ctxt, geom ) == GEOS_MULTIPOLYGON )
1269 geometryBoundary.reset( GEOSBoundary_r( geosinit()->ctxt, geom ) );
1271 geometryBoundary.reset( GEOSGeom_clone_r( geosinit()->ctxt, geom ) );
1273 geos::unique_ptr splitLineClone( GEOSGeom_clone_r( geosinit()->ctxt, splitLine ) );
1274 geos::unique_ptr unionGeometry( GEOSUnion_r( geosinit()->ctxt, splitLineClone.get(), geometryBoundary.get() ) );
1276 return unionGeometry;
1279int QgsGeos::mergeGeometriesMultiTypeSplit( QVector<GEOSGeometry *> &splitResult )
const
1285 int type = GEOSGeomTypeId_r( geosinit()->ctxt, mGeos.get() );
1286 if ( type != GEOS_GEOMETRYCOLLECTION &&
1287 type != GEOS_MULTILINESTRING &&
1288 type != GEOS_MULTIPOLYGON &&
1289 type != GEOS_MULTIPOINT )
1292 QVector<GEOSGeometry *> copyList = splitResult;
1293 splitResult.clear();
1296 QVector<GEOSGeometry *> unionGeom;
1298 for (
int i = 0; i < copyList.size(); ++i )
1301 bool isPart =
false;
1302 for (
int j = 0; j < GEOSGetNumGeometries_r( geosinit()->ctxt, mGeos.get() ); j++ )
1304 if ( GEOSEquals_r( geosinit()->ctxt, copyList[i], GEOSGetGeometryN_r( geosinit()->ctxt, mGeos.get(), j ) ) )
1313 unionGeom << copyList[i];
1317 QVector<GEOSGeometry *> geomVector;
1318 geomVector << copyList[i];
1320 if ( type == GEOS_MULTILINESTRING )
1321 splitResult << createGeosCollection( GEOS_MULTILINESTRING, geomVector ).release();
1322 else if ( type == GEOS_MULTIPOLYGON )
1323 splitResult << createGeosCollection( GEOS_MULTIPOLYGON, geomVector ).release();
1325 GEOSGeom_destroy_r( geosinit()->ctxt, copyList[i] );
1330 if ( !unionGeom.isEmpty() )
1332 if ( type == GEOS_MULTILINESTRING )
1333 splitResult << createGeosCollection( GEOS_MULTILINESTRING, unionGeom ).release();
1334 else if ( type == GEOS_MULTIPOLYGON )
1335 splitResult << createGeosCollection( GEOS_MULTIPOLYGON, unionGeom ).release();
1345geos::unique_ptr QgsGeos::createGeosCollection(
int typeId,
const QVector<GEOSGeometry *> &geoms )
1347 int nNullGeoms = geoms.count(
nullptr );
1348 int nNotNullGeoms = geoms.size() - nNullGeoms;
1350 GEOSGeometry **geomarr =
new GEOSGeometry*[ nNotNullGeoms ];
1357 QVector<GEOSGeometry *>::const_iterator geomIt = geoms.constBegin();
1358 for ( ; geomIt != geoms.constEnd(); ++geomIt )
1362 if ( GEOSisEmpty_r( geosinit()->ctxt, *geomIt ) )
1367 GEOSGeom_destroy_r( geosinit()->ctxt, *geomIt );
1371 geomarr[i] = *geomIt;
1380 geom.reset( GEOSGeom_createCollection_r( geosinit()->ctxt, typeId, geomarr, nNotNullGeoms ) );
1382 catch ( GEOSException & )
1398 int nCoordDims = GEOSGeom_getCoordinateDimension_r( geosinit()->ctxt,
geos );
1399 int nDims = GEOSGeom_getDimensions_r( geosinit()->ctxt,
geos );
1400 bool hasZ = ( nCoordDims == 3 );
1401 bool hasM = ( ( nDims - nCoordDims ) == 1 );
1403 switch ( GEOSGeomTypeId_r( geosinit()->ctxt,
geos ) )
1407 if ( GEOSisEmpty_r( geosinit()->ctxt,
geos ) )
1410 const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq_r( geosinit()->ctxt,
geos );
1411 unsigned int nPoints = 0;
1412 GEOSCoordSeq_getSize_r( geosinit()->ctxt, cs, &nPoints );
1413 return nPoints > 0 ? std::unique_ptr<QgsAbstractGeometry>(
coordSeqPoint( cs, 0, hasZ, hasM ).clone() ) :
nullptr;
1415 case GEOS_LINESTRING:
1417 return sequenceToLinestring(
geos, hasZ, hasM );
1423 case GEOS_MULTIPOINT:
1425 std::unique_ptr< QgsMultiPoint > multiPoint(
new QgsMultiPoint() );
1426 int nParts = GEOSGetNumGeometries_r( geosinit()->ctxt,
geos );
1427 multiPoint->reserve( nParts );
1428 for (
int i = 0; i < nParts; ++i )
1430 const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, GEOSGetGeometryN_r( geosinit()->ctxt,
geos, i ) );
1433 unsigned int nPoints = 0;
1434 GEOSCoordSeq_getSize_r( geosinit()->ctxt, cs, &nPoints );
1436 multiPoint->addGeometry(
coordSeqPoint( cs, 0, hasZ, hasM ).clone() );
1439 return std::move( multiPoint );
1441 case GEOS_MULTILINESTRING:
1444 int nParts = GEOSGetNumGeometries_r( geosinit()->ctxt,
geos );
1445 multiLineString->reserve( nParts );
1446 for (
int i = 0; i < nParts; ++i )
1448 std::unique_ptr< QgsLineString >line( sequenceToLinestring( GEOSGetGeometryN_r( geosinit()->ctxt,
geos, i ), hasZ, hasM ) );
1451 multiLineString->addGeometry( line.release() );
1454 return std::move( multiLineString );
1456 case GEOS_MULTIPOLYGON:
1458 std::unique_ptr< QgsMultiPolygon > multiPolygon(
new QgsMultiPolygon() );
1460 int nParts = GEOSGetNumGeometries_r( geosinit()->ctxt,
geos );
1461 multiPolygon->reserve( nParts );
1462 for (
int i = 0; i < nParts; ++i )
1464 std::unique_ptr< QgsPolygon > poly =
fromGeosPolygon( GEOSGetGeometryN_r( geosinit()->ctxt,
geos, i ) );
1467 multiPolygon->addGeometry( poly.release() );
1470 return std::move( multiPolygon );
1472 case GEOS_GEOMETRYCOLLECTION:
1475 int nParts = GEOSGetNumGeometries_r( geosinit()->ctxt,
geos );
1476 geomCollection->reserve( nParts );
1477 for (
int i = 0; i < nParts; ++i )
1479 std::unique_ptr< QgsAbstractGeometry > geom(
fromGeos( GEOSGetGeometryN_r( geosinit()->ctxt,
geos, i ) ) );
1482 geomCollection->addGeometry( geom.release() );
1485 return std::move( geomCollection );
1493 if ( GEOSGeomTypeId_r( geosinit()->ctxt,
geos ) != GEOS_POLYGON )
1498 int nCoordDims = GEOSGeom_getCoordinateDimension_r( geosinit()->ctxt,
geos );
1499 int nDims = GEOSGeom_getDimensions_r( geosinit()->ctxt,
geos );
1500 bool hasZ = ( nCoordDims == 3 );
1501 bool hasM = ( ( nDims - nCoordDims ) == 1 );
1503 std::unique_ptr< QgsPolygon > polygon(
new QgsPolygon() );
1505 const GEOSGeometry *ring = GEOSGetExteriorRing_r( geosinit()->ctxt,
geos );
1508 polygon->setExteriorRing( sequenceToLinestring( ring, hasZ, hasM ).release() );
1511 QVector<QgsCurve *> interiorRings;
1512 const int ringCount = GEOSGetNumInteriorRings_r( geosinit()->ctxt,
geos );
1513 interiorRings.reserve( ringCount );
1514 for (
int i = 0; i < ringCount; ++i )
1516 ring = GEOSGetInteriorRingN_r( geosinit()->ctxt,
geos, i );
1519 interiorRings.push_back( sequenceToLinestring( ring, hasZ, hasM ).release() );
1522 polygon->setInteriorRings( interiorRings );
1527std::unique_ptr<QgsLineString> QgsGeos::sequenceToLinestring(
const GEOSGeometry *
geos,
bool hasZ,
bool hasM )
1529 const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq_r( geosinit()->ctxt,
geos );
1531 unsigned int nPoints;
1532 GEOSCoordSeq_getSize_r( geosinit()->ctxt, cs, &nPoints );
1534 QVector< double > xOut( nPoints );
1535 QVector< double > yOut( nPoints );
1536 QVector< double > zOut;
1538 zOut.resize( nPoints );
1539 QVector< double > mOut;
1541 mOut.resize( nPoints );
1543 double *x = xOut.data();
1544 double *y = yOut.data();
1545 double *z = zOut.data();
1546 double *m = mOut.data();
1548#if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=10 )
1549 GEOSCoordSeq_copyToArrays_r( geosinit()->ctxt, cs, x, y, hasZ ? z :
nullptr, hasM ? m :
nullptr );
1551 for (
unsigned int i = 0; i < nPoints; ++i )
1554 GEOSCoordSeq_getXYZ_r( geosinit()->ctxt, cs, i, x++, y++, z++ );
1556 GEOSCoordSeq_getXY_r( geosinit()->ctxt, cs, i, x++, y++ );
1559 GEOSCoordSeq_getOrdinate_r( geosinit()->ctxt, cs, i, 3, m++ );
1563 std::unique_ptr< QgsLineString > line(
new QgsLineString( xOut, yOut, zOut, mOut ) );
1567int QgsGeos::numberOfGeometries( GEOSGeometry *g )
1572 int geometryType = GEOSGeomTypeId_r( geosinit()->ctxt, g );
1573 if ( geometryType == GEOS_POINT || geometryType == GEOS_LINESTRING || geometryType == GEOS_LINEARRING
1574 || geometryType == GEOS_POLYGON )
1578 return GEOSGetNumGeometries_r( geosinit()->ctxt, g );
1592 GEOSCoordSeq_getXYZ_r( geosinit()->ctxt, cs, i, &x, &y, &z );
1594 GEOSCoordSeq_getXY_r( geosinit()->ctxt, cs, i, &x, &y );
1597 GEOSCoordSeq_getOrdinate_r( geosinit()->ctxt, cs, i, 3, &m );
1633 int geosType = GEOS_GEOMETRYCOLLECTION;
1639 case Qgis::GeometryType::Point:
1640 geosType = GEOS_MULTIPOINT;
1643 case Qgis::GeometryType::Line:
1644 geosType = GEOS_MULTILINESTRING;
1647 case Qgis::GeometryType::Polygon:
1648 geosType = GEOS_MULTIPOLYGON;
1651 case Qgis::GeometryType::Unknown:
1652 case Qgis::GeometryType::Null:
1663 QVector< GEOSGeometry * > geomVector(
c->numGeometries() );
1664 for (
int i = 0; i <
c->numGeometries(); ++i )
1668 return createGeosCollection( geosType, geomVector );
1674 case Qgis::GeometryType::Point:
1675 return createGeosPoint(
static_cast<const QgsPoint *
>( geom ), coordDims,
precision );
1677 case Qgis::GeometryType::Line:
1680 case Qgis::GeometryType::Polygon:
1683 case Qgis::GeometryType::Unknown:
1684 case Qgis::GeometryType::Null:
1693 if ( !mGeos || !geom )
1704 const double gridSize = parameters.
gridSize();
1711 case OverlayIntersection:
1714 opGeom.reset( GEOSIntersectionPrec_r( geosinit()->ctxt, mGeos.get(), geosGeom.get(), gridSize ) );
1718 opGeom.reset( GEOSIntersection_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) );
1722 case OverlayDifference:
1725 opGeom.reset( GEOSDifferencePrec_r( geosinit()->ctxt, mGeos.get(), geosGeom.get(), gridSize ) );
1729 opGeom.reset( GEOSDifference_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) );
1738 unionGeometry.reset( GEOSUnionPrec_r( geosinit()->ctxt, mGeos.get(), geosGeom.get(), gridSize ) );
1742 unionGeometry.reset( GEOSUnion_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) );
1745 if ( unionGeometry && GEOSGeomTypeId_r( geosinit()->ctxt, unionGeometry.get() ) == GEOS_MULTILINESTRING )
1747 geos::unique_ptr mergedLines( GEOSLineMerge_r( geosinit()->ctxt, unionGeometry.get() ) );
1750 unionGeometry = std::move( mergedLines );
1754 opGeom = std::move( unionGeometry );
1758 case OverlaySymDifference:
1761 opGeom.reset( GEOSSymDifferencePrec_r( geosinit()->ctxt, mGeos.get(), geosGeom.get(), gridSize ) );
1765 opGeom.reset( GEOSSymDifference_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) );
1771 catch ( GEOSException &e )
1773 logError( QStringLiteral(
"GEOS" ), e.what() );
1776 *errorMsg = e.what();
1782bool QgsGeos::relation(
const QgsAbstractGeometry *geom, Relation r, QString *errorMsg )
const
1784 if ( !mGeos || !geom )
1795 bool result =
false;
1798 if ( mGeosPrepared )
1802 case RelationIntersects:
1803 result = ( GEOSPreparedIntersects_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1805 case RelationTouches:
1806 result = ( GEOSPreparedTouches_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1808 case RelationCrosses:
1809 result = ( GEOSPreparedCrosses_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1811 case RelationWithin:
1812 result = ( GEOSPreparedWithin_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1814 case RelationContains:
1815 result = ( GEOSPreparedContains_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1817 case RelationDisjoint:
1818 result = ( GEOSPreparedDisjoint_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1820 case RelationOverlaps:
1821 result = ( GEOSPreparedOverlaps_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1829 case RelationIntersects:
1830 result = ( GEOSIntersects_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1832 case RelationTouches:
1833 result = ( GEOSTouches_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1835 case RelationCrosses:
1836 result = ( GEOSCrosses_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1838 case RelationWithin:
1839 result = ( GEOSWithin_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1841 case RelationContains:
1842 result = ( GEOSContains_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1844 case RelationDisjoint:
1845 result = ( GEOSDisjoint_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1847 case RelationOverlaps:
1848 result = ( GEOSOverlaps_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1852 catch ( GEOSException &e )
1854 logError( QStringLiteral(
"GEOS" ), e.what() );
1857 *errorMsg = e.what();
1875 geos.reset( GEOSBuffer_r( geosinit()->ctxt, mGeos.get(),
distance, segments ) );
1891 geos.reset( GEOSBufferWithStyle_r( geosinit()->ctxt, mGeos.get(),
distance, segments,
static_cast< int >( endCapStyle ),
static_cast< int >( joinStyle ), miterLimit ) );
1906 geos.reset( GEOSTopologyPreserveSimplify_r( geosinit()->ctxt, mGeos.get(), tolerance ) );
1921 geos.reset( GEOSInterpolate_r( geosinit()->ctxt, mGeos.get(),
distance ) );
1940 geos.reset( GEOSGetCentroid_r( geosinit()->ctxt, mGeos.get() ) );
1945 GEOSGeomGetX_r( geosinit()->ctxt,
geos.get(), &x );
1946 GEOSGeomGetY_r( geosinit()->ctxt,
geos.get(), &y );
1962 geos.reset( GEOSEnvelope_r( geosinit()->ctxt, mGeos.get() ) );
1981 geos.reset( GEOSPointOnSurface_r( geosinit()->ctxt, mGeos.get() ) );
1983 if ( !
geos || GEOSisEmpty_r( geosinit()->ctxt,
geos.get() ) != 0 )
1988 GEOSGeomGetX_r( geosinit()->ctxt,
geos.get(), &x );
1989 GEOSGeomGetY_r( geosinit()->ctxt,
geos.get(), &y );
2005 geos::unique_ptr cHull( GEOSConvexHull_r( geosinit()->ctxt, mGeos.get() ) );
2006 std::unique_ptr< QgsAbstractGeometry > cHullGeom =
fromGeos( cHull.get() );
2007 return cHullGeom.release();
2014#if GEOS_VERSION_MAJOR==3 && GEOS_VERSION_MINOR<11
2016 ( void )targetPercent;
2018 throw QgsNotSupportedException( QObject::tr(
"Calculating concaveHull requires a QGIS build based on GEOS 3.11 or later" ) );
2029 return concaveHullGeom.release();
2044 GEOSGeometry *g1 =
nullptr;
2046 char res = GEOSisValidDetail_r( geosinit()->ctxt, mGeos.get(), allowSelfTouchingHoles ? GEOSVALID_ALLOW_SELFTOUCHING_RING_FORMING_HOLE : 0, &r, &g1 );
2047 const bool invalid = res != 1;
2052 error = QString( r );
2053 GEOSFree_r( geosinit()->ctxt, r );
2056 if ( invalid && errorMsg )
2060 if ( translatedErrors.empty() )
2063 translatedErrors.insert( QStringLiteral(
"topology validation error" ), QObject::tr(
"Topology validation error",
"GEOS Error" ) );
2064 translatedErrors.insert( QStringLiteral(
"repeated point" ), QObject::tr(
"Repeated point",
"GEOS Error" ) );
2065 translatedErrors.insert( QStringLiteral(
"hole lies outside shell" ), QObject::tr(
"Hole lies outside shell",
"GEOS Error" ) );
2066 translatedErrors.insert( QStringLiteral(
"holes are nested" ), QObject::tr(
"Holes are nested",
"GEOS Error" ) );
2067 translatedErrors.insert( QStringLiteral(
"interior is disconnected" ), QObject::tr(
"Interior is disconnected",
"GEOS Error" ) );
2068 translatedErrors.insert( QStringLiteral(
"self-intersection" ), QObject::tr(
"Self-intersection",
"GEOS Error" ) );
2069 translatedErrors.insert( QStringLiteral(
"ring self-intersection" ), QObject::tr(
"Ring self-intersection",
"GEOS Error" ) );
2070 translatedErrors.insert( QStringLiteral(
"nested shells" ), QObject::tr(
"Nested shells",
"GEOS Error" ) );
2071 translatedErrors.insert( QStringLiteral(
"duplicate rings" ), QObject::tr(
"Duplicate rings",
"GEOS Error" ) );
2072 translatedErrors.insert( QStringLiteral(
"too few points in geometry component" ), QObject::tr(
"Too few points in geometry component",
"GEOS Error" ) );
2073 translatedErrors.insert( QStringLiteral(
"invalid coordinate" ), QObject::tr(
"Invalid coordinate",
"GEOS Error" ) );
2074 translatedErrors.insert( QStringLiteral(
"ring is not closed" ), QObject::tr(
"Ring is not closed",
"GEOS Error" ) );
2077 *errorMsg = translatedErrors.value( error.toLower(), error );
2079 if ( g1 && errorLoc )
2085 GEOSGeom_destroy_r( geosinit()->ctxt, g1 );
2095 if ( !mGeos || !geom )
2107 bool equal = GEOSEquals_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() );
2122 return GEOSisEmpty_r( geosinit()->ctxt, mGeos.get() );
2136 return GEOSisSimple_r( geosinit()->ctxt, mGeos.get() );
2141GEOSCoordSequence *QgsGeos::createCoordinateSequence(
const QgsCurve *curve,
double precision,
bool forceClose )
2143 GEOSContextHandle_t ctxt = geosinit()->ctxt;
2145 std::unique_ptr< QgsLineString > segmentized;
2146 const QgsLineString *line = qgsgeometry_cast<const QgsLineString *>( curve );
2151 line = segmentized.get();
2158 GEOSCoordSequence *coordSeq =
nullptr;
2160 const int numPoints = line->
numPoints();
2162 const bool hasZ = line->
is3D();
2164#if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=10 )
2167 if ( !forceClose || ( line->
pointN( 0 ) == line->
pointN( numPoints - 1 ) ) )
2172 coordSeq = GEOSCoordSeq_copyFromArrays_r( ctxt, line->
xData(), line->
yData(), line->
zData(),
nullptr, numPoints );
2175 QgsDebugMsg( QStringLiteral(
"GEOS Exception: Could not create coordinate sequence for %1 points" ).arg( numPoints ) );
2183 QVector< double > x = line->
xVector();
2184 if ( numPoints > 0 )
2185 x.append( x.at( 0 ) );
2186 QVector< double > y = line->
yVector();
2187 if ( numPoints > 0 )
2188 y.append( y.at( 0 ) );
2189 QVector< double > z = line->
zVector();
2190 if ( hasZ && numPoints > 0 )
2191 z.append( z.at( 0 ) );
2194 coordSeq = GEOSCoordSeq_copyFromArrays_r( ctxt, x.constData(), y.constData(), !hasZ ?
nullptr : z.constData(),
nullptr, numPoints + 1 );
2197 QgsDebugMsg( QStringLiteral(
"GEOS Exception: Could not create closed coordinate sequence for %1 points" ).arg( numPoints + 1 ) );
2208 const bool hasM =
false;
2219 int numOutPoints = numPoints;
2220 if ( forceClose && ( line->
pointN( 0 ) != line->
pointN( numPoints - 1 ) ) )
2227 coordSeq = GEOSCoordSeq_create_r( ctxt, numOutPoints, coordDims );
2230 QgsDebugMsg( QStringLiteral(
"GEOS Exception: Could not create coordinate sequence for %1 points in %2 dimensions" ).arg( numPoints ).arg( coordDims ) );
2234 const double *xData = line->
xData();
2235 const double *yData = line->
yData();
2236 const double *zData = hasZ ? line->
zData() :
nullptr;
2237 const double *mData = hasM ? line->
mData() :
nullptr;
2241 for (
int i = 0; i < numOutPoints; ++i )
2243 if ( i >= numPoints )
2246 xData = line->
xData();
2247 yData = line->
yData();
2248 zData = hasZ ? line->
zData() :
nullptr;
2249 mData = hasM ? line->
mData() :
nullptr;
2261 GEOSCoordSeq_setOrdinate_r( ctxt, coordSeq, i, 3, *mData++ );
2267 for (
int i = 0; i < numOutPoints; ++i )
2269 if ( i >= numPoints )
2272 xData = line->
xData();
2273 yData = line->
yData();
2274 zData = hasZ ? line->
zData() :
nullptr;
2275 mData = hasM ? line->
mData() :
nullptr;
2279 GEOSCoordSeq_setXYZ_r( ctxt, coordSeq, i, *xData++, *yData++, *zData++ );
2283 GEOSCoordSeq_setXY_r( ctxt, coordSeq, i, *xData++, *yData++ );
2287 GEOSCoordSeq_setOrdinate_r( ctxt, coordSeq, i, 3, *mData++ );
2299 const QgsPoint *pt = qgsgeometry_cast<const QgsPoint *>( point );
2306geos::unique_ptr QgsGeos::createGeosPointXY(
double x,
double y,
bool hasZ,
double z,
bool hasM,
double m,
int coordDims,
double precision )
2314 if ( coordDims == 2 )
2320 geosPoint.reset( GEOSGeom_createPointFromXY_r( geosinit()->ctxt, x, y ) );
2324 GEOSCoordSequence *coordSeq = GEOSCoordSeq_create_r( geosinit()->ctxt, 1, coordDims );
2327 QgsDebugMsg( QStringLiteral(
"GEOS Exception: Could not create coordinate sequence for point with %1 dimensions" ).arg( coordDims ) );
2332 GEOSCoordSeq_setX_r( geosinit()->ctxt, coordSeq, 0, std::round( x /
precision ) *
precision );
2333 GEOSCoordSeq_setY_r( geosinit()->ctxt, coordSeq, 0, std::round( y /
precision ) *
precision );
2336 GEOSCoordSeq_setOrdinate_r( geosinit()->ctxt, coordSeq, 0, 2, std::round( z /
precision ) *
precision );
2341 GEOSCoordSeq_setX_r( geosinit()->ctxt, coordSeq, 0, x );
2342 GEOSCoordSeq_setY_r( geosinit()->ctxt, coordSeq, 0, y );
2345 GEOSCoordSeq_setOrdinate_r( geosinit()->ctxt, coordSeq, 0, 2, z );
2351 GEOSCoordSeq_setOrdinate_r( geosinit()->ctxt, coordSeq, 0, 3, m );
2354 geosPoint.reset( GEOSGeom_createPoint_r( geosinit()->ctxt, coordSeq ) );
2362 const QgsCurve *
c = qgsgeometry_cast<const QgsCurve *>( curve );
2366 GEOSCoordSequence *coordSeq = createCoordinateSequence(
c,
precision );
2373 geosGeom.reset( GEOSGeom_createLineString_r( geosinit()->ctxt, coordSeq ) );
2381 const QgsCurvePolygon *polygon = qgsgeometry_cast<const QgsCurvePolygon *>( poly );
2386 if ( !exteriorRing )
2394 geos::unique_ptr exteriorRingGeos( GEOSGeom_createLinearRing_r( geosinit()->ctxt, createCoordinateSequence( exteriorRing,
precision,
true ) ) );
2397 GEOSGeometry **holes =
nullptr;
2400 holes =
new GEOSGeometry*[ nHoles ];
2403 for (
int i = 0; i < nHoles; ++i )
2406 holes[i] = GEOSGeom_createLinearRing_r( geosinit()->ctxt, createCoordinateSequence( interiorRing,
precision,
true ) );
2408 geosPolygon.reset( GEOSGeom_createPolygon_r( geosinit()->ctxt, exteriorRingGeos.release(), holes, nHoles ) );
2424 offset.reset( GEOSOffsetCurve_r( geosinit()->ctxt, mGeos.get(),
distance, segments,
static_cast< int >( joinStyle ), miterLimit ) );
2427 std::unique_ptr< QgsAbstractGeometry > offsetGeom =
fromGeos( offset.get() );
2428 return offsetGeom.release();
2442 GEOSBufferParams_setSingleSided_r( geosinit()->ctxt, bp.get(), 1 );
2443 GEOSBufferParams_setQuadrantSegments_r( geosinit()->ctxt, bp.get(), segments );
2444 GEOSBufferParams_setJoinStyle_r( geosinit()->ctxt, bp.get(),
static_cast< int >( joinStyle ) );
2445 GEOSBufferParams_setMitreLimit_r( geosinit()->ctxt, bp.get(), miterLimit );
2447 if ( side == Qgis::BufferSide::Right )
2451 geos.reset( GEOSBufferWithParams_r( geosinit()->ctxt, mGeos.get(), bp.get(),
distance ) );
2467 geos.reset( GEOSMaximumInscribedCircle_r( geosinit()->ctxt, mGeos.get(), tolerance ) );
2485 boundaryGeos =
asGeos( boundary );
2487 geos.reset( GEOSLargestEmptyCircle_r( geosinit()->ctxt, mGeos.get(), boundaryGeos.get(), tolerance ) );
2503 geos.reset( GEOSMinimumWidth_r( geosinit()->ctxt, mGeos.get() ) );
2513 return std::numeric_limits< double >::quiet_NaN();
2520 if ( GEOSMinimumClearance_r( geosinit()->ctxt, mGeos.get(), &res ) != 0 )
2521 return std::numeric_limits< double >::quiet_NaN();
2537 geos.reset( GEOSMinimumClearanceLine_r( geosinit()->ctxt, mGeos.get() ) );
2553 geos.reset( GEOSNode_r( geosinit()->ctxt, mGeos.get() ) );
2561 if ( !mGeos || !other )
2573 geos.reset( GEOSSharedPaths_r( geosinit()->ctxt, mGeos.get(), otherGeos.get() ) );
2593 geos::unique_ptr reshapeLineGeos = createGeosLinestring( &reshapeWithLine, mPrecision );
2596 int numGeoms = GEOSGetNumGeometries_r( geosinit()->ctxt, mGeos.get() );
2597 if ( numGeoms == -1 )
2606 bool isMultiGeom =
false;
2607 int geosTypeId = GEOSGeomTypeId_r( geosinit()->ctxt, mGeos.get() );
2608 if ( geosTypeId == GEOS_MULTILINESTRING || geosTypeId == GEOS_MULTIPOLYGON )
2618 reshapedGeometry = reshapeLine( mGeos.get(), reshapeLineGeos.get(), mPrecision );
2622 reshapedGeometry = reshapePolygon( mGeos.get(), reshapeLineGeos.get(), mPrecision );
2627 std::unique_ptr< QgsAbstractGeometry > reshapeResult =
fromGeos( reshapedGeometry.get() );
2628 return reshapeResult;
2635 bool reshapeTookPlace =
false;
2638 GEOSGeometry **newGeoms =
new GEOSGeometry*[numGeoms];
2640 for (
int i = 0; i < numGeoms; ++i )
2643 currentReshapeGeometry = reshapeLine( GEOSGetGeometryN_r( geosinit()->ctxt, mGeos.get(), i ), reshapeLineGeos.get(), mPrecision );
2645 currentReshapeGeometry = reshapePolygon( GEOSGetGeometryN_r( geosinit()->ctxt, mGeos.get(), i ), reshapeLineGeos.get(), mPrecision );
2647 if ( currentReshapeGeometry )
2649 newGeoms[i] = currentReshapeGeometry.release();
2650 reshapeTookPlace =
true;
2654 newGeoms[i] = GEOSGeom_clone_r( geosinit()->ctxt, GEOSGetGeometryN_r( geosinit()->ctxt, mGeos.get(), i ) );
2661 newMultiGeom.reset( GEOSGeom_createCollection_r( geosinit()->ctxt, GEOS_MULTILINESTRING, newGeoms, numGeoms ) );
2665 newMultiGeom.reset( GEOSGeom_createCollection_r( geosinit()->ctxt, GEOS_MULTIPOLYGON, newGeoms, numGeoms ) );
2669 if ( !newMultiGeom )
2675 if ( reshapeTookPlace )
2679 std::unique_ptr< QgsAbstractGeometry > reshapedMultiGeom =
fromGeos( newMultiGeom.get() );
2680 return reshapedMultiGeom;
2702 if ( GEOSGeomTypeId_r( geosinit()->ctxt, mGeos.get() ) != GEOS_MULTILINESTRING )
2708 geos.reset( GEOSLineMerge_r( geosinit()->ctxt, mGeos.get() ) );
2732 if ( mGeosPrepared )
2734 nearestCoord.reset( GEOSPreparedNearestPoints_r( geosinit()->ctxt, mGeosPrepared.get(), otherGeom.get() ) );
2738 nearestCoord.reset( GEOSNearestPoints_r( geosinit()->ctxt, mGeos.get(), otherGeom.get() ) );
2741 ( void )GEOSCoordSeq_getX_r( geosinit()->ctxt, nearestCoord.get(), 0, &nx );
2742 ( void )GEOSCoordSeq_getY_r( geosinit()->ctxt, nearestCoord.get(), 0, &ny );
2744 catch ( GEOSException &e )
2746 logError( QStringLiteral(
"GEOS" ), e.what() );
2749 *errorMsg = e.what();
2759 if ( !mGeos || other.
isEmpty() )
2769 if ( !other || other->
isEmpty() )
2786 if ( !nearestCoord )
2789 *errorMsg = QStringLiteral(
"GEOS returned no nearest points" );
2793 ( void )GEOSCoordSeq_getX_r( geosinit()->ctxt, nearestCoord.get(), 0, &nx1 );
2794 ( void )GEOSCoordSeq_getY_r( geosinit()->ctxt, nearestCoord.get(), 0, &ny1 );
2795 ( void )GEOSCoordSeq_getX_r( geosinit()->ctxt, nearestCoord.get(), 1, &nx2 );
2796 ( void )GEOSCoordSeq_getY_r( geosinit()->ctxt, nearestCoord.get(), 1, &ny2 );
2798 catch ( GEOSException &e )
2800 logError( QStringLiteral(
"GEOS" ), e.what() );
2803 *errorMsg = e.what();
2830 distance = GEOSProject_r( geosinit()->ctxt, mGeos.get(), otherGeom.get() );
2832 catch ( GEOSException &e )
2834 logError( QStringLiteral(
"GEOS" ), e.what() );
2837 *errorMsg = e.what();
2852 geos::unique_ptr point = createGeosPointXY( x, y,
false, 0,
false, 0, 2, 0 );
2859 distance = GEOSProject_r( geosinit()->ctxt, mGeos.get(), point.get() );
2861 catch ( GEOSException &e )
2863 logError( QStringLiteral(
"GEOS" ), e.what() );
2866 *errorMsg = e.what();
2876 GEOSGeometry **
const lineGeosGeometries =
new GEOSGeometry*[ geometries.size()];
2883 lineGeosGeometries[validLines] = l.release();
2890 geos::unique_ptr result( GEOSPolygonize_r( geosinit()->ctxt, lineGeosGeometries, validLines ) );
2891 for (
int i = 0; i < validLines; ++i )
2893 GEOSGeom_destroy_r( geosinit()->ctxt, lineGeosGeometries[i] );
2895 delete[] lineGeosGeometries;
2898 catch ( GEOSException &e )
2902 *errorMsg = e.what();
2904 for (
int i = 0; i < validLines; ++i )
2906 GEOSGeom_destroy_r( geosinit()->ctxt, lineGeosGeometries[i] );
2908 delete[] lineGeosGeometries;
2923 extentGeosGeom =
asGeos( extent, mPrecision );
2924 if ( !extentGeosGeom )
2933 geos.reset( GEOSVoronoiDiagram_r( geosinit()->ctxt, mGeos.get(), extentGeosGeom.get(), tolerance, edgesOnly ) );
2935 if ( !
geos || GEOSisEmpty_r( geosinit()->ctxt,
geos.get() ) != 0 )
2955 geos.reset( GEOSDelaunayTriangulation_r( geosinit()->ctxt, mGeos.get(), tolerance, edgesOnly ) );
2957 if ( !
geos || GEOSisEmpty_r( geosinit()->ctxt,
geos.get() ) != 0 )
2969static bool _linestringEndpoints(
const GEOSGeometry *linestring,
double &x1,
double &y1,
double &x2,
double &y2 )
2971 const GEOSCoordSequence *coordSeq = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, linestring );
2975 unsigned int coordSeqSize;
2976 if ( GEOSCoordSeq_getSize_r( geosinit()->ctxt, coordSeq, &coordSeqSize ) == 0 )
2979 if ( coordSeqSize < 2 )
2982 GEOSCoordSeq_getX_r( geosinit()->ctxt, coordSeq, 0, &x1 );
2983 GEOSCoordSeq_getY_r( geosinit()->ctxt, coordSeq, 0, &y1 );
2984 GEOSCoordSeq_getX_r( geosinit()->ctxt, coordSeq, coordSeqSize - 1, &x2 );
2985 GEOSCoordSeq_getY_r( geosinit()->ctxt, coordSeq, coordSeqSize - 1, &y2 );
2991static geos::unique_ptr _mergeLinestrings(
const GEOSGeometry *line1,
const GEOSGeometry *line2,
const QgsPointXY &intersectionPoint )
2993 double x1, y1, x2, y2;
2994 if ( !_linestringEndpoints( line1, x1, y1, x2, y2 ) )
2997 double rx1, ry1, rx2, ry2;
2998 if ( !_linestringEndpoints( line2, rx1, ry1, rx2, ry2 ) )
3001 bool intersectionAtOrigLineEndpoint =
3002 ( intersectionPoint.
x() == x1 && intersectionPoint.
y() == y1 ) !=
3003 ( intersectionPoint.
x() == x2 && intersectionPoint.
y() == y2 );
3004 bool intersectionAtReshapeLineEndpoint =
3005 ( intersectionPoint.
x() == rx1 && intersectionPoint.
y() == ry1 ) ||
3006 ( intersectionPoint.
x() == rx2 && intersectionPoint.
y() == ry2 );
3009 if ( intersectionAtOrigLineEndpoint && intersectionAtReshapeLineEndpoint )
3013 GEOSGeometry *geoms[2] = { g1.release(), g2.release() };
3014 geos::unique_ptr multiGeom( GEOSGeom_createCollection_r( geosinit()->ctxt, GEOS_MULTILINESTRING, geoms, 2 ) );
3015 geos::unique_ptr res( GEOSLineMerge_r( geosinit()->ctxt, multiGeom.get() ) );
3025 if ( !line || !reshapeLineGeos )
3028 bool atLeastTwoIntersections =
false;
3029 bool oneIntersection =
false;
3035 geos::unique_ptr intersectGeom( GEOSIntersection_r( geosinit()->ctxt, line, reshapeLineGeos ) );
3036 if ( intersectGeom )
3038 const int geomType = GEOSGeomTypeId_r( geosinit()->ctxt, intersectGeom.get() );
3039 atLeastTwoIntersections = ( geomType == GEOS_MULTIPOINT && GEOSGetNumGeometries_r( geosinit()->ctxt, intersectGeom.get() ) > 1 )
3040 || ( geomType == GEOS_GEOMETRYCOLLECTION && GEOSGetNumGeometries_r( geosinit()->ctxt, intersectGeom.get() ) > 0 )
3041 || ( geomType == GEOS_MULTILINESTRING && GEOSGetNumGeometries_r( geosinit()->ctxt, intersectGeom.get() ) > 0 );
3043 if ( GEOSGeomTypeId_r( geosinit()->ctxt, intersectGeom.get() ) == GEOS_POINT )
3045 const GEOSCoordSequence *intersectionCoordSeq = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, intersectGeom.get() );
3047 GEOSCoordSeq_getX_r( geosinit()->ctxt, intersectionCoordSeq, 0, &xi );
3048 GEOSCoordSeq_getY_r( geosinit()->ctxt, intersectionCoordSeq, 0, &yi );
3049 oneIntersection =
true;
3054 catch ( GEOSException & )
3056 atLeastTwoIntersections =
false;
3060 if ( oneIntersection )
3061 return _mergeLinestrings( line, reshapeLineGeos, oneIntersectionPoint );
3063 if ( !atLeastTwoIntersections )
3067 double x1, y1, x2, y2;
3068 if ( !_linestringEndpoints( line, x1, y1, x2, y2 ) )
3074 bool isRing =
false;
3075 if ( GEOSGeomTypeId_r( geosinit()->ctxt, line ) == GEOS_LINEARRING
3076 || GEOSEquals_r( geosinit()->ctxt, beginLineVertex.get(), endLineVertex.get() ) == 1 )
3081 if ( !nodedGeometry )
3087 geos::unique_ptr mergedLines( GEOSLineMerge_r( geosinit()->ctxt, nodedGeometry.get() ) );
3093 int numMergedLines = GEOSGetNumGeometries_r( geosinit()->ctxt, mergedLines.get() );
3094 if ( numMergedLines < 2 )
3096 if ( numMergedLines == 1 )
3098 geos::unique_ptr result( GEOSGeom_clone_r( geosinit()->ctxt, reshapeLineGeos ) );
3105 QVector<GEOSGeometry *> resultLineParts;
3106 QVector<GEOSGeometry *> probableParts;
3108 for (
int i = 0; i < numMergedLines; ++i )
3110 const GEOSGeometry *currentGeom = GEOSGetGeometryN_r( geosinit()->ctxt, mergedLines.get(), i );
3113 bool alreadyAdded =
false;
3115 double bufferDistance = std::pow( 10.0L, geomDigits( currentGeom ) - 11 );
3116 for (
const GEOSGeometry *other : std::as_const( resultLineParts ) )
3118 GEOSHausdorffDistance_r( geosinit()->ctxt, currentGeom, other, &
distance );
3121 alreadyAdded =
true;
3128 const GEOSCoordSequence *currentCoordSeq = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, currentGeom );
3129 unsigned int currentCoordSeqSize;
3130 GEOSCoordSeq_getSize_r( geosinit()->ctxt, currentCoordSeq, ¤tCoordSeqSize );
3131 if ( currentCoordSeqSize < 2 )
3135 double xBegin, xEnd, yBegin, yEnd;
3136 GEOSCoordSeq_getX_r( geosinit()->ctxt, currentCoordSeq, 0, &xBegin );
3137 GEOSCoordSeq_getY_r( geosinit()->ctxt, currentCoordSeq, 0, &yBegin );
3138 GEOSCoordSeq_getX_r( geosinit()->ctxt, currentCoordSeq, currentCoordSeqSize - 1, &xEnd );
3139 GEOSCoordSeq_getY_r( geosinit()->ctxt, currentCoordSeq, currentCoordSeqSize - 1, &yEnd );
3144 int nEndpointsOnOriginalLine = 0;
3145 if ( pointContainedInLine( beginCurrentGeomVertex.get(), line ) == 1 )
3146 nEndpointsOnOriginalLine += 1;
3148 if ( pointContainedInLine( endCurrentGeomVertex.get(), line ) == 1 )
3149 nEndpointsOnOriginalLine += 1;
3152 int nEndpointsSameAsOriginalLine = 0;
3153 if ( GEOSEquals_r( geosinit()->ctxt, beginCurrentGeomVertex.get(), beginLineVertex.get() ) == 1
3154 || GEOSEquals_r( geosinit()->ctxt, beginCurrentGeomVertex.get(), endLineVertex.get() ) == 1 )
3155 nEndpointsSameAsOriginalLine += 1;
3157 if ( GEOSEquals_r( geosinit()->ctxt, endCurrentGeomVertex.get(), beginLineVertex.get() ) == 1
3158 || GEOSEquals_r( geosinit()->ctxt, endCurrentGeomVertex.get(), endLineVertex.get() ) == 1 )
3159 nEndpointsSameAsOriginalLine += 1;
3162 bool currentGeomOverlapsOriginalGeom =
false;
3163 bool currentGeomOverlapsReshapeLine =
false;
3164 if ( lineContainedInLine( currentGeom, line ) == 1 )
3165 currentGeomOverlapsOriginalGeom =
true;
3167 if ( lineContainedInLine( currentGeom, reshapeLineGeos ) == 1 )
3168 currentGeomOverlapsReshapeLine =
true;
3171 if ( !isRing && nEndpointsSameAsOriginalLine == 1 && nEndpointsOnOriginalLine == 2 && currentGeomOverlapsOriginalGeom )
3173 resultLineParts.push_back( GEOSGeom_clone_r( geosinit()->ctxt, currentGeom ) );
3176 else if ( isRing && nEndpointsOnOriginalLine == 2 && currentGeomOverlapsOriginalGeom )
3178 probableParts.push_back( GEOSGeom_clone_r( geosinit()->ctxt, currentGeom ) );
3180 else if ( nEndpointsOnOriginalLine == 2 && !currentGeomOverlapsOriginalGeom )
3182 resultLineParts.push_back( GEOSGeom_clone_r( geosinit()->ctxt, currentGeom ) );
3184 else if ( nEndpointsSameAsOriginalLine == 2 && !currentGeomOverlapsOriginalGeom )
3186 resultLineParts.push_back( GEOSGeom_clone_r( geosinit()->ctxt, currentGeom ) );
3188 else if ( currentGeomOverlapsOriginalGeom && currentGeomOverlapsReshapeLine )
3190 resultLineParts.push_back( GEOSGeom_clone_r( geosinit()->ctxt, currentGeom ) );
3195 if ( isRing && !probableParts.isEmpty() )
3198 GEOSGeometry *currentGeom =
nullptr;
3199 double maxLength = -std::numeric_limits<double>::max();
3200 double currentLength = 0;
3201 for (
int i = 0; i < probableParts.size(); ++i )
3203 currentGeom = probableParts.at( i );
3204 GEOSLength_r( geosinit()->ctxt, currentGeom, ¤tLength );
3205 if ( currentLength > maxLength )
3207 maxLength = currentLength;
3208 maxGeom.reset( currentGeom );
3212 GEOSGeom_destroy_r( geosinit()->ctxt, currentGeom );
3215 resultLineParts.push_back( maxGeom.release() );
3219 if ( resultLineParts.empty() )
3222 if ( resultLineParts.size() == 1 )
3224 result.reset( resultLineParts[0] );
3228 GEOSGeometry **lineArray =
new GEOSGeometry*[resultLineParts.size()];
3229 for (
int i = 0; i < resultLineParts.size(); ++i )
3231 lineArray[i] = resultLineParts[i];
3235 geos::unique_ptr multiLineGeom( GEOSGeom_createCollection_r( geosinit()->ctxt, GEOS_MULTILINESTRING, lineArray, resultLineParts.size() ) );
3236 delete [] lineArray;
3239 result.reset( GEOSLineMerge_r( geosinit()->ctxt, multiLineGeom.get() ) );
3243 if ( GEOSGeomTypeId_r( geosinit()->ctxt, result.get() ) != GEOS_LINESTRING )
3251geos::unique_ptr QgsGeos::reshapePolygon(
const GEOSGeometry *polygon,
const GEOSGeometry *reshapeLineGeos,
double precision )
3254 int nIntersections = 0;
3255 int lastIntersectingRing = -2;
3256 const GEOSGeometry *lastIntersectingGeom =
nullptr;
3258 int nRings = GEOSGetNumInteriorRings_r( geosinit()->ctxt, polygon );
3263 const GEOSGeometry *outerRing = GEOSGetExteriorRing_r( geosinit()->ctxt, polygon );
3264 if ( GEOSIntersects_r( geosinit()->ctxt, outerRing, reshapeLineGeos ) == 1 )
3267 lastIntersectingRing = -1;
3268 lastIntersectingGeom = outerRing;
3272 const GEOSGeometry **innerRings =
new const GEOSGeometry*[nRings];
3276 for (
int i = 0; i < nRings; ++i )
3278 innerRings[i] = GEOSGetInteriorRingN_r( geosinit()->ctxt, polygon, i );
3279 if ( GEOSIntersects_r( geosinit()->ctxt, innerRings[i], reshapeLineGeos ) == 1 )
3282 lastIntersectingRing = i;
3283 lastIntersectingGeom = innerRings[i];
3287 catch ( GEOSException & )
3292 if ( nIntersections != 1 )
3294 delete [] innerRings;
3300 if ( !reshapeResult )
3302 delete [] innerRings;
3307 GEOSGeometry *newRing =
nullptr;
3308 const GEOSCoordSequence *reshapeSequence = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, reshapeResult.get() );
3309 GEOSCoordSequence *newCoordSequence = GEOSCoordSeq_clone_r( geosinit()->ctxt, reshapeSequence );
3311 reshapeResult.reset();
3313 newRing = GEOSGeom_createLinearRing_r( geosinit()->ctxt, newCoordSequence );
3316 delete [] innerRings;
3320 GEOSGeometry *newOuterRing =
nullptr;
3321 if ( lastIntersectingRing == -1 )
3322 newOuterRing = newRing;
3324 newOuterRing = GEOSGeom_clone_r( geosinit()->ctxt, outerRing );
3327 QVector<GEOSGeometry *> ringList;
3330 GEOSGeometry *outerRingPoly = GEOSGeom_createPolygon_r( geosinit()->ctxt, GEOSGeom_clone_r( geosinit()->ctxt, newOuterRing ),
nullptr, 0 );
3331 if ( outerRingPoly )
3333 ringList.reserve( nRings );
3334 GEOSGeometry *currentRing =
nullptr;
3335 for (
int i = 0; i < nRings; ++i )
3337 if ( lastIntersectingRing == i )
3338 currentRing = newRing;
3340 currentRing = GEOSGeom_clone_r( geosinit()->ctxt, innerRings[i] );
3343 if ( GEOSContains_r( geosinit()->ctxt, outerRingPoly, currentRing ) == 1 )
3344 ringList.push_back( currentRing );
3346 GEOSGeom_destroy_r( geosinit()->ctxt, currentRing );
3349 GEOSGeom_destroy_r( geosinit()->ctxt, outerRingPoly );
3352 GEOSGeometry **newInnerRings =
new GEOSGeometry*[ringList.size()];
3353 for (
int i = 0; i < ringList.size(); ++i )
3354 newInnerRings[i] = ringList.at( i );
3356 delete [] innerRings;
3358 geos::unique_ptr reshapedPolygon( GEOSGeom_createPolygon_r( geosinit()->ctxt, newOuterRing, newInnerRings, ringList.size() ) );
3359 delete[] newInnerRings;
3361 return reshapedPolygon;
3364int QgsGeos::lineContainedInLine(
const GEOSGeometry *line1,
const GEOSGeometry *line2 )
3366 if ( !line1 || !line2 )
3371 double bufferDistance = std::pow( 10.0L, geomDigits( line2 ) - 11 );
3377 geos::unique_ptr intersectionGeom( GEOSIntersection_r( geosinit()->ctxt, bufferGeom.get(), line1 ) );
3380 double intersectGeomLength;
3383 GEOSLength_r( geosinit()->ctxt, intersectionGeom.get(), &intersectGeomLength );
3384 GEOSLength_r( geosinit()->ctxt, line1, &line1Length );
3386 double intersectRatio = line1Length / intersectGeomLength;
3387 if ( intersectRatio > 0.9 && intersectRatio < 1.1 )
3393int QgsGeos::pointContainedInLine(
const GEOSGeometry *point,
const GEOSGeometry *line )
3395 if ( !point || !line )
3398 double bufferDistance = std::pow( 10.0L, geomDigits( line ) - 11 );
3400 geos::unique_ptr lineBuffer( GEOSBuffer_r( geosinit()->ctxt, line, bufferDistance, 8 ) );
3404 bool contained =
false;
3405 if ( GEOSContains_r( geosinit()->ctxt, lineBuffer.get(), point ) == 1 )
3411int QgsGeos::geomDigits(
const GEOSGeometry *geom )
3417 const GEOSGeometry *bBoxRing = GEOSGetExteriorRing_r( geosinit()->ctxt, bbox.get() );
3421 const GEOSCoordSequence *bBoxCoordSeq = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, bBoxRing );
3423 if ( !bBoxCoordSeq )
3426 unsigned int nCoords = 0;
3427 if ( !GEOSCoordSeq_getSize_r( geosinit()->ctxt, bBoxCoordSeq, &nCoords ) )
3431 for (
unsigned int i = 0; i < nCoords - 1; ++i )
3434 GEOSCoordSeq_getX_r( geosinit()->ctxt, bBoxCoordSeq, i, &t );
3437 digits = std::ceil( std::log10( std::fabs( t ) ) );
3438 if ( digits > maxDigits )
3441 GEOSCoordSeq_getY_r( geosinit()->ctxt, bBoxCoordSeq, i, &t );
3442 digits = std::ceil( std::log10( std::fabs( t ) ) );
3443 if ( digits > maxDigits )
3452 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...
WkbType
The WKB type describes the number of dimensions a geometry has.
@ GeometryCollection
GeometryCollection.
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.
Qgis::WkbType 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(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.
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 Qgis::GeometryType geometryType(Qgis::WkbType type) SIP_HOLDGIL
Returns the geometry type for a WKB type, e.g., both MultiPolygon and CurvePolygon would have a Polyg...
static bool isMultiType(Qgis::WkbType type) SIP_HOLDGIL
Returns true if the WKB type is a multi type.
static Qgis::WkbType flatType(Qgis::WkbType 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.