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();
215 mGeosPrepared.reset();
218 mGeosPrepared.reset( GEOSPrepare_r( geosinit()->ctxt, mGeos.get() ) );
222 void QgsGeos::cacheGeos()
const
234 return overlay( geom, OverlayIntersection, errorMsg ).release();
239 return overlay( geom, OverlayDifference, errorMsg ).release();
254 catch ( GEOSException &e )
256 logError( QStringLiteral(
"GEOS" ), e.what() );
259 *errorMsg = e.what();
270 int partType = GEOSGeomTypeId_r( geosinit()->ctxt, currentPart );
273 if ( partType == GEOS_POINT )
284 if ( partType == GEOS_MULTILINESTRING || partType == GEOS_MULTIPOLYGON || partType == GEOS_GEOMETRYCOLLECTION )
286 int partCount = GEOSGetNumGeometries_r( geosinit()->ctxt, currentPart );
287 for (
int i = 0; i < partCount; ++i )
289 subdivideRecursive( GEOSGetGeometryN_r( geosinit()->ctxt, currentPart, i ), maxNodes, depth, parts, clipRect );
300 int vertexCount = GEOSGetNumCoordinates_r( geosinit()->ctxt, currentPart );
301 if ( vertexCount == 0 )
305 else if ( vertexCount < maxNodes )
312 double width = clipRect.
width();
313 double height = clipRect.
height();
316 if ( width > height )
329 halfClipRect1.
setYMinimum( halfClipRect1.
yMinimum() - std::numeric_limits<double>::epsilon() );
330 halfClipRect2.
setYMinimum( halfClipRect2.
yMinimum() - std::numeric_limits<double>::epsilon() );
331 halfClipRect1.
setYMaximum( halfClipRect1.
yMaximum() + std::numeric_limits<double>::epsilon() );
332 halfClipRect2.
setYMaximum( halfClipRect2.
yMaximum() + std::numeric_limits<double>::epsilon() );
336 halfClipRect1.
setXMinimum( halfClipRect1.
xMinimum() - std::numeric_limits<double>::epsilon() );
337 halfClipRect2.
setXMinimum( halfClipRect2.
xMinimum() - std::numeric_limits<double>::epsilon() );
338 halfClipRect1.
setXMaximum( halfClipRect1.
xMaximum() + std::numeric_limits<double>::epsilon() );
339 halfClipRect2.
setXMaximum( halfClipRect2.
xMaximum() + std::numeric_limits<double>::epsilon() );
349 subdivideRecursive( clipPart1.get(), maxNodes, depth, parts, halfClipRect1 );
353 subdivideRecursive( clipPart2.get(), maxNodes, depth, parts, halfClipRect2 );
365 maxNodes = std::max( maxNodes, 8 );
374 return std::move( parts );
379 return overlay( geom, OverlayUnion, errorMsg ).release();
384 QVector< GEOSGeometry * > geosGeometries;
385 geosGeometries.reserve( geomList.size() );
391 geosGeometries <<
asGeos( g, mPrecision ).release();
397 geos::unique_ptr geomCollection = createGeosCollection( GEOS_GEOMETRYCOLLECTION, geosGeometries );
398 geomUnion.reset( GEOSUnaryUnion_r( geosinit()->ctxt, geomCollection.get() ) );
402 std::unique_ptr< QgsAbstractGeometry > result =
fromGeos( geomUnion.get() );
403 return result.release();
408 QVector< GEOSGeometry * > geosGeometries;
409 geosGeometries.reserve( geomList.size() );
415 geosGeometries <<
asGeos( g.constGet(), mPrecision ).release();
421 geos::unique_ptr geomCollection = createGeosCollection( GEOS_GEOMETRYCOLLECTION, geosGeometries );
422 geomUnion.reset( GEOSUnaryUnion_r( geosinit()->ctxt, geomCollection.get() ) );
426 std::unique_ptr< QgsAbstractGeometry > result =
fromGeos( geomUnion.get() );
427 return result.release();
432 return overlay( geom, OverlaySymDifference, errorMsg ).release();
444 if ( !otherGeosGeom )
451 #if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=9 )
454 GEOSPreparedDistance_r( geosinit()->ctxt, mGeosPrepared.get(), otherGeosGeom.get(), &
distance );
458 GEOSDistance_r( geosinit()->ctxt, mGeos.get(), otherGeosGeom.get(), &
distance );
461 GEOSDistance_r( geosinit()->ctxt, mGeos.get(), otherGeosGeom.get(), &
distance );
478 if ( !otherGeosGeom )
485 GEOSHausdorffDistance_r( geosinit()->ctxt, mGeos.get(), otherGeosGeom.get(), &
distance );
501 if ( !otherGeosGeom )
508 GEOSHausdorffDistanceDensify_r( geosinit()->ctxt, mGeos.get(), otherGeosGeom.get(), densifyFraction, &
distance );
517 #if GEOS_VERSION_MAJOR==3 && GEOS_VERSION_MINOR<7
520 throw QgsNotSupportedException( QStringLiteral(
"Calculating frechetDistance requires a QGIS build based on GEOS 3.7 or later" ) );
529 if ( !otherGeosGeom )
536 GEOSFrechetDistance_r( geosinit()->ctxt, mGeos.get(), otherGeosGeom.get(), &
distance );
546 #if GEOS_VERSION_MAJOR==3 && GEOS_VERSION_MINOR<7
548 ( void )densifyFraction;
550 throw QgsNotSupportedException( QStringLiteral(
"Calculating frechetDistanceDensify requires a QGIS build based on GEOS 3.7 or later" ) );
559 if ( !otherGeosGeom )
566 GEOSFrechetDistanceDensify_r( geosinit()->ctxt, mGeos.get(), otherGeosGeom.get(), densifyFraction, &
distance );
576 return relation( geom, RelationIntersects, errorMsg );
581 return relation( geom, RelationTouches, errorMsg );
586 return relation( geom, RelationCrosses, errorMsg );
591 return relation( geom, RelationWithin, errorMsg );
596 return relation( geom, RelationOverlaps, errorMsg );
601 return relation( geom, RelationContains, errorMsg );
606 return relation( geom, RelationDisjoint, errorMsg );
625 char *r = GEOSRelate_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() );
628 result = QString( r );
629 GEOSFree_r( geosinit()->ctxt, r );
632 catch ( GEOSException &e )
634 logError( QStringLiteral(
"GEOS" ), e.what() );
637 *errorMsg = e.what();
646 if ( !mGeos || !geom )
660 result = ( GEOSRelatePattern_r( geosinit()->ctxt, mGeos.get(), geosGeom.get(), pattern.toLocal8Bit().constData() ) == 1 );
662 catch ( GEOSException &e )
664 logError( QStringLiteral(
"GEOS" ), e.what() );
667 *errorMsg = e.what();
684 if ( GEOSArea_r( geosinit()->ctxt, mGeos.get(), &
area ) != 1 )
700 if ( GEOSLength_r( geosinit()->ctxt, mGeos.get(), &
length ) != 1 )
708 QVector<QgsGeometry> &newGeometries,
711 QString *errorMsg,
bool skipIntersectionCheck )
const
726 if ( !GEOSisValid_r( geosinit()->ctxt, mGeos.get() ) )
734 newGeometries.clear();
741 splitLineGeos = createGeosLinestring( &splitLine, mPrecision );
745 splitLineGeos = createGeosPointXY( splitLine.
xAt( 0 ), splitLine.
yAt( 0 ),
false, 0,
false, 0, 2, mPrecision );
752 if ( !GEOSisValid_r( geosinit()->ctxt, splitLineGeos.get() ) || !GEOSisSimple_r( geosinit()->ctxt, splitLineGeos.get() ) )
760 if ( !topologicalTestPointsSplit( splitLineGeos.get(), topologyTestPoints ) )
769 returnCode = splitLinearGeometry( splitLineGeos.get(), newGeometries, skipIntersectionCheck );
773 returnCode = splitPolygonGeometry( splitLineGeos.get(), newGeometries, skipIntersectionCheck );
787 bool QgsGeos::topologicalTestPointsSplit(
const GEOSGeometry *splitLine,
QgsPointSequence &testPoints, QString *errorMsg )
const
801 geos::unique_ptr intersectionGeom( GEOSIntersection_r( geosinit()->ctxt, mGeos.get(), splitLine ) );
802 if ( !intersectionGeom )
806 int nIntersectGeoms = 1;
807 if ( GEOSGeomTypeId_r( geosinit()->ctxt, intersectionGeom.get() ) == GEOS_LINESTRING
808 || GEOSGeomTypeId_r( geosinit()->ctxt, intersectionGeom.get() ) == GEOS_POINT )
812 nIntersectGeoms = GEOSGetNumGeometries_r( geosinit()->ctxt, intersectionGeom.get() );
814 for (
int i = 0; i < nIntersectGeoms; ++i )
816 const GEOSGeometry *currentIntersectGeom =
nullptr;
818 currentIntersectGeom = intersectionGeom.get();
820 currentIntersectGeom = GEOSGetGeometryN_r( geosinit()->ctxt, intersectionGeom.get(), i );
822 const GEOSCoordSequence *lineSequence = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, currentIntersectGeom );
823 unsigned int sequenceSize = 0;
825 if ( GEOSCoordSeq_getSize_r( geosinit()->ctxt, lineSequence, &sequenceSize ) != 0 )
827 for (
unsigned int i = 0; i < sequenceSize; ++i )
829 if ( GEOSCoordSeq_getX_r( geosinit()->ctxt, lineSequence, i, &x ) != 0 )
831 if ( GEOSCoordSeq_getY_r( geosinit()->ctxt, lineSequence, i, &y ) != 0 )
833 testPoints.push_back(
QgsPoint( x, y ) );
847 int type = GEOSGeomTypeId_r( geosinit()->ctxt, mGeos.get() );
849 std::unique_ptr< QgsMultiCurve > multiCurve;
850 if ( type == GEOS_MULTILINESTRING )
852 multiCurve.reset( qgsgeometry_cast<QgsMultiCurve *>(
mGeometry->
clone() ) );
854 else if ( type == GEOS_LINESTRING )
870 std::unique_ptr< QgsAbstractGeometry > splitGeom(
fromGeos( GEOSsplitPoint ) );
871 QgsPoint *splitPoint = qgsgeometry_cast<QgsPoint *>( splitGeom.get() );
880 for (
int i = 0; i < multiCurve->numGeometries(); ++i )
882 const QgsLineString *line = qgsgeometry_cast<const QgsLineString *>( multiCurve->geometryN( i ) );
889 for (
int j = 1; j < ( nVertices - 1 ); ++j )
893 if ( currentPoint == *splitPoint )
905 return asGeos( &lines, mPrecision );
917 if ( !skipIntersectionCheck && !GEOSIntersects_r( geosinit()->ctxt, splitLine, mGeos.get() ) )
921 int linearIntersect = GEOSRelatePattern_r( geosinit()->ctxt, mGeos.get(), splitLine,
"1********" );
922 if ( linearIntersect > 0 )
925 int splitGeomType = GEOSGeomTypeId_r( geosinit()->ctxt, splitLine );
928 if ( splitGeomType == GEOS_POINT )
930 splitGeom = linePointDifference( splitLine );
934 splitGeom.reset( GEOSDifference_r( geosinit()->ctxt, mGeos.get(), splitLine ) );
936 QVector<GEOSGeometry *> lineGeoms;
938 int splitType = GEOSGeomTypeId_r( geosinit()->ctxt, splitGeom.get() );
939 if ( splitType == GEOS_MULTILINESTRING )
941 int nGeoms = GEOSGetNumGeometries_r( geosinit()->ctxt, splitGeom.get() );
942 lineGeoms.reserve( nGeoms );
943 for (
int i = 0; i < nGeoms; ++i )
944 lineGeoms << GEOSGeom_clone_r( geosinit()->ctxt, GEOSGetGeometryN_r( geosinit()->ctxt, splitGeom.get(), i ) );
949 lineGeoms << GEOSGeom_clone_r( geosinit()->ctxt, splitGeom.get() );
952 mergeGeometriesMultiTypeSplit( lineGeoms );
954 for (
int i = 0; i < lineGeoms.size(); ++i )
957 GEOSGeom_destroy_r( geosinit()->ctxt, lineGeoms[i] );
973 if ( !mGeosPrepared )
977 if ( !skipIntersectionCheck && !GEOSPreparedIntersects_r( geosinit()->ctxt, mGeosPrepared.get(), splitLine ) )
982 if ( !nodedGeometry )
985 const GEOSGeometry *noded = nodedGeometry.get();
986 geos::unique_ptr polygons( GEOSPolygonize_r( geosinit()->ctxt, &noded, 1 ) );
987 if ( !polygons || numberOfGeometries( polygons.get() ) == 0 )
994 QVector<GEOSGeometry *> testedGeometries;
999 for (
int i = 0; i < numberOfGeometries( polygons.get() ); i++ )
1001 const GEOSGeometry *polygon = GEOSGetGeometryN_r( geosinit()->ctxt, polygons.get(), i );
1005 testedGeometries << GEOSGeom_clone_r( geosinit()->ctxt, polygon );
1008 int nGeometriesThis = numberOfGeometries( mGeos.get() );
1009 if ( testedGeometries.empty() || testedGeometries.size() == nGeometriesThis )
1012 for (
int i = 0; i < testedGeometries.size(); ++i )
1014 GEOSGeom_destroy_r( geosinit()->ctxt, testedGeometries[i] );
1023 mergeGeometriesMultiTypeSplit( testedGeometries );
1026 for ( i = 0; i < testedGeometries.size() && GEOSisValid_r( geosinit()->ctxt, testedGeometries[i] ); ++i )
1029 if ( i < testedGeometries.size() )
1031 for ( i = 0; i < testedGeometries.size(); ++i )
1032 GEOSGeom_destroy_r( geosinit()->ctxt, testedGeometries[i] );
1037 for ( i = 0; i < testedGeometries.size(); ++i )
1040 GEOSGeom_destroy_r( geosinit()->ctxt, testedGeometries[i] );
1046 geos::unique_ptr QgsGeos::nodeGeometries(
const GEOSGeometry *splitLine,
const GEOSGeometry *geom )
1048 if ( !splitLine || !geom )
1052 if ( GEOSGeomTypeId_r( geosinit()->ctxt, geom ) == GEOS_POLYGON || GEOSGeomTypeId_r( geosinit()->ctxt, geom ) == GEOS_MULTIPOLYGON )
1053 geometryBoundary.reset( GEOSBoundary_r( geosinit()->ctxt, geom ) );
1055 geometryBoundary.reset( GEOSGeom_clone_r( geosinit()->ctxt, geom ) );
1057 geos::unique_ptr splitLineClone( GEOSGeom_clone_r( geosinit()->ctxt, splitLine ) );
1058 geos::unique_ptr unionGeometry( GEOSUnion_r( geosinit()->ctxt, splitLineClone.get(), geometryBoundary.get() ) );
1060 return unionGeometry;
1063 int QgsGeos::mergeGeometriesMultiTypeSplit( QVector<GEOSGeometry *> &splitResult )
const
1069 int type = GEOSGeomTypeId_r( geosinit()->ctxt, mGeos.get() );
1070 if ( type != GEOS_GEOMETRYCOLLECTION &&
1071 type != GEOS_MULTILINESTRING &&
1072 type != GEOS_MULTIPOLYGON &&
1073 type != GEOS_MULTIPOINT )
1076 QVector<GEOSGeometry *> copyList = splitResult;
1077 splitResult.clear();
1080 QVector<GEOSGeometry *> unionGeom;
1082 for (
int i = 0; i < copyList.size(); ++i )
1085 bool isPart =
false;
1086 for (
int j = 0; j < GEOSGetNumGeometries_r( geosinit()->ctxt, mGeos.get() ); j++ )
1088 if ( GEOSEquals_r( geosinit()->ctxt, copyList[i], GEOSGetGeometryN_r( geosinit()->ctxt, mGeos.get(), j ) ) )
1097 unionGeom << copyList[i];
1101 QVector<GEOSGeometry *> geomVector;
1102 geomVector << copyList[i];
1104 if ( type == GEOS_MULTILINESTRING )
1105 splitResult << createGeosCollection( GEOS_MULTILINESTRING, geomVector ).release();
1106 else if ( type == GEOS_MULTIPOLYGON )
1107 splitResult << createGeosCollection( GEOS_MULTIPOLYGON, geomVector ).release();
1109 GEOSGeom_destroy_r( geosinit()->ctxt, copyList[i] );
1114 if ( !unionGeom.isEmpty() )
1116 if ( type == GEOS_MULTILINESTRING )
1117 splitResult << createGeosCollection( GEOS_MULTILINESTRING, unionGeom ).release();
1118 else if ( type == GEOS_MULTIPOLYGON )
1119 splitResult << createGeosCollection( GEOS_MULTIPOLYGON, unionGeom ).release();
1129 geos::unique_ptr QgsGeos::createGeosCollection(
int typeId,
const QVector<GEOSGeometry *> &geoms )
1131 int nNullGeoms = geoms.count(
nullptr );
1132 int nNotNullGeoms = geoms.size() - nNullGeoms;
1134 GEOSGeometry **geomarr =
new GEOSGeometry*[ nNotNullGeoms ];
1141 QVector<GEOSGeometry *>::const_iterator geomIt = geoms.constBegin();
1142 for ( ; geomIt != geoms.constEnd(); ++geomIt )
1146 if ( GEOSisEmpty_r( geosinit()->ctxt, *geomIt ) )
1151 GEOSGeom_destroy_r( geosinit()->ctxt, *geomIt );
1155 geomarr[i] = *geomIt;
1164 geom.reset( GEOSGeom_createCollection_r( geosinit()->ctxt, typeId, geomarr, nNotNullGeoms ) );
1166 catch ( GEOSException & )
1182 int nCoordDims = GEOSGeom_getCoordinateDimension_r( geosinit()->ctxt,
geos );
1183 int nDims = GEOSGeom_getDimensions_r( geosinit()->ctxt,
geos );
1184 bool hasZ = ( nCoordDims == 3 );
1185 bool hasM = ( ( nDims - nCoordDims ) == 1 );
1187 switch ( GEOSGeomTypeId_r( geosinit()->ctxt,
geos ) )
1191 if ( GEOSisEmpty_r( geosinit()->ctxt,
geos ) )
1194 const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq_r( geosinit()->ctxt,
geos );
1195 unsigned int nPoints = 0;
1196 GEOSCoordSeq_getSize_r( geosinit()->ctxt, cs, &nPoints );
1197 return nPoints > 0 ? std::unique_ptr<QgsAbstractGeometry>(
coordSeqPoint( cs, 0, hasZ, hasM ).clone() ) : std::make_unique< QgsPoint >();
1199 case GEOS_LINESTRING:
1201 return sequenceToLinestring(
geos, hasZ, hasM );
1207 case GEOS_MULTIPOINT:
1209 std::unique_ptr< QgsMultiPoint > multiPoint(
new QgsMultiPoint() );
1210 int nParts = GEOSGetNumGeometries_r( geosinit()->ctxt,
geos );
1211 multiPoint->reserve( nParts );
1212 for (
int i = 0; i < nParts; ++i )
1214 const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, GEOSGetGeometryN_r( geosinit()->ctxt,
geos, i ) );
1217 unsigned int nPoints = 0;
1218 GEOSCoordSeq_getSize_r( geosinit()->ctxt, cs, &nPoints );
1220 multiPoint->addGeometry(
coordSeqPoint( cs, 0, hasZ, hasM ).clone() );
1223 return std::move( multiPoint );
1225 case GEOS_MULTILINESTRING:
1228 int nParts = GEOSGetNumGeometries_r( geosinit()->ctxt,
geos );
1229 multiLineString->reserve( nParts );
1230 for (
int i = 0; i < nParts; ++i )
1232 std::unique_ptr< QgsLineString >line( sequenceToLinestring( GEOSGetGeometryN_r( geosinit()->ctxt,
geos, i ), hasZ, hasM ) );
1235 multiLineString->addGeometry( line.release() );
1238 return std::move( multiLineString );
1240 case GEOS_MULTIPOLYGON:
1242 std::unique_ptr< QgsMultiPolygon > multiPolygon(
new QgsMultiPolygon() );
1244 int nParts = GEOSGetNumGeometries_r( geosinit()->ctxt,
geos );
1245 multiPolygon->reserve( nParts );
1246 for (
int i = 0; i < nParts; ++i )
1248 std::unique_ptr< QgsPolygon > poly =
fromGeosPolygon( GEOSGetGeometryN_r( geosinit()->ctxt,
geos, i ) );
1251 multiPolygon->addGeometry( poly.release() );
1254 return std::move( multiPolygon );
1256 case GEOS_GEOMETRYCOLLECTION:
1259 int nParts = GEOSGetNumGeometries_r( geosinit()->ctxt,
geos );
1260 geomCollection->reserve( nParts );
1261 for (
int i = 0; i < nParts; ++i )
1263 std::unique_ptr< QgsAbstractGeometry > geom(
fromGeos( GEOSGetGeometryN_r( geosinit()->ctxt,
geos, i ) ) );
1266 geomCollection->addGeometry( geom.release() );
1269 return std::move( geomCollection );
1277 if ( GEOSGeomTypeId_r( geosinit()->ctxt,
geos ) != GEOS_POLYGON )
1282 int nCoordDims = GEOSGeom_getCoordinateDimension_r( geosinit()->ctxt,
geos );
1283 int nDims = GEOSGeom_getDimensions_r( geosinit()->ctxt,
geos );
1284 bool hasZ = ( nCoordDims == 3 );
1285 bool hasM = ( ( nDims - nCoordDims ) == 1 );
1287 std::unique_ptr< QgsPolygon > polygon(
new QgsPolygon() );
1289 const GEOSGeometry *ring = GEOSGetExteriorRing_r( geosinit()->ctxt,
geos );
1292 polygon->setExteriorRing( sequenceToLinestring( ring, hasZ, hasM ).release() );
1295 QVector<QgsCurve *> interiorRings;
1296 const int ringCount = GEOSGetNumInteriorRings_r( geosinit()->ctxt,
geos );
1297 interiorRings.reserve( ringCount );
1298 for (
int i = 0; i < ringCount; ++i )
1300 ring = GEOSGetInteriorRingN_r( geosinit()->ctxt,
geos, i );
1303 interiorRings.push_back( sequenceToLinestring( ring, hasZ, hasM ).release() );
1306 polygon->setInteriorRings( interiorRings );
1311 std::unique_ptr<QgsLineString> QgsGeos::sequenceToLinestring(
const GEOSGeometry *
geos,
bool hasZ,
bool hasM )
1313 const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq_r( geosinit()->ctxt,
geos );
1314 unsigned int nPoints;
1315 GEOSCoordSeq_getSize_r( geosinit()->ctxt, cs, &nPoints );
1316 QVector< double > xOut( nPoints );
1317 QVector< double > yOut( nPoints );
1318 QVector< double > zOut;
1320 zOut.resize( nPoints );
1321 QVector< double > mOut;
1323 mOut.resize( nPoints );
1324 double *x = xOut.data();
1325 double *y = yOut.data();
1326 double *z = zOut.data();
1327 double *m = mOut.data();
1328 for (
unsigned int i = 0; i < nPoints; ++i )
1330 #if GEOS_VERSION_MAJOR>3 || GEOS_VERSION_MINOR>=8
1332 GEOSCoordSeq_getXYZ_r( geosinit()->ctxt, cs, i, x++, y++, z++ );
1334 GEOSCoordSeq_getXY_r( geosinit()->ctxt, cs, i, x++, y++ );
1336 GEOSCoordSeq_getX_r( geosinit()->ctxt, cs, i, x++ );
1337 GEOSCoordSeq_getY_r( geosinit()->ctxt, cs, i, y++ );
1340 GEOSCoordSeq_getZ_r( geosinit()->ctxt, cs, i, z++ );
1345 GEOSCoordSeq_getOrdinate_r( geosinit()->ctxt, cs, i, 3, m++ );
1348 std::unique_ptr< QgsLineString > line(
new QgsLineString( xOut, yOut, zOut, mOut ) );
1352 int QgsGeos::numberOfGeometries( GEOSGeometry *g )
1357 int geometryType = GEOSGeomTypeId_r( geosinit()->ctxt, g );
1358 if ( geometryType == GEOS_POINT || geometryType == GEOS_LINESTRING || geometryType == GEOS_LINEARRING
1359 || geometryType == GEOS_POLYGON )
1363 return GEOSGetNumGeometries_r( geosinit()->ctxt, g );
1376 #if GEOS_VERSION_MAJOR>3 || GEOS_VERSION_MINOR>=8
1378 GEOSCoordSeq_getXYZ_r( geosinit()->ctxt, cs, i, &x, &y, &z );
1380 GEOSCoordSeq_getXY_r( geosinit()->ctxt, cs, i, &x, &y );
1382 GEOSCoordSeq_getX_r( geosinit()->ctxt, cs, i, &x );
1383 GEOSCoordSeq_getY_r( geosinit()->ctxt, cs, i, &y );
1386 GEOSCoordSeq_getZ_r( geosinit()->ctxt, cs, i, &z );
1391 GEOSCoordSeq_getOrdinate_r( geosinit()->ctxt, cs, i, 3, &m );
1427 int geosType = GEOS_GEOMETRYCOLLECTION;
1434 geosType = GEOS_MULTIPOINT;
1438 geosType = GEOS_MULTILINESTRING;
1442 geosType = GEOS_MULTIPOLYGON;
1457 QVector< GEOSGeometry * > geomVector(
c->numGeometries() );
1458 for (
int i = 0; i <
c->numGeometries(); ++i )
1462 return createGeosCollection( geosType, geomVector );
1469 return createGeosPoint(
static_cast<const QgsPoint *
>( geom ), coordDims,
precision );
1485 std::unique_ptr<QgsAbstractGeometry> QgsGeos::overlay(
const QgsAbstractGeometry *geom, Overlay op, QString *errorMsg )
const
1487 if ( !mGeos || !geom )
1503 case OverlayIntersection:
1504 opGeom.reset( GEOSIntersection_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) );
1507 case OverlayDifference:
1508 opGeom.reset( GEOSDifference_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) );
1513 geos::unique_ptr unionGeometry( GEOSUnion_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) );
1515 if ( unionGeometry && GEOSGeomTypeId_r( geosinit()->ctxt, unionGeometry.get() ) == GEOS_MULTILINESTRING )
1517 geos::unique_ptr mergedLines( GEOSLineMerge_r( geosinit()->ctxt, unionGeometry.get() ) );
1520 unionGeometry = std::move( mergedLines );
1524 opGeom = std::move( unionGeometry );
1528 case OverlaySymDifference:
1529 opGeom.reset( GEOSSymDifference_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) );
1534 catch ( GEOSException &e )
1536 logError( QStringLiteral(
"GEOS" ), e.what() );
1539 *errorMsg = e.what();
1545 bool QgsGeos::relation(
const QgsAbstractGeometry *geom, Relation r, QString *errorMsg )
const
1547 if ( !mGeos || !geom )
1558 bool result =
false;
1561 if ( mGeosPrepared )
1565 case RelationIntersects:
1566 result = ( GEOSPreparedIntersects_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1568 case RelationTouches:
1569 result = ( GEOSPreparedTouches_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1571 case RelationCrosses:
1572 result = ( GEOSPreparedCrosses_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1574 case RelationWithin:
1575 result = ( GEOSPreparedWithin_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1577 case RelationContains:
1578 result = ( GEOSPreparedContains_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1580 case RelationDisjoint:
1581 result = ( GEOSPreparedDisjoint_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1583 case RelationOverlaps:
1584 result = ( GEOSPreparedOverlaps_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1592 case RelationIntersects:
1593 result = ( GEOSIntersects_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1595 case RelationTouches:
1596 result = ( GEOSTouches_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1598 case RelationCrosses:
1599 result = ( GEOSCrosses_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1601 case RelationWithin:
1602 result = ( GEOSWithin_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1604 case RelationContains:
1605 result = ( GEOSContains_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1607 case RelationDisjoint:
1608 result = ( GEOSDisjoint_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1610 case RelationOverlaps:
1611 result = ( GEOSOverlaps_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1615 catch ( GEOSException &e )
1617 logError( QStringLiteral(
"GEOS" ), e.what() );
1620 *errorMsg = e.what();
1638 geos.reset( GEOSBuffer_r( geosinit()->ctxt, mGeos.get(),
distance, segments ) );
1654 geos.reset( GEOSBufferWithStyle_r( geosinit()->ctxt, mGeos.get(),
distance, segments, endCapStyle, joinStyle, miterLimit ) );
1669 geos.reset( GEOSTopologyPreserveSimplify_r( geosinit()->ctxt, mGeos.get(), tolerance ) );
1684 geos.reset( GEOSInterpolate_r( geosinit()->ctxt, mGeos.get(),
distance ) );
1703 geos.reset( GEOSGetCentroid_r( geosinit()->ctxt, mGeos.get() ) );
1708 GEOSGeomGetX_r( geosinit()->ctxt,
geos.get(), &x );
1709 GEOSGeomGetY_r( geosinit()->ctxt,
geos.get(), &y );
1725 geos.reset( GEOSEnvelope_r( geosinit()->ctxt, mGeos.get() ) );
1744 geos.reset( GEOSPointOnSurface_r( geosinit()->ctxt, mGeos.get() ) );
1746 if ( !
geos || GEOSisEmpty_r( geosinit()->ctxt,
geos.get() ) != 0 )
1751 GEOSGeomGetX_r( geosinit()->ctxt,
geos.get(), &x );
1752 GEOSGeomGetY_r( geosinit()->ctxt,
geos.get(), &y );
1768 geos::unique_ptr cHull( GEOSConvexHull_r( geosinit()->ctxt, mGeos.get() ) );
1769 std::unique_ptr< QgsAbstractGeometry > cHullGeom =
fromGeos( cHull.get() );
1770 return cHullGeom.release();
1784 GEOSGeometry *g1 =
nullptr;
1786 char res = GEOSisValidDetail_r( geosinit()->ctxt, mGeos.get(), allowSelfTouchingHoles ? GEOSVALID_ALLOW_SELFTOUCHING_RING_FORMING_HOLE : 0, &r, &g1 );
1787 const bool invalid = res != 1;
1792 error = QString( r );
1793 GEOSFree_r( geosinit()->ctxt, r );
1796 if ( invalid && errorMsg )
1800 if ( translatedErrors.empty() )
1803 translatedErrors.insert( QStringLiteral(
"topology validation error" ), QObject::tr(
"Topology validation error",
"GEOS Error" ) );
1804 translatedErrors.insert( QStringLiteral(
"repeated point" ), QObject::tr(
"Repeated point",
"GEOS Error" ) );
1805 translatedErrors.insert( QStringLiteral(
"hole lies outside shell" ), QObject::tr(
"Hole lies outside shell",
"GEOS Error" ) );
1806 translatedErrors.insert( QStringLiteral(
"holes are nested" ), QObject::tr(
"Holes are nested",
"GEOS Error" ) );
1807 translatedErrors.insert( QStringLiteral(
"interior is disconnected" ), QObject::tr(
"Interior is disconnected",
"GEOS Error" ) );
1808 translatedErrors.insert( QStringLiteral(
"self-intersection" ), QObject::tr(
"Self-intersection",
"GEOS Error" ) );
1809 translatedErrors.insert( QStringLiteral(
"ring self-intersection" ), QObject::tr(
"Ring self-intersection",
"GEOS Error" ) );
1810 translatedErrors.insert( QStringLiteral(
"nested shells" ), QObject::tr(
"Nested shells",
"GEOS Error" ) );
1811 translatedErrors.insert( QStringLiteral(
"duplicate rings" ), QObject::tr(
"Duplicate rings",
"GEOS Error" ) );
1812 translatedErrors.insert( QStringLiteral(
"too few points in geometry component" ), QObject::tr(
"Too few points in geometry component",
"GEOS Error" ) );
1813 translatedErrors.insert( QStringLiteral(
"invalid coordinate" ), QObject::tr(
"Invalid coordinate",
"GEOS Error" ) );
1814 translatedErrors.insert( QStringLiteral(
"ring is not closed" ), QObject::tr(
"Ring is not closed",
"GEOS Error" ) );
1817 *errorMsg = translatedErrors.value( error.toLower(), error );
1819 if ( g1 && errorLoc )
1825 GEOSGeom_destroy_r( geosinit()->ctxt, g1 );
1835 if ( !mGeos || !geom )
1847 bool equal = GEOSEquals_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() );
1862 return GEOSisEmpty_r( geosinit()->ctxt, mGeos.get() );
1876 return GEOSisSimple_r( geosinit()->ctxt, mGeos.get() );
1881 GEOSCoordSequence *QgsGeos::createCoordinateSequence(
const QgsCurve *curve,
double precision,
bool forceClose )
1883 std::unique_ptr< QgsLineString > segmentized;
1884 const QgsLineString *line = qgsgeometry_cast<const QgsLineString *>( curve );
1889 line = segmentized.get();
1897 bool hasZ = line->
is3D();
1911 int numOutPoints = numPoints;
1912 if ( forceClose && ( line->
pointN( 0 ) != line->
pointN( numPoints - 1 ) ) )
1917 GEOSCoordSequence *coordSeq =
nullptr;
1920 coordSeq = GEOSCoordSeq_create_r( geosinit()->ctxt, numOutPoints, coordDims );
1923 QgsDebugMsg( QStringLiteral(
"GEOS Exception: Could not create coordinate sequence for %1 points in %2 dimensions" ).arg( numPoints ).arg( coordDims ) );
1927 const double *xData = line->
xData();
1928 const double *yData = line->
yData();
1929 const double *zData = hasZ ? line->
zData() :
nullptr;
1930 const double *mData = hasM ? line->
mData() :
nullptr;
1934 for (
int i = 0; i < numOutPoints; ++i )
1936 if ( i >= numPoints )
1939 xData = line->
xData();
1940 yData = line->
yData();
1941 zData = hasZ ? line->
zData() :
nullptr;
1942 mData = hasM ? line->
mData() :
nullptr;
1944 #if GEOS_VERSION_MAJOR>3 || GEOS_VERSION_MINOR>=8
1954 GEOSCoordSeq_setX_r( geosinit()->ctxt, coordSeq, i, std::round( *xData++ /
precision ) *
precision );
1955 GEOSCoordSeq_setY_r( geosinit()->ctxt, coordSeq, i, std::round( *yData++ /
precision ) *
precision );
1958 GEOSCoordSeq_setOrdinate_r( geosinit()->ctxt, coordSeq, i, 2, std::round( *zData++ /
precision ) *
precision );
1963 GEOSCoordSeq_setOrdinate_r( geosinit()->ctxt, coordSeq, i, 3, line->
mAt( *mData++ ) );
1969 for (
int i = 0; i < numOutPoints; ++i )
1971 if ( i >= numPoints )
1974 xData = line->
xData();
1975 yData = line->
yData();
1976 zData = hasZ ? line->
zData() :
nullptr;
1977 mData = hasM ? line->
mData() :
nullptr;
1979 #if GEOS_VERSION_MAJOR>3 || GEOS_VERSION_MINOR>=8
1982 GEOSCoordSeq_setXYZ_r( geosinit()->ctxt, coordSeq, i, *xData++, *yData++, *zData++ );
1986 GEOSCoordSeq_setXY_r( geosinit()->ctxt, coordSeq, i, *xData++, *yData++ );
1989 GEOSCoordSeq_setX_r( geosinit()->ctxt, coordSeq, i, *xData++ );
1990 GEOSCoordSeq_setY_r( geosinit()->ctxt, coordSeq, i, *yData++ );
1993 GEOSCoordSeq_setOrdinate_r( geosinit()->ctxt, coordSeq, i, 2, *zData++ );
1998 GEOSCoordSeq_setOrdinate_r( geosinit()->ctxt, coordSeq, i, 3, *mData++ );
2010 const QgsPoint *pt = qgsgeometry_cast<const QgsPoint *>( point );
2017 geos::unique_ptr QgsGeos::createGeosPointXY(
double x,
double y,
bool hasZ,
double z,
bool hasM,
double m,
int coordDims,
double precision )
2025 #if GEOS_VERSION_MAJOR>3 || GEOS_VERSION_MINOR>=8
2026 if ( coordDims == 2 )
2032 geosPoint.reset( GEOSGeom_createPointFromXY_r( geosinit()->ctxt, x, y ) );
2037 GEOSCoordSequence *coordSeq = GEOSCoordSeq_create_r( geosinit()->ctxt, 1, coordDims );
2040 QgsDebugMsg( QStringLiteral(
"GEOS Exception: Could not create coordinate sequence for point with %1 dimensions" ).arg( coordDims ) );
2045 GEOSCoordSeq_setX_r( geosinit()->ctxt, coordSeq, 0, std::round( x /
precision ) *
precision );
2046 GEOSCoordSeq_setY_r( geosinit()->ctxt, coordSeq, 0, std::round( y /
precision ) *
precision );
2049 GEOSCoordSeq_setOrdinate_r( geosinit()->ctxt, coordSeq, 0, 2, std::round( z /
precision ) *
precision );
2054 GEOSCoordSeq_setX_r( geosinit()->ctxt, coordSeq, 0, x );
2055 GEOSCoordSeq_setY_r( geosinit()->ctxt, coordSeq, 0, y );
2058 GEOSCoordSeq_setOrdinate_r( geosinit()->ctxt, coordSeq, 0, 2, z );
2064 GEOSCoordSeq_setOrdinate_r( geosinit()->ctxt, coordSeq, 0, 3, m );
2067 geosPoint.reset( GEOSGeom_createPoint_r( geosinit()->ctxt, coordSeq ) );
2075 const QgsCurve *
c = qgsgeometry_cast<const QgsCurve *>( curve );
2079 GEOSCoordSequence *coordSeq = createCoordinateSequence(
c,
precision );
2086 geosGeom.reset( GEOSGeom_createLineString_r( geosinit()->ctxt, coordSeq ) );
2094 const QgsCurvePolygon *polygon = qgsgeometry_cast<const QgsCurvePolygon *>( poly );
2099 if ( !exteriorRing )
2107 geos::unique_ptr exteriorRingGeos( GEOSGeom_createLinearRing_r( geosinit()->ctxt, createCoordinateSequence( exteriorRing,
precision,
true ) ) );
2110 GEOSGeometry **holes =
nullptr;
2113 holes =
new GEOSGeometry*[ nHoles ];
2116 for (
int i = 0; i < nHoles; ++i )
2119 holes[i] = GEOSGeom_createLinearRing_r( geosinit()->ctxt, createCoordinateSequence( interiorRing,
precision,
true ) );
2121 geosPolygon.reset( GEOSGeom_createPolygon_r( geosinit()->ctxt, exteriorRingGeos.release(), holes, nHoles ) );
2137 offset.reset( GEOSOffsetCurve_r( geosinit()->ctxt, mGeos.get(),
distance, segments, joinStyle, miterLimit ) );
2140 std::unique_ptr< QgsAbstractGeometry > offsetGeom =
fromGeos( offset.get() );
2141 return offsetGeom.release();
2155 GEOSBufferParams_setSingleSided_r( geosinit()->ctxt, bp.get(), 1 );
2156 GEOSBufferParams_setQuadrantSegments_r( geosinit()->ctxt, bp.get(), segments );
2157 GEOSBufferParams_setJoinStyle_r( geosinit()->ctxt, bp.get(), joinStyle );
2158 GEOSBufferParams_setMitreLimit_r( geosinit()->ctxt, bp.get(), miterLimit );
2164 geos.reset( GEOSBufferWithParams_r( geosinit()->ctxt, mGeos.get(), bp.get(),
distance ) );
2172 #if GEOS_VERSION_MAJOR==3 && GEOS_VERSION_MINOR<9
2175 throw QgsNotSupportedException( QStringLiteral(
"Calculating maximumInscribedCircle requires a QGIS build based on GEOS 3.9 or later" ) );
2185 geos.reset( GEOSMaximumInscribedCircle_r( geosinit()->ctxt, mGeos.get(), tolerance ) );
2194 #if GEOS_VERSION_MAJOR==3 && GEOS_VERSION_MINOR<9
2198 throw QgsNotSupportedException( QStringLiteral(
"Calculating largestEmptyCircle requires a QGIS build based on GEOS 3.9 or later" ) );
2210 boundaryGeos =
asGeos( boundary );
2212 geos.reset( GEOSLargestEmptyCircle_r( geosinit()->ctxt, mGeos.get(), boundaryGeos.get(), tolerance ) );
2221 #if GEOS_VERSION_MAJOR==3 && GEOS_VERSION_MINOR<6
2223 throw QgsNotSupportedException( QStringLiteral(
"Calculating minimumWidth requires a QGIS build based on GEOS 3.6 or later" ) );
2233 geos.reset( GEOSMinimumWidth_r( geosinit()->ctxt, mGeos.get() ) );
2242 #if GEOS_VERSION_MAJOR==3 && GEOS_VERSION_MINOR<6
2244 throw QgsNotSupportedException( QStringLiteral(
"Calculating minimumClearance requires a QGIS build based on GEOS 3.6 or later" ) );
2248 return std::numeric_limits< double >::quiet_NaN();
2255 if ( GEOSMinimumClearance_r( geosinit()->ctxt, mGeos.get(), &res ) != 0 )
2256 return std::numeric_limits< double >::quiet_NaN();
2265 #if GEOS_VERSION_MAJOR==3 && GEOS_VERSION_MINOR<6
2267 throw QgsNotSupportedException( QStringLiteral(
"Calculating minimumClearanceLine requires a QGIS build based on GEOS 3.6 or later" ) );
2277 geos.reset( GEOSMinimumClearanceLine_r( geosinit()->ctxt, mGeos.get() ) );
2294 geos.reset( GEOSNode_r( geosinit()->ctxt, mGeos.get() ) );
2302 if ( !mGeos || !other )
2314 geos.reset( GEOSSharedPaths_r( geosinit()->ctxt, mGeos.get(), otherGeos.get() ) );
2334 geos::unique_ptr reshapeLineGeos = createGeosLinestring( &reshapeWithLine, mPrecision );
2337 int numGeoms = GEOSGetNumGeometries_r( geosinit()->ctxt, mGeos.get() );
2338 if ( numGeoms == -1 )
2347 bool isMultiGeom =
false;
2348 int geosTypeId = GEOSGeomTypeId_r( geosinit()->ctxt, mGeos.get() );
2349 if ( geosTypeId == GEOS_MULTILINESTRING || geosTypeId == GEOS_MULTIPOLYGON )
2359 reshapedGeometry = reshapeLine( mGeos.get(), reshapeLineGeos.get(), mPrecision );
2363 reshapedGeometry = reshapePolygon( mGeos.get(), reshapeLineGeos.get(), mPrecision );
2368 std::unique_ptr< QgsAbstractGeometry > reshapeResult =
fromGeos( reshapedGeometry.get() );
2369 return reshapeResult;
2376 bool reshapeTookPlace =
false;
2379 GEOSGeometry **newGeoms =
new GEOSGeometry*[numGeoms];
2381 for (
int i = 0; i < numGeoms; ++i )
2384 currentReshapeGeometry = reshapeLine( GEOSGetGeometryN_r( geosinit()->ctxt, mGeos.get(), i ), reshapeLineGeos.get(), mPrecision );
2386 currentReshapeGeometry = reshapePolygon( GEOSGetGeometryN_r( geosinit()->ctxt, mGeos.get(), i ), reshapeLineGeos.get(), mPrecision );
2388 if ( currentReshapeGeometry )
2390 newGeoms[i] = currentReshapeGeometry.release();
2391 reshapeTookPlace =
true;
2395 newGeoms[i] = GEOSGeom_clone_r( geosinit()->ctxt, GEOSGetGeometryN_r( geosinit()->ctxt, mGeos.get(), i ) );
2402 newMultiGeom.reset( GEOSGeom_createCollection_r( geosinit()->ctxt, GEOS_MULTILINESTRING, newGeoms, numGeoms ) );
2406 newMultiGeom.reset( GEOSGeom_createCollection_r( geosinit()->ctxt, GEOS_MULTIPOLYGON, newGeoms, numGeoms ) );
2410 if ( !newMultiGeom )
2416 if ( reshapeTookPlace )
2420 std::unique_ptr< QgsAbstractGeometry > reshapedMultiGeom =
fromGeos( newMultiGeom.get() );
2421 return reshapedMultiGeom;
2443 if ( GEOSGeomTypeId_r( geosinit()->ctxt, mGeos.get() ) != GEOS_MULTILINESTRING )
2449 geos.reset( GEOSLineMerge_r( geosinit()->ctxt, mGeos.get() ) );
2472 #if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=9 )
2474 if ( mGeosPrepared )
2476 nearestCoord.reset( GEOSPreparedNearestPoints_r( geosinit()->ctxt, mGeosPrepared.get(), otherGeom.get() ) );
2480 nearestCoord.reset( GEOSNearestPoints_r( geosinit()->ctxt, mGeos.get(), otherGeom.get() ) );
2486 ( void )GEOSCoordSeq_getX_r( geosinit()->ctxt, nearestCoord.get(), 0, &nx );
2487 ( void )GEOSCoordSeq_getY_r( geosinit()->ctxt, nearestCoord.get(), 0, &ny );
2489 catch ( GEOSException &e )
2491 logError( QStringLiteral(
"GEOS" ), e.what() );
2494 *errorMsg = e.what();
2504 if ( !mGeos || other.
isEmpty() )
2514 if ( !other || other->
isEmpty() )
2531 if ( !nearestCoord )
2534 *errorMsg = QStringLiteral(
"GEOS returned no nearest points" );
2538 ( void )GEOSCoordSeq_getX_r( geosinit()->ctxt, nearestCoord.get(), 0, &nx1 );
2539 ( void )GEOSCoordSeq_getY_r( geosinit()->ctxt, nearestCoord.get(), 0, &ny1 );
2540 ( void )GEOSCoordSeq_getX_r( geosinit()->ctxt, nearestCoord.get(), 1, &nx2 );
2541 ( void )GEOSCoordSeq_getY_r( geosinit()->ctxt, nearestCoord.get(), 1, &ny2 );
2543 catch ( GEOSException &e )
2545 logError( QStringLiteral(
"GEOS" ), e.what() );
2548 *errorMsg = e.what();
2575 distance = GEOSProject_r( geosinit()->ctxt, mGeos.get(), otherGeom.get() );
2577 catch ( GEOSException &e )
2579 logError( QStringLiteral(
"GEOS" ), e.what() );
2582 *errorMsg = e.what();
2592 GEOSGeometry **
const lineGeosGeometries =
new GEOSGeometry*[ geometries.size()];
2599 lineGeosGeometries[validLines] = l.release();
2606 geos::unique_ptr result( GEOSPolygonize_r( geosinit()->ctxt, lineGeosGeometries, validLines ) );
2607 for (
int i = 0; i < validLines; ++i )
2609 GEOSGeom_destroy_r( geosinit()->ctxt, lineGeosGeometries[i] );
2611 delete[] lineGeosGeometries;
2614 catch ( GEOSException &e )
2618 *errorMsg = e.what();
2620 for (
int i = 0; i < validLines; ++i )
2622 GEOSGeom_destroy_r( geosinit()->ctxt, lineGeosGeometries[i] );
2624 delete[] lineGeosGeometries;
2639 extentGeosGeom =
asGeos( extent, mPrecision );
2640 if ( !extentGeosGeom )
2649 geos.reset( GEOSVoronoiDiagram_r( geosinit()->ctxt, mGeos.get(), extentGeosGeom.get(), tolerance, edgesOnly ) );
2651 if ( !
geos || GEOSisEmpty_r( geosinit()->ctxt,
geos.get() ) != 0 )
2671 geos.reset( GEOSDelaunayTriangulation_r( geosinit()->ctxt, mGeos.get(), tolerance, edgesOnly ) );
2673 if ( !
geos || GEOSisEmpty_r( geosinit()->ctxt,
geos.get() ) != 0 )
2685 static bool _linestringEndpoints(
const GEOSGeometry *linestring,
double &x1,
double &y1,
double &x2,
double &y2 )
2687 const GEOSCoordSequence *coordSeq = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, linestring );
2691 unsigned int coordSeqSize;
2692 if ( GEOSCoordSeq_getSize_r( geosinit()->ctxt, coordSeq, &coordSeqSize ) == 0 )
2695 if ( coordSeqSize < 2 )
2698 GEOSCoordSeq_getX_r( geosinit()->ctxt, coordSeq, 0, &x1 );
2699 GEOSCoordSeq_getY_r( geosinit()->ctxt, coordSeq, 0, &y1 );
2700 GEOSCoordSeq_getX_r( geosinit()->ctxt, coordSeq, coordSeqSize - 1, &x2 );
2701 GEOSCoordSeq_getY_r( geosinit()->ctxt, coordSeq, coordSeqSize - 1, &y2 );
2707 static geos::unique_ptr _mergeLinestrings(
const GEOSGeometry *line1,
const GEOSGeometry *line2,
const QgsPointXY &intersectionPoint )
2709 double x1, y1, x2, y2;
2710 if ( !_linestringEndpoints( line1, x1, y1, x2, y2 ) )
2713 double rx1, ry1, rx2, ry2;
2714 if ( !_linestringEndpoints( line2, rx1, ry1, rx2, ry2 ) )
2717 bool intersectionAtOrigLineEndpoint =
2718 ( intersectionPoint.
x() == x1 && intersectionPoint.
y() == y1 ) !=
2719 ( intersectionPoint.
x() == x2 && intersectionPoint.
y() == y2 );
2720 bool intersectionAtReshapeLineEndpoint =
2721 ( intersectionPoint.
x() == rx1 && intersectionPoint.
y() == ry1 ) ||
2722 ( intersectionPoint.
x() == rx2 && intersectionPoint.
y() == ry2 );
2725 if ( intersectionAtOrigLineEndpoint && intersectionAtReshapeLineEndpoint )
2729 GEOSGeometry *geoms[2] = { g1.release(), g2.release() };
2730 geos::unique_ptr multiGeom( GEOSGeom_createCollection_r( geosinit()->ctxt, GEOS_MULTILINESTRING, geoms, 2 ) );
2731 geos::unique_ptr res( GEOSLineMerge_r( geosinit()->ctxt, multiGeom.get() ) );
2739 geos::unique_ptr QgsGeos::reshapeLine(
const GEOSGeometry *line,
const GEOSGeometry *reshapeLineGeos,
double precision )
2741 if ( !line || !reshapeLineGeos )
2744 bool atLeastTwoIntersections =
false;
2745 bool oneIntersection =
false;
2751 geos::unique_ptr intersectGeom( GEOSIntersection_r( geosinit()->ctxt, line, reshapeLineGeos ) );
2752 if ( intersectGeom )
2754 const int geomType = GEOSGeomTypeId_r( geosinit()->ctxt, intersectGeom.get() );
2755 atLeastTwoIntersections = ( geomType == GEOS_MULTIPOINT && GEOSGetNumGeometries_r( geosinit()->ctxt, intersectGeom.get() ) > 1 )
2756 || ( geomType == GEOS_GEOMETRYCOLLECTION && GEOSGetNumGeometries_r( geosinit()->ctxt, intersectGeom.get() ) > 0 )
2757 || ( geomType == GEOS_MULTILINESTRING && GEOSGetNumGeometries_r( geosinit()->ctxt, intersectGeom.get() ) > 0 );
2759 if ( GEOSGeomTypeId_r( geosinit()->ctxt, intersectGeom.get() ) == GEOS_POINT )
2761 const GEOSCoordSequence *intersectionCoordSeq = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, intersectGeom.get() );
2763 GEOSCoordSeq_getX_r( geosinit()->ctxt, intersectionCoordSeq, 0, &xi );
2764 GEOSCoordSeq_getY_r( geosinit()->ctxt, intersectionCoordSeq, 0, &yi );
2765 oneIntersection =
true;
2770 catch ( GEOSException & )
2772 atLeastTwoIntersections =
false;
2776 if ( oneIntersection )
2777 return _mergeLinestrings( line, reshapeLineGeos, oneIntersectionPoint );
2779 if ( !atLeastTwoIntersections )
2783 double x1, y1, x2, y2;
2784 if ( !_linestringEndpoints( line, x1, y1, x2, y2 ) )
2790 bool isRing =
false;
2791 if ( GEOSGeomTypeId_r( geosinit()->ctxt, line ) == GEOS_LINEARRING
2792 || GEOSEquals_r( geosinit()->ctxt, beginLineVertex.get(), endLineVertex.get() ) == 1 )
2797 if ( !nodedGeometry )
2803 geos::unique_ptr mergedLines( GEOSLineMerge_r( geosinit()->ctxt, nodedGeometry.get() ) );
2809 int numMergedLines = GEOSGetNumGeometries_r( geosinit()->ctxt, mergedLines.get() );
2810 if ( numMergedLines < 2 )
2812 if ( numMergedLines == 1 )
2814 geos::unique_ptr result( GEOSGeom_clone_r( geosinit()->ctxt, reshapeLineGeos ) );
2821 QVector<GEOSGeometry *> resultLineParts;
2822 QVector<GEOSGeometry *> probableParts;
2824 for (
int i = 0; i < numMergedLines; ++i )
2826 const GEOSGeometry *currentGeom = GEOSGetGeometryN_r( geosinit()->ctxt, mergedLines.get(), i );
2829 bool alreadyAdded =
false;
2831 double bufferDistance = std::pow( 10.0L, geomDigits( currentGeom ) - 11 );
2832 for (
const GEOSGeometry *other : std::as_const( resultLineParts ) )
2834 GEOSHausdorffDistance_r( geosinit()->ctxt, currentGeom, other, &
distance );
2837 alreadyAdded =
true;
2844 const GEOSCoordSequence *currentCoordSeq = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, currentGeom );
2845 unsigned int currentCoordSeqSize;
2846 GEOSCoordSeq_getSize_r( geosinit()->ctxt, currentCoordSeq, ¤tCoordSeqSize );
2847 if ( currentCoordSeqSize < 2 )
2851 double xBegin, xEnd, yBegin, yEnd;
2852 GEOSCoordSeq_getX_r( geosinit()->ctxt, currentCoordSeq, 0, &xBegin );
2853 GEOSCoordSeq_getY_r( geosinit()->ctxt, currentCoordSeq, 0, &yBegin );
2854 GEOSCoordSeq_getX_r( geosinit()->ctxt, currentCoordSeq, currentCoordSeqSize - 1, &xEnd );
2855 GEOSCoordSeq_getY_r( geosinit()->ctxt, currentCoordSeq, currentCoordSeqSize - 1, &yEnd );
2860 int nEndpointsOnOriginalLine = 0;
2861 if ( pointContainedInLine( beginCurrentGeomVertex.get(), line ) == 1 )
2862 nEndpointsOnOriginalLine += 1;
2864 if ( pointContainedInLine( endCurrentGeomVertex.get(), line ) == 1 )
2865 nEndpointsOnOriginalLine += 1;
2868 int nEndpointsSameAsOriginalLine = 0;
2869 if ( GEOSEquals_r( geosinit()->ctxt, beginCurrentGeomVertex.get(), beginLineVertex.get() ) == 1
2870 || GEOSEquals_r( geosinit()->ctxt, beginCurrentGeomVertex.get(), endLineVertex.get() ) == 1 )
2871 nEndpointsSameAsOriginalLine += 1;
2873 if ( GEOSEquals_r( geosinit()->ctxt, endCurrentGeomVertex.get(), beginLineVertex.get() ) == 1
2874 || GEOSEquals_r( geosinit()->ctxt, endCurrentGeomVertex.get(), endLineVertex.get() ) == 1 )
2875 nEndpointsSameAsOriginalLine += 1;
2878 bool currentGeomOverlapsOriginalGeom =
false;
2879 bool currentGeomOverlapsReshapeLine =
false;
2880 if ( lineContainedInLine( currentGeom, line ) == 1 )
2881 currentGeomOverlapsOriginalGeom =
true;
2883 if ( lineContainedInLine( currentGeom, reshapeLineGeos ) == 1 )
2884 currentGeomOverlapsReshapeLine =
true;
2887 if ( !isRing && nEndpointsSameAsOriginalLine == 1 && nEndpointsOnOriginalLine == 2 && currentGeomOverlapsOriginalGeom )
2889 resultLineParts.push_back( GEOSGeom_clone_r( geosinit()->ctxt, currentGeom ) );
2892 else if ( isRing && nEndpointsOnOriginalLine == 2 && currentGeomOverlapsOriginalGeom )
2894 probableParts.push_back( GEOSGeom_clone_r( geosinit()->ctxt, currentGeom ) );
2896 else if ( nEndpointsOnOriginalLine == 2 && !currentGeomOverlapsOriginalGeom )
2898 resultLineParts.push_back( GEOSGeom_clone_r( geosinit()->ctxt, currentGeom ) );
2900 else if ( nEndpointsSameAsOriginalLine == 2 && !currentGeomOverlapsOriginalGeom )
2902 resultLineParts.push_back( GEOSGeom_clone_r( geosinit()->ctxt, currentGeom ) );
2904 else if ( currentGeomOverlapsOriginalGeom && currentGeomOverlapsReshapeLine )
2906 resultLineParts.push_back( GEOSGeom_clone_r( geosinit()->ctxt, currentGeom ) );
2911 if ( isRing && !probableParts.isEmpty() )
2914 GEOSGeometry *currentGeom =
nullptr;
2915 double maxLength = -std::numeric_limits<double>::max();
2916 double currentLength = 0;
2917 for (
int i = 0; i < probableParts.size(); ++i )
2919 currentGeom = probableParts.at( i );
2920 GEOSLength_r( geosinit()->ctxt, currentGeom, ¤tLength );
2921 if ( currentLength > maxLength )
2923 maxLength = currentLength;
2924 maxGeom.reset( currentGeom );
2928 GEOSGeom_destroy_r( geosinit()->ctxt, currentGeom );
2931 resultLineParts.push_back( maxGeom.release() );
2935 if ( resultLineParts.empty() )
2938 if ( resultLineParts.size() == 1 )
2940 result.reset( resultLineParts[0] );
2944 GEOSGeometry **lineArray =
new GEOSGeometry*[resultLineParts.size()];
2945 for (
int i = 0; i < resultLineParts.size(); ++i )
2947 lineArray[i] = resultLineParts[i];
2951 geos::unique_ptr multiLineGeom( GEOSGeom_createCollection_r( geosinit()->ctxt, GEOS_MULTILINESTRING, lineArray, resultLineParts.size() ) );
2952 delete [] lineArray;
2955 result.reset( GEOSLineMerge_r( geosinit()->ctxt, multiLineGeom.get() ) );
2959 if ( GEOSGeomTypeId_r( geosinit()->ctxt, result.get() ) != GEOS_LINESTRING )
2967 geos::unique_ptr QgsGeos::reshapePolygon(
const GEOSGeometry *polygon,
const GEOSGeometry *reshapeLineGeos,
double precision )
2970 int nIntersections = 0;
2971 int lastIntersectingRing = -2;
2972 const GEOSGeometry *lastIntersectingGeom =
nullptr;
2974 int nRings = GEOSGetNumInteriorRings_r( geosinit()->ctxt, polygon );
2979 const GEOSGeometry *outerRing = GEOSGetExteriorRing_r( geosinit()->ctxt, polygon );
2980 if ( GEOSIntersects_r( geosinit()->ctxt, outerRing, reshapeLineGeos ) == 1 )
2983 lastIntersectingRing = -1;
2984 lastIntersectingGeom = outerRing;
2988 const GEOSGeometry **innerRings =
new const GEOSGeometry*[nRings];
2992 for (
int i = 0; i < nRings; ++i )
2994 innerRings[i] = GEOSGetInteriorRingN_r( geosinit()->ctxt, polygon, i );
2995 if ( GEOSIntersects_r( geosinit()->ctxt, innerRings[i], reshapeLineGeos ) == 1 )
2998 lastIntersectingRing = i;
2999 lastIntersectingGeom = innerRings[i];
3003 catch ( GEOSException & )
3008 if ( nIntersections != 1 )
3010 delete [] innerRings;
3016 if ( !reshapeResult )
3018 delete [] innerRings;
3023 GEOSGeometry *newRing =
nullptr;
3024 const GEOSCoordSequence *reshapeSequence = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, reshapeResult.get() );
3025 GEOSCoordSequence *newCoordSequence = GEOSCoordSeq_clone_r( geosinit()->ctxt, reshapeSequence );
3027 reshapeResult.reset();
3029 newRing = GEOSGeom_createLinearRing_r( geosinit()->ctxt, newCoordSequence );
3032 delete [] innerRings;
3036 GEOSGeometry *newOuterRing =
nullptr;
3037 if ( lastIntersectingRing == -1 )
3038 newOuterRing = newRing;
3040 newOuterRing = GEOSGeom_clone_r( geosinit()->ctxt, outerRing );
3043 QVector<GEOSGeometry *> ringList;
3046 GEOSGeometry *outerRingPoly = GEOSGeom_createPolygon_r( geosinit()->ctxt, GEOSGeom_clone_r( geosinit()->ctxt, newOuterRing ),
nullptr, 0 );
3047 if ( outerRingPoly )
3049 ringList.reserve( nRings );
3050 GEOSGeometry *currentRing =
nullptr;
3051 for (
int i = 0; i < nRings; ++i )
3053 if ( lastIntersectingRing == i )
3054 currentRing = newRing;
3056 currentRing = GEOSGeom_clone_r( geosinit()->ctxt, innerRings[i] );
3059 if ( GEOSContains_r( geosinit()->ctxt, outerRingPoly, currentRing ) == 1 )
3060 ringList.push_back( currentRing );
3062 GEOSGeom_destroy_r( geosinit()->ctxt, currentRing );
3065 GEOSGeom_destroy_r( geosinit()->ctxt, outerRingPoly );
3068 GEOSGeometry **newInnerRings =
new GEOSGeometry*[ringList.size()];
3069 for (
int i = 0; i < ringList.size(); ++i )
3070 newInnerRings[i] = ringList.at( i );
3072 delete [] innerRings;
3074 geos::unique_ptr reshapedPolygon( GEOSGeom_createPolygon_r( geosinit()->ctxt, newOuterRing, newInnerRings, ringList.size() ) );
3075 delete[] newInnerRings;
3077 return reshapedPolygon;
3080 int QgsGeos::lineContainedInLine(
const GEOSGeometry *line1,
const GEOSGeometry *line2 )
3082 if ( !line1 || !line2 )
3087 double bufferDistance = std::pow( 10.0L, geomDigits( line2 ) - 11 );
3093 geos::unique_ptr intersectionGeom( GEOSIntersection_r( geosinit()->ctxt, bufferGeom.get(), line1 ) );
3096 double intersectGeomLength;
3099 GEOSLength_r( geosinit()->ctxt, intersectionGeom.get(), &intersectGeomLength );
3100 GEOSLength_r( geosinit()->ctxt, line1, &line1Length );
3102 double intersectRatio = line1Length / intersectGeomLength;
3103 if ( intersectRatio > 0.9 && intersectRatio < 1.1 )
3109 int QgsGeos::pointContainedInLine(
const GEOSGeometry *point,
const GEOSGeometry *line )
3111 if ( !point || !line )
3114 double bufferDistance = std::pow( 10.0L, geomDigits( line ) - 11 );
3116 geos::unique_ptr lineBuffer( GEOSBuffer_r( geosinit()->ctxt, line, bufferDistance, 8 ) );
3120 bool contained =
false;
3121 if ( GEOSContains_r( geosinit()->ctxt, lineBuffer.get(), point ) == 1 )
3127 int QgsGeos::geomDigits(
const GEOSGeometry *geom )
3133 const GEOSGeometry *bBoxRing = GEOSGetExteriorRing_r( geosinit()->ctxt, bbox.get() );
3137 const GEOSCoordSequence *bBoxCoordSeq = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, bBoxRing );
3139 if ( !bBoxCoordSeq )
3142 unsigned int nCoords = 0;
3143 if ( !GEOSCoordSeq_getSize_r( geosinit()->ctxt, bBoxCoordSeq, &nCoords ) )
3147 for (
unsigned int i = 0; i < nCoords - 1; ++i )
3150 GEOSCoordSeq_getX_r( geosinit()->ctxt, bBoxCoordSeq, i, &t );
3153 digits = std::ceil( std::log10( std::fabs( t ) ) );
3154 if ( digits > maxDigits )
3157 GEOSCoordSeq_getY_r( geosinit()->ctxt, bBoxCoordSeq, i, &t );
3158 digits = std::ceil( std::log10( std::fabs( t ) ) );
3159 if ( digits > maxDigits )
3168 return geosinit()->ctxt;
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 QgsGeometry::OperationResult 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.
OperationResult
Success or failure of a geometry operation.
@ InvalidBaseGeometry
The base geometry on which the operation is done is invalid or empty.
@ AddPartNotMultiGeometry
The source geometry is not multi.
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.
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.
static QgsGeometry::OperationResult addPart(QgsGeometry &geometry, GEOSGeometry *newPart)
Adds a new island polygon to a multipolygon feature.
QgsGeometry shortestLine(const QgsGeometry &other, QString *errorMsg=nullptr) const
Returns the shortest line joining this geometry to the other geometry.
QgsAbstractGeometry * offsetCurve(double distance, int segments, int joinStyle, double miterLimit, QString *errorMsg=nullptr) const override
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.
std::unique_ptr< QgsAbstractGeometry > singleSidedBuffer(double distance, int segments, int side, int joinStyle, double miterLimit, QString *errorMsg=nullptr) const
Returns a single sided buffer for a geometry.
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 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...
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
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.