31#define DEFAULT_QUADRANT_SEGMENTS 8
33#define CATCH_GEOS(r) \
34 catch (GEOSException &) \
33#define CATCH_GEOS(r) \ …
39#define CATCH_GEOS_WITH_ERRMSG(r) \
40 catch (GEOSException &e) \
44 *errorMsg = e.what(); \
39#define CATCH_GEOS_WITH_ERRMSG(r) \ …
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();
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 );
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 )
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_getXYZ_r( geosinit()->ctxt, lineSequence, i, &x, &y, &z ) )
986 testPoints.push_back(
QgsPoint( x, y, z ) );
999 int type = GEOSGeomTypeId_r( geosinit()->ctxt, mGeos.get() );
1001 std::unique_ptr< QgsMultiCurve > multiCurve;
1002 if ( type == GEOS_MULTILINESTRING )
1004 multiCurve.reset( qgsgeometry_cast<QgsMultiCurve *>(
mGeometry->
clone() ) );
1006 else if ( type == GEOS_LINESTRING )
1024 std::unique_ptr< QgsMultiPoint > splitPoints;
1026 std::unique_ptr< QgsAbstractGeometry > splitGeom(
fromGeos( GEOSsplitPoint ) );
1028 if ( qgsgeometry_cast<QgsMultiPoint *>( splitGeom.get() ) )
1030 splitPoints.reset( qgsgeometry_cast<QgsMultiPoint *>( splitGeom.release() ) );
1032 else if ( qgsgeometry_cast<QgsPoint *>( splitGeom.get() ) )
1034 splitPoints = std::make_unique< QgsMultiPoint >();
1035 if ( qgsgeometry_cast<QgsPoint *>( splitGeom.get() ) )
1037 splitPoints->addGeometry( qgsgeometry_cast<QgsPoint *>( splitGeom.release() ) );
1045 for (
int geometryIndex = 0; geometryIndex < multiCurve->numGeometries(); ++geometryIndex )
1047 const QgsLineString *line = qgsgeometry_cast<const QgsLineString *>( multiCurve->geometryN( geometryIndex ) );
1050 const QgsCurve *curve = qgsgeometry_cast<const QgsCurve *>( multiCurve->geometryN( geometryIndex ) );
1058 QMap< int, QVector< QPair< double, QgsPoint > > >pointMap;
1059 for (
int splitPointIndex = 0; splitPointIndex < splitPoints->numGeometries(); ++splitPointIndex )
1061 const QgsPoint *intersectionPoint = splitPoints->pointN( splitPointIndex );
1067 line->
closestSegment( *intersectionPoint, segmentPoint2D, nextVertex );
1083 const QPair< double, QgsPoint > pair = qMakePair(
distance, *correctSegmentPoint.get() );
1084 if ( pointMap.contains( nextVertex.
vertex - 1 ) )
1085 pointMap[ nextVertex.
vertex - 1 ].append( pair );
1087 pointMap[ nextVertex.
vertex - 1 ] = QVector< QPair< double, QgsPoint > >() << pair;
1092 for (
auto &p : pointMap )
1094 std::sort( p.begin(), p.end(), [](
const QPair< double, QgsPoint > &a,
const QPair< double, QgsPoint > &b ) { return a.first < b.first; } );
1101 for (
int vertexIndex = 0; vertexIndex < nVertices; ++vertexIndex )
1105 if ( pointMap.contains( vertexIndex ) )
1108 for (
int k = 0; k < pointMap[ vertexIndex ].size(); ++k )
1110 splitPoint = pointMap[ vertexIndex ][k].second;
1111 if ( splitPoint == currentPoint )
1117 else if ( splitPoint == line->
pointN( vertexIndex + 1 ) )
1136 return asGeos( &lines, mPrecision );
1141 Q_UNUSED( skipIntersectionCheck )
1148 geos::unique_ptr intersectGeom( GEOSIntersection_r( geosinit()->ctxt, splitLine, mGeos.get() ) );
1149 if ( !intersectGeom || GEOSisEmpty_r( geosinit()->ctxt, intersectGeom.get() ) )
1153 int linearIntersect = GEOSRelatePattern_r( geosinit()->ctxt, mGeos.get(), splitLine,
"1********" );
1154 if ( linearIntersect > 0 )
1158 splitGeom = linePointDifference( intersectGeom.get() );
1163 QVector<GEOSGeometry *> lineGeoms;
1165 int splitType = GEOSGeomTypeId_r( geosinit()->ctxt, splitGeom.get() );
1166 if ( splitType == GEOS_MULTILINESTRING )
1168 int nGeoms = GEOSGetNumGeometries_r( geosinit()->ctxt, splitGeom.get() );
1169 lineGeoms.reserve( nGeoms );
1170 for (
int i = 0; i < nGeoms; ++i )
1171 lineGeoms << GEOSGeom_clone_r( geosinit()->ctxt, GEOSGetGeometryN_r( geosinit()->ctxt, splitGeom.get(), i ) );
1176 lineGeoms << GEOSGeom_clone_r( geosinit()->ctxt, splitGeom.get() );
1179 mergeGeometriesMultiTypeSplit( lineGeoms );
1181 for (
int i = 0; i < lineGeoms.size(); ++i )
1184 GEOSGeom_destroy_r( geosinit()->ctxt, lineGeoms[i] );
1200 if ( !mGeosPrepared )
1204 if ( !skipIntersectionCheck && !GEOSPreparedIntersects_r( geosinit()->ctxt, mGeosPrepared.get(), splitLine ) )
1209 if ( !nodedGeometry )
1213 geos::unique_ptr polygons( GEOSPolygonize_r( geosinit()->ctxt, &noded, 1 ) );
1214 if ( !polygons || numberOfGeometries( polygons.get() ) == 0 )
1221 QVector<GEOSGeometry *> testedGeometries;
1226 for (
int i = 0; i < numberOfGeometries( polygons.get() ); i++ )
1228 const GEOSGeometry *polygon = GEOSGetGeometryN_r( geosinit()->ctxt, polygons.get(), i );
1232 testedGeometries << GEOSGeom_clone_r( geosinit()->ctxt, polygon );
1235 int nGeometriesThis = numberOfGeometries( mGeos.get() );
1236 if ( testedGeometries.empty() || testedGeometries.size() == nGeometriesThis )
1239 for (
int i = 0; i < testedGeometries.size(); ++i )
1241 GEOSGeom_destroy_r( geosinit()->ctxt, testedGeometries[i] );
1250 mergeGeometriesMultiTypeSplit( testedGeometries );
1253 for ( i = 0; i < testedGeometries.size() && GEOSisValid_r( geosinit()->ctxt, testedGeometries[i] ); ++i )
1256 if ( i < testedGeometries.size() )
1258 for ( i = 0; i < testedGeometries.size(); ++i )
1259 GEOSGeom_destroy_r( geosinit()->ctxt, testedGeometries[i] );
1264 for ( i = 0; i < testedGeometries.size(); ++i )
1267 GEOSGeom_destroy_r( geosinit()->ctxt, testedGeometries[i] );
1275 if ( !splitLine || !geom )
1279 if ( GEOSGeomTypeId_r( geosinit()->ctxt, geom ) == GEOS_POLYGON || GEOSGeomTypeId_r( geosinit()->ctxt, geom ) == GEOS_MULTIPOLYGON )
1280 geometryBoundary.reset( GEOSBoundary_r( geosinit()->ctxt, geom ) );
1282 geometryBoundary.reset( GEOSGeom_clone_r( geosinit()->ctxt, geom ) );
1284 geos::unique_ptr splitLineClone( GEOSGeom_clone_r( geosinit()->ctxt, splitLine ) );
1285 geos::unique_ptr unionGeometry( GEOSUnion_r( geosinit()->ctxt, splitLineClone.get(), geometryBoundary.get() ) );
1287 return unionGeometry;
1290int QgsGeos::mergeGeometriesMultiTypeSplit( QVector<GEOSGeometry *> &splitResult )
const
1296 int type = GEOSGeomTypeId_r( geosinit()->ctxt, mGeos.get() );
1297 if ( type != GEOS_GEOMETRYCOLLECTION &&
1298 type != GEOS_MULTILINESTRING &&
1299 type != GEOS_MULTIPOLYGON &&
1300 type != GEOS_MULTIPOINT )
1303 QVector<GEOSGeometry *> copyList = splitResult;
1304 splitResult.clear();
1307 QVector<GEOSGeometry *> unionGeom;
1309 for (
int i = 0; i < copyList.size(); ++i )
1312 bool isPart =
false;
1313 for (
int j = 0; j < GEOSGetNumGeometries_r( geosinit()->ctxt, mGeos.get() ); j++ )
1315 if ( GEOSEquals_r( geosinit()->ctxt, copyList[i], GEOSGetGeometryN_r( geosinit()->ctxt, mGeos.get(), j ) ) )
1324 unionGeom << copyList[i];
1328 QVector<GEOSGeometry *> geomVector;
1329 geomVector << copyList[i];
1331 if ( type == GEOS_MULTILINESTRING )
1332 splitResult << createGeosCollection( GEOS_MULTILINESTRING, geomVector ).release();
1333 else if ( type == GEOS_MULTIPOLYGON )
1334 splitResult << createGeosCollection( GEOS_MULTIPOLYGON, geomVector ).release();
1336 GEOSGeom_destroy_r( geosinit()->ctxt, copyList[i] );
1341 if ( !unionGeom.isEmpty() )
1343 if ( type == GEOS_MULTILINESTRING )
1344 splitResult << createGeosCollection( GEOS_MULTILINESTRING, unionGeom ).release();
1345 else if ( type == GEOS_MULTIPOLYGON )
1346 splitResult << createGeosCollection( GEOS_MULTIPOLYGON, unionGeom ).release();
1356geos::unique_ptr QgsGeos::createGeosCollection(
int typeId,
const QVector<GEOSGeometry *> &geoms )
1358 int nNullGeoms = geoms.count(
nullptr );
1359 int nNotNullGeoms = geoms.size() - nNullGeoms;
1368 QVector<GEOSGeometry *>::const_iterator geomIt = geoms.constBegin();
1369 for ( ; geomIt != geoms.constEnd(); ++geomIt )
1373 if ( GEOSisEmpty_r( geosinit()->ctxt, *geomIt ) )
1378 GEOSGeom_destroy_r( geosinit()->ctxt, *geomIt );
1382 geomarr[i] = *geomIt;
1391 geom.reset( GEOSGeom_createCollection_r( geosinit()->ctxt, typeId, geomarr, nNotNullGeoms ) );
1393 catch ( GEOSException & )
1409 int nCoordDims = GEOSGeom_getCoordinateDimension_r( geosinit()->ctxt,
geos );
1410 int nDims = GEOSGeom_getDimensions_r( geosinit()->ctxt,
geos );
1411 bool hasZ = ( nCoordDims == 3 );
1412 bool hasM = ( ( nDims - nCoordDims ) == 1 );
1414 switch ( GEOSGeomTypeId_r( geosinit()->ctxt,
geos ) )
1418 if ( GEOSisEmpty_r( geosinit()->ctxt,
geos ) )
1421 const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq_r( geosinit()->ctxt,
geos );
1422 unsigned int nPoints = 0;
1423 GEOSCoordSeq_getSize_r( geosinit()->ctxt, cs, &nPoints );
1424 return nPoints > 0 ? std::unique_ptr<QgsAbstractGeometry>(
coordSeqPoint( cs, 0, hasZ, hasM ).clone() ) :
nullptr;
1426 case GEOS_LINESTRING:
1428 return sequenceToLinestring(
geos, hasZ, hasM );
1434 case GEOS_MULTIPOINT:
1436 std::unique_ptr< QgsMultiPoint > multiPoint(
new QgsMultiPoint() );
1437 int nParts = GEOSGetNumGeometries_r( geosinit()->ctxt,
geos );
1438 multiPoint->reserve( nParts );
1439 for (
int i = 0; i < nParts; ++i )
1441 const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, GEOSGetGeometryN_r( geosinit()->ctxt,
geos, i ) );
1444 unsigned int nPoints = 0;
1445 GEOSCoordSeq_getSize_r( geosinit()->ctxt, cs, &nPoints );
1447 multiPoint->addGeometry(
coordSeqPoint( cs, 0, hasZ, hasM ).clone() );
1450 return std::move( multiPoint );
1452 case GEOS_MULTILINESTRING:
1455 int nParts = GEOSGetNumGeometries_r( geosinit()->ctxt,
geos );
1456 multiLineString->reserve( nParts );
1457 for (
int i = 0; i < nParts; ++i )
1459 std::unique_ptr< QgsLineString >line( sequenceToLinestring( GEOSGetGeometryN_r( geosinit()->ctxt,
geos, i ), hasZ, hasM ) );
1462 multiLineString->addGeometry( line.release() );
1465 return std::move( multiLineString );
1467 case GEOS_MULTIPOLYGON:
1469 std::unique_ptr< QgsMultiPolygon > multiPolygon(
new QgsMultiPolygon() );
1471 int nParts = GEOSGetNumGeometries_r( geosinit()->ctxt,
geos );
1472 multiPolygon->reserve( nParts );
1473 for (
int i = 0; i < nParts; ++i )
1475 std::unique_ptr< QgsPolygon > poly =
fromGeosPolygon( GEOSGetGeometryN_r( geosinit()->ctxt,
geos, i ) );
1478 multiPolygon->addGeometry( poly.release() );
1481 return std::move( multiPolygon );
1483 case GEOS_GEOMETRYCOLLECTION:
1486 int nParts = GEOSGetNumGeometries_r( geosinit()->ctxt,
geos );
1487 geomCollection->reserve( nParts );
1488 for (
int i = 0; i < nParts; ++i )
1490 std::unique_ptr< QgsAbstractGeometry > geom(
fromGeos( GEOSGetGeometryN_r( geosinit()->ctxt,
geos, i ) ) );
1493 geomCollection->addGeometry( geom.release() );
1496 return std::move( geomCollection );
1504 if ( GEOSGeomTypeId_r( geosinit()->ctxt,
geos ) != GEOS_POLYGON )
1509 int nCoordDims = GEOSGeom_getCoordinateDimension_r( geosinit()->ctxt,
geos );
1510 int nDims = GEOSGeom_getDimensions_r( geosinit()->ctxt,
geos );
1511 bool hasZ = ( nCoordDims == 3 );
1512 bool hasM = ( ( nDims - nCoordDims ) == 1 );
1514 std::unique_ptr< QgsPolygon > polygon(
new QgsPolygon() );
1516 const GEOSGeometry *ring = GEOSGetExteriorRing_r( geosinit()->ctxt,
geos );
1519 polygon->setExteriorRing( sequenceToLinestring( ring, hasZ, hasM ).release() );
1522 QVector<QgsCurve *> interiorRings;
1523 const int ringCount = GEOSGetNumInteriorRings_r( geosinit()->ctxt,
geos );
1524 interiorRings.reserve( ringCount );
1525 for (
int i = 0; i < ringCount; ++i )
1527 ring = GEOSGetInteriorRingN_r( geosinit()->ctxt,
geos, i );
1530 interiorRings.push_back( sequenceToLinestring( ring, hasZ, hasM ).release() );
1533 polygon->setInteriorRings( interiorRings );
1538std::unique_ptr<QgsLineString> QgsGeos::sequenceToLinestring(
const GEOSGeometry *
geos,
bool hasZ,
bool hasM )
1540 const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq_r( geosinit()->ctxt,
geos );
1542 unsigned int nPoints;
1543 GEOSCoordSeq_getSize_r( geosinit()->ctxt, cs, &nPoints );
1545 QVector< double > xOut( nPoints );
1546 QVector< double > yOut( nPoints );
1547 QVector< double > zOut;
1549 zOut.resize( nPoints );
1550 QVector< double > mOut;
1552 mOut.resize( nPoints );
1554 double *x = xOut.data();
1555 double *y = yOut.data();
1556 double *z = zOut.data();
1557 double *m = mOut.data();
1559#if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=10 )
1560 GEOSCoordSeq_copyToArrays_r( geosinit()->ctxt, cs, x, y, hasZ ? z : nullptr, hasM ? m : nullptr );
1562 for (
unsigned int i = 0; i < nPoints; ++i )
1565 GEOSCoordSeq_getXYZ_r( geosinit()->ctxt, cs, i, x++, y++, z++ );
1567 GEOSCoordSeq_getXY_r( geosinit()->ctxt, cs, i, x++, y++ );
1570 GEOSCoordSeq_getOrdinate_r( geosinit()->ctxt, cs, i, 3, m++ );
1574 std::unique_ptr< QgsLineString > line(
new QgsLineString( xOut, yOut, zOut, mOut ) );
1583 int geometryType = GEOSGeomTypeId_r( geosinit()->ctxt, g );
1584 if ( geometryType == GEOS_POINT || geometryType == GEOS_LINESTRING || geometryType == GEOS_LINEARRING
1585 || geometryType == GEOS_POLYGON )
1589 return GEOSGetNumGeometries_r( geosinit()->ctxt, g );
1603 GEOSCoordSeq_getXYZ_r( geosinit()->ctxt, cs, i, &x, &y, &z );
1605 GEOSCoordSeq_getXY_r( geosinit()->ctxt, cs, i, &x, &y );
1608 GEOSCoordSeq_getOrdinate_r( geosinit()->ctxt, cs, i, 3, &m );
1644 int geosType = GEOS_GEOMETRYCOLLECTION;
1651 geosType = GEOS_MULTIPOINT;
1655 geosType = GEOS_MULTILINESTRING;
1659 geosType = GEOS_MULTIPOLYGON;
1674 QVector< GEOSGeometry * > geomVector(
c->numGeometries() );
1675 for (
int i = 0; i <
c->numGeometries(); ++i )
1679 return createGeosCollection( geosType, geomVector );
1686 return createGeosPoint(
static_cast<const QgsPoint *
>( geom ), coordDims,
precision );
1704 if ( !mGeos || !geom )
1715 const double gridSize = parameters.
gridSize();
1722 case OverlayIntersection:
1725 opGeom.reset( GEOSIntersectionPrec_r( geosinit()->ctxt, mGeos.get(), geosGeom.get(), gridSize ) );
1729 opGeom.reset( GEOSIntersection_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) );
1733 case OverlayDifference:
1736 opGeom.reset( GEOSDifferencePrec_r( geosinit()->ctxt, mGeos.get(), geosGeom.get(), gridSize ) );
1740 opGeom.reset( GEOSDifference_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) );
1749 unionGeometry.reset( GEOSUnionPrec_r( geosinit()->ctxt, mGeos.get(), geosGeom.get(), gridSize ) );
1753 unionGeometry.reset( GEOSUnion_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) );
1756 if ( unionGeometry && GEOSGeomTypeId_r( geosinit()->ctxt, unionGeometry.get() ) == GEOS_MULTILINESTRING )
1758 geos::unique_ptr mergedLines( GEOSLineMerge_r( geosinit()->ctxt, unionGeometry.get() ) );
1761 unionGeometry = std::move( mergedLines );
1765 opGeom = std::move( unionGeometry );
1769 case OverlaySymDifference:
1772 opGeom.reset( GEOSSymDifferencePrec_r( geosinit()->ctxt, mGeos.get(), geosGeom.get(), gridSize ) );
1776 opGeom.reset( GEOSSymDifference_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) );
1782 catch ( GEOSException &e )
1784 logError( QStringLiteral(
"GEOS" ), e.what() );
1787 *errorMsg = e.what();
1793bool QgsGeos::relation(
const QgsAbstractGeometry *geom, Relation r, QString *errorMsg )
const
1795 if ( !mGeos || !geom )
1806 bool result =
false;
1809 if ( mGeosPrepared )
1813 case RelationIntersects:
1814 result = ( GEOSPreparedIntersects_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1816 case RelationTouches:
1817 result = ( GEOSPreparedTouches_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1819 case RelationCrosses:
1820 result = ( GEOSPreparedCrosses_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1822 case RelationWithin:
1823 result = ( GEOSPreparedWithin_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1825 case RelationContains:
1826 result = ( GEOSPreparedContains_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1828 case RelationDisjoint:
1829 result = ( GEOSPreparedDisjoint_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1831 case RelationOverlaps:
1832 result = ( GEOSPreparedOverlaps_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1840 case RelationIntersects:
1841 result = ( GEOSIntersects_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1843 case RelationTouches:
1844 result = ( GEOSTouches_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1846 case RelationCrosses:
1847 result = ( GEOSCrosses_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1849 case RelationWithin:
1850 result = ( GEOSWithin_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1852 case RelationContains:
1853 result = ( GEOSContains_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1855 case RelationDisjoint:
1856 result = ( GEOSDisjoint_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1858 case RelationOverlaps:
1859 result = ( GEOSOverlaps_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1863 catch ( GEOSException &e )
1865 logError( QStringLiteral(
"GEOS" ), e.what() );
1868 *errorMsg = e.what();
1886 geos.reset( GEOSBuffer_r( geosinit()->ctxt, mGeos.get(),
distance, segments ) );
1902 geos.reset( GEOSBufferWithStyle_r( geosinit()->ctxt, mGeos.get(),
distance, segments,
static_cast< int >( endCapStyle ),
static_cast< int >( joinStyle ), miterLimit ) );
1917 geos.reset( GEOSTopologyPreserveSimplify_r( geosinit()->ctxt, mGeos.get(), tolerance ) );
1932 geos.reset( GEOSInterpolate_r( geosinit()->ctxt, mGeos.get(),
distance ) );
1951 geos.reset( GEOSGetCentroid_r( geosinit()->ctxt, mGeos.get() ) );
1956 GEOSGeomGetX_r( geosinit()->ctxt,
geos.get(), &x );
1957 GEOSGeomGetY_r( geosinit()->ctxt,
geos.get(), &y );
1973 geos.reset( GEOSEnvelope_r( geosinit()->ctxt, mGeos.get() ) );
1992 geos.reset( GEOSPointOnSurface_r( geosinit()->ctxt, mGeos.get() ) );
1994 if ( !
geos || GEOSisEmpty_r( geosinit()->ctxt,
geos.get() ) != 0 )
1999 GEOSGeomGetX_r( geosinit()->ctxt,
geos.get(), &x );
2000 GEOSGeomGetY_r( geosinit()->ctxt,
geos.get(), &y );
2016 geos::unique_ptr cHull( GEOSConvexHull_r( geosinit()->ctxt, mGeos.get() ) );
2017 std::unique_ptr< QgsAbstractGeometry > cHullGeom =
fromGeos( cHull.get() );
2018 return cHullGeom.release();
2025#if GEOS_VERSION_MAJOR==3 && GEOS_VERSION_MINOR<11
2027 ( void )targetPercent;
2029 throw QgsNotSupportedException( QObject::tr(
"Calculating concaveHull requires a QGIS build based on GEOS 3.11 or later" ) );
2040 return concaveHullGeom.release();
2048#if GEOS_VERSION_MAJOR==3 && GEOS_VERSION_MINOR<12
2050 ( void )invalidEdges;
2052 throw QgsNotSupportedException( QObject::tr(
"Validating coverages requires a QGIS build based on GEOS 3.12 or later" ) );
2057 *errorMsg = QStringLiteral(
"Input geometry was not set" );
2064 const int result = GEOSCoverageIsValid_r( geosinit()->ctxt, mGeos.get(), gapWidth, invalidEdges ? &invalidEdgesGeos : nullptr );
2065 if ( invalidEdges && invalidEdgesGeos )
2067 *invalidEdges =
fromGeos( invalidEdgesGeos );
2069 if ( invalidEdgesGeos )
2071 GEOSGeom_destroy_r( geosinit()->ctxt, invalidEdgesGeos );
2072 invalidEdgesGeos =
nullptr;
2092#if GEOS_VERSION_MAJOR==3 && GEOS_VERSION_MINOR<12
2094 ( void )preserveBoundary;
2096 throw QgsNotSupportedException( QObject::tr(
"Simplifying coverages requires a QGIS build based on GEOS 3.12 or later" ) );
2101 *errorMsg = QStringLiteral(
"Input geometry was not set" );
2107 geos::unique_ptr simplified( GEOSCoverageSimplifyVW_r( geosinit()->ctxt, mGeos.get(), tolerance, preserveBoundary ? 1 : 0 ) );
2108 std::unique_ptr< QgsAbstractGeometry > simplifiedGeom =
fromGeos( simplified.get() );
2109 return simplifiedGeom;
2120 *errorMsg = QStringLiteral(
"Input geometry was not set" );
2126 geos::unique_ptr unioned( GEOSCoverageUnion_r( geosinit()->ctxt, mGeos.get() ) );
2127 std::unique_ptr< QgsAbstractGeometry > result =
fromGeos( unioned.get() );
2144 char res = GEOSisValidDetail_r( geosinit()->ctxt, mGeos.get(), allowSelfTouchingHoles ? GEOSVALID_ALLOW_SELFTOUCHING_RING_FORMING_HOLE : 0, &r, &g1 );
2145 const bool invalid = res != 1;
2150 error = QString( r );
2151 GEOSFree_r( geosinit()->ctxt, r );
2154 if ( invalid && errorMsg )
2158 if ( translatedErrors.empty() )
2161 translatedErrors.insert( QStringLiteral(
"topology validation error" ), QObject::tr(
"Topology validation error",
"GEOS Error" ) );
2162 translatedErrors.insert( QStringLiteral(
"repeated point" ), QObject::tr(
"Repeated point",
"GEOS Error" ) );
2163 translatedErrors.insert( QStringLiteral(
"hole lies outside shell" ), QObject::tr(
"Hole lies outside shell",
"GEOS Error" ) );
2164 translatedErrors.insert( QStringLiteral(
"holes are nested" ), QObject::tr(
"Holes are nested",
"GEOS Error" ) );
2165 translatedErrors.insert( QStringLiteral(
"interior is disconnected" ), QObject::tr(
"Interior is disconnected",
"GEOS Error" ) );
2166 translatedErrors.insert( QStringLiteral(
"self-intersection" ), QObject::tr(
"Self-intersection",
"GEOS Error" ) );
2167 translatedErrors.insert( QStringLiteral(
"ring self-intersection" ), QObject::tr(
"Ring self-intersection",
"GEOS Error" ) );
2168 translatedErrors.insert( QStringLiteral(
"nested shells" ), QObject::tr(
"Nested shells",
"GEOS Error" ) );
2169 translatedErrors.insert( QStringLiteral(
"duplicate rings" ), QObject::tr(
"Duplicate rings",
"GEOS Error" ) );
2170 translatedErrors.insert( QStringLiteral(
"too few points in geometry component" ), QObject::tr(
"Too few points in geometry component",
"GEOS Error" ) );
2171 translatedErrors.insert( QStringLiteral(
"invalid coordinate" ), QObject::tr(
"Invalid coordinate",
"GEOS Error" ) );
2172 translatedErrors.insert( QStringLiteral(
"ring is not closed" ), QObject::tr(
"Ring is not closed",
"GEOS Error" ) );
2175 *errorMsg = translatedErrors.value( error.toLower(), error );
2177 if ( g1 && errorLoc )
2183 GEOSGeom_destroy_r( geosinit()->ctxt, g1 );
2193 if ( !mGeos || !geom )
2205 bool equal = GEOSEquals_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() );
2220 return GEOSisEmpty_r( geosinit()->ctxt, mGeos.get() );
2234 return GEOSisSimple_r( geosinit()->ctxt, mGeos.get() );
2239GEOSCoordSequence *QgsGeos::createCoordinateSequence(
const QgsCurve *curve,
double precision,
bool forceClose )
2241 GEOSContextHandle_t ctxt = geosinit()->ctxt;
2243 std::unique_ptr< QgsLineString > segmentized;
2244 const QgsLineString *line = qgsgeometry_cast<const QgsLineString *>( curve );
2249 line = segmentized.get();
2256 GEOSCoordSequence *coordSeq =
nullptr;
2258 const int numPoints = line->
numPoints();
2260 const bool hasZ = line->
is3D();
2262#if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=10 )
2265 if ( !forceClose || ( line->
pointN( 0 ) == line->
pointN( numPoints - 1 ) ) )
2270 coordSeq = GEOSCoordSeq_copyFromArrays_r( ctxt, line->
xData(), line->
yData(), line->
zData(),
nullptr, numPoints );
2273 QgsDebugError( QStringLiteral(
"GEOS Exception: Could not create coordinate sequence for %1 points" ).arg( numPoints ) );
2281 QVector< double > x = line->
xVector();
2282 if ( numPoints > 0 )
2283 x.append( x.at( 0 ) );
2284 QVector< double > y = line->
yVector();
2285 if ( numPoints > 0 )
2286 y.append( y.at( 0 ) );
2287 QVector< double > z = line->
zVector();
2288 if ( hasZ && numPoints > 0 )
2289 z.append( z.at( 0 ) );
2292 coordSeq = GEOSCoordSeq_copyFromArrays_r( ctxt, x.constData(), y.constData(), !hasZ ?
nullptr : z.constData(), nullptr, numPoints + 1 );
2295 QgsDebugError( QStringLiteral(
"GEOS Exception: Could not create closed coordinate sequence for %1 points" ).arg( numPoints + 1 ) );
2306 const bool hasM =
false;
2317 int numOutPoints = numPoints;
2318 if ( forceClose && ( line->
pointN( 0 ) != line->
pointN( numPoints - 1 ) ) )
2325 coordSeq = GEOSCoordSeq_create_r( ctxt, numOutPoints, coordDims );
2328 QgsDebugError( QStringLiteral(
"GEOS Exception: Could not create coordinate sequence for %1 points in %2 dimensions" ).arg( numPoints ).arg( coordDims ) );
2332 const double *xData = line->
xData();
2333 const double *yData = line->
yData();
2334 const double *zData = hasZ ? line->
zData() :
nullptr;
2335 const double *mData = hasM ? line->
mData() :
nullptr;
2339 for (
int i = 0; i < numOutPoints; ++i )
2341 if ( i >= numPoints )
2344 xData = line->
xData();
2345 yData = line->
yData();
2346 zData = hasZ ? line->
zData() :
nullptr;
2347 mData = hasM ? line->
mData() :
nullptr;
2359 GEOSCoordSeq_setOrdinate_r( ctxt, coordSeq, i, 3, *mData++ );
2365 for (
int i = 0; i < numOutPoints; ++i )
2367 if ( i >= numPoints )
2370 xData = line->
xData();
2371 yData = line->
yData();
2372 zData = hasZ ? line->
zData() :
nullptr;
2373 mData = hasM ? line->
mData() :
nullptr;
2377 GEOSCoordSeq_setXYZ_r( ctxt, coordSeq, i, *xData++, *yData++, *zData++ );
2381 GEOSCoordSeq_setXY_r( ctxt, coordSeq, i, *xData++, *yData++ );
2385 GEOSCoordSeq_setOrdinate_r( ctxt, coordSeq, i, 3, *mData++ );
2397 const QgsPoint *pt = qgsgeometry_cast<const QgsPoint *>( point );
2404geos::unique_ptr QgsGeos::createGeosPointXY(
double x,
double y,
bool hasZ,
double z,
bool hasM,
double m,
int coordDims,
double precision )
2412 if ( coordDims == 2 )
2418 geosPoint.reset( GEOSGeom_createPointFromXY_r( geosinit()->ctxt, x, y ) );
2422 GEOSCoordSequence *coordSeq = GEOSCoordSeq_create_r( geosinit()->ctxt, 1, coordDims );
2425 QgsDebugError( QStringLiteral(
"GEOS Exception: Could not create coordinate sequence for point with %1 dimensions" ).arg( coordDims ) );
2430 GEOSCoordSeq_setX_r( geosinit()->ctxt, coordSeq, 0, std::round( x /
precision ) *
precision );
2431 GEOSCoordSeq_setY_r( geosinit()->ctxt, coordSeq, 0, std::round( y /
precision ) *
precision );
2434 GEOSCoordSeq_setOrdinate_r( geosinit()->ctxt, coordSeq, 0, 2, std::round( z /
precision ) *
precision );
2439 GEOSCoordSeq_setX_r( geosinit()->ctxt, coordSeq, 0, x );
2440 GEOSCoordSeq_setY_r( geosinit()->ctxt, coordSeq, 0, y );
2443 GEOSCoordSeq_setOrdinate_r( geosinit()->ctxt, coordSeq, 0, 2, z );
2449 GEOSCoordSeq_setOrdinate_r( geosinit()->ctxt, coordSeq, 0, 3, m );
2452 geosPoint.reset( GEOSGeom_createPoint_r( geosinit()->ctxt, coordSeq ) );
2460 const QgsCurve *
c = qgsgeometry_cast<const QgsCurve *>( curve );
2464 GEOSCoordSequence *coordSeq = createCoordinateSequence(
c,
precision );
2471 geosGeom.reset( GEOSGeom_createLineString_r( geosinit()->ctxt, coordSeq ) );
2479 const QgsCurvePolygon *polygon = qgsgeometry_cast<const QgsCurvePolygon *>( poly );
2484 if ( !exteriorRing )
2492 geos::unique_ptr exteriorRingGeos( GEOSGeom_createLinearRing_r( geosinit()->ctxt, createCoordinateSequence( exteriorRing,
precision,
true ) ) );
2501 for (
int i = 0; i < nHoles; ++i )
2504 holes[i] = GEOSGeom_createLinearRing_r( geosinit()->ctxt, createCoordinateSequence( interiorRing,
precision,
true ) );
2506 geosPolygon.reset( GEOSGeom_createPolygon_r( geosinit()->ctxt, exteriorRingGeos.release(), holes, nHoles ) );
2526 offset.reset( GEOSOffsetCurve_r( geosinit()->ctxt, mGeos.get(),
distance, segments,
static_cast< int >( joinStyle ), miterLimit ) );
2529 std::unique_ptr< QgsAbstractGeometry > offsetGeom =
fromGeos( offset.get() );
2530 return offsetGeom.release();
2544 GEOSBufferParams_setSingleSided_r( geosinit()->ctxt, bp.get(), 1 );
2545 GEOSBufferParams_setQuadrantSegments_r( geosinit()->ctxt, bp.get(), segments );
2546 GEOSBufferParams_setJoinStyle_r( geosinit()->ctxt, bp.get(),
static_cast< int >( joinStyle ) );
2547 GEOSBufferParams_setMitreLimit_r( geosinit()->ctxt, bp.get(), miterLimit );
2553 geos.reset( GEOSBufferWithParams_r( geosinit()->ctxt, mGeos.get(), bp.get(),
distance ) );
2569 geos.reset( GEOSMaximumInscribedCircle_r( geosinit()->ctxt, mGeos.get(), tolerance ) );
2587 boundaryGeos =
asGeos( boundary );
2589 geos.reset( GEOSLargestEmptyCircle_r( geosinit()->ctxt, mGeos.get(), boundaryGeos.get(), tolerance ) );
2605 geos.reset( GEOSMinimumWidth_r( geosinit()->ctxt, mGeos.get() ) );
2615 return std::numeric_limits< double >::quiet_NaN();
2622 if ( GEOSMinimumClearance_r( geosinit()->ctxt, mGeos.get(), &res ) != 0 )
2623 return std::numeric_limits< double >::quiet_NaN();
2639 geos.reset( GEOSMinimumClearanceLine_r( geosinit()->ctxt, mGeos.get() ) );
2655 geos.reset( GEOSNode_r( geosinit()->ctxt, mGeos.get() ) );
2663 if ( !mGeos || !other )
2675 geos.reset( GEOSSharedPaths_r( geosinit()->ctxt, mGeos.get(), otherGeos.get() ) );
2695 geos::unique_ptr reshapeLineGeos = createGeosLinestring( &reshapeWithLine, mPrecision );
2698 int numGeoms = GEOSGetNumGeometries_r( geosinit()->ctxt, mGeos.get() );
2699 if ( numGeoms == -1 )
2708 bool isMultiGeom =
false;
2709 int geosTypeId = GEOSGeomTypeId_r( geosinit()->ctxt, mGeos.get() );
2710 if ( geosTypeId == GEOS_MULTILINESTRING || geosTypeId == GEOS_MULTIPOLYGON )
2720 reshapedGeometry = reshapeLine( mGeos.get(), reshapeLineGeos.get(), mPrecision );
2724 reshapedGeometry = reshapePolygon( mGeos.get(), reshapeLineGeos.get(), mPrecision );
2729 std::unique_ptr< QgsAbstractGeometry > reshapeResult =
fromGeos( reshapedGeometry.get() );
2730 return reshapeResult;
2737 bool reshapeTookPlace =
false;
2742 for (
int i = 0; i < numGeoms; ++i )
2745 currentReshapeGeometry = reshapeLine( GEOSGetGeometryN_r( geosinit()->ctxt, mGeos.get(), i ), reshapeLineGeos.get(), mPrecision );
2747 currentReshapeGeometry = reshapePolygon( GEOSGetGeometryN_r( geosinit()->ctxt, mGeos.get(), i ), reshapeLineGeos.get(), mPrecision );
2749 if ( currentReshapeGeometry )
2751 newGeoms[i] = currentReshapeGeometry.release();
2752 reshapeTookPlace =
true;
2756 newGeoms[i] = GEOSGeom_clone_r( geosinit()->ctxt, GEOSGetGeometryN_r( geosinit()->ctxt, mGeos.get(), i ) );
2763 newMultiGeom.reset( GEOSGeom_createCollection_r( geosinit()->ctxt, GEOS_MULTILINESTRING, newGeoms, numGeoms ) );
2767 newMultiGeom.reset( GEOSGeom_createCollection_r( geosinit()->ctxt, GEOS_MULTIPOLYGON, newGeoms, numGeoms ) );
2771 if ( !newMultiGeom )
2777 if ( reshapeTookPlace )
2781 std::unique_ptr< QgsAbstractGeometry > reshapedMultiGeom =
fromGeos( newMultiGeom.get() );
2782 return reshapedMultiGeom;
2804 if ( GEOSGeomTypeId_r( geosinit()->ctxt, mGeos.get() ) != GEOS_MULTILINESTRING )
2810 geos.reset( GEOSLineMerge_r( geosinit()->ctxt, mGeos.get() ) );
2834 if ( mGeosPrepared )
2836 nearestCoord.reset( GEOSPreparedNearestPoints_r( geosinit()->ctxt, mGeosPrepared.get(), otherGeom.get() ) );
2840 nearestCoord.reset( GEOSNearestPoints_r( geosinit()->ctxt, mGeos.get(), otherGeom.get() ) );
2843 ( void )GEOSCoordSeq_getX_r( geosinit()->ctxt, nearestCoord.get(), 0, &nx );
2844 ( void )GEOSCoordSeq_getY_r( geosinit()->ctxt, nearestCoord.get(), 0, &ny );
2846 catch ( GEOSException &e )
2848 logError( QStringLiteral(
"GEOS" ), e.what() );
2851 *errorMsg = e.what();
2861 if ( !mGeos || other.
isEmpty() )
2871 if ( !other || other->
isEmpty() )
2888 if ( !nearestCoord )
2891 *errorMsg = QStringLiteral(
"GEOS returned no nearest points" );
2895 ( void )GEOSCoordSeq_getX_r( geosinit()->ctxt, nearestCoord.get(), 0, &nx1 );
2896 ( void )GEOSCoordSeq_getY_r( geosinit()->ctxt, nearestCoord.get(), 0, &ny1 );
2897 ( void )GEOSCoordSeq_getX_r( geosinit()->ctxt, nearestCoord.get(), 1, &nx2 );
2898 ( void )GEOSCoordSeq_getY_r( geosinit()->ctxt, nearestCoord.get(), 1, &ny2 );
2900 catch ( GEOSException &e )
2902 logError( QStringLiteral(
"GEOS" ), e.what() );
2905 *errorMsg = e.what();
2932 distance = GEOSProject_r( geosinit()->ctxt, mGeos.get(), otherGeom.get() );
2934 catch ( GEOSException &e )
2936 logError( QStringLiteral(
"GEOS" ), e.what() );
2939 *errorMsg = e.what();
2954 geos::unique_ptr point = createGeosPointXY( x, y,
false, 0,
false, 0, 2, 0 );
2961 distance = GEOSProject_r( geosinit()->ctxt, mGeos.get(), point.get() );
2963 catch ( GEOSException &e )
2965 logError( QStringLiteral(
"GEOS" ), e.what() );
2968 *errorMsg = e.what();
2985 lineGeosGeometries[validLines] = l.release();
2992 geos::unique_ptr result( GEOSPolygonize_r( geosinit()->ctxt, lineGeosGeometries, validLines ) );
2993 for (
int i = 0; i < validLines; ++i )
2995 GEOSGeom_destroy_r( geosinit()->ctxt, lineGeosGeometries[i] );
2997 delete[] lineGeosGeometries;
3000 catch ( GEOSException &e )
3004 *errorMsg = e.what();
3006 for (
int i = 0; i < validLines; ++i )
3008 GEOSGeom_destroy_r( geosinit()->ctxt, lineGeosGeometries[i] );
3010 delete[] lineGeosGeometries;
3025 extentGeosGeom =
asGeos( extent, mPrecision );
3026 if ( !extentGeosGeom )
3035 geos.reset( GEOSVoronoiDiagram_r( geosinit()->ctxt, mGeos.get(), extentGeosGeom.get(), tolerance, edgesOnly ) );
3037 if ( !
geos || GEOSisEmpty_r( geosinit()->ctxt,
geos.get() ) != 0 )
3057 geos.reset( GEOSDelaunayTriangulation_r( geosinit()->ctxt, mGeos.get(), tolerance, edgesOnly ) );
3059 if ( !
geos || GEOSisEmpty_r( geosinit()->ctxt,
geos.get() ) != 0 )
3071#if GEOS_VERSION_MAJOR==3 && GEOS_VERSION_MINOR<11
3073 throw QgsNotSupportedException( QObject::tr(
"Calculating constrainedDelaunayTriangulation requires a QGIS build based on GEOS 3.11 or later" ) );
3083 geos.reset( GEOSConstrainedDelaunayTriangulation_r( geosinit()->ctxt, mGeos.get() ) );
3085 if ( !
geos || GEOSisEmpty_r( geosinit()->ctxt,
geos.get() ) != 0 )
3090 std::unique_ptr< QgsAbstractGeometry > res =
fromGeos(
geos.get() );
3091 if (
const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( res.get() ) )
3093 return std::unique_ptr< QgsAbstractGeometry >( collection->extractPartsByType(
Qgis::WkbType::Polygon,
true ) );
3105static bool _linestringEndpoints(
const GEOSGeometry *linestring,
double &x1,
double &y1,
double &x2,
double &y2 )
3107 const GEOSCoordSequence *coordSeq = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, linestring );
3111 unsigned int coordSeqSize;
3112 if ( GEOSCoordSeq_getSize_r( geosinit()->ctxt, coordSeq, &coordSeqSize ) == 0 )
3115 if ( coordSeqSize < 2 )
3118 GEOSCoordSeq_getX_r( geosinit()->ctxt, coordSeq, 0, &x1 );
3119 GEOSCoordSeq_getY_r( geosinit()->ctxt, coordSeq, 0, &y1 );
3120 GEOSCoordSeq_getX_r( geosinit()->ctxt, coordSeq, coordSeqSize - 1, &x2 );
3121 GEOSCoordSeq_getY_r( geosinit()->ctxt, coordSeq, coordSeqSize - 1, &y2 );
3129 double x1, y1, x2, y2;
3130 if ( !_linestringEndpoints( line1, x1, y1, x2, y2 ) )
3133 double rx1, ry1, rx2, ry2;
3134 if ( !_linestringEndpoints( line2, rx1, ry1, rx2, ry2 ) )
3137 bool intersectionAtOrigLineEndpoint =
3138 ( intersectionPoint.
x() == x1 && intersectionPoint.
y() == y1 ) !=
3139 ( intersectionPoint.
x() == x2 && intersectionPoint.
y() == y2 );
3140 bool intersectionAtReshapeLineEndpoint =
3141 ( intersectionPoint.
x() == rx1 && intersectionPoint.
y() == ry1 ) ||
3142 ( intersectionPoint.
x() == rx2 && intersectionPoint.
y() == ry2 );
3145 if ( intersectionAtOrigLineEndpoint && intersectionAtReshapeLineEndpoint )
3149 GEOSGeometry *geoms[2] = { g1.release(), g2.release() };
3150 geos::unique_ptr multiGeom( GEOSGeom_createCollection_r( geosinit()->ctxt, GEOS_MULTILINESTRING, geoms, 2 ) );
3151 geos::unique_ptr res( GEOSLineMerge_r( geosinit()->ctxt, multiGeom.get() ) );
3161 if ( !line || !reshapeLineGeos )
3164 bool atLeastTwoIntersections =
false;
3165 bool oneIntersection =
false;
3171 geos::unique_ptr intersectGeom( GEOSIntersection_r( geosinit()->ctxt, line, reshapeLineGeos ) );
3172 if ( intersectGeom )
3174 const int geomType = GEOSGeomTypeId_r( geosinit()->ctxt, intersectGeom.get() );
3175 atLeastTwoIntersections = ( geomType == GEOS_MULTIPOINT && GEOSGetNumGeometries_r( geosinit()->ctxt, intersectGeom.get() ) > 1 )
3176 || ( geomType == GEOS_GEOMETRYCOLLECTION && GEOSGetNumGeometries_r( geosinit()->ctxt, intersectGeom.get() ) > 0 )
3177 || ( geomType == GEOS_MULTILINESTRING && GEOSGetNumGeometries_r( geosinit()->ctxt, intersectGeom.get() ) > 0 );
3179 if ( GEOSGeomTypeId_r( geosinit()->ctxt, intersectGeom.get() ) == GEOS_POINT )
3181 const GEOSCoordSequence *intersectionCoordSeq = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, intersectGeom.get() );
3183 GEOSCoordSeq_getX_r( geosinit()->ctxt, intersectionCoordSeq, 0, &xi );
3184 GEOSCoordSeq_getY_r( geosinit()->ctxt, intersectionCoordSeq, 0, &yi );
3185 oneIntersection =
true;
3190 catch ( GEOSException & )
3192 atLeastTwoIntersections =
false;
3196 if ( oneIntersection )
3197 return _mergeLinestrings( line, reshapeLineGeos, oneIntersectionPoint );
3199 if ( !atLeastTwoIntersections )
3203 double x1, y1, x2, y2;
3204 if ( !_linestringEndpoints( line, x1, y1, x2, y2 ) )
3210 bool isRing =
false;
3211 if ( GEOSGeomTypeId_r( geosinit()->ctxt, line ) == GEOS_LINEARRING
3212 || GEOSEquals_r( geosinit()->ctxt, beginLineVertex.get(), endLineVertex.get() ) == 1 )
3217 if ( !nodedGeometry )
3223 geos::unique_ptr mergedLines( GEOSLineMerge_r( geosinit()->ctxt, nodedGeometry.get() ) );
3229 int numMergedLines = GEOSGetNumGeometries_r( geosinit()->ctxt, mergedLines.get() );
3230 if ( numMergedLines < 2 )
3232 if ( numMergedLines == 1 )
3234 geos::unique_ptr result( GEOSGeom_clone_r( geosinit()->ctxt, reshapeLineGeos ) );
3241 QVector<GEOSGeometry *> resultLineParts;
3242 QVector<GEOSGeometry *> probableParts;
3244 for (
int i = 0; i < numMergedLines; ++i )
3246 const GEOSGeometry *currentGeom = GEOSGetGeometryN_r( geosinit()->ctxt, mergedLines.get(), i );
3249 bool alreadyAdded =
false;
3251 double bufferDistance = std::pow( 10.0L, geomDigits( currentGeom ) - 11 );
3252 for (
const GEOSGeometry *other : std::as_const( resultLineParts ) )
3254 GEOSHausdorffDistance_r( geosinit()->ctxt, currentGeom, other, &
distance );
3257 alreadyAdded =
true;
3264 const GEOSCoordSequence *currentCoordSeq = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, currentGeom );
3265 unsigned int currentCoordSeqSize;
3266 GEOSCoordSeq_getSize_r( geosinit()->ctxt, currentCoordSeq, ¤tCoordSeqSize );
3267 if ( currentCoordSeqSize < 2 )
3271 double xBegin, xEnd, yBegin, yEnd;
3272 GEOSCoordSeq_getX_r( geosinit()->ctxt, currentCoordSeq, 0, &xBegin );
3273 GEOSCoordSeq_getY_r( geosinit()->ctxt, currentCoordSeq, 0, &yBegin );
3274 GEOSCoordSeq_getX_r( geosinit()->ctxt, currentCoordSeq, currentCoordSeqSize - 1, &xEnd );
3275 GEOSCoordSeq_getY_r( geosinit()->ctxt, currentCoordSeq, currentCoordSeqSize - 1, &yEnd );
3280 int nEndpointsOnOriginalLine = 0;
3281 if ( pointContainedInLine( beginCurrentGeomVertex.get(), line ) == 1 )
3282 nEndpointsOnOriginalLine += 1;
3284 if ( pointContainedInLine( endCurrentGeomVertex.get(), line ) == 1 )
3285 nEndpointsOnOriginalLine += 1;
3288 int nEndpointsSameAsOriginalLine = 0;
3289 if ( GEOSEquals_r( geosinit()->ctxt, beginCurrentGeomVertex.get(), beginLineVertex.get() ) == 1
3290 || GEOSEquals_r( geosinit()->ctxt, beginCurrentGeomVertex.get(), endLineVertex.get() ) == 1 )
3291 nEndpointsSameAsOriginalLine += 1;
3293 if ( GEOSEquals_r( geosinit()->ctxt, endCurrentGeomVertex.get(), beginLineVertex.get() ) == 1
3294 || GEOSEquals_r( geosinit()->ctxt, endCurrentGeomVertex.get(), endLineVertex.get() ) == 1 )
3295 nEndpointsSameAsOriginalLine += 1;
3298 bool currentGeomOverlapsOriginalGeom =
false;
3299 bool currentGeomOverlapsReshapeLine =
false;
3300 if ( lineContainedInLine( currentGeom, line ) == 1 )
3301 currentGeomOverlapsOriginalGeom =
true;
3303 if ( lineContainedInLine( currentGeom, reshapeLineGeos ) == 1 )
3304 currentGeomOverlapsReshapeLine =
true;
3307 if ( !isRing && nEndpointsSameAsOriginalLine == 1 && nEndpointsOnOriginalLine == 2 && currentGeomOverlapsOriginalGeom )
3309 resultLineParts.push_back( GEOSGeom_clone_r( geosinit()->ctxt, currentGeom ) );
3312 else if ( isRing && nEndpointsOnOriginalLine == 2 && currentGeomOverlapsOriginalGeom )
3314 probableParts.push_back( GEOSGeom_clone_r( geosinit()->ctxt, currentGeom ) );
3316 else if ( nEndpointsOnOriginalLine == 2 && !currentGeomOverlapsOriginalGeom )
3318 resultLineParts.push_back( GEOSGeom_clone_r( geosinit()->ctxt, currentGeom ) );
3320 else if ( nEndpointsSameAsOriginalLine == 2 && !currentGeomOverlapsOriginalGeom )
3322 resultLineParts.push_back( GEOSGeom_clone_r( geosinit()->ctxt, currentGeom ) );
3324 else if ( currentGeomOverlapsOriginalGeom && currentGeomOverlapsReshapeLine )
3326 resultLineParts.push_back( GEOSGeom_clone_r( geosinit()->ctxt, currentGeom ) );
3331 if ( isRing && !probableParts.isEmpty() )
3335 double maxLength = -std::numeric_limits<double>::max();
3336 double currentLength = 0;
3337 for (
int i = 0; i < probableParts.size(); ++i )
3339 currentGeom = probableParts.at( i );
3340 GEOSLength_r( geosinit()->ctxt, currentGeom, ¤tLength );
3341 if ( currentLength > maxLength )
3343 maxLength = currentLength;
3344 maxGeom.reset( currentGeom );
3348 GEOSGeom_destroy_r( geosinit()->ctxt, currentGeom );
3351 resultLineParts.push_back( maxGeom.release() );
3355 if ( resultLineParts.empty() )
3358 if ( resultLineParts.size() == 1 )
3360 result.reset( resultLineParts[0] );
3365 for (
int i = 0; i < resultLineParts.size(); ++i )
3367 lineArray[i] = resultLineParts[i];
3371 geos::unique_ptr multiLineGeom( GEOSGeom_createCollection_r( geosinit()->ctxt, GEOS_MULTILINESTRING, lineArray, resultLineParts.size() ) );
3372 delete [] lineArray;
3375 result.reset( GEOSLineMerge_r( geosinit()->ctxt, multiLineGeom.get() ) );
3379 if ( GEOSGeomTypeId_r( geosinit()->ctxt, result.get() ) != GEOS_LINESTRING )
3390 int nIntersections = 0;
3391 int lastIntersectingRing = -2;
3394 int nRings = GEOSGetNumInteriorRings_r( geosinit()->ctxt, polygon );
3399 const GEOSGeometry *outerRing = GEOSGetExteriorRing_r( geosinit()->ctxt, polygon );
3400 if ( GEOSIntersects_r( geosinit()->ctxt, outerRing, reshapeLineGeos ) == 1 )
3403 lastIntersectingRing = -1;
3404 lastIntersectingGeom = outerRing;
3412 for (
int i = 0; i < nRings; ++i )
3414 innerRings[i] = GEOSGetInteriorRingN_r( geosinit()->ctxt, polygon, i );
3415 if ( GEOSIntersects_r( geosinit()->ctxt, innerRings[i], reshapeLineGeos ) == 1 )
3418 lastIntersectingRing = i;
3419 lastIntersectingGeom = innerRings[i];
3423 catch ( GEOSException & )
3428 if ( nIntersections != 1 )
3430 delete [] innerRings;
3436 if ( !reshapeResult )
3438 delete [] innerRings;
3444 const GEOSCoordSequence *reshapeSequence = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, reshapeResult.get() );
3445 GEOSCoordSequence *newCoordSequence = GEOSCoordSeq_clone_r( geosinit()->ctxt, reshapeSequence );
3447 reshapeResult.reset();
3449 newRing = GEOSGeom_createLinearRing_r( geosinit()->ctxt, newCoordSequence );
3452 delete [] innerRings;
3457 if ( lastIntersectingRing == -1 )
3458 newOuterRing = newRing;
3460 newOuterRing = GEOSGeom_clone_r( geosinit()->ctxt, outerRing );
3463 QVector<GEOSGeometry *> ringList;
3466 GEOSGeometry *outerRingPoly = GEOSGeom_createPolygon_r( geosinit()->ctxt, GEOSGeom_clone_r( geosinit()->ctxt, newOuterRing ),
nullptr, 0 );
3467 if ( outerRingPoly )
3469 ringList.reserve( nRings );
3471 for (
int i = 0; i < nRings; ++i )
3473 if ( lastIntersectingRing == i )
3474 currentRing = newRing;
3476 currentRing = GEOSGeom_clone_r( geosinit()->ctxt, innerRings[i] );
3479 if ( GEOSContains_r( geosinit()->ctxt, outerRingPoly, currentRing ) == 1 )
3480 ringList.push_back( currentRing );
3482 GEOSGeom_destroy_r( geosinit()->ctxt, currentRing );
3485 GEOSGeom_destroy_r( geosinit()->ctxt, outerRingPoly );
3489 for (
int i = 0; i < ringList.size(); ++i )
3490 newInnerRings[i] = ringList.at( i );
3492 delete [] innerRings;
3494 geos::unique_ptr reshapedPolygon( GEOSGeom_createPolygon_r( geosinit()->ctxt, newOuterRing, newInnerRings, ringList.size() ) );
3495 delete[] newInnerRings;
3497 return reshapedPolygon;
3502 if ( !line1 || !line2 )
3507 double bufferDistance = std::pow( 10.0L, geomDigits( line2 ) - 11 );
3513 geos::unique_ptr intersectionGeom( GEOSIntersection_r( geosinit()->ctxt, bufferGeom.get(), line1 ) );
3516 double intersectGeomLength;
3519 GEOSLength_r( geosinit()->ctxt, intersectionGeom.get(), &intersectGeomLength );
3520 GEOSLength_r( geosinit()->ctxt, line1, &line1Length );
3522 double intersectRatio = line1Length / intersectGeomLength;
3523 if ( intersectRatio > 0.9 && intersectRatio < 1.1 )
3531 if ( !point || !line )
3534 double bufferDistance = std::pow( 10.0L, geomDigits( line ) - 11 );
3536 geos::unique_ptr lineBuffer( GEOSBuffer_r( geosinit()->ctxt, line, bufferDistance, 8 ) );
3540 bool contained =
false;
3541 if ( GEOSContains_r( geosinit()->ctxt, lineBuffer.get(), point ) == 1 )
3553 const GEOSGeometry *bBoxRing = GEOSGetExteriorRing_r( geosinit()->ctxt, bbox.get() );
3557 const GEOSCoordSequence *bBoxCoordSeq = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, bBoxRing );
3559 if ( !bBoxCoordSeq )
3562 unsigned int nCoords = 0;
3563 if ( !GEOSCoordSeq_getSize_r( geosinit()->ctxt, bBoxCoordSeq, &nCoords ) )
3567 for (
unsigned int i = 0; i < nCoords - 1; ++i )
3570 GEOSCoordSeq_getX_r( geosinit()->ctxt, bBoxCoordSeq, i, &t );
3573 digits = std::ceil( std::log10( std::fabs( t ) ) );
3574 if ( digits > maxDigits )
3577 GEOSCoordSeq_getY_r( geosinit()->ctxt, bBoxCoordSeq, i, &t );
3578 digits = std::ceil( std::log10( std::fabs( t ) ) );
3579 if ( digits > maxDigits )
3588 return geosinit()->ctxt;
The Qgis class provides global constants for use throughout the application.
BufferSide
Side of line to buffer.
@ Right
Buffer to right of line.
GeometryOperationResult
Success or failure of a geometry operation.
@ AddPartNotMultiGeometry
The source geometry is not multi.
@ InvalidBaseGeometry
The base geometry on which the operation is done is invalid or empty.
JoinStyle
Join styles for buffers.
EndCapStyle
End cap styles for buffers.
CoverageValidityResult
Coverage validity results.
@ Valid
Coverage is valid.
@ Invalid
Coverage is invalid. Invalidity includes polygons that overlap, that have gaps smaller than the gap w...
@ Error
An exception occurred while determining validity.
MakeValidMethod
Algorithms to use when repairing invalid geometries.
@ Linework
Combines all rings into a set of noded lines and then extracts valid polygons from that linework.
@ Structure
Structured method, first makes all rings valid and then merges shells and subtracts holes from shells...
WkbType
The WKB type describes the number of dimensions a geometry has.
@ GeometryCollection
GeometryCollection.
Abstract base class for all geometries.
bool isMeasure() const
Returns true if the geometry contains m values.
virtual QgsRectangle boundingBox() const
Returns the minimal bounding box for the geometry.
bool is3D() const
Returns true if the geometry is 3D and contains a z-value.
Qgis::WkbType wkbType() const
Returns the WKB type of the geometry.
virtual bool isEmpty() const
Returns true if the geometry is empty.
virtual int dimension() const =0
Returns the inherent dimension of the geometry.
virtual QgsAbstractGeometry * clone() const =0
Clones the geometry by performing a deep copy.
Curve polygon geometry type.
int numInteriorRings() const
Returns the number of interior rings contained with the curve polygon.
const QgsCurve * exteriorRing() const
Returns the curve polygon's exterior ring.
const QgsCurve * interiorRing(int i) const
Retrieves an interior ring from the curve polygon.
Abstract base class for curved geometry type.
virtual QgsLineString * curveToLine(double tolerance=M_PI_2/90, SegmentationToleranceType toleranceType=MaximumAngle) const =0
Returns a new line string geometry corresponding to a segmentized approximation of the curve.
virtual bool addGeometry(QgsAbstractGeometry *g)
Adds a geometry and takes ownership. Returns true in case of success.
static Qgis::GeometryOperationResult addPart(QgsAbstractGeometry *geometry, std::unique_ptr< QgsAbstractGeometry > part)
Add a part to multi type geometry.
A geometry engine is a low-level representation of a QgsAbstractGeometry object, optimised for use wi...
const QgsAbstractGeometry * mGeometry
EngineOperationResult
Success or failure of a geometry operation.
@ NothingHappened
Nothing happened, without any error.
@ InvalidBaseGeometry
The geometry on which the operation occurs is not valid.
@ InvalidInput
The input is not valid.
@ NodedGeometryError
Error occurred while creating a noded geometry.
@ EngineError
Error occurred in the geometry engine.
@ SplitCannotSplitPoint
Points cannot be split.
@ Success
Operation succeeded.
void logError(const QString &engineName, const QString &message) const
Logs an error message encountered during an operation.
static std::unique_ptr< QgsGeometryCollection > createCollectionOfType(Qgis::WkbType type)
Returns a new geometry collection matching a specified WKB type.
Encapsulates parameters under which a geometry operation is performed.
double gridSize() const
Returns the grid size which will be used to snap vertices of a geometry.
A geometry is the spatial representation of a feature.
QgsAbstractGeometry * get()
Returns a modifiable (non-const) reference to the underlying abstract geometry primitive.
const QgsAbstractGeometry * constGet() const
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
bool isEmpty() const
Returns true if the geometry is empty (eg a linestring with no vertices, or a collection with no geom...
Does vector analysis using the geos library and handles import, export, exception handling*.
QgsGeometry delaunayTriangulation(double tolerance=0.0, bool edgesOnly=false, QString *errorMsg=nullptr) const
Returns the Delaunay triangulation for the vertices of the geometry.
bool touches(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Checks if geom touches this.
QgsAbstractGeometry * symDifference(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr, const QgsGeometryParameters ¶meters=QgsGeometryParameters()) const override
Calculate the symmetric difference of this and geom.
double hausdorffDistanceDensify(const QgsAbstractGeometry *geom, double densifyFraction, QString *errorMsg=nullptr) const
Returns the Hausdorff distance between this geometry and geom.
bool isValid(QString *errorMsg=nullptr, bool allowSelfTouchingHoles=false, QgsGeometry *errorLoc=nullptr) const override
Returns true if the geometry is valid.
std::unique_ptr< QgsAbstractGeometry > subdivide(int maxNodes, QString *errorMsg=nullptr, const QgsGeometryParameters ¶meters=QgsGeometryParameters()) const
Subdivides the geometry.
QgsAbstractGeometry * intersection(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr, const QgsGeometryParameters ¶meters=QgsGeometryParameters()) const override
Calculate the intersection of this and geom.
double hausdorffDistance(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const
Returns the Hausdorff distance between this geometry and geom.
std::unique_ptr< QgsAbstractGeometry > constrainedDelaunayTriangulation(QString *errorMsg=nullptr) const
Returns a constrained Delaunay triangulation for the vertices of the geometry.
static geos::unique_ptr asGeos(const QgsGeometry &geometry, double precision=0)
Returns a geos geometry - caller takes ownership of the object (should be deleted with GEOSGeom_destr...
QgsAbstractGeometry * buffer(double distance, int segments, QString *errorMsg=nullptr) const override
QgsAbstractGeometry * concaveHull(double targetPercent, bool allowHoles=false, QString *errorMsg=nullptr) const
Returns a possibly concave geometry that encloses the input geometry.
std::unique_ptr< QgsAbstractGeometry > reshapeGeometry(const QgsLineString &reshapeWithLine, EngineOperationResult *errorCode, QString *errorMsg=nullptr) const
Reshapes the geometry using a line.
std::unique_ptr< QgsAbstractGeometry > maximumInscribedCircle(double tolerance, QString *errorMsg=nullptr) const
Returns the maximum inscribed circle.
QgsAbstractGeometry * difference(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr, const QgsGeometryParameters ¶meters=QgsGeometryParameters()) const override
Calculate the difference of this and geom.
EngineOperationResult splitGeometry(const QgsLineString &splitLine, QVector< QgsGeometry > &newGeometries, bool topological, QgsPointSequence &topologyTestPoints, QString *errorMsg=nullptr, bool skipIntersectionCheck=false) const override
Splits this geometry according to a given line.
std::unique_ptr< QgsAbstractGeometry > sharedPaths(const QgsAbstractGeometry *other, QString *errorMsg=nullptr) const
Find paths shared between the two given lineal geometries (this and other).
std::unique_ptr< QgsAbstractGeometry > clip(const QgsRectangle &rectangle, QString *errorMsg=nullptr) const
Performs a fast, non-robust intersection between the geometry and a rectangle.
std::unique_ptr< QgsAbstractGeometry > node(QString *errorMsg=nullptr) const
Returns a (Multi)LineString representing the fully noded version of a collection of linestrings.
double minimumClearance(QString *errorMsg=nullptr) const
Computes the minimum clearance of a geometry.
std::unique_ptr< QgsAbstractGeometry > singleSidedBuffer(double distance, int segments, Qgis::BufferSide side, Qgis::JoinStyle joinStyle, double miterLimit, QString *errorMsg=nullptr) const
Returns a single sided buffer for a geometry.
bool disjoint(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Checks if geom is disjoint from this.
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
std::unique_ptr< QgsAbstractGeometry > unionCoverage(QString *errorMsg=nullptr) const
Optimized union algorithm for polygonal inputs that are correctly noded and do not overlap.
QgsGeometry closestPoint(const QgsGeometry &other, QString *errorMsg=nullptr) const
Returns the closest point on the geometry to the other geometry.
static std::unique_ptr< QgsPolygon > fromGeosPolygon(const GEOSGeometry *geos)
std::unique_ptr< QgsAbstractGeometry > minimumClearanceLine(QString *errorMsg=nullptr) const
Returns a LineString whose endpoints define the minimum clearance of a geometry.
QgsAbstractGeometry * envelope(QString *errorMsg=nullptr) const override
QString relate(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Returns the Dimensional Extended 9 Intersection Model (DE-9IM) representation of the relationship bet...
bool crosses(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Checks if geom crosses this.
QgsAbstractGeometry * convexHull(QString *errorMsg=nullptr) const override
Calculate the convex hull of this.
double distance(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Calculates the distance between this and geom.
std::unique_ptr< QgsAbstractGeometry > minimumWidth(QString *errorMsg=nullptr) const
Returns a linestring geometry which represents the minimum diameter of the geometry.
bool isSimple(QString *errorMsg=nullptr) const override
Determines whether the geometry is simple (according to OGC definition).
QgsAbstractGeometry * combine(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr, const QgsGeometryParameters ¶meters=QgsGeometryParameters()) const override
Calculate the combination of this and geom.
bool within(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Checks if geom is within this.
void prepareGeometry() override
Prepares the geometry, so that subsequent calls to spatial relation methods are much faster.
static std::unique_ptr< QgsAbstractGeometry > fromGeos(const GEOSGeometry *geos)
Create a geometry from a GEOSGeometry.
QgsAbstractGeometry * interpolate(double distance, QString *errorMsg=nullptr) const override
bool distanceWithin(const QgsAbstractGeometry *geom, double maxdistance, QString *errorMsg=nullptr) const override
Checks if geom is within maxdistance distance from this geometry.
bool isEqual(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Checks if this is equal to geom.
bool contains(double x, double y, QString *errorMsg=nullptr) const
Returns true if the geometry contains the point at (x, y).
QgsGeometry mergeLines(QString *errorMsg=nullptr) const
Merges any connected lines in a LineString/MultiLineString geometry and converts them to single line ...
static QgsGeometry polygonize(const QVector< const QgsAbstractGeometry * > &geometries, QString *errorMsg=nullptr)
Creates a GeometryCollection geometry containing possible polygons formed from the constituent linewo...
bool relatePattern(const QgsAbstractGeometry *geom, const QString &pattern, QString *errorMsg=nullptr) const override
Tests whether two geometries are related by a specified Dimensional Extended 9 Intersection Model (DE...
QgsAbstractGeometry * offsetCurve(double distance, int segments, Qgis::JoinStyle joinStyle, double miterLimit, QString *errorMsg=nullptr) const override
Offsets a curve.
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...
std::unique_ptr< QgsAbstractGeometry > simplifyCoverageVW(double tolerance, bool preserveBoundary, QString *errorMsg=nullptr) const
Operates on a coverage (represented as a list of polygonal geometry with exactly matching edge geomet...
bool isEmpty(QString *errorMsg=nullptr) const override
static Qgis::GeometryOperationResult addPart(QgsGeometry &geometry, GEOSGeometry *newPart)
Adds a new island polygon to a multipolygon feature.
double frechetDistance(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const
Returns the Fréchet distance between this geometry and geom, restricted to discrete points for both g...
QgsGeometry voronoiDiagram(const QgsAbstractGeometry *extent=nullptr, double tolerance=0.0, bool edgesOnly=false, QString *errorMsg=nullptr) const
Creates a Voronoi diagram for the nodes contained within the geometry.
bool intersects(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Checks if geom intersects this.
void geometryChanged() override
Should be called whenever the geometry associated with the engine has been modified and the engine mu...
bool overlaps(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Checks if geom overlaps this.
double area(QString *errorMsg=nullptr) const override
double length(QString *errorMsg=nullptr) const override
std::unique_ptr< QgsAbstractGeometry > largestEmptyCircle(double tolerance, const QgsAbstractGeometry *boundary=nullptr, QString *errorMsg=nullptr) const
Constructs the Largest Empty Circle for a set of obstacle geometries, up to a specified tolerance.
Qgis::CoverageValidityResult validateCoverage(double gapWidth, std::unique_ptr< QgsAbstractGeometry > *invalidEdges, QString *errorMsg=nullptr) const
Analyze a coverage (represented as a collection of polygonal geometry with exactly matching edge geom...
double frechetDistanceDensify(const QgsAbstractGeometry *geom, double densifyFraction, QString *errorMsg=nullptr) const
Returns the Fréchet distance between this geometry and geom, restricted to discrete points for both g...
static QgsPoint coordSeqPoint(const GEOSCoordSequence *cs, int i, bool hasZ, bool hasM)
QgsPoint * pointOnSurface(QString *errorMsg=nullptr) const override
Calculate a point that is guaranteed to be on the surface of this.
static QgsGeometry geometryFromGeos(GEOSGeometry *geos)
Creates a new QgsGeometry object, feeding in a geometry in GEOS format.
Line string geometry type, with support for z-dimension and m-values.
const double * yData() const
Returns a const pointer to the y vertex data.
const double * xData() const
Returns a const pointer to the x vertex data.
QVector< double > xVector() const
Returns the x vertex values as a vector.
const double * zData() const
Returns a const pointer to the z vertex data, or nullptr if the linestring does not have z values.
int numPoints() const override
Returns the number of points in the curve.
QgsPoint pointN(int i) const
Returns the specified point from inside the line string.
QVector< double > yVector() const
Returns the y vertex values as a vector.
double yAt(int index) const override
Returns the y-coordinate of the specified node in the line string.
QVector< double > zVector() const
Returns the z vertex values as a vector.
double closestSegment(const QgsPoint &pt, QgsPoint &segmentPt, QgsVertexId &vertexAfter, int *leftOf=nullptr, double epsilon=4 *std::numeric_limits< double >::epsilon()) const override
Searches for the closest segment of the geometry to a given point.
const double * mData() const
Returns a const pointer to the m vertex data, or nullptr if the linestring does not have m values.
void addVertex(const QgsPoint &pt)
Adds a new vertex to the end of the line string.
QgsLineString * clone() const override
Clones the geometry by performing a deep copy.
double xAt(int index) const override
Returns the x-coordinate of the specified node in the line string.
Multi curve geometry collection.
bool addGeometry(QgsAbstractGeometry *g) override
Adds a geometry and takes ownership. Returns true in case of success.
Multi line string geometry collection.
Multi point geometry collection.
Multi polygon geometry collection.
Custom exception class which is raised when an operation is not supported.
A class to represent a 2D point.
Point geometry type, with support for z-dimension and m-values.
double distance(double x, double y) const
Returns the Cartesian 2D distance between this point and a specified x, y coordinate.
A rectangle specified with double values.
double xMinimum() const
Returns the x minimum value (left side of rectangle).
void setYMinimum(double y)
Set the minimum y value.
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
void setXMinimum(double x)
Set the minimum x value.
double width() const
Returns the width of the rectangle.
double xMaximum() const
Returns the x maximum value (right side of rectangle).
bool isNull() const
Test if the rectangle is null (holding no spatial information).
double yMaximum() const
Returns the y maximum value (top side of rectangle).
void setYMaximum(double y)
Set the maximum y value.
void setXMaximum(double x)
Set the maximum x value.
bool isEmpty() const
Returns true if the rectangle has no area.
double height() const
Returns the height of the rectangle.
static Qgis::GeometryType geometryType(Qgis::WkbType type)
Returns the geometry type for a WKB type, e.g., both MultiPolygon and CurvePolygon would have a Polyg...
static bool isMultiType(Qgis::WkbType type)
Returns true if the WKB type is a multi type.
static Qgis::WkbType flatType(Qgis::WkbType type)
Returns the flat type for a WKB type.
Contains geos related utilities and functions.
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)
#define QgsDebugError(str)
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.
struct GEOSGeom_t GEOSGeometry