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 for (
int i = 0; i < nParts; ++i )
1114 const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq_r( geosinit.ctxt, GEOSGetGeometryN_r( geosinit.ctxt, geos, i ) );
1117 multiPoint->addGeometry(
coordSeqPoint( cs, 0, hasZ, hasM ).clone() );
1120 return std::move( multiPoint );
1122 case GEOS_MULTILINESTRING:
1125 int nParts = GEOSGetNumGeometries_r( geosinit.ctxt, geos );
1126 for (
int i = 0; i < nParts; ++i )
1128 std::unique_ptr< QgsLineString >line( sequenceToLinestring( GEOSGetGeometryN_r( geosinit.ctxt, geos, i ), hasZ, hasM ) );
1131 multiLineString->addGeometry( line.release() );
1134 return std::move( multiLineString );
1136 case GEOS_MULTIPOLYGON:
1138 std::unique_ptr< QgsMultiPolygon > multiPolygon(
new QgsMultiPolygon() );
1140 int nParts = GEOSGetNumGeometries_r( geosinit.ctxt, geos );
1141 for (
int i = 0; i < nParts; ++i )
1143 std::unique_ptr< QgsPolygon > poly =
fromGeosPolygon( GEOSGetGeometryN_r( geosinit.ctxt, geos, i ) );
1146 multiPolygon->addGeometry( poly.release() );
1149 return std::move( multiPolygon );
1151 case GEOS_GEOMETRYCOLLECTION:
1154 int nParts = GEOSGetNumGeometries_r( geosinit.ctxt, geos );
1155 for (
int i = 0; i < nParts; ++i )
1157 std::unique_ptr< QgsAbstractGeometry > geom(
fromGeos( GEOSGetGeometryN_r( geosinit.ctxt, geos, i ) ) );
1160 geomCollection->addGeometry( geom.release() );
1163 return std::move( geomCollection );
1171 if ( GEOSGeomTypeId_r( geosinit.ctxt, geos ) != GEOS_POLYGON )
1176 int nCoordDims = GEOSGeom_getCoordinateDimension_r( geosinit.ctxt, geos );
1177 int nDims = GEOSGeom_getDimensions_r( geosinit.ctxt, geos );
1178 bool hasZ = ( nCoordDims == 3 );
1179 bool hasM = ( ( nDims - nCoordDims ) == 1 );
1181 std::unique_ptr< QgsPolygon > polygon(
new QgsPolygon() );
1183 const GEOSGeometry *ring = GEOSGetExteriorRing_r( geosinit.ctxt, geos );
1186 polygon->setExteriorRing( sequenceToLinestring( ring, hasZ, hasM ).release() );
1189 QVector<QgsCurve *> interiorRings;
1190 const int ringCount = GEOSGetNumInteriorRings_r( geosinit.ctxt, geos );
1191 interiorRings.reserve( ringCount );
1192 for (
int i = 0; i < ringCount; ++i )
1194 ring = GEOSGetInteriorRingN_r( geosinit.ctxt, geos, i );
1197 interiorRings.push_back( sequenceToLinestring( ring, hasZ, hasM ).release() );
1200 polygon->setInteriorRings( interiorRings );
1205 std::unique_ptr<QgsLineString> QgsGeos::sequenceToLinestring(
const GEOSGeometry *
geos,
bool hasZ,
bool hasM )
1207 const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq_r( geosinit.ctxt,
geos );
1208 unsigned int nPoints;
1209 GEOSCoordSeq_getSize_r( geosinit.ctxt, cs, &nPoints );
1210 QVector< double > xOut( nPoints );
1211 QVector< double > yOut( nPoints );
1212 QVector< double > zOut;
1214 zOut.resize( nPoints );
1215 QVector< double > mOut;
1217 mOut.resize( nPoints );
1218 double *x = xOut.data();
1219 double *y = yOut.data();
1220 double *z = zOut.data();
1221 double *m = mOut.data();
1222 for (
unsigned int i = 0; i < nPoints; ++i )
1224 GEOSCoordSeq_getX_r( geosinit.ctxt, cs, i, x++ );
1225 GEOSCoordSeq_getY_r( geosinit.ctxt, cs, i, y++ );
1228 GEOSCoordSeq_getZ_r( geosinit.ctxt, cs, i, z++ );
1232 GEOSCoordSeq_getOrdinate_r( geosinit.ctxt, cs, i, 3, m++ );
1235 std::unique_ptr< QgsLineString > line(
new QgsLineString( xOut, yOut, zOut, mOut ) );
1239 int QgsGeos::numberOfGeometries( GEOSGeometry *g )
1244 int geometryType = GEOSGeomTypeId_r( geosinit.ctxt, g );
1245 if ( geometryType == GEOS_POINT || geometryType == GEOS_LINESTRING || geometryType == GEOS_LINEARRING
1246 || geometryType == GEOS_POLYGON )
1250 return GEOSGetNumGeometries_r( geosinit.ctxt, g );
1263 GEOSCoordSeq_getX_r( geosinit.ctxt, cs, i, &x );
1264 GEOSCoordSeq_getY_r( geosinit.ctxt, cs, i, &y );
1267 GEOSCoordSeq_getZ_r( geosinit.ctxt, cs, i, &z );
1271 GEOSCoordSeq_getOrdinate_r( geosinit.ctxt, cs, i, 3, &m );
1307 int geosType = GEOS_GEOMETRYCOLLECTION;
1314 geosType = GEOS_MULTIPOINT;
1318 geosType = GEOS_MULTILINESTRING;
1322 geosType = GEOS_MULTIPOLYGON;
1343 return createGeosCollection( geosType, geomVector );
1350 return createGeosPoint( static_cast<const QgsPoint *>( geom ), coordDims, precision );
1354 return createGeosLinestring( static_cast<const QgsLineString *>( geom ), precision );
1358 return createGeosPolygon( static_cast<const QgsPolygon *>( geom ), precision );
1370 std::unique_ptr<QgsAbstractGeometry> QgsGeos::overlay(
const QgsAbstractGeometry *geom, Overlay op, QString *errorMsg )
const 1372 if ( !mGeos || !geom )
1388 case OverlayIntersection:
1389 opGeom.reset( GEOSIntersection_r( geosinit.ctxt, mGeos.get(), geosGeom.get() ) );
1391 case OverlayDifference:
1392 opGeom.reset( GEOSDifference_r( geosinit.ctxt, mGeos.get(), geosGeom.get() ) );
1396 geos::unique_ptr unionGeometry( GEOSUnion_r( geosinit.ctxt, mGeos.get(), geosGeom.get() ) );
1398 if ( unionGeometry && GEOSGeomTypeId_r( geosinit.ctxt, unionGeometry.get() ) == GEOS_MULTILINESTRING )
1400 geos::unique_ptr mergedLines( GEOSLineMerge_r( geosinit.ctxt, unionGeometry.get() ) );
1403 unionGeometry = std::move( mergedLines );
1407 opGeom = std::move( unionGeometry );
1410 case OverlaySymDifference:
1411 opGeom.reset( GEOSSymDifference_r( geosinit.ctxt, mGeos.get(), geosGeom.get() ) );
1418 catch ( GEOSException &e )
1422 *errorMsg = e.what();
1428 bool QgsGeos::relation(
const QgsAbstractGeometry *geom, Relation r, QString *errorMsg )
const 1430 if ( !mGeos || !geom )
1441 bool result =
false;
1444 if ( mGeosPrepared )
1448 case RelationIntersects:
1449 result = ( GEOSPreparedIntersects_r( geosinit.ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1451 case RelationTouches:
1452 result = ( GEOSPreparedTouches_r( geosinit.ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1454 case RelationCrosses:
1455 result = ( GEOSPreparedCrosses_r( geosinit.ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1457 case RelationWithin:
1458 result = ( GEOSPreparedWithin_r( geosinit.ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1460 case RelationContains:
1461 result = ( GEOSPreparedContains_r( geosinit.ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1463 case RelationDisjoint:
1464 result = ( GEOSPreparedDisjoint_r( geosinit.ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1466 case RelationOverlaps:
1467 result = ( GEOSPreparedOverlaps_r( geosinit.ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1477 case RelationIntersects:
1478 result = ( GEOSIntersects_r( geosinit.ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1480 case RelationTouches:
1481 result = ( GEOSTouches_r( geosinit.ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1483 case RelationCrosses:
1484 result = ( GEOSCrosses_r( geosinit.ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1486 case RelationWithin:
1487 result = ( GEOSWithin_r( geosinit.ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1489 case RelationContains:
1490 result = ( GEOSContains_r( geosinit.ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1492 case RelationDisjoint:
1493 result = ( GEOSDisjoint_r( geosinit.ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1495 case RelationOverlaps:
1496 result = ( GEOSOverlaps_r( geosinit.ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1502 catch ( GEOSException &e )
1506 *errorMsg = e.what();
1524 geos.reset( GEOSBuffer_r( geosinit.ctxt, mGeos.get(),
distance, segments ) );
1527 return fromGeos( geos.get() ).release();
1540 geos.reset( GEOSBufferWithStyle_r( geosinit.ctxt, mGeos.get(),
distance, segments, endCapStyle, joinStyle, miterLimit ) );
1543 return fromGeos( geos.get() ).release();
1555 geos.reset( GEOSTopologyPreserveSimplify_r( geosinit.ctxt, mGeos.get(), tolerance ) );
1558 return fromGeos( geos.get() ).release();
1570 geos.reset( GEOSInterpolate_r( geosinit.ctxt, mGeos.get(),
distance ) );
1573 return fromGeos( geos.get() ).release();
1589 geos.reset( GEOSGetCentroid_r( geosinit.ctxt, mGeos.get() ) );
1594 GEOSGeomGetX_r( geosinit.ctxt, geos.get(), &x );
1595 GEOSGeomGetY_r( geosinit.ctxt, geos.get(), &y );
1611 geos.reset( GEOSEnvelope_r( geosinit.ctxt, mGeos.get() ) );
1614 return fromGeos( geos.get() ).release();
1630 geos.reset( GEOSPointOnSurface_r( geosinit.ctxt, mGeos.get() ) );
1632 if ( !geos || GEOSisEmpty_r( geosinit.ctxt, geos.get() ) != 0 )
1637 GEOSGeomGetX_r( geosinit.ctxt, geos.get(), &x );
1638 GEOSGeomGetY_r( geosinit.ctxt, geos.get(), &y );
1655 std::unique_ptr< QgsAbstractGeometry > cHullGeom =
fromGeos( cHull.get() );
1656 return cHullGeom.release();
1670 GEOSGeometry *g1 =
nullptr;
1672 char res = GEOSisValidDetail_r( geosinit.ctxt, mGeos.get(), allowSelfTouchingHoles ? GEOSVALID_ALLOW_SELFTOUCHING_RING_FORMING_HOLE : 0, &r, &g1 );
1673 const bool invalid = res != 1;
1678 error = QString( r );
1679 GEOSFree_r( geosinit.ctxt, r );
1682 if ( invalid && errorMsg )
1686 if ( translatedErrors.empty() )
1689 translatedErrors.insert( QStringLiteral(
"topology validation error" ), QObject::tr(
"Topology validation error",
"GEOS Error" ) );
1690 translatedErrors.insert( QStringLiteral(
"repeated point" ), QObject::tr(
"Repeated point",
"GEOS Error" ) );
1691 translatedErrors.insert( QStringLiteral(
"hole lies outside shell" ), QObject::tr(
"Hole lies outside shell",
"GEOS Error" ) );
1692 translatedErrors.insert( QStringLiteral(
"holes are nested" ), QObject::tr(
"Holes are nested",
"GEOS Error" ) );
1693 translatedErrors.insert( QStringLiteral(
"interior is disconnected" ), QObject::tr(
"Interior is disconnected",
"GEOS Error" ) );
1694 translatedErrors.insert( QStringLiteral(
"self-intersection" ), QObject::tr(
"Self-intersection",
"GEOS Error" ) );
1695 translatedErrors.insert( QStringLiteral(
"ring self-intersection" ), QObject::tr(
"Ring self-intersection",
"GEOS Error" ) );
1696 translatedErrors.insert( QStringLiteral(
"nested shells" ), QObject::tr(
"Nested shells",
"GEOS Error" ) );
1697 translatedErrors.insert( QStringLiteral(
"duplicate rings" ), QObject::tr(
"Duplicate rings",
"GEOS Error" ) );
1698 translatedErrors.insert( QStringLiteral(
"too few points in geometry component" ), QObject::tr(
"Too few points in geometry component",
"GEOS Error" ) );
1699 translatedErrors.insert( QStringLiteral(
"invalid coordinate" ), QObject::tr(
"Invalid coordinate",
"GEOS Error" ) );
1700 translatedErrors.insert( QStringLiteral(
"ring is not closed" ), QObject::tr(
"Ring is not closed",
"GEOS Error" ) );
1703 *errorMsg = translatedErrors.value( error.toLower(), error );
1705 if ( g1 && errorLoc )
1711 GEOSGeom_destroy_r( geosinit.ctxt, g1 );
1721 if ( !mGeos || !geom )
1733 bool equal = GEOSEquals_r( geosinit.ctxt, mGeos.get(), geosGeom.get() );
1748 return GEOSisEmpty_r( geosinit.ctxt, mGeos.get() );
1762 return GEOSisSimple_r( geosinit.ctxt, mGeos.get() );
1767 GEOSCoordSequence *QgsGeos::createCoordinateSequence(
const QgsCurve *curve,
double precision,
bool forceClose )
1769 std::unique_ptr< QgsLineString > segmentized;
1775 line = segmentized.get();
1783 bool hasZ = line->
is3D();
1797 int numOutPoints = numPoints;
1798 if ( forceClose && ( line->
pointN( 0 ) != line->
pointN( numPoints - 1 ) ) )
1803 GEOSCoordSequence *coordSeq =
nullptr;
1806 coordSeq = GEOSCoordSeq_create_r( geosinit.ctxt, numOutPoints, coordDims );
1809 QgsDebugMsg( QStringLiteral(
"GEOS Exception: Could not create coordinate sequence for %1 points in %2 dimensions" ).arg( numPoints ).arg( coordDims ) );
1813 const double *xData = line->
xData();
1814 const double *yData = line->
yData();
1815 const double *zData = hasZ ? line->
zData() :
nullptr;
1816 const double *mData = hasM ? line->
mData() :
nullptr;
1820 for (
int i = 0; i < numOutPoints; ++i )
1822 if ( i >= numPoints )
1825 xData = line->
xData();
1826 yData = line->
yData();
1827 zData = hasZ ? line->
zData() :
nullptr;
1828 mData = hasM ? line->
mData() :
nullptr;
1830 GEOSCoordSeq_setX_r( geosinit.ctxt, coordSeq, i, std::round( *xData++ /
precision ) *
precision );
1831 GEOSCoordSeq_setY_r( geosinit.ctxt, coordSeq, i, std::round( *yData++ / precision ) * precision );
1834 GEOSCoordSeq_setOrdinate_r( geosinit.ctxt, coordSeq, i, 2, std::round( *zData++ / precision ) * precision );
1838 GEOSCoordSeq_setOrdinate_r( geosinit.ctxt, coordSeq, i, 3, line->
mAt( *mData++ ) );
1844 for (
int i = 0; i < numOutPoints; ++i )
1846 if ( i >= numPoints )
1849 xData = line->
xData();
1850 yData = line->
yData();
1851 zData = hasZ ? line->
zData() :
nullptr;
1852 mData = hasM ? line->
mData() :
nullptr;
1854 GEOSCoordSeq_setX_r( geosinit.ctxt, coordSeq, i, *xData++ );
1855 GEOSCoordSeq_setY_r( geosinit.ctxt, coordSeq, i, *yData++ );
1858 GEOSCoordSeq_setOrdinate_r( geosinit.ctxt, coordSeq, i, 2, *zData++ );
1862 GEOSCoordSeq_setOrdinate_r( geosinit.ctxt, coordSeq, i, 3, *mData++ );
1881 geos::unique_ptr QgsGeos::createGeosPointXY(
double x,
double y,
bool hasZ,
double z,
bool hasM,
double m,
int coordDims,
double precision )
1890 GEOSCoordSequence *coordSeq = GEOSCoordSeq_create_r( geosinit.ctxt, 1, coordDims );
1893 QgsDebugMsg( QStringLiteral(
"GEOS Exception: Could not create coordinate sequence for point with %1 dimensions" ).arg( coordDims ) );
1896 if ( precision > 0. )
1898 GEOSCoordSeq_setX_r( geosinit.ctxt, coordSeq, 0, std::round( x / precision ) * precision );
1899 GEOSCoordSeq_setY_r( geosinit.ctxt, coordSeq, 0, std::round( y / precision ) * precision );
1902 GEOSCoordSeq_setOrdinate_r( geosinit.ctxt, coordSeq, 0, 2, std::round( z / precision ) * precision );
1907 GEOSCoordSeq_setX_r( geosinit.ctxt, coordSeq, 0, x );
1908 GEOSCoordSeq_setY_r( geosinit.ctxt, coordSeq, 0, y );
1911 GEOSCoordSeq_setOrdinate_r( geosinit.ctxt, coordSeq, 0, 2, z );
1914 #if 0 //disabled until geos supports m-coordinates 1917 GEOSCoordSeq_setOrdinate_r( geosinit.ctxt, coordSeq, 0, 3, m );
1920 geosPoint.reset( GEOSGeom_createPoint_r( geosinit.ctxt, coordSeq ) );
1932 GEOSCoordSequence *coordSeq = createCoordinateSequence( c, precision );
1939 geosGeom.reset( GEOSGeom_createLineString_r( geosinit.ctxt, coordSeq ) );
1952 if ( !exteriorRing )
1960 geos::unique_ptr exteriorRingGeos( GEOSGeom_createLinearRing_r( geosinit.ctxt, createCoordinateSequence( exteriorRing, precision,
true ) ) );
1963 GEOSGeometry **holes =
nullptr;
1966 holes =
new GEOSGeometry*[ nHoles ];
1969 for (
int i = 0; i < nHoles; ++i )
1972 holes[i] = GEOSGeom_createLinearRing_r( geosinit.ctxt, createCoordinateSequence( interiorRing, precision,
true ) );
1974 geosPolygon.reset( GEOSGeom_createPolygon_r( geosinit.ctxt, exteriorRingGeos.release(), holes, nHoles ) );
1990 offset.reset( GEOSOffsetCurve_r( geosinit.ctxt, mGeos.get(),
distance, segments, joinStyle, miterLimit ) );
1993 std::unique_ptr< QgsAbstractGeometry > offsetGeom =
fromGeos( offset.get() );
1994 return offsetGeom.release();
2008 GEOSBufferParams_setSingleSided_r( geosinit.ctxt, bp.get(), 1 );
2009 GEOSBufferParams_setQuadrantSegments_r( geosinit.ctxt, bp.get(), segments );
2010 GEOSBufferParams_setJoinStyle_r( geosinit.ctxt, bp.get(), joinStyle );
2011 GEOSBufferParams_setMitreLimit_r( geosinit.ctxt, bp.get(), miterLimit );
2017 geos.reset( GEOSBufferWithParams_r( geosinit.ctxt, mGeos.get(), bp.get(),
distance ) );
2037 geos::unique_ptr reshapeLineGeos = createGeosLinestring( &reshapeWithLine, mPrecision );
2040 int numGeoms = GEOSGetNumGeometries_r( geosinit.ctxt, mGeos.get() );
2041 if ( numGeoms == -1 )
2050 bool isMultiGeom =
false;
2051 int geosTypeId = GEOSGeomTypeId_r( geosinit.ctxt, mGeos.get() );
2052 if ( geosTypeId == GEOS_MULTILINESTRING || geosTypeId == GEOS_MULTIPOLYGON )
2062 reshapedGeometry = reshapeLine( mGeos.get(), reshapeLineGeos.get(), mPrecision );
2066 reshapedGeometry = reshapePolygon( mGeos.get(), reshapeLineGeos.get(), mPrecision );
2071 std::unique_ptr< QgsAbstractGeometry > reshapeResult =
fromGeos( reshapedGeometry.get() );
2072 return reshapeResult;
2079 bool reshapeTookPlace =
false;
2082 GEOSGeometry **newGeoms =
new GEOSGeometry*[numGeoms];
2084 for (
int i = 0; i < numGeoms; ++i )
2087 currentReshapeGeometry = reshapeLine( GEOSGetGeometryN_r( geosinit.ctxt, mGeos.get(), i ), reshapeLineGeos.get(), mPrecision );
2089 currentReshapeGeometry = reshapePolygon( GEOSGetGeometryN_r( geosinit.ctxt, mGeos.get(), i ), reshapeLineGeos.get(), mPrecision );
2091 if ( currentReshapeGeometry )
2093 newGeoms[i] = currentReshapeGeometry.release();
2094 reshapeTookPlace =
true;
2098 newGeoms[i] = GEOSGeom_clone_r( geosinit.ctxt, GEOSGetGeometryN_r( geosinit.ctxt, mGeos.get(), i ) );
2105 newMultiGeom.reset( GEOSGeom_createCollection_r( geosinit.ctxt, GEOS_MULTILINESTRING, newGeoms, numGeoms ) );
2109 newMultiGeom.reset( GEOSGeom_createCollection_r( geosinit.ctxt, GEOS_MULTIPOLYGON, newGeoms, numGeoms ) );
2113 if ( !newMultiGeom )
2119 if ( reshapeTookPlace )
2123 std::unique_ptr< QgsAbstractGeometry > reshapedMultiGeom =
fromGeos( newMultiGeom.get() );
2124 return reshapedMultiGeom;
2146 if ( GEOSGeomTypeId_r( geosinit.ctxt, mGeos.get() ) != GEOS_MULTILINESTRING )
2152 geos.reset( GEOSLineMerge_r( geosinit.ctxt, mGeos.get() ) );
2160 if ( !mGeos || other.
isNull() )
2177 ( void )GEOSCoordSeq_getX_r( geosinit.ctxt, nearestCoord.get(), 0, &nx );
2178 ( void )GEOSCoordSeq_getY_r( geosinit.ctxt, nearestCoord.get(), 0, &ny );
2180 catch ( GEOSException &e )
2184 *errorMsg = e.what();
2194 if ( !mGeos || other.
isNull() )
2213 ( void )GEOSCoordSeq_getX_r( geosinit.ctxt, nearestCoord.get(), 0, &nx1 );
2214 ( void )GEOSCoordSeq_getY_r( geosinit.ctxt, nearestCoord.get(), 0, &ny1 );
2215 ( void )GEOSCoordSeq_getX_r( geosinit.ctxt, nearestCoord.get(), 1, &nx2 );
2216 ( void )GEOSCoordSeq_getY_r( geosinit.ctxt, nearestCoord.get(), 1, &ny2 );
2218 catch ( GEOSException &e )
2222 *errorMsg = e.what();
2249 distance = GEOSProject_r( geosinit.ctxt, mGeos.get(), otherGeom.get() );
2251 catch ( GEOSException &e )
2255 *errorMsg = e.what();
2265 GEOSGeometry **
const lineGeosGeometries =
new GEOSGeometry*[ geometries.size()];
2272 lineGeosGeometries[validLines] = l.release();
2279 geos::unique_ptr result( GEOSPolygonize_r( geosinit.ctxt, lineGeosGeometries, validLines ) );
2280 for (
int i = 0; i < validLines; ++i )
2282 GEOSGeom_destroy_r( geosinit.ctxt, lineGeosGeometries[i] );
2284 delete[] lineGeosGeometries;
2287 catch ( GEOSException &e )
2291 *errorMsg = e.what();
2293 for (
int i = 0; i < validLines; ++i )
2295 GEOSGeom_destroy_r( geosinit.ctxt, lineGeosGeometries[i] );
2297 delete[] lineGeosGeometries;
2312 extentGeosGeom =
asGeos( extent, mPrecision );
2313 if ( !extentGeosGeom )
2322 geos.reset( GEOSVoronoiDiagram_r( geosinit.ctxt, mGeos.get(), extentGeosGeom.get(), tolerance, edgesOnly ) );
2324 if ( !geos || GEOSisEmpty_r( geosinit.ctxt, geos.get() ) != 0 )
2344 geos.reset( GEOSDelaunayTriangulation_r( geosinit.ctxt, mGeos.get(), tolerance, edgesOnly ) );
2346 if ( !geos || GEOSisEmpty_r( geosinit.ctxt, geos.get() ) != 0 )
2358 static bool _linestringEndpoints(
const GEOSGeometry *linestring,
double &x1,
double &y1,
double &x2,
double &y2 )
2360 const GEOSCoordSequence *coordSeq = GEOSGeom_getCoordSeq_r( geosinit.ctxt, linestring );
2364 unsigned int coordSeqSize;
2365 if ( GEOSCoordSeq_getSize_r( geosinit.ctxt, coordSeq, &coordSeqSize ) == 0 )
2368 if ( coordSeqSize < 2 )
2371 GEOSCoordSeq_getX_r( geosinit.ctxt, coordSeq, 0, &x1 );
2372 GEOSCoordSeq_getY_r( geosinit.ctxt, coordSeq, 0, &y1 );
2373 GEOSCoordSeq_getX_r( geosinit.ctxt, coordSeq, coordSeqSize - 1, &x2 );
2374 GEOSCoordSeq_getY_r( geosinit.ctxt, coordSeq, coordSeqSize - 1, &y2 );
2380 static geos::unique_ptr _mergeLinestrings(
const GEOSGeometry *line1,
const GEOSGeometry *line2,
const QgsPointXY &intersectionPoint )
2382 double x1, y1, x2, y2;
2383 if ( !_linestringEndpoints( line1, x1, y1, x2, y2 ) )
2386 double rx1, ry1, rx2, ry2;
2387 if ( !_linestringEndpoints( line2, rx1, ry1, rx2, ry2 ) )
2390 bool intersectionAtOrigLineEndpoint =
2391 ( intersectionPoint.
x() == x1 && intersectionPoint.
y() == y1 ) !=
2392 ( intersectionPoint.
x() == x2 && intersectionPoint.
y() == y2 );
2393 bool intersectionAtReshapeLineEndpoint =
2394 ( intersectionPoint.
x() == rx1 && intersectionPoint.
y() == ry1 ) ||
2395 ( intersectionPoint.
x() == rx2 && intersectionPoint.
y() == ry2 );
2398 if ( intersectionAtOrigLineEndpoint && intersectionAtReshapeLineEndpoint )
2402 GEOSGeometry *geoms[2] = { g1.release(), g2.release() };
2403 geos::unique_ptr multiGeom( GEOSGeom_createCollection_r( geosinit.ctxt, GEOS_MULTILINESTRING, geoms, 2 ) );
2412 geos::unique_ptr QgsGeos::reshapeLine(
const GEOSGeometry *line,
const GEOSGeometry *reshapeLineGeos,
double precision )
2414 if ( !line || !reshapeLineGeos )
2417 bool atLeastTwoIntersections =
false;
2418 bool oneIntersection =
false;
2424 geos::unique_ptr intersectGeom( GEOSIntersection_r( geosinit.ctxt, line, reshapeLineGeos ) );
2425 if ( intersectGeom )
2427 atLeastTwoIntersections = ( GEOSGeomTypeId_r( geosinit.ctxt, intersectGeom.get() ) == GEOS_MULTIPOINT
2428 && GEOSGetNumGeometries_r( geosinit.ctxt, intersectGeom.get() ) > 1 );
2430 if ( GEOSGeomTypeId_r( geosinit.ctxt, intersectGeom.get() ) == GEOS_POINT )
2432 const GEOSCoordSequence *intersectionCoordSeq = GEOSGeom_getCoordSeq_r( geosinit.ctxt, intersectGeom.get() );
2434 GEOSCoordSeq_getX_r( geosinit.ctxt, intersectionCoordSeq, 0, &xi );
2435 GEOSCoordSeq_getY_r( geosinit.ctxt, intersectionCoordSeq, 0, &yi );
2436 oneIntersection =
true;
2441 catch ( GEOSException & )
2443 atLeastTwoIntersections =
false;
2447 if ( oneIntersection )
2448 return _mergeLinestrings( line, reshapeLineGeos, oneIntersectionPoint );
2450 if ( !atLeastTwoIntersections )
2454 double x1, y1, x2, y2;
2455 if ( !_linestringEndpoints( line, x1, y1, x2, y2 ) )
2458 geos::unique_ptr beginLineVertex = createGeosPointXY( x1, y1,
false, 0,
false, 0, 2, precision );
2459 geos::unique_ptr endLineVertex = createGeosPointXY( x2, y2,
false, 0,
false, 0, 2, precision );
2461 bool isRing =
false;
2462 if ( GEOSGeomTypeId_r( geosinit.ctxt, line ) == GEOS_LINEARRING
2463 || GEOSEquals_r( geosinit.ctxt, beginLineVertex.get(), endLineVertex.get() ) == 1 )
2468 if ( !nodedGeometry )
2474 geos::unique_ptr mergedLines( GEOSLineMerge_r( geosinit.ctxt, nodedGeometry.get() ) );
2480 int numMergedLines = GEOSGetNumGeometries_r( geosinit.ctxt, mergedLines.get() );
2481 if ( numMergedLines < 2 )
2483 if ( numMergedLines == 1 )
2485 geos::unique_ptr result( GEOSGeom_clone_r( geosinit.ctxt, reshapeLineGeos ) );
2492 QVector<GEOSGeometry *> resultLineParts;
2493 QVector<GEOSGeometry *> probableParts;
2495 for (
int i = 0; i < numMergedLines; ++i )
2497 const GEOSGeometry *currentGeom =
nullptr;
2499 currentGeom = GEOSGetGeometryN_r( geosinit.ctxt, mergedLines.get(), i );
2500 const GEOSCoordSequence *currentCoordSeq = GEOSGeom_getCoordSeq_r( geosinit.ctxt, currentGeom );
2501 unsigned int currentCoordSeqSize;
2502 GEOSCoordSeq_getSize_r( geosinit.ctxt, currentCoordSeq, ¤tCoordSeqSize );
2503 if ( currentCoordSeqSize < 2 )
2507 double xBegin, xEnd, yBegin, yEnd;
2508 GEOSCoordSeq_getX_r( geosinit.ctxt, currentCoordSeq, 0, &xBegin );
2509 GEOSCoordSeq_getY_r( geosinit.ctxt, currentCoordSeq, 0, &yBegin );
2510 GEOSCoordSeq_getX_r( geosinit.ctxt, currentCoordSeq, currentCoordSeqSize - 1, &xEnd );
2511 GEOSCoordSeq_getY_r( geosinit.ctxt, currentCoordSeq, currentCoordSeqSize - 1, &yEnd );
2512 geos::unique_ptr beginCurrentGeomVertex = createGeosPointXY( xBegin, yBegin,
false, 0,
false, 0, 2, precision );
2513 geos::unique_ptr endCurrentGeomVertex = createGeosPointXY( xEnd, yEnd,
false, 0,
false, 0, 2, precision );
2516 int nEndpointsOnOriginalLine = 0;
2517 if ( pointContainedInLine( beginCurrentGeomVertex.get(), line ) == 1 )
2518 nEndpointsOnOriginalLine += 1;
2520 if ( pointContainedInLine( endCurrentGeomVertex.get(), line ) == 1 )
2521 nEndpointsOnOriginalLine += 1;
2524 int nEndpointsSameAsOriginalLine = 0;
2525 if ( GEOSEquals_r( geosinit.ctxt, beginCurrentGeomVertex.get(), beginLineVertex.get() ) == 1
2526 || GEOSEquals_r( geosinit.ctxt, beginCurrentGeomVertex.get(), endLineVertex.get() ) == 1 )
2527 nEndpointsSameAsOriginalLine += 1;
2529 if ( GEOSEquals_r( geosinit.ctxt, endCurrentGeomVertex.get(), beginLineVertex.get() ) == 1
2530 || GEOSEquals_r( geosinit.ctxt, endCurrentGeomVertex.get(), endLineVertex.get() ) == 1 )
2531 nEndpointsSameAsOriginalLine += 1;
2534 bool currentGeomOverlapsOriginalGeom =
false;
2535 bool currentGeomOverlapsReshapeLine =
false;
2536 if ( lineContainedInLine( currentGeom, line ) == 1 )
2537 currentGeomOverlapsOriginalGeom =
true;
2539 if ( lineContainedInLine( currentGeom, reshapeLineGeos ) == 1 )
2540 currentGeomOverlapsReshapeLine =
true;
2543 if ( !isRing && nEndpointsSameAsOriginalLine == 1 && nEndpointsOnOriginalLine == 2 && currentGeomOverlapsOriginalGeom )
2545 resultLineParts.push_back( GEOSGeom_clone_r( geosinit.ctxt, currentGeom ) );
2548 else if ( isRing && nEndpointsOnOriginalLine == 2 && currentGeomOverlapsOriginalGeom )
2550 probableParts.push_back( GEOSGeom_clone_r( geosinit.ctxt, currentGeom ) );
2552 else if ( nEndpointsOnOriginalLine == 2 && !currentGeomOverlapsOriginalGeom )
2554 resultLineParts.push_back( GEOSGeom_clone_r( geosinit.ctxt, currentGeom ) );
2556 else if ( nEndpointsSameAsOriginalLine == 2 && !currentGeomOverlapsOriginalGeom )
2558 resultLineParts.push_back( GEOSGeom_clone_r( geosinit.ctxt, currentGeom ) );
2560 else if ( currentGeomOverlapsOriginalGeom && currentGeomOverlapsReshapeLine )
2562 resultLineParts.push_back( GEOSGeom_clone_r( geosinit.ctxt, currentGeom ) );
2567 if ( isRing && !probableParts.isEmpty() )
2570 GEOSGeometry *currentGeom =
nullptr;
2571 double maxLength = -std::numeric_limits<double>::max();
2572 double currentLength = 0;
2573 for (
int i = 0; i < probableParts.size(); ++i )
2575 currentGeom = probableParts.at( i );
2576 GEOSLength_r( geosinit.ctxt, currentGeom, ¤tLength );
2577 if ( currentLength > maxLength )
2579 maxLength = currentLength;
2580 maxGeom.reset( currentGeom );
2584 GEOSGeom_destroy_r( geosinit.ctxt, currentGeom );
2587 resultLineParts.push_back( maxGeom.release() );
2591 if ( resultLineParts.empty() )
2594 if ( resultLineParts.size() == 1 )
2596 result.reset( resultLineParts[0] );
2600 GEOSGeometry **lineArray =
new GEOSGeometry*[resultLineParts.size()];
2601 for (
int i = 0; i < resultLineParts.size(); ++i )
2603 lineArray[i] = resultLineParts[i];
2607 geos::unique_ptr multiLineGeom( GEOSGeom_createCollection_r( geosinit.ctxt, GEOS_MULTILINESTRING, lineArray, resultLineParts.size() ) );
2608 delete [] lineArray;
2611 result.reset( GEOSLineMerge_r( geosinit.ctxt, multiLineGeom.get() ) );
2615 if ( GEOSGeomTypeId_r( geosinit.ctxt, result.get() ) != GEOS_LINESTRING )
2623 geos::unique_ptr QgsGeos::reshapePolygon(
const GEOSGeometry *polygon,
const GEOSGeometry *reshapeLineGeos,
double precision )
2626 int nIntersections = 0;
2627 int lastIntersectingRing = -2;
2628 const GEOSGeometry *lastIntersectingGeom =
nullptr;
2630 int nRings = GEOSGetNumInteriorRings_r( geosinit.ctxt, polygon );
2635 const GEOSGeometry *outerRing = GEOSGetExteriorRing_r( geosinit.ctxt, polygon );
2636 if ( GEOSIntersects_r( geosinit.ctxt, outerRing, reshapeLineGeos ) == 1 )
2639 lastIntersectingRing = -1;
2640 lastIntersectingGeom = outerRing;
2644 const GEOSGeometry **innerRings =
new const GEOSGeometry*[nRings];
2648 for (
int i = 0; i < nRings; ++i )
2650 innerRings[i] = GEOSGetInteriorRingN_r( geosinit.ctxt, polygon, i );
2651 if ( GEOSIntersects_r( geosinit.ctxt, innerRings[i], reshapeLineGeos ) == 1 )
2654 lastIntersectingRing = i;
2655 lastIntersectingGeom = innerRings[i];
2659 catch ( GEOSException & )
2664 if ( nIntersections != 1 )
2666 delete [] innerRings;
2671 geos::unique_ptr reshapeResult = reshapeLine( lastIntersectingGeom, reshapeLineGeos, precision );
2672 if ( !reshapeResult )
2674 delete [] innerRings;
2679 GEOSGeometry *newRing =
nullptr;
2680 const GEOSCoordSequence *reshapeSequence = GEOSGeom_getCoordSeq_r( geosinit.ctxt, reshapeResult.get() );
2681 GEOSCoordSequence *newCoordSequence = GEOSCoordSeq_clone_r( geosinit.ctxt, reshapeSequence );
2683 reshapeResult.reset();
2685 newRing = GEOSGeom_createLinearRing_r( geosinit.ctxt, newCoordSequence );
2688 delete [] innerRings;
2692 GEOSGeometry *newOuterRing =
nullptr;
2693 if ( lastIntersectingRing == -1 )
2694 newOuterRing = newRing;
2696 newOuterRing = GEOSGeom_clone_r( geosinit.ctxt, outerRing );
2699 QVector<GEOSGeometry *> ringList;
2702 GEOSGeometry *outerRingPoly = GEOSGeom_createPolygon_r( geosinit.ctxt, GEOSGeom_clone_r( geosinit.ctxt, newOuterRing ),
nullptr, 0 );
2703 if ( outerRingPoly )
2705 GEOSGeometry *currentRing =
nullptr;
2706 for (
int i = 0; i < nRings; ++i )
2708 if ( lastIntersectingRing == i )
2709 currentRing = newRing;
2711 currentRing = GEOSGeom_clone_r( geosinit.ctxt, innerRings[i] );
2714 if ( GEOSContains_r( geosinit.ctxt, outerRingPoly, currentRing ) == 1 )
2715 ringList.push_back( currentRing );
2717 GEOSGeom_destroy_r( geosinit.ctxt, currentRing );
2720 GEOSGeom_destroy_r( geosinit.ctxt, outerRingPoly );
2723 GEOSGeometry **newInnerRings =
new GEOSGeometry*[ringList.size()];
2724 for (
int i = 0; i < ringList.size(); ++i )
2725 newInnerRings[i] = ringList.at( i );
2727 delete [] innerRings;
2729 geos::unique_ptr reshapedPolygon( GEOSGeom_createPolygon_r( geosinit.ctxt, newOuterRing, newInnerRings, ringList.size() ) );
2730 delete[] newInnerRings;
2732 return reshapedPolygon;
2735 int QgsGeos::lineContainedInLine(
const GEOSGeometry *line1,
const GEOSGeometry *line2 )
2737 if ( !line1 || !line2 )
2742 double bufferDistance = std::pow( 10.0L, geomDigits( line2 ) - 11 );
2748 geos::unique_ptr intersectionGeom( GEOSIntersection_r( geosinit.ctxt, bufferGeom.get(), line1 ) );
2751 double intersectGeomLength;
2754 GEOSLength_r( geosinit.ctxt, intersectionGeom.get(), &intersectGeomLength );
2755 GEOSLength_r( geosinit.ctxt, line1, &line1Length );
2757 double intersectRatio = line1Length / intersectGeomLength;
2758 if ( intersectRatio > 0.9 && intersectRatio < 1.1 )
2764 int QgsGeos::pointContainedInLine(
const GEOSGeometry *point,
const GEOSGeometry *line )
2766 if ( !point || !line )
2769 double bufferDistance = std::pow( 10.0L, geomDigits( line ) - 11 );
2771 geos::unique_ptr lineBuffer( GEOSBuffer_r( geosinit.ctxt, line, bufferDistance, 8 ) );
2775 bool contained =
false;
2776 if ( GEOSContains_r( geosinit.ctxt, lineBuffer.get(), point ) == 1 )
2782 int QgsGeos::geomDigits(
const GEOSGeometry *geom )
2788 const GEOSGeometry *bBoxRing = GEOSGetExteriorRing_r( geosinit.ctxt, bbox.get() );
2792 const GEOSCoordSequence *bBoxCoordSeq = GEOSGeom_getCoordSeq_r( geosinit.ctxt, bBoxRing );
2794 if ( !bBoxCoordSeq )
2797 unsigned int nCoords = 0;
2798 if ( !GEOSCoordSeq_getSize_r( geosinit.ctxt, bBoxCoordSeq, &nCoords ) )
2802 for (
unsigned int i = 0; i < nCoords - 1; ++i )
2805 GEOSCoordSeq_getX_r( geosinit.ctxt, bBoxCoordSeq, i, &t );
2808 digits = std::ceil( std::log10( std::fabs( t ) ) );
2809 if ( digits > maxDigits )
2812 GEOSCoordSeq_getY_r( geosinit.ctxt, bBoxCoordSeq, i, &t );
2813 digits = std::ceil( std::log10( std::fabs( t ) ) );
2814 if ( digits > maxDigits )
2823 return geosinit.ctxt;
const QgsCurve * exteriorRing() const
Returns the curve polygon's exterior ring.
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.
bool isEmpty() const
Returns true if the rectangle is empty.
bool isNull() const
Returns true if the geometry is null (ie, contains no underlying geometry accessible via geometry() )...
QgsGeos(const QgsAbstractGeometry *geometry, double precision=0)
GEOS geometry engine constructor.
void setXMaximum(double x)
Set the maximum x value.
Multi point geometry collection.
double hausdorffDistanceDensify(const QgsAbstractGeometry *geom, double densifyFraction, QString *errorMsg=nullptr) const
Returns the Hausdorff distance between this geometry and geom.
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
const double * zData() const
Returns a const pointer to the z vertex data, or a nullptr if the linestring does not have z values...
double yMaximum() const
Returns the y maximum value (top side of rectangle).
QgsPoint * pointOnSurface(QString *errorMsg=nullptr) const override
Calculate a point that is guaranteed to be on the surface of this.
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
QgsWkbTypes::Type wkbType() const
Returns the WKB type of the geometry.
QgsAbstractGeometry * buffer(double distance, int segments, QString *errorMsg=nullptr) const override
bool isNull() const
Test if the rectangle is null (all coordinates zero or after call to setMinimal()).
bool isValid(QString *errorMsg=nullptr, bool allowSelfTouchingHoles=false, QgsGeometry *errorLoc=nullptr) const override
Returns true if the geometry is valid.
QgsGeometry closestPoint(const QgsGeometry &other, QString *errorMsg=nullptr) const
Returns the closest point on the geometry to the other geometry.
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.
const QgsAbstractGeometry * geometryN(int n) const
Returns a const reference to a geometry from within the collection.
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.
double mAt(int index) const
Returns the m value of the specified node in the line string.
static GEOSContextHandle_t getGEOSHandler()
int numInteriorRings() const
Returns the number of interior rings contained with the curve polygon.
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.
#define CATCH_GEOS_WITH_ERRMSG(r)
const QgsAbstractGeometry * constGet() const
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
Nothing happened, without any error.
Type
The WKB type describes the number of dimensions a geometry has.
QgsAbstractGeometry * envelope(QString *errorMsg=nullptr) const override
bool isMeasure() const
Returns true if the geometry contains m values.
static std::unique_ptr< QgsAbstractGeometry > fromGeos(const GEOSGeometry *geos)
Create a geometry from a GEOSGeometry.
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
void addVertex(const QgsPoint &pt)
Adds a new vertex to the end of the line string.
double hausdorffDistance(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const
Returns the Hausdorff distance between this geometry and geom.
bool touches(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Checks if geom touches this.
double xMaximum() const
Returns the x maximum value (right side of rectangle).
void prepareGeometry() override
Prepares the geometry, so that subsequent calls to spatial relation methods are much faster...
void setYMinimum(double y)
Set the minimum y value.
QgsPoint pointN(int i) const
Returns the specified point from inside the line string.
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...
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.
QgsPoint * clone() const override
Clones the geometry by performing a deep copy.
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.
Abstract base class for curved geometry type.
int numGeometries() const
Returns the number of geometries within the collection.
QgsGeometry delaunayTriangulation(double tolerance=0.0, bool edgesOnly=false, QString *errorMsg=nullptr) const
Returns the Delaunay triangulation for the vertices of the geometry.
Abstract base class for all geometries.
virtual int dimension() const =0
Returns the inherent dimension of the geometry.
const double * xData() const
Returns a const pointer to the x vertex data.
std::unique_ptr< GEOSBufferParams, GeosDeleter > buffer_params_unique_ptr
Scoped GEOS buffer params pointer.
Point geometry type, with support for z-dimension and m-values.
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.
QgsAbstractGeometry * symDifference(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Calculate the symmetric difference of this and geom.
Contains geos related utilities and functions.
QgsAbstractGeometry * get()
Returns a modifiable (non-const) reference to the underlying abstract geometry primitive.
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 * combine(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Calculate the combination of this and geom.
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)
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...
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.
Line string geometry type, with support for z-dimension and m-values.
const QgsCurve * interiorRing(int i) const
Retrieves an interior ring from the curve polygon.
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...
QgsGeometry shortestLine(const QgsGeometry &other, QString *errorMsg=nullptr) const
Returns the shortest line joining this geometry to the other geometry.
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.
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 is3D() const
Returns true if the geometry is 3D and contains a z-value.
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 xAt(int index) const override
Returns the x-coordinate of the specified node in the line string.
QgsGeometry mergeLines(QString *errorMsg=nullptr) const
Merges any connected lines in a LineString/MultiLineString geometry and converts them to single line ...
QgsAbstractGeometry * difference(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Calculate the difference of this and geom.
const double * mData() const
Returns a const pointer to the m vertex data, or a nullptr if the linestring does not have m values...
bool overlaps(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Checks if geom overlaps this.
static QgsGeometry polygonize(const QVector< const QgsAbstractGeometry * > &geometries, QString *errorMsg=nullptr)
Creates a GeometryCollection geometry containing possible polygons formed from the constituent linewo...
Contains geometry relation and modification algorithms.
static std::unique_ptr< QgsPolygon > fromGeosPolygon(const GEOSGeometry *geos)
std::unique_ptr< QgsAbstractGeometry > subdivide(int maxNodes, QString *errorMsg=nullptr) const
Subdivides the geometry.
std::unique_ptr< GEOSCoordSequence, GeosDeleter > coord_sequence_unique_ptr
Scoped GEOS coordinate sequence pointer.
EngineOperationResult
Success or failure of a geometry operation.
std::unique_ptr< QgsAbstractGeometry > reshapeGeometry(const QgsLineString &reshapeWithLine, EngineOperationResult *errorCode, QString *errorMsg=nullptr) const
Reshapes the geometry using a line.
static QgsGeometry geometryFromGeos(GEOSGeometry *geos)
Creates a new QgsGeometry object, feeding in a geometry in GEOS format.
double width() const
Returns the width of the rectangle.
static Type flatType(Type type)
Returns the flat type for a WKB type.
double xMinimum() const
Returns the x minimum value (left side of rectangle).
The geometry on which the operation occurs is not valid.
#define DEFAULT_QUADRANT_SEGMENTS
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.
const double * yData() const
Returns a const pointer to the y vertex data.