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;
1675 if ( invalid && errorMsg )
1679 if ( translatedErrors.empty() )
1682 translatedErrors.insert( QStringLiteral(
"topology validation error" ), QObject::tr(
"Topology validation error",
"GEOS Error" ) );
1683 translatedErrors.insert( QStringLiteral(
"repeated point" ), QObject::tr(
"Repeated point",
"GEOS Error" ) );
1684 translatedErrors.insert( QStringLiteral(
"hole lies outside shell" ), QObject::tr(
"Hole lies outside shell",
"GEOS Error" ) );
1685 translatedErrors.insert( QStringLiteral(
"holes are nested" ), QObject::tr(
"Holes are nested",
"GEOS Error" ) );
1686 translatedErrors.insert( QStringLiteral(
"interior is disconnected" ), QObject::tr(
"Interior is disconnected",
"GEOS Error" ) );
1687 translatedErrors.insert( QStringLiteral(
"self-intersection" ), QObject::tr(
"Self-intersection",
"GEOS Error" ) );
1688 translatedErrors.insert( QStringLiteral(
"ring self-intersection" ), QObject::tr(
"Ring self-intersection",
"GEOS Error" ) );
1689 translatedErrors.insert( QStringLiteral(
"nested shells" ), QObject::tr(
"Nested shells",
"GEOS Error" ) );
1690 translatedErrors.insert( QStringLiteral(
"duplicate rings" ), QObject::tr(
"Duplicate rings",
"GEOS Error" ) );
1691 translatedErrors.insert( QStringLiteral(
"too few points in geometry component" ), QObject::tr(
"Too few points in geometry component",
"GEOS Error" ) );
1692 translatedErrors.insert( QStringLiteral(
"invalid coordinate" ), QObject::tr(
"Invalid coordinate",
"GEOS Error" ) );
1693 translatedErrors.insert( QStringLiteral(
"ring is not closed" ), QObject::tr(
"Ring is not closed",
"GEOS Error" ) );
1696 const QString error( r );
1697 *errorMsg = translatedErrors.value( error.toLower(), error );
1699 if ( g1 && errorLoc )
1705 GEOSGeom_destroy_r( geosinit.ctxt, g1 );
1715 if ( !mGeos || !geom )
1727 bool equal = GEOSEquals_r( geosinit.ctxt, mGeos.get(), geosGeom.get() );
1742 return GEOSisEmpty_r( geosinit.ctxt, mGeos.get() );
1756 return GEOSisSimple_r( geosinit.ctxt, mGeos.get() );
1761 GEOSCoordSequence *QgsGeos::createCoordinateSequence(
const QgsCurve *curve,
double precision,
bool forceClose )
1763 std::unique_ptr< QgsLineString > segmentized;
1769 line = segmentized.get();
1777 bool hasZ = line->
is3D();
1791 int numOutPoints = numPoints;
1792 if ( forceClose && ( line->
pointN( 0 ) != line->
pointN( numPoints - 1 ) ) )
1797 GEOSCoordSequence *coordSeq =
nullptr;
1800 coordSeq = GEOSCoordSeq_create_r( geosinit.ctxt, numOutPoints, coordDims );
1803 QgsDebugMsg( QStringLiteral(
"GEOS Exception: Could not create coordinate sequence for %1 points in %2 dimensions" ).arg( numPoints ).arg( coordDims ) );
1807 const double *xData = line->
xData();
1808 const double *yData = line->
yData();
1809 const double *zData = hasZ ? line->
zData() :
nullptr;
1810 const double *mData = hasM ? line->
mData() :
nullptr;
1814 for (
int i = 0; i < numOutPoints; ++i )
1816 if ( i >= numPoints )
1819 xData = line->
xData();
1820 yData = line->
yData();
1821 zData = hasZ ? line->
zData() :
nullptr;
1822 mData = hasM ? line->
mData() :
nullptr;
1824 GEOSCoordSeq_setX_r( geosinit.ctxt, coordSeq, i, std::round( *xData++ /
precision ) *
precision );
1825 GEOSCoordSeq_setY_r( geosinit.ctxt, coordSeq, i, std::round( *yData++ / precision ) * precision );
1828 GEOSCoordSeq_setOrdinate_r( geosinit.ctxt, coordSeq, i, 2, std::round( *zData++ / precision ) * precision );
1832 GEOSCoordSeq_setOrdinate_r( geosinit.ctxt, coordSeq, i, 3, line->
mAt( *mData++ ) );
1838 for (
int i = 0; i < numOutPoints; ++i )
1840 if ( i >= numPoints )
1843 xData = line->
xData();
1844 yData = line->
yData();
1845 zData = hasZ ? line->
zData() :
nullptr;
1846 mData = hasM ? line->
mData() :
nullptr;
1848 GEOSCoordSeq_setX_r( geosinit.ctxt, coordSeq, i, *xData++ );
1849 GEOSCoordSeq_setY_r( geosinit.ctxt, coordSeq, i, *yData++ );
1852 GEOSCoordSeq_setOrdinate_r( geosinit.ctxt, coordSeq, i, 2, *zData++ );
1856 GEOSCoordSeq_setOrdinate_r( geosinit.ctxt, coordSeq, i, 3, *mData++ );
1875 geos::unique_ptr QgsGeos::createGeosPointXY(
double x,
double y,
bool hasZ,
double z,
bool hasM,
double m,
int coordDims,
double precision )
1884 GEOSCoordSequence *coordSeq = GEOSCoordSeq_create_r( geosinit.ctxt, 1, coordDims );
1887 QgsDebugMsg( QStringLiteral(
"GEOS Exception: Could not create coordinate sequence for point with %1 dimensions" ).arg( coordDims ) );
1890 if ( precision > 0. )
1892 GEOSCoordSeq_setX_r( geosinit.ctxt, coordSeq, 0, std::round( x / precision ) * precision );
1893 GEOSCoordSeq_setY_r( geosinit.ctxt, coordSeq, 0, std::round( y / precision ) * precision );
1896 GEOSCoordSeq_setOrdinate_r( geosinit.ctxt, coordSeq, 0, 2, std::round( z / precision ) * precision );
1901 GEOSCoordSeq_setX_r( geosinit.ctxt, coordSeq, 0, x );
1902 GEOSCoordSeq_setY_r( geosinit.ctxt, coordSeq, 0, y );
1905 GEOSCoordSeq_setOrdinate_r( geosinit.ctxt, coordSeq, 0, 2, z );
1908 #if 0 //disabled until geos supports m-coordinates 1911 GEOSCoordSeq_setOrdinate_r( geosinit.ctxt, coordSeq, 0, 3, m );
1914 geosPoint.reset( GEOSGeom_createPoint_r( geosinit.ctxt, coordSeq ) );
1926 GEOSCoordSequence *coordSeq = createCoordinateSequence( c, precision );
1933 geosGeom.reset( GEOSGeom_createLineString_r( geosinit.ctxt, coordSeq ) );
1946 if ( !exteriorRing )
1954 geos::unique_ptr exteriorRingGeos( GEOSGeom_createLinearRing_r( geosinit.ctxt, createCoordinateSequence( exteriorRing, precision,
true ) ) );
1957 GEOSGeometry **holes =
nullptr;
1960 holes =
new GEOSGeometry*[ nHoles ];
1963 for (
int i = 0; i < nHoles; ++i )
1966 holes[i] = GEOSGeom_createLinearRing_r( geosinit.ctxt, createCoordinateSequence( interiorRing, precision,
true ) );
1968 geosPolygon.reset( GEOSGeom_createPolygon_r( geosinit.ctxt, exteriorRingGeos.release(), holes, nHoles ) );
1984 offset.reset( GEOSOffsetCurve_r( geosinit.ctxt, mGeos.get(),
distance, segments, joinStyle, miterLimit ) );
1987 std::unique_ptr< QgsAbstractGeometry > offsetGeom =
fromGeos( offset.get() );
1988 return offsetGeom.release();
2002 GEOSBufferParams_setSingleSided_r( geosinit.ctxt, bp.get(), 1 );
2003 GEOSBufferParams_setQuadrantSegments_r( geosinit.ctxt, bp.get(), segments );
2004 GEOSBufferParams_setJoinStyle_r( geosinit.ctxt, bp.get(), joinStyle );
2005 GEOSBufferParams_setMitreLimit_r( geosinit.ctxt, bp.get(), miterLimit );
2011 geos.reset( GEOSBufferWithParams_r( geosinit.ctxt, mGeos.get(), bp.get(),
distance ) );
2031 geos::unique_ptr reshapeLineGeos = createGeosLinestring( &reshapeWithLine, mPrecision );
2034 int numGeoms = GEOSGetNumGeometries_r( geosinit.ctxt, mGeos.get() );
2035 if ( numGeoms == -1 )
2044 bool isMultiGeom =
false;
2045 int geosTypeId = GEOSGeomTypeId_r( geosinit.ctxt, mGeos.get() );
2046 if ( geosTypeId == GEOS_MULTILINESTRING || geosTypeId == GEOS_MULTIPOLYGON )
2056 reshapedGeometry = reshapeLine( mGeos.get(), reshapeLineGeos.get(), mPrecision );
2060 reshapedGeometry = reshapePolygon( mGeos.get(), reshapeLineGeos.get(), mPrecision );
2065 std::unique_ptr< QgsAbstractGeometry > reshapeResult =
fromGeos( reshapedGeometry.get() );
2066 return reshapeResult;
2073 bool reshapeTookPlace =
false;
2076 GEOSGeometry **newGeoms =
new GEOSGeometry*[numGeoms];
2078 for (
int i = 0; i < numGeoms; ++i )
2081 currentReshapeGeometry = reshapeLine( GEOSGetGeometryN_r( geosinit.ctxt, mGeos.get(), i ), reshapeLineGeos.get(), mPrecision );
2083 currentReshapeGeometry = reshapePolygon( GEOSGetGeometryN_r( geosinit.ctxt, mGeos.get(), i ), reshapeLineGeos.get(), mPrecision );
2085 if ( currentReshapeGeometry )
2087 newGeoms[i] = currentReshapeGeometry.release();
2088 reshapeTookPlace =
true;
2092 newGeoms[i] = GEOSGeom_clone_r( geosinit.ctxt, GEOSGetGeometryN_r( geosinit.ctxt, mGeos.get(), i ) );
2099 newMultiGeom.reset( GEOSGeom_createCollection_r( geosinit.ctxt, GEOS_MULTILINESTRING, newGeoms, numGeoms ) );
2103 newMultiGeom.reset( GEOSGeom_createCollection_r( geosinit.ctxt, GEOS_MULTIPOLYGON, newGeoms, numGeoms ) );
2107 if ( !newMultiGeom )
2113 if ( reshapeTookPlace )
2117 std::unique_ptr< QgsAbstractGeometry > reshapedMultiGeom =
fromGeos( newMultiGeom.get() );
2118 return reshapedMultiGeom;
2140 if ( GEOSGeomTypeId_r( geosinit.ctxt, mGeos.get() ) != GEOS_MULTILINESTRING )
2146 geos.reset( GEOSLineMerge_r( geosinit.ctxt, mGeos.get() ) );
2154 if ( !mGeos || other.
isNull() )
2171 ( void )GEOSCoordSeq_getX_r( geosinit.ctxt, nearestCoord.get(), 0, &nx );
2172 ( void )GEOSCoordSeq_getY_r( geosinit.ctxt, nearestCoord.get(), 0, &ny );
2174 catch ( GEOSException &e )
2178 *errorMsg = e.what();
2188 if ( !mGeos || other.
isNull() )
2207 ( void )GEOSCoordSeq_getX_r( geosinit.ctxt, nearestCoord.get(), 0, &nx1 );
2208 ( void )GEOSCoordSeq_getY_r( geosinit.ctxt, nearestCoord.get(), 0, &ny1 );
2209 ( void )GEOSCoordSeq_getX_r( geosinit.ctxt, nearestCoord.get(), 1, &nx2 );
2210 ( void )GEOSCoordSeq_getY_r( geosinit.ctxt, nearestCoord.get(), 1, &ny2 );
2212 catch ( GEOSException &e )
2216 *errorMsg = e.what();
2243 distance = GEOSProject_r( geosinit.ctxt, mGeos.get(), otherGeom.get() );
2245 catch ( GEOSException &e )
2249 *errorMsg = e.what();
2259 GEOSGeometry **
const lineGeosGeometries =
new GEOSGeometry*[ geometries.size()];
2266 lineGeosGeometries[validLines] = l.release();
2273 geos::unique_ptr result( GEOSPolygonize_r( geosinit.ctxt, lineGeosGeometries, validLines ) );
2274 for (
int i = 0; i < validLines; ++i )
2276 GEOSGeom_destroy_r( geosinit.ctxt, lineGeosGeometries[i] );
2278 delete[] lineGeosGeometries;
2281 catch ( GEOSException &e )
2285 *errorMsg = e.what();
2287 for (
int i = 0; i < validLines; ++i )
2289 GEOSGeom_destroy_r( geosinit.ctxt, lineGeosGeometries[i] );
2291 delete[] lineGeosGeometries;
2306 extentGeosGeom =
asGeos( extent, mPrecision );
2307 if ( !extentGeosGeom )
2316 geos.reset( GEOSVoronoiDiagram_r( geosinit.ctxt, mGeos.get(), extentGeosGeom.get(), tolerance, edgesOnly ) );
2318 if ( !geos || GEOSisEmpty_r( geosinit.ctxt, geos.get() ) != 0 )
2338 geos.reset( GEOSDelaunayTriangulation_r( geosinit.ctxt, mGeos.get(), tolerance, edgesOnly ) );
2340 if ( !geos || GEOSisEmpty_r( geosinit.ctxt, geos.get() ) != 0 )
2352 static bool _linestringEndpoints(
const GEOSGeometry *linestring,
double &x1,
double &y1,
double &x2,
double &y2 )
2354 const GEOSCoordSequence *coordSeq = GEOSGeom_getCoordSeq_r( geosinit.ctxt, linestring );
2358 unsigned int coordSeqSize;
2359 if ( GEOSCoordSeq_getSize_r( geosinit.ctxt, coordSeq, &coordSeqSize ) == 0 )
2362 if ( coordSeqSize < 2 )
2365 GEOSCoordSeq_getX_r( geosinit.ctxt, coordSeq, 0, &x1 );
2366 GEOSCoordSeq_getY_r( geosinit.ctxt, coordSeq, 0, &y1 );
2367 GEOSCoordSeq_getX_r( geosinit.ctxt, coordSeq, coordSeqSize - 1, &x2 );
2368 GEOSCoordSeq_getY_r( geosinit.ctxt, coordSeq, coordSeqSize - 1, &y2 );
2374 static geos::unique_ptr _mergeLinestrings(
const GEOSGeometry *line1,
const GEOSGeometry *line2,
const QgsPointXY &intersectionPoint )
2376 double x1, y1, x2, y2;
2377 if ( !_linestringEndpoints( line1, x1, y1, x2, y2 ) )
2380 double rx1, ry1, rx2, ry2;
2381 if ( !_linestringEndpoints( line2, rx1, ry1, rx2, ry2 ) )
2384 bool intersectionAtOrigLineEndpoint =
2385 ( intersectionPoint.
x() == x1 && intersectionPoint.
y() == y1 ) !=
2386 ( intersectionPoint.
x() == x2 && intersectionPoint.
y() == y2 );
2387 bool intersectionAtReshapeLineEndpoint =
2388 ( intersectionPoint.
x() == rx1 && intersectionPoint.
y() == ry1 ) ||
2389 ( intersectionPoint.
x() == rx2 && intersectionPoint.
y() == ry2 );
2392 if ( intersectionAtOrigLineEndpoint && intersectionAtReshapeLineEndpoint )
2396 GEOSGeometry *geoms[2] = { g1.release(), g2.release() };
2397 geos::unique_ptr multiGeom( GEOSGeom_createCollection_r( geosinit.ctxt, GEOS_MULTILINESTRING, geoms, 2 ) );
2406 geos::unique_ptr QgsGeos::reshapeLine(
const GEOSGeometry *line,
const GEOSGeometry *reshapeLineGeos,
double precision )
2408 if ( !line || !reshapeLineGeos )
2411 bool atLeastTwoIntersections =
false;
2412 bool oneIntersection =
false;
2418 geos::unique_ptr intersectGeom( GEOSIntersection_r( geosinit.ctxt, line, reshapeLineGeos ) );
2419 if ( intersectGeom )
2421 atLeastTwoIntersections = ( GEOSGeomTypeId_r( geosinit.ctxt, intersectGeom.get() ) == GEOS_MULTIPOINT
2422 && GEOSGetNumGeometries_r( geosinit.ctxt, intersectGeom.get() ) > 1 );
2424 if ( GEOSGeomTypeId_r( geosinit.ctxt, intersectGeom.get() ) == GEOS_POINT )
2426 const GEOSCoordSequence *intersectionCoordSeq = GEOSGeom_getCoordSeq_r( geosinit.ctxt, intersectGeom.get() );
2428 GEOSCoordSeq_getX_r( geosinit.ctxt, intersectionCoordSeq, 0, &xi );
2429 GEOSCoordSeq_getY_r( geosinit.ctxt, intersectionCoordSeq, 0, &yi );
2430 oneIntersection =
true;
2435 catch ( GEOSException & )
2437 atLeastTwoIntersections =
false;
2441 if ( oneIntersection )
2442 return _mergeLinestrings( line, reshapeLineGeos, oneIntersectionPoint );
2444 if ( !atLeastTwoIntersections )
2448 double x1, y1, x2, y2;
2449 if ( !_linestringEndpoints( line, x1, y1, x2, y2 ) )
2452 geos::unique_ptr beginLineVertex = createGeosPointXY( x1, y1,
false, 0,
false, 0, 2, precision );
2453 geos::unique_ptr endLineVertex = createGeosPointXY( x2, y2,
false, 0,
false, 0, 2, precision );
2455 bool isRing =
false;
2456 if ( GEOSGeomTypeId_r( geosinit.ctxt, line ) == GEOS_LINEARRING
2457 || GEOSEquals_r( geosinit.ctxt, beginLineVertex.get(), endLineVertex.get() ) == 1 )
2462 if ( !nodedGeometry )
2468 geos::unique_ptr mergedLines( GEOSLineMerge_r( geosinit.ctxt, nodedGeometry.get() ) );
2474 int numMergedLines = GEOSGetNumGeometries_r( geosinit.ctxt, mergedLines.get() );
2475 if ( numMergedLines < 2 )
2477 if ( numMergedLines == 1 )
2479 geos::unique_ptr result( GEOSGeom_clone_r( geosinit.ctxt, reshapeLineGeos ) );
2486 QVector<GEOSGeometry *> resultLineParts;
2487 QVector<GEOSGeometry *> probableParts;
2489 for (
int i = 0; i < numMergedLines; ++i )
2491 const GEOSGeometry *currentGeom =
nullptr;
2493 currentGeom = GEOSGetGeometryN_r( geosinit.ctxt, mergedLines.get(), i );
2494 const GEOSCoordSequence *currentCoordSeq = GEOSGeom_getCoordSeq_r( geosinit.ctxt, currentGeom );
2495 unsigned int currentCoordSeqSize;
2496 GEOSCoordSeq_getSize_r( geosinit.ctxt, currentCoordSeq, ¤tCoordSeqSize );
2497 if ( currentCoordSeqSize < 2 )
2501 double xBegin, xEnd, yBegin, yEnd;
2502 GEOSCoordSeq_getX_r( geosinit.ctxt, currentCoordSeq, 0, &xBegin );
2503 GEOSCoordSeq_getY_r( geosinit.ctxt, currentCoordSeq, 0, &yBegin );
2504 GEOSCoordSeq_getX_r( geosinit.ctxt, currentCoordSeq, currentCoordSeqSize - 1, &xEnd );
2505 GEOSCoordSeq_getY_r( geosinit.ctxt, currentCoordSeq, currentCoordSeqSize - 1, &yEnd );
2506 geos::unique_ptr beginCurrentGeomVertex = createGeosPointXY( xBegin, yBegin,
false, 0,
false, 0, 2, precision );
2507 geos::unique_ptr endCurrentGeomVertex = createGeosPointXY( xEnd, yEnd,
false, 0,
false, 0, 2, precision );
2510 int nEndpointsOnOriginalLine = 0;
2511 if ( pointContainedInLine( beginCurrentGeomVertex.get(), line ) == 1 )
2512 nEndpointsOnOriginalLine += 1;
2514 if ( pointContainedInLine( endCurrentGeomVertex.get(), line ) == 1 )
2515 nEndpointsOnOriginalLine += 1;
2518 int nEndpointsSameAsOriginalLine = 0;
2519 if ( GEOSEquals_r( geosinit.ctxt, beginCurrentGeomVertex.get(), beginLineVertex.get() ) == 1
2520 || GEOSEquals_r( geosinit.ctxt, beginCurrentGeomVertex.get(), endLineVertex.get() ) == 1 )
2521 nEndpointsSameAsOriginalLine += 1;
2523 if ( GEOSEquals_r( geosinit.ctxt, endCurrentGeomVertex.get(), beginLineVertex.get() ) == 1
2524 || GEOSEquals_r( geosinit.ctxt, endCurrentGeomVertex.get(), endLineVertex.get() ) == 1 )
2525 nEndpointsSameAsOriginalLine += 1;
2528 bool currentGeomOverlapsOriginalGeom =
false;
2529 bool currentGeomOverlapsReshapeLine =
false;
2530 if ( lineContainedInLine( currentGeom, line ) == 1 )
2531 currentGeomOverlapsOriginalGeom =
true;
2533 if ( lineContainedInLine( currentGeom, reshapeLineGeos ) == 1 )
2534 currentGeomOverlapsReshapeLine =
true;
2537 if ( !isRing && nEndpointsSameAsOriginalLine == 1 && nEndpointsOnOriginalLine == 2 && currentGeomOverlapsOriginalGeom )
2539 resultLineParts.push_back( GEOSGeom_clone_r( geosinit.ctxt, currentGeom ) );
2542 else if ( isRing && nEndpointsOnOriginalLine == 2 && currentGeomOverlapsOriginalGeom )
2544 probableParts.push_back( GEOSGeom_clone_r( geosinit.ctxt, currentGeom ) );
2546 else if ( nEndpointsOnOriginalLine == 2 && !currentGeomOverlapsOriginalGeom )
2548 resultLineParts.push_back( GEOSGeom_clone_r( geosinit.ctxt, currentGeom ) );
2550 else if ( nEndpointsSameAsOriginalLine == 2 && !currentGeomOverlapsOriginalGeom )
2552 resultLineParts.push_back( GEOSGeom_clone_r( geosinit.ctxt, currentGeom ) );
2554 else if ( currentGeomOverlapsOriginalGeom && currentGeomOverlapsReshapeLine )
2556 resultLineParts.push_back( GEOSGeom_clone_r( geosinit.ctxt, currentGeom ) );
2561 if ( isRing && !probableParts.isEmpty() )
2564 GEOSGeometry *currentGeom =
nullptr;
2565 double maxLength = -std::numeric_limits<double>::max();
2566 double currentLength = 0;
2567 for (
int i = 0; i < probableParts.size(); ++i )
2569 currentGeom = probableParts.at( i );
2570 GEOSLength_r( geosinit.ctxt, currentGeom, ¤tLength );
2571 if ( currentLength > maxLength )
2573 maxLength = currentLength;
2574 maxGeom.reset( currentGeom );
2578 GEOSGeom_destroy_r( geosinit.ctxt, currentGeom );
2581 resultLineParts.push_back( maxGeom.release() );
2585 if ( resultLineParts.empty() )
2588 if ( resultLineParts.size() == 1 )
2590 result.reset( resultLineParts[0] );
2594 GEOSGeometry **lineArray =
new GEOSGeometry*[resultLineParts.size()];
2595 for (
int i = 0; i < resultLineParts.size(); ++i )
2597 lineArray[i] = resultLineParts[i];
2601 geos::unique_ptr multiLineGeom( GEOSGeom_createCollection_r( geosinit.ctxt, GEOS_MULTILINESTRING, lineArray, resultLineParts.size() ) );
2602 delete [] lineArray;
2605 result.reset( GEOSLineMerge_r( geosinit.ctxt, multiLineGeom.get() ) );
2609 if ( GEOSGeomTypeId_r( geosinit.ctxt, result.get() ) != GEOS_LINESTRING )
2617 geos::unique_ptr QgsGeos::reshapePolygon(
const GEOSGeometry *polygon,
const GEOSGeometry *reshapeLineGeos,
double precision )
2620 int nIntersections = 0;
2621 int lastIntersectingRing = -2;
2622 const GEOSGeometry *lastIntersectingGeom =
nullptr;
2624 int nRings = GEOSGetNumInteriorRings_r( geosinit.ctxt, polygon );
2629 const GEOSGeometry *outerRing = GEOSGetExteriorRing_r( geosinit.ctxt, polygon );
2630 if ( GEOSIntersects_r( geosinit.ctxt, outerRing, reshapeLineGeos ) == 1 )
2633 lastIntersectingRing = -1;
2634 lastIntersectingGeom = outerRing;
2638 const GEOSGeometry **innerRings =
new const GEOSGeometry*[nRings];
2642 for (
int i = 0; i < nRings; ++i )
2644 innerRings[i] = GEOSGetInteriorRingN_r( geosinit.ctxt, polygon, i );
2645 if ( GEOSIntersects_r( geosinit.ctxt, innerRings[i], reshapeLineGeos ) == 1 )
2648 lastIntersectingRing = i;
2649 lastIntersectingGeom = innerRings[i];
2653 catch ( GEOSException & )
2658 if ( nIntersections != 1 )
2660 delete [] innerRings;
2665 geos::unique_ptr reshapeResult = reshapeLine( lastIntersectingGeom, reshapeLineGeos, precision );
2666 if ( !reshapeResult )
2668 delete [] innerRings;
2673 GEOSGeometry *newRing =
nullptr;
2674 const GEOSCoordSequence *reshapeSequence = GEOSGeom_getCoordSeq_r( geosinit.ctxt, reshapeResult.get() );
2675 GEOSCoordSequence *newCoordSequence = GEOSCoordSeq_clone_r( geosinit.ctxt, reshapeSequence );
2677 reshapeResult.reset();
2679 newRing = GEOSGeom_createLinearRing_r( geosinit.ctxt, newCoordSequence );
2682 delete [] innerRings;
2686 GEOSGeometry *newOuterRing =
nullptr;
2687 if ( lastIntersectingRing == -1 )
2688 newOuterRing = newRing;
2690 newOuterRing = GEOSGeom_clone_r( geosinit.ctxt, outerRing );
2693 QVector<GEOSGeometry *> ringList;
2696 GEOSGeometry *outerRingPoly = GEOSGeom_createPolygon_r( geosinit.ctxt, GEOSGeom_clone_r( geosinit.ctxt, newOuterRing ),
nullptr, 0 );
2697 if ( outerRingPoly )
2699 GEOSGeometry *currentRing =
nullptr;
2700 for (
int i = 0; i < nRings; ++i )
2702 if ( lastIntersectingRing == i )
2703 currentRing = newRing;
2705 currentRing = GEOSGeom_clone_r( geosinit.ctxt, innerRings[i] );
2708 if ( GEOSContains_r( geosinit.ctxt, outerRingPoly, currentRing ) == 1 )
2709 ringList.push_back( currentRing );
2711 GEOSGeom_destroy_r( geosinit.ctxt, currentRing );
2714 GEOSGeom_destroy_r( geosinit.ctxt, outerRingPoly );
2717 GEOSGeometry **newInnerRings =
new GEOSGeometry*[ringList.size()];
2718 for (
int i = 0; i < ringList.size(); ++i )
2719 newInnerRings[i] = ringList.at( i );
2721 delete [] innerRings;
2723 geos::unique_ptr reshapedPolygon( GEOSGeom_createPolygon_r( geosinit.ctxt, newOuterRing, newInnerRings, ringList.size() ) );
2724 delete[] newInnerRings;
2726 return reshapedPolygon;
2729 int QgsGeos::lineContainedInLine(
const GEOSGeometry *line1,
const GEOSGeometry *line2 )
2731 if ( !line1 || !line2 )
2736 double bufferDistance = std::pow( 10.0L, geomDigits( line2 ) - 11 );
2742 geos::unique_ptr intersectionGeom( GEOSIntersection_r( geosinit.ctxt, bufferGeom.get(), line1 ) );
2745 double intersectGeomLength;
2748 GEOSLength_r( geosinit.ctxt, intersectionGeom.get(), &intersectGeomLength );
2749 GEOSLength_r( geosinit.ctxt, line1, &line1Length );
2751 double intersectRatio = line1Length / intersectGeomLength;
2752 if ( intersectRatio > 0.9 && intersectRatio < 1.1 )
2758 int QgsGeos::pointContainedInLine(
const GEOSGeometry *point,
const GEOSGeometry *line )
2760 if ( !point || !line )
2763 double bufferDistance = std::pow( 10.0L, geomDigits( line ) - 11 );
2765 geos::unique_ptr lineBuffer( GEOSBuffer_r( geosinit.ctxt, line, bufferDistance, 8 ) );
2769 bool contained =
false;
2770 if ( GEOSContains_r( geosinit.ctxt, lineBuffer.get(), point ) == 1 )
2776 int QgsGeos::geomDigits(
const GEOSGeometry *geom )
2782 const GEOSGeometry *bBoxRing = GEOSGetExteriorRing_r( geosinit.ctxt, bbox.get() );
2786 const GEOSCoordSequence *bBoxCoordSeq = GEOSGeom_getCoordSeq_r( geosinit.ctxt, bBoxRing );
2788 if ( !bBoxCoordSeq )
2791 unsigned int nCoords = 0;
2792 if ( !GEOSCoordSeq_getSize_r( geosinit.ctxt, bBoxCoordSeq, &nCoords ) )
2796 for (
unsigned int i = 0; i < nCoords - 1; ++i )
2799 GEOSCoordSeq_getX_r( geosinit.ctxt, bBoxCoordSeq, i, &t );
2802 digits = std::ceil( std::log10( std::fabs( t ) ) );
2803 if ( digits > maxDigits )
2806 GEOSCoordSeq_getY_r( geosinit.ctxt, bBoxCoordSeq, i, &t );
2807 digits = std::ceil( std::log10( std::fabs( t ) ) );
2808 if ( digits > maxDigits )
2817 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.