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();
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< QgsAbstractGeometry > splitGeom(
fromGeos( GEOSsplitPoint ) );
1025 std::unique_ptr< QgsMultiPoint > splitPoints( qgsgeometry_cast<QgsMultiPoint *>( splitGeom->clone() ) );
1028 QgsPoint *splitPoint = qgsgeometry_cast<QgsPoint *>( splitGeom->clone() );
1034 splitPoints->addGeometry( splitPoint );
1040 for (
int i = 0; i < multiCurve->numGeometries(); ++i )
1042 const QgsLineString *line = qgsgeometry_cast<const QgsLineString *>( multiCurve->geometryN( i ) );
1045 const QgsCurve *curve = qgsgeometry_cast<const QgsCurve *>( multiCurve->geometryN( i ) );
1053 QMap< int, QVector< QPair< double, QgsPoint > > >pointMap;
1054 for (
int p = 0; p < splitPoints->numGeometries(); ++p )
1056 const QgsPoint *intersectionPoint = splitPoints->pointN( p );
1061 line->
closestSegment( *intersectionPoint, segmentPoint2D, nextVertex );
1069 const QPair< double, QgsPoint > pair = qMakePair(
distance, *correctSegmentPoint.get() );
1070 if ( pointMap.contains( nextVertex.
vertex - 1 ) )
1071 pointMap[ nextVertex.
vertex - 1 ].append( pair );
1073 pointMap[ nextVertex.
vertex - 1 ] = QVector< QPair< double, QgsPoint > >() << pair;
1078 for (
auto &p : pointMap )
1080 std::sort( p.begin(), p.end(), [](
const QPair< double, QgsPoint > &a,
const QPair< double, QgsPoint > &b ) { return a.first < b.first; } );
1087 for (
int j = 0; j < nVertices; ++j )
1091 if ( pointMap.contains( j ) )
1094 for (
int k = 0; k < pointMap[ j ].size(); ++k )
1096 splitPoint = pointMap[ j ][k].second;
1097 if ( splitPoint == currentPoint )
1103 else if ( splitPoint == line->
pointN( j + 1 ) )
1122 return asGeos( &lines, mPrecision );
1127 Q_UNUSED( skipIntersectionCheck )
1134 geos::unique_ptr intersectGeom( GEOSIntersection_r( geosinit()->ctxt, splitLine, mGeos.get() ) );
1135 if ( !intersectGeom || GEOSisEmpty_r( geosinit()->ctxt, intersectGeom.get() ) )
1139 int linearIntersect = GEOSRelatePattern_r( geosinit()->ctxt, mGeos.get(), splitLine,
"1********" );
1140 if ( linearIntersect > 0 )
1144 splitGeom = linePointDifference( intersectGeom.get() );
1149 QVector<GEOSGeometry *> lineGeoms;
1151 int splitType = GEOSGeomTypeId_r( geosinit()->ctxt, splitGeom.get() );
1152 if ( splitType == GEOS_MULTILINESTRING )
1154 int nGeoms = GEOSGetNumGeometries_r( geosinit()->ctxt, splitGeom.get() );
1155 lineGeoms.reserve( nGeoms );
1156 for (
int i = 0; i < nGeoms; ++i )
1157 lineGeoms << GEOSGeom_clone_r( geosinit()->ctxt, GEOSGetGeometryN_r( geosinit()->ctxt, splitGeom.get(), i ) );
1162 lineGeoms << GEOSGeom_clone_r( geosinit()->ctxt, splitGeom.get() );
1165 mergeGeometriesMultiTypeSplit( lineGeoms );
1167 for (
int i = 0; i < lineGeoms.size(); ++i )
1170 GEOSGeom_destroy_r( geosinit()->ctxt, lineGeoms[i] );
1186 if ( !mGeosPrepared )
1190 if ( !skipIntersectionCheck && !GEOSPreparedIntersects_r( geosinit()->ctxt, mGeosPrepared.get(), splitLine ) )
1195 if ( !nodedGeometry )
1199 geos::unique_ptr polygons( GEOSPolygonize_r( geosinit()->ctxt, &noded, 1 ) );
1200 if ( !polygons || numberOfGeometries( polygons.get() ) == 0 )
1207 QVector<GEOSGeometry *> testedGeometries;
1212 for (
int i = 0; i < numberOfGeometries( polygons.get() ); i++ )
1214 const GEOSGeometry *polygon = GEOSGetGeometryN_r( geosinit()->ctxt, polygons.get(), i );
1218 testedGeometries << GEOSGeom_clone_r( geosinit()->ctxt, polygon );
1221 int nGeometriesThis = numberOfGeometries( mGeos.get() );
1222 if ( testedGeometries.empty() || testedGeometries.size() == nGeometriesThis )
1225 for (
int i = 0; i < testedGeometries.size(); ++i )
1227 GEOSGeom_destroy_r( geosinit()->ctxt, testedGeometries[i] );
1236 mergeGeometriesMultiTypeSplit( testedGeometries );
1239 for ( i = 0; i < testedGeometries.size() && GEOSisValid_r( geosinit()->ctxt, testedGeometries[i] ); ++i )
1242 if ( i < testedGeometries.size() )
1244 for ( i = 0; i < testedGeometries.size(); ++i )
1245 GEOSGeom_destroy_r( geosinit()->ctxt, testedGeometries[i] );
1250 for ( i = 0; i < testedGeometries.size(); ++i )
1253 GEOSGeom_destroy_r( geosinit()->ctxt, testedGeometries[i] );
1261 if ( !splitLine || !geom )
1265 if ( GEOSGeomTypeId_r( geosinit()->ctxt, geom ) == GEOS_POLYGON || GEOSGeomTypeId_r( geosinit()->ctxt, geom ) == GEOS_MULTIPOLYGON )
1266 geometryBoundary.reset( GEOSBoundary_r( geosinit()->ctxt, geom ) );
1268 geometryBoundary.reset( GEOSGeom_clone_r( geosinit()->ctxt, geom ) );
1270 geos::unique_ptr splitLineClone( GEOSGeom_clone_r( geosinit()->ctxt, splitLine ) );
1271 geos::unique_ptr unionGeometry( GEOSUnion_r( geosinit()->ctxt, splitLineClone.get(), geometryBoundary.get() ) );
1273 return unionGeometry;
1276int QgsGeos::mergeGeometriesMultiTypeSplit( QVector<GEOSGeometry *> &splitResult )
const
1282 int type = GEOSGeomTypeId_r( geosinit()->ctxt, mGeos.get() );
1283 if ( type != GEOS_GEOMETRYCOLLECTION &&
1284 type != GEOS_MULTILINESTRING &&
1285 type != GEOS_MULTIPOLYGON &&
1286 type != GEOS_MULTIPOINT )
1289 QVector<GEOSGeometry *> copyList = splitResult;
1290 splitResult.clear();
1293 QVector<GEOSGeometry *> unionGeom;
1295 for (
int i = 0; i < copyList.size(); ++i )
1298 bool isPart =
false;
1299 for (
int j = 0; j < GEOSGetNumGeometries_r( geosinit()->ctxt, mGeos.get() ); j++ )
1301 if ( GEOSEquals_r( geosinit()->ctxt, copyList[i], GEOSGetGeometryN_r( geosinit()->ctxt, mGeos.get(), j ) ) )
1310 unionGeom << copyList[i];
1314 QVector<GEOSGeometry *> geomVector;
1315 geomVector << copyList[i];
1317 if ( type == GEOS_MULTILINESTRING )
1318 splitResult << createGeosCollection( GEOS_MULTILINESTRING, geomVector ).release();
1319 else if ( type == GEOS_MULTIPOLYGON )
1320 splitResult << createGeosCollection( GEOS_MULTIPOLYGON, geomVector ).release();
1322 GEOSGeom_destroy_r( geosinit()->ctxt, copyList[i] );
1327 if ( !unionGeom.isEmpty() )
1329 if ( type == GEOS_MULTILINESTRING )
1330 splitResult << createGeosCollection( GEOS_MULTILINESTRING, unionGeom ).release();
1331 else if ( type == GEOS_MULTIPOLYGON )
1332 splitResult << createGeosCollection( GEOS_MULTIPOLYGON, unionGeom ).release();
1342geos::unique_ptr QgsGeos::createGeosCollection(
int typeId,
const QVector<GEOSGeometry *> &geoms )
1344 int nNullGeoms = geoms.count(
nullptr );
1345 int nNotNullGeoms = geoms.size() - nNullGeoms;
1354 QVector<GEOSGeometry *>::const_iterator geomIt = geoms.constBegin();
1355 for ( ; geomIt != geoms.constEnd(); ++geomIt )
1359 if ( GEOSisEmpty_r( geosinit()->ctxt, *geomIt ) )
1364 GEOSGeom_destroy_r( geosinit()->ctxt, *geomIt );
1368 geomarr[i] = *geomIt;
1377 geom.reset( GEOSGeom_createCollection_r( geosinit()->ctxt, typeId, geomarr, nNotNullGeoms ) );
1379 catch ( GEOSException & )
1395 int nCoordDims = GEOSGeom_getCoordinateDimension_r( geosinit()->ctxt,
geos );
1396 int nDims = GEOSGeom_getDimensions_r( geosinit()->ctxt,
geos );
1397 bool hasZ = ( nCoordDims == 3 );
1398 bool hasM = ( ( nDims - nCoordDims ) == 1 );
1400 switch ( GEOSGeomTypeId_r( geosinit()->ctxt,
geos ) )
1404 if ( GEOSisEmpty_r( geosinit()->ctxt,
geos ) )
1407 const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq_r( geosinit()->ctxt,
geos );
1408 unsigned int nPoints = 0;
1409 GEOSCoordSeq_getSize_r( geosinit()->ctxt, cs, &nPoints );
1410 return nPoints > 0 ? std::unique_ptr<QgsAbstractGeometry>(
coordSeqPoint( cs, 0, hasZ, hasM ).clone() ) :
nullptr;
1412 case GEOS_LINESTRING:
1414 return sequenceToLinestring(
geos, hasZ, hasM );
1420 case GEOS_MULTIPOINT:
1422 std::unique_ptr< QgsMultiPoint > multiPoint(
new QgsMultiPoint() );
1423 int nParts = GEOSGetNumGeometries_r( geosinit()->ctxt,
geos );
1424 multiPoint->reserve( nParts );
1425 for (
int i = 0; i < nParts; ++i )
1427 const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, GEOSGetGeometryN_r( geosinit()->ctxt,
geos, i ) );
1430 unsigned int nPoints = 0;
1431 GEOSCoordSeq_getSize_r( geosinit()->ctxt, cs, &nPoints );
1433 multiPoint->addGeometry(
coordSeqPoint( cs, 0, hasZ, hasM ).clone() );
1436 return std::move( multiPoint );
1438 case GEOS_MULTILINESTRING:
1441 int nParts = GEOSGetNumGeometries_r( geosinit()->ctxt,
geos );
1442 multiLineString->reserve( nParts );
1443 for (
int i = 0; i < nParts; ++i )
1445 std::unique_ptr< QgsLineString >line( sequenceToLinestring( GEOSGetGeometryN_r( geosinit()->ctxt,
geos, i ), hasZ, hasM ) );
1448 multiLineString->addGeometry( line.release() );
1451 return std::move( multiLineString );
1453 case GEOS_MULTIPOLYGON:
1455 std::unique_ptr< QgsMultiPolygon > multiPolygon(
new QgsMultiPolygon() );
1457 int nParts = GEOSGetNumGeometries_r( geosinit()->ctxt,
geos );
1458 multiPolygon->reserve( nParts );
1459 for (
int i = 0; i < nParts; ++i )
1461 std::unique_ptr< QgsPolygon > poly =
fromGeosPolygon( GEOSGetGeometryN_r( geosinit()->ctxt,
geos, i ) );
1464 multiPolygon->addGeometry( poly.release() );
1467 return std::move( multiPolygon );
1469 case GEOS_GEOMETRYCOLLECTION:
1472 int nParts = GEOSGetNumGeometries_r( geosinit()->ctxt,
geos );
1473 geomCollection->reserve( nParts );
1474 for (
int i = 0; i < nParts; ++i )
1476 std::unique_ptr< QgsAbstractGeometry > geom(
fromGeos( GEOSGetGeometryN_r( geosinit()->ctxt,
geos, i ) ) );
1479 geomCollection->addGeometry( geom.release() );
1482 return std::move( geomCollection );
1490 if ( GEOSGeomTypeId_r( geosinit()->ctxt,
geos ) != GEOS_POLYGON )
1495 int nCoordDims = GEOSGeom_getCoordinateDimension_r( geosinit()->ctxt,
geos );
1496 int nDims = GEOSGeom_getDimensions_r( geosinit()->ctxt,
geos );
1497 bool hasZ = ( nCoordDims == 3 );
1498 bool hasM = ( ( nDims - nCoordDims ) == 1 );
1500 std::unique_ptr< QgsPolygon > polygon(
new QgsPolygon() );
1502 const GEOSGeometry *ring = GEOSGetExteriorRing_r( geosinit()->ctxt,
geos );
1505 polygon->setExteriorRing( sequenceToLinestring( ring, hasZ, hasM ).release() );
1508 QVector<QgsCurve *> interiorRings;
1509 const int ringCount = GEOSGetNumInteriorRings_r( geosinit()->ctxt,
geos );
1510 interiorRings.reserve( ringCount );
1511 for (
int i = 0; i < ringCount; ++i )
1513 ring = GEOSGetInteriorRingN_r( geosinit()->ctxt,
geos, i );
1516 interiorRings.push_back( sequenceToLinestring( ring, hasZ, hasM ).release() );
1519 polygon->setInteriorRings( interiorRings );
1524std::unique_ptr<QgsLineString> QgsGeos::sequenceToLinestring(
const GEOSGeometry *
geos,
bool hasZ,
bool hasM )
1526 const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq_r( geosinit()->ctxt,
geos );
1528 unsigned int nPoints;
1529 GEOSCoordSeq_getSize_r( geosinit()->ctxt, cs, &nPoints );
1531 QVector< double > xOut( nPoints );
1532 QVector< double > yOut( nPoints );
1533 QVector< double > zOut;
1535 zOut.resize( nPoints );
1536 QVector< double > mOut;
1538 mOut.resize( nPoints );
1540 double *x = xOut.data();
1541 double *y = yOut.data();
1542 double *z = zOut.data();
1543 double *m = mOut.data();
1545#if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=10 )
1546 GEOSCoordSeq_copyToArrays_r( geosinit()->ctxt, cs, x, y, hasZ ? z :
nullptr, hasM ? m :
nullptr );
1548 for (
unsigned int i = 0; i < nPoints; ++i )
1551 GEOSCoordSeq_getXYZ_r( geosinit()->ctxt, cs, i, x++, y++, z++ );
1553 GEOSCoordSeq_getXY_r( geosinit()->ctxt, cs, i, x++, y++ );
1556 GEOSCoordSeq_getOrdinate_r( geosinit()->ctxt, cs, i, 3, m++ );
1560 std::unique_ptr< QgsLineString > line(
new QgsLineString( xOut, yOut, zOut, mOut ) );
1569 int geometryType = GEOSGeomTypeId_r( geosinit()->ctxt, g );
1570 if ( geometryType == GEOS_POINT || geometryType == GEOS_LINESTRING || geometryType == GEOS_LINEARRING
1571 || geometryType == GEOS_POLYGON )
1575 return GEOSGetNumGeometries_r( geosinit()->ctxt, g );
1589 GEOSCoordSeq_getXYZ_r( geosinit()->ctxt, cs, i, &x, &y, &z );
1591 GEOSCoordSeq_getXY_r( geosinit()->ctxt, cs, i, &x, &y );
1594 GEOSCoordSeq_getOrdinate_r( geosinit()->ctxt, cs, i, 3, &m );
1630 int geosType = GEOS_GEOMETRYCOLLECTION;
1636 case Qgis::GeometryType::Point:
1637 geosType = GEOS_MULTIPOINT;
1640 case Qgis::GeometryType::Line:
1641 geosType = GEOS_MULTILINESTRING;
1644 case Qgis::GeometryType::Polygon:
1645 geosType = GEOS_MULTIPOLYGON;
1648 case Qgis::GeometryType::Unknown:
1649 case Qgis::GeometryType::Null:
1660 QVector< GEOSGeometry * > geomVector(
c->numGeometries() );
1661 for (
int i = 0; i <
c->numGeometries(); ++i )
1665 return createGeosCollection( geosType, geomVector );
1671 case Qgis::GeometryType::Point:
1672 return createGeosPoint(
static_cast<const QgsPoint *
>( geom ), coordDims,
precision );
1674 case Qgis::GeometryType::Line:
1677 case Qgis::GeometryType::Polygon:
1680 case Qgis::GeometryType::Unknown:
1681 case Qgis::GeometryType::Null:
1690 if ( !mGeos || !geom )
1701 const double gridSize = parameters.
gridSize();
1708 case OverlayIntersection:
1711 opGeom.reset( GEOSIntersectionPrec_r( geosinit()->ctxt, mGeos.get(), geosGeom.get(), gridSize ) );
1715 opGeom.reset( GEOSIntersection_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) );
1719 case OverlayDifference:
1722 opGeom.reset( GEOSDifferencePrec_r( geosinit()->ctxt, mGeos.get(), geosGeom.get(), gridSize ) );
1726 opGeom.reset( GEOSDifference_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) );
1735 unionGeometry.reset( GEOSUnionPrec_r( geosinit()->ctxt, mGeos.get(), geosGeom.get(), gridSize ) );
1739 unionGeometry.reset( GEOSUnion_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) );
1742 if ( unionGeometry && GEOSGeomTypeId_r( geosinit()->ctxt, unionGeometry.get() ) == GEOS_MULTILINESTRING )
1744 geos::unique_ptr mergedLines( GEOSLineMerge_r( geosinit()->ctxt, unionGeometry.get() ) );
1747 unionGeometry = std::move( mergedLines );
1751 opGeom = std::move( unionGeometry );
1755 case OverlaySymDifference:
1758 opGeom.reset( GEOSSymDifferencePrec_r( geosinit()->ctxt, mGeos.get(), geosGeom.get(), gridSize ) );
1762 opGeom.reset( GEOSSymDifference_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) );
1768 catch ( GEOSException &e )
1770 logError( QStringLiteral(
"GEOS" ), e.what() );
1773 *errorMsg = e.what();
1779bool QgsGeos::relation(
const QgsAbstractGeometry *geom, Relation r, QString *errorMsg )
const
1781 if ( !mGeos || !geom )
1792 bool result =
false;
1795 if ( mGeosPrepared )
1799 case RelationIntersects:
1800 result = ( GEOSPreparedIntersects_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1802 case RelationTouches:
1803 result = ( GEOSPreparedTouches_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1805 case RelationCrosses:
1806 result = ( GEOSPreparedCrosses_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1808 case RelationWithin:
1809 result = ( GEOSPreparedWithin_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1811 case RelationContains:
1812 result = ( GEOSPreparedContains_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1814 case RelationDisjoint:
1815 result = ( GEOSPreparedDisjoint_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1817 case RelationOverlaps:
1818 result = ( GEOSPreparedOverlaps_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1826 case RelationIntersects:
1827 result = ( GEOSIntersects_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1829 case RelationTouches:
1830 result = ( GEOSTouches_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1832 case RelationCrosses:
1833 result = ( GEOSCrosses_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1835 case RelationWithin:
1836 result = ( GEOSWithin_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1838 case RelationContains:
1839 result = ( GEOSContains_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1841 case RelationDisjoint:
1842 result = ( GEOSDisjoint_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1844 case RelationOverlaps:
1845 result = ( GEOSOverlaps_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1849 catch ( GEOSException &e )
1851 logError( QStringLiteral(
"GEOS" ), e.what() );
1854 *errorMsg = e.what();
1872 geos.reset( GEOSBuffer_r( geosinit()->ctxt, mGeos.get(),
distance, segments ) );
1888 geos.reset( GEOSBufferWithStyle_r( geosinit()->ctxt, mGeos.get(),
distance, segments,
static_cast< int >( endCapStyle ),
static_cast< int >( joinStyle ), miterLimit ) );
1903 geos.reset( GEOSTopologyPreserveSimplify_r( geosinit()->ctxt, mGeos.get(), tolerance ) );
1918 geos.reset( GEOSInterpolate_r( geosinit()->ctxt, mGeos.get(),
distance ) );
1937 geos.reset( GEOSGetCentroid_r( geosinit()->ctxt, mGeos.get() ) );
1942 GEOSGeomGetX_r( geosinit()->ctxt,
geos.get(), &x );
1943 GEOSGeomGetY_r( geosinit()->ctxt,
geos.get(), &y );
1959 geos.reset( GEOSEnvelope_r( geosinit()->ctxt, mGeos.get() ) );
1978 geos.reset( GEOSPointOnSurface_r( geosinit()->ctxt, mGeos.get() ) );
1980 if ( !
geos || GEOSisEmpty_r( geosinit()->ctxt,
geos.get() ) != 0 )
1985 GEOSGeomGetX_r( geosinit()->ctxt,
geos.get(), &x );
1986 GEOSGeomGetY_r( geosinit()->ctxt,
geos.get(), &y );
2002 geos::unique_ptr cHull( GEOSConvexHull_r( geosinit()->ctxt, mGeos.get() ) );
2003 std::unique_ptr< QgsAbstractGeometry > cHullGeom =
fromGeos( cHull.get() );
2004 return cHullGeom.release();
2011#if GEOS_VERSION_MAJOR==3 && GEOS_VERSION_MINOR<11
2013 ( void )targetPercent;
2015 throw QgsNotSupportedException( QObject::tr(
"Calculating concaveHull requires a QGIS build based on GEOS 3.11 or later" ) );
2026 return concaveHullGeom.release();
2043 char res = GEOSisValidDetail_r( geosinit()->ctxt, mGeos.get(), allowSelfTouchingHoles ? GEOSVALID_ALLOW_SELFTOUCHING_RING_FORMING_HOLE : 0, &r, &g1 );
2044 const bool invalid = res != 1;
2049 error = QString( r );
2050 GEOSFree_r( geosinit()->ctxt, r );
2053 if ( invalid && errorMsg )
2057 if ( translatedErrors.empty() )
2060 translatedErrors.insert( QStringLiteral(
"topology validation error" ), QObject::tr(
"Topology validation error",
"GEOS Error" ) );
2061 translatedErrors.insert( QStringLiteral(
"repeated point" ), QObject::tr(
"Repeated point",
"GEOS Error" ) );
2062 translatedErrors.insert( QStringLiteral(
"hole lies outside shell" ), QObject::tr(
"Hole lies outside shell",
"GEOS Error" ) );
2063 translatedErrors.insert( QStringLiteral(
"holes are nested" ), QObject::tr(
"Holes are nested",
"GEOS Error" ) );
2064 translatedErrors.insert( QStringLiteral(
"interior is disconnected" ), QObject::tr(
"Interior is disconnected",
"GEOS Error" ) );
2065 translatedErrors.insert( QStringLiteral(
"self-intersection" ), QObject::tr(
"Self-intersection",
"GEOS Error" ) );
2066 translatedErrors.insert( QStringLiteral(
"ring self-intersection" ), QObject::tr(
"Ring self-intersection",
"GEOS Error" ) );
2067 translatedErrors.insert( QStringLiteral(
"nested shells" ), QObject::tr(
"Nested shells",
"GEOS Error" ) );
2068 translatedErrors.insert( QStringLiteral(
"duplicate rings" ), QObject::tr(
"Duplicate rings",
"GEOS Error" ) );
2069 translatedErrors.insert( QStringLiteral(
"too few points in geometry component" ), QObject::tr(
"Too few points in geometry component",
"GEOS Error" ) );
2070 translatedErrors.insert( QStringLiteral(
"invalid coordinate" ), QObject::tr(
"Invalid coordinate",
"GEOS Error" ) );
2071 translatedErrors.insert( QStringLiteral(
"ring is not closed" ), QObject::tr(
"Ring is not closed",
"GEOS Error" ) );
2074 *errorMsg = translatedErrors.value( error.toLower(), error );
2076 if ( g1 && errorLoc )
2082 GEOSGeom_destroy_r( geosinit()->ctxt, g1 );
2092 if ( !mGeos || !geom )
2104 bool equal = GEOSEquals_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() );
2119 return GEOSisEmpty_r( geosinit()->ctxt, mGeos.get() );
2133 return GEOSisSimple_r( geosinit()->ctxt, mGeos.get() );
2138GEOSCoordSequence *QgsGeos::createCoordinateSequence(
const QgsCurve *curve,
double precision,
bool forceClose )
2140 GEOSContextHandle_t ctxt = geosinit()->ctxt;
2142 std::unique_ptr< QgsLineString > segmentized;
2143 const QgsLineString *line = qgsgeometry_cast<const QgsLineString *>( curve );
2148 line = segmentized.get();
2155 GEOSCoordSequence *coordSeq =
nullptr;
2157 const int numPoints = line->
numPoints();
2159 const bool hasZ = line->
is3D();
2161#if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=10 )
2164 if ( !forceClose || ( line->
pointN( 0 ) == line->
pointN( numPoints - 1 ) ) )
2169 coordSeq = GEOSCoordSeq_copyFromArrays_r( ctxt, line->
xData(), line->
yData(), line->
zData(),
nullptr, numPoints );
2172 QgsDebugError( QStringLiteral(
"GEOS Exception: Could not create coordinate sequence for %1 points" ).arg( numPoints ) );
2180 QVector< double > x = line->
xVector();
2181 if ( numPoints > 0 )
2182 x.append( x.at( 0 ) );
2183 QVector< double > y = line->
yVector();
2184 if ( numPoints > 0 )
2185 y.append( y.at( 0 ) );
2186 QVector< double > z = line->
zVector();
2187 if ( hasZ && numPoints > 0 )
2188 z.append( z.at( 0 ) );
2191 coordSeq = GEOSCoordSeq_copyFromArrays_r( ctxt, x.constData(), y.constData(), !hasZ ?
nullptr : z.constData(),
nullptr, numPoints + 1 );
2194 QgsDebugError( QStringLiteral(
"GEOS Exception: Could not create closed coordinate sequence for %1 points" ).arg( numPoints + 1 ) );
2205 const bool hasM =
false;
2216 int numOutPoints = numPoints;
2217 if ( forceClose && ( line->
pointN( 0 ) != line->
pointN( numPoints - 1 ) ) )
2224 coordSeq = GEOSCoordSeq_create_r( ctxt, numOutPoints, coordDims );
2227 QgsDebugError( QStringLiteral(
"GEOS Exception: Could not create coordinate sequence for %1 points in %2 dimensions" ).arg( numPoints ).arg( coordDims ) );
2231 const double *xData = line->
xData();
2232 const double *yData = line->
yData();
2233 const double *zData = hasZ ? line->
zData() :
nullptr;
2234 const double *mData = hasM ? line->
mData() :
nullptr;
2238 for (
int i = 0; i < numOutPoints; ++i )
2240 if ( i >= numPoints )
2243 xData = line->
xData();
2244 yData = line->
yData();
2245 zData = hasZ ? line->
zData() :
nullptr;
2246 mData = hasM ? line->
mData() :
nullptr;
2258 GEOSCoordSeq_setOrdinate_r( ctxt, coordSeq, i, 3, *mData++ );
2264 for (
int i = 0; i < numOutPoints; ++i )
2266 if ( i >= numPoints )
2269 xData = line->
xData();
2270 yData = line->
yData();
2271 zData = hasZ ? line->
zData() :
nullptr;
2272 mData = hasM ? line->
mData() :
nullptr;
2276 GEOSCoordSeq_setXYZ_r( ctxt, coordSeq, i, *xData++, *yData++, *zData++ );
2280 GEOSCoordSeq_setXY_r( ctxt, coordSeq, i, *xData++, *yData++ );
2284 GEOSCoordSeq_setOrdinate_r( ctxt, coordSeq, i, 3, *mData++ );
2296 const QgsPoint *pt = qgsgeometry_cast<const QgsPoint *>( point );
2303geos::unique_ptr QgsGeos::createGeosPointXY(
double x,
double y,
bool hasZ,
double z,
bool hasM,
double m,
int coordDims,
double precision )
2311 if ( coordDims == 2 )
2317 geosPoint.reset( GEOSGeom_createPointFromXY_r( geosinit()->ctxt, x, y ) );
2321 GEOSCoordSequence *coordSeq = GEOSCoordSeq_create_r( geosinit()->ctxt, 1, coordDims );
2324 QgsDebugError( QStringLiteral(
"GEOS Exception: Could not create coordinate sequence for point with %1 dimensions" ).arg( coordDims ) );
2329 GEOSCoordSeq_setX_r( geosinit()->ctxt, coordSeq, 0, std::round( x /
precision ) *
precision );
2330 GEOSCoordSeq_setY_r( geosinit()->ctxt, coordSeq, 0, std::round( y /
precision ) *
precision );
2333 GEOSCoordSeq_setOrdinate_r( geosinit()->ctxt, coordSeq, 0, 2, std::round( z /
precision ) *
precision );
2338 GEOSCoordSeq_setX_r( geosinit()->ctxt, coordSeq, 0, x );
2339 GEOSCoordSeq_setY_r( geosinit()->ctxt, coordSeq, 0, y );
2342 GEOSCoordSeq_setOrdinate_r( geosinit()->ctxt, coordSeq, 0, 2, z );
2348 GEOSCoordSeq_setOrdinate_r( geosinit()->ctxt, coordSeq, 0, 3, m );
2351 geosPoint.reset( GEOSGeom_createPoint_r( geosinit()->ctxt, coordSeq ) );
2359 const QgsCurve *
c = qgsgeometry_cast<const QgsCurve *>( curve );
2363 GEOSCoordSequence *coordSeq = createCoordinateSequence(
c,
precision );
2370 geosGeom.reset( GEOSGeom_createLineString_r( geosinit()->ctxt, coordSeq ) );
2378 const QgsCurvePolygon *polygon = qgsgeometry_cast<const QgsCurvePolygon *>( poly );
2383 if ( !exteriorRing )
2391 geos::unique_ptr exteriorRingGeos( GEOSGeom_createLinearRing_r( geosinit()->ctxt, createCoordinateSequence( exteriorRing,
precision,
true ) ) );
2400 for (
int i = 0; i < nHoles; ++i )
2403 holes[i] = GEOSGeom_createLinearRing_r( geosinit()->ctxt, createCoordinateSequence( interiorRing,
precision,
true ) );
2405 geosPolygon.reset( GEOSGeom_createPolygon_r( geosinit()->ctxt, exteriorRingGeos.release(), holes, nHoles ) );
2425 offset.reset( GEOSOffsetCurve_r( geosinit()->ctxt, mGeos.get(),
distance, segments,
static_cast< int >( joinStyle ), miterLimit ) );
2428 std::unique_ptr< QgsAbstractGeometry > offsetGeom =
fromGeos( offset.get() );
2429 return offsetGeom.release();
2443 GEOSBufferParams_setSingleSided_r( geosinit()->ctxt, bp.get(), 1 );
2444 GEOSBufferParams_setQuadrantSegments_r( geosinit()->ctxt, bp.get(), segments );
2445 GEOSBufferParams_setJoinStyle_r( geosinit()->ctxt, bp.get(),
static_cast< int >( joinStyle ) );
2446 GEOSBufferParams_setMitreLimit_r( geosinit()->ctxt, bp.get(), miterLimit );
2448 if ( side == Qgis::BufferSide::Right )
2452 geos.reset( GEOSBufferWithParams_r( geosinit()->ctxt, mGeos.get(), bp.get(),
distance ) );
2468 geos.reset( GEOSMaximumInscribedCircle_r( geosinit()->ctxt, mGeos.get(), tolerance ) );
2486 boundaryGeos =
asGeos( boundary );
2488 geos.reset( GEOSLargestEmptyCircle_r( geosinit()->ctxt, mGeos.get(), boundaryGeos.get(), tolerance ) );
2504 geos.reset( GEOSMinimumWidth_r( geosinit()->ctxt, mGeos.get() ) );
2514 return std::numeric_limits< double >::quiet_NaN();
2521 if ( GEOSMinimumClearance_r( geosinit()->ctxt, mGeos.get(), &res ) != 0 )
2522 return std::numeric_limits< double >::quiet_NaN();
2538 geos.reset( GEOSMinimumClearanceLine_r( geosinit()->ctxt, mGeos.get() ) );
2554 geos.reset( GEOSNode_r( geosinit()->ctxt, mGeos.get() ) );
2562 if ( !mGeos || !other )
2574 geos.reset( GEOSSharedPaths_r( geosinit()->ctxt, mGeos.get(), otherGeos.get() ) );
2594 geos::unique_ptr reshapeLineGeos = createGeosLinestring( &reshapeWithLine, mPrecision );
2597 int numGeoms = GEOSGetNumGeometries_r( geosinit()->ctxt, mGeos.get() );
2598 if ( numGeoms == -1 )
2607 bool isMultiGeom =
false;
2608 int geosTypeId = GEOSGeomTypeId_r( geosinit()->ctxt, mGeos.get() );
2609 if ( geosTypeId == GEOS_MULTILINESTRING || geosTypeId == GEOS_MULTIPOLYGON )
2619 reshapedGeometry = reshapeLine( mGeos.get(), reshapeLineGeos.get(), mPrecision );
2623 reshapedGeometry = reshapePolygon( mGeos.get(), reshapeLineGeos.get(), mPrecision );
2628 std::unique_ptr< QgsAbstractGeometry > reshapeResult =
fromGeos( reshapedGeometry.get() );
2629 return reshapeResult;
2636 bool reshapeTookPlace =
false;
2641 for (
int i = 0; i < numGeoms; ++i )
2644 currentReshapeGeometry = reshapeLine( GEOSGetGeometryN_r( geosinit()->ctxt, mGeos.get(), i ), reshapeLineGeos.get(), mPrecision );
2646 currentReshapeGeometry = reshapePolygon( GEOSGetGeometryN_r( geosinit()->ctxt, mGeos.get(), i ), reshapeLineGeos.get(), mPrecision );
2648 if ( currentReshapeGeometry )
2650 newGeoms[i] = currentReshapeGeometry.release();
2651 reshapeTookPlace =
true;
2655 newGeoms[i] = GEOSGeom_clone_r( geosinit()->ctxt, GEOSGetGeometryN_r( geosinit()->ctxt, mGeos.get(), i ) );
2662 newMultiGeom.reset( GEOSGeom_createCollection_r( geosinit()->ctxt, GEOS_MULTILINESTRING, newGeoms, numGeoms ) );
2666 newMultiGeom.reset( GEOSGeom_createCollection_r( geosinit()->ctxt, GEOS_MULTIPOLYGON, newGeoms, numGeoms ) );
2670 if ( !newMultiGeom )
2676 if ( reshapeTookPlace )
2680 std::unique_ptr< QgsAbstractGeometry > reshapedMultiGeom =
fromGeos( newMultiGeom.get() );
2681 return reshapedMultiGeom;
2703 if ( GEOSGeomTypeId_r( geosinit()->ctxt, mGeos.get() ) != GEOS_MULTILINESTRING )
2709 geos.reset( GEOSLineMerge_r( geosinit()->ctxt, mGeos.get() ) );
2733 if ( mGeosPrepared )
2735 nearestCoord.reset( GEOSPreparedNearestPoints_r( geosinit()->ctxt, mGeosPrepared.get(), otherGeom.get() ) );
2739 nearestCoord.reset( GEOSNearestPoints_r( geosinit()->ctxt, mGeos.get(), otherGeom.get() ) );
2742 ( void )GEOSCoordSeq_getX_r( geosinit()->ctxt, nearestCoord.get(), 0, &nx );
2743 ( void )GEOSCoordSeq_getY_r( geosinit()->ctxt, nearestCoord.get(), 0, &ny );
2745 catch ( GEOSException &e )
2747 logError( QStringLiteral(
"GEOS" ), e.what() );
2750 *errorMsg = e.what();
2760 if ( !mGeos || other.
isEmpty() )
2770 if ( !other || other->
isEmpty() )
2787 if ( !nearestCoord )
2790 *errorMsg = QStringLiteral(
"GEOS returned no nearest points" );
2794 ( void )GEOSCoordSeq_getX_r( geosinit()->ctxt, nearestCoord.get(), 0, &nx1 );
2795 ( void )GEOSCoordSeq_getY_r( geosinit()->ctxt, nearestCoord.get(), 0, &ny1 );
2796 ( void )GEOSCoordSeq_getX_r( geosinit()->ctxt, nearestCoord.get(), 1, &nx2 );
2797 ( void )GEOSCoordSeq_getY_r( geosinit()->ctxt, nearestCoord.get(), 1, &ny2 );
2799 catch ( GEOSException &e )
2801 logError( QStringLiteral(
"GEOS" ), e.what() );
2804 *errorMsg = e.what();
2831 distance = GEOSProject_r( geosinit()->ctxt, mGeos.get(), otherGeom.get() );
2833 catch ( GEOSException &e )
2835 logError( QStringLiteral(
"GEOS" ), e.what() );
2838 *errorMsg = e.what();
2853 geos::unique_ptr point = createGeosPointXY( x, y,
false, 0,
false, 0, 2, 0 );
2860 distance = GEOSProject_r( geosinit()->ctxt, mGeos.get(), point.get() );
2862 catch ( GEOSException &e )
2864 logError( QStringLiteral(
"GEOS" ), e.what() );
2867 *errorMsg = e.what();
2884 lineGeosGeometries[validLines] = l.release();
2891 geos::unique_ptr result( GEOSPolygonize_r( geosinit()->ctxt, lineGeosGeometries, validLines ) );
2892 for (
int i = 0; i < validLines; ++i )
2894 GEOSGeom_destroy_r( geosinit()->ctxt, lineGeosGeometries[i] );
2896 delete[] lineGeosGeometries;
2899 catch ( GEOSException &e )
2903 *errorMsg = e.what();
2905 for (
int i = 0; i < validLines; ++i )
2907 GEOSGeom_destroy_r( geosinit()->ctxt, lineGeosGeometries[i] );
2909 delete[] lineGeosGeometries;
2924 extentGeosGeom =
asGeos( extent, mPrecision );
2925 if ( !extentGeosGeom )
2934 geos.reset( GEOSVoronoiDiagram_r( geosinit()->ctxt, mGeos.get(), extentGeosGeom.get(), tolerance, edgesOnly ) );
2936 if ( !
geos || GEOSisEmpty_r( geosinit()->ctxt,
geos.get() ) != 0 )
2956 geos.reset( GEOSDelaunayTriangulation_r( geosinit()->ctxt, mGeos.get(), tolerance, edgesOnly ) );
2958 if ( !
geos || GEOSisEmpty_r( geosinit()->ctxt,
geos.get() ) != 0 )
2970static bool _linestringEndpoints(
const GEOSGeometry *linestring,
double &x1,
double &y1,
double &x2,
double &y2 )
2972 const GEOSCoordSequence *coordSeq = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, linestring );
2976 unsigned int coordSeqSize;
2977 if ( GEOSCoordSeq_getSize_r( geosinit()->ctxt, coordSeq, &coordSeqSize ) == 0 )
2980 if ( coordSeqSize < 2 )
2983 GEOSCoordSeq_getX_r( geosinit()->ctxt, coordSeq, 0, &x1 );
2984 GEOSCoordSeq_getY_r( geosinit()->ctxt, coordSeq, 0, &y1 );
2985 GEOSCoordSeq_getX_r( geosinit()->ctxt, coordSeq, coordSeqSize - 1, &x2 );
2986 GEOSCoordSeq_getY_r( geosinit()->ctxt, coordSeq, coordSeqSize - 1, &y2 );
2994 double x1, y1, x2, y2;
2995 if ( !_linestringEndpoints( line1, x1, y1, x2, y2 ) )
2998 double rx1, ry1, rx2, ry2;
2999 if ( !_linestringEndpoints( line2, rx1, ry1, rx2, ry2 ) )
3002 bool intersectionAtOrigLineEndpoint =
3003 ( intersectionPoint.
x() == x1 && intersectionPoint.
y() == y1 ) !=
3004 ( intersectionPoint.
x() == x2 && intersectionPoint.
y() == y2 );
3005 bool intersectionAtReshapeLineEndpoint =
3006 ( intersectionPoint.
x() == rx1 && intersectionPoint.
y() == ry1 ) ||
3007 ( intersectionPoint.
x() == rx2 && intersectionPoint.
y() == ry2 );
3010 if ( intersectionAtOrigLineEndpoint && intersectionAtReshapeLineEndpoint )
3014 GEOSGeometry *geoms[2] = { g1.release(), g2.release() };
3015 geos::unique_ptr multiGeom( GEOSGeom_createCollection_r( geosinit()->ctxt, GEOS_MULTILINESTRING, geoms, 2 ) );
3016 geos::unique_ptr res( GEOSLineMerge_r( geosinit()->ctxt, multiGeom.get() ) );
3026 if ( !line || !reshapeLineGeos )
3029 bool atLeastTwoIntersections =
false;
3030 bool oneIntersection =
false;
3036 geos::unique_ptr intersectGeom( GEOSIntersection_r( geosinit()->ctxt, line, reshapeLineGeos ) );
3037 if ( intersectGeom )
3039 const int geomType = GEOSGeomTypeId_r( geosinit()->ctxt, intersectGeom.get() );
3040 atLeastTwoIntersections = ( geomType == GEOS_MULTIPOINT && GEOSGetNumGeometries_r( geosinit()->ctxt, intersectGeom.get() ) > 1 )
3041 || ( geomType == GEOS_GEOMETRYCOLLECTION && GEOSGetNumGeometries_r( geosinit()->ctxt, intersectGeom.get() ) > 0 )
3042 || ( geomType == GEOS_MULTILINESTRING && GEOSGetNumGeometries_r( geosinit()->ctxt, intersectGeom.get() ) > 0 );
3044 if ( GEOSGeomTypeId_r( geosinit()->ctxt, intersectGeom.get() ) == GEOS_POINT )
3046 const GEOSCoordSequence *intersectionCoordSeq = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, intersectGeom.get() );
3048 GEOSCoordSeq_getX_r( geosinit()->ctxt, intersectionCoordSeq, 0, &xi );
3049 GEOSCoordSeq_getY_r( geosinit()->ctxt, intersectionCoordSeq, 0, &yi );
3050 oneIntersection =
true;
3055 catch ( GEOSException & )
3057 atLeastTwoIntersections =
false;
3061 if ( oneIntersection )
3062 return _mergeLinestrings( line, reshapeLineGeos, oneIntersectionPoint );
3064 if ( !atLeastTwoIntersections )
3068 double x1, y1, x2, y2;
3069 if ( !_linestringEndpoints( line, x1, y1, x2, y2 ) )
3075 bool isRing =
false;
3076 if ( GEOSGeomTypeId_r( geosinit()->ctxt, line ) == GEOS_LINEARRING
3077 || GEOSEquals_r( geosinit()->ctxt, beginLineVertex.get(), endLineVertex.get() ) == 1 )
3082 if ( !nodedGeometry )
3088 geos::unique_ptr mergedLines( GEOSLineMerge_r( geosinit()->ctxt, nodedGeometry.get() ) );
3094 int numMergedLines = GEOSGetNumGeometries_r( geosinit()->ctxt, mergedLines.get() );
3095 if ( numMergedLines < 2 )
3097 if ( numMergedLines == 1 )
3099 geos::unique_ptr result( GEOSGeom_clone_r( geosinit()->ctxt, reshapeLineGeos ) );
3106 QVector<GEOSGeometry *> resultLineParts;
3107 QVector<GEOSGeometry *> probableParts;
3109 for (
int i = 0; i < numMergedLines; ++i )
3111 const GEOSGeometry *currentGeom = GEOSGetGeometryN_r( geosinit()->ctxt, mergedLines.get(), i );
3114 bool alreadyAdded =
false;
3116 double bufferDistance = std::pow( 10.0L, geomDigits( currentGeom ) - 11 );
3117 for (
const GEOSGeometry *other : std::as_const( resultLineParts ) )
3119 GEOSHausdorffDistance_r( geosinit()->ctxt, currentGeom, other, &
distance );
3122 alreadyAdded =
true;
3129 const GEOSCoordSequence *currentCoordSeq = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, currentGeom );
3130 unsigned int currentCoordSeqSize;
3131 GEOSCoordSeq_getSize_r( geosinit()->ctxt, currentCoordSeq, ¤tCoordSeqSize );
3132 if ( currentCoordSeqSize < 2 )
3136 double xBegin, xEnd, yBegin, yEnd;
3137 GEOSCoordSeq_getX_r( geosinit()->ctxt, currentCoordSeq, 0, &xBegin );
3138 GEOSCoordSeq_getY_r( geosinit()->ctxt, currentCoordSeq, 0, &yBegin );
3139 GEOSCoordSeq_getX_r( geosinit()->ctxt, currentCoordSeq, currentCoordSeqSize - 1, &xEnd );
3140 GEOSCoordSeq_getY_r( geosinit()->ctxt, currentCoordSeq, currentCoordSeqSize - 1, &yEnd );
3145 int nEndpointsOnOriginalLine = 0;
3146 if ( pointContainedInLine( beginCurrentGeomVertex.get(), line ) == 1 )
3147 nEndpointsOnOriginalLine += 1;
3149 if ( pointContainedInLine( endCurrentGeomVertex.get(), line ) == 1 )
3150 nEndpointsOnOriginalLine += 1;
3153 int nEndpointsSameAsOriginalLine = 0;
3154 if ( GEOSEquals_r( geosinit()->ctxt, beginCurrentGeomVertex.get(), beginLineVertex.get() ) == 1
3155 || GEOSEquals_r( geosinit()->ctxt, beginCurrentGeomVertex.get(), endLineVertex.get() ) == 1 )
3156 nEndpointsSameAsOriginalLine += 1;
3158 if ( GEOSEquals_r( geosinit()->ctxt, endCurrentGeomVertex.get(), beginLineVertex.get() ) == 1
3159 || GEOSEquals_r( geosinit()->ctxt, endCurrentGeomVertex.get(), endLineVertex.get() ) == 1 )
3160 nEndpointsSameAsOriginalLine += 1;
3163 bool currentGeomOverlapsOriginalGeom =
false;
3164 bool currentGeomOverlapsReshapeLine =
false;
3165 if ( lineContainedInLine( currentGeom, line ) == 1 )
3166 currentGeomOverlapsOriginalGeom =
true;
3168 if ( lineContainedInLine( currentGeom, reshapeLineGeos ) == 1 )
3169 currentGeomOverlapsReshapeLine =
true;
3172 if ( !isRing && nEndpointsSameAsOriginalLine == 1 && nEndpointsOnOriginalLine == 2 && currentGeomOverlapsOriginalGeom )
3174 resultLineParts.push_back( GEOSGeom_clone_r( geosinit()->ctxt, currentGeom ) );
3177 else if ( isRing && nEndpointsOnOriginalLine == 2 && currentGeomOverlapsOriginalGeom )
3179 probableParts.push_back( GEOSGeom_clone_r( geosinit()->ctxt, currentGeom ) );
3181 else if ( nEndpointsOnOriginalLine == 2 && !currentGeomOverlapsOriginalGeom )
3183 resultLineParts.push_back( GEOSGeom_clone_r( geosinit()->ctxt, currentGeom ) );
3185 else if ( nEndpointsSameAsOriginalLine == 2 && !currentGeomOverlapsOriginalGeom )
3187 resultLineParts.push_back( GEOSGeom_clone_r( geosinit()->ctxt, currentGeom ) );
3189 else if ( currentGeomOverlapsOriginalGeom && currentGeomOverlapsReshapeLine )
3191 resultLineParts.push_back( GEOSGeom_clone_r( geosinit()->ctxt, currentGeom ) );
3196 if ( isRing && !probableParts.isEmpty() )
3200 double maxLength = -std::numeric_limits<double>::max();
3201 double currentLength = 0;
3202 for (
int i = 0; i < probableParts.size(); ++i )
3204 currentGeom = probableParts.at( i );
3205 GEOSLength_r( geosinit()->ctxt, currentGeom, ¤tLength );
3206 if ( currentLength > maxLength )
3208 maxLength = currentLength;
3209 maxGeom.reset( currentGeom );
3213 GEOSGeom_destroy_r( geosinit()->ctxt, currentGeom );
3216 resultLineParts.push_back( maxGeom.release() );
3220 if ( resultLineParts.empty() )
3223 if ( resultLineParts.size() == 1 )
3225 result.reset( resultLineParts[0] );
3230 for (
int i = 0; i < resultLineParts.size(); ++i )
3232 lineArray[i] = resultLineParts[i];
3236 geos::unique_ptr multiLineGeom( GEOSGeom_createCollection_r( geosinit()->ctxt, GEOS_MULTILINESTRING, lineArray, resultLineParts.size() ) );
3237 delete [] lineArray;
3240 result.reset( GEOSLineMerge_r( geosinit()->ctxt, multiLineGeom.get() ) );
3244 if ( GEOSGeomTypeId_r( geosinit()->ctxt, result.get() ) != GEOS_LINESTRING )
3255 int nIntersections = 0;
3256 int lastIntersectingRing = -2;
3259 int nRings = GEOSGetNumInteriorRings_r( geosinit()->ctxt, polygon );
3264 const GEOSGeometry *outerRing = GEOSGetExteriorRing_r( geosinit()->ctxt, polygon );
3265 if ( GEOSIntersects_r( geosinit()->ctxt, outerRing, reshapeLineGeos ) == 1 )
3268 lastIntersectingRing = -1;
3269 lastIntersectingGeom = outerRing;
3277 for (
int i = 0; i < nRings; ++i )
3279 innerRings[i] = GEOSGetInteriorRingN_r( geosinit()->ctxt, polygon, i );
3280 if ( GEOSIntersects_r( geosinit()->ctxt, innerRings[i], reshapeLineGeos ) == 1 )
3283 lastIntersectingRing = i;
3284 lastIntersectingGeom = innerRings[i];
3288 catch ( GEOSException & )
3293 if ( nIntersections != 1 )
3295 delete [] innerRings;
3301 if ( !reshapeResult )
3303 delete [] innerRings;
3309 const GEOSCoordSequence *reshapeSequence = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, reshapeResult.get() );
3310 GEOSCoordSequence *newCoordSequence = GEOSCoordSeq_clone_r( geosinit()->ctxt, reshapeSequence );
3312 reshapeResult.reset();
3314 newRing = GEOSGeom_createLinearRing_r( geosinit()->ctxt, newCoordSequence );
3317 delete [] innerRings;
3322 if ( lastIntersectingRing == -1 )
3323 newOuterRing = newRing;
3325 newOuterRing = GEOSGeom_clone_r( geosinit()->ctxt, outerRing );
3328 QVector<GEOSGeometry *> ringList;
3331 GEOSGeometry *outerRingPoly = GEOSGeom_createPolygon_r( geosinit()->ctxt, GEOSGeom_clone_r( geosinit()->ctxt, newOuterRing ),
nullptr, 0 );
3332 if ( outerRingPoly )
3334 ringList.reserve( nRings );
3336 for (
int i = 0; i < nRings; ++i )
3338 if ( lastIntersectingRing == i )
3339 currentRing = newRing;
3341 currentRing = GEOSGeom_clone_r( geosinit()->ctxt, innerRings[i] );
3344 if ( GEOSContains_r( geosinit()->ctxt, outerRingPoly, currentRing ) == 1 )
3345 ringList.push_back( currentRing );
3347 GEOSGeom_destroy_r( geosinit()->ctxt, currentRing );
3350 GEOSGeom_destroy_r( geosinit()->ctxt, outerRingPoly );
3354 for (
int i = 0; i < ringList.size(); ++i )
3355 newInnerRings[i] = ringList.at( i );
3357 delete [] innerRings;
3359 geos::unique_ptr reshapedPolygon( GEOSGeom_createPolygon_r( geosinit()->ctxt, newOuterRing, newInnerRings, ringList.size() ) );
3360 delete[] newInnerRings;
3362 return reshapedPolygon;
3367 if ( !line1 || !line2 )
3372 double bufferDistance = std::pow( 10.0L, geomDigits( line2 ) - 11 );
3378 geos::unique_ptr intersectionGeom( GEOSIntersection_r( geosinit()->ctxt, bufferGeom.get(), line1 ) );
3381 double intersectGeomLength;
3384 GEOSLength_r( geosinit()->ctxt, intersectionGeom.get(), &intersectGeomLength );
3385 GEOSLength_r( geosinit()->ctxt, line1, &line1Length );
3387 double intersectRatio = line1Length / intersectGeomLength;
3388 if ( intersectRatio > 0.9 && intersectRatio < 1.1 )
3396 if ( !point || !line )
3399 double bufferDistance = std::pow( 10.0L, geomDigits( line ) - 11 );
3401 geos::unique_ptr lineBuffer( GEOSBuffer_r( geosinit()->ctxt, line, bufferDistance, 8 ) );
3405 bool contained =
false;
3406 if ( GEOSContains_r( geosinit()->ctxt, lineBuffer.get(), point ) == 1 )
3418 const GEOSGeometry *bBoxRing = GEOSGetExteriorRing_r( geosinit()->ctxt, bbox.get() );
3422 const GEOSCoordSequence *bBoxCoordSeq = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, bBoxRing );
3424 if ( !bBoxCoordSeq )
3427 unsigned int nCoords = 0;
3428 if ( !GEOSCoordSeq_getSize_r( geosinit()->ctxt, bBoxCoordSeq, &nCoords ) )
3432 for (
unsigned int i = 0; i < nCoords - 1; ++i )
3435 GEOSCoordSeq_getX_r( geosinit()->ctxt, bBoxCoordSeq, i, &t );
3438 digits = std::ceil( std::log10( std::fabs( t ) ) );
3439 if ( digits > maxDigits )
3442 GEOSCoordSeq_getY_r( geosinit()->ctxt, bBoxCoordSeq, i, &t );
3443 digits = std::ceil( std::log10( std::fabs( t ) ) );
3444 if ( digits > maxDigits )
3453 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)
#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