31#define DEFAULT_QUADRANT_SEGMENTS 8
33#define CATCH_GEOS(r) \
34 catch (GEOSException &) \
39#define CATCH_GEOS_WITH_ERRMSG(r) \
40 catch (GEOSException &e) \
44 *errorMsg = e.what(); \
51static void throwGEOSException(
const char *fmt, ... )
57 vsnprintf( buffer,
sizeof buffer, fmt, ap );
60 QString message = QString::fromUtf8( buffer );
70 throw GEOSException( message );
78 throw GEOSException( message );
83static void printGEOSNotice(
const char *fmt, ... )
90 vsnprintf( buffer,
sizeof buffer, fmt, ap );
100 GEOSContextHandle_t ctxt;
104 ctxt = initGEOS_r( printGEOSNotice, throwGEOSException );
109 finishGEOS_r( ctxt );
112 GEOSInit(
const GEOSInit &rh ) =
delete;
113 GEOSInit &operator=(
const GEOSInit &rh ) =
delete;
120 GEOSGeom_destroy_r( geosinit()->ctxt, geom );
125 GEOSPreparedGeom_destroy_r( geosinit()->ctxt, geom );
130 GEOSBufferParams_destroy_r( geosinit()->ctxt, params );
135 GEOSCoordSeq_destroy_r( geosinit()->ctxt, sequence );
163#if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=8 )
164std::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() ) );
226void 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 geos::unique_ptr point = createGeosPointXY( x, y,
false, 0,
false, 0, 2, 0 );
492#if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=9 )
495 GEOSPreparedDistance_r( geosinit()->ctxt, mGeosPrepared.get(), point.get(), &
distance );
499 GEOSDistance_r( geosinit()->ctxt, mGeos.get(), point.get(), &
distance );
502 GEOSDistance_r( geosinit()->ctxt, mGeos.get(), point.get(), &
distance );
518 if ( !otherGeosGeom )
531#if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=9 )
534#if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=10 )
535 return GEOSPreparedDistanceWithin_r( geosinit()->ctxt, mGeosPrepared.get(), otherGeosGeom.get(), maxdist );
537 GEOSPreparedDistance_r( geosinit()->ctxt, mGeosPrepared.get(), otherGeosGeom.get(), &
distance );
542#if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=10 )
543 return GEOSDistanceWithin_r( geosinit()->ctxt, mGeos.get(), otherGeosGeom.get(), maxdist );
545 GEOSDistance_r( geosinit()->ctxt, mGeos.get(), otherGeosGeom.get(), &
distance );
549 GEOSDistance_r( geosinit()->ctxt, mGeos.get(), otherGeosGeom.get(), &
distance );
559 geos::unique_ptr point = createGeosPointXY( x, y,
false, 0,
false, 0, 2, 0 );
568 return GEOSPreparedContains_r( geosinit()->ctxt, mGeosPrepared.get(), point.get() ) == 1;
571 result = ( GEOSContains_r( geosinit()->ctxt, mGeos.get(), point.get() ) == 1 );
573 catch ( GEOSException &e )
575 logError( QStringLiteral(
"GEOS" ), e.what() );
578 *errorMsg = e.what();
595 if ( !otherGeosGeom )
602 GEOSHausdorffDistance_r( geosinit()->ctxt, mGeos.get(), otherGeosGeom.get(), &
distance );
618 if ( !otherGeosGeom )
625 GEOSHausdorffDistanceDensify_r( geosinit()->ctxt, mGeos.get(), otherGeosGeom.get(), densifyFraction, &
distance );
634#if GEOS_VERSION_MAJOR==3 && GEOS_VERSION_MINOR<7
637 throw QgsNotSupportedException( QStringLiteral(
"Calculating frechetDistance requires a QGIS build based on GEOS 3.7 or later" ) );
646 if ( !otherGeosGeom )
653 GEOSFrechetDistance_r( geosinit()->ctxt, mGeos.get(), otherGeosGeom.get(), &
distance );
663#if GEOS_VERSION_MAJOR==3 && GEOS_VERSION_MINOR<7
665 ( void )densifyFraction;
667 throw QgsNotSupportedException( QStringLiteral(
"Calculating frechetDistanceDensify requires a QGIS build based on GEOS 3.7 or later" ) );
676 if ( !otherGeosGeom )
683 GEOSFrechetDistanceDensify_r( geosinit()->ctxt, mGeos.get(), otherGeosGeom.get(), densifyFraction, &
distance );
693 return relation( geom, RelationIntersects, errorMsg );
698 return relation( geom, RelationTouches, errorMsg );
703 return relation( geom, RelationCrosses, errorMsg );
708 return relation( geom, RelationWithin, errorMsg );
713 return relation( geom, RelationOverlaps, errorMsg );
718 return relation( geom, RelationContains, errorMsg );
723 return relation( geom, RelationDisjoint, errorMsg );
742 char *r = GEOSRelate_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() );
745 result = QString( r );
746 GEOSFree_r( geosinit()->ctxt, r );
749 catch ( GEOSException &e )
751 logError( QStringLiteral(
"GEOS" ), e.what() );
754 *errorMsg = e.what();
763 if ( !mGeos || !geom )
777 result = ( GEOSRelatePattern_r( geosinit()->ctxt, mGeos.get(), geosGeom.get(), pattern.toLocal8Bit().constData() ) == 1 );
779 catch ( GEOSException &e )
781 logError( QStringLiteral(
"GEOS" ), e.what() );
784 *errorMsg = e.what();
801 if ( GEOSArea_r( geosinit()->ctxt, mGeos.get(), &
area ) != 1 )
817 if ( GEOSLength_r( geosinit()->ctxt, mGeos.get(), &
length ) != 1 )
825 QVector<QgsGeometry> &newGeometries,
828 QString *errorMsg,
bool skipIntersectionCheck )
const
843 if ( !GEOSisValid_r( geosinit()->ctxt, mGeos.get() ) )
851 newGeometries.clear();
858 splitLineGeos = createGeosLinestring( &splitLine, mPrecision );
862 splitLineGeos = createGeosPointXY( splitLine.
xAt( 0 ), splitLine.
yAt( 0 ),
false, 0,
false, 0, 2, mPrecision );
869 if ( !GEOSisValid_r( geosinit()->ctxt, splitLineGeos.get() ) || !GEOSisSimple_r( geosinit()->ctxt, splitLineGeos.get() ) )
877 if ( !topologicalTestPointsSplit( splitLineGeos.get(), topologyTestPoints ) )
886 returnCode = splitLinearGeometry( splitLineGeos.get(), newGeometries, skipIntersectionCheck );
890 returnCode = splitPolygonGeometry( splitLineGeos.get(), newGeometries, skipIntersectionCheck );
904bool QgsGeos::topologicalTestPointsSplit(
const GEOSGeometry *splitLine,
QgsPointSequence &testPoints, QString *errorMsg )
const
918 geos::unique_ptr intersectionGeom( GEOSIntersection_r( geosinit()->ctxt, mGeos.get(), splitLine ) );
919 if ( !intersectionGeom )
923 int nIntersectGeoms = 1;
924 if ( GEOSGeomTypeId_r( geosinit()->ctxt, intersectionGeom.get() ) == GEOS_LINESTRING
925 || GEOSGeomTypeId_r( geosinit()->ctxt, intersectionGeom.get() ) == GEOS_POINT )
929 nIntersectGeoms = GEOSGetNumGeometries_r( geosinit()->ctxt, intersectionGeom.get() );
931 for (
int i = 0; i < nIntersectGeoms; ++i )
933 const GEOSGeometry *currentIntersectGeom =
nullptr;
935 currentIntersectGeom = intersectionGeom.get();
937 currentIntersectGeom = GEOSGetGeometryN_r( geosinit()->ctxt, intersectionGeom.get(), i );
939 const GEOSCoordSequence *lineSequence = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, currentIntersectGeom );
940 unsigned int sequenceSize = 0;
942 if ( GEOSCoordSeq_getSize_r( geosinit()->ctxt, lineSequence, &sequenceSize ) != 0 )
944 for (
unsigned int i = 0; i < sequenceSize; ++i )
946 if ( GEOSCoordSeq_getX_r( geosinit()->ctxt, lineSequence, i, &x ) != 0 )
948 if ( GEOSCoordSeq_getY_r( geosinit()->ctxt, lineSequence, i, &y ) != 0 )
950 testPoints.push_back(
QgsPoint( x, y ) );
964 int type = GEOSGeomTypeId_r( geosinit()->ctxt, mGeos.get() );
966 std::unique_ptr< QgsMultiCurve > multiCurve;
967 if ( type == GEOS_MULTILINESTRING )
969 multiCurve.reset( qgsgeometry_cast<QgsMultiCurve *>(
mGeometry->
clone() ) );
971 else if ( type == GEOS_LINESTRING )
989 std::unique_ptr< QgsAbstractGeometry > splitGeom(
fromGeos( GEOSsplitPoint ) );
990 std::unique_ptr< QgsMultiPoint > splitPoints( qgsgeometry_cast<QgsMultiPoint *>( splitGeom->clone() ) );
993 QgsPoint *splitPoint = qgsgeometry_cast<QgsPoint *>( splitGeom->clone() );
999 splitPoints->addGeometry( splitPoint );
1005 for (
int i = 0; i < multiCurve->numGeometries(); ++i )
1007 const QgsLineString *line = qgsgeometry_cast<const QgsLineString *>( multiCurve->geometryN( i ) );
1010 const QgsCurve *curve = qgsgeometry_cast<const QgsCurve *>( multiCurve->geometryN( i ) );
1018 QMap< int, QVector< QPair< double, QgsPoint > > >pointMap;
1019 for (
int p = 0; p < splitPoints->numGeometries(); ++p )
1021 const QgsPoint *intersectionPoint = splitPoints->pointN( p );
1026 line->
closestSegment( *intersectionPoint, segmentPoint2D, nextVertex );
1029 std::unique_ptr< QgsPoint > correctSegmentPoint(
segment.interpolatePoint(
distance ) );
1030 const QPair< double, QgsPoint > pair = qMakePair(
distance, *correctSegmentPoint.get() );
1031 if ( pointMap.contains( nextVertex.
vertex - 1 ) )
1032 pointMap[ nextVertex.
vertex - 1 ].append( pair );
1034 pointMap[ nextVertex.
vertex - 1 ] = QVector< QPair< double, QgsPoint > >() << pair;
1039 for (
auto &p : pointMap )
1041 std::sort( p.begin(), p.end(), [](
const QPair< double, QgsPoint > &a,
const QPair< double, QgsPoint > &b ) { return a.first < b.first; } );
1048 for (
int j = 0; j < nVertices; ++j )
1052 if ( pointMap.contains( j ) )
1055 for (
int k = 0; k < pointMap[ j ].size(); ++k )
1057 splitPoint = pointMap[ j ][k].second;
1058 if ( splitPoint == currentPoint )
1064 else if ( splitPoint == line->
pointN( j + 1 ) )
1083 return asGeos( &lines, mPrecision );
1088 Q_UNUSED( skipIntersectionCheck )
1095 geos::unique_ptr intersectGeom( GEOSIntersection_r( geosinit()->ctxt, splitLine, mGeos.get() ) );
1096 if ( !intersectGeom )
1100 int linearIntersect = GEOSRelatePattern_r( geosinit()->ctxt, mGeos.get(), splitLine,
"1********" );
1101 if ( linearIntersect > 0 )
1105 splitGeom = linePointDifference( intersectGeom.get() );
1110 QVector<GEOSGeometry *> lineGeoms;
1112 int splitType = GEOSGeomTypeId_r( geosinit()->ctxt, splitGeom.get() );
1113 if ( splitType == GEOS_MULTILINESTRING )
1115 int nGeoms = GEOSGetNumGeometries_r( geosinit()->ctxt, splitGeom.get() );
1116 lineGeoms.reserve( nGeoms );
1117 for (
int i = 0; i < nGeoms; ++i )
1118 lineGeoms << GEOSGeom_clone_r( geosinit()->ctxt, GEOSGetGeometryN_r( geosinit()->ctxt, splitGeom.get(), i ) );
1123 lineGeoms << GEOSGeom_clone_r( geosinit()->ctxt, splitGeom.get() );
1126 mergeGeometriesMultiTypeSplit( lineGeoms );
1128 for (
int i = 0; i < lineGeoms.size(); ++i )
1131 GEOSGeom_destroy_r( geosinit()->ctxt, lineGeoms[i] );
1147 if ( !mGeosPrepared )
1151 if ( !skipIntersectionCheck && !GEOSPreparedIntersects_r( geosinit()->ctxt, mGeosPrepared.get(), splitLine ) )
1156 if ( !nodedGeometry )
1159 const GEOSGeometry *noded = nodedGeometry.get();
1160 geos::unique_ptr polygons( GEOSPolygonize_r( geosinit()->ctxt, &noded, 1 ) );
1161 if ( !polygons || numberOfGeometries( polygons.get() ) == 0 )
1168 QVector<GEOSGeometry *> testedGeometries;
1173 for (
int i = 0; i < numberOfGeometries( polygons.get() ); i++ )
1175 const GEOSGeometry *polygon = GEOSGetGeometryN_r( geosinit()->ctxt, polygons.get(), i );
1179 testedGeometries << GEOSGeom_clone_r( geosinit()->ctxt, polygon );
1182 int nGeometriesThis = numberOfGeometries( mGeos.get() );
1183 if ( testedGeometries.empty() || testedGeometries.size() == nGeometriesThis )
1186 for (
int i = 0; i < testedGeometries.size(); ++i )
1188 GEOSGeom_destroy_r( geosinit()->ctxt, testedGeometries[i] );
1197 mergeGeometriesMultiTypeSplit( testedGeometries );
1200 for ( i = 0; i < testedGeometries.size() && GEOSisValid_r( geosinit()->ctxt, testedGeometries[i] ); ++i )
1203 if ( i < testedGeometries.size() )
1205 for ( i = 0; i < testedGeometries.size(); ++i )
1206 GEOSGeom_destroy_r( geosinit()->ctxt, testedGeometries[i] );
1211 for ( i = 0; i < testedGeometries.size(); ++i )
1214 GEOSGeom_destroy_r( geosinit()->ctxt, testedGeometries[i] );
1220geos::unique_ptr QgsGeos::nodeGeometries(
const GEOSGeometry *splitLine,
const GEOSGeometry *geom )
1222 if ( !splitLine || !geom )
1226 if ( GEOSGeomTypeId_r( geosinit()->ctxt, geom ) == GEOS_POLYGON || GEOSGeomTypeId_r( geosinit()->ctxt, geom ) == GEOS_MULTIPOLYGON )
1227 geometryBoundary.reset( GEOSBoundary_r( geosinit()->ctxt, geom ) );
1229 geometryBoundary.reset( GEOSGeom_clone_r( geosinit()->ctxt, geom ) );
1231 geos::unique_ptr splitLineClone( GEOSGeom_clone_r( geosinit()->ctxt, splitLine ) );
1232 geos::unique_ptr unionGeometry( GEOSUnion_r( geosinit()->ctxt, splitLineClone.get(), geometryBoundary.get() ) );
1234 return unionGeometry;
1237int QgsGeos::mergeGeometriesMultiTypeSplit( QVector<GEOSGeometry *> &splitResult )
const
1243 int type = GEOSGeomTypeId_r( geosinit()->ctxt, mGeos.get() );
1244 if ( type != GEOS_GEOMETRYCOLLECTION &&
1245 type != GEOS_MULTILINESTRING &&
1246 type != GEOS_MULTIPOLYGON &&
1247 type != GEOS_MULTIPOINT )
1250 QVector<GEOSGeometry *> copyList = splitResult;
1251 splitResult.clear();
1254 QVector<GEOSGeometry *> unionGeom;
1256 for (
int i = 0; i < copyList.size(); ++i )
1259 bool isPart =
false;
1260 for (
int j = 0; j < GEOSGetNumGeometries_r( geosinit()->ctxt, mGeos.get() ); j++ )
1262 if ( GEOSEquals_r( geosinit()->ctxt, copyList[i], GEOSGetGeometryN_r( geosinit()->ctxt, mGeos.get(), j ) ) )
1271 unionGeom << copyList[i];
1275 QVector<GEOSGeometry *> geomVector;
1276 geomVector << copyList[i];
1278 if ( type == GEOS_MULTILINESTRING )
1279 splitResult << createGeosCollection( GEOS_MULTILINESTRING, geomVector ).release();
1280 else if ( type == GEOS_MULTIPOLYGON )
1281 splitResult << createGeosCollection( GEOS_MULTIPOLYGON, geomVector ).release();
1283 GEOSGeom_destroy_r( geosinit()->ctxt, copyList[i] );
1288 if ( !unionGeom.isEmpty() )
1290 if ( type == GEOS_MULTILINESTRING )
1291 splitResult << createGeosCollection( GEOS_MULTILINESTRING, unionGeom ).release();
1292 else if ( type == GEOS_MULTIPOLYGON )
1293 splitResult << createGeosCollection( GEOS_MULTIPOLYGON, unionGeom ).release();
1303geos::unique_ptr QgsGeos::createGeosCollection(
int typeId,
const QVector<GEOSGeometry *> &geoms )
1305 int nNullGeoms = geoms.count(
nullptr );
1306 int nNotNullGeoms = geoms.size() - nNullGeoms;
1308 GEOSGeometry **geomarr =
new GEOSGeometry*[ nNotNullGeoms ];
1315 QVector<GEOSGeometry *>::const_iterator geomIt = geoms.constBegin();
1316 for ( ; geomIt != geoms.constEnd(); ++geomIt )
1320 if ( GEOSisEmpty_r( geosinit()->ctxt, *geomIt ) )
1325 GEOSGeom_destroy_r( geosinit()->ctxt, *geomIt );
1329 geomarr[i] = *geomIt;
1338 geom.reset( GEOSGeom_createCollection_r( geosinit()->ctxt, typeId, geomarr, nNotNullGeoms ) );
1340 catch ( GEOSException & )
1356 int nCoordDims = GEOSGeom_getCoordinateDimension_r( geosinit()->ctxt,
geos );
1357 int nDims = GEOSGeom_getDimensions_r( geosinit()->ctxt,
geos );
1358 bool hasZ = ( nCoordDims == 3 );
1359 bool hasM = ( ( nDims - nCoordDims ) == 1 );
1361 switch ( GEOSGeomTypeId_r( geosinit()->ctxt,
geos ) )
1365 if ( GEOSisEmpty_r( geosinit()->ctxt,
geos ) )
1368 const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq_r( geosinit()->ctxt,
geos );
1369 unsigned int nPoints = 0;
1370 GEOSCoordSeq_getSize_r( geosinit()->ctxt, cs, &nPoints );
1371 return nPoints > 0 ? std::unique_ptr<QgsAbstractGeometry>(
coordSeqPoint( cs, 0, hasZ, hasM ).clone() ) :
nullptr;
1373 case GEOS_LINESTRING:
1375 return sequenceToLinestring(
geos, hasZ, hasM );
1381 case GEOS_MULTIPOINT:
1383 std::unique_ptr< QgsMultiPoint > multiPoint(
new QgsMultiPoint() );
1384 int nParts = GEOSGetNumGeometries_r( geosinit()->ctxt,
geos );
1385 multiPoint->reserve( nParts );
1386 for (
int i = 0; i < nParts; ++i )
1388 const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, GEOSGetGeometryN_r( geosinit()->ctxt,
geos, i ) );
1391 unsigned int nPoints = 0;
1392 GEOSCoordSeq_getSize_r( geosinit()->ctxt, cs, &nPoints );
1394 multiPoint->addGeometry(
coordSeqPoint( cs, 0, hasZ, hasM ).clone() );
1397 return std::move( multiPoint );
1399 case GEOS_MULTILINESTRING:
1402 int nParts = GEOSGetNumGeometries_r( geosinit()->ctxt,
geos );
1403 multiLineString->reserve( nParts );
1404 for (
int i = 0; i < nParts; ++i )
1406 std::unique_ptr< QgsLineString >line( sequenceToLinestring( GEOSGetGeometryN_r( geosinit()->ctxt,
geos, i ), hasZ, hasM ) );
1409 multiLineString->addGeometry( line.release() );
1412 return std::move( multiLineString );
1414 case GEOS_MULTIPOLYGON:
1416 std::unique_ptr< QgsMultiPolygon > multiPolygon(
new QgsMultiPolygon() );
1418 int nParts = GEOSGetNumGeometries_r( geosinit()->ctxt,
geos );
1419 multiPolygon->reserve( nParts );
1420 for (
int i = 0; i < nParts; ++i )
1422 std::unique_ptr< QgsPolygon > poly =
fromGeosPolygon( GEOSGetGeometryN_r( geosinit()->ctxt,
geos, i ) );
1425 multiPolygon->addGeometry( poly.release() );
1428 return std::move( multiPolygon );
1430 case GEOS_GEOMETRYCOLLECTION:
1433 int nParts = GEOSGetNumGeometries_r( geosinit()->ctxt,
geos );
1434 geomCollection->reserve( nParts );
1435 for (
int i = 0; i < nParts; ++i )
1437 std::unique_ptr< QgsAbstractGeometry > geom(
fromGeos( GEOSGetGeometryN_r( geosinit()->ctxt,
geos, i ) ) );
1440 geomCollection->addGeometry( geom.release() );
1443 return std::move( geomCollection );
1451 if ( GEOSGeomTypeId_r( geosinit()->ctxt,
geos ) != GEOS_POLYGON )
1456 int nCoordDims = GEOSGeom_getCoordinateDimension_r( geosinit()->ctxt,
geos );
1457 int nDims = GEOSGeom_getDimensions_r( geosinit()->ctxt,
geos );
1458 bool hasZ = ( nCoordDims == 3 );
1459 bool hasM = ( ( nDims - nCoordDims ) == 1 );
1461 std::unique_ptr< QgsPolygon > polygon(
new QgsPolygon() );
1463 const GEOSGeometry *ring = GEOSGetExteriorRing_r( geosinit()->ctxt,
geos );
1466 polygon->setExteriorRing( sequenceToLinestring( ring, hasZ, hasM ).release() );
1469 QVector<QgsCurve *> interiorRings;
1470 const int ringCount = GEOSGetNumInteriorRings_r( geosinit()->ctxt,
geos );
1471 interiorRings.reserve( ringCount );
1472 for (
int i = 0; i < ringCount; ++i )
1474 ring = GEOSGetInteriorRingN_r( geosinit()->ctxt,
geos, i );
1477 interiorRings.push_back( sequenceToLinestring( ring, hasZ, hasM ).release() );
1480 polygon->setInteriorRings( interiorRings );
1485std::unique_ptr<QgsLineString> QgsGeos::sequenceToLinestring(
const GEOSGeometry *
geos,
bool hasZ,
bool hasM )
1487 const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq_r( geosinit()->ctxt,
geos );
1488 unsigned int nPoints;
1489 GEOSCoordSeq_getSize_r( geosinit()->ctxt, cs, &nPoints );
1490 QVector< double > xOut( nPoints );
1491 QVector< double > yOut( nPoints );
1492 QVector< double > zOut;
1494 zOut.resize( nPoints );
1495 QVector< double > mOut;
1497 mOut.resize( nPoints );
1498 double *x = xOut.data();
1499 double *y = yOut.data();
1500 double *z = zOut.data();
1501 double *m = mOut.data();
1502 for (
unsigned int i = 0; i < nPoints; ++i )
1504#if GEOS_VERSION_MAJOR>3 || GEOS_VERSION_MINOR>=8
1506 GEOSCoordSeq_getXYZ_r( geosinit()->ctxt, cs, i, x++, y++, z++ );
1508 GEOSCoordSeq_getXY_r( geosinit()->ctxt, cs, i, x++, y++ );
1510 GEOSCoordSeq_getX_r( geosinit()->ctxt, cs, i, x++ );
1511 GEOSCoordSeq_getY_r( geosinit()->ctxt, cs, i, y++ );
1514 GEOSCoordSeq_getZ_r( geosinit()->ctxt, cs, i, z++ );
1519 GEOSCoordSeq_getOrdinate_r( geosinit()->ctxt, cs, i, 3, m++ );
1522 std::unique_ptr< QgsLineString > line(
new QgsLineString( xOut, yOut, zOut, mOut ) );
1526int QgsGeos::numberOfGeometries( GEOSGeometry *g )
1531 int geometryType = GEOSGeomTypeId_r( geosinit()->ctxt, g );
1532 if ( geometryType == GEOS_POINT || geometryType == GEOS_LINESTRING || geometryType == GEOS_LINEARRING
1533 || geometryType == GEOS_POLYGON )
1537 return GEOSGetNumGeometries_r( geosinit()->ctxt, g );
1550#if GEOS_VERSION_MAJOR>3 || GEOS_VERSION_MINOR>=8
1552 GEOSCoordSeq_getXYZ_r( geosinit()->ctxt, cs, i, &x, &y, &z );
1554 GEOSCoordSeq_getXY_r( geosinit()->ctxt, cs, i, &x, &y );
1556 GEOSCoordSeq_getX_r( geosinit()->ctxt, cs, i, &x );
1557 GEOSCoordSeq_getY_r( geosinit()->ctxt, cs, i, &y );
1560 GEOSCoordSeq_getZ_r( geosinit()->ctxt, cs, i, &z );
1565 GEOSCoordSeq_getOrdinate_r( geosinit()->ctxt, cs, i, 3, &m );
1601 int geosType = GEOS_GEOMETRYCOLLECTION;
1608 geosType = GEOS_MULTIPOINT;
1612 geosType = GEOS_MULTILINESTRING;
1616 geosType = GEOS_MULTIPOLYGON;
1631 QVector< GEOSGeometry * > geomVector(
c->numGeometries() );
1632 for (
int i = 0; i <
c->numGeometries(); ++i )
1636 return createGeosCollection( geosType, geomVector );
1643 return createGeosPoint(
static_cast<const QgsPoint *
>( geom ), coordDims,
precision );
1659std::unique_ptr<QgsAbstractGeometry> QgsGeos::overlay(
const QgsAbstractGeometry *geom, Overlay op, QString *errorMsg )
const
1661 if ( !mGeos || !geom )
1677 case OverlayIntersection:
1678 opGeom.reset( GEOSIntersection_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) );
1681 case OverlayDifference:
1682 opGeom.reset( GEOSDifference_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) );
1687 geos::unique_ptr unionGeometry( GEOSUnion_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) );
1689 if ( unionGeometry && GEOSGeomTypeId_r( geosinit()->ctxt, unionGeometry.get() ) == GEOS_MULTILINESTRING )
1691 geos::unique_ptr mergedLines( GEOSLineMerge_r( geosinit()->ctxt, unionGeometry.get() ) );
1694 unionGeometry = std::move( mergedLines );
1698 opGeom = std::move( unionGeometry );
1702 case OverlaySymDifference:
1703 opGeom.reset( GEOSSymDifference_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) );
1708 catch ( GEOSException &e )
1710 logError( QStringLiteral(
"GEOS" ), e.what() );
1713 *errorMsg = e.what();
1719bool QgsGeos::relation(
const QgsAbstractGeometry *geom, Relation r, QString *errorMsg )
const
1721 if ( !mGeos || !geom )
1732 bool result =
false;
1735 if ( mGeosPrepared )
1739 case RelationIntersects:
1740 result = ( GEOSPreparedIntersects_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1742 case RelationTouches:
1743 result = ( GEOSPreparedTouches_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1745 case RelationCrosses:
1746 result = ( GEOSPreparedCrosses_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1748 case RelationWithin:
1749 result = ( GEOSPreparedWithin_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1751 case RelationContains:
1752 result = ( GEOSPreparedContains_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1754 case RelationDisjoint:
1755 result = ( GEOSPreparedDisjoint_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1757 case RelationOverlaps:
1758 result = ( GEOSPreparedOverlaps_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1766 case RelationIntersects:
1767 result = ( GEOSIntersects_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1769 case RelationTouches:
1770 result = ( GEOSTouches_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1772 case RelationCrosses:
1773 result = ( GEOSCrosses_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1775 case RelationWithin:
1776 result = ( GEOSWithin_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1778 case RelationContains:
1779 result = ( GEOSContains_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1781 case RelationDisjoint:
1782 result = ( GEOSDisjoint_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1784 case RelationOverlaps:
1785 result = ( GEOSOverlaps_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1789 catch ( GEOSException &e )
1791 logError( QStringLiteral(
"GEOS" ), e.what() );
1794 *errorMsg = e.what();
1812 geos.reset( GEOSBuffer_r( geosinit()->ctxt, mGeos.get(),
distance, segments ) );
1828 geos.reset( GEOSBufferWithStyle_r( geosinit()->ctxt, mGeos.get(),
distance, segments,
static_cast< int >( endCapStyle ),
static_cast< int >( joinStyle ), miterLimit ) );
1843 geos.reset( GEOSTopologyPreserveSimplify_r( geosinit()->ctxt, mGeos.get(), tolerance ) );
1858 geos.reset( GEOSInterpolate_r( geosinit()->ctxt, mGeos.get(),
distance ) );
1877 geos.reset( GEOSGetCentroid_r( geosinit()->ctxt, mGeos.get() ) );
1882 GEOSGeomGetX_r( geosinit()->ctxt,
geos.get(), &x );
1883 GEOSGeomGetY_r( geosinit()->ctxt,
geos.get(), &y );
1899 geos.reset( GEOSEnvelope_r( geosinit()->ctxt, mGeos.get() ) );
1918 geos.reset( GEOSPointOnSurface_r( geosinit()->ctxt, mGeos.get() ) );
1920 if ( !
geos || GEOSisEmpty_r( geosinit()->ctxt,
geos.get() ) != 0 )
1925 GEOSGeomGetX_r( geosinit()->ctxt,
geos.get(), &x );
1926 GEOSGeomGetY_r( geosinit()->ctxt,
geos.get(), &y );
1942 geos::unique_ptr cHull( GEOSConvexHull_r( geosinit()->ctxt, mGeos.get() ) );
1943 std::unique_ptr< QgsAbstractGeometry > cHullGeom =
fromGeos( cHull.get() );
1944 return cHullGeom.release();
1958 GEOSGeometry *g1 =
nullptr;
1960 char res = GEOSisValidDetail_r( geosinit()->ctxt, mGeos.get(), allowSelfTouchingHoles ? GEOSVALID_ALLOW_SELFTOUCHING_RING_FORMING_HOLE : 0, &r, &g1 );
1961 const bool invalid = res != 1;
1966 error = QString( r );
1967 GEOSFree_r( geosinit()->ctxt, r );
1970 if ( invalid && errorMsg )
1974 if ( translatedErrors.empty() )
1977 translatedErrors.insert( QStringLiteral(
"topology validation error" ), QObject::tr(
"Topology validation error",
"GEOS Error" ) );
1978 translatedErrors.insert( QStringLiteral(
"repeated point" ), QObject::tr(
"Repeated point",
"GEOS Error" ) );
1979 translatedErrors.insert( QStringLiteral(
"hole lies outside shell" ), QObject::tr(
"Hole lies outside shell",
"GEOS Error" ) );
1980 translatedErrors.insert( QStringLiteral(
"holes are nested" ), QObject::tr(
"Holes are nested",
"GEOS Error" ) );
1981 translatedErrors.insert( QStringLiteral(
"interior is disconnected" ), QObject::tr(
"Interior is disconnected",
"GEOS Error" ) );
1982 translatedErrors.insert( QStringLiteral(
"self-intersection" ), QObject::tr(
"Self-intersection",
"GEOS Error" ) );
1983 translatedErrors.insert( QStringLiteral(
"ring self-intersection" ), QObject::tr(
"Ring self-intersection",
"GEOS Error" ) );
1984 translatedErrors.insert( QStringLiteral(
"nested shells" ), QObject::tr(
"Nested shells",
"GEOS Error" ) );
1985 translatedErrors.insert( QStringLiteral(
"duplicate rings" ), QObject::tr(
"Duplicate rings",
"GEOS Error" ) );
1986 translatedErrors.insert( QStringLiteral(
"too few points in geometry component" ), QObject::tr(
"Too few points in geometry component",
"GEOS Error" ) );
1987 translatedErrors.insert( QStringLiteral(
"invalid coordinate" ), QObject::tr(
"Invalid coordinate",
"GEOS Error" ) );
1988 translatedErrors.insert( QStringLiteral(
"ring is not closed" ), QObject::tr(
"Ring is not closed",
"GEOS Error" ) );
1991 *errorMsg = translatedErrors.value( error.toLower(), error );
1993 if ( g1 && errorLoc )
1999 GEOSGeom_destroy_r( geosinit()->ctxt, g1 );
2009 if ( !mGeos || !geom )
2021 bool equal = GEOSEquals_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() );
2036 return GEOSisEmpty_r( geosinit()->ctxt, mGeos.get() );
2050 return GEOSisSimple_r( geosinit()->ctxt, mGeos.get() );
2055GEOSCoordSequence *QgsGeos::createCoordinateSequence(
const QgsCurve *curve,
double precision,
bool forceClose )
2057 std::unique_ptr< QgsLineString > segmentized;
2058 const QgsLineString *line = qgsgeometry_cast<const QgsLineString *>( curve );
2063 line = segmentized.get();
2071 bool hasZ = line->
is3D();
2085 int numOutPoints = numPoints;
2086 if ( forceClose && ( line->
pointN( 0 ) != line->
pointN( numPoints - 1 ) ) )
2091 GEOSCoordSequence *coordSeq =
nullptr;
2094 coordSeq = GEOSCoordSeq_create_r( geosinit()->ctxt, numOutPoints, coordDims );
2097 QgsDebugMsg( QStringLiteral(
"GEOS Exception: Could not create coordinate sequence for %1 points in %2 dimensions" ).arg( numPoints ).arg( coordDims ) );
2101 const double *xData = line->
xData();
2102 const double *yData = line->
yData();
2103 const double *zData = hasZ ? line->
zData() :
nullptr;
2104 const double *mData = hasM ? line->
mData() :
nullptr;
2108 for (
int i = 0; i < numOutPoints; ++i )
2110 if ( i >= numPoints )
2113 xData = line->
xData();
2114 yData = line->
yData();
2115 zData = hasZ ? line->
zData() :
nullptr;
2116 mData = hasM ? line->
mData() :
nullptr;
2118#if GEOS_VERSION_MAJOR>3 || GEOS_VERSION_MINOR>=8
2128 GEOSCoordSeq_setX_r( geosinit()->ctxt, coordSeq, i, std::round( *xData++ /
precision ) *
precision );
2129 GEOSCoordSeq_setY_r( geosinit()->ctxt, coordSeq, i, std::round( *yData++ /
precision ) *
precision );
2132 GEOSCoordSeq_setOrdinate_r( geosinit()->ctxt, coordSeq, i, 2, std::round( *zData++ /
precision ) *
precision );
2137 GEOSCoordSeq_setOrdinate_r( geosinit()->ctxt, coordSeq, i, 3, line->
mAt( *mData++ ) );
2143 for (
int i = 0; i < numOutPoints; ++i )
2145 if ( i >= numPoints )
2148 xData = line->
xData();
2149 yData = line->
yData();
2150 zData = hasZ ? line->
zData() :
nullptr;
2151 mData = hasM ? line->
mData() :
nullptr;
2153#if GEOS_VERSION_MAJOR>3 || GEOS_VERSION_MINOR>=8
2156 GEOSCoordSeq_setXYZ_r( geosinit()->ctxt, coordSeq, i, *xData++, *yData++, *zData++ );
2160 GEOSCoordSeq_setXY_r( geosinit()->ctxt, coordSeq, i, *xData++, *yData++ );
2163 GEOSCoordSeq_setX_r( geosinit()->ctxt, coordSeq, i, *xData++ );
2164 GEOSCoordSeq_setY_r( geosinit()->ctxt, coordSeq, i, *yData++ );
2167 GEOSCoordSeq_setOrdinate_r( geosinit()->ctxt, coordSeq, i, 2, *zData++ );
2172 GEOSCoordSeq_setOrdinate_r( geosinit()->ctxt, coordSeq, i, 3, *mData++ );
2184 const QgsPoint *pt = qgsgeometry_cast<const QgsPoint *>( point );
2191geos::unique_ptr QgsGeos::createGeosPointXY(
double x,
double y,
bool hasZ,
double z,
bool hasM,
double m,
int coordDims,
double precision )
2199#if GEOS_VERSION_MAJOR>3 || GEOS_VERSION_MINOR>=8
2200 if ( coordDims == 2 )
2206 geosPoint.reset( GEOSGeom_createPointFromXY_r( geosinit()->ctxt, x, y ) );
2211 GEOSCoordSequence *coordSeq = GEOSCoordSeq_create_r( geosinit()->ctxt, 1, coordDims );
2214 QgsDebugMsg( QStringLiteral(
"GEOS Exception: Could not create coordinate sequence for point with %1 dimensions" ).arg( coordDims ) );
2219 GEOSCoordSeq_setX_r( geosinit()->ctxt, coordSeq, 0, std::round( x /
precision ) *
precision );
2220 GEOSCoordSeq_setY_r( geosinit()->ctxt, coordSeq, 0, std::round( y /
precision ) *
precision );
2223 GEOSCoordSeq_setOrdinate_r( geosinit()->ctxt, coordSeq, 0, 2, std::round( z /
precision ) *
precision );
2228 GEOSCoordSeq_setX_r( geosinit()->ctxt, coordSeq, 0, x );
2229 GEOSCoordSeq_setY_r( geosinit()->ctxt, coordSeq, 0, y );
2232 GEOSCoordSeq_setOrdinate_r( geosinit()->ctxt, coordSeq, 0, 2, z );
2238 GEOSCoordSeq_setOrdinate_r( geosinit()->ctxt, coordSeq, 0, 3, m );
2241 geosPoint.reset( GEOSGeom_createPoint_r( geosinit()->ctxt, coordSeq ) );
2249 const QgsCurve *
c = qgsgeometry_cast<const QgsCurve *>( curve );
2253 GEOSCoordSequence *coordSeq = createCoordinateSequence(
c,
precision );
2260 geosGeom.reset( GEOSGeom_createLineString_r( geosinit()->ctxt, coordSeq ) );
2268 const QgsCurvePolygon *polygon = qgsgeometry_cast<const QgsCurvePolygon *>( poly );
2273 if ( !exteriorRing )
2281 geos::unique_ptr exteriorRingGeos( GEOSGeom_createLinearRing_r( geosinit()->ctxt, createCoordinateSequence( exteriorRing,
precision,
true ) ) );
2284 GEOSGeometry **holes =
nullptr;
2287 holes =
new GEOSGeometry*[ nHoles ];
2290 for (
int i = 0; i < nHoles; ++i )
2293 holes[i] = GEOSGeom_createLinearRing_r( geosinit()->ctxt, createCoordinateSequence( interiorRing,
precision,
true ) );
2295 geosPolygon.reset( GEOSGeom_createPolygon_r( geosinit()->ctxt, exteriorRingGeos.release(), holes, nHoles ) );
2311 offset.reset( GEOSOffsetCurve_r( geosinit()->ctxt, mGeos.get(),
distance, segments,
static_cast< int >( joinStyle ), miterLimit ) );
2314 std::unique_ptr< QgsAbstractGeometry > offsetGeom =
fromGeos( offset.get() );
2315 return offsetGeom.release();
2329 GEOSBufferParams_setSingleSided_r( geosinit()->ctxt, bp.get(), 1 );
2330 GEOSBufferParams_setQuadrantSegments_r( geosinit()->ctxt, bp.get(), segments );
2331 GEOSBufferParams_setJoinStyle_r( geosinit()->ctxt, bp.get(),
static_cast< int >( joinStyle ) );
2332 GEOSBufferParams_setMitreLimit_r( geosinit()->ctxt, bp.get(), miterLimit );
2334 if ( side == Qgis::BufferSide::Right )
2338 geos.reset( GEOSBufferWithParams_r( geosinit()->ctxt, mGeos.get(), bp.get(),
distance ) );
2346#if GEOS_VERSION_MAJOR==3 && GEOS_VERSION_MINOR<9
2349 throw QgsNotSupportedException( QStringLiteral(
"Calculating maximumInscribedCircle requires a QGIS build based on GEOS 3.9 or later" ) );
2359 geos.reset( GEOSMaximumInscribedCircle_r( geosinit()->ctxt, mGeos.get(), tolerance ) );
2368#if GEOS_VERSION_MAJOR==3 && GEOS_VERSION_MINOR<9
2372 throw QgsNotSupportedException( QStringLiteral(
"Calculating largestEmptyCircle requires a QGIS build based on GEOS 3.9 or later" ) );
2384 boundaryGeos =
asGeos( boundary );
2386 geos.reset( GEOSLargestEmptyCircle_r( geosinit()->ctxt, mGeos.get(), boundaryGeos.get(), tolerance ) );
2395#if GEOS_VERSION_MAJOR==3 && GEOS_VERSION_MINOR<6
2397 throw QgsNotSupportedException( QStringLiteral(
"Calculating minimumWidth requires a QGIS build based on GEOS 3.6 or later" ) );
2407 geos.reset( GEOSMinimumWidth_r( geosinit()->ctxt, mGeos.get() ) );
2416#if GEOS_VERSION_MAJOR==3 && GEOS_VERSION_MINOR<6
2418 throw QgsNotSupportedException( QStringLiteral(
"Calculating minimumClearance requires a QGIS build based on GEOS 3.6 or later" ) );
2422 return std::numeric_limits< double >::quiet_NaN();
2429 if ( GEOSMinimumClearance_r( geosinit()->ctxt, mGeos.get(), &res ) != 0 )
2430 return std::numeric_limits< double >::quiet_NaN();
2439#if GEOS_VERSION_MAJOR==3 && GEOS_VERSION_MINOR<6
2441 throw QgsNotSupportedException( QStringLiteral(
"Calculating minimumClearanceLine requires a QGIS build based on GEOS 3.6 or later" ) );
2451 geos.reset( GEOSMinimumClearanceLine_r( geosinit()->ctxt, mGeos.get() ) );
2468 geos.reset( GEOSNode_r( geosinit()->ctxt, mGeos.get() ) );
2476 if ( !mGeos || !other )
2488 geos.reset( GEOSSharedPaths_r( geosinit()->ctxt, mGeos.get(), otherGeos.get() ) );
2508 geos::unique_ptr reshapeLineGeos = createGeosLinestring( &reshapeWithLine, mPrecision );
2511 int numGeoms = GEOSGetNumGeometries_r( geosinit()->ctxt, mGeos.get() );
2512 if ( numGeoms == -1 )
2521 bool isMultiGeom =
false;
2522 int geosTypeId = GEOSGeomTypeId_r( geosinit()->ctxt, mGeos.get() );
2523 if ( geosTypeId == GEOS_MULTILINESTRING || geosTypeId == GEOS_MULTIPOLYGON )
2533 reshapedGeometry = reshapeLine( mGeos.get(), reshapeLineGeos.get(), mPrecision );
2537 reshapedGeometry = reshapePolygon( mGeos.get(), reshapeLineGeos.get(), mPrecision );
2542 std::unique_ptr< QgsAbstractGeometry > reshapeResult =
fromGeos( reshapedGeometry.get() );
2543 return reshapeResult;
2550 bool reshapeTookPlace =
false;
2553 GEOSGeometry **newGeoms =
new GEOSGeometry*[numGeoms];
2555 for (
int i = 0; i < numGeoms; ++i )
2558 currentReshapeGeometry = reshapeLine( GEOSGetGeometryN_r( geosinit()->ctxt, mGeos.get(), i ), reshapeLineGeos.get(), mPrecision );
2560 currentReshapeGeometry = reshapePolygon( GEOSGetGeometryN_r( geosinit()->ctxt, mGeos.get(), i ), reshapeLineGeos.get(), mPrecision );
2562 if ( currentReshapeGeometry )
2564 newGeoms[i] = currentReshapeGeometry.release();
2565 reshapeTookPlace =
true;
2569 newGeoms[i] = GEOSGeom_clone_r( geosinit()->ctxt, GEOSGetGeometryN_r( geosinit()->ctxt, mGeos.get(), i ) );
2576 newMultiGeom.reset( GEOSGeom_createCollection_r( geosinit()->ctxt, GEOS_MULTILINESTRING, newGeoms, numGeoms ) );
2580 newMultiGeom.reset( GEOSGeom_createCollection_r( geosinit()->ctxt, GEOS_MULTIPOLYGON, newGeoms, numGeoms ) );
2584 if ( !newMultiGeom )
2590 if ( reshapeTookPlace )
2594 std::unique_ptr< QgsAbstractGeometry > reshapedMultiGeom =
fromGeos( newMultiGeom.get() );
2595 return reshapedMultiGeom;
2617 if ( GEOSGeomTypeId_r( geosinit()->ctxt, mGeos.get() ) != GEOS_MULTILINESTRING )
2623 geos.reset( GEOSLineMerge_r( geosinit()->ctxt, mGeos.get() ) );
2646#if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=9 )
2648 if ( mGeosPrepared )
2650 nearestCoord.reset( GEOSPreparedNearestPoints_r( geosinit()->ctxt, mGeosPrepared.get(), otherGeom.get() ) );
2654 nearestCoord.reset( GEOSNearestPoints_r( geosinit()->ctxt, mGeos.get(), otherGeom.get() ) );
2660 ( void )GEOSCoordSeq_getX_r( geosinit()->ctxt, nearestCoord.get(), 0, &nx );
2661 ( void )GEOSCoordSeq_getY_r( geosinit()->ctxt, nearestCoord.get(), 0, &ny );
2663 catch ( GEOSException &e )
2665 logError( QStringLiteral(
"GEOS" ), e.what() );
2668 *errorMsg = e.what();
2678 if ( !mGeos || other.
isEmpty() )
2688 if ( !other || other->
isEmpty() )
2705 if ( !nearestCoord )
2708 *errorMsg = QStringLiteral(
"GEOS returned no nearest points" );
2712 ( void )GEOSCoordSeq_getX_r( geosinit()->ctxt, nearestCoord.get(), 0, &nx1 );
2713 ( void )GEOSCoordSeq_getY_r( geosinit()->ctxt, nearestCoord.get(), 0, &ny1 );
2714 ( void )GEOSCoordSeq_getX_r( geosinit()->ctxt, nearestCoord.get(), 1, &nx2 );
2715 ( void )GEOSCoordSeq_getY_r( geosinit()->ctxt, nearestCoord.get(), 1, &ny2 );
2717 catch ( GEOSException &e )
2719 logError( QStringLiteral(
"GEOS" ), e.what() );
2722 *errorMsg = e.what();
2749 distance = GEOSProject_r( geosinit()->ctxt, mGeos.get(), otherGeom.get() );
2751 catch ( GEOSException &e )
2753 logError( QStringLiteral(
"GEOS" ), e.what() );
2756 *errorMsg = e.what();
2771 geos::unique_ptr point = createGeosPointXY( x, y,
false, 0,
false, 0, 2, 0 );
2778 distance = GEOSProject_r( geosinit()->ctxt, mGeos.get(), point.get() );
2780 catch ( GEOSException &e )
2782 logError( QStringLiteral(
"GEOS" ), e.what() );
2785 *errorMsg = e.what();
2795 GEOSGeometry **
const lineGeosGeometries =
new GEOSGeometry*[ geometries.size()];
2802 lineGeosGeometries[validLines] = l.release();
2809 geos::unique_ptr result( GEOSPolygonize_r( geosinit()->ctxt, lineGeosGeometries, validLines ) );
2810 for (
int i = 0; i < validLines; ++i )
2812 GEOSGeom_destroy_r( geosinit()->ctxt, lineGeosGeometries[i] );
2814 delete[] lineGeosGeometries;
2817 catch ( GEOSException &e )
2821 *errorMsg = e.what();
2823 for (
int i = 0; i < validLines; ++i )
2825 GEOSGeom_destroy_r( geosinit()->ctxt, lineGeosGeometries[i] );
2827 delete[] lineGeosGeometries;
2842 extentGeosGeom =
asGeos( extent, mPrecision );
2843 if ( !extentGeosGeom )
2852 geos.reset( GEOSVoronoiDiagram_r( geosinit()->ctxt, mGeos.get(), extentGeosGeom.get(), tolerance, edgesOnly ) );
2854 if ( !
geos || GEOSisEmpty_r( geosinit()->ctxt,
geos.get() ) != 0 )
2874 geos.reset( GEOSDelaunayTriangulation_r( geosinit()->ctxt, mGeos.get(), tolerance, edgesOnly ) );
2876 if ( !
geos || GEOSisEmpty_r( geosinit()->ctxt,
geos.get() ) != 0 )
2888static bool _linestringEndpoints(
const GEOSGeometry *linestring,
double &x1,
double &y1,
double &x2,
double &y2 )
2890 const GEOSCoordSequence *coordSeq = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, linestring );
2894 unsigned int coordSeqSize;
2895 if ( GEOSCoordSeq_getSize_r( geosinit()->ctxt, coordSeq, &coordSeqSize ) == 0 )
2898 if ( coordSeqSize < 2 )
2901 GEOSCoordSeq_getX_r( geosinit()->ctxt, coordSeq, 0, &x1 );
2902 GEOSCoordSeq_getY_r( geosinit()->ctxt, coordSeq, 0, &y1 );
2903 GEOSCoordSeq_getX_r( geosinit()->ctxt, coordSeq, coordSeqSize - 1, &x2 );
2904 GEOSCoordSeq_getY_r( geosinit()->ctxt, coordSeq, coordSeqSize - 1, &y2 );
2910static geos::unique_ptr _mergeLinestrings(
const GEOSGeometry *line1,
const GEOSGeometry *line2,
const QgsPointXY &intersectionPoint )
2912 double x1, y1, x2, y2;
2913 if ( !_linestringEndpoints( line1, x1, y1, x2, y2 ) )
2916 double rx1, ry1, rx2, ry2;
2917 if ( !_linestringEndpoints( line2, rx1, ry1, rx2, ry2 ) )
2920 bool intersectionAtOrigLineEndpoint =
2921 ( intersectionPoint.
x() == x1 && intersectionPoint.
y() == y1 ) !=
2922 ( intersectionPoint.
x() == x2 && intersectionPoint.
y() == y2 );
2923 bool intersectionAtReshapeLineEndpoint =
2924 ( intersectionPoint.
x() == rx1 && intersectionPoint.
y() == ry1 ) ||
2925 ( intersectionPoint.
x() == rx2 && intersectionPoint.
y() == ry2 );
2928 if ( intersectionAtOrigLineEndpoint && intersectionAtReshapeLineEndpoint )
2932 GEOSGeometry *geoms[2] = { g1.release(), g2.release() };
2933 geos::unique_ptr multiGeom( GEOSGeom_createCollection_r( geosinit()->ctxt, GEOS_MULTILINESTRING, geoms, 2 ) );
2934 geos::unique_ptr res( GEOSLineMerge_r( geosinit()->ctxt, multiGeom.get() ) );
2944 if ( !line || !reshapeLineGeos )
2947 bool atLeastTwoIntersections =
false;
2948 bool oneIntersection =
false;
2954 geos::unique_ptr intersectGeom( GEOSIntersection_r( geosinit()->ctxt, line, reshapeLineGeos ) );
2955 if ( intersectGeom )
2957 const int geomType = GEOSGeomTypeId_r( geosinit()->ctxt, intersectGeom.get() );
2958 atLeastTwoIntersections = ( geomType == GEOS_MULTIPOINT && GEOSGetNumGeometries_r( geosinit()->ctxt, intersectGeom.get() ) > 1 )
2959 || ( geomType == GEOS_GEOMETRYCOLLECTION && GEOSGetNumGeometries_r( geosinit()->ctxt, intersectGeom.get() ) > 0 )
2960 || ( geomType == GEOS_MULTILINESTRING && GEOSGetNumGeometries_r( geosinit()->ctxt, intersectGeom.get() ) > 0 );
2962 if ( GEOSGeomTypeId_r( geosinit()->ctxt, intersectGeom.get() ) == GEOS_POINT )
2964 const GEOSCoordSequence *intersectionCoordSeq = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, intersectGeom.get() );
2966 GEOSCoordSeq_getX_r( geosinit()->ctxt, intersectionCoordSeq, 0, &xi );
2967 GEOSCoordSeq_getY_r( geosinit()->ctxt, intersectionCoordSeq, 0, &yi );
2968 oneIntersection =
true;
2973 catch ( GEOSException & )
2975 atLeastTwoIntersections =
false;
2979 if ( oneIntersection )
2980 return _mergeLinestrings( line, reshapeLineGeos, oneIntersectionPoint );
2982 if ( !atLeastTwoIntersections )
2986 double x1, y1, x2, y2;
2987 if ( !_linestringEndpoints( line, x1, y1, x2, y2 ) )
2993 bool isRing =
false;
2994 if ( GEOSGeomTypeId_r( geosinit()->ctxt, line ) == GEOS_LINEARRING
2995 || GEOSEquals_r( geosinit()->ctxt, beginLineVertex.get(), endLineVertex.get() ) == 1 )
3000 if ( !nodedGeometry )
3006 geos::unique_ptr mergedLines( GEOSLineMerge_r( geosinit()->ctxt, nodedGeometry.get() ) );
3012 int numMergedLines = GEOSGetNumGeometries_r( geosinit()->ctxt, mergedLines.get() );
3013 if ( numMergedLines < 2 )
3015 if ( numMergedLines == 1 )
3017 geos::unique_ptr result( GEOSGeom_clone_r( geosinit()->ctxt, reshapeLineGeos ) );
3024 QVector<GEOSGeometry *> resultLineParts;
3025 QVector<GEOSGeometry *> probableParts;
3027 for (
int i = 0; i < numMergedLines; ++i )
3029 const GEOSGeometry *currentGeom = GEOSGetGeometryN_r( geosinit()->ctxt, mergedLines.get(), i );
3032 bool alreadyAdded =
false;
3034 double bufferDistance = std::pow( 10.0L, geomDigits( currentGeom ) - 11 );
3035 for (
const GEOSGeometry *other : std::as_const( resultLineParts ) )
3037 GEOSHausdorffDistance_r( geosinit()->ctxt, currentGeom, other, &
distance );
3040 alreadyAdded =
true;
3047 const GEOSCoordSequence *currentCoordSeq = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, currentGeom );
3048 unsigned int currentCoordSeqSize;
3049 GEOSCoordSeq_getSize_r( geosinit()->ctxt, currentCoordSeq, ¤tCoordSeqSize );
3050 if ( currentCoordSeqSize < 2 )
3054 double xBegin, xEnd, yBegin, yEnd;
3055 GEOSCoordSeq_getX_r( geosinit()->ctxt, currentCoordSeq, 0, &xBegin );
3056 GEOSCoordSeq_getY_r( geosinit()->ctxt, currentCoordSeq, 0, &yBegin );
3057 GEOSCoordSeq_getX_r( geosinit()->ctxt, currentCoordSeq, currentCoordSeqSize - 1, &xEnd );
3058 GEOSCoordSeq_getY_r( geosinit()->ctxt, currentCoordSeq, currentCoordSeqSize - 1, &yEnd );
3063 int nEndpointsOnOriginalLine = 0;
3064 if ( pointContainedInLine( beginCurrentGeomVertex.get(), line ) == 1 )
3065 nEndpointsOnOriginalLine += 1;
3067 if ( pointContainedInLine( endCurrentGeomVertex.get(), line ) == 1 )
3068 nEndpointsOnOriginalLine += 1;
3071 int nEndpointsSameAsOriginalLine = 0;
3072 if ( GEOSEquals_r( geosinit()->ctxt, beginCurrentGeomVertex.get(), beginLineVertex.get() ) == 1
3073 || GEOSEquals_r( geosinit()->ctxt, beginCurrentGeomVertex.get(), endLineVertex.get() ) == 1 )
3074 nEndpointsSameAsOriginalLine += 1;
3076 if ( GEOSEquals_r( geosinit()->ctxt, endCurrentGeomVertex.get(), beginLineVertex.get() ) == 1
3077 || GEOSEquals_r( geosinit()->ctxt, endCurrentGeomVertex.get(), endLineVertex.get() ) == 1 )
3078 nEndpointsSameAsOriginalLine += 1;
3081 bool currentGeomOverlapsOriginalGeom =
false;
3082 bool currentGeomOverlapsReshapeLine =
false;
3083 if ( lineContainedInLine( currentGeom, line ) == 1 )
3084 currentGeomOverlapsOriginalGeom =
true;
3086 if ( lineContainedInLine( currentGeom, reshapeLineGeos ) == 1 )
3087 currentGeomOverlapsReshapeLine =
true;
3090 if ( !isRing && nEndpointsSameAsOriginalLine == 1 && nEndpointsOnOriginalLine == 2 && currentGeomOverlapsOriginalGeom )
3092 resultLineParts.push_back( GEOSGeom_clone_r( geosinit()->ctxt, currentGeom ) );
3095 else if ( isRing && nEndpointsOnOriginalLine == 2 && currentGeomOverlapsOriginalGeom )
3097 probableParts.push_back( GEOSGeom_clone_r( geosinit()->ctxt, currentGeom ) );
3099 else if ( nEndpointsOnOriginalLine == 2 && !currentGeomOverlapsOriginalGeom )
3101 resultLineParts.push_back( GEOSGeom_clone_r( geosinit()->ctxt, currentGeom ) );
3103 else if ( nEndpointsSameAsOriginalLine == 2 && !currentGeomOverlapsOriginalGeom )
3105 resultLineParts.push_back( GEOSGeom_clone_r( geosinit()->ctxt, currentGeom ) );
3107 else if ( currentGeomOverlapsOriginalGeom && currentGeomOverlapsReshapeLine )
3109 resultLineParts.push_back( GEOSGeom_clone_r( geosinit()->ctxt, currentGeom ) );
3114 if ( isRing && !probableParts.isEmpty() )
3117 GEOSGeometry *currentGeom =
nullptr;
3118 double maxLength = -std::numeric_limits<double>::max();
3119 double currentLength = 0;
3120 for (
int i = 0; i < probableParts.size(); ++i )
3122 currentGeom = probableParts.at( i );
3123 GEOSLength_r( geosinit()->ctxt, currentGeom, ¤tLength );
3124 if ( currentLength > maxLength )
3126 maxLength = currentLength;
3127 maxGeom.reset( currentGeom );
3131 GEOSGeom_destroy_r( geosinit()->ctxt, currentGeom );
3134 resultLineParts.push_back( maxGeom.release() );
3138 if ( resultLineParts.empty() )
3141 if ( resultLineParts.size() == 1 )
3143 result.reset( resultLineParts[0] );
3147 GEOSGeometry **lineArray =
new GEOSGeometry*[resultLineParts.size()];
3148 for (
int i = 0; i < resultLineParts.size(); ++i )
3150 lineArray[i] = resultLineParts[i];
3154 geos::unique_ptr multiLineGeom( GEOSGeom_createCollection_r( geosinit()->ctxt, GEOS_MULTILINESTRING, lineArray, resultLineParts.size() ) );
3155 delete [] lineArray;
3158 result.reset( GEOSLineMerge_r( geosinit()->ctxt, multiLineGeom.get() ) );
3162 if ( GEOSGeomTypeId_r( geosinit()->ctxt, result.get() ) != GEOS_LINESTRING )
3170geos::unique_ptr QgsGeos::reshapePolygon(
const GEOSGeometry *polygon,
const GEOSGeometry *reshapeLineGeos,
double precision )
3173 int nIntersections = 0;
3174 int lastIntersectingRing = -2;
3175 const GEOSGeometry *lastIntersectingGeom =
nullptr;
3177 int nRings = GEOSGetNumInteriorRings_r( geosinit()->ctxt, polygon );
3182 const GEOSGeometry *outerRing = GEOSGetExteriorRing_r( geosinit()->ctxt, polygon );
3183 if ( GEOSIntersects_r( geosinit()->ctxt, outerRing, reshapeLineGeos ) == 1 )
3186 lastIntersectingRing = -1;
3187 lastIntersectingGeom = outerRing;
3191 const GEOSGeometry **innerRings =
new const GEOSGeometry*[nRings];
3195 for (
int i = 0; i < nRings; ++i )
3197 innerRings[i] = GEOSGetInteriorRingN_r( geosinit()->ctxt, polygon, i );
3198 if ( GEOSIntersects_r( geosinit()->ctxt, innerRings[i], reshapeLineGeos ) == 1 )
3201 lastIntersectingRing = i;
3202 lastIntersectingGeom = innerRings[i];
3206 catch ( GEOSException & )
3211 if ( nIntersections != 1 )
3213 delete [] innerRings;
3219 if ( !reshapeResult )
3221 delete [] innerRings;
3226 GEOSGeometry *newRing =
nullptr;
3227 const GEOSCoordSequence *reshapeSequence = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, reshapeResult.get() );
3228 GEOSCoordSequence *newCoordSequence = GEOSCoordSeq_clone_r( geosinit()->ctxt, reshapeSequence );
3230 reshapeResult.reset();
3232 newRing = GEOSGeom_createLinearRing_r( geosinit()->ctxt, newCoordSequence );
3235 delete [] innerRings;
3239 GEOSGeometry *newOuterRing =
nullptr;
3240 if ( lastIntersectingRing == -1 )
3241 newOuterRing = newRing;
3243 newOuterRing = GEOSGeom_clone_r( geosinit()->ctxt, outerRing );
3246 QVector<GEOSGeometry *> ringList;
3249 GEOSGeometry *outerRingPoly = GEOSGeom_createPolygon_r( geosinit()->ctxt, GEOSGeom_clone_r( geosinit()->ctxt, newOuterRing ),
nullptr, 0 );
3250 if ( outerRingPoly )
3252 ringList.reserve( nRings );
3253 GEOSGeometry *currentRing =
nullptr;
3254 for (
int i = 0; i < nRings; ++i )
3256 if ( lastIntersectingRing == i )
3257 currentRing = newRing;
3259 currentRing = GEOSGeom_clone_r( geosinit()->ctxt, innerRings[i] );
3262 if ( GEOSContains_r( geosinit()->ctxt, outerRingPoly, currentRing ) == 1 )
3263 ringList.push_back( currentRing );
3265 GEOSGeom_destroy_r( geosinit()->ctxt, currentRing );
3268 GEOSGeom_destroy_r( geosinit()->ctxt, outerRingPoly );
3271 GEOSGeometry **newInnerRings =
new GEOSGeometry*[ringList.size()];
3272 for (
int i = 0; i < ringList.size(); ++i )
3273 newInnerRings[i] = ringList.at( i );
3275 delete [] innerRings;
3277 geos::unique_ptr reshapedPolygon( GEOSGeom_createPolygon_r( geosinit()->ctxt, newOuterRing, newInnerRings, ringList.size() ) );
3278 delete[] newInnerRings;
3280 return reshapedPolygon;
3283int QgsGeos::lineContainedInLine(
const GEOSGeometry *line1,
const GEOSGeometry *line2 )
3285 if ( !line1 || !line2 )
3290 double bufferDistance = std::pow( 10.0L, geomDigits( line2 ) - 11 );
3296 geos::unique_ptr intersectionGeom( GEOSIntersection_r( geosinit()->ctxt, bufferGeom.get(), line1 ) );
3299 double intersectGeomLength;
3302 GEOSLength_r( geosinit()->ctxt, intersectionGeom.get(), &intersectGeomLength );
3303 GEOSLength_r( geosinit()->ctxt, line1, &line1Length );
3305 double intersectRatio = line1Length / intersectGeomLength;
3306 if ( intersectRatio > 0.9 && intersectRatio < 1.1 )
3312int QgsGeos::pointContainedInLine(
const GEOSGeometry *point,
const GEOSGeometry *line )
3314 if ( !point || !line )
3317 double bufferDistance = std::pow( 10.0L, geomDigits( line ) - 11 );
3319 geos::unique_ptr lineBuffer( GEOSBuffer_r( geosinit()->ctxt, line, bufferDistance, 8 ) );
3323 bool contained =
false;
3324 if ( GEOSContains_r( geosinit()->ctxt, lineBuffer.get(), point ) == 1 )
3330int QgsGeos::geomDigits(
const GEOSGeometry *geom )
3336 const GEOSGeometry *bBoxRing = GEOSGetExteriorRing_r( geosinit()->ctxt, bbox.get() );
3340 const GEOSCoordSequence *bBoxCoordSeq = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, bBoxRing );
3342 if ( !bBoxCoordSeq )
3345 unsigned int nCoords = 0;
3346 if ( !GEOSCoordSeq_getSize_r( geosinit()->ctxt, bBoxCoordSeq, &nCoords ) )
3350 for (
unsigned int i = 0; i < nCoords - 1; ++i )
3353 GEOSCoordSeq_getX_r( geosinit()->ctxt, bBoxCoordSeq, i, &t );
3356 digits = std::ceil( std::log10( std::fabs( t ) ) );
3357 if ( digits > maxDigits )
3360 GEOSCoordSeq_getY_r( geosinit()->ctxt, bBoxCoordSeq, i, &t );
3361 digits = std::ceil( std::log10( std::fabs( t ) ) );
3362 if ( digits > maxDigits )
3371 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 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.
virtual QgsAbstractGeometry * clone() const =0
Clones the geometry by performing a deep copy.
Curve polygon geometry type.
const QgsCurve * interiorRing(int i) const SIP_HOLDGIL
Retrieves an interior ring from the curve polygon.
const QgsCurve * exteriorRing() const SIP_HOLDGIL
Returns the curve polygon's exterior ring.
int numInteriorRings() const SIP_HOLDGIL
Returns the number of interior rings contained with the curve polygon.
Abstract base class for curved geometry type.
virtual QgsLineString * curveToLine(double tolerance=M_PI_2/90, SegmentationToleranceType toleranceType=MaximumAngle) const =0
Returns a new line string geometry corresponding to a segmentized approximation of the curve.
virtual bool addGeometry(QgsAbstractGeometry *g)
Adds a geometry and takes ownership. Returns true in case of success.
static Qgis::GeometryOperationResult addPart(QgsAbstractGeometry *geometry, std::unique_ptr< QgsAbstractGeometry > part)
Add a part to multi type geometry.
A geometry engine is a low-level representation of a QgsAbstractGeometry object, optimised for use wi...
const QgsAbstractGeometry * mGeometry
EngineOperationResult
Success or failure of a geometry operation.
@ NothingHappened
Nothing happened, without any error.
@ InvalidBaseGeometry
The geometry on which the operation occurs is not valid.
@ InvalidInput
The input is not valid.
@ NodedGeometryError
Error occurred while creating a noded geometry.
@ EngineError
Error occurred in the geometry engine.
@ SplitCannotSplitPoint
Points cannot be split.
@ Success
Operation succeeded.
void logError(const QString &engineName, const QString &message) const
Logs an error message encountered during an operation.
static std::unique_ptr< QgsGeometryCollection > createCollectionOfType(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.
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.
bool contains(double x, double y, QString *errorMsg=nullptr) const
Returns true if the geometry contains the point at (x, y).
QgsGeometry mergeLines(QString *errorMsg=nullptr) const
Merges any connected lines in a LineString/MultiLineString geometry and converts them to single line ...
static QgsGeometry polygonize(const QVector< const QgsAbstractGeometry * > &geometries, QString *errorMsg=nullptr)
Creates a GeometryCollection geometry containing possible polygons formed from the constituent linewo...
bool relatePattern(const QgsAbstractGeometry *geom, const QString &pattern, QString *errorMsg=nullptr) const override
Tests whether two geometries are related by a specified Dimensional Extended 9 Intersection Model (DE...
QgsAbstractGeometry * offsetCurve(double distance, int segments, Qgis::JoinStyle joinStyle, double miterLimit, QString *errorMsg=nullptr) const override
Offsets a curve.
static GEOSContextHandle_t getGEOSHandler()
QgsPoint * centroid(QString *errorMsg=nullptr) const override
Calculates the centroid of this.
double lineLocatePoint(const QgsPoint &point, QString *errorMsg=nullptr) const
Returns a distance representing the location along this linestring of the closest point on this lines...
bool isEmpty(QString *errorMsg=nullptr) const override
static Qgis::GeometryOperationResult addPart(QgsGeometry &geometry, GEOSGeometry *newPart)
Adds a new island polygon to a multipolygon feature.
double frechetDistance(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const
Returns the Fréchet distance between this geometry and geom, restricted to discrete points for both g...
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.
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.
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.
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.
double closestSegment(const QgsPoint &pt, QgsPoint &segmentPt, QgsVertexId &vertexAfter, int *leftOf=nullptr, double epsilon=4 *std::numeric_limits< double >::epsilon()) const override
Searches for the closest segment of the geometry to a given point.
const double * mData() const
Returns a const pointer to the m vertex data, or nullptr if the linestring does not have m values.
void addVertex(const QgsPoint &pt)
Adds a new vertex to the end of the line string.
QgsLineString * clone() const override
Clones the geometry by performing a deep copy.
double xAt(int index) const override
Returns the x-coordinate of the specified node in the line string.
Multi curve geometry collection.
bool addGeometry(QgsAbstractGeometry *g) override
Adds a geometry and takes ownership. Returns true in case of success.
Multi line string geometry collection.
Multi point geometry collection.
Multi polygon geometry collection.
Custom exception class which is raised when an operation is not supported.
A class to represent a 2D point.
Point geometry type, with support for z-dimension and m-values.
double distance(double x, double y) const SIP_HOLDGIL
Returns the Cartesian 2D distance between this point and a specified x, y coordinate.
A rectangle specified with double values.
double yMaximum() const SIP_HOLDGIL
Returns the y maximum value (top side of rectangle).
double xMaximum() const SIP_HOLDGIL
Returns the x maximum value (right side of rectangle).
double xMinimum() const SIP_HOLDGIL
Returns the x minimum value (left side of rectangle).
double yMinimum() const SIP_HOLDGIL
Returns the y minimum value (bottom side of rectangle).
void setYMinimum(double y) SIP_HOLDGIL
Set the minimum y value.
bool isNull() const
Test if the rectangle is null (all coordinates zero or after call to setMinimal()).
void setXMaximum(double x) SIP_HOLDGIL
Set the maximum x value.
void setXMinimum(double x) SIP_HOLDGIL
Set the minimum x value.
double height() const SIP_HOLDGIL
Returns the height of the rectangle.
void setYMaximum(double y) SIP_HOLDGIL
Set the maximum y value.
double width() const SIP_HOLDGIL
Returns the width of the rectangle.
bool isEmpty() const
Returns true if the rectangle is empty.
static 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)
QLineF segment(int index, QRectF rect, double radius)
Utility class for identifying a unique vertex within a geometry.
void CORE_EXPORT operator()(GEOSGeometry *geom) const
Destroys the GEOS geometry geom, using the static QGIS geos context.