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 return GEOSisValid_r( geosinit.ctxt, mGeos.get() );
1677 if ( !mGeos || !geom )
1689 bool equal = GEOSEquals_r( geosinit.ctxt, mGeos.get(), geosGeom.get() );
1704 return GEOSisEmpty_r( geosinit.ctxt, mGeos.get() );
1718 return GEOSisSimple_r( geosinit.ctxt, mGeos.get() );
1723 GEOSCoordSequence *QgsGeos::createCoordinateSequence(
const QgsCurve *curve,
double precision,
bool forceClose )
1725 std::unique_ptr< QgsLineString > segmentized;
1731 line = segmentized.get();
1739 bool hasZ = line->
is3D();
1753 int numOutPoints = numPoints;
1754 if ( forceClose && ( line->
pointN( 0 ) != line->
pointN( numPoints - 1 ) ) )
1759 GEOSCoordSequence *coordSeq =
nullptr;
1762 coordSeq = GEOSCoordSeq_create_r( geosinit.ctxt, numOutPoints, coordDims );
1765 QgsDebugMsg( QStringLiteral(
"GEOS Exception: Could not create coordinate sequence for %1 points in %2 dimensions" ).arg( numPoints ).arg( coordDims ) );
1769 const double *xData = line->
xData();
1770 const double *yData = line->
yData();
1771 const double *zData = hasZ ? line->
zData() :
nullptr;
1772 const double *mData = hasM ? line->
mData() :
nullptr;
1776 for (
int i = 0; i < numOutPoints; ++i )
1778 if ( i >= numPoints )
1781 xData = line->
xData();
1782 yData = line->
yData();
1783 zData = hasZ ? line->
zData() :
nullptr;
1784 mData = hasM ? line->
mData() :
nullptr;
1786 GEOSCoordSeq_setX_r( geosinit.ctxt, coordSeq, i, std::round( *xData++ /
precision ) *
precision );
1787 GEOSCoordSeq_setY_r( geosinit.ctxt, coordSeq, i, std::round( *yData++ / precision ) * precision );
1790 GEOSCoordSeq_setOrdinate_r( geosinit.ctxt, coordSeq, i, 2, std::round( *zData++ / precision ) * precision );
1794 GEOSCoordSeq_setOrdinate_r( geosinit.ctxt, coordSeq, i, 3, line->
mAt( *mData++ ) );
1800 for (
int i = 0; i < numOutPoints; ++i )
1802 if ( i >= numPoints )
1805 xData = line->
xData();
1806 yData = line->
yData();
1807 zData = hasZ ? line->
zData() :
nullptr;
1808 mData = hasM ? line->
mData() :
nullptr;
1810 GEOSCoordSeq_setX_r( geosinit.ctxt, coordSeq, i, *xData++ );
1811 GEOSCoordSeq_setY_r( geosinit.ctxt, coordSeq, i, *yData++ );
1814 GEOSCoordSeq_setOrdinate_r( geosinit.ctxt, coordSeq, i, 2, *zData++ );
1818 GEOSCoordSeq_setOrdinate_r( geosinit.ctxt, coordSeq, i, 3, *mData++ );
1837 geos::unique_ptr QgsGeos::createGeosPointXY(
double x,
double y,
bool hasZ,
double z,
bool hasM,
double m,
int coordDims,
double precision )
1846 GEOSCoordSequence *coordSeq = GEOSCoordSeq_create_r( geosinit.ctxt, 1, coordDims );
1849 QgsDebugMsg( QStringLiteral(
"GEOS Exception: Could not create coordinate sequence for point with %1 dimensions" ).arg( coordDims ) );
1852 if ( precision > 0. )
1854 GEOSCoordSeq_setX_r( geosinit.ctxt, coordSeq, 0, std::round( x / precision ) * precision );
1855 GEOSCoordSeq_setY_r( geosinit.ctxt, coordSeq, 0, std::round( y / precision ) * precision );
1858 GEOSCoordSeq_setOrdinate_r( geosinit.ctxt, coordSeq, 0, 2, std::round( z / precision ) * precision );
1863 GEOSCoordSeq_setX_r( geosinit.ctxt, coordSeq, 0, x );
1864 GEOSCoordSeq_setY_r( geosinit.ctxt, coordSeq, 0, y );
1867 GEOSCoordSeq_setOrdinate_r( geosinit.ctxt, coordSeq, 0, 2, z );
1870 #if 0 //disabled until geos supports m-coordinates 1873 GEOSCoordSeq_setOrdinate_r( geosinit.ctxt, coordSeq, 0, 3, m );
1876 geosPoint.reset( GEOSGeom_createPoint_r( geosinit.ctxt, coordSeq ) );
1888 GEOSCoordSequence *coordSeq = createCoordinateSequence( c, precision );
1895 geosGeom.reset( GEOSGeom_createLineString_r( geosinit.ctxt, coordSeq ) );
1908 if ( !exteriorRing )
1916 geos::unique_ptr exteriorRingGeos( GEOSGeom_createLinearRing_r( geosinit.ctxt, createCoordinateSequence( exteriorRing, precision,
true ) ) );
1919 GEOSGeometry **holes =
nullptr;
1922 holes =
new GEOSGeometry*[ nHoles ];
1925 for (
int i = 0; i < nHoles; ++i )
1928 holes[i] = GEOSGeom_createLinearRing_r( geosinit.ctxt, createCoordinateSequence( interiorRing, precision,
true ) );
1930 geosPolygon.reset( GEOSGeom_createPolygon_r( geosinit.ctxt, exteriorRingGeos.release(), holes, nHoles ) );
1946 offset.reset( GEOSOffsetCurve_r( geosinit.ctxt, mGeos.get(),
distance, segments, joinStyle, miterLimit ) );
1949 std::unique_ptr< QgsAbstractGeometry > offsetGeom =
fromGeos( offset.get() );
1950 return offsetGeom.release();
1964 GEOSBufferParams_setSingleSided_r( geosinit.ctxt, bp.get(), 1 );
1965 GEOSBufferParams_setQuadrantSegments_r( geosinit.ctxt, bp.get(), segments );
1966 GEOSBufferParams_setJoinStyle_r( geosinit.ctxt, bp.get(), joinStyle );
1967 GEOSBufferParams_setMitreLimit_r( geosinit.ctxt, bp.get(), miterLimit );
1973 geos.reset( GEOSBufferWithParams_r( geosinit.ctxt, mGeos.get(), bp.get(),
distance ) );
1993 geos::unique_ptr reshapeLineGeos = createGeosLinestring( &reshapeWithLine, mPrecision );
1996 int numGeoms = GEOSGetNumGeometries_r( geosinit.ctxt, mGeos.get() );
1997 if ( numGeoms == -1 )
2006 bool isMultiGeom =
false;
2007 int geosTypeId = GEOSGeomTypeId_r( geosinit.ctxt, mGeos.get() );
2008 if ( geosTypeId == GEOS_MULTILINESTRING || geosTypeId == GEOS_MULTIPOLYGON )
2018 reshapedGeometry = reshapeLine( mGeos.get(), reshapeLineGeos.get(), mPrecision );
2022 reshapedGeometry = reshapePolygon( mGeos.get(), reshapeLineGeos.get(), mPrecision );
2027 std::unique_ptr< QgsAbstractGeometry > reshapeResult =
fromGeos( reshapedGeometry.get() );
2028 return reshapeResult;
2035 bool reshapeTookPlace =
false;
2038 GEOSGeometry **newGeoms =
new GEOSGeometry*[numGeoms];
2040 for (
int i = 0; i < numGeoms; ++i )
2043 currentReshapeGeometry = reshapeLine( GEOSGetGeometryN_r( geosinit.ctxt, mGeos.get(), i ), reshapeLineGeos.get(), mPrecision );
2045 currentReshapeGeometry = reshapePolygon( GEOSGetGeometryN_r( geosinit.ctxt, mGeos.get(), i ), reshapeLineGeos.get(), mPrecision );
2047 if ( currentReshapeGeometry )
2049 newGeoms[i] = currentReshapeGeometry.release();
2050 reshapeTookPlace =
true;
2054 newGeoms[i] = GEOSGeom_clone_r( geosinit.ctxt, GEOSGetGeometryN_r( geosinit.ctxt, mGeos.get(), i ) );
2061 newMultiGeom.reset( GEOSGeom_createCollection_r( geosinit.ctxt, GEOS_MULTILINESTRING, newGeoms, numGeoms ) );
2065 newMultiGeom.reset( GEOSGeom_createCollection_r( geosinit.ctxt, GEOS_MULTIPOLYGON, newGeoms, numGeoms ) );
2069 if ( !newMultiGeom )
2075 if ( reshapeTookPlace )
2079 std::unique_ptr< QgsAbstractGeometry > reshapedMultiGeom =
fromGeos( newMultiGeom.get() );
2080 return reshapedMultiGeom;
2102 if ( GEOSGeomTypeId_r( geosinit.ctxt, mGeos.get() ) != GEOS_MULTILINESTRING )
2108 geos.reset( GEOSLineMerge_r( geosinit.ctxt, mGeos.get() ) );
2116 if ( !mGeos || other.
isNull() )
2133 ( void )GEOSCoordSeq_getX_r( geosinit.ctxt, nearestCoord.get(), 0, &nx );
2134 ( void )GEOSCoordSeq_getY_r( geosinit.ctxt, nearestCoord.get(), 0, &ny );
2136 catch ( GEOSException &e )
2140 *errorMsg = e.what();
2150 if ( !mGeos || other.
isNull() )
2169 ( void )GEOSCoordSeq_getX_r( geosinit.ctxt, nearestCoord.get(), 0, &nx1 );
2170 ( void )GEOSCoordSeq_getY_r( geosinit.ctxt, nearestCoord.get(), 0, &ny1 );
2171 ( void )GEOSCoordSeq_getX_r( geosinit.ctxt, nearestCoord.get(), 1, &nx2 );
2172 ( void )GEOSCoordSeq_getY_r( geosinit.ctxt, nearestCoord.get(), 1, &ny2 );
2174 catch ( GEOSException &e )
2178 *errorMsg = e.what();
2205 distance = GEOSProject_r( geosinit.ctxt, mGeos.get(), otherGeom.get() );
2207 catch ( GEOSException &e )
2211 *errorMsg = e.what();
2221 GEOSGeometry **
const lineGeosGeometries =
new GEOSGeometry*[ geometries.size()];
2228 lineGeosGeometries[validLines] = l.release();
2235 geos::unique_ptr result( GEOSPolygonize_r( geosinit.ctxt, lineGeosGeometries, validLines ) );
2236 for (
int i = 0; i < validLines; ++i )
2238 GEOSGeom_destroy_r( geosinit.ctxt, lineGeosGeometries[i] );
2240 delete[] lineGeosGeometries;
2243 catch ( GEOSException &e )
2247 *errorMsg = e.what();
2249 for (
int i = 0; i < validLines; ++i )
2251 GEOSGeom_destroy_r( geosinit.ctxt, lineGeosGeometries[i] );
2253 delete[] lineGeosGeometries;
2268 extentGeosGeom =
asGeos( extent, mPrecision );
2269 if ( !extentGeosGeom )
2278 geos.reset( GEOSVoronoiDiagram_r( geosinit.ctxt, mGeos.get(), extentGeosGeom.get(), tolerance, edgesOnly ) );
2280 if ( !geos || GEOSisEmpty_r( geosinit.ctxt, geos.get() ) != 0 )
2300 geos.reset( GEOSDelaunayTriangulation_r( geosinit.ctxt, mGeos.get(), tolerance, edgesOnly ) );
2302 if ( !geos || GEOSisEmpty_r( geosinit.ctxt, geos.get() ) != 0 )
2314 static bool _linestringEndpoints(
const GEOSGeometry *linestring,
double &x1,
double &y1,
double &x2,
double &y2 )
2316 const GEOSCoordSequence *coordSeq = GEOSGeom_getCoordSeq_r( geosinit.ctxt, linestring );
2320 unsigned int coordSeqSize;
2321 if ( GEOSCoordSeq_getSize_r( geosinit.ctxt, coordSeq, &coordSeqSize ) == 0 )
2324 if ( coordSeqSize < 2 )
2327 GEOSCoordSeq_getX_r( geosinit.ctxt, coordSeq, 0, &x1 );
2328 GEOSCoordSeq_getY_r( geosinit.ctxt, coordSeq, 0, &y1 );
2329 GEOSCoordSeq_getX_r( geosinit.ctxt, coordSeq, coordSeqSize - 1, &x2 );
2330 GEOSCoordSeq_getY_r( geosinit.ctxt, coordSeq, coordSeqSize - 1, &y2 );
2336 static geos::unique_ptr _mergeLinestrings(
const GEOSGeometry *line1,
const GEOSGeometry *line2,
const QgsPointXY &intersectionPoint )
2338 double x1, y1, x2, y2;
2339 if ( !_linestringEndpoints( line1, x1, y1, x2, y2 ) )
2342 double rx1, ry1, rx2, ry2;
2343 if ( !_linestringEndpoints( line2, rx1, ry1, rx2, ry2 ) )
2346 bool intersectionAtOrigLineEndpoint =
2347 ( intersectionPoint.
x() == x1 && intersectionPoint.
y() == y1 ) ||
2348 ( intersectionPoint.
x() == x2 && intersectionPoint.
y() == y2 );
2349 bool intersectionAtReshapeLineEndpoint =
2350 ( intersectionPoint.
x() == rx1 && intersectionPoint.
y() == ry1 ) ||
2351 ( intersectionPoint.
x() == rx2 && intersectionPoint.
y() == ry2 );
2354 if ( intersectionAtOrigLineEndpoint && intersectionAtReshapeLineEndpoint )
2358 GEOSGeometry *geoms[2] = { g1.release(), g2.release() };
2359 geos::unique_ptr multiGeom( GEOSGeom_createCollection_r( geosinit.ctxt, GEOS_MULTILINESTRING, geoms, 2 ) );
2368 geos::unique_ptr QgsGeos::reshapeLine(
const GEOSGeometry *line,
const GEOSGeometry *reshapeLineGeos,
double precision )
2370 if ( !line || !reshapeLineGeos )
2373 bool atLeastTwoIntersections =
false;
2374 bool oneIntersection =
false;
2380 geos::unique_ptr intersectGeom( GEOSIntersection_r( geosinit.ctxt, line, reshapeLineGeos ) );
2381 if ( intersectGeom )
2383 atLeastTwoIntersections = ( GEOSGeomTypeId_r( geosinit.ctxt, intersectGeom.get() ) == GEOS_MULTIPOINT
2384 && GEOSGetNumGeometries_r( geosinit.ctxt, intersectGeom.get() ) > 1 );
2386 if ( GEOSGeomTypeId_r( geosinit.ctxt, intersectGeom.get() ) == GEOS_POINT )
2388 const GEOSCoordSequence *intersectionCoordSeq = GEOSGeom_getCoordSeq_r( geosinit.ctxt, intersectGeom.get() );
2390 GEOSCoordSeq_getX_r( geosinit.ctxt, intersectionCoordSeq, 0, &xi );
2391 GEOSCoordSeq_getY_r( geosinit.ctxt, intersectionCoordSeq, 0, &yi );
2392 oneIntersection =
true;
2397 catch ( GEOSException & )
2399 atLeastTwoIntersections =
false;
2403 if ( oneIntersection )
2404 return _mergeLinestrings( line, reshapeLineGeos, oneIntersectionPoint );
2406 if ( !atLeastTwoIntersections )
2410 double x1, y1, x2, y2;
2411 if ( !_linestringEndpoints( line, x1, y1, x2, y2 ) )
2414 geos::unique_ptr beginLineVertex = createGeosPointXY( x1, y1,
false, 0,
false, 0, 2, precision );
2415 geos::unique_ptr endLineVertex = createGeosPointXY( x2, y2,
false, 0,
false, 0, 2, precision );
2417 bool isRing =
false;
2418 if ( GEOSGeomTypeId_r( geosinit.ctxt, line ) == GEOS_LINEARRING
2419 || GEOSEquals_r( geosinit.ctxt, beginLineVertex.get(), endLineVertex.get() ) == 1 )
2424 if ( !nodedGeometry )
2430 geos::unique_ptr mergedLines( GEOSLineMerge_r( geosinit.ctxt, nodedGeometry.get() ) );
2436 int numMergedLines = GEOSGetNumGeometries_r( geosinit.ctxt, mergedLines.get() );
2437 if ( numMergedLines < 2 )
2439 if ( numMergedLines == 1 )
2441 geos::unique_ptr result( GEOSGeom_clone_r( geosinit.ctxt, reshapeLineGeos ) );
2448 QVector<GEOSGeometry *> resultLineParts;
2449 QVector<GEOSGeometry *> probableParts;
2451 for (
int i = 0; i < numMergedLines; ++i )
2453 const GEOSGeometry *currentGeom =
nullptr;
2455 currentGeom = GEOSGetGeometryN_r( geosinit.ctxt, mergedLines.get(), i );
2456 const GEOSCoordSequence *currentCoordSeq = GEOSGeom_getCoordSeq_r( geosinit.ctxt, currentGeom );
2457 unsigned int currentCoordSeqSize;
2458 GEOSCoordSeq_getSize_r( geosinit.ctxt, currentCoordSeq, ¤tCoordSeqSize );
2459 if ( currentCoordSeqSize < 2 )
2463 double xBegin, xEnd, yBegin, yEnd;
2464 GEOSCoordSeq_getX_r( geosinit.ctxt, currentCoordSeq, 0, &xBegin );
2465 GEOSCoordSeq_getY_r( geosinit.ctxt, currentCoordSeq, 0, &yBegin );
2466 GEOSCoordSeq_getX_r( geosinit.ctxt, currentCoordSeq, currentCoordSeqSize - 1, &xEnd );
2467 GEOSCoordSeq_getY_r( geosinit.ctxt, currentCoordSeq, currentCoordSeqSize - 1, &yEnd );
2468 geos::unique_ptr beginCurrentGeomVertex = createGeosPointXY( xBegin, yBegin,
false, 0,
false, 0, 2, precision );
2469 geos::unique_ptr endCurrentGeomVertex = createGeosPointXY( xEnd, yEnd,
false, 0,
false, 0, 2, precision );
2472 int nEndpointsOnOriginalLine = 0;
2473 if ( pointContainedInLine( beginCurrentGeomVertex.get(), line ) == 1 )
2474 nEndpointsOnOriginalLine += 1;
2476 if ( pointContainedInLine( endCurrentGeomVertex.get(), line ) == 1 )
2477 nEndpointsOnOriginalLine += 1;
2480 int nEndpointsSameAsOriginalLine = 0;
2481 if ( GEOSEquals_r( geosinit.ctxt, beginCurrentGeomVertex.get(), beginLineVertex.get() ) == 1
2482 || GEOSEquals_r( geosinit.ctxt, beginCurrentGeomVertex.get(), endLineVertex.get() ) == 1 )
2483 nEndpointsSameAsOriginalLine += 1;
2485 if ( GEOSEquals_r( geosinit.ctxt, endCurrentGeomVertex.get(), beginLineVertex.get() ) == 1
2486 || GEOSEquals_r( geosinit.ctxt, endCurrentGeomVertex.get(), endLineVertex.get() ) == 1 )
2487 nEndpointsSameAsOriginalLine += 1;
2490 bool currentGeomOverlapsOriginalGeom =
false;
2491 bool currentGeomOverlapsReshapeLine =
false;
2492 if ( lineContainedInLine( currentGeom, line ) == 1 )
2493 currentGeomOverlapsOriginalGeom =
true;
2495 if ( lineContainedInLine( currentGeom, reshapeLineGeos ) == 1 )
2496 currentGeomOverlapsReshapeLine =
true;
2499 if ( !isRing && nEndpointsSameAsOriginalLine == 1 && nEndpointsOnOriginalLine == 2 && currentGeomOverlapsOriginalGeom )
2501 resultLineParts.push_back( GEOSGeom_clone_r( geosinit.ctxt, currentGeom ) );
2504 else if ( isRing && nEndpointsOnOriginalLine == 2 && currentGeomOverlapsOriginalGeom )
2506 probableParts.push_back( GEOSGeom_clone_r( geosinit.ctxt, currentGeom ) );
2508 else if ( nEndpointsOnOriginalLine == 2 && !currentGeomOverlapsOriginalGeom )
2510 resultLineParts.push_back( GEOSGeom_clone_r( geosinit.ctxt, currentGeom ) );
2512 else if ( nEndpointsSameAsOriginalLine == 2 && !currentGeomOverlapsOriginalGeom )
2514 resultLineParts.push_back( GEOSGeom_clone_r( geosinit.ctxt, currentGeom ) );
2516 else if ( currentGeomOverlapsOriginalGeom && currentGeomOverlapsReshapeLine )
2518 resultLineParts.push_back( GEOSGeom_clone_r( geosinit.ctxt, currentGeom ) );
2523 if ( isRing && !probableParts.isEmpty() )
2526 GEOSGeometry *currentGeom =
nullptr;
2527 double maxLength = -std::numeric_limits<double>::max();
2528 double currentLength = 0;
2529 for (
int i = 0; i < probableParts.size(); ++i )
2531 currentGeom = probableParts.at( i );
2532 GEOSLength_r( geosinit.ctxt, currentGeom, ¤tLength );
2533 if ( currentLength > maxLength )
2535 maxLength = currentLength;
2536 maxGeom.reset( currentGeom );
2540 GEOSGeom_destroy_r( geosinit.ctxt, currentGeom );
2543 resultLineParts.push_back( maxGeom.release() );
2547 if ( resultLineParts.empty() )
2550 if ( resultLineParts.size() == 1 )
2552 result.reset( resultLineParts[0] );
2556 GEOSGeometry **lineArray =
new GEOSGeometry*[resultLineParts.size()];
2557 for (
int i = 0; i < resultLineParts.size(); ++i )
2559 lineArray[i] = resultLineParts[i];
2563 geos::unique_ptr multiLineGeom( GEOSGeom_createCollection_r( geosinit.ctxt, GEOS_MULTILINESTRING, lineArray, resultLineParts.size() ) );
2564 delete [] lineArray;
2567 result.reset( GEOSLineMerge_r( geosinit.ctxt, multiLineGeom.get() ) );
2571 if ( GEOSGeomTypeId_r( geosinit.ctxt, result.get() ) != GEOS_LINESTRING )
2579 geos::unique_ptr QgsGeos::reshapePolygon(
const GEOSGeometry *polygon,
const GEOSGeometry *reshapeLineGeos,
double precision )
2582 int nIntersections = 0;
2583 int lastIntersectingRing = -2;
2584 const GEOSGeometry *lastIntersectingGeom =
nullptr;
2586 int nRings = GEOSGetNumInteriorRings_r( geosinit.ctxt, polygon );
2591 const GEOSGeometry *outerRing = GEOSGetExteriorRing_r( geosinit.ctxt, polygon );
2592 if ( GEOSIntersects_r( geosinit.ctxt, outerRing, reshapeLineGeos ) == 1 )
2595 lastIntersectingRing = -1;
2596 lastIntersectingGeom = outerRing;
2600 const GEOSGeometry **innerRings =
new const GEOSGeometry*[nRings];
2604 for (
int i = 0; i < nRings; ++i )
2606 innerRings[i] = GEOSGetInteriorRingN_r( geosinit.ctxt, polygon, i );
2607 if ( GEOSIntersects_r( geosinit.ctxt, innerRings[i], reshapeLineGeos ) == 1 )
2610 lastIntersectingRing = i;
2611 lastIntersectingGeom = innerRings[i];
2615 catch ( GEOSException & )
2620 if ( nIntersections != 1 )
2622 delete [] innerRings;
2627 geos::unique_ptr reshapeResult = reshapeLine( lastIntersectingGeom, reshapeLineGeos, precision );
2628 if ( !reshapeResult )
2630 delete [] innerRings;
2635 GEOSGeometry *newRing =
nullptr;
2636 const GEOSCoordSequence *reshapeSequence = GEOSGeom_getCoordSeq_r( geosinit.ctxt, reshapeResult.get() );
2637 GEOSCoordSequence *newCoordSequence = GEOSCoordSeq_clone_r( geosinit.ctxt, reshapeSequence );
2639 reshapeResult.reset();
2641 newRing = GEOSGeom_createLinearRing_r( geosinit.ctxt, newCoordSequence );
2644 delete [] innerRings;
2648 GEOSGeometry *newOuterRing =
nullptr;
2649 if ( lastIntersectingRing == -1 )
2650 newOuterRing = newRing;
2652 newOuterRing = GEOSGeom_clone_r( geosinit.ctxt, outerRing );
2655 QVector<GEOSGeometry *> ringList;
2658 GEOSGeometry *outerRingPoly = GEOSGeom_createPolygon_r( geosinit.ctxt, GEOSGeom_clone_r( geosinit.ctxt, newOuterRing ),
nullptr, 0 );
2659 if ( outerRingPoly )
2661 GEOSGeometry *currentRing =
nullptr;
2662 for (
int i = 0; i < nRings; ++i )
2664 if ( lastIntersectingRing == i )
2665 currentRing = newRing;
2667 currentRing = GEOSGeom_clone_r( geosinit.ctxt, innerRings[i] );
2670 if ( GEOSContains_r( geosinit.ctxt, outerRingPoly, currentRing ) == 1 )
2671 ringList.push_back( currentRing );
2673 GEOSGeom_destroy_r( geosinit.ctxt, currentRing );
2676 GEOSGeom_destroy_r( geosinit.ctxt, outerRingPoly );
2679 GEOSGeometry **newInnerRings =
new GEOSGeometry*[ringList.size()];
2680 for (
int i = 0; i < ringList.size(); ++i )
2681 newInnerRings[i] = ringList.at( i );
2683 delete [] innerRings;
2685 geos::unique_ptr reshapedPolygon( GEOSGeom_createPolygon_r( geosinit.ctxt, newOuterRing, newInnerRings, ringList.size() ) );
2686 delete[] newInnerRings;
2688 return reshapedPolygon;
2691 int QgsGeos::lineContainedInLine(
const GEOSGeometry *line1,
const GEOSGeometry *line2 )
2693 if ( !line1 || !line2 )
2698 double bufferDistance = std::pow( 10.0L, geomDigits( line2 ) - 11 );
2704 geos::unique_ptr intersectionGeom( GEOSIntersection_r( geosinit.ctxt, bufferGeom.get(), line1 ) );
2707 double intersectGeomLength;
2710 GEOSLength_r( geosinit.ctxt, intersectionGeom.get(), &intersectGeomLength );
2711 GEOSLength_r( geosinit.ctxt, line1, &line1Length );
2713 double intersectRatio = line1Length / intersectGeomLength;
2714 if ( intersectRatio > 0.9 && intersectRatio < 1.1 )
2720 int QgsGeos::pointContainedInLine(
const GEOSGeometry *point,
const GEOSGeometry *line )
2722 if ( !point || !line )
2725 double bufferDistance = std::pow( 10.0L, geomDigits( line ) - 11 );
2727 geos::unique_ptr lineBuffer( GEOSBuffer_r( geosinit.ctxt, line, bufferDistance, 8 ) );
2731 bool contained =
false;
2732 if ( GEOSContains_r( geosinit.ctxt, lineBuffer.get(), point ) == 1 )
2738 int QgsGeos::geomDigits(
const GEOSGeometry *geom )
2744 const GEOSGeometry *bBoxRing = GEOSGetExteriorRing_r( geosinit.ctxt, bbox.get() );
2748 const GEOSCoordSequence *bBoxCoordSeq = GEOSGeom_getCoordSeq_r( geosinit.ctxt, bBoxRing );
2750 if ( !bBoxCoordSeq )
2753 unsigned int nCoords = 0;
2754 if ( !GEOSCoordSeq_getSize_r( geosinit.ctxt, bBoxCoordSeq, &nCoords ) )
2758 for (
unsigned int i = 0; i < nCoords - 1; ++i )
2761 GEOSCoordSeq_getX_r( geosinit.ctxt, bBoxCoordSeq, i, &t );
2764 digits = std::ceil( std::log10( std::fabs( t ) ) );
2765 if ( digits > maxDigits )
2768 GEOSCoordSeq_getY_r( geosinit.ctxt, bBoxCoordSeq, i, &t );
2769 digits = std::ceil( std::log10( std::fabs( t ) ) );
2770 if ( digits > maxDigits )
2779 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 a 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
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.
bool isValid(QString *errorMsg=nullptr) const override
QgsGeometry closestPoint(const QgsGeometry &other, QString *errorMsg=nullptr) const
Returns the closest point on the geometry to the other geometry.
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.
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 a 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.