31#define DEFAULT_QUADRANT_SEGMENTS 8
33#define CATCH_GEOS(r) \
34 catch (GEOSException &) \
39#define CATCH_GEOS_WITH_ERRMSG(r) \
40 catch (GEOSException &e) \
44 *errorMsg = e.what(); \
51static void throwGEOSException(
const char *fmt, ... )
57 vsnprintf( buffer,
sizeof buffer, fmt, ap );
60 QString message = QString::fromUtf8( buffer );
70 throw GEOSException( message );
78 throw GEOSException( message );
83static void printGEOSNotice(
const char *fmt, ... )
90 vsnprintf( buffer,
sizeof buffer, fmt, ap );
100 GEOSContextHandle_t ctxt;
104 ctxt = initGEOS_r( printGEOSNotice, throwGEOSException );
109 finishGEOS_r( ctxt );
112 GEOSInit(
const GEOSInit &rh ) =
delete;
113 GEOSInit &operator=(
const GEOSInit &rh ) =
delete;
120 GEOSGeom_destroy_r( geosinit()->ctxt, geom );
125 GEOSPreparedGeom_destroy_r( geosinit()->ctxt, geom );
130 GEOSBufferParams_destroy_r( geosinit()->ctxt, params );
135 GEOSCoordSeq_destroy_r( geosinit()->ctxt, sequence );
170#if GEOS_VERSION_MAJOR==3 && GEOS_VERSION_MINOR<10
172 throw QgsNotSupportedException( QObject::tr(
"The structured method to make geometries valid requires a QGIS build based on GEOS 3.10 or later" ) );
175 throw QgsNotSupportedException( QObject::tr(
"The keep collapsed option for making geometries valid requires a QGIS build based on GEOS 3.10 or later" ) );
179 geos.reset( GEOSMakeValid_r( geosinit()->ctxt, mGeos.get() ) );
184 GEOSMakeValidParams *params = GEOSMakeValidParams_create_r( geosinit()->ctxt );
188 GEOSMakeValidParams_setMethod_r( geosinit()->ctxt, params, GEOS_MAKE_VALID_LINEWORK );
192 GEOSMakeValidParams_setMethod_r( geosinit()->ctxt, params, GEOS_MAKE_VALID_STRUCTURE );
196 GEOSMakeValidParams_setKeepCollapsed_r( geosinit()->ctxt,
198 keepCollapsed ? 1 : 0 );
203 geos.reset( GEOSMakeValidWithParams_r( geosinit()->ctxt, mGeos.get(), params ) );
204 GEOSMakeValidParams_destroy_r( geosinit()->ctxt, params );
206 catch ( GEOSException &e )
210 *errorMsg = e.what();
212 GEOSMakeValidParams_destroy_r( geosinit()->ctxt, params );
241 std::unique_ptr< QgsAbstractGeometry > geom =
fromGeos( newPart );
248 mGeosPrepared.reset();
261 mGeosPrepared.reset( GEOSPrepare_r( geosinit()->ctxt, mGeos.get() ) );
265void QgsGeos::cacheGeos()
const
282 return overlay( geom, OverlayIntersection, errorMsg, parameters ).release();
287 return overlay( geom, OverlayDifference, errorMsg, parameters ).release();
302 catch ( GEOSException &e )
304 logError( QStringLiteral(
"GEOS" ), e.what() );
307 *errorMsg = e.what();
316void QgsGeos::subdivideRecursive(
const GEOSGeometry *currentPart,
int maxNodes,
int depth,
QgsGeometryCollection *parts,
const QgsRectangle &clipRect,
double gridSize )
const
318 int partType = GEOSGeomTypeId_r( geosinit()->ctxt, currentPart );
321 if ( partType == GEOS_POINT )
332 if ( partType == GEOS_MULTILINESTRING || partType == GEOS_MULTIPOLYGON || partType == GEOS_GEOMETRYCOLLECTION )
334 int partCount = GEOSGetNumGeometries_r( geosinit()->ctxt, currentPart );
335 for (
int i = 0; i < partCount; ++i )
337 subdivideRecursive( GEOSGetGeometryN_r( geosinit()->ctxt, currentPart, i ), maxNodes, depth, parts, clipRect, gridSize );
348 int vertexCount = GEOSGetNumCoordinates_r( geosinit()->ctxt, currentPart );
349 if ( vertexCount == 0 )
353 else if ( vertexCount < maxNodes )
360 double width = clipRect.
width();
361 double height = clipRect.
height();
364 if ( width > height )
377 halfClipRect1.
setYMinimum( halfClipRect1.
yMinimum() - std::numeric_limits<double>::epsilon() );
378 halfClipRect2.
setYMinimum( halfClipRect2.
yMinimum() - std::numeric_limits<double>::epsilon() );
379 halfClipRect1.
setYMaximum( halfClipRect1.
yMaximum() + std::numeric_limits<double>::epsilon() );
380 halfClipRect2.
setYMaximum( halfClipRect2.
yMaximum() + std::numeric_limits<double>::epsilon() );
384 halfClipRect1.
setXMinimum( halfClipRect1.
xMinimum() - std::numeric_limits<double>::epsilon() );
385 halfClipRect2.
setXMinimum( halfClipRect2.
xMinimum() - std::numeric_limits<double>::epsilon() );
386 halfClipRect1.
setXMaximum( halfClipRect1.
xMaximum() + std::numeric_limits<double>::epsilon() );
387 halfClipRect2.
setXMaximum( halfClipRect2.
xMaximum() + std::numeric_limits<double>::epsilon() );
399 clipPart1.reset( GEOSIntersectionPrec_r( geosinit()->ctxt, mGeos.get(), clipPart1.get(), gridSize ) );
401 subdivideRecursive( clipPart1.get(), maxNodes, depth, parts, halfClipRect1, gridSize );
407 clipPart2.reset( GEOSIntersectionPrec_r( geosinit()->ctxt, mGeos.get(), clipPart2.get(), gridSize ) );
409 subdivideRecursive( clipPart2.get(), maxNodes, depth, parts, halfClipRect2, gridSize );
421 maxNodes = std::max( maxNodes, 8 );
430 return std::move( parts );
435 return overlay( geom, OverlayUnion, errorMsg, parameters ).release();
440 QVector< GEOSGeometry * > geosGeometries;
441 geosGeometries.reserve( geomList.size() );
447 geosGeometries <<
asGeos( g, mPrecision ).release();
453 geos::unique_ptr geomCollection = createGeosCollection( GEOS_GEOMETRYCOLLECTION, geosGeometries );
456 geomUnion.reset( GEOSUnaryUnionPrec_r( geosinit()->ctxt, geomCollection.get(), parameters.
gridSize() ) );
460 geomUnion.reset( GEOSUnaryUnion_r( geosinit()->ctxt, geomCollection.get() ) );
465 std::unique_ptr< QgsAbstractGeometry > result =
fromGeos( geomUnion.get() );
466 return result.release();
471 QVector< GEOSGeometry * > geosGeometries;
472 geosGeometries.reserve( geomList.size() );
478 geosGeometries <<
asGeos( g.constGet(), mPrecision ).release();
484 geos::unique_ptr geomCollection = createGeosCollection( GEOS_GEOMETRYCOLLECTION, geosGeometries );
488 geomUnion.reset( GEOSUnaryUnionPrec_r( geosinit()->ctxt, geomCollection.get(), parameters.
gridSize() ) );
492 geomUnion.reset( GEOSUnaryUnion_r( geosinit()->ctxt, geomCollection.get() ) );
498 std::unique_ptr< QgsAbstractGeometry > result =
fromGeos( geomUnion.get() );
499 return result.release();
504 return overlay( geom, OverlaySymDifference, errorMsg, parameters ).release();
516 if ( !otherGeosGeom )
525 GEOSPreparedDistance_r( geosinit()->ctxt, mGeosPrepared.get(), otherGeosGeom.get(), &
distance );
529 GEOSDistance_r( geosinit()->ctxt, mGeos.get(), otherGeosGeom.get(), &
distance );
545 geos::unique_ptr point = createGeosPointXY( x, y,
false, 0,
false, 0, 2, 0 );
553 GEOSPreparedDistance_r( geosinit()->ctxt, mGeosPrepared.get(), point.get(), &
distance );
557 GEOSDistance_r( geosinit()->ctxt, mGeos.get(), point.get(), &
distance );
573 if ( !otherGeosGeom )
588#if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=10 )
589 return GEOSPreparedDistanceWithin_r( geosinit()->ctxt, mGeosPrepared.get(), otherGeosGeom.get(), maxdist );
591 GEOSPreparedDistance_r( geosinit()->ctxt, mGeosPrepared.get(), otherGeosGeom.get(), &
distance );
596#if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=10 )
597 return GEOSDistanceWithin_r( geosinit()->ctxt, mGeos.get(), otherGeosGeom.get(), maxdist );
599 GEOSDistance_r( geosinit()->ctxt, mGeos.get(), otherGeosGeom.get(), &
distance );
610 geos::unique_ptr point = createGeosPointXY( x, y,
false, 0,
false, 0, 2, 0 );
619 return GEOSPreparedContains_r( geosinit()->ctxt, mGeosPrepared.get(), point.get() ) == 1;
622 result = ( GEOSContains_r( geosinit()->ctxt, mGeos.get(), point.get() ) == 1 );
624 catch ( GEOSException &e )
626 logError( QStringLiteral(
"GEOS" ), e.what() );
629 *errorMsg = e.what();
646 if ( !otherGeosGeom )
653 GEOSHausdorffDistance_r( geosinit()->ctxt, mGeos.get(), otherGeosGeom.get(), &
distance );
669 if ( !otherGeosGeom )
676 GEOSHausdorffDistanceDensify_r( geosinit()->ctxt, mGeos.get(), otherGeosGeom.get(), densifyFraction, &
distance );
692 if ( !otherGeosGeom )
699 GEOSFrechetDistance_r( geosinit()->ctxt, mGeos.get(), otherGeosGeom.get(), &
distance );
715 if ( !otherGeosGeom )
722 GEOSFrechetDistanceDensify_r( geosinit()->ctxt, mGeos.get(), otherGeosGeom.get(), densifyFraction, &
distance );
731 return relation( geom, RelationIntersects, errorMsg );
736 return relation( geom, RelationTouches, errorMsg );
741 return relation( geom, RelationCrosses, errorMsg );
746 return relation( geom, RelationWithin, errorMsg );
751 return relation( geom, RelationOverlaps, errorMsg );
756 return relation( geom, RelationContains, errorMsg );
761 return relation( geom, RelationDisjoint, errorMsg );
780 char *r = GEOSRelate_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() );
783 result = QString( r );
784 GEOSFree_r( geosinit()->ctxt, r );
787 catch ( GEOSException &e )
789 logError( QStringLiteral(
"GEOS" ), e.what() );
792 *errorMsg = e.what();
801 if ( !mGeos || !geom )
815 result = ( GEOSRelatePattern_r( geosinit()->ctxt, mGeos.get(), geosGeom.get(), pattern.toLocal8Bit().constData() ) == 1 );
817 catch ( GEOSException &e )
819 logError( QStringLiteral(
"GEOS" ), e.what() );
822 *errorMsg = e.what();
839 if ( GEOSArea_r( geosinit()->ctxt, mGeos.get(), &
area ) != 1 )
855 if ( GEOSLength_r( geosinit()->ctxt, mGeos.get(), &
length ) != 1 )
863 QVector<QgsGeometry> &newGeometries,
866 QString *errorMsg,
bool skipIntersectionCheck )
const
881 if ( !GEOSisValid_r( geosinit()->ctxt, mGeos.get() ) )
889 newGeometries.clear();
896 splitLineGeos = createGeosLinestring( &splitLine, mPrecision );
900 splitLineGeos = createGeosPointXY( splitLine.
xAt( 0 ), splitLine.
yAt( 0 ),
false, 0,
false, 0, 2, mPrecision );
907 if ( !GEOSisValid_r( geosinit()->ctxt, splitLineGeos.get() ) || !GEOSisSimple_r( geosinit()->ctxt, splitLineGeos.get() ) )
915 if ( !topologicalTestPointsSplit( splitLineGeos.get(), topologyTestPoints ) )
924 returnCode = splitLinearGeometry( splitLineGeos.get(), newGeometries, skipIntersectionCheck );
928 returnCode = splitPolygonGeometry( splitLineGeos.get(), newGeometries, skipIntersectionCheck );
942bool QgsGeos::topologicalTestPointsSplit(
const GEOSGeometry *splitLine,
QgsPointSequence &testPoints, QString *errorMsg )
const
956 geos::unique_ptr intersectionGeom( GEOSIntersection_r( geosinit()->ctxt, mGeos.get(), splitLine ) );
957 if ( !intersectionGeom )
961 int nIntersectGeoms = 1;
962 if ( GEOSGeomTypeId_r( geosinit()->ctxt, intersectionGeom.get() ) == GEOS_LINESTRING
963 || GEOSGeomTypeId_r( geosinit()->ctxt, intersectionGeom.get() ) == GEOS_POINT )
967 nIntersectGeoms = GEOSGetNumGeometries_r( geosinit()->ctxt, intersectionGeom.get() );
969 for (
int i = 0; i < nIntersectGeoms; ++i )
971 const GEOSGeometry *currentIntersectGeom =
nullptr;
973 currentIntersectGeom = intersectionGeom.get();
975 currentIntersectGeom = GEOSGetGeometryN_r( geosinit()->ctxt, intersectionGeom.get(), i );
977 const GEOSCoordSequence *lineSequence = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, currentIntersectGeom );
978 unsigned int sequenceSize = 0;
980 if ( GEOSCoordSeq_getSize_r( geosinit()->ctxt, lineSequence, &sequenceSize ) != 0 )
982 for (
unsigned int i = 0; i < sequenceSize; ++i )
984 if ( GEOSCoordSeq_getXYZ_r( geosinit()->ctxt, lineSequence, i, &x, &y, &z ) )
986 testPoints.push_back(
QgsPoint( x, y, z ) );
997geos::unique_ptr
QgsGeos::linePointDifference( GEOSGeometry *GEOSsplitPoint )
const
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 (
QgsPoint *point = qgsgeometry_cast<QgsPoint *>( splitGeom.get() ) )
1037 splitPoints->addGeometry( qgsgeometry_cast<QgsPoint *>( splitGeom.release() ) );
1045 for (
int i = 0; i < multiCurve->numGeometries(); ++i )
1047 const QgsLineString *line = qgsgeometry_cast<const QgsLineString *>( multiCurve->geometryN( i ) );
1050 const QgsCurve *curve = qgsgeometry_cast<const QgsCurve *>( multiCurve->geometryN( i ) );
1058 QMap< int, QVector< QPair< double, QgsPoint > > >pointMap;
1059 for (
int p = 0; p < splitPoints->numGeometries(); ++p )
1061 const QgsPoint *intersectionPoint = splitPoints->pointN( p );
1066 line->
closestSegment( *intersectionPoint, segmentPoint2D, nextVertex );
1074 const QPair< double, QgsPoint > pair = qMakePair(
distance, *correctSegmentPoint.get() );
1075 if ( pointMap.contains( nextVertex.
vertex - 1 ) )
1076 pointMap[ nextVertex.
vertex - 1 ].append( pair );
1078 pointMap[ nextVertex.
vertex - 1 ] = QVector< QPair< double, QgsPoint > >() << pair;
1083 for (
auto &p : pointMap )
1085 std::sort( p.begin(), p.end(), [](
const QPair< double, QgsPoint > &a,
const QPair< double, QgsPoint > &b ) { return a.first < b.first; } );
1092 for (
int j = 0; j < nVertices; ++j )
1096 if ( pointMap.contains( j ) )
1099 for (
int k = 0; k < pointMap[ j ].size(); ++k )
1101 splitPoint = pointMap[ j ][k].second;
1102 if ( splitPoint == currentPoint )
1108 else if ( splitPoint == line->
pointN( j + 1 ) )
1127 return asGeos( &lines, mPrecision );
1132 Q_UNUSED( skipIntersectionCheck )
1139 geos::unique_ptr intersectGeom( GEOSIntersection_r( geosinit()->ctxt, splitLine, mGeos.get() ) );
1140 if ( !intersectGeom || GEOSisEmpty_r( geosinit()->ctxt, intersectGeom.get() ) )
1144 int linearIntersect = GEOSRelatePattern_r( geosinit()->ctxt, mGeos.get(), splitLine,
"1********" );
1145 if ( linearIntersect > 0 )
1149 splitGeom = linePointDifference( intersectGeom.get() );
1154 QVector<GEOSGeometry *> lineGeoms;
1156 int splitType = GEOSGeomTypeId_r( geosinit()->ctxt, splitGeom.get() );
1157 if ( splitType == GEOS_MULTILINESTRING )
1159 int nGeoms = GEOSGetNumGeometries_r( geosinit()->ctxt, splitGeom.get() );
1160 lineGeoms.reserve( nGeoms );
1161 for (
int i = 0; i < nGeoms; ++i )
1162 lineGeoms << GEOSGeom_clone_r( geosinit()->ctxt, GEOSGetGeometryN_r( geosinit()->ctxt, splitGeom.get(), i ) );
1167 lineGeoms << GEOSGeom_clone_r( geosinit()->ctxt, splitGeom.get() );
1170 mergeGeometriesMultiTypeSplit( lineGeoms );
1172 for (
int i = 0; i < lineGeoms.size(); ++i )
1175 GEOSGeom_destroy_r( geosinit()->ctxt, lineGeoms[i] );
1191 if ( !mGeosPrepared )
1195 if ( !skipIntersectionCheck && !GEOSPreparedIntersects_r( geosinit()->ctxt, mGeosPrepared.get(), splitLine ) )
1200 if ( !nodedGeometry )
1203 const GEOSGeometry *noded = nodedGeometry.get();
1204 geos::unique_ptr polygons( GEOSPolygonize_r( geosinit()->ctxt, &noded, 1 ) );
1205 if ( !polygons || numberOfGeometries( polygons.get() ) == 0 )
1212 QVector<GEOSGeometry *> testedGeometries;
1217 for (
int i = 0; i < numberOfGeometries( polygons.get() ); i++ )
1219 const GEOSGeometry *polygon = GEOSGetGeometryN_r( geosinit()->ctxt, polygons.get(), i );
1223 testedGeometries << GEOSGeom_clone_r( geosinit()->ctxt, polygon );
1226 int nGeometriesThis = numberOfGeometries( mGeos.get() );
1227 if ( testedGeometries.empty() || testedGeometries.size() == nGeometriesThis )
1230 for (
int i = 0; i < testedGeometries.size(); ++i )
1232 GEOSGeom_destroy_r( geosinit()->ctxt, testedGeometries[i] );
1241 mergeGeometriesMultiTypeSplit( testedGeometries );
1244 for ( i = 0; i < testedGeometries.size() && GEOSisValid_r( geosinit()->ctxt, testedGeometries[i] ); ++i )
1247 if ( i < testedGeometries.size() )
1249 for ( i = 0; i < testedGeometries.size(); ++i )
1250 GEOSGeom_destroy_r( geosinit()->ctxt, testedGeometries[i] );
1255 for ( i = 0; i < testedGeometries.size(); ++i )
1258 GEOSGeom_destroy_r( geosinit()->ctxt, testedGeometries[i] );
1264geos::unique_ptr QgsGeos::nodeGeometries(
const GEOSGeometry *splitLine,
const GEOSGeometry *geom )
1266 if ( !splitLine || !geom )
1270 if ( GEOSGeomTypeId_r( geosinit()->ctxt, geom ) == GEOS_POLYGON || GEOSGeomTypeId_r( geosinit()->ctxt, geom ) == GEOS_MULTIPOLYGON )
1271 geometryBoundary.reset( GEOSBoundary_r( geosinit()->ctxt, geom ) );
1273 geometryBoundary.reset( GEOSGeom_clone_r( geosinit()->ctxt, geom ) );
1275 geos::unique_ptr splitLineClone( GEOSGeom_clone_r( geosinit()->ctxt, splitLine ) );
1276 geos::unique_ptr unionGeometry( GEOSUnion_r( geosinit()->ctxt, splitLineClone.get(), geometryBoundary.get() ) );
1278 return unionGeometry;
1281int QgsGeos::mergeGeometriesMultiTypeSplit( QVector<GEOSGeometry *> &splitResult )
const
1287 int type = GEOSGeomTypeId_r( geosinit()->ctxt, mGeos.get() );
1288 if ( type != GEOS_GEOMETRYCOLLECTION &&
1289 type != GEOS_MULTILINESTRING &&
1290 type != GEOS_MULTIPOLYGON &&
1291 type != GEOS_MULTIPOINT )
1294 QVector<GEOSGeometry *> copyList = splitResult;
1295 splitResult.clear();
1298 QVector<GEOSGeometry *> unionGeom;
1300 for (
int i = 0; i < copyList.size(); ++i )
1303 bool isPart =
false;
1304 for (
int j = 0; j < GEOSGetNumGeometries_r( geosinit()->ctxt, mGeos.get() ); j++ )
1306 if ( GEOSEquals_r( geosinit()->ctxt, copyList[i], GEOSGetGeometryN_r( geosinit()->ctxt, mGeos.get(), j ) ) )
1315 unionGeom << copyList[i];
1319 QVector<GEOSGeometry *> geomVector;
1320 geomVector << copyList[i];
1322 if ( type == GEOS_MULTILINESTRING )
1323 splitResult << createGeosCollection( GEOS_MULTILINESTRING, geomVector ).release();
1324 else if ( type == GEOS_MULTIPOLYGON )
1325 splitResult << createGeosCollection( GEOS_MULTIPOLYGON, geomVector ).release();
1327 GEOSGeom_destroy_r( geosinit()->ctxt, copyList[i] );
1332 if ( !unionGeom.isEmpty() )
1334 if ( type == GEOS_MULTILINESTRING )
1335 splitResult << createGeosCollection( GEOS_MULTILINESTRING, unionGeom ).release();
1336 else if ( type == GEOS_MULTIPOLYGON )
1337 splitResult << createGeosCollection( GEOS_MULTIPOLYGON, unionGeom ).release();
1347geos::unique_ptr QgsGeos::createGeosCollection(
int typeId,
const QVector<GEOSGeometry *> &geoms )
1349 int nNullGeoms = geoms.count(
nullptr );
1350 int nNotNullGeoms = geoms.size() - nNullGeoms;
1352 GEOSGeometry **geomarr =
new GEOSGeometry*[ nNotNullGeoms ];
1359 QVector<GEOSGeometry *>::const_iterator geomIt = geoms.constBegin();
1360 for ( ; geomIt != geoms.constEnd(); ++geomIt )
1364 if ( GEOSisEmpty_r( geosinit()->ctxt, *geomIt ) )
1369 GEOSGeom_destroy_r( geosinit()->ctxt, *geomIt );
1373 geomarr[i] = *geomIt;
1382 geom.reset( GEOSGeom_createCollection_r( geosinit()->ctxt, typeId, geomarr, nNotNullGeoms ) );
1384 catch ( GEOSException & )
1400 int nCoordDims = GEOSGeom_getCoordinateDimension_r( geosinit()->ctxt,
geos );
1401 int nDims = GEOSGeom_getDimensions_r( geosinit()->ctxt,
geos );
1402 bool hasZ = ( nCoordDims == 3 );
1403 bool hasM = ( ( nDims - nCoordDims ) == 1 );
1405 switch ( GEOSGeomTypeId_r( geosinit()->ctxt,
geos ) )
1409 if ( GEOSisEmpty_r( geosinit()->ctxt,
geos ) )
1412 const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq_r( geosinit()->ctxt,
geos );
1413 unsigned int nPoints = 0;
1414 GEOSCoordSeq_getSize_r( geosinit()->ctxt, cs, &nPoints );
1415 return nPoints > 0 ? std::unique_ptr<QgsAbstractGeometry>(
coordSeqPoint( cs, 0, hasZ, hasM ).clone() ) :
nullptr;
1417 case GEOS_LINESTRING:
1419 return sequenceToLinestring(
geos, hasZ, hasM );
1425 case GEOS_MULTIPOINT:
1427 std::unique_ptr< QgsMultiPoint > multiPoint(
new QgsMultiPoint() );
1428 int nParts = GEOSGetNumGeometries_r( geosinit()->ctxt,
geos );
1429 multiPoint->reserve( nParts );
1430 for (
int i = 0; i < nParts; ++i )
1432 const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, GEOSGetGeometryN_r( geosinit()->ctxt,
geos, i ) );
1435 unsigned int nPoints = 0;
1436 GEOSCoordSeq_getSize_r( geosinit()->ctxt, cs, &nPoints );
1438 multiPoint->addGeometry(
coordSeqPoint( cs, 0, hasZ, hasM ).clone() );
1441 return std::move( multiPoint );
1443 case GEOS_MULTILINESTRING:
1446 int nParts = GEOSGetNumGeometries_r( geosinit()->ctxt,
geos );
1447 multiLineString->reserve( nParts );
1448 for (
int i = 0; i < nParts; ++i )
1450 std::unique_ptr< QgsLineString >line( sequenceToLinestring( GEOSGetGeometryN_r( geosinit()->ctxt,
geos, i ), hasZ, hasM ) );
1453 multiLineString->addGeometry( line.release() );
1456 return std::move( multiLineString );
1458 case GEOS_MULTIPOLYGON:
1460 std::unique_ptr< QgsMultiPolygon > multiPolygon(
new QgsMultiPolygon() );
1462 int nParts = GEOSGetNumGeometries_r( geosinit()->ctxt,
geos );
1463 multiPolygon->reserve( nParts );
1464 for (
int i = 0; i < nParts; ++i )
1466 std::unique_ptr< QgsPolygon > poly =
fromGeosPolygon( GEOSGetGeometryN_r( geosinit()->ctxt,
geos, i ) );
1469 multiPolygon->addGeometry( poly.release() );
1472 return std::move( multiPolygon );
1474 case GEOS_GEOMETRYCOLLECTION:
1477 int nParts = GEOSGetNumGeometries_r( geosinit()->ctxt,
geos );
1478 geomCollection->reserve( nParts );
1479 for (
int i = 0; i < nParts; ++i )
1481 std::unique_ptr< QgsAbstractGeometry > geom(
fromGeos( GEOSGetGeometryN_r( geosinit()->ctxt,
geos, i ) ) );
1484 geomCollection->addGeometry( geom.release() );
1487 return std::move( geomCollection );
1495 if ( GEOSGeomTypeId_r( geosinit()->ctxt,
geos ) != GEOS_POLYGON )
1500 int nCoordDims = GEOSGeom_getCoordinateDimension_r( geosinit()->ctxt,
geos );
1501 int nDims = GEOSGeom_getDimensions_r( geosinit()->ctxt,
geos );
1502 bool hasZ = ( nCoordDims == 3 );
1503 bool hasM = ( ( nDims - nCoordDims ) == 1 );
1505 std::unique_ptr< QgsPolygon > polygon(
new QgsPolygon() );
1507 const GEOSGeometry *ring = GEOSGetExteriorRing_r( geosinit()->ctxt,
geos );
1510 polygon->setExteriorRing( sequenceToLinestring( ring, hasZ, hasM ).release() );
1513 QVector<QgsCurve *> interiorRings;
1514 const int ringCount = GEOSGetNumInteriorRings_r( geosinit()->ctxt,
geos );
1515 interiorRings.reserve( ringCount );
1516 for (
int i = 0; i < ringCount; ++i )
1518 ring = GEOSGetInteriorRingN_r( geosinit()->ctxt,
geos, i );
1521 interiorRings.push_back( sequenceToLinestring( ring, hasZ, hasM ).release() );
1524 polygon->setInteriorRings( interiorRings );
1529std::unique_ptr<QgsLineString> QgsGeos::sequenceToLinestring(
const GEOSGeometry *
geos,
bool hasZ,
bool hasM )
1531 const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq_r( geosinit()->ctxt,
geos );
1533 unsigned int nPoints;
1534 GEOSCoordSeq_getSize_r( geosinit()->ctxt, cs, &nPoints );
1536 QVector< double > xOut( nPoints );
1537 QVector< double > yOut( nPoints );
1538 QVector< double > zOut;
1540 zOut.resize( nPoints );
1541 QVector< double > mOut;
1543 mOut.resize( nPoints );
1545 double *x = xOut.data();
1546 double *y = yOut.data();
1547 double *z = zOut.data();
1548 double *m = mOut.data();
1550#if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=10 )
1551 GEOSCoordSeq_copyToArrays_r( geosinit()->ctxt, cs, x, y, hasZ ? z : nullptr, hasM ? m : nullptr );
1553 for (
unsigned int i = 0; i < nPoints; ++i )
1556 GEOSCoordSeq_getXYZ_r( geosinit()->ctxt, cs, i, x++, y++, z++ );
1558 GEOSCoordSeq_getXY_r( geosinit()->ctxt, cs, i, x++, y++ );
1561 GEOSCoordSeq_getOrdinate_r( geosinit()->ctxt, cs, i, 3, m++ );
1565 std::unique_ptr< QgsLineString > line(
new QgsLineString( xOut, yOut, zOut, mOut ) );
1569int QgsGeos::numberOfGeometries( GEOSGeometry *g )
1574 int geometryType = GEOSGeomTypeId_r( geosinit()->ctxt, g );
1575 if ( geometryType == GEOS_POINT || geometryType == GEOS_LINESTRING || geometryType == GEOS_LINEARRING
1576 || geometryType == GEOS_POLYGON )
1580 return GEOSGetNumGeometries_r( geosinit()->ctxt, g );
1594 GEOSCoordSeq_getXYZ_r( geosinit()->ctxt, cs, i, &x, &y, &z );
1596 GEOSCoordSeq_getXY_r( geosinit()->ctxt, cs, i, &x, &y );
1599 GEOSCoordSeq_getOrdinate_r( geosinit()->ctxt, cs, i, 3, &m );
1635 int geosType = GEOS_GEOMETRYCOLLECTION;
1642 geosType = GEOS_MULTIPOINT;
1646 geosType = GEOS_MULTILINESTRING;
1650 geosType = GEOS_MULTIPOLYGON;
1665 QVector< GEOSGeometry * > geomVector(
c->numGeometries() );
1666 for (
int i = 0; i <
c->numGeometries(); ++i )
1670 return createGeosCollection( geosType, geomVector );
1677 return createGeosPoint(
static_cast<const QgsPoint *
>( geom ), coordDims,
precision );
1695 if ( !mGeos || !geom )
1706 const double gridSize = parameters.
gridSize();
1713 case OverlayIntersection:
1716 opGeom.reset( GEOSIntersectionPrec_r( geosinit()->ctxt, mGeos.get(), geosGeom.get(), gridSize ) );
1720 opGeom.reset( GEOSIntersection_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) );
1724 case OverlayDifference:
1727 opGeom.reset( GEOSDifferencePrec_r( geosinit()->ctxt, mGeos.get(), geosGeom.get(), gridSize ) );
1731 opGeom.reset( GEOSDifference_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) );
1740 unionGeometry.reset( GEOSUnionPrec_r( geosinit()->ctxt, mGeos.get(), geosGeom.get(), gridSize ) );
1744 unionGeometry.reset( GEOSUnion_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) );
1747 if ( unionGeometry && GEOSGeomTypeId_r( geosinit()->ctxt, unionGeometry.get() ) == GEOS_MULTILINESTRING )
1749 geos::unique_ptr mergedLines( GEOSLineMerge_r( geosinit()->ctxt, unionGeometry.get() ) );
1752 unionGeometry = std::move( mergedLines );
1756 opGeom = std::move( unionGeometry );
1760 case OverlaySymDifference:
1763 opGeom.reset( GEOSSymDifferencePrec_r( geosinit()->ctxt, mGeos.get(), geosGeom.get(), gridSize ) );
1767 opGeom.reset( GEOSSymDifference_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) );
1773 catch ( GEOSException &e )
1775 logError( QStringLiteral(
"GEOS" ), e.what() );
1778 *errorMsg = e.what();
1784bool QgsGeos::relation(
const QgsAbstractGeometry *geom, Relation r, QString *errorMsg )
const
1786 if ( !mGeos || !geom )
1797 bool result =
false;
1800 if ( mGeosPrepared )
1804 case RelationIntersects:
1805 result = ( GEOSPreparedIntersects_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1807 case RelationTouches:
1808 result = ( GEOSPreparedTouches_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1810 case RelationCrosses:
1811 result = ( GEOSPreparedCrosses_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1813 case RelationWithin:
1814 result = ( GEOSPreparedWithin_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1816 case RelationContains:
1817 result = ( GEOSPreparedContains_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1819 case RelationDisjoint:
1820 result = ( GEOSPreparedDisjoint_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1822 case RelationOverlaps:
1823 result = ( GEOSPreparedOverlaps_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1831 case RelationIntersects:
1832 result = ( GEOSIntersects_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1834 case RelationTouches:
1835 result = ( GEOSTouches_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1837 case RelationCrosses:
1838 result = ( GEOSCrosses_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1840 case RelationWithin:
1841 result = ( GEOSWithin_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1843 case RelationContains:
1844 result = ( GEOSContains_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1846 case RelationDisjoint:
1847 result = ( GEOSDisjoint_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1849 case RelationOverlaps:
1850 result = ( GEOSOverlaps_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1854 catch ( GEOSException &e )
1856 logError( QStringLiteral(
"GEOS" ), e.what() );
1859 *errorMsg = e.what();
1877 geos.reset( GEOSBuffer_r( geosinit()->ctxt, mGeos.get(),
distance, segments ) );
1893 geos.reset( GEOSBufferWithStyle_r( geosinit()->ctxt, mGeos.get(),
distance, segments,
static_cast< int >( endCapStyle ),
static_cast< int >( joinStyle ), miterLimit ) );
1908 geos.reset( GEOSTopologyPreserveSimplify_r( geosinit()->ctxt, mGeos.get(), tolerance ) );
1923 geos.reset( GEOSInterpolate_r( geosinit()->ctxt, mGeos.get(),
distance ) );
1942 geos.reset( GEOSGetCentroid_r( geosinit()->ctxt, mGeos.get() ) );
1947 GEOSGeomGetX_r( geosinit()->ctxt,
geos.get(), &x );
1948 GEOSGeomGetY_r( geosinit()->ctxt,
geos.get(), &y );
1964 geos.reset( GEOSEnvelope_r( geosinit()->ctxt, mGeos.get() ) );
1983 geos.reset( GEOSPointOnSurface_r( geosinit()->ctxt, mGeos.get() ) );
1985 if ( !
geos || GEOSisEmpty_r( geosinit()->ctxt,
geos.get() ) != 0 )
1990 GEOSGeomGetX_r( geosinit()->ctxt,
geos.get(), &x );
1991 GEOSGeomGetY_r( geosinit()->ctxt,
geos.get(), &y );
2007 geos::unique_ptr cHull( GEOSConvexHull_r( geosinit()->ctxt, mGeos.get() ) );
2008 std::unique_ptr< QgsAbstractGeometry > cHullGeom =
fromGeos( cHull.get() );
2009 return cHullGeom.release();
2016#if GEOS_VERSION_MAJOR==3 && GEOS_VERSION_MINOR<11
2018 ( void )targetPercent;
2020 throw QgsNotSupportedException( QObject::tr(
"Calculating concaveHull requires a QGIS build based on GEOS 3.11 or later" ) );
2031 return concaveHullGeom.release();
2046 GEOSGeometry *g1 =
nullptr;
2048 char res = GEOSisValidDetail_r( geosinit()->ctxt, mGeos.get(), allowSelfTouchingHoles ? GEOSVALID_ALLOW_SELFTOUCHING_RING_FORMING_HOLE : 0, &r, &g1 );
2049 const bool invalid = res != 1;
2054 error = QString( r );
2055 GEOSFree_r( geosinit()->ctxt, r );
2058 if ( invalid && errorMsg )
2062 if ( translatedErrors.empty() )
2065 translatedErrors.insert( QStringLiteral(
"topology validation error" ), QObject::tr(
"Topology validation error",
"GEOS Error" ) );
2066 translatedErrors.insert( QStringLiteral(
"repeated point" ), QObject::tr(
"Repeated point",
"GEOS Error" ) );
2067 translatedErrors.insert( QStringLiteral(
"hole lies outside shell" ), QObject::tr(
"Hole lies outside shell",
"GEOS Error" ) );
2068 translatedErrors.insert( QStringLiteral(
"holes are nested" ), QObject::tr(
"Holes are nested",
"GEOS Error" ) );
2069 translatedErrors.insert( QStringLiteral(
"interior is disconnected" ), QObject::tr(
"Interior is disconnected",
"GEOS Error" ) );
2070 translatedErrors.insert( QStringLiteral(
"self-intersection" ), QObject::tr(
"Self-intersection",
"GEOS Error" ) );
2071 translatedErrors.insert( QStringLiteral(
"ring self-intersection" ), QObject::tr(
"Ring self-intersection",
"GEOS Error" ) );
2072 translatedErrors.insert( QStringLiteral(
"nested shells" ), QObject::tr(
"Nested shells",
"GEOS Error" ) );
2073 translatedErrors.insert( QStringLiteral(
"duplicate rings" ), QObject::tr(
"Duplicate rings",
"GEOS Error" ) );
2074 translatedErrors.insert( QStringLiteral(
"too few points in geometry component" ), QObject::tr(
"Too few points in geometry component",
"GEOS Error" ) );
2075 translatedErrors.insert( QStringLiteral(
"invalid coordinate" ), QObject::tr(
"Invalid coordinate",
"GEOS Error" ) );
2076 translatedErrors.insert( QStringLiteral(
"ring is not closed" ), QObject::tr(
"Ring is not closed",
"GEOS Error" ) );
2079 *errorMsg = translatedErrors.value( error.toLower(), error );
2081 if ( g1 && errorLoc )
2087 GEOSGeom_destroy_r( geosinit()->ctxt, g1 );
2097 if ( !mGeos || !geom )
2109 bool equal = GEOSEquals_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() );
2124 return GEOSisEmpty_r( geosinit()->ctxt, mGeos.get() );
2138 return GEOSisSimple_r( geosinit()->ctxt, mGeos.get() );
2143GEOSCoordSequence *QgsGeos::createCoordinateSequence(
const QgsCurve *curve,
double precision,
bool forceClose )
2145 GEOSContextHandle_t ctxt = geosinit()->ctxt;
2147 std::unique_ptr< QgsLineString > segmentized;
2148 const QgsLineString *line = qgsgeometry_cast<const QgsLineString *>( curve );
2153 line = segmentized.get();
2160 GEOSCoordSequence *coordSeq =
nullptr;
2162 const int numPoints = line->
numPoints();
2164 const bool hasZ = line->
is3D();
2166#if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=10 )
2169 if ( !forceClose || ( line->
pointN( 0 ) == line->
pointN( numPoints - 1 ) ) )
2174 coordSeq = GEOSCoordSeq_copyFromArrays_r( ctxt, line->
xData(), line->
yData(), line->
zData(),
nullptr, numPoints );
2177 QgsDebugMsg( QStringLiteral(
"GEOS Exception: Could not create coordinate sequence for %1 points" ).arg( numPoints ) );
2185 QVector< double > x = line->
xVector();
2186 if ( numPoints > 0 )
2187 x.append( x.at( 0 ) );
2188 QVector< double > y = line->
yVector();
2189 if ( numPoints > 0 )
2190 y.append( y.at( 0 ) );
2191 QVector< double > z = line->
zVector();
2192 if ( hasZ && numPoints > 0 )
2193 z.append( z.at( 0 ) );
2196 coordSeq = GEOSCoordSeq_copyFromArrays_r( ctxt, x.constData(), y.constData(), !hasZ ?
nullptr : z.constData(), nullptr, numPoints + 1 );
2199 QgsDebugMsg( QStringLiteral(
"GEOS Exception: Could not create closed coordinate sequence for %1 points" ).arg( numPoints + 1 ) );
2210 const bool hasM =
false;
2221 int numOutPoints = numPoints;
2222 if ( forceClose && ( line->
pointN( 0 ) != line->
pointN( numPoints - 1 ) ) )
2229 coordSeq = GEOSCoordSeq_create_r( ctxt, numOutPoints, coordDims );
2232 QgsDebugMsg( QStringLiteral(
"GEOS Exception: Could not create coordinate sequence for %1 points in %2 dimensions" ).arg( numPoints ).arg( coordDims ) );
2236 const double *xData = line->
xData();
2237 const double *yData = line->
yData();
2238 const double *zData = hasZ ? line->
zData() :
nullptr;
2239 const double *mData = hasM ? line->
mData() :
nullptr;
2243 for (
int i = 0; i < numOutPoints; ++i )
2245 if ( i >= numPoints )
2248 xData = line->
xData();
2249 yData = line->
yData();
2250 zData = hasZ ? line->
zData() :
nullptr;
2251 mData = hasM ? line->
mData() :
nullptr;
2263 GEOSCoordSeq_setOrdinate_r( ctxt, coordSeq, i, 3, *mData++ );
2269 for (
int i = 0; i < numOutPoints; ++i )
2271 if ( i >= numPoints )
2274 xData = line->
xData();
2275 yData = line->
yData();
2276 zData = hasZ ? line->
zData() :
nullptr;
2277 mData = hasM ? line->
mData() :
nullptr;
2281 GEOSCoordSeq_setXYZ_r( ctxt, coordSeq, i, *xData++, *yData++, *zData++ );
2285 GEOSCoordSeq_setXY_r( ctxt, coordSeq, i, *xData++, *yData++ );
2289 GEOSCoordSeq_setOrdinate_r( ctxt, coordSeq, i, 3, *mData++ );
2301 const QgsPoint *pt = qgsgeometry_cast<const QgsPoint *>( point );
2308geos::unique_ptr QgsGeos::createGeosPointXY(
double x,
double y,
bool hasZ,
double z,
bool hasM,
double m,
int coordDims,
double precision )
2316 if ( coordDims == 2 )
2322 geosPoint.reset( GEOSGeom_createPointFromXY_r( geosinit()->ctxt, x, y ) );
2326 GEOSCoordSequence *coordSeq = GEOSCoordSeq_create_r( geosinit()->ctxt, 1, coordDims );
2329 QgsDebugMsg( QStringLiteral(
"GEOS Exception: Could not create coordinate sequence for point with %1 dimensions" ).arg( coordDims ) );
2334 GEOSCoordSeq_setX_r( geosinit()->ctxt, coordSeq, 0, std::round( x /
precision ) *
precision );
2335 GEOSCoordSeq_setY_r( geosinit()->ctxt, coordSeq, 0, std::round( y /
precision ) *
precision );
2338 GEOSCoordSeq_setOrdinate_r( geosinit()->ctxt, coordSeq, 0, 2, std::round( z /
precision ) *
precision );
2343 GEOSCoordSeq_setX_r( geosinit()->ctxt, coordSeq, 0, x );
2344 GEOSCoordSeq_setY_r( geosinit()->ctxt, coordSeq, 0, y );
2347 GEOSCoordSeq_setOrdinate_r( geosinit()->ctxt, coordSeq, 0, 2, z );
2353 GEOSCoordSeq_setOrdinate_r( geosinit()->ctxt, coordSeq, 0, 3, m );
2356 geosPoint.reset( GEOSGeom_createPoint_r( geosinit()->ctxt, coordSeq ) );
2364 const QgsCurve *
c = qgsgeometry_cast<const QgsCurve *>( curve );
2368 GEOSCoordSequence *coordSeq = createCoordinateSequence(
c,
precision );
2375 geosGeom.reset( GEOSGeom_createLineString_r( geosinit()->ctxt, coordSeq ) );
2383 const QgsCurvePolygon *polygon = qgsgeometry_cast<const QgsCurvePolygon *>( poly );
2388 if ( !exteriorRing )
2396 geos::unique_ptr exteriorRingGeos( GEOSGeom_createLinearRing_r( geosinit()->ctxt, createCoordinateSequence( exteriorRing,
precision,
true ) ) );
2399 GEOSGeometry **holes =
nullptr;
2402 holes =
new GEOSGeometry*[ nHoles ];
2405 for (
int i = 0; i < nHoles; ++i )
2408 holes[i] = GEOSGeom_createLinearRing_r( geosinit()->ctxt, createCoordinateSequence( interiorRing,
precision,
true ) );
2410 geosPolygon.reset( GEOSGeom_createPolygon_r( geosinit()->ctxt, exteriorRingGeos.release(), holes, nHoles ) );
2428 if ( segments < 8 ) segments = 8;
2429 offset.reset( GEOSOffsetCurve_r( geosinit()->ctxt, mGeos.get(),
distance, segments,
static_cast< int >( joinStyle ), miterLimit ) );
2432 std::unique_ptr< QgsAbstractGeometry > offsetGeom =
fromGeos( offset.get() );
2433 return offsetGeom.release();
2447 GEOSBufferParams_setSingleSided_r( geosinit()->ctxt, bp.get(), 1 );
2448 GEOSBufferParams_setQuadrantSegments_r( geosinit()->ctxt, bp.get(), segments );
2449 GEOSBufferParams_setJoinStyle_r( geosinit()->ctxt, bp.get(),
static_cast< int >( joinStyle ) );
2450 GEOSBufferParams_setMitreLimit_r( geosinit()->ctxt, bp.get(), miterLimit );
2456 geos.reset( GEOSBufferWithParams_r( geosinit()->ctxt, mGeos.get(), bp.get(),
distance ) );
2472 geos.reset( GEOSMaximumInscribedCircle_r( geosinit()->ctxt, mGeos.get(), tolerance ) );
2490 boundaryGeos =
asGeos( boundary );
2492 geos.reset( GEOSLargestEmptyCircle_r( geosinit()->ctxt, mGeos.get(), boundaryGeos.get(), tolerance ) );
2508 geos.reset( GEOSMinimumWidth_r( geosinit()->ctxt, mGeos.get() ) );
2518 return std::numeric_limits< double >::quiet_NaN();
2525 if ( GEOSMinimumClearance_r( geosinit()->ctxt, mGeos.get(), &res ) != 0 )
2526 return std::numeric_limits< double >::quiet_NaN();
2542 geos.reset( GEOSMinimumClearanceLine_r( geosinit()->ctxt, mGeos.get() ) );
2558 geos.reset( GEOSNode_r( geosinit()->ctxt, mGeos.get() ) );
2566 if ( !mGeos || !other )
2578 geos.reset( GEOSSharedPaths_r( geosinit()->ctxt, mGeos.get(), otherGeos.get() ) );
2598 geos::unique_ptr reshapeLineGeos = createGeosLinestring( &reshapeWithLine, mPrecision );
2601 int numGeoms = GEOSGetNumGeometries_r( geosinit()->ctxt, mGeos.get() );
2602 if ( numGeoms == -1 )
2611 bool isMultiGeom =
false;
2612 int geosTypeId = GEOSGeomTypeId_r( geosinit()->ctxt, mGeos.get() );
2613 if ( geosTypeId == GEOS_MULTILINESTRING || geosTypeId == GEOS_MULTIPOLYGON )
2623 reshapedGeometry = reshapeLine( mGeos.get(), reshapeLineGeos.get(), mPrecision );
2627 reshapedGeometry = reshapePolygon( mGeos.get(), reshapeLineGeos.get(), mPrecision );
2632 std::unique_ptr< QgsAbstractGeometry > reshapeResult =
fromGeos( reshapedGeometry.get() );
2633 return reshapeResult;
2640 bool reshapeTookPlace =
false;
2643 GEOSGeometry **newGeoms =
new GEOSGeometry*[numGeoms];
2645 for (
int i = 0; i < numGeoms; ++i )
2648 currentReshapeGeometry = reshapeLine( GEOSGetGeometryN_r( geosinit()->ctxt, mGeos.get(), i ), reshapeLineGeos.get(), mPrecision );
2650 currentReshapeGeometry = reshapePolygon( GEOSGetGeometryN_r( geosinit()->ctxt, mGeos.get(), i ), reshapeLineGeos.get(), mPrecision );
2652 if ( currentReshapeGeometry )
2654 newGeoms[i] = currentReshapeGeometry.release();
2655 reshapeTookPlace =
true;
2659 newGeoms[i] = GEOSGeom_clone_r( geosinit()->ctxt, GEOSGetGeometryN_r( geosinit()->ctxt, mGeos.get(), i ) );
2666 newMultiGeom.reset( GEOSGeom_createCollection_r( geosinit()->ctxt, GEOS_MULTILINESTRING, newGeoms, numGeoms ) );
2670 newMultiGeom.reset( GEOSGeom_createCollection_r( geosinit()->ctxt, GEOS_MULTIPOLYGON, newGeoms, numGeoms ) );
2674 if ( !newMultiGeom )
2680 if ( reshapeTookPlace )
2684 std::unique_ptr< QgsAbstractGeometry > reshapedMultiGeom =
fromGeos( newMultiGeom.get() );
2685 return reshapedMultiGeom;
2707 if ( GEOSGeomTypeId_r( geosinit()->ctxt, mGeos.get() ) != GEOS_MULTILINESTRING )
2713 geos.reset( GEOSLineMerge_r( geosinit()->ctxt, mGeos.get() ) );
2737 if ( mGeosPrepared )
2739 nearestCoord.reset( GEOSPreparedNearestPoints_r( geosinit()->ctxt, mGeosPrepared.get(), otherGeom.get() ) );
2743 nearestCoord.reset( GEOSNearestPoints_r( geosinit()->ctxt, mGeos.get(), otherGeom.get() ) );
2746 ( void )GEOSCoordSeq_getX_r( geosinit()->ctxt, nearestCoord.get(), 0, &nx );
2747 ( void )GEOSCoordSeq_getY_r( geosinit()->ctxt, nearestCoord.get(), 0, &ny );
2749 catch ( GEOSException &e )
2751 logError( QStringLiteral(
"GEOS" ), e.what() );
2754 *errorMsg = e.what();
2764 if ( !mGeos || other.
isEmpty() )
2774 if ( !other || other->
isEmpty() )
2791 if ( !nearestCoord )
2794 *errorMsg = QStringLiteral(
"GEOS returned no nearest points" );
2798 ( void )GEOSCoordSeq_getX_r( geosinit()->ctxt, nearestCoord.get(), 0, &nx1 );
2799 ( void )GEOSCoordSeq_getY_r( geosinit()->ctxt, nearestCoord.get(), 0, &ny1 );
2800 ( void )GEOSCoordSeq_getX_r( geosinit()->ctxt, nearestCoord.get(), 1, &nx2 );
2801 ( void )GEOSCoordSeq_getY_r( geosinit()->ctxt, nearestCoord.get(), 1, &ny2 );
2803 catch ( GEOSException &e )
2805 logError( QStringLiteral(
"GEOS" ), e.what() );
2808 *errorMsg = e.what();
2835 distance = GEOSProject_r( geosinit()->ctxt, mGeos.get(), otherGeom.get() );
2837 catch ( GEOSException &e )
2839 logError( QStringLiteral(
"GEOS" ), e.what() );
2842 *errorMsg = e.what();
2857 geos::unique_ptr point = createGeosPointXY( x, y,
false, 0,
false, 0, 2, 0 );
2864 distance = GEOSProject_r( geosinit()->ctxt, mGeos.get(), point.get() );
2866 catch ( GEOSException &e )
2868 logError( QStringLiteral(
"GEOS" ), e.what() );
2871 *errorMsg = e.what();
2881 GEOSGeometry **
const lineGeosGeometries =
new GEOSGeometry*[ geometries.size()];
2888 lineGeosGeometries[validLines] = l.release();
2895 geos::unique_ptr result( GEOSPolygonize_r( geosinit()->ctxt, lineGeosGeometries, validLines ) );
2896 for (
int i = 0; i < validLines; ++i )
2898 GEOSGeom_destroy_r( geosinit()->ctxt, lineGeosGeometries[i] );
2900 delete[] lineGeosGeometries;
2903 catch ( GEOSException &e )
2907 *errorMsg = e.what();
2909 for (
int i = 0; i < validLines; ++i )
2911 GEOSGeom_destroy_r( geosinit()->ctxt, lineGeosGeometries[i] );
2913 delete[] lineGeosGeometries;
2928 extentGeosGeom =
asGeos( extent, mPrecision );
2929 if ( !extentGeosGeom )
2938 geos.reset( GEOSVoronoiDiagram_r( geosinit()->ctxt, mGeos.get(), extentGeosGeom.get(), tolerance, edgesOnly ) );
2940 if ( !
geos || GEOSisEmpty_r( geosinit()->ctxt,
geos.get() ) != 0 )
2960 geos.reset( GEOSDelaunayTriangulation_r( geosinit()->ctxt, mGeos.get(), tolerance, edgesOnly ) );
2962 if ( !
geos || GEOSisEmpty_r( geosinit()->ctxt,
geos.get() ) != 0 )
2974static bool _linestringEndpoints(
const GEOSGeometry *linestring,
double &x1,
double &y1,
double &x2,
double &y2 )
2976 const GEOSCoordSequence *coordSeq = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, linestring );
2980 unsigned int coordSeqSize;
2981 if ( GEOSCoordSeq_getSize_r( geosinit()->ctxt, coordSeq, &coordSeqSize ) == 0 )
2984 if ( coordSeqSize < 2 )
2987 GEOSCoordSeq_getX_r( geosinit()->ctxt, coordSeq, 0, &x1 );
2988 GEOSCoordSeq_getY_r( geosinit()->ctxt, coordSeq, 0, &y1 );
2989 GEOSCoordSeq_getX_r( geosinit()->ctxt, coordSeq, coordSeqSize - 1, &x2 );
2990 GEOSCoordSeq_getY_r( geosinit()->ctxt, coordSeq, coordSeqSize - 1, &y2 );
2996static geos::unique_ptr _mergeLinestrings(
const GEOSGeometry *line1,
const GEOSGeometry *line2,
const QgsPointXY &intersectionPoint )
2998 double x1, y1, x2, y2;
2999 if ( !_linestringEndpoints( line1, x1, y1, x2, y2 ) )
3002 double rx1, ry1, rx2, ry2;
3003 if ( !_linestringEndpoints( line2, rx1, ry1, rx2, ry2 ) )
3006 bool intersectionAtOrigLineEndpoint =
3007 ( intersectionPoint.
x() == x1 && intersectionPoint.
y() == y1 ) !=
3008 ( intersectionPoint.
x() == x2 && intersectionPoint.
y() == y2 );
3009 bool intersectionAtReshapeLineEndpoint =
3010 ( intersectionPoint.
x() == rx1 && intersectionPoint.
y() == ry1 ) ||
3011 ( intersectionPoint.
x() == rx2 && intersectionPoint.
y() == ry2 );
3014 if ( intersectionAtOrigLineEndpoint && intersectionAtReshapeLineEndpoint )
3018 GEOSGeometry *geoms[2] = { g1.release(), g2.release() };
3019 geos::unique_ptr multiGeom( GEOSGeom_createCollection_r( geosinit()->ctxt, GEOS_MULTILINESTRING, geoms, 2 ) );
3020 geos::unique_ptr res( GEOSLineMerge_r( geosinit()->ctxt, multiGeom.get() ) );
3030 if ( !line || !reshapeLineGeos )
3033 bool atLeastTwoIntersections =
false;
3034 bool oneIntersection =
false;
3040 geos::unique_ptr intersectGeom( GEOSIntersection_r( geosinit()->ctxt, line, reshapeLineGeos ) );
3041 if ( intersectGeom )
3043 const int geomType = GEOSGeomTypeId_r( geosinit()->ctxt, intersectGeom.get() );
3044 atLeastTwoIntersections = ( geomType == GEOS_MULTIPOINT && GEOSGetNumGeometries_r( geosinit()->ctxt, intersectGeom.get() ) > 1 )
3045 || ( geomType == GEOS_GEOMETRYCOLLECTION && GEOSGetNumGeometries_r( geosinit()->ctxt, intersectGeom.get() ) > 0 )
3046 || ( geomType == GEOS_MULTILINESTRING && GEOSGetNumGeometries_r( geosinit()->ctxt, intersectGeom.get() ) > 0 );
3048 if ( GEOSGeomTypeId_r( geosinit()->ctxt, intersectGeom.get() ) == GEOS_POINT )
3050 const GEOSCoordSequence *intersectionCoordSeq = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, intersectGeom.get() );
3052 GEOSCoordSeq_getX_r( geosinit()->ctxt, intersectionCoordSeq, 0, &xi );
3053 GEOSCoordSeq_getY_r( geosinit()->ctxt, intersectionCoordSeq, 0, &yi );
3054 oneIntersection =
true;
3059 catch ( GEOSException & )
3061 atLeastTwoIntersections =
false;
3065 if ( oneIntersection )
3066 return _mergeLinestrings( line, reshapeLineGeos, oneIntersectionPoint );
3068 if ( !atLeastTwoIntersections )
3072 double x1, y1, x2, y2;
3073 if ( !_linestringEndpoints( line, x1, y1, x2, y2 ) )
3079 bool isRing =
false;
3080 if ( GEOSGeomTypeId_r( geosinit()->ctxt, line ) == GEOS_LINEARRING
3081 || GEOSEquals_r( geosinit()->ctxt, beginLineVertex.get(), endLineVertex.get() ) == 1 )
3086 if ( !nodedGeometry )
3092 geos::unique_ptr mergedLines( GEOSLineMerge_r( geosinit()->ctxt, nodedGeometry.get() ) );
3098 int numMergedLines = GEOSGetNumGeometries_r( geosinit()->ctxt, mergedLines.get() );
3099 if ( numMergedLines < 2 )
3101 if ( numMergedLines == 1 )
3103 geos::unique_ptr result( GEOSGeom_clone_r( geosinit()->ctxt, reshapeLineGeos ) );
3110 QVector<GEOSGeometry *> resultLineParts;
3111 QVector<GEOSGeometry *> probableParts;
3113 for (
int i = 0; i < numMergedLines; ++i )
3115 const GEOSGeometry *currentGeom = GEOSGetGeometryN_r( geosinit()->ctxt, mergedLines.get(), i );
3118 bool alreadyAdded =
false;
3120 double bufferDistance = std::pow( 10.0L, geomDigits( currentGeom ) - 11 );
3121 for (
const GEOSGeometry *other : std::as_const( resultLineParts ) )
3123 GEOSHausdorffDistance_r( geosinit()->ctxt, currentGeom, other, &
distance );
3126 alreadyAdded =
true;
3133 const GEOSCoordSequence *currentCoordSeq = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, currentGeom );
3134 unsigned int currentCoordSeqSize;
3135 GEOSCoordSeq_getSize_r( geosinit()->ctxt, currentCoordSeq, ¤tCoordSeqSize );
3136 if ( currentCoordSeqSize < 2 )
3140 double xBegin, xEnd, yBegin, yEnd;
3141 GEOSCoordSeq_getX_r( geosinit()->ctxt, currentCoordSeq, 0, &xBegin );
3142 GEOSCoordSeq_getY_r( geosinit()->ctxt, currentCoordSeq, 0, &yBegin );
3143 GEOSCoordSeq_getX_r( geosinit()->ctxt, currentCoordSeq, currentCoordSeqSize - 1, &xEnd );
3144 GEOSCoordSeq_getY_r( geosinit()->ctxt, currentCoordSeq, currentCoordSeqSize - 1, &yEnd );
3149 int nEndpointsOnOriginalLine = 0;
3150 if ( pointContainedInLine( beginCurrentGeomVertex.get(), line ) == 1 )
3151 nEndpointsOnOriginalLine += 1;
3153 if ( pointContainedInLine( endCurrentGeomVertex.get(), line ) == 1 )
3154 nEndpointsOnOriginalLine += 1;
3157 int nEndpointsSameAsOriginalLine = 0;
3158 if ( GEOSEquals_r( geosinit()->ctxt, beginCurrentGeomVertex.get(), beginLineVertex.get() ) == 1
3159 || GEOSEquals_r( geosinit()->ctxt, beginCurrentGeomVertex.get(), endLineVertex.get() ) == 1 )
3160 nEndpointsSameAsOriginalLine += 1;
3162 if ( GEOSEquals_r( geosinit()->ctxt, endCurrentGeomVertex.get(), beginLineVertex.get() ) == 1
3163 || GEOSEquals_r( geosinit()->ctxt, endCurrentGeomVertex.get(), endLineVertex.get() ) == 1 )
3164 nEndpointsSameAsOriginalLine += 1;
3167 bool currentGeomOverlapsOriginalGeom =
false;
3168 bool currentGeomOverlapsReshapeLine =
false;
3169 if ( lineContainedInLine( currentGeom, line ) == 1 )
3170 currentGeomOverlapsOriginalGeom =
true;
3172 if ( lineContainedInLine( currentGeom, reshapeLineGeos ) == 1 )
3173 currentGeomOverlapsReshapeLine =
true;
3176 if ( !isRing && nEndpointsSameAsOriginalLine == 1 && nEndpointsOnOriginalLine == 2 && currentGeomOverlapsOriginalGeom )
3178 resultLineParts.push_back( GEOSGeom_clone_r( geosinit()->ctxt, currentGeom ) );
3181 else if ( isRing && nEndpointsOnOriginalLine == 2 && currentGeomOverlapsOriginalGeom )
3183 probableParts.push_back( GEOSGeom_clone_r( geosinit()->ctxt, currentGeom ) );
3185 else if ( nEndpointsOnOriginalLine == 2 && !currentGeomOverlapsOriginalGeom )
3187 resultLineParts.push_back( GEOSGeom_clone_r( geosinit()->ctxt, currentGeom ) );
3189 else if ( nEndpointsSameAsOriginalLine == 2 && !currentGeomOverlapsOriginalGeom )
3191 resultLineParts.push_back( GEOSGeom_clone_r( geosinit()->ctxt, currentGeom ) );
3193 else if ( currentGeomOverlapsOriginalGeom && currentGeomOverlapsReshapeLine )
3195 resultLineParts.push_back( GEOSGeom_clone_r( geosinit()->ctxt, currentGeom ) );
3200 if ( isRing && !probableParts.isEmpty() )
3203 GEOSGeometry *currentGeom =
nullptr;
3204 double maxLength = -std::numeric_limits<double>::max();
3205 double currentLength = 0;
3206 for (
int i = 0; i < probableParts.size(); ++i )
3208 currentGeom = probableParts.at( i );
3209 GEOSLength_r( geosinit()->ctxt, currentGeom, ¤tLength );
3210 if ( currentLength > maxLength )
3212 maxLength = currentLength;
3213 maxGeom.reset( currentGeom );
3217 GEOSGeom_destroy_r( geosinit()->ctxt, currentGeom );
3220 resultLineParts.push_back( maxGeom.release() );
3224 if ( resultLineParts.empty() )
3227 if ( resultLineParts.size() == 1 )
3229 result.reset( resultLineParts[0] );
3233 GEOSGeometry **lineArray =
new GEOSGeometry*[resultLineParts.size()];
3234 for (
int i = 0; i < resultLineParts.size(); ++i )
3236 lineArray[i] = resultLineParts[i];
3240 geos::unique_ptr multiLineGeom( GEOSGeom_createCollection_r( geosinit()->ctxt, GEOS_MULTILINESTRING, lineArray, resultLineParts.size() ) );
3241 delete [] lineArray;
3244 result.reset( GEOSLineMerge_r( geosinit()->ctxt, multiLineGeom.get() ) );
3248 if ( GEOSGeomTypeId_r( geosinit()->ctxt, result.get() ) != GEOS_LINESTRING )
3256geos::unique_ptr QgsGeos::reshapePolygon(
const GEOSGeometry *polygon,
const GEOSGeometry *reshapeLineGeos,
double precision )
3259 int nIntersections = 0;
3260 int lastIntersectingRing = -2;
3261 const GEOSGeometry *lastIntersectingGeom =
nullptr;
3263 int nRings = GEOSGetNumInteriorRings_r( geosinit()->ctxt, polygon );
3268 const GEOSGeometry *outerRing = GEOSGetExteriorRing_r( geosinit()->ctxt, polygon );
3269 if ( GEOSIntersects_r( geosinit()->ctxt, outerRing, reshapeLineGeos ) == 1 )
3272 lastIntersectingRing = -1;
3273 lastIntersectingGeom = outerRing;
3277 const GEOSGeometry **innerRings =
new const GEOSGeometry*[nRings];
3281 for (
int i = 0; i < nRings; ++i )
3283 innerRings[i] = GEOSGetInteriorRingN_r( geosinit()->ctxt, polygon, i );
3284 if ( GEOSIntersects_r( geosinit()->ctxt, innerRings[i], reshapeLineGeos ) == 1 )
3287 lastIntersectingRing = i;
3288 lastIntersectingGeom = innerRings[i];
3292 catch ( GEOSException & )
3297 if ( nIntersections != 1 )
3299 delete [] innerRings;
3305 if ( !reshapeResult )
3307 delete [] innerRings;
3312 GEOSGeometry *newRing =
nullptr;
3313 const GEOSCoordSequence *reshapeSequence = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, reshapeResult.get() );
3314 GEOSCoordSequence *newCoordSequence = GEOSCoordSeq_clone_r( geosinit()->ctxt, reshapeSequence );
3316 reshapeResult.reset();
3318 newRing = GEOSGeom_createLinearRing_r( geosinit()->ctxt, newCoordSequence );
3321 delete [] innerRings;
3325 GEOSGeometry *newOuterRing =
nullptr;
3326 if ( lastIntersectingRing == -1 )
3327 newOuterRing = newRing;
3329 newOuterRing = GEOSGeom_clone_r( geosinit()->ctxt, outerRing );
3332 QVector<GEOSGeometry *> ringList;
3335 GEOSGeometry *outerRingPoly = GEOSGeom_createPolygon_r( geosinit()->ctxt, GEOSGeom_clone_r( geosinit()->ctxt, newOuterRing ),
nullptr, 0 );
3336 if ( outerRingPoly )
3338 ringList.reserve( nRings );
3339 GEOSGeometry *currentRing =
nullptr;
3340 for (
int i = 0; i < nRings; ++i )
3342 if ( lastIntersectingRing == i )
3343 currentRing = newRing;
3345 currentRing = GEOSGeom_clone_r( geosinit()->ctxt, innerRings[i] );
3348 if ( GEOSContains_r( geosinit()->ctxt, outerRingPoly, currentRing ) == 1 )
3349 ringList.push_back( currentRing );
3351 GEOSGeom_destroy_r( geosinit()->ctxt, currentRing );
3354 GEOSGeom_destroy_r( geosinit()->ctxt, outerRingPoly );
3357 GEOSGeometry **newInnerRings =
new GEOSGeometry*[ringList.size()];
3358 for (
int i = 0; i < ringList.size(); ++i )
3359 newInnerRings[i] = ringList.at( i );
3361 delete [] innerRings;
3363 geos::unique_ptr reshapedPolygon( GEOSGeom_createPolygon_r( geosinit()->ctxt, newOuterRing, newInnerRings, ringList.size() ) );
3364 delete[] newInnerRings;
3366 return reshapedPolygon;
3369int QgsGeos::lineContainedInLine(
const GEOSGeometry *line1,
const GEOSGeometry *line2 )
3371 if ( !line1 || !line2 )
3376 double bufferDistance = std::pow( 10.0L, geomDigits( line2 ) - 11 );
3382 geos::unique_ptr intersectionGeom( GEOSIntersection_r( geosinit()->ctxt, bufferGeom.get(), line1 ) );
3385 double intersectGeomLength;
3388 GEOSLength_r( geosinit()->ctxt, intersectionGeom.get(), &intersectGeomLength );
3389 GEOSLength_r( geosinit()->ctxt, line1, &line1Length );
3391 double intersectRatio = line1Length / intersectGeomLength;
3392 if ( intersectRatio > 0.9 && intersectRatio < 1.1 )
3398int QgsGeos::pointContainedInLine(
const GEOSGeometry *point,
const GEOSGeometry *line )
3400 if ( !point || !line )
3403 double bufferDistance = std::pow( 10.0L, geomDigits( line ) - 11 );
3405 geos::unique_ptr lineBuffer( GEOSBuffer_r( geosinit()->ctxt, line, bufferDistance, 8 ) );
3409 bool contained =
false;
3410 if ( GEOSContains_r( geosinit()->ctxt, lineBuffer.get(), point ) == 1 )
3416int QgsGeos::geomDigits(
const GEOSGeometry *geom )
3422 const GEOSGeometry *bBoxRing = GEOSGetExteriorRing_r( geosinit()->ctxt, bbox.get() );
3426 const GEOSCoordSequence *bBoxCoordSeq = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, bBoxRing );
3428 if ( !bBoxCoordSeq )
3431 unsigned int nCoords = 0;
3432 if ( !GEOSCoordSeq_getSize_r( geosinit()->ctxt, bBoxCoordSeq, &nCoords ) )
3436 for (
unsigned int i = 0; i < nCoords - 1; ++i )
3439 GEOSCoordSeq_getX_r( geosinit()->ctxt, bBoxCoordSeq, i, &t );
3442 digits = std::ceil( std::log10( std::fabs( t ) ) );
3443 if ( digits > maxDigits )
3446 GEOSCoordSeq_getY_r( geosinit()->ctxt, bBoxCoordSeq, i, &t );
3447 digits = std::ceil( std::log10( std::fabs( t ) ) );
3448 if ( digits > maxDigits )
3457 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.
MakeValidMethod
Algorithms to use when repairing invalid geometries.
@ Linework
Combines all rings into a set of noded lines and then extracts valid polygons from that linework.
@ Structure
Structured method, first makes all rings valid and then merges shells and subtracts holes from shells...
Abstract base class for all geometries.
bool isMeasure() const
Returns true if the geometry contains m values.
virtual QgsRectangle boundingBox() const =0
Returns the minimal bounding box for the geometry.
bool is3D() const
Returns true if the geometry is 3D and contains a z-value.
QgsWkbTypes::Type 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(QgsWkbTypes::Type type)
Returns a new geometry collection matching a specified WKB type.
Encapsulates parameters under which a geometry operation is performed.
double gridSize() const
Returns the grid size which will be used to snap vertices of a geometry.
A geometry is the spatial representation of a feature.
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.
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
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 (all coordinates zero or after call to setMinimal()).
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 is empty.
double height() const
Returns the height of the rectangle.
static GeometryType geometryType(Type type)
Returns the geometry type for a WKB type, e.g., both MultiPolygon and CurvePolygon would have a Polyg...
Type
The WKB type describes the number of dimensions a geometry has.
static Type flatType(Type type)
Returns the flat type for a WKB type.
static bool isMultiType(Type type)
Returns true if the WKB type is a multi type.
Contains geos related utilities and functions.
std::unique_ptr< GEOSGeometry, GeosDeleter > unique_ptr
Scoped GEOS pointer.
std::unique_ptr< GEOSCoordSequence, GeosDeleter > coord_sequence_unique_ptr
Scoped GEOS coordinate sequence pointer.
std::unique_ptr< GEOSBufferParams, GeosDeleter > buffer_params_unique_ptr
Scoped GEOS buffer params pointer.
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
QMap< QString, QString > QgsStringMap
QVector< QgsPoint > QgsPointSequence
Q_GLOBAL_STATIC(QReadWriteLock, sDefinitionCacheLock)
#define DEFAULT_QUADRANT_SEGMENTS
#define CATCH_GEOS_WITH_ERRMSG(r)
QLineF segment(int index, QRectF rect, double radius)
Utility class for identifying a unique vertex within a geometry.
void CORE_EXPORT operator()(GEOSGeometry *geom) const
Destroys the GEOS geometry geom, using the static QGIS geos context.