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(); \
51 static 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 );
83 static void printGEOSNotice(
const char *fmt, ... )
85 #if defined(QGISDEBUG)
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 );
163 #if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=8 )
164 std::unique_ptr<QgsAbstractGeometry> QgsGeos::makeValid( QString *errorMsg )
const
174 geos.reset( GEOSMakeValid_r( geosinit()->ctxt, mGeos.get() ) );
202 std::unique_ptr< QgsAbstractGeometry > geom =
fromGeos( newPart );
209 mGeosPrepared.reset();
222 mGeosPrepared.reset( GEOSPrepare_r( geosinit()->ctxt, mGeos.get() ) );
226 void QgsGeos::cacheGeos()
const
243 return overlay( geom, OverlayIntersection, errorMsg ).release();
248 return overlay( geom, OverlayDifference, errorMsg ).release();
263 catch ( GEOSException &e )
265 logError( QStringLiteral(
"GEOS" ), e.what() );
268 *errorMsg = e.what();
279 int partType = GEOSGeomTypeId_r( geosinit()->ctxt, currentPart );
282 if ( partType == GEOS_POINT )
293 if ( partType == GEOS_MULTILINESTRING || partType == GEOS_MULTIPOLYGON || partType == GEOS_GEOMETRYCOLLECTION )
295 int partCount = GEOSGetNumGeometries_r( geosinit()->ctxt, currentPart );
296 for (
int i = 0; i < partCount; ++i )
298 subdivideRecursive( GEOSGetGeometryN_r( geosinit()->ctxt, currentPart, i ), maxNodes, depth, parts, clipRect );
309 int vertexCount = GEOSGetNumCoordinates_r( geosinit()->ctxt, currentPart );
310 if ( vertexCount == 0 )
314 else if ( vertexCount < maxNodes )
321 double width = clipRect.
width();
322 double height = clipRect.
height();
325 if ( width > height )
338 halfClipRect1.
setYMinimum( halfClipRect1.
yMinimum() - std::numeric_limits<double>::epsilon() );
339 halfClipRect2.
setYMinimum( halfClipRect2.
yMinimum() - std::numeric_limits<double>::epsilon() );
340 halfClipRect1.
setYMaximum( halfClipRect1.
yMaximum() + std::numeric_limits<double>::epsilon() );
341 halfClipRect2.
setYMaximum( halfClipRect2.
yMaximum() + std::numeric_limits<double>::epsilon() );
345 halfClipRect1.
setXMinimum( halfClipRect1.
xMinimum() - std::numeric_limits<double>::epsilon() );
346 halfClipRect2.
setXMinimum( halfClipRect2.
xMinimum() - std::numeric_limits<double>::epsilon() );
347 halfClipRect1.
setXMaximum( halfClipRect1.
xMaximum() + std::numeric_limits<double>::epsilon() );
348 halfClipRect2.
setXMaximum( halfClipRect2.
xMaximum() + std::numeric_limits<double>::epsilon() );
358 subdivideRecursive( clipPart1.get(), maxNodes, depth, parts, halfClipRect1 );
362 subdivideRecursive( clipPart2.get(), maxNodes, depth, parts, halfClipRect2 );
374 maxNodes = std::max( maxNodes, 8 );
383 return std::move( parts );
388 return overlay( geom, OverlayUnion, errorMsg ).release();
393 QVector< GEOSGeometry * > geosGeometries;
394 geosGeometries.reserve( geomList.size() );
400 geosGeometries <<
asGeos( g, mPrecision ).release();
406 geos::unique_ptr geomCollection = createGeosCollection( GEOS_GEOMETRYCOLLECTION, geosGeometries );
407 geomUnion.reset( GEOSUnaryUnion_r( geosinit()->ctxt, geomCollection.get() ) );
411 std::unique_ptr< QgsAbstractGeometry > result =
fromGeos( geomUnion.get() );
412 return result.release();
417 QVector< GEOSGeometry * > geosGeometries;
418 geosGeometries.reserve( geomList.size() );
424 geosGeometries <<
asGeos( g.constGet(), mPrecision ).release();
430 geos::unique_ptr geomCollection = createGeosCollection( GEOS_GEOMETRYCOLLECTION, geosGeometries );
431 geomUnion.reset( GEOSUnaryUnion_r( geosinit()->ctxt, geomCollection.get() ) );
435 std::unique_ptr< QgsAbstractGeometry > result =
fromGeos( geomUnion.get() );
436 return result.release();
441 return overlay( geom, OverlaySymDifference, errorMsg ).release();
453 if ( !otherGeosGeom )
460 #if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=9 )
463 GEOSPreparedDistance_r( geosinit()->ctxt, mGeosPrepared.get(), otherGeosGeom.get(), &
distance );
467 GEOSDistance_r( geosinit()->ctxt, mGeos.get(), otherGeosGeom.get(), &
distance );
470 GEOSDistance_r( geosinit()->ctxt, mGeos.get(), otherGeosGeom.get(), &
distance );
486 if ( !otherGeosGeom )
499 #if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=9 )
502 #if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=10 )
503 return GEOSPreparedDistanceWithin_r( geosinit()->ctxt, mGeosPrepared.get(), otherGeosGeom.get(), maxdist );
505 GEOSPreparedDistance_r( geosinit()->ctxt, mGeosPrepared.get(), otherGeosGeom.get(), &
distance );
510 #if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=10 )
511 return GEOSDistanceWithin_r( geosinit()->ctxt, mGeos.get(), otherGeosGeom.get(), maxdist );
513 GEOSDistance_r( geosinit()->ctxt, mGeos.get(), otherGeosGeom.get(), &
distance );
517 GEOSDistance_r( geosinit()->ctxt, mGeos.get(), otherGeosGeom.get(), &
distance );
534 if ( !otherGeosGeom )
541 GEOSHausdorffDistance_r( geosinit()->ctxt, mGeos.get(), otherGeosGeom.get(), &
distance );
557 if ( !otherGeosGeom )
564 GEOSHausdorffDistanceDensify_r( geosinit()->ctxt, mGeos.get(), otherGeosGeom.get(), densifyFraction, &
distance );
573 #if GEOS_VERSION_MAJOR==3 && GEOS_VERSION_MINOR<7
576 throw QgsNotSupportedException( QStringLiteral(
"Calculating frechetDistance requires a QGIS build based on GEOS 3.7 or later" ) );
585 if ( !otherGeosGeom )
592 GEOSFrechetDistance_r( geosinit()->ctxt, mGeos.get(), otherGeosGeom.get(), &
distance );
602 #if GEOS_VERSION_MAJOR==3 && GEOS_VERSION_MINOR<7
604 ( void )densifyFraction;
606 throw QgsNotSupportedException( QStringLiteral(
"Calculating frechetDistanceDensify requires a QGIS build based on GEOS 3.7 or later" ) );
615 if ( !otherGeosGeom )
622 GEOSFrechetDistanceDensify_r( geosinit()->ctxt, mGeos.get(), otherGeosGeom.get(), densifyFraction, &
distance );
632 return relation( geom, RelationIntersects, errorMsg );
637 return relation( geom, RelationTouches, errorMsg );
642 return relation( geom, RelationCrosses, errorMsg );
647 return relation( geom, RelationWithin, errorMsg );
652 return relation( geom, RelationOverlaps, errorMsg );
657 return relation( geom, RelationContains, errorMsg );
662 return relation( geom, RelationDisjoint, errorMsg );
681 char *r = GEOSRelate_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() );
684 result = QString( r );
685 GEOSFree_r( geosinit()->ctxt, r );
688 catch ( GEOSException &e )
690 logError( QStringLiteral(
"GEOS" ), e.what() );
693 *errorMsg = e.what();
702 if ( !mGeos || !geom )
716 result = ( GEOSRelatePattern_r( geosinit()->ctxt, mGeos.get(), geosGeom.get(), pattern.toLocal8Bit().constData() ) == 1 );
718 catch ( GEOSException &e )
720 logError( QStringLiteral(
"GEOS" ), e.what() );
723 *errorMsg = e.what();
740 if ( GEOSArea_r( geosinit()->ctxt, mGeos.get(), &
area ) != 1 )
756 if ( GEOSLength_r( geosinit()->ctxt, mGeos.get(), &
length ) != 1 )
764 QVector<QgsGeometry> &newGeometries,
767 QString *errorMsg,
bool skipIntersectionCheck )
const
782 if ( !GEOSisValid_r( geosinit()->ctxt, mGeos.get() ) )
790 newGeometries.clear();
797 splitLineGeos = createGeosLinestring( &splitLine, mPrecision );
801 splitLineGeos = createGeosPointXY( splitLine.
xAt( 0 ), splitLine.
yAt( 0 ),
false, 0,
false, 0, 2, mPrecision );
808 if ( !GEOSisValid_r( geosinit()->ctxt, splitLineGeos.get() ) || !GEOSisSimple_r( geosinit()->ctxt, splitLineGeos.get() ) )
816 if ( !topologicalTestPointsSplit( splitLineGeos.get(), topologyTestPoints ) )
825 returnCode = splitLinearGeometry( splitLineGeos.get(), newGeometries, skipIntersectionCheck );
829 returnCode = splitPolygonGeometry( splitLineGeos.get(), newGeometries, skipIntersectionCheck );
843 bool QgsGeos::topologicalTestPointsSplit(
const GEOSGeometry *splitLine,
QgsPointSequence &testPoints, QString *errorMsg )
const
857 geos::unique_ptr intersectionGeom( GEOSIntersection_r( geosinit()->ctxt, mGeos.get(), splitLine ) );
858 if ( !intersectionGeom )
862 int nIntersectGeoms = 1;
863 if ( GEOSGeomTypeId_r( geosinit()->ctxt, intersectionGeom.get() ) == GEOS_LINESTRING
864 || GEOSGeomTypeId_r( geosinit()->ctxt, intersectionGeom.get() ) == GEOS_POINT )
868 nIntersectGeoms = GEOSGetNumGeometries_r( geosinit()->ctxt, intersectionGeom.get() );
870 for (
int i = 0; i < nIntersectGeoms; ++i )
872 const GEOSGeometry *currentIntersectGeom =
nullptr;
874 currentIntersectGeom = intersectionGeom.get();
876 currentIntersectGeom = GEOSGetGeometryN_r( geosinit()->ctxt, intersectionGeom.get(), i );
878 const GEOSCoordSequence *lineSequence = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, currentIntersectGeom );
879 unsigned int sequenceSize = 0;
881 if ( GEOSCoordSeq_getSize_r( geosinit()->ctxt, lineSequence, &sequenceSize ) != 0 )
883 for (
unsigned int i = 0; i < sequenceSize; ++i )
885 if ( GEOSCoordSeq_getX_r( geosinit()->ctxt, lineSequence, i, &x ) != 0 )
887 if ( GEOSCoordSeq_getY_r( geosinit()->ctxt, lineSequence, i, &y ) != 0 )
889 testPoints.push_back(
QgsPoint( x, y ) );
903 int type = GEOSGeomTypeId_r( geosinit()->ctxt, mGeos.get() );
905 std::unique_ptr< QgsMultiCurve > multiCurve;
906 if ( type == GEOS_MULTILINESTRING )
908 multiCurve.reset( qgsgeometry_cast<QgsMultiCurve *>(
mGeometry->
clone() ) );
910 else if ( type == GEOS_LINESTRING )
926 std::unique_ptr< QgsAbstractGeometry > splitGeom(
fromGeos( GEOSsplitPoint ) );
927 QgsPoint *splitPoint = qgsgeometry_cast<QgsPoint *>( splitGeom.get() );
936 for (
int i = 0; i < multiCurve->numGeometries(); ++i )
938 const QgsLineString *line = qgsgeometry_cast<const QgsLineString *>( multiCurve->geometryN( i ) );
945 for (
int j = 1; j < ( nVertices - 1 ); ++j )
949 if ( currentPoint == *splitPoint )
961 return asGeos( &lines, mPrecision );
973 if ( !skipIntersectionCheck && !GEOSIntersects_r( geosinit()->ctxt, splitLine, mGeos.get() ) )
977 int linearIntersect = GEOSRelatePattern_r( geosinit()->ctxt, mGeos.get(), splitLine,
"1********" );
978 if ( linearIntersect > 0 )
981 int splitGeomType = GEOSGeomTypeId_r( geosinit()->ctxt, splitLine );
984 if ( splitGeomType == GEOS_POINT )
986 splitGeom = linePointDifference( splitLine );
990 splitGeom.reset( GEOSDifference_r( geosinit()->ctxt, mGeos.get(), splitLine ) );
992 QVector<GEOSGeometry *> lineGeoms;
994 int splitType = GEOSGeomTypeId_r( geosinit()->ctxt, splitGeom.get() );
995 if ( splitType == GEOS_MULTILINESTRING )
997 int nGeoms = GEOSGetNumGeometries_r( geosinit()->ctxt, splitGeom.get() );
998 lineGeoms.reserve( nGeoms );
999 for (
int i = 0; i < nGeoms; ++i )
1000 lineGeoms << GEOSGeom_clone_r( geosinit()->ctxt, GEOSGetGeometryN_r( geosinit()->ctxt, splitGeom.get(), i ) );
1005 lineGeoms << GEOSGeom_clone_r( geosinit()->ctxt, splitGeom.get() );
1008 mergeGeometriesMultiTypeSplit( lineGeoms );
1010 for (
int i = 0; i < lineGeoms.size(); ++i )
1013 GEOSGeom_destroy_r( geosinit()->ctxt, lineGeoms[i] );
1029 if ( !mGeosPrepared )
1033 if ( !skipIntersectionCheck && !GEOSPreparedIntersects_r( geosinit()->ctxt, mGeosPrepared.get(), splitLine ) )
1038 if ( !nodedGeometry )
1041 const GEOSGeometry *noded = nodedGeometry.get();
1042 geos::unique_ptr polygons( GEOSPolygonize_r( geosinit()->ctxt, &noded, 1 ) );
1043 if ( !polygons || numberOfGeometries( polygons.get() ) == 0 )
1050 QVector<GEOSGeometry *> testedGeometries;
1055 for (
int i = 0; i < numberOfGeometries( polygons.get() ); i++ )
1057 const GEOSGeometry *polygon = GEOSGetGeometryN_r( geosinit()->ctxt, polygons.get(), i );
1061 testedGeometries << GEOSGeom_clone_r( geosinit()->ctxt, polygon );
1064 int nGeometriesThis = numberOfGeometries( mGeos.get() );
1065 if ( testedGeometries.empty() || testedGeometries.size() == nGeometriesThis )
1068 for (
int i = 0; i < testedGeometries.size(); ++i )
1070 GEOSGeom_destroy_r( geosinit()->ctxt, testedGeometries[i] );
1079 mergeGeometriesMultiTypeSplit( testedGeometries );
1082 for ( i = 0; i < testedGeometries.size() && GEOSisValid_r( geosinit()->ctxt, testedGeometries[i] ); ++i )
1085 if ( i < testedGeometries.size() )
1087 for ( i = 0; i < testedGeometries.size(); ++i )
1088 GEOSGeom_destroy_r( geosinit()->ctxt, testedGeometries[i] );
1093 for ( i = 0; i < testedGeometries.size(); ++i )
1096 GEOSGeom_destroy_r( geosinit()->ctxt, testedGeometries[i] );
1102 geos::unique_ptr QgsGeos::nodeGeometries(
const GEOSGeometry *splitLine,
const GEOSGeometry *geom )
1104 if ( !splitLine || !geom )
1108 if ( GEOSGeomTypeId_r( geosinit()->ctxt, geom ) == GEOS_POLYGON || GEOSGeomTypeId_r( geosinit()->ctxt, geom ) == GEOS_MULTIPOLYGON )
1109 geometryBoundary.reset( GEOSBoundary_r( geosinit()->ctxt, geom ) );
1111 geometryBoundary.reset( GEOSGeom_clone_r( geosinit()->ctxt, geom ) );
1113 geos::unique_ptr splitLineClone( GEOSGeom_clone_r( geosinit()->ctxt, splitLine ) );
1114 geos::unique_ptr unionGeometry( GEOSUnion_r( geosinit()->ctxt, splitLineClone.get(), geometryBoundary.get() ) );
1116 return unionGeometry;
1119 int QgsGeos::mergeGeometriesMultiTypeSplit( QVector<GEOSGeometry *> &splitResult )
const
1125 int type = GEOSGeomTypeId_r( geosinit()->ctxt, mGeos.get() );
1126 if ( type != GEOS_GEOMETRYCOLLECTION &&
1127 type != GEOS_MULTILINESTRING &&
1128 type != GEOS_MULTIPOLYGON &&
1129 type != GEOS_MULTIPOINT )
1132 QVector<GEOSGeometry *> copyList = splitResult;
1133 splitResult.clear();
1136 QVector<GEOSGeometry *> unionGeom;
1138 for (
int i = 0; i < copyList.size(); ++i )
1141 bool isPart =
false;
1142 for (
int j = 0; j < GEOSGetNumGeometries_r( geosinit()->ctxt, mGeos.get() ); j++ )
1144 if ( GEOSEquals_r( geosinit()->ctxt, copyList[i], GEOSGetGeometryN_r( geosinit()->ctxt, mGeos.get(), j ) ) )
1153 unionGeom << copyList[i];
1157 QVector<GEOSGeometry *> geomVector;
1158 geomVector << copyList[i];
1160 if ( type == GEOS_MULTILINESTRING )
1161 splitResult << createGeosCollection( GEOS_MULTILINESTRING, geomVector ).release();
1162 else if ( type == GEOS_MULTIPOLYGON )
1163 splitResult << createGeosCollection( GEOS_MULTIPOLYGON, geomVector ).release();
1165 GEOSGeom_destroy_r( geosinit()->ctxt, copyList[i] );
1170 if ( !unionGeom.isEmpty() )
1172 if ( type == GEOS_MULTILINESTRING )
1173 splitResult << createGeosCollection( GEOS_MULTILINESTRING, unionGeom ).release();
1174 else if ( type == GEOS_MULTIPOLYGON )
1175 splitResult << createGeosCollection( GEOS_MULTIPOLYGON, unionGeom ).release();
1185 geos::unique_ptr QgsGeos::createGeosCollection(
int typeId,
const QVector<GEOSGeometry *> &geoms )
1187 int nNullGeoms = geoms.count(
nullptr );
1188 int nNotNullGeoms = geoms.size() - nNullGeoms;
1190 GEOSGeometry **geomarr =
new GEOSGeometry*[ nNotNullGeoms ];
1197 QVector<GEOSGeometry *>::const_iterator geomIt = geoms.constBegin();
1198 for ( ; geomIt != geoms.constEnd(); ++geomIt )
1202 if ( GEOSisEmpty_r( geosinit()->ctxt, *geomIt ) )
1207 GEOSGeom_destroy_r( geosinit()->ctxt, *geomIt );
1211 geomarr[i] = *geomIt;
1220 geom.reset( GEOSGeom_createCollection_r( geosinit()->ctxt, typeId, geomarr, nNotNullGeoms ) );
1222 catch ( GEOSException & )
1238 int nCoordDims = GEOSGeom_getCoordinateDimension_r( geosinit()->ctxt,
geos );
1239 int nDims = GEOSGeom_getDimensions_r( geosinit()->ctxt,
geos );
1240 bool hasZ = ( nCoordDims == 3 );
1241 bool hasM = ( ( nDims - nCoordDims ) == 1 );
1243 switch ( GEOSGeomTypeId_r( geosinit()->ctxt,
geos ) )
1247 if ( GEOSisEmpty_r( geosinit()->ctxt,
geos ) )
1250 const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq_r( geosinit()->ctxt,
geos );
1251 unsigned int nPoints = 0;
1252 GEOSCoordSeq_getSize_r( geosinit()->ctxt, cs, &nPoints );
1253 return nPoints > 0 ? std::unique_ptr<QgsAbstractGeometry>(
coordSeqPoint( cs, 0, hasZ, hasM ).clone() ) : std::make_unique< QgsPoint >();
1255 case GEOS_LINESTRING:
1257 return sequenceToLinestring(
geos, hasZ, hasM );
1263 case GEOS_MULTIPOINT:
1265 std::unique_ptr< QgsMultiPoint > multiPoint(
new QgsMultiPoint() );
1266 int nParts = GEOSGetNumGeometries_r( geosinit()->ctxt,
geos );
1267 multiPoint->reserve( nParts );
1268 for (
int i = 0; i < nParts; ++i )
1270 const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, GEOSGetGeometryN_r( geosinit()->ctxt,
geos, i ) );
1273 unsigned int nPoints = 0;
1274 GEOSCoordSeq_getSize_r( geosinit()->ctxt, cs, &nPoints );
1276 multiPoint->addGeometry(
coordSeqPoint( cs, 0, hasZ, hasM ).clone() );
1279 return std::move( multiPoint );
1281 case GEOS_MULTILINESTRING:
1284 int nParts = GEOSGetNumGeometries_r( geosinit()->ctxt,
geos );
1285 multiLineString->reserve( nParts );
1286 for (
int i = 0; i < nParts; ++i )
1288 std::unique_ptr< QgsLineString >line( sequenceToLinestring( GEOSGetGeometryN_r( geosinit()->ctxt,
geos, i ), hasZ, hasM ) );
1291 multiLineString->addGeometry( line.release() );
1294 return std::move( multiLineString );
1296 case GEOS_MULTIPOLYGON:
1298 std::unique_ptr< QgsMultiPolygon > multiPolygon(
new QgsMultiPolygon() );
1300 int nParts = GEOSGetNumGeometries_r( geosinit()->ctxt,
geos );
1301 multiPolygon->reserve( nParts );
1302 for (
int i = 0; i < nParts; ++i )
1304 std::unique_ptr< QgsPolygon > poly =
fromGeosPolygon( GEOSGetGeometryN_r( geosinit()->ctxt,
geos, i ) );
1307 multiPolygon->addGeometry( poly.release() );
1310 return std::move( multiPolygon );
1312 case GEOS_GEOMETRYCOLLECTION:
1315 int nParts = GEOSGetNumGeometries_r( geosinit()->ctxt,
geos );
1316 geomCollection->reserve( nParts );
1317 for (
int i = 0; i < nParts; ++i )
1319 std::unique_ptr< QgsAbstractGeometry > geom(
fromGeos( GEOSGetGeometryN_r( geosinit()->ctxt,
geos, i ) ) );
1322 geomCollection->addGeometry( geom.release() );
1325 return std::move( geomCollection );
1333 if ( GEOSGeomTypeId_r( geosinit()->ctxt,
geos ) != GEOS_POLYGON )
1338 int nCoordDims = GEOSGeom_getCoordinateDimension_r( geosinit()->ctxt,
geos );
1339 int nDims = GEOSGeom_getDimensions_r( geosinit()->ctxt,
geos );
1340 bool hasZ = ( nCoordDims == 3 );
1341 bool hasM = ( ( nDims - nCoordDims ) == 1 );
1343 std::unique_ptr< QgsPolygon > polygon(
new QgsPolygon() );
1345 const GEOSGeometry *ring = GEOSGetExteriorRing_r( geosinit()->ctxt,
geos );
1348 polygon->setExteriorRing( sequenceToLinestring( ring, hasZ, hasM ).release() );
1351 QVector<QgsCurve *> interiorRings;
1352 const int ringCount = GEOSGetNumInteriorRings_r( geosinit()->ctxt,
geos );
1353 interiorRings.reserve( ringCount );
1354 for (
int i = 0; i < ringCount; ++i )
1356 ring = GEOSGetInteriorRingN_r( geosinit()->ctxt,
geos, i );
1359 interiorRings.push_back( sequenceToLinestring( ring, hasZ, hasM ).release() );
1362 polygon->setInteriorRings( interiorRings );
1367 std::unique_ptr<QgsLineString> QgsGeos::sequenceToLinestring(
const GEOSGeometry *
geos,
bool hasZ,
bool hasM )
1369 const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq_r( geosinit()->ctxt,
geos );
1370 unsigned int nPoints;
1371 GEOSCoordSeq_getSize_r( geosinit()->ctxt, cs, &nPoints );
1372 QVector< double > xOut( nPoints );
1373 QVector< double > yOut( nPoints );
1374 QVector< double > zOut;
1376 zOut.resize( nPoints );
1377 QVector< double > mOut;
1379 mOut.resize( nPoints );
1380 double *x = xOut.data();
1381 double *y = yOut.data();
1382 double *z = zOut.data();
1383 double *m = mOut.data();
1384 for (
unsigned int i = 0; i < nPoints; ++i )
1386 #if GEOS_VERSION_MAJOR>3 || GEOS_VERSION_MINOR>=8
1388 GEOSCoordSeq_getXYZ_r( geosinit()->ctxt, cs, i, x++, y++, z++ );
1390 GEOSCoordSeq_getXY_r( geosinit()->ctxt, cs, i, x++, y++ );
1392 GEOSCoordSeq_getX_r( geosinit()->ctxt, cs, i, x++ );
1393 GEOSCoordSeq_getY_r( geosinit()->ctxt, cs, i, y++ );
1396 GEOSCoordSeq_getZ_r( geosinit()->ctxt, cs, i, z++ );
1401 GEOSCoordSeq_getOrdinate_r( geosinit()->ctxt, cs, i, 3, m++ );
1404 std::unique_ptr< QgsLineString > line(
new QgsLineString( xOut, yOut, zOut, mOut ) );
1408 int QgsGeos::numberOfGeometries( GEOSGeometry *g )
1413 int geometryType = GEOSGeomTypeId_r( geosinit()->ctxt, g );
1414 if ( geometryType == GEOS_POINT || geometryType == GEOS_LINESTRING || geometryType == GEOS_LINEARRING
1415 || geometryType == GEOS_POLYGON )
1419 return GEOSGetNumGeometries_r( geosinit()->ctxt, g );
1432 #if GEOS_VERSION_MAJOR>3 || GEOS_VERSION_MINOR>=8
1434 GEOSCoordSeq_getXYZ_r( geosinit()->ctxt, cs, i, &x, &y, &z );
1436 GEOSCoordSeq_getXY_r( geosinit()->ctxt, cs, i, &x, &y );
1438 GEOSCoordSeq_getX_r( geosinit()->ctxt, cs, i, &x );
1439 GEOSCoordSeq_getY_r( geosinit()->ctxt, cs, i, &y );
1442 GEOSCoordSeq_getZ_r( geosinit()->ctxt, cs, i, &z );
1447 GEOSCoordSeq_getOrdinate_r( geosinit()->ctxt, cs, i, 3, &m );
1483 int geosType = GEOS_GEOMETRYCOLLECTION;
1490 geosType = GEOS_MULTIPOINT;
1494 geosType = GEOS_MULTILINESTRING;
1498 geosType = GEOS_MULTIPOLYGON;
1513 QVector< GEOSGeometry * > geomVector(
c->numGeometries() );
1514 for (
int i = 0; i <
c->numGeometries(); ++i )
1518 return createGeosCollection( geosType, geomVector );
1525 return createGeosPoint(
static_cast<const QgsPoint *
>( geom ), coordDims,
precision );
1541 std::unique_ptr<QgsAbstractGeometry> QgsGeos::overlay(
const QgsAbstractGeometry *geom, Overlay op, QString *errorMsg )
const
1543 if ( !mGeos || !geom )
1559 case OverlayIntersection:
1560 opGeom.reset( GEOSIntersection_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) );
1563 case OverlayDifference:
1564 opGeom.reset( GEOSDifference_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) );
1569 geos::unique_ptr unionGeometry( GEOSUnion_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) );
1571 if ( unionGeometry && GEOSGeomTypeId_r( geosinit()->ctxt, unionGeometry.get() ) == GEOS_MULTILINESTRING )
1573 geos::unique_ptr mergedLines( GEOSLineMerge_r( geosinit()->ctxt, unionGeometry.get() ) );
1576 unionGeometry = std::move( mergedLines );
1580 opGeom = std::move( unionGeometry );
1584 case OverlaySymDifference:
1585 opGeom.reset( GEOSSymDifference_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) );
1590 catch ( GEOSException &e )
1592 logError( QStringLiteral(
"GEOS" ), e.what() );
1595 *errorMsg = e.what();
1601 bool QgsGeos::relation(
const QgsAbstractGeometry *geom, Relation r, QString *errorMsg )
const
1603 if ( !mGeos || !geom )
1614 bool result =
false;
1617 if ( mGeosPrepared )
1621 case RelationIntersects:
1622 result = ( GEOSPreparedIntersects_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1624 case RelationTouches:
1625 result = ( GEOSPreparedTouches_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1627 case RelationCrosses:
1628 result = ( GEOSPreparedCrosses_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1630 case RelationWithin:
1631 result = ( GEOSPreparedWithin_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1633 case RelationContains:
1634 result = ( GEOSPreparedContains_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1636 case RelationDisjoint:
1637 result = ( GEOSPreparedDisjoint_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1639 case RelationOverlaps:
1640 result = ( GEOSPreparedOverlaps_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1648 case RelationIntersects:
1649 result = ( GEOSIntersects_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1651 case RelationTouches:
1652 result = ( GEOSTouches_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1654 case RelationCrosses:
1655 result = ( GEOSCrosses_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1657 case RelationWithin:
1658 result = ( GEOSWithin_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1660 case RelationContains:
1661 result = ( GEOSContains_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1663 case RelationDisjoint:
1664 result = ( GEOSDisjoint_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1666 case RelationOverlaps:
1667 result = ( GEOSOverlaps_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1671 catch ( GEOSException &e )
1673 logError( QStringLiteral(
"GEOS" ), e.what() );
1676 *errorMsg = e.what();
1694 geos.reset( GEOSBuffer_r( geosinit()->ctxt, mGeos.get(),
distance, segments ) );
1710 geos.reset( GEOSBufferWithStyle_r( geosinit()->ctxt, mGeos.get(),
distance, segments,
static_cast< int >( endCapStyle ),
static_cast< int >( joinStyle ), miterLimit ) );
1725 geos.reset( GEOSTopologyPreserveSimplify_r( geosinit()->ctxt, mGeos.get(), tolerance ) );
1740 geos.reset( GEOSInterpolate_r( geosinit()->ctxt, mGeos.get(),
distance ) );
1759 geos.reset( GEOSGetCentroid_r( geosinit()->ctxt, mGeos.get() ) );
1764 GEOSGeomGetX_r( geosinit()->ctxt,
geos.get(), &x );
1765 GEOSGeomGetY_r( geosinit()->ctxt,
geos.get(), &y );
1781 geos.reset( GEOSEnvelope_r( geosinit()->ctxt, mGeos.get() ) );
1800 geos.reset( GEOSPointOnSurface_r( geosinit()->ctxt, mGeos.get() ) );
1802 if ( !
geos || GEOSisEmpty_r( geosinit()->ctxt,
geos.get() ) != 0 )
1807 GEOSGeomGetX_r( geosinit()->ctxt,
geos.get(), &x );
1808 GEOSGeomGetY_r( geosinit()->ctxt,
geos.get(), &y );
1824 geos::unique_ptr cHull( GEOSConvexHull_r( geosinit()->ctxt, mGeos.get() ) );
1825 std::unique_ptr< QgsAbstractGeometry > cHullGeom =
fromGeos( cHull.get() );
1826 return cHullGeom.release();
1840 GEOSGeometry *g1 =
nullptr;
1842 char res = GEOSisValidDetail_r( geosinit()->ctxt, mGeos.get(), allowSelfTouchingHoles ? GEOSVALID_ALLOW_SELFTOUCHING_RING_FORMING_HOLE : 0, &r, &g1 );
1843 const bool invalid = res != 1;
1848 error = QString( r );
1849 GEOSFree_r( geosinit()->ctxt, r );
1852 if ( invalid && errorMsg )
1856 if ( translatedErrors.empty() )
1859 translatedErrors.insert( QStringLiteral(
"topology validation error" ), QObject::tr(
"Topology validation error",
"GEOS Error" ) );
1860 translatedErrors.insert( QStringLiteral(
"repeated point" ), QObject::tr(
"Repeated point",
"GEOS Error" ) );
1861 translatedErrors.insert( QStringLiteral(
"hole lies outside shell" ), QObject::tr(
"Hole lies outside shell",
"GEOS Error" ) );
1862 translatedErrors.insert( QStringLiteral(
"holes are nested" ), QObject::tr(
"Holes are nested",
"GEOS Error" ) );
1863 translatedErrors.insert( QStringLiteral(
"interior is disconnected" ), QObject::tr(
"Interior is disconnected",
"GEOS Error" ) );
1864 translatedErrors.insert( QStringLiteral(
"self-intersection" ), QObject::tr(
"Self-intersection",
"GEOS Error" ) );
1865 translatedErrors.insert( QStringLiteral(
"ring self-intersection" ), QObject::tr(
"Ring self-intersection",
"GEOS Error" ) );
1866 translatedErrors.insert( QStringLiteral(
"nested shells" ), QObject::tr(
"Nested shells",
"GEOS Error" ) );
1867 translatedErrors.insert( QStringLiteral(
"duplicate rings" ), QObject::tr(
"Duplicate rings",
"GEOS Error" ) );
1868 translatedErrors.insert( QStringLiteral(
"too few points in geometry component" ), QObject::tr(
"Too few points in geometry component",
"GEOS Error" ) );
1869 translatedErrors.insert( QStringLiteral(
"invalid coordinate" ), QObject::tr(
"Invalid coordinate",
"GEOS Error" ) );
1870 translatedErrors.insert( QStringLiteral(
"ring is not closed" ), QObject::tr(
"Ring is not closed",
"GEOS Error" ) );
1873 *errorMsg = translatedErrors.value( error.toLower(), error );
1875 if ( g1 && errorLoc )
1881 GEOSGeom_destroy_r( geosinit()->ctxt, g1 );
1891 if ( !mGeos || !geom )
1903 bool equal = GEOSEquals_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() );
1918 return GEOSisEmpty_r( geosinit()->ctxt, mGeos.get() );
1932 return GEOSisSimple_r( geosinit()->ctxt, mGeos.get() );
1937 GEOSCoordSequence *QgsGeos::createCoordinateSequence(
const QgsCurve *curve,
double precision,
bool forceClose )
1939 std::unique_ptr< QgsLineString > segmentized;
1940 const QgsLineString *line = qgsgeometry_cast<const QgsLineString *>( curve );
1945 line = segmentized.get();
1953 bool hasZ = line->
is3D();
1967 int numOutPoints = numPoints;
1968 if ( forceClose && ( line->
pointN( 0 ) != line->
pointN( numPoints - 1 ) ) )
1973 GEOSCoordSequence *coordSeq =
nullptr;
1976 coordSeq = GEOSCoordSeq_create_r( geosinit()->ctxt, numOutPoints, coordDims );
1979 QgsDebugMsg( QStringLiteral(
"GEOS Exception: Could not create coordinate sequence for %1 points in %2 dimensions" ).arg( numPoints ).arg( coordDims ) );
1983 const double *xData = line->
xData();
1984 const double *yData = line->
yData();
1985 const double *zData = hasZ ? line->
zData() :
nullptr;
1986 const double *mData = hasM ? line->
mData() :
nullptr;
1990 for (
int i = 0; i < numOutPoints; ++i )
1992 if ( i >= numPoints )
1995 xData = line->
xData();
1996 yData = line->
yData();
1997 zData = hasZ ? line->
zData() :
nullptr;
1998 mData = hasM ? line->
mData() :
nullptr;
2000 #if GEOS_VERSION_MAJOR>3 || GEOS_VERSION_MINOR>=8
2010 GEOSCoordSeq_setX_r( geosinit()->ctxt, coordSeq, i, std::round( *xData++ /
precision ) *
precision );
2011 GEOSCoordSeq_setY_r( geosinit()->ctxt, coordSeq, i, std::round( *yData++ /
precision ) *
precision );
2014 GEOSCoordSeq_setOrdinate_r( geosinit()->ctxt, coordSeq, i, 2, std::round( *zData++ /
precision ) *
precision );
2019 GEOSCoordSeq_setOrdinate_r( geosinit()->ctxt, coordSeq, i, 3, line->
mAt( *mData++ ) );
2025 for (
int i = 0; i < numOutPoints; ++i )
2027 if ( i >= numPoints )
2030 xData = line->
xData();
2031 yData = line->
yData();
2032 zData = hasZ ? line->
zData() :
nullptr;
2033 mData = hasM ? line->
mData() :
nullptr;
2035 #if GEOS_VERSION_MAJOR>3 || GEOS_VERSION_MINOR>=8
2038 GEOSCoordSeq_setXYZ_r( geosinit()->ctxt, coordSeq, i, *xData++, *yData++, *zData++ );
2042 GEOSCoordSeq_setXY_r( geosinit()->ctxt, coordSeq, i, *xData++, *yData++ );
2045 GEOSCoordSeq_setX_r( geosinit()->ctxt, coordSeq, i, *xData++ );
2046 GEOSCoordSeq_setY_r( geosinit()->ctxt, coordSeq, i, *yData++ );
2049 GEOSCoordSeq_setOrdinate_r( geosinit()->ctxt, coordSeq, i, 2, *zData++ );
2054 GEOSCoordSeq_setOrdinate_r( geosinit()->ctxt, coordSeq, i, 3, *mData++ );
2066 const QgsPoint *pt = qgsgeometry_cast<const QgsPoint *>( point );
2073 geos::unique_ptr QgsGeos::createGeosPointXY(
double x,
double y,
bool hasZ,
double z,
bool hasM,
double m,
int coordDims,
double precision )
2081 #if GEOS_VERSION_MAJOR>3 || GEOS_VERSION_MINOR>=8
2082 if ( coordDims == 2 )
2088 geosPoint.reset( GEOSGeom_createPointFromXY_r( geosinit()->ctxt, x, y ) );
2093 GEOSCoordSequence *coordSeq = GEOSCoordSeq_create_r( geosinit()->ctxt, 1, coordDims );
2096 QgsDebugMsg( QStringLiteral(
"GEOS Exception: Could not create coordinate sequence for point with %1 dimensions" ).arg( coordDims ) );
2101 GEOSCoordSeq_setX_r( geosinit()->ctxt, coordSeq, 0, std::round( x /
precision ) *
precision );
2102 GEOSCoordSeq_setY_r( geosinit()->ctxt, coordSeq, 0, std::round( y /
precision ) *
precision );
2105 GEOSCoordSeq_setOrdinate_r( geosinit()->ctxt, coordSeq, 0, 2, std::round( z /
precision ) *
precision );
2110 GEOSCoordSeq_setX_r( geosinit()->ctxt, coordSeq, 0, x );
2111 GEOSCoordSeq_setY_r( geosinit()->ctxt, coordSeq, 0, y );
2114 GEOSCoordSeq_setOrdinate_r( geosinit()->ctxt, coordSeq, 0, 2, z );
2120 GEOSCoordSeq_setOrdinate_r( geosinit()->ctxt, coordSeq, 0, 3, m );
2123 geosPoint.reset( GEOSGeom_createPoint_r( geosinit()->ctxt, coordSeq ) );
2131 const QgsCurve *
c = qgsgeometry_cast<const QgsCurve *>( curve );
2135 GEOSCoordSequence *coordSeq = createCoordinateSequence(
c,
precision );
2142 geosGeom.reset( GEOSGeom_createLineString_r( geosinit()->ctxt, coordSeq ) );
2150 const QgsCurvePolygon *polygon = qgsgeometry_cast<const QgsCurvePolygon *>( poly );
2155 if ( !exteriorRing )
2163 geos::unique_ptr exteriorRingGeos( GEOSGeom_createLinearRing_r( geosinit()->ctxt, createCoordinateSequence( exteriorRing,
precision,
true ) ) );
2166 GEOSGeometry **holes =
nullptr;
2169 holes =
new GEOSGeometry*[ nHoles ];
2172 for (
int i = 0; i < nHoles; ++i )
2175 holes[i] = GEOSGeom_createLinearRing_r( geosinit()->ctxt, createCoordinateSequence( interiorRing,
precision,
true ) );
2177 geosPolygon.reset( GEOSGeom_createPolygon_r( geosinit()->ctxt, exteriorRingGeos.release(), holes, nHoles ) );
2193 offset.reset( GEOSOffsetCurve_r( geosinit()->ctxt, mGeos.get(),
distance, segments,
static_cast< int >( joinStyle ), miterLimit ) );
2196 std::unique_ptr< QgsAbstractGeometry > offsetGeom =
fromGeos( offset.get() );
2197 return offsetGeom.release();
2211 GEOSBufferParams_setSingleSided_r( geosinit()->ctxt, bp.get(), 1 );
2212 GEOSBufferParams_setQuadrantSegments_r( geosinit()->ctxt, bp.get(), segments );
2213 GEOSBufferParams_setJoinStyle_r( geosinit()->ctxt, bp.get(),
static_cast< int >( joinStyle ) );
2214 GEOSBufferParams_setMitreLimit_r( geosinit()->ctxt, bp.get(), miterLimit );
2216 if ( side == Qgis::BufferSide::Right )
2220 geos.reset( GEOSBufferWithParams_r( geosinit()->ctxt, mGeos.get(), bp.get(),
distance ) );
2228 #if GEOS_VERSION_MAJOR==3 && GEOS_VERSION_MINOR<9
2231 throw QgsNotSupportedException( QStringLiteral(
"Calculating maximumInscribedCircle requires a QGIS build based on GEOS 3.9 or later" ) );
2241 geos.reset( GEOSMaximumInscribedCircle_r( geosinit()->ctxt, mGeos.get(), tolerance ) );
2250 #if GEOS_VERSION_MAJOR==3 && GEOS_VERSION_MINOR<9
2254 throw QgsNotSupportedException( QStringLiteral(
"Calculating largestEmptyCircle requires a QGIS build based on GEOS 3.9 or later" ) );
2266 boundaryGeos =
asGeos( boundary );
2268 geos.reset( GEOSLargestEmptyCircle_r( geosinit()->ctxt, mGeos.get(), boundaryGeos.get(), tolerance ) );
2277 #if GEOS_VERSION_MAJOR==3 && GEOS_VERSION_MINOR<6
2279 throw QgsNotSupportedException( QStringLiteral(
"Calculating minimumWidth requires a QGIS build based on GEOS 3.6 or later" ) );
2289 geos.reset( GEOSMinimumWidth_r( geosinit()->ctxt, mGeos.get() ) );
2298 #if GEOS_VERSION_MAJOR==3 && GEOS_VERSION_MINOR<6
2300 throw QgsNotSupportedException( QStringLiteral(
"Calculating minimumClearance requires a QGIS build based on GEOS 3.6 or later" ) );
2304 return std::numeric_limits< double >::quiet_NaN();
2311 if ( GEOSMinimumClearance_r( geosinit()->ctxt, mGeos.get(), &res ) != 0 )
2312 return std::numeric_limits< double >::quiet_NaN();
2321 #if GEOS_VERSION_MAJOR==3 && GEOS_VERSION_MINOR<6
2323 throw QgsNotSupportedException( QStringLiteral(
"Calculating minimumClearanceLine requires a QGIS build based on GEOS 3.6 or later" ) );
2333 geos.reset( GEOSMinimumClearanceLine_r( geosinit()->ctxt, mGeos.get() ) );
2350 geos.reset( GEOSNode_r( geosinit()->ctxt, mGeos.get() ) );
2358 if ( !mGeos || !other )
2370 geos.reset( GEOSSharedPaths_r( geosinit()->ctxt, mGeos.get(), otherGeos.get() ) );
2390 geos::unique_ptr reshapeLineGeos = createGeosLinestring( &reshapeWithLine, mPrecision );
2393 int numGeoms = GEOSGetNumGeometries_r( geosinit()->ctxt, mGeos.get() );
2394 if ( numGeoms == -1 )
2403 bool isMultiGeom =
false;
2404 int geosTypeId = GEOSGeomTypeId_r( geosinit()->ctxt, mGeos.get() );
2405 if ( geosTypeId == GEOS_MULTILINESTRING || geosTypeId == GEOS_MULTIPOLYGON )
2415 reshapedGeometry = reshapeLine( mGeos.get(), reshapeLineGeos.get(), mPrecision );
2419 reshapedGeometry = reshapePolygon( mGeos.get(), reshapeLineGeos.get(), mPrecision );
2424 std::unique_ptr< QgsAbstractGeometry > reshapeResult =
fromGeos( reshapedGeometry.get() );
2425 return reshapeResult;
2432 bool reshapeTookPlace =
false;
2435 GEOSGeometry **newGeoms =
new GEOSGeometry*[numGeoms];
2437 for (
int i = 0; i < numGeoms; ++i )
2440 currentReshapeGeometry = reshapeLine( GEOSGetGeometryN_r( geosinit()->ctxt, mGeos.get(), i ), reshapeLineGeos.get(), mPrecision );
2442 currentReshapeGeometry = reshapePolygon( GEOSGetGeometryN_r( geosinit()->ctxt, mGeos.get(), i ), reshapeLineGeos.get(), mPrecision );
2444 if ( currentReshapeGeometry )
2446 newGeoms[i] = currentReshapeGeometry.release();
2447 reshapeTookPlace =
true;
2451 newGeoms[i] = GEOSGeom_clone_r( geosinit()->ctxt, GEOSGetGeometryN_r( geosinit()->ctxt, mGeos.get(), i ) );
2458 newMultiGeom.reset( GEOSGeom_createCollection_r( geosinit()->ctxt, GEOS_MULTILINESTRING, newGeoms, numGeoms ) );
2462 newMultiGeom.reset( GEOSGeom_createCollection_r( geosinit()->ctxt, GEOS_MULTIPOLYGON, newGeoms, numGeoms ) );
2466 if ( !newMultiGeom )
2472 if ( reshapeTookPlace )
2476 std::unique_ptr< QgsAbstractGeometry > reshapedMultiGeom =
fromGeos( newMultiGeom.get() );
2477 return reshapedMultiGeom;
2499 if ( GEOSGeomTypeId_r( geosinit()->ctxt, mGeos.get() ) != GEOS_MULTILINESTRING )
2505 geos.reset( GEOSLineMerge_r( geosinit()->ctxt, mGeos.get() ) );
2528 #if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=9 )
2530 if ( mGeosPrepared )
2532 nearestCoord.reset( GEOSPreparedNearestPoints_r( geosinit()->ctxt, mGeosPrepared.get(), otherGeom.get() ) );
2536 nearestCoord.reset( GEOSNearestPoints_r( geosinit()->ctxt, mGeos.get(), otherGeom.get() ) );
2542 ( void )GEOSCoordSeq_getX_r( geosinit()->ctxt, nearestCoord.get(), 0, &nx );
2543 ( void )GEOSCoordSeq_getY_r( geosinit()->ctxt, nearestCoord.get(), 0, &ny );
2545 catch ( GEOSException &e )
2547 logError( QStringLiteral(
"GEOS" ), e.what() );
2550 *errorMsg = e.what();
2560 if ( !mGeos || other.
isEmpty() )
2570 if ( !other || other->
isEmpty() )
2587 if ( !nearestCoord )
2590 *errorMsg = QStringLiteral(
"GEOS returned no nearest points" );
2594 ( void )GEOSCoordSeq_getX_r( geosinit()->ctxt, nearestCoord.get(), 0, &nx1 );
2595 ( void )GEOSCoordSeq_getY_r( geosinit()->ctxt, nearestCoord.get(), 0, &ny1 );
2596 ( void )GEOSCoordSeq_getX_r( geosinit()->ctxt, nearestCoord.get(), 1, &nx2 );
2597 ( void )GEOSCoordSeq_getY_r( geosinit()->ctxt, nearestCoord.get(), 1, &ny2 );
2599 catch ( GEOSException &e )
2601 logError( QStringLiteral(
"GEOS" ), e.what() );
2604 *errorMsg = e.what();
2631 distance = GEOSProject_r( geosinit()->ctxt, mGeos.get(), otherGeom.get() );
2633 catch ( GEOSException &e )
2635 logError( QStringLiteral(
"GEOS" ), e.what() );
2638 *errorMsg = e.what();
2648 GEOSGeometry **
const lineGeosGeometries =
new GEOSGeometry*[ geometries.size()];
2655 lineGeosGeometries[validLines] = l.release();
2662 geos::unique_ptr result( GEOSPolygonize_r( geosinit()->ctxt, lineGeosGeometries, validLines ) );
2663 for (
int i = 0; i < validLines; ++i )
2665 GEOSGeom_destroy_r( geosinit()->ctxt, lineGeosGeometries[i] );
2667 delete[] lineGeosGeometries;
2670 catch ( GEOSException &e )
2674 *errorMsg = e.what();
2676 for (
int i = 0; i < validLines; ++i )
2678 GEOSGeom_destroy_r( geosinit()->ctxt, lineGeosGeometries[i] );
2680 delete[] lineGeosGeometries;
2695 extentGeosGeom =
asGeos( extent, mPrecision );
2696 if ( !extentGeosGeom )
2705 geos.reset( GEOSVoronoiDiagram_r( geosinit()->ctxt, mGeos.get(), extentGeosGeom.get(), tolerance, edgesOnly ) );
2707 if ( !
geos || GEOSisEmpty_r( geosinit()->ctxt,
geos.get() ) != 0 )
2727 geos.reset( GEOSDelaunayTriangulation_r( geosinit()->ctxt, mGeos.get(), tolerance, edgesOnly ) );
2729 if ( !
geos || GEOSisEmpty_r( geosinit()->ctxt,
geos.get() ) != 0 )
2741 static bool _linestringEndpoints(
const GEOSGeometry *linestring,
double &x1,
double &y1,
double &x2,
double &y2 )
2743 const GEOSCoordSequence *coordSeq = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, linestring );
2747 unsigned int coordSeqSize;
2748 if ( GEOSCoordSeq_getSize_r( geosinit()->ctxt, coordSeq, &coordSeqSize ) == 0 )
2751 if ( coordSeqSize < 2 )
2754 GEOSCoordSeq_getX_r( geosinit()->ctxt, coordSeq, 0, &x1 );
2755 GEOSCoordSeq_getY_r( geosinit()->ctxt, coordSeq, 0, &y1 );
2756 GEOSCoordSeq_getX_r( geosinit()->ctxt, coordSeq, coordSeqSize - 1, &x2 );
2757 GEOSCoordSeq_getY_r( geosinit()->ctxt, coordSeq, coordSeqSize - 1, &y2 );
2763 static geos::unique_ptr _mergeLinestrings(
const GEOSGeometry *line1,
const GEOSGeometry *line2,
const QgsPointXY &intersectionPoint )
2765 double x1, y1, x2, y2;
2766 if ( !_linestringEndpoints( line1, x1, y1, x2, y2 ) )
2769 double rx1, ry1, rx2, ry2;
2770 if ( !_linestringEndpoints( line2, rx1, ry1, rx2, ry2 ) )
2773 bool intersectionAtOrigLineEndpoint =
2774 ( intersectionPoint.
x() == x1 && intersectionPoint.
y() == y1 ) !=
2775 ( intersectionPoint.
x() == x2 && intersectionPoint.
y() == y2 );
2776 bool intersectionAtReshapeLineEndpoint =
2777 ( intersectionPoint.
x() == rx1 && intersectionPoint.
y() == ry1 ) ||
2778 ( intersectionPoint.
x() == rx2 && intersectionPoint.
y() == ry2 );
2781 if ( intersectionAtOrigLineEndpoint && intersectionAtReshapeLineEndpoint )
2785 GEOSGeometry *geoms[2] = { g1.release(), g2.release() };
2786 geos::unique_ptr multiGeom( GEOSGeom_createCollection_r( geosinit()->ctxt, GEOS_MULTILINESTRING, geoms, 2 ) );
2787 geos::unique_ptr res( GEOSLineMerge_r( geosinit()->ctxt, multiGeom.get() ) );
2795 geos::unique_ptr QgsGeos::reshapeLine(
const GEOSGeometry *line,
const GEOSGeometry *reshapeLineGeos,
double precision )
2797 if ( !line || !reshapeLineGeos )
2800 bool atLeastTwoIntersections =
false;
2801 bool oneIntersection =
false;
2807 geos::unique_ptr intersectGeom( GEOSIntersection_r( geosinit()->ctxt, line, reshapeLineGeos ) );
2808 if ( intersectGeom )
2810 const int geomType = GEOSGeomTypeId_r( geosinit()->ctxt, intersectGeom.get() );
2811 atLeastTwoIntersections = ( geomType == GEOS_MULTIPOINT && GEOSGetNumGeometries_r( geosinit()->ctxt, intersectGeom.get() ) > 1 )
2812 || ( geomType == GEOS_GEOMETRYCOLLECTION && GEOSGetNumGeometries_r( geosinit()->ctxt, intersectGeom.get() ) > 0 )
2813 || ( geomType == GEOS_MULTILINESTRING && GEOSGetNumGeometries_r( geosinit()->ctxt, intersectGeom.get() ) > 0 );
2815 if ( GEOSGeomTypeId_r( geosinit()->ctxt, intersectGeom.get() ) == GEOS_POINT )
2817 const GEOSCoordSequence *intersectionCoordSeq = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, intersectGeom.get() );
2819 GEOSCoordSeq_getX_r( geosinit()->ctxt, intersectionCoordSeq, 0, &xi );
2820 GEOSCoordSeq_getY_r( geosinit()->ctxt, intersectionCoordSeq, 0, &yi );
2821 oneIntersection =
true;
2826 catch ( GEOSException & )
2828 atLeastTwoIntersections =
false;
2832 if ( oneIntersection )
2833 return _mergeLinestrings( line, reshapeLineGeos, oneIntersectionPoint );
2835 if ( !atLeastTwoIntersections )
2839 double x1, y1, x2, y2;
2840 if ( !_linestringEndpoints( line, x1, y1, x2, y2 ) )
2846 bool isRing =
false;
2847 if ( GEOSGeomTypeId_r( geosinit()->ctxt, line ) == GEOS_LINEARRING
2848 || GEOSEquals_r( geosinit()->ctxt, beginLineVertex.get(), endLineVertex.get() ) == 1 )
2853 if ( !nodedGeometry )
2859 geos::unique_ptr mergedLines( GEOSLineMerge_r( geosinit()->ctxt, nodedGeometry.get() ) );
2865 int numMergedLines = GEOSGetNumGeometries_r( geosinit()->ctxt, mergedLines.get() );
2866 if ( numMergedLines < 2 )
2868 if ( numMergedLines == 1 )
2870 geos::unique_ptr result( GEOSGeom_clone_r( geosinit()->ctxt, reshapeLineGeos ) );
2877 QVector<GEOSGeometry *> resultLineParts;
2878 QVector<GEOSGeometry *> probableParts;
2880 for (
int i = 0; i < numMergedLines; ++i )
2882 const GEOSGeometry *currentGeom = GEOSGetGeometryN_r( geosinit()->ctxt, mergedLines.get(), i );
2885 bool alreadyAdded =
false;
2887 double bufferDistance = std::pow( 10.0L, geomDigits( currentGeom ) - 11 );
2888 for (
const GEOSGeometry *other : std::as_const( resultLineParts ) )
2890 GEOSHausdorffDistance_r( geosinit()->ctxt, currentGeom, other, &
distance );
2893 alreadyAdded =
true;
2900 const GEOSCoordSequence *currentCoordSeq = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, currentGeom );
2901 unsigned int currentCoordSeqSize;
2902 GEOSCoordSeq_getSize_r( geosinit()->ctxt, currentCoordSeq, ¤tCoordSeqSize );
2903 if ( currentCoordSeqSize < 2 )
2907 double xBegin, xEnd, yBegin, yEnd;
2908 GEOSCoordSeq_getX_r( geosinit()->ctxt, currentCoordSeq, 0, &xBegin );
2909 GEOSCoordSeq_getY_r( geosinit()->ctxt, currentCoordSeq, 0, &yBegin );
2910 GEOSCoordSeq_getX_r( geosinit()->ctxt, currentCoordSeq, currentCoordSeqSize - 1, &xEnd );
2911 GEOSCoordSeq_getY_r( geosinit()->ctxt, currentCoordSeq, currentCoordSeqSize - 1, &yEnd );
2916 int nEndpointsOnOriginalLine = 0;
2917 if ( pointContainedInLine( beginCurrentGeomVertex.get(), line ) == 1 )
2918 nEndpointsOnOriginalLine += 1;
2920 if ( pointContainedInLine( endCurrentGeomVertex.get(), line ) == 1 )
2921 nEndpointsOnOriginalLine += 1;
2924 int nEndpointsSameAsOriginalLine = 0;
2925 if ( GEOSEquals_r( geosinit()->ctxt, beginCurrentGeomVertex.get(), beginLineVertex.get() ) == 1
2926 || GEOSEquals_r( geosinit()->ctxt, beginCurrentGeomVertex.get(), endLineVertex.get() ) == 1 )
2927 nEndpointsSameAsOriginalLine += 1;
2929 if ( GEOSEquals_r( geosinit()->ctxt, endCurrentGeomVertex.get(), beginLineVertex.get() ) == 1
2930 || GEOSEquals_r( geosinit()->ctxt, endCurrentGeomVertex.get(), endLineVertex.get() ) == 1 )
2931 nEndpointsSameAsOriginalLine += 1;
2934 bool currentGeomOverlapsOriginalGeom =
false;
2935 bool currentGeomOverlapsReshapeLine =
false;
2936 if ( lineContainedInLine( currentGeom, line ) == 1 )
2937 currentGeomOverlapsOriginalGeom =
true;
2939 if ( lineContainedInLine( currentGeom, reshapeLineGeos ) == 1 )
2940 currentGeomOverlapsReshapeLine =
true;
2943 if ( !isRing && nEndpointsSameAsOriginalLine == 1 && nEndpointsOnOriginalLine == 2 && currentGeomOverlapsOriginalGeom )
2945 resultLineParts.push_back( GEOSGeom_clone_r( geosinit()->ctxt, currentGeom ) );
2948 else if ( isRing && nEndpointsOnOriginalLine == 2 && currentGeomOverlapsOriginalGeom )
2950 probableParts.push_back( GEOSGeom_clone_r( geosinit()->ctxt, currentGeom ) );
2952 else if ( nEndpointsOnOriginalLine == 2 && !currentGeomOverlapsOriginalGeom )
2954 resultLineParts.push_back( GEOSGeom_clone_r( geosinit()->ctxt, currentGeom ) );
2956 else if ( nEndpointsSameAsOriginalLine == 2 && !currentGeomOverlapsOriginalGeom )
2958 resultLineParts.push_back( GEOSGeom_clone_r( geosinit()->ctxt, currentGeom ) );
2960 else if ( currentGeomOverlapsOriginalGeom && currentGeomOverlapsReshapeLine )
2962 resultLineParts.push_back( GEOSGeom_clone_r( geosinit()->ctxt, currentGeom ) );
2967 if ( isRing && !probableParts.isEmpty() )
2970 GEOSGeometry *currentGeom =
nullptr;
2971 double maxLength = -std::numeric_limits<double>::max();
2972 double currentLength = 0;
2973 for (
int i = 0; i < probableParts.size(); ++i )
2975 currentGeom = probableParts.at( i );
2976 GEOSLength_r( geosinit()->ctxt, currentGeom, ¤tLength );
2977 if ( currentLength > maxLength )
2979 maxLength = currentLength;
2980 maxGeom.reset( currentGeom );
2984 GEOSGeom_destroy_r( geosinit()->ctxt, currentGeom );
2987 resultLineParts.push_back( maxGeom.release() );
2991 if ( resultLineParts.empty() )
2994 if ( resultLineParts.size() == 1 )
2996 result.reset( resultLineParts[0] );
3000 GEOSGeometry **lineArray =
new GEOSGeometry*[resultLineParts.size()];
3001 for (
int i = 0; i < resultLineParts.size(); ++i )
3003 lineArray[i] = resultLineParts[i];
3007 geos::unique_ptr multiLineGeom( GEOSGeom_createCollection_r( geosinit()->ctxt, GEOS_MULTILINESTRING, lineArray, resultLineParts.size() ) );
3008 delete [] lineArray;
3011 result.reset( GEOSLineMerge_r( geosinit()->ctxt, multiLineGeom.get() ) );
3015 if ( GEOSGeomTypeId_r( geosinit()->ctxt, result.get() ) != GEOS_LINESTRING )
3023 geos::unique_ptr QgsGeos::reshapePolygon(
const GEOSGeometry *polygon,
const GEOSGeometry *reshapeLineGeos,
double precision )
3026 int nIntersections = 0;
3027 int lastIntersectingRing = -2;
3028 const GEOSGeometry *lastIntersectingGeom =
nullptr;
3030 int nRings = GEOSGetNumInteriorRings_r( geosinit()->ctxt, polygon );
3035 const GEOSGeometry *outerRing = GEOSGetExteriorRing_r( geosinit()->ctxt, polygon );
3036 if ( GEOSIntersects_r( geosinit()->ctxt, outerRing, reshapeLineGeos ) == 1 )
3039 lastIntersectingRing = -1;
3040 lastIntersectingGeom = outerRing;
3044 const GEOSGeometry **innerRings =
new const GEOSGeometry*[nRings];
3048 for (
int i = 0; i < nRings; ++i )
3050 innerRings[i] = GEOSGetInteriorRingN_r( geosinit()->ctxt, polygon, i );
3051 if ( GEOSIntersects_r( geosinit()->ctxt, innerRings[i], reshapeLineGeos ) == 1 )
3054 lastIntersectingRing = i;
3055 lastIntersectingGeom = innerRings[i];
3059 catch ( GEOSException & )
3064 if ( nIntersections != 1 )
3066 delete [] innerRings;
3072 if ( !reshapeResult )
3074 delete [] innerRings;
3079 GEOSGeometry *newRing =
nullptr;
3080 const GEOSCoordSequence *reshapeSequence = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, reshapeResult.get() );
3081 GEOSCoordSequence *newCoordSequence = GEOSCoordSeq_clone_r( geosinit()->ctxt, reshapeSequence );
3083 reshapeResult.reset();
3085 newRing = GEOSGeom_createLinearRing_r( geosinit()->ctxt, newCoordSequence );
3088 delete [] innerRings;
3092 GEOSGeometry *newOuterRing =
nullptr;
3093 if ( lastIntersectingRing == -1 )
3094 newOuterRing = newRing;
3096 newOuterRing = GEOSGeom_clone_r( geosinit()->ctxt, outerRing );
3099 QVector<GEOSGeometry *> ringList;
3102 GEOSGeometry *outerRingPoly = GEOSGeom_createPolygon_r( geosinit()->ctxt, GEOSGeom_clone_r( geosinit()->ctxt, newOuterRing ),
nullptr, 0 );
3103 if ( outerRingPoly )
3105 ringList.reserve( nRings );
3106 GEOSGeometry *currentRing =
nullptr;
3107 for (
int i = 0; i < nRings; ++i )
3109 if ( lastIntersectingRing == i )
3110 currentRing = newRing;
3112 currentRing = GEOSGeom_clone_r( geosinit()->ctxt, innerRings[i] );
3115 if ( GEOSContains_r( geosinit()->ctxt, outerRingPoly, currentRing ) == 1 )
3116 ringList.push_back( currentRing );
3118 GEOSGeom_destroy_r( geosinit()->ctxt, currentRing );
3121 GEOSGeom_destroy_r( geosinit()->ctxt, outerRingPoly );
3124 GEOSGeometry **newInnerRings =
new GEOSGeometry*[ringList.size()];
3125 for (
int i = 0; i < ringList.size(); ++i )
3126 newInnerRings[i] = ringList.at( i );
3128 delete [] innerRings;
3130 geos::unique_ptr reshapedPolygon( GEOSGeom_createPolygon_r( geosinit()->ctxt, newOuterRing, newInnerRings, ringList.size() ) );
3131 delete[] newInnerRings;
3133 return reshapedPolygon;
3136 int QgsGeos::lineContainedInLine(
const GEOSGeometry *line1,
const GEOSGeometry *line2 )
3138 if ( !line1 || !line2 )
3143 double bufferDistance = std::pow( 10.0L, geomDigits( line2 ) - 11 );
3149 geos::unique_ptr intersectionGeom( GEOSIntersection_r( geosinit()->ctxt, bufferGeom.get(), line1 ) );
3152 double intersectGeomLength;
3155 GEOSLength_r( geosinit()->ctxt, intersectionGeom.get(), &intersectGeomLength );
3156 GEOSLength_r( geosinit()->ctxt, line1, &line1Length );
3158 double intersectRatio = line1Length / intersectGeomLength;
3159 if ( intersectRatio > 0.9 && intersectRatio < 1.1 )
3165 int QgsGeos::pointContainedInLine(
const GEOSGeometry *point,
const GEOSGeometry *line )
3167 if ( !point || !line )
3170 double bufferDistance = std::pow( 10.0L, geomDigits( line ) - 11 );
3172 geos::unique_ptr lineBuffer( GEOSBuffer_r( geosinit()->ctxt, line, bufferDistance, 8 ) );
3176 bool contained =
false;
3177 if ( GEOSContains_r( geosinit()->ctxt, lineBuffer.get(), point ) == 1 )
3183 int QgsGeos::geomDigits(
const GEOSGeometry *geom )
3189 const GEOSGeometry *bBoxRing = GEOSGetExteriorRing_r( geosinit()->ctxt, bbox.get() );
3193 const GEOSCoordSequence *bBoxCoordSeq = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, bBoxRing );
3195 if ( !bBoxCoordSeq )
3198 unsigned int nCoords = 0;
3199 if ( !GEOSCoordSeq_getSize_r( geosinit()->ctxt, bBoxCoordSeq, &nCoords ) )
3203 for (
unsigned int i = 0; i < nCoords - 1; ++i )
3206 GEOSCoordSeq_getX_r( geosinit()->ctxt, bBoxCoordSeq, i, &t );
3209 digits = std::ceil( std::log10( std::fabs( t ) ) );
3210 if ( digits > maxDigits )
3213 GEOSCoordSeq_getY_r( geosinit()->ctxt, bBoxCoordSeq, i, &t );
3214 digits = std::ceil( std::log10( std::fabs( t ) ) );
3215 if ( digits > maxDigits )
3224 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.
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 QgsAbstractGeometry * clone() const =0
Clones the geometry by performing a deep copy.
virtual bool isEmpty() const
Returns true if the geometry is empty.
QgsWkbTypes::Type wkbType() const SIP_HOLDGIL
Returns the WKB type of the geometry.
virtual int dimension() const =0
Returns the inherent dimension of the geometry.
bool isMeasure() const SIP_HOLDGIL
Returns true if the geometry contains m values.
Curve polygon geometry type.
const QgsCurve * interiorRing(int i) const SIP_HOLDGIL
Retrieves an interior ring from the curve polygon.
const QgsCurve * exteriorRing() const SIP_HOLDGIL
Returns the curve polygon's exterior ring.
int numInteriorRings() const SIP_HOLDGIL
Returns the number of interior rings contained with the curve polygon.
Abstract base class for curved geometry type.
virtual QgsLineString * curveToLine(double tolerance=M_PI_2/90, SegmentationToleranceType toleranceType=MaximumAngle) const =0
Returns a new line string geometry corresponding to a segmentized approximation of the curve.
virtual bool addGeometry(QgsAbstractGeometry *g)
Adds a geometry and takes ownership. Returns true in case of success.
static Qgis::GeometryOperationResult addPart(QgsAbstractGeometry *geometry, std::unique_ptr< QgsAbstractGeometry > part)
Add a part to multi type geometry.
A geometry engine is a low-level representation of a QgsAbstractGeometry object, optimised for use wi...
const QgsAbstractGeometry * mGeometry
EngineOperationResult
Success or failure of a geometry operation.
@ NothingHappened
Nothing happened, without any error.
@ InvalidBaseGeometry
The geometry on which the operation occurs is not valid.
@ InvalidInput
The input is not valid.
@ NodedGeometryError
Error occurred while creating a noded geometry.
@ EngineError
Error occurred in the geometry engine.
@ SplitCannotSplitPoint
Points cannot be split.
@ Success
Operation succeeded.
void logError(const QString &engineName, const QString &message) const
Logs an error message encountered during an operation.
static std::unique_ptr< QgsGeometryCollection > createCollectionOfType(QgsWkbTypes::Type type)
Returns a new geometry collection matching a specified WKB type.
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.
QgsAbstractGeometry * intersection(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Calculate the intersection of this and geom.
bool touches(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Checks if geom touches this.
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.
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
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 * combine(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Calculate the combination 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.
bool contains(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Checks if geom contains this.
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.
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.
QgsAbstractGeometry * symDifference(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Calculate the symmetric difference of this and geom.
bool isSimple(QString *errorMsg=nullptr) const override
Determines whether the geometry is simple (according to OGC definition).
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.
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...
std::unique_ptr< QgsAbstractGeometry > subdivide(int maxNodes, QString *errorMsg=nullptr) const
Subdivides the geometry.
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...
QgsAbstractGeometry * difference(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Calculate the difference of this and geom.
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.
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.
const double * mData() const
Returns a const pointer to the m vertex data, or nullptr if the linestring does not have m values.
double yAt(int index) const override
Returns the y-coordinate of the specified node in the line string.
double mAt(int index) const
Returns the m value of the specified node in the line string.
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.
const double * xData() const
Returns a const pointer to the x vertex data.
const double * zData() const
Returns a const pointer to the z vertex data, or nullptr if the linestring does not have z values.
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.
A rectangle specified with double values.
double yMaximum() const SIP_HOLDGIL
Returns the y maximum value (top side of rectangle).
double xMaximum() const SIP_HOLDGIL
Returns the x maximum value (right side of rectangle).
double xMinimum() const SIP_HOLDGIL
Returns the x minimum value (left side of rectangle).
double yMinimum() const SIP_HOLDGIL
Returns the y minimum value (bottom side of rectangle).
void setYMinimum(double y) SIP_HOLDGIL
Set the minimum y value.
bool isNull() const
Test if the rectangle is null (all coordinates zero or after call to setMinimal()).
void setXMaximum(double x) SIP_HOLDGIL
Set the maximum x value.
void setXMinimum(double x) SIP_HOLDGIL
Set the minimum x value.
double height() const SIP_HOLDGIL
Returns the height of the rectangle.
void setYMaximum(double y) SIP_HOLDGIL
Set the maximum y value.
double width() const SIP_HOLDGIL
Returns the width of the rectangle.
bool isEmpty() const
Returns true if the rectangle is empty.
static GeometryType geometryType(Type type) SIP_HOLDGIL
Returns the geometry type for a WKB type, e.g., both MultiPolygon and CurvePolygon would have a Polyg...
static bool isMultiType(Type type) SIP_HOLDGIL
Returns true if the WKB type is a multi type.
Type
The WKB type describes the number of dimensions a geometry has.
static Type flatType(Type type) SIP_HOLDGIL
Returns the flat type for a WKB type.
Contains geos related utilities and functions.
std::unique_ptr< GEOSGeometry, GeosDeleter > unique_ptr
Scoped GEOS pointer.
std::unique_ptr< GEOSCoordSequence, GeosDeleter > coord_sequence_unique_ptr
Scoped GEOS coordinate sequence pointer.
std::unique_ptr< GEOSBufferParams, GeosDeleter > buffer_params_unique_ptr
Scoped GEOS buffer params pointer.
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
QMap< QString, QString > QgsStringMap
QVector< QgsPoint > QgsPointSequence
Q_GLOBAL_STATIC(QReadWriteLock, sDefinitionCacheLock)
#define DEFAULT_QUADRANT_SEGMENTS
#define CATCH_GEOS_WITH_ERRMSG(r)
void CORE_EXPORT operator()(GEOSGeometry *geom)
Destroys the GEOS geometry geom, using the static QGIS geos context.