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 qWarning(
"GEOS exception: %s", buffer );
61 QString message = QString::fromUtf8( buffer );
71 throw GEOSException( message );
79 throw GEOSException( message );
84 static void printGEOSNotice(
const char *fmt, ... )
86 #if defined(QGISDEBUG) 91 vsnprintf( buffer,
sizeof buffer, fmt, ap );
94 QgsDebugMsg( QStringLiteral(
"GEOS notice: %1" ).arg( QString::fromUtf8( buffer ) ) );
103 GEOSContextHandle_t ctxt;
107 ctxt = initGEOS_r( printGEOSNotice, throwGEOSException );
112 finishGEOS_r( ctxt );
115 GEOSInit(
const GEOSInit &rh ) =
delete;
116 GEOSInit &operator=(
const GEOSInit &rh ) =
delete;
119 static GEOSInit geosinit;
123 GEOSGeom_destroy_r( geosinit.ctxt, geom );
128 GEOSPreparedGeom_destroy_r( geosinit.ctxt, geom );
133 GEOSBufferParams_destroy_r( geosinit.ctxt, params );
138 GEOSCoordSeq_destroy_r( geosinit.ctxt, sequence );
148 , mPrecision( precision )
187 std::unique_ptr< QgsAbstractGeometry > geom =
fromGeos( newPart );
194 mGeosPrepared.reset();
200 mGeosPrepared.reset();
203 mGeosPrepared.reset( GEOSPrepare_r( geosinit.ctxt, mGeos.get() ) );
207 void QgsGeos::cacheGeos()
const 219 return overlay( geom, OverlayIntersection, errorMsg ).release();
224 return overlay( geom, OverlayDifference, errorMsg ).release();
239 catch ( GEOSException &e )
243 *errorMsg = e.what();
254 int partType = GEOSGeomTypeId_r( geosinit.ctxt, currentPart );
257 if ( partType == GEOS_POINT )
268 if ( partType == GEOS_MULTILINESTRING || partType == GEOS_MULTIPOLYGON || partType == GEOS_GEOMETRYCOLLECTION )
270 int partCount = GEOSGetNumGeometries_r( geosinit.ctxt, currentPart );
271 for (
int i = 0; i < partCount; ++i )
273 subdivideRecursive( GEOSGetGeometryN_r( geosinit.ctxt, currentPart, i ), maxNodes, depth, parts, clipRect );
284 int vertexCount = GEOSGetNumCoordinates_r( geosinit.ctxt, currentPart );
285 if ( vertexCount == 0 )
289 else if ( vertexCount < maxNodes )
296 double width = clipRect.
width();
297 double height = clipRect.
height();
300 if ( width > height )
313 halfClipRect1.
setYMinimum( halfClipRect1.
yMinimum() - std::numeric_limits<double>::epsilon() );
314 halfClipRect2.
setYMinimum( halfClipRect2.
yMinimum() - std::numeric_limits<double>::epsilon() );
315 halfClipRect1.
setYMaximum( halfClipRect1.
yMaximum() + std::numeric_limits<double>::epsilon() );
316 halfClipRect2.
setYMaximum( halfClipRect2.
yMaximum() + std::numeric_limits<double>::epsilon() );
320 halfClipRect1.
setXMinimum( halfClipRect1.
xMinimum() - std::numeric_limits<double>::epsilon() );
321 halfClipRect2.
setXMinimum( halfClipRect2.
xMinimum() - std::numeric_limits<double>::epsilon() );
322 halfClipRect1.
setXMaximum( halfClipRect1.
xMaximum() + std::numeric_limits<double>::epsilon() );
323 halfClipRect2.
setXMaximum( halfClipRect2.
xMaximum() + std::numeric_limits<double>::epsilon() );
333 subdivideRecursive( clipPart1.get(), maxNodes, depth, parts, halfClipRect1 );
337 subdivideRecursive( clipPart2.get(), maxNodes, depth, parts, halfClipRect2 );
349 maxNodes = std::max( maxNodes, 8 );
358 return std::move( parts );
363 return overlay( geom, OverlayUnion, errorMsg ).release();
368 QVector< GEOSGeometry * > geosGeometries;
369 geosGeometries.reserve( geomList.size() );
375 geosGeometries <<
asGeos( g, mPrecision ).release();
381 geos::unique_ptr geomCollection = createGeosCollection( GEOS_GEOMETRYCOLLECTION, geosGeometries );
382 geomUnion.reset( GEOSUnaryUnion_r( geosinit.ctxt, geomCollection.get() ) );
386 std::unique_ptr< QgsAbstractGeometry > result =
fromGeos( geomUnion.get() );
387 return result.release();
392 QVector< GEOSGeometry * > geosGeometries;
393 geosGeometries.reserve( geomList.size() );
399 geosGeometries <<
asGeos( g.constGet(), mPrecision ).release();
405 geos::unique_ptr geomCollection = createGeosCollection( GEOS_GEOMETRYCOLLECTION, geosGeometries );
406 geomUnion.reset( GEOSUnaryUnion_r( geosinit.ctxt, geomCollection.get() ) );
410 std::unique_ptr< QgsAbstractGeometry > result =
fromGeos( geomUnion.get() );
411 return result.release();
416 return overlay( geom, OverlaySymDifference, errorMsg ).release();
428 if ( !otherGeosGeom )
435 GEOSDistance_r( geosinit.ctxt, mGeos.get(), otherGeosGeom.get(), &
distance );
451 if ( !otherGeosGeom )
458 GEOSHausdorffDistance_r( geosinit.ctxt, mGeos.get(), otherGeosGeom.get(), &
distance );
474 if ( !otherGeosGeom )
481 GEOSHausdorffDistanceDensify_r( geosinit.ctxt, mGeos.get(), otherGeosGeom.get(), densifyFraction, &
distance );
490 return relation( geom, RelationIntersects, errorMsg );
495 return relation( geom, RelationTouches, errorMsg );
500 return relation( geom, RelationCrosses, errorMsg );
505 return relation( geom, RelationWithin, errorMsg );
510 return relation( geom, RelationOverlaps, errorMsg );
515 return relation( geom, RelationContains, errorMsg );
520 return relation( geom, RelationDisjoint, errorMsg );
539 char *r = GEOSRelate_r( geosinit.ctxt, mGeos.get(), geosGeom.get() );
542 result = QString( r );
543 GEOSFree_r( geosinit.ctxt, r );
546 catch ( GEOSException &e )
550 *errorMsg = e.what();
559 if ( !mGeos || !geom )
573 result = ( GEOSRelatePattern_r( geosinit.ctxt, mGeos.get(), geosGeom.get(), pattern.toLocal8Bit().constData() ) == 1 );
575 catch ( GEOSException &e )
579 *errorMsg = e.what();
596 if ( GEOSArea_r( geosinit.ctxt, mGeos.get(), &
area ) != 1 )
612 if ( GEOSLength_r( geosinit.ctxt, mGeos.get(), &
length ) != 1 )
620 QVector<QgsGeometry> &newGeometries,
623 QString *errorMsg )
const 638 if ( !GEOSisValid_r( geosinit.ctxt, mGeos.get() ) )
646 newGeometries.clear();
653 splitLineGeos = createGeosLinestring( &splitLine, mPrecision );
657 splitLineGeos = createGeosPointXY( splitLine.
xAt( 0 ), splitLine.
yAt( 0 ),
false, 0,
false, 0, 2, mPrecision );
664 if ( !GEOSisValid_r( geosinit.ctxt, splitLineGeos.get() ) || !GEOSisSimple_r( geosinit.ctxt, splitLineGeos.get() ) )
672 if ( !topologicalTestPointsSplit( splitLineGeos.get(), topologyTestPoints ) )
681 returnCode = splitLinearGeometry( splitLineGeos.get(), newGeometries );
685 returnCode = splitPolygonGeometry( splitLineGeos.get(), newGeometries );
699 bool QgsGeos::topologicalTestPointsSplit(
const GEOSGeometry *splitLine,
QgsPointSequence &testPoints, QString *errorMsg )
const 713 geos::unique_ptr intersectionGeom( GEOSIntersection_r( geosinit.ctxt, mGeos.get(), splitLine ) );
714 if ( !intersectionGeom )
718 int nIntersectGeoms = 1;
719 if ( GEOSGeomTypeId_r( geosinit.ctxt, intersectionGeom.get() ) == GEOS_LINESTRING
720 || GEOSGeomTypeId_r( geosinit.ctxt, intersectionGeom.get() ) == GEOS_POINT )
724 nIntersectGeoms = GEOSGetNumGeometries_r( geosinit.ctxt, intersectionGeom.get() );
726 for (
int i = 0; i < nIntersectGeoms; ++i )
728 const GEOSGeometry *currentIntersectGeom =
nullptr;
730 currentIntersectGeom = intersectionGeom.get();
732 currentIntersectGeom = GEOSGetGeometryN_r( geosinit.ctxt, intersectionGeom.get(), i );
734 const GEOSCoordSequence *lineSequence = GEOSGeom_getCoordSeq_r( geosinit.ctxt, currentIntersectGeom );
735 unsigned int sequenceSize = 0;
737 if ( GEOSCoordSeq_getSize_r( geosinit.ctxt, lineSequence, &sequenceSize ) != 0 )
739 for (
unsigned int i = 0; i < sequenceSize; ++i )
741 if ( GEOSCoordSeq_getX_r( geosinit.ctxt, lineSequence, i, &x ) != 0 )
743 if ( GEOSCoordSeq_getY_r( geosinit.ctxt, lineSequence, i, &y ) != 0 )
745 testPoints.push_back(
QgsPoint( x, y ) );
757 geos::unique_ptr QgsGeos::linePointDifference( GEOSGeometry *GEOSsplitPoint )
const 759 int type = GEOSGeomTypeId_r( geosinit.ctxt, mGeos.get() );
761 std::unique_ptr< QgsMultiCurve > multiCurve;
762 if ( type == GEOS_MULTILINESTRING )
764 multiCurve.reset( qgsgeometry_cast<QgsMultiCurve *>(
mGeometry->
clone() ) );
766 else if ( type == GEOS_LINESTRING )
782 std::unique_ptr< QgsAbstractGeometry > splitGeom(
fromGeos( GEOSsplitPoint ) );
792 for (
int i = 0; i < multiCurve->numGeometries(); ++i )
801 for (
int j = 1; j < ( nVertices - 1 ); ++j )
805 if ( currentPoint == *splitPoint )
817 return asGeos( &lines, mPrecision );
829 if ( !GEOSIntersects_r( geosinit.ctxt, splitLine, mGeos.get() ) )
833 int linearIntersect = GEOSRelatePattern_r( geosinit.ctxt, mGeos.get(), splitLine,
"1********" );
834 if ( linearIntersect > 0 )
837 int splitGeomType = GEOSGeomTypeId_r( geosinit.ctxt, splitLine );
840 if ( splitGeomType == GEOS_POINT )
842 splitGeom = linePointDifference( splitLine );
846 splitGeom.reset( GEOSDifference_r( geosinit.ctxt, mGeos.get(), splitLine ) );
848 QVector<GEOSGeometry *> lineGeoms;
850 int splitType = GEOSGeomTypeId_r( geosinit.ctxt, splitGeom.get() );
851 if ( splitType == GEOS_MULTILINESTRING )
853 int nGeoms = GEOSGetNumGeometries_r( geosinit.ctxt, splitGeom.get() );
854 lineGeoms.reserve( nGeoms );
855 for (
int i = 0; i < nGeoms; ++i )
856 lineGeoms << GEOSGeom_clone_r( geosinit.ctxt, GEOSGetGeometryN_r( geosinit.ctxt, splitGeom.get(), i ) );
861 lineGeoms << GEOSGeom_clone_r( geosinit.ctxt, splitGeom.get() );
864 mergeGeometriesMultiTypeSplit( lineGeoms );
866 for (
int i = 0; i < lineGeoms.size(); ++i )
869 GEOSGeom_destroy_r( geosinit.ctxt, lineGeoms[i] );
884 if ( !GEOSIntersects_r( geosinit.ctxt, splitLine, mGeos.get() ) )
889 if ( !nodedGeometry )
892 const GEOSGeometry *noded = nodedGeometry.get();
894 if ( !polygons || numberOfGeometries( polygons.get() ) == 0 )
901 QVector<GEOSGeometry *> testedGeometries;
907 for (
int i = 0; i < numberOfGeometries( polygons.get() ); i++ )
909 const GEOSGeometry *polygon = GEOSGetGeometryN_r( geosinit.ctxt, polygons.get(), i );
910 intersectGeometry.reset( GEOSIntersection_r( geosinit.ctxt, mGeos.get(), polygon ) );
911 if ( !intersectGeometry )
913 QgsDebugMsg( QStringLiteral(
"intersectGeometry is nullptr" ) );
917 double intersectionArea;
918 GEOSArea_r( geosinit.ctxt, intersectGeometry.get(), &intersectionArea );
921 GEOSArea_r( geosinit.ctxt, polygon, &polygonArea );
923 const double areaRatio = intersectionArea / polygonArea;
924 if ( areaRatio > 0.99 && areaRatio < 1.01 )
925 testedGeometries << GEOSGeom_clone_r( geosinit.ctxt, polygon );
928 int nGeometriesThis = numberOfGeometries( mGeos.get() );
929 if ( testedGeometries.empty() || testedGeometries.size() == nGeometriesThis )
932 for (
int i = 0; i < testedGeometries.size(); ++i )
934 GEOSGeom_destroy_r( geosinit.ctxt, testedGeometries[i] );
939 mergeGeometriesMultiTypeSplit( testedGeometries );
942 for ( i = 0; i < testedGeometries.size() && GEOSisValid_r( geosinit.ctxt, testedGeometries[i] ); ++i )
945 if ( i < testedGeometries.size() )
947 for ( i = 0; i < testedGeometries.size(); ++i )
948 GEOSGeom_destroy_r( geosinit.ctxt, testedGeometries[i] );
953 for ( i = 0; i < testedGeometries.size(); ++i )
956 GEOSGeom_destroy_r( geosinit.ctxt, testedGeometries[i] );
962 geos::unique_ptr QgsGeos::nodeGeometries(
const GEOSGeometry *splitLine,
const GEOSGeometry *geom )
964 if ( !splitLine || !geom )
968 if ( GEOSGeomTypeId_r( geosinit.ctxt, geom ) == GEOS_POLYGON || GEOSGeomTypeId_r( geosinit.ctxt, geom ) == GEOS_MULTIPOLYGON )
969 geometryBoundary.reset( GEOSBoundary_r( geosinit.ctxt, geom ) );
971 geometryBoundary.reset( GEOSGeom_clone_r( geosinit.ctxt, geom ) );
973 geos::unique_ptr splitLineClone( GEOSGeom_clone_r( geosinit.ctxt, splitLine ) );
974 geos::unique_ptr unionGeometry( GEOSUnion_r( geosinit.ctxt, splitLineClone.get(), geometryBoundary.get() ) );
976 return unionGeometry;
979 int QgsGeos::mergeGeometriesMultiTypeSplit( QVector<GEOSGeometry *> &splitResult )
const 985 int type = GEOSGeomTypeId_r( geosinit.ctxt, mGeos.get() );
986 if ( type != GEOS_GEOMETRYCOLLECTION &&
987 type != GEOS_MULTILINESTRING &&
988 type != GEOS_MULTIPOLYGON &&
989 type != GEOS_MULTIPOINT )
992 QVector<GEOSGeometry *> copyList = splitResult;
996 QVector<GEOSGeometry *> unionGeom;
998 for (
int i = 0; i < copyList.size(); ++i )
1001 bool isPart =
false;
1002 for (
int j = 0; j < GEOSGetNumGeometries_r( geosinit.ctxt, mGeos.get() ); j++ )
1004 if ( GEOSEquals_r( geosinit.ctxt, copyList[i], GEOSGetGeometryN_r( geosinit.ctxt, mGeos.get(), j ) ) )
1013 unionGeom << copyList[i];
1017 QVector<GEOSGeometry *> geomVector;
1018 geomVector << copyList[i];
1020 if ( type == GEOS_MULTILINESTRING )
1021 splitResult << createGeosCollection( GEOS_MULTILINESTRING, geomVector ).release();
1022 else if ( type == GEOS_MULTIPOLYGON )
1023 splitResult << createGeosCollection( GEOS_MULTIPOLYGON, geomVector ).release();
1025 GEOSGeom_destroy_r( geosinit.ctxt, copyList[i] );
1030 if ( !unionGeom.isEmpty() )
1032 if ( type == GEOS_MULTILINESTRING )
1033 splitResult << createGeosCollection( GEOS_MULTILINESTRING, unionGeom ).release();
1034 else if ( type == GEOS_MULTIPOLYGON )
1035 splitResult << createGeosCollection( GEOS_MULTIPOLYGON, unionGeom ).release();
1045 geos::unique_ptr QgsGeos::createGeosCollection(
int typeId,
const QVector<GEOSGeometry *> &geoms )
1047 int nNullGeoms = geoms.count(
nullptr );
1048 int nNotNullGeoms = geoms.size() - nNullGeoms;
1050 GEOSGeometry **geomarr =
new GEOSGeometry*[ nNotNullGeoms ];
1057 QVector<GEOSGeometry *>::const_iterator geomIt = geoms.constBegin();
1058 for ( ; geomIt != geoms.constEnd(); ++geomIt )
1062 geomarr[i] = *geomIt;
1070 geom.reset( GEOSGeom_createCollection_r( geosinit.ctxt, typeId, geomarr, nNotNullGeoms ) );
1072 catch ( GEOSException & )
1088 int nCoordDims = GEOSGeom_getCoordinateDimension_r( geosinit.ctxt, geos );
1089 int nDims = GEOSGeom_getDimensions_r( geosinit.ctxt, geos );
1090 bool hasZ = ( nCoordDims == 3 );
1091 bool hasM = ( ( nDims - nCoordDims ) == 1 );
1093 switch ( GEOSGeomTypeId_r( geosinit.ctxt, geos ) )
1097 const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq_r( geosinit.ctxt, geos );
1098 return std::unique_ptr<QgsAbstractGeometry>(
coordSeqPoint( cs, 0, hasZ, hasM ).
clone() );
1100 case GEOS_LINESTRING:
1102 return sequenceToLinestring( geos, hasZ, hasM );
1108 case GEOS_MULTIPOINT:
1110 std::unique_ptr< QgsMultiPoint > multiPoint(
new QgsMultiPoint() );
1111 int nParts = GEOSGetNumGeometries_r( geosinit.ctxt, geos );
1112 multiPoint->reserve( nParts );
1113 for (
int i = 0; i < nParts; ++i )
1115 const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq_r( geosinit.ctxt, GEOSGetGeometryN_r( geosinit.ctxt, geos, i ) );
1118 multiPoint->addGeometry(
coordSeqPoint( cs, 0, hasZ, hasM ).clone() );
1121 return std::move( multiPoint );
1123 case GEOS_MULTILINESTRING:
1126 int nParts = GEOSGetNumGeometries_r( geosinit.ctxt, geos );
1127 multiLineString->reserve( nParts );
1128 for (
int i = 0; i < nParts; ++i )
1130 std::unique_ptr< QgsLineString >line( sequenceToLinestring( GEOSGetGeometryN_r( geosinit.ctxt, geos, i ), hasZ, hasM ) );
1133 multiLineString->addGeometry( line.release() );
1136 return std::move( multiLineString );
1138 case GEOS_MULTIPOLYGON:
1140 std::unique_ptr< QgsMultiPolygon > multiPolygon(
new QgsMultiPolygon() );
1142 int nParts = GEOSGetNumGeometries_r( geosinit.ctxt, geos );
1143 multiPolygon->reserve( nParts );
1144 for (
int i = 0; i < nParts; ++i )
1146 std::unique_ptr< QgsPolygon > poly =
fromGeosPolygon( GEOSGetGeometryN_r( geosinit.ctxt, geos, i ) );
1149 multiPolygon->addGeometry( poly.release() );
1152 return std::move( multiPolygon );
1154 case GEOS_GEOMETRYCOLLECTION:
1157 int nParts = GEOSGetNumGeometries_r( geosinit.ctxt, geos );
1158 geomCollection->reserve( nParts );
1159 for (
int i = 0; i < nParts; ++i )
1161 std::unique_ptr< QgsAbstractGeometry > geom(
fromGeos( GEOSGetGeometryN_r( geosinit.ctxt, geos, i ) ) );
1164 geomCollection->addGeometry( geom.release() );
1167 return std::move( geomCollection );
1175 if ( GEOSGeomTypeId_r( geosinit.ctxt, geos ) != GEOS_POLYGON )
1180 int nCoordDims = GEOSGeom_getCoordinateDimension_r( geosinit.ctxt, geos );
1181 int nDims = GEOSGeom_getDimensions_r( geosinit.ctxt, geos );
1182 bool hasZ = ( nCoordDims == 3 );
1183 bool hasM = ( ( nDims - nCoordDims ) == 1 );
1185 std::unique_ptr< QgsPolygon > polygon(
new QgsPolygon() );
1187 const GEOSGeometry *ring = GEOSGetExteriorRing_r( geosinit.ctxt, geos );
1190 polygon->setExteriorRing( sequenceToLinestring( ring, hasZ, hasM ).release() );
1193 QVector<QgsCurve *> interiorRings;
1194 const int ringCount = GEOSGetNumInteriorRings_r( geosinit.ctxt, geos );
1195 interiorRings.reserve( ringCount );
1196 for (
int i = 0; i < ringCount; ++i )
1198 ring = GEOSGetInteriorRingN_r( geosinit.ctxt, geos, i );
1201 interiorRings.push_back( sequenceToLinestring( ring, hasZ, hasM ).release() );
1204 polygon->setInteriorRings( interiorRings );
1209 std::unique_ptr<QgsLineString> QgsGeos::sequenceToLinestring(
const GEOSGeometry *
geos,
bool hasZ,
bool hasM )
1211 const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq_r( geosinit.ctxt,
geos );
1212 unsigned int nPoints;
1213 GEOSCoordSeq_getSize_r( geosinit.ctxt, cs, &nPoints );
1214 QVector< double > xOut( nPoints );
1215 QVector< double > yOut( nPoints );
1216 QVector< double > zOut;
1218 zOut.resize( nPoints );
1219 QVector< double > mOut;
1221 mOut.resize( nPoints );
1222 double *x = xOut.data();
1223 double *y = yOut.data();
1224 double *z = zOut.data();
1225 double *m = mOut.data();
1226 for (
unsigned int i = 0; i < nPoints; ++i )
1228 GEOSCoordSeq_getX_r( geosinit.ctxt, cs, i, x++ );
1229 GEOSCoordSeq_getY_r( geosinit.ctxt, cs, i, y++ );
1232 GEOSCoordSeq_getZ_r( geosinit.ctxt, cs, i, z++ );
1236 GEOSCoordSeq_getOrdinate_r( geosinit.ctxt, cs, i, 3, m++ );
1239 std::unique_ptr< QgsLineString > line(
new QgsLineString( xOut, yOut, zOut, mOut ) );
1243 int QgsGeos::numberOfGeometries( GEOSGeometry *g )
1248 int geometryType = GEOSGeomTypeId_r( geosinit.ctxt, g );
1249 if ( geometryType == GEOS_POINT || geometryType == GEOS_LINESTRING || geometryType == GEOS_LINEARRING
1250 || geometryType == GEOS_POLYGON )
1254 return GEOSGetNumGeometries_r( geosinit.ctxt, g );
1267 GEOSCoordSeq_getX_r( geosinit.ctxt, cs, i, &x );
1268 GEOSCoordSeq_getY_r( geosinit.ctxt, cs, i, &y );
1271 GEOSCoordSeq_getZ_r( geosinit.ctxt, cs, i, &z );
1275 GEOSCoordSeq_getOrdinate_r( geosinit.ctxt, cs, i, 3, &m );
1311 int geosType = GEOS_GEOMETRYCOLLECTION;
1318 geosType = GEOS_MULTIPOINT;
1322 geosType = GEOS_MULTILINESTRING;
1326 geosType = GEOS_MULTIPOLYGON;
1347 return createGeosCollection( geosType, geomVector );
1354 return createGeosPoint( static_cast<const QgsPoint *>( geom ), coordDims, precision );
1358 return createGeosLinestring( static_cast<const QgsLineString *>( geom ), precision );
1362 return createGeosPolygon( static_cast<const QgsPolygon *>( geom ), precision );
1374 std::unique_ptr<QgsAbstractGeometry> QgsGeos::overlay(
const QgsAbstractGeometry *geom, Overlay op, QString *errorMsg )
const 1376 if ( !mGeos || !geom )
1392 case OverlayIntersection:
1393 opGeom.reset( GEOSIntersection_r( geosinit.ctxt, mGeos.get(), geosGeom.get() ) );
1395 case OverlayDifference:
1396 opGeom.reset( GEOSDifference_r( geosinit.ctxt, mGeos.get(), geosGeom.get() ) );
1400 geos::unique_ptr unionGeometry( GEOSUnion_r( geosinit.ctxt, mGeos.get(), geosGeom.get() ) );
1402 if ( unionGeometry && GEOSGeomTypeId_r( geosinit.ctxt, unionGeometry.get() ) == GEOS_MULTILINESTRING )
1404 geos::unique_ptr mergedLines( GEOSLineMerge_r( geosinit.ctxt, unionGeometry.get() ) );
1407 unionGeometry = std::move( mergedLines );
1411 opGeom = std::move( unionGeometry );
1414 case OverlaySymDifference:
1415 opGeom.reset( GEOSSymDifference_r( geosinit.ctxt, mGeos.get(), geosGeom.get() ) );
1422 catch ( GEOSException &e )
1426 *errorMsg = e.what();
1432 bool QgsGeos::relation(
const QgsAbstractGeometry *geom, Relation r, QString *errorMsg )
const 1434 if ( !mGeos || !geom )
1445 bool result =
false;
1448 if ( mGeosPrepared )
1452 case RelationIntersects:
1453 result = ( GEOSPreparedIntersects_r( geosinit.ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1455 case RelationTouches:
1456 result = ( GEOSPreparedTouches_r( geosinit.ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1458 case RelationCrosses:
1459 result = ( GEOSPreparedCrosses_r( geosinit.ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1461 case RelationWithin:
1462 result = ( GEOSPreparedWithin_r( geosinit.ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1464 case RelationContains:
1465 result = ( GEOSPreparedContains_r( geosinit.ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1467 case RelationDisjoint:
1468 result = ( GEOSPreparedDisjoint_r( geosinit.ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1470 case RelationOverlaps:
1471 result = ( GEOSPreparedOverlaps_r( geosinit.ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1481 case RelationIntersects:
1482 result = ( GEOSIntersects_r( geosinit.ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1484 case RelationTouches:
1485 result = ( GEOSTouches_r( geosinit.ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1487 case RelationCrosses:
1488 result = ( GEOSCrosses_r( geosinit.ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1490 case RelationWithin:
1491 result = ( GEOSWithin_r( geosinit.ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1493 case RelationContains:
1494 result = ( GEOSContains_r( geosinit.ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1496 case RelationDisjoint:
1497 result = ( GEOSDisjoint_r( geosinit.ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1499 case RelationOverlaps:
1500 result = ( GEOSOverlaps_r( geosinit.ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1506 catch ( GEOSException &e )
1510 *errorMsg = e.what();
1528 geos.reset( GEOSBuffer_r( geosinit.ctxt, mGeos.get(),
distance, segments ) );
1531 return fromGeos( geos.get() ).release();
1544 geos.reset( GEOSBufferWithStyle_r( geosinit.ctxt, mGeos.get(),
distance, segments, endCapStyle, joinStyle, miterLimit ) );
1547 return fromGeos( geos.get() ).release();
1559 geos.reset( GEOSTopologyPreserveSimplify_r( geosinit.ctxt, mGeos.get(), tolerance ) );
1562 return fromGeos( geos.get() ).release();
1574 geos.reset( GEOSInterpolate_r( geosinit.ctxt, mGeos.get(),
distance ) );
1577 return fromGeos( geos.get() ).release();
1593 geos.reset( GEOSGetCentroid_r( geosinit.ctxt, mGeos.get() ) );
1598 GEOSGeomGetX_r( geosinit.ctxt, geos.get(), &x );
1599 GEOSGeomGetY_r( geosinit.ctxt, geos.get(), &y );
1615 geos.reset( GEOSEnvelope_r( geosinit.ctxt, mGeos.get() ) );
1618 return fromGeos( geos.get() ).release();
1634 geos.reset( GEOSPointOnSurface_r( geosinit.ctxt, mGeos.get() ) );
1636 if ( !geos || GEOSisEmpty_r( geosinit.ctxt, geos.get() ) != 0 )
1641 GEOSGeomGetX_r( geosinit.ctxt, geos.get(), &x );
1642 GEOSGeomGetY_r( geosinit.ctxt, geos.get(), &y );
1659 std::unique_ptr< QgsAbstractGeometry > cHullGeom =
fromGeos( cHull.get() );
1660 return cHullGeom.release();
1674 GEOSGeometry *g1 =
nullptr;
1676 char res = GEOSisValidDetail_r( geosinit.ctxt, mGeos.get(), allowSelfTouchingHoles ? GEOSVALID_ALLOW_SELFTOUCHING_RING_FORMING_HOLE : 0, &r, &g1 );
1677 const bool invalid = res != 1;
1682 error = QString( r );
1683 GEOSFree_r( geosinit.ctxt, r );
1686 if ( invalid && errorMsg )
1690 if ( translatedErrors.empty() )
1693 translatedErrors.insert( QStringLiteral(
"topology validation error" ), QObject::tr(
"Topology validation error",
"GEOS Error" ) );
1694 translatedErrors.insert( QStringLiteral(
"repeated point" ), QObject::tr(
"Repeated point",
"GEOS Error" ) );
1695 translatedErrors.insert( QStringLiteral(
"hole lies outside shell" ), QObject::tr(
"Hole lies outside shell",
"GEOS Error" ) );
1696 translatedErrors.insert( QStringLiteral(
"holes are nested" ), QObject::tr(
"Holes are nested",
"GEOS Error" ) );
1697 translatedErrors.insert( QStringLiteral(
"interior is disconnected" ), QObject::tr(
"Interior is disconnected",
"GEOS Error" ) );
1698 translatedErrors.insert( QStringLiteral(
"self-intersection" ), QObject::tr(
"Self-intersection",
"GEOS Error" ) );
1699 translatedErrors.insert( QStringLiteral(
"ring self-intersection" ), QObject::tr(
"Ring self-intersection",
"GEOS Error" ) );
1700 translatedErrors.insert( QStringLiteral(
"nested shells" ), QObject::tr(
"Nested shells",
"GEOS Error" ) );
1701 translatedErrors.insert( QStringLiteral(
"duplicate rings" ), QObject::tr(
"Duplicate rings",
"GEOS Error" ) );
1702 translatedErrors.insert( QStringLiteral(
"too few points in geometry component" ), QObject::tr(
"Too few points in geometry component",
"GEOS Error" ) );
1703 translatedErrors.insert( QStringLiteral(
"invalid coordinate" ), QObject::tr(
"Invalid coordinate",
"GEOS Error" ) );
1704 translatedErrors.insert( QStringLiteral(
"ring is not closed" ), QObject::tr(
"Ring is not closed",
"GEOS Error" ) );
1707 *errorMsg = translatedErrors.value( error.toLower(), error );
1709 if ( g1 && errorLoc )
1715 GEOSGeom_destroy_r( geosinit.ctxt, g1 );
1725 if ( !mGeos || !geom )
1737 bool equal = GEOSEquals_r( geosinit.ctxt, mGeos.get(), geosGeom.get() );
1752 return GEOSisEmpty_r( geosinit.ctxt, mGeos.get() );
1766 return GEOSisSimple_r( geosinit.ctxt, mGeos.get() );
1771 GEOSCoordSequence *QgsGeos::createCoordinateSequence(
const QgsCurve *curve,
double precision,
bool forceClose )
1773 std::unique_ptr< QgsLineString > segmentized;
1779 line = segmentized.get();
1787 bool hasZ = line->
is3D();
1801 int numOutPoints = numPoints;
1802 if ( forceClose && ( line->
pointN( 0 ) != line->
pointN( numPoints - 1 ) ) )
1807 GEOSCoordSequence *coordSeq =
nullptr;
1810 coordSeq = GEOSCoordSeq_create_r( geosinit.ctxt, numOutPoints, coordDims );
1813 QgsDebugMsg( QStringLiteral(
"GEOS Exception: Could not create coordinate sequence for %1 points in %2 dimensions" ).arg( numPoints ).arg( coordDims ) );
1817 const double *xData = line->
xData();
1818 const double *yData = line->
yData();
1819 const double *zData = hasZ ? line->
zData() :
nullptr;
1820 const double *mData = hasM ? line->
mData() :
nullptr;
1824 for (
int i = 0; i < numOutPoints; ++i )
1826 if ( i >= numPoints )
1829 xData = line->
xData();
1830 yData = line->
yData();
1831 zData = hasZ ? line->
zData() :
nullptr;
1832 mData = hasM ? line->
mData() :
nullptr;
1834 GEOSCoordSeq_setX_r( geosinit.ctxt, coordSeq, i, std::round( *xData++ /
precision ) *
precision );
1835 GEOSCoordSeq_setY_r( geosinit.ctxt, coordSeq, i, std::round( *yData++ / precision ) * precision );
1838 GEOSCoordSeq_setOrdinate_r( geosinit.ctxt, coordSeq, i, 2, std::round( *zData++ / precision ) * precision );
1842 GEOSCoordSeq_setOrdinate_r( geosinit.ctxt, coordSeq, i, 3, line->
mAt( *mData++ ) );
1848 for (
int i = 0; i < numOutPoints; ++i )
1850 if ( i >= numPoints )
1853 xData = line->
xData();
1854 yData = line->
yData();
1855 zData = hasZ ? line->
zData() :
nullptr;
1856 mData = hasM ? line->
mData() :
nullptr;
1858 GEOSCoordSeq_setX_r( geosinit.ctxt, coordSeq, i, *xData++ );
1859 GEOSCoordSeq_setY_r( geosinit.ctxt, coordSeq, i, *yData++ );
1862 GEOSCoordSeq_setOrdinate_r( geosinit.ctxt, coordSeq, i, 2, *zData++ );
1866 GEOSCoordSeq_setOrdinate_r( geosinit.ctxt, coordSeq, i, 3, *mData++ );
1885 geos::unique_ptr QgsGeos::createGeosPointXY(
double x,
double y,
bool hasZ,
double z,
bool hasM,
double m,
int coordDims,
double precision )
1894 GEOSCoordSequence *coordSeq = GEOSCoordSeq_create_r( geosinit.ctxt, 1, coordDims );
1897 QgsDebugMsg( QStringLiteral(
"GEOS Exception: Could not create coordinate sequence for point with %1 dimensions" ).arg( coordDims ) );
1900 if ( precision > 0. )
1902 GEOSCoordSeq_setX_r( geosinit.ctxt, coordSeq, 0, std::round( x / precision ) * precision );
1903 GEOSCoordSeq_setY_r( geosinit.ctxt, coordSeq, 0, std::round( y / precision ) * precision );
1906 GEOSCoordSeq_setOrdinate_r( geosinit.ctxt, coordSeq, 0, 2, std::round( z / precision ) * precision );
1911 GEOSCoordSeq_setX_r( geosinit.ctxt, coordSeq, 0, x );
1912 GEOSCoordSeq_setY_r( geosinit.ctxt, coordSeq, 0, y );
1915 GEOSCoordSeq_setOrdinate_r( geosinit.ctxt, coordSeq, 0, 2, z );
1918 #if 0 //disabled until geos supports m-coordinates 1921 GEOSCoordSeq_setOrdinate_r( geosinit.ctxt, coordSeq, 0, 3, m );
1924 geosPoint.reset( GEOSGeom_createPoint_r( geosinit.ctxt, coordSeq ) );
1936 GEOSCoordSequence *coordSeq = createCoordinateSequence( c, precision );
1943 geosGeom.reset( GEOSGeom_createLineString_r( geosinit.ctxt, coordSeq ) );
1956 if ( !exteriorRing )
1964 geos::unique_ptr exteriorRingGeos( GEOSGeom_createLinearRing_r( geosinit.ctxt, createCoordinateSequence( exteriorRing, precision,
true ) ) );
1967 GEOSGeometry **holes =
nullptr;
1970 holes =
new GEOSGeometry*[ nHoles ];
1973 for (
int i = 0; i < nHoles; ++i )
1976 holes[i] = GEOSGeom_createLinearRing_r( geosinit.ctxt, createCoordinateSequence( interiorRing, precision,
true ) );
1978 geosPolygon.reset( GEOSGeom_createPolygon_r( geosinit.ctxt, exteriorRingGeos.release(), holes, nHoles ) );
1994 offset.reset( GEOSOffsetCurve_r( geosinit.ctxt, mGeos.get(),
distance, segments, joinStyle, miterLimit ) );
1997 std::unique_ptr< QgsAbstractGeometry > offsetGeom =
fromGeos( offset.get() );
1998 return offsetGeom.release();
2012 GEOSBufferParams_setSingleSided_r( geosinit.ctxt, bp.get(), 1 );
2013 GEOSBufferParams_setQuadrantSegments_r( geosinit.ctxt, bp.get(), segments );
2014 GEOSBufferParams_setJoinStyle_r( geosinit.ctxt, bp.get(), joinStyle );
2015 GEOSBufferParams_setMitreLimit_r( geosinit.ctxt, bp.get(), miterLimit );
2021 geos.reset( GEOSBufferWithParams_r( geosinit.ctxt, mGeos.get(), bp.get(),
distance ) );
2041 geos::unique_ptr reshapeLineGeos = createGeosLinestring( &reshapeWithLine, mPrecision );
2044 int numGeoms = GEOSGetNumGeometries_r( geosinit.ctxt, mGeos.get() );
2045 if ( numGeoms == -1 )
2054 bool isMultiGeom =
false;
2055 int geosTypeId = GEOSGeomTypeId_r( geosinit.ctxt, mGeos.get() );
2056 if ( geosTypeId == GEOS_MULTILINESTRING || geosTypeId == GEOS_MULTIPOLYGON )
2066 reshapedGeometry = reshapeLine( mGeos.get(), reshapeLineGeos.get(), mPrecision );
2070 reshapedGeometry = reshapePolygon( mGeos.get(), reshapeLineGeos.get(), mPrecision );
2075 std::unique_ptr< QgsAbstractGeometry > reshapeResult =
fromGeos( reshapedGeometry.get() );
2076 return reshapeResult;
2083 bool reshapeTookPlace =
false;
2086 GEOSGeometry **newGeoms =
new GEOSGeometry*[numGeoms];
2088 for (
int i = 0; i < numGeoms; ++i )
2091 currentReshapeGeometry = reshapeLine( GEOSGetGeometryN_r( geosinit.ctxt, mGeos.get(), i ), reshapeLineGeos.get(), mPrecision );
2093 currentReshapeGeometry = reshapePolygon( GEOSGetGeometryN_r( geosinit.ctxt, mGeos.get(), i ), reshapeLineGeos.get(), mPrecision );
2095 if ( currentReshapeGeometry )
2097 newGeoms[i] = currentReshapeGeometry.release();
2098 reshapeTookPlace =
true;
2102 newGeoms[i] = GEOSGeom_clone_r( geosinit.ctxt, GEOSGetGeometryN_r( geosinit.ctxt, mGeos.get(), i ) );
2109 newMultiGeom.reset( GEOSGeom_createCollection_r( geosinit.ctxt, GEOS_MULTILINESTRING, newGeoms, numGeoms ) );
2113 newMultiGeom.reset( GEOSGeom_createCollection_r( geosinit.ctxt, GEOS_MULTIPOLYGON, newGeoms, numGeoms ) );
2117 if ( !newMultiGeom )
2123 if ( reshapeTookPlace )
2127 std::unique_ptr< QgsAbstractGeometry > reshapedMultiGeom =
fromGeos( newMultiGeom.get() );
2128 return reshapedMultiGeom;
2150 if ( GEOSGeomTypeId_r( geosinit.ctxt, mGeos.get() ) != GEOS_MULTILINESTRING )
2156 geos.reset( GEOSLineMerge_r( geosinit.ctxt, mGeos.get() ) );
2164 if ( !mGeos || other.
isNull() )
2181 ( void )GEOSCoordSeq_getX_r( geosinit.ctxt, nearestCoord.get(), 0, &nx );
2182 ( void )GEOSCoordSeq_getY_r( geosinit.ctxt, nearestCoord.get(), 0, &ny );
2184 catch ( GEOSException &e )
2188 *errorMsg = e.what();
2198 if ( !mGeos || other.
isNull() )
2217 ( void )GEOSCoordSeq_getX_r( geosinit.ctxt, nearestCoord.get(), 0, &nx1 );
2218 ( void )GEOSCoordSeq_getY_r( geosinit.ctxt, nearestCoord.get(), 0, &ny1 );
2219 ( void )GEOSCoordSeq_getX_r( geosinit.ctxt, nearestCoord.get(), 1, &nx2 );
2220 ( void )GEOSCoordSeq_getY_r( geosinit.ctxt, nearestCoord.get(), 1, &ny2 );
2222 catch ( GEOSException &e )
2226 *errorMsg = e.what();
2253 distance = GEOSProject_r( geosinit.ctxt, mGeos.get(), otherGeom.get() );
2255 catch ( GEOSException &e )
2259 *errorMsg = e.what();
2269 GEOSGeometry **
const lineGeosGeometries =
new GEOSGeometry*[ geometries.size()];
2276 lineGeosGeometries[validLines] = l.release();
2283 geos::unique_ptr result( GEOSPolygonize_r( geosinit.ctxt, lineGeosGeometries, validLines ) );
2284 for (
int i = 0; i < validLines; ++i )
2286 GEOSGeom_destroy_r( geosinit.ctxt, lineGeosGeometries[i] );
2288 delete[] lineGeosGeometries;
2291 catch ( GEOSException &e )
2295 *errorMsg = e.what();
2297 for (
int i = 0; i < validLines; ++i )
2299 GEOSGeom_destroy_r( geosinit.ctxt, lineGeosGeometries[i] );
2301 delete[] lineGeosGeometries;
2316 extentGeosGeom =
asGeos( extent, mPrecision );
2317 if ( !extentGeosGeom )
2326 geos.reset( GEOSVoronoiDiagram_r( geosinit.ctxt, mGeos.get(), extentGeosGeom.get(), tolerance, edgesOnly ) );
2328 if ( !geos || GEOSisEmpty_r( geosinit.ctxt, geos.get() ) != 0 )
2348 geos.reset( GEOSDelaunayTriangulation_r( geosinit.ctxt, mGeos.get(), tolerance, edgesOnly ) );
2350 if ( !geos || GEOSisEmpty_r( geosinit.ctxt, geos.get() ) != 0 )
2362 static bool _linestringEndpoints(
const GEOSGeometry *linestring,
double &x1,
double &y1,
double &x2,
double &y2 )
2364 const GEOSCoordSequence *coordSeq = GEOSGeom_getCoordSeq_r( geosinit.ctxt, linestring );
2368 unsigned int coordSeqSize;
2369 if ( GEOSCoordSeq_getSize_r( geosinit.ctxt, coordSeq, &coordSeqSize ) == 0 )
2372 if ( coordSeqSize < 2 )
2375 GEOSCoordSeq_getX_r( geosinit.ctxt, coordSeq, 0, &x1 );
2376 GEOSCoordSeq_getY_r( geosinit.ctxt, coordSeq, 0, &y1 );
2377 GEOSCoordSeq_getX_r( geosinit.ctxt, coordSeq, coordSeqSize - 1, &x2 );
2378 GEOSCoordSeq_getY_r( geosinit.ctxt, coordSeq, coordSeqSize - 1, &y2 );
2384 static geos::unique_ptr _mergeLinestrings(
const GEOSGeometry *line1,
const GEOSGeometry *line2,
const QgsPointXY &intersectionPoint )
2386 double x1, y1, x2, y2;
2387 if ( !_linestringEndpoints( line1, x1, y1, x2, y2 ) )
2390 double rx1, ry1, rx2, ry2;
2391 if ( !_linestringEndpoints( line2, rx1, ry1, rx2, ry2 ) )
2394 bool intersectionAtOrigLineEndpoint =
2395 ( intersectionPoint.
x() == x1 && intersectionPoint.
y() == y1 ) !=
2396 ( intersectionPoint.
x() == x2 && intersectionPoint.
y() == y2 );
2397 bool intersectionAtReshapeLineEndpoint =
2398 ( intersectionPoint.
x() == rx1 && intersectionPoint.
y() == ry1 ) ||
2399 ( intersectionPoint.
x() == rx2 && intersectionPoint.
y() == ry2 );
2402 if ( intersectionAtOrigLineEndpoint && intersectionAtReshapeLineEndpoint )
2406 GEOSGeometry *geoms[2] = { g1.release(), g2.release() };
2407 geos::unique_ptr multiGeom( GEOSGeom_createCollection_r( geosinit.ctxt, GEOS_MULTILINESTRING, geoms, 2 ) );
2416 geos::unique_ptr QgsGeos::reshapeLine(
const GEOSGeometry *line,
const GEOSGeometry *reshapeLineGeos,
double precision )
2418 if ( !line || !reshapeLineGeos )
2421 bool atLeastTwoIntersections =
false;
2422 bool oneIntersection =
false;
2428 geos::unique_ptr intersectGeom( GEOSIntersection_r( geosinit.ctxt, line, reshapeLineGeos ) );
2429 if ( intersectGeom )
2431 atLeastTwoIntersections = ( GEOSGeomTypeId_r( geosinit.ctxt, intersectGeom.get() ) == GEOS_MULTIPOINT
2432 && GEOSGetNumGeometries_r( geosinit.ctxt, intersectGeom.get() ) > 1 );
2434 if ( GEOSGeomTypeId_r( geosinit.ctxt, intersectGeom.get() ) == GEOS_POINT )
2436 const GEOSCoordSequence *intersectionCoordSeq = GEOSGeom_getCoordSeq_r( geosinit.ctxt, intersectGeom.get() );
2438 GEOSCoordSeq_getX_r( geosinit.ctxt, intersectionCoordSeq, 0, &xi );
2439 GEOSCoordSeq_getY_r( geosinit.ctxt, intersectionCoordSeq, 0, &yi );
2440 oneIntersection =
true;
2445 catch ( GEOSException & )
2447 atLeastTwoIntersections =
false;
2451 if ( oneIntersection )
2452 return _mergeLinestrings( line, reshapeLineGeos, oneIntersectionPoint );
2454 if ( !atLeastTwoIntersections )
2458 double x1, y1, x2, y2;
2459 if ( !_linestringEndpoints( line, x1, y1, x2, y2 ) )
2462 geos::unique_ptr beginLineVertex = createGeosPointXY( x1, y1,
false, 0,
false, 0, 2, precision );
2463 geos::unique_ptr endLineVertex = createGeosPointXY( x2, y2,
false, 0,
false, 0, 2, precision );
2465 bool isRing =
false;
2466 if ( GEOSGeomTypeId_r( geosinit.ctxt, line ) == GEOS_LINEARRING
2467 || GEOSEquals_r( geosinit.ctxt, beginLineVertex.get(), endLineVertex.get() ) == 1 )
2472 if ( !nodedGeometry )
2478 geos::unique_ptr mergedLines( GEOSLineMerge_r( geosinit.ctxt, nodedGeometry.get() ) );
2484 int numMergedLines = GEOSGetNumGeometries_r( geosinit.ctxt, mergedLines.get() );
2485 if ( numMergedLines < 2 )
2487 if ( numMergedLines == 1 )
2489 geos::unique_ptr result( GEOSGeom_clone_r( geosinit.ctxt, reshapeLineGeos ) );
2496 QVector<GEOSGeometry *> resultLineParts;
2497 QVector<GEOSGeometry *> probableParts;
2499 for (
int i = 0; i < numMergedLines; ++i )
2501 const GEOSGeometry *currentGeom =
nullptr;
2503 currentGeom = GEOSGetGeometryN_r( geosinit.ctxt, mergedLines.get(), i );
2504 const GEOSCoordSequence *currentCoordSeq = GEOSGeom_getCoordSeq_r( geosinit.ctxt, currentGeom );
2505 unsigned int currentCoordSeqSize;
2506 GEOSCoordSeq_getSize_r( geosinit.ctxt, currentCoordSeq, ¤tCoordSeqSize );
2507 if ( currentCoordSeqSize < 2 )
2511 double xBegin, xEnd, yBegin, yEnd;
2512 GEOSCoordSeq_getX_r( geosinit.ctxt, currentCoordSeq, 0, &xBegin );
2513 GEOSCoordSeq_getY_r( geosinit.ctxt, currentCoordSeq, 0, &yBegin );
2514 GEOSCoordSeq_getX_r( geosinit.ctxt, currentCoordSeq, currentCoordSeqSize - 1, &xEnd );
2515 GEOSCoordSeq_getY_r( geosinit.ctxt, currentCoordSeq, currentCoordSeqSize - 1, &yEnd );
2516 geos::unique_ptr beginCurrentGeomVertex = createGeosPointXY( xBegin, yBegin,
false, 0,
false, 0, 2, precision );
2517 geos::unique_ptr endCurrentGeomVertex = createGeosPointXY( xEnd, yEnd,
false, 0,
false, 0, 2, precision );
2520 int nEndpointsOnOriginalLine = 0;
2521 if ( pointContainedInLine( beginCurrentGeomVertex.get(), line ) == 1 )
2522 nEndpointsOnOriginalLine += 1;
2524 if ( pointContainedInLine( endCurrentGeomVertex.get(), line ) == 1 )
2525 nEndpointsOnOriginalLine += 1;
2528 int nEndpointsSameAsOriginalLine = 0;
2529 if ( GEOSEquals_r( geosinit.ctxt, beginCurrentGeomVertex.get(), beginLineVertex.get() ) == 1
2530 || GEOSEquals_r( geosinit.ctxt, beginCurrentGeomVertex.get(), endLineVertex.get() ) == 1 )
2531 nEndpointsSameAsOriginalLine += 1;
2533 if ( GEOSEquals_r( geosinit.ctxt, endCurrentGeomVertex.get(), beginLineVertex.get() ) == 1
2534 || GEOSEquals_r( geosinit.ctxt, endCurrentGeomVertex.get(), endLineVertex.get() ) == 1 )
2535 nEndpointsSameAsOriginalLine += 1;
2538 bool currentGeomOverlapsOriginalGeom =
false;
2539 bool currentGeomOverlapsReshapeLine =
false;
2540 if ( lineContainedInLine( currentGeom, line ) == 1 )
2541 currentGeomOverlapsOriginalGeom =
true;
2543 if ( lineContainedInLine( currentGeom, reshapeLineGeos ) == 1 )
2544 currentGeomOverlapsReshapeLine =
true;
2547 if ( !isRing && nEndpointsSameAsOriginalLine == 1 && nEndpointsOnOriginalLine == 2 && currentGeomOverlapsOriginalGeom )
2549 resultLineParts.push_back( GEOSGeom_clone_r( geosinit.ctxt, currentGeom ) );
2552 else if ( isRing && nEndpointsOnOriginalLine == 2 && currentGeomOverlapsOriginalGeom )
2554 probableParts.push_back( GEOSGeom_clone_r( geosinit.ctxt, currentGeom ) );
2556 else if ( nEndpointsOnOriginalLine == 2 && !currentGeomOverlapsOriginalGeom )
2558 resultLineParts.push_back( GEOSGeom_clone_r( geosinit.ctxt, currentGeom ) );
2560 else if ( nEndpointsSameAsOriginalLine == 2 && !currentGeomOverlapsOriginalGeom )
2562 resultLineParts.push_back( GEOSGeom_clone_r( geosinit.ctxt, currentGeom ) );
2564 else if ( currentGeomOverlapsOriginalGeom && currentGeomOverlapsReshapeLine )
2566 resultLineParts.push_back( GEOSGeom_clone_r( geosinit.ctxt, currentGeom ) );
2571 if ( isRing && !probableParts.isEmpty() )
2574 GEOSGeometry *currentGeom =
nullptr;
2575 double maxLength = -std::numeric_limits<double>::max();
2576 double currentLength = 0;
2577 for (
int i = 0; i < probableParts.size(); ++i )
2579 currentGeom = probableParts.at( i );
2580 GEOSLength_r( geosinit.ctxt, currentGeom, ¤tLength );
2581 if ( currentLength > maxLength )
2583 maxLength = currentLength;
2584 maxGeom.reset( currentGeom );
2588 GEOSGeom_destroy_r( geosinit.ctxt, currentGeom );
2591 resultLineParts.push_back( maxGeom.release() );
2595 if ( resultLineParts.empty() )
2598 if ( resultLineParts.size() == 1 )
2600 result.reset( resultLineParts[0] );
2604 GEOSGeometry **lineArray =
new GEOSGeometry*[resultLineParts.size()];
2605 for (
int i = 0; i < resultLineParts.size(); ++i )
2607 lineArray[i] = resultLineParts[i];
2611 geos::unique_ptr multiLineGeom( GEOSGeom_createCollection_r( geosinit.ctxt, GEOS_MULTILINESTRING, lineArray, resultLineParts.size() ) );
2612 delete [] lineArray;
2615 result.reset( GEOSLineMerge_r( geosinit.ctxt, multiLineGeom.get() ) );
2619 if ( GEOSGeomTypeId_r( geosinit.ctxt, result.get() ) != GEOS_LINESTRING )
2627 geos::unique_ptr QgsGeos::reshapePolygon(
const GEOSGeometry *polygon,
const GEOSGeometry *reshapeLineGeos,
double precision )
2630 int nIntersections = 0;
2631 int lastIntersectingRing = -2;
2632 const GEOSGeometry *lastIntersectingGeom =
nullptr;
2634 int nRings = GEOSGetNumInteriorRings_r( geosinit.ctxt, polygon );
2639 const GEOSGeometry *outerRing = GEOSGetExteriorRing_r( geosinit.ctxt, polygon );
2640 if ( GEOSIntersects_r( geosinit.ctxt, outerRing, reshapeLineGeos ) == 1 )
2643 lastIntersectingRing = -1;
2644 lastIntersectingGeom = outerRing;
2648 const GEOSGeometry **innerRings =
new const GEOSGeometry*[nRings];
2652 for (
int i = 0; i < nRings; ++i )
2654 innerRings[i] = GEOSGetInteriorRingN_r( geosinit.ctxt, polygon, i );
2655 if ( GEOSIntersects_r( geosinit.ctxt, innerRings[i], reshapeLineGeos ) == 1 )
2658 lastIntersectingRing = i;
2659 lastIntersectingGeom = innerRings[i];
2663 catch ( GEOSException & )
2668 if ( nIntersections != 1 )
2670 delete [] innerRings;
2675 geos::unique_ptr reshapeResult = reshapeLine( lastIntersectingGeom, reshapeLineGeos, precision );
2676 if ( !reshapeResult )
2678 delete [] innerRings;
2683 GEOSGeometry *newRing =
nullptr;
2684 const GEOSCoordSequence *reshapeSequence = GEOSGeom_getCoordSeq_r( geosinit.ctxt, reshapeResult.get() );
2685 GEOSCoordSequence *newCoordSequence = GEOSCoordSeq_clone_r( geosinit.ctxt, reshapeSequence );
2687 reshapeResult.reset();
2689 newRing = GEOSGeom_createLinearRing_r( geosinit.ctxt, newCoordSequence );
2692 delete [] innerRings;
2696 GEOSGeometry *newOuterRing =
nullptr;
2697 if ( lastIntersectingRing == -1 )
2698 newOuterRing = newRing;
2700 newOuterRing = GEOSGeom_clone_r( geosinit.ctxt, outerRing );
2703 QVector<GEOSGeometry *> ringList;
2706 GEOSGeometry *outerRingPoly = GEOSGeom_createPolygon_r( geosinit.ctxt, GEOSGeom_clone_r( geosinit.ctxt, newOuterRing ),
nullptr, 0 );
2707 if ( outerRingPoly )
2709 GEOSGeometry *currentRing =
nullptr;
2710 for (
int i = 0; i < nRings; ++i )
2712 if ( lastIntersectingRing == i )
2713 currentRing = newRing;
2715 currentRing = GEOSGeom_clone_r( geosinit.ctxt, innerRings[i] );
2718 if ( GEOSContains_r( geosinit.ctxt, outerRingPoly, currentRing ) == 1 )
2719 ringList.push_back( currentRing );
2721 GEOSGeom_destroy_r( geosinit.ctxt, currentRing );
2724 GEOSGeom_destroy_r( geosinit.ctxt, outerRingPoly );
2727 GEOSGeometry **newInnerRings =
new GEOSGeometry*[ringList.size()];
2728 for (
int i = 0; i < ringList.size(); ++i )
2729 newInnerRings[i] = ringList.at( i );
2731 delete [] innerRings;
2733 geos::unique_ptr reshapedPolygon( GEOSGeom_createPolygon_r( geosinit.ctxt, newOuterRing, newInnerRings, ringList.size() ) );
2734 delete[] newInnerRings;
2736 return reshapedPolygon;
2739 int QgsGeos::lineContainedInLine(
const GEOSGeometry *line1,
const GEOSGeometry *line2 )
2741 if ( !line1 || !line2 )
2746 double bufferDistance = std::pow( 10.0L, geomDigits( line2 ) - 11 );
2752 geos::unique_ptr intersectionGeom( GEOSIntersection_r( geosinit.ctxt, bufferGeom.get(), line1 ) );
2755 double intersectGeomLength;
2758 GEOSLength_r( geosinit.ctxt, intersectionGeom.get(), &intersectGeomLength );
2759 GEOSLength_r( geosinit.ctxt, line1, &line1Length );
2761 double intersectRatio = line1Length / intersectGeomLength;
2762 if ( intersectRatio > 0.9 && intersectRatio < 1.1 )
2768 int QgsGeos::pointContainedInLine(
const GEOSGeometry *point,
const GEOSGeometry *line )
2770 if ( !point || !line )
2773 double bufferDistance = std::pow( 10.0L, geomDigits( line ) - 11 );
2775 geos::unique_ptr lineBuffer( GEOSBuffer_r( geosinit.ctxt, line, bufferDistance, 8 ) );
2779 bool contained =
false;
2780 if ( GEOSContains_r( geosinit.ctxt, lineBuffer.get(), point ) == 1 )
2786 int QgsGeos::geomDigits(
const GEOSGeometry *geom )
2792 const GEOSGeometry *bBoxRing = GEOSGetExteriorRing_r( geosinit.ctxt, bbox.get() );
2796 const GEOSCoordSequence *bBoxCoordSeq = GEOSGeom_getCoordSeq_r( geosinit.ctxt, bBoxRing );
2798 if ( !bBoxCoordSeq )
2801 unsigned int nCoords = 0;
2802 if ( !GEOSCoordSeq_getSize_r( geosinit.ctxt, bBoxCoordSeq, &nCoords ) )
2806 for (
unsigned int i = 0; i < nCoords - 1; ++i )
2809 GEOSCoordSeq_getX_r( geosinit.ctxt, bBoxCoordSeq, i, &t );
2812 digits = std::ceil( std::log10( std::fabs( t ) ) );
2813 if ( digits > maxDigits )
2816 GEOSCoordSeq_getY_r( geosinit.ctxt, bBoxCoordSeq, i, &t );
2817 digits = std::ceil( std::log10( std::fabs( t ) ) );
2818 if ( digits > maxDigits )
2827 return geosinit.ctxt;
bool isMeasure() const
Returns true if the geometry contains m values.
A rectangle specified with double values.
bool disjoint(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Checks if geom is disjoint from this.
QgsAbstractGeometry * intersection(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Calculate the intersection of this and geom.
QgsGeometry mergeLines(QString *errorMsg=nullptr) const
Merges any connected lines in a LineString/MultiLineString geometry and converts them to single line ...
QgsGeos(const QgsAbstractGeometry *geometry, double precision=0)
GEOS geometry engine constructor.
void setXMaximum(double x)
Set the maximum x value.
const double * mData() const
Returns a const pointer to the m vertex data, or nullptr if the linestring does not have m values...
Multi point geometry collection.
static bool isMultiType(Type type)
Returns true if the WKB type is a multi type.
The source geometry is not multi.
bool isEmpty(QString *errorMsg=nullptr) const override
QgsPoint * pointOnSurface(QString *errorMsg=nullptr) const override
Calculate a point that is guaranteed to be on the surface of this.
QgsGeometry shortestLine(const QgsGeometry &other, QString *errorMsg=nullptr) const
Returns the shortest line joining this geometry to the other geometry.
double area(QString *errorMsg=nullptr) const override
A class to represent a 2D point.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
const QgsAbstractGeometry * mGeometry
const QgsCurve * interiorRing(int i) const
Retrieves an interior ring from the curve polygon.
QgsAbstractGeometry * buffer(double distance, int segments, QString *errorMsg=nullptr) const override
bool isValid(QString *errorMsg=nullptr, bool allowSelfTouchingHoles=false, QgsGeometry *errorLoc=nullptr) const override
Returns true if the geometry is valid.
Multi line string geometry collection.
Curve polygon geometry type.
static std::unique_ptr< QgsGeometryCollection > createCollectionOfType(QgsWkbTypes::Type type)
Returns a new geometry collection matching a specified WKB type.
double length(QString *errorMsg=nullptr) const override
A geometry is the spatial representation of a feature.
bool isEqual(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Checks if this is equal to geom.
QgsGeometry closestPoint(const QgsGeometry &other, QString *errorMsg=nullptr) const
Returns the closest point on the geometry to the other geometry.
virtual QgsRectangle boundingBox() const =0
Returns the minimal bounding box for the geometry.
static QgsGeometry::OperationResult addPart(QgsGeometry &geometry, GEOSGeometry *newPart)
Adds a new island polygon to a multipolygon feature.
void CORE_EXPORT operator()(GEOSGeometry *geom)
Destroys the GEOS geometry geom, using the static QGIS geos context.
virtual QgsAbstractGeometry * clone() const =0
Clones the geometry by performing a deep copy.
QMap< QString, QString > QgsStringMap
OperationResult
Success or failure of a geometry operation.
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 GEOSContextHandle_t getGEOSHandler()
int numPoints() const override
Returns the number of points in the curve.
QgsAbstractGeometry * interpolate(double distance, QString *errorMsg=nullptr) const override
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 within(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Checks if geom is within this.
const double * xData() const
Returns a const pointer to the x vertex data.
#define CATCH_GEOS_WITH_ERRMSG(r)
int numInteriorRings() const
Returns the number of interior rings contained with the curve polygon.
Nothing happened, without any error.
Type
The WKB type describes the number of dimensions a geometry has.
QgsAbstractGeometry * envelope(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.
static std::unique_ptr< QgsAbstractGeometry > fromGeos(const GEOSGeometry *geos)
Create a geometry from a GEOSGeometry.
void addVertex(const QgsPoint &pt)
Adds a new vertex to the end of the line string.
bool touches(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Checks if geom touches this.
bool isEmpty() const
Returns true if the rectangle is empty.
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...
void prepareGeometry() override
Prepares the geometry, so that subsequent calls to spatial relation methods are much faster...
double width() const
Returns the width of the rectangle.
double mAt(int index) const
Returns the m value of the specified node in the line string.
void setYMinimum(double y)
Set the minimum y value.
std::unique_ptr< GEOSGeometry, GeosDeleter > unique_ptr
Scoped GEOS pointer.
double yAt(int index) const override
Returns the y-coordinate of the specified node in the line string.
static GeometryType geometryType(Type type)
Returns the geometry type for a WKB type, e.g., both MultiPolygon and CurvePolygon would have a Polyg...
double hausdorffDistanceDensify(const QgsAbstractGeometry *geom, double densifyFraction, QString *errorMsg=nullptr) const
Returns the Hausdorff distance between this geometry and geom.
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...
QgsPoint * centroid(QString *errorMsg=nullptr) const override
Calculates the centroid of this.
T qgsgeometry_cast(const QgsAbstractGeometry *geom)
Multi curve geometry collection.
double distance(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Calculates the distance between this and geom.
static QgsGeometry polygonize(const QVector< const QgsAbstractGeometry *> &geometries, QString *errorMsg=nullptr)
Creates a GeometryCollection geometry containing possible polygons formed from the constituent linewo...
QgsPoint * clone() const override
Clones the geometry by performing a deep copy.
Abstract base class for curved geometry type.
Abstract base class for all geometries.
virtual int dimension() const =0
Returns the inherent dimension of the geometry.
std::unique_ptr< GEOSBufferParams, GeosDeleter > buffer_params_unique_ptr
Scoped GEOS buffer params pointer.
QgsWkbTypes::Type wkbType() const
Returns the WKB type of the geometry.
Point geometry type, with support for z-dimension and m-values.
QgsGeometry delaunayTriangulation(double tolerance=0.0, bool edgesOnly=false, QString *errorMsg=nullptr) const
Returns the Delaunay triangulation for the vertices of the geometry.
const double * yData() const
Returns a const pointer to the y vertex data.
Error occurred while creating a noded geometry.
QgsLineString * clone() const override
Clones the geometry by performing a deep copy.
Error occurred in the geometry engine.
const double * zData() const
Returns a const pointer to the z vertex data, or nullptr if the linestring does not have z values...
int numGeometries() const
Returns the number of geometries within the collection.
QgsAbstractGeometry * symDifference(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Calculate the symmetric difference of this and geom.
Contains geos related utilities and functions.
std::unique_ptr< QgsAbstractGeometry > clip(const QgsRectangle &rectangle, QString *errorMsg=nullptr) const
Performs a fast, non-robust intersection between the geometry and a rectangle.
QgsAbstractGeometry * get()
Returns a modifiable (non-const) reference to the underlying abstract geometry primitive.
const QgsAbstractGeometry * constGet() const
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
QgsAbstractGeometry * combine(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Calculate the combination of this and geom.
double xMaximum() const
Returns the x maximum value (right side of rectangle).
void geometryChanged() override
Should be called whenever the geometry associated with the engine has been modified and the engine mu...
QVector< QgsPoint > QgsPointSequence
static QgsPoint coordSeqPoint(const GEOSCoordSequence *cs, int i, bool hasZ, bool hasM)
static QgsGeometry::OperationResult addPart(QgsAbstractGeometry *geometry, std::unique_ptr< QgsAbstractGeometry > part)
Add a part to multi type geometry.
QgsAbstractGeometry * offsetCurve(double distance, int segments, int joinStyle, double miterLimit, QString *errorMsg=nullptr) const override
QgsAbstractGeometry * convexHull(QString *errorMsg=nullptr) const override
Calculate the convex hull of this.
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...
The base geometry on which the operation is done is invalid or empty.
Multi polygon geometry collection.
bool addGeometry(QgsAbstractGeometry *g) override
Adds a geometry and takes ownership. Returns true in case of success.
bool contains(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Checks if geom contains this.
void setYMaximum(double y)
Set the maximum y value.
std::unique_ptr< QgsAbstractGeometry > subdivide(int maxNodes, QString *errorMsg=nullptr) const
Subdivides the geometry.
Line string geometry type, with support for z-dimension and m-values.
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...
const QgsAbstractGeometry * geometryN(int n) const
Returns a const reference to a geometry from within the collection.
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 isNull() const
Test if the rectangle is null (all coordinates zero or after call to setMinimal()).
QgsPoint pointN(int i) const
Returns the specified point from inside the line string.
EngineOperationResult splitGeometry(const QgsLineString &splitLine, QVector< QgsGeometry > &newGeometries, bool topological, QgsPointSequence &topologyTestPoints, QString *errorMsg=nullptr) const override
Splits this geometry according to a given line.
bool intersects(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Checks if geom intersects this.
double xMinimum() const
Returns the x minimum value (left side of rectangle).
double hausdorffDistance(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const
Returns the Hausdorff distance between this geometry and geom.
double xAt(int index) const override
Returns the x-coordinate of the specified node in the line string.
QgsAbstractGeometry * difference(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Calculate the difference of this and geom.
bool overlaps(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Checks if geom overlaps this.
Contains geometry relation and modification algorithms.
double yMaximum() const
Returns the y maximum value (top side of rectangle).
static std::unique_ptr< QgsPolygon > fromGeosPolygon(const GEOSGeometry *geos)
std::unique_ptr< GEOSCoordSequence, GeosDeleter > coord_sequence_unique_ptr
Scoped GEOS coordinate sequence pointer.
EngineOperationResult
Success or failure of a geometry operation.
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.
static QgsGeometry geometryFromGeos(GEOSGeometry *geos)
Creates a new QgsGeometry object, feeding in a geometry in GEOS format.
const QgsCurve * exteriorRing() const
Returns the curve polygon's exterior ring.
static Type flatType(Type type)
Returns the flat type for a WKB type.
The geometry on which the operation occurs is not valid.
#define DEFAULT_QUADRANT_SEGMENTS
bool is3D() const
Returns true if the geometry is 3D and contains a z-value.
bool isSimple(QString *errorMsg=nullptr) const override
Determines whether the geometry is simple (according to OGC definition).
bool crosses(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Checks if geom crosses this.
void setXMinimum(double x)
Set the minimum x value.
QgsAbstractGeometry * simplify(double tolerance, QString *errorMsg=nullptr) const override
virtual bool addGeometry(QgsAbstractGeometry *g)
Adds a geometry and takes ownership. Returns true in case of success.
double height() const
Returns the height of the rectangle.