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( QString(
"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 )
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 for (
int i = 0; i < GEOSGetNumInteriorRings_r( geosinit.ctxt, geos ); ++i )
1192 ring = GEOSGetInteriorRingN_r( geosinit.ctxt, geos, i );
1195 interiorRings.push_back( sequenceToLinestring( ring, hasZ, hasM ).release() );
1198 polygon->setInteriorRings( interiorRings );
1203 std::unique_ptr<QgsLineString> QgsGeos::sequenceToLinestring(
const GEOSGeometry *
geos,
bool hasZ,
bool hasM )
1205 const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq_r( geosinit.ctxt,
geos );
1206 unsigned int nPoints;
1207 GEOSCoordSeq_getSize_r( geosinit.ctxt, cs, &nPoints );
1208 QVector< double > xOut( nPoints );
1209 QVector< double > yOut( nPoints );
1210 QVector< double > zOut;
1212 zOut.resize( nPoints );
1213 QVector< double > mOut;
1215 mOut.resize( nPoints );
1216 double *x = xOut.data();
1217 double *y = yOut.data();
1218 double *z = zOut.data();
1219 double *m = mOut.data();
1220 for (
unsigned int i = 0; i < nPoints; ++i )
1222 GEOSCoordSeq_getX_r( geosinit.ctxt, cs, i, x++ );
1223 GEOSCoordSeq_getY_r( geosinit.ctxt, cs, i, y++ );
1226 GEOSCoordSeq_getZ_r( geosinit.ctxt, cs, i, z++ );
1230 GEOSCoordSeq_getOrdinate_r( geosinit.ctxt, cs, i, 3, m++ );
1233 std::unique_ptr< QgsLineString > line(
new QgsLineString( xOut, yOut, zOut, mOut ) );
1237 int QgsGeos::numberOfGeometries( GEOSGeometry *g )
1242 int geometryType = GEOSGeomTypeId_r( geosinit.ctxt, g );
1243 if ( geometryType == GEOS_POINT || geometryType == GEOS_LINESTRING || geometryType == GEOS_LINEARRING
1244 || geometryType == GEOS_POLYGON )
1248 return GEOSGetNumGeometries_r( geosinit.ctxt, g );
1261 GEOSCoordSeq_getX_r( geosinit.ctxt, cs, i, &x );
1262 GEOSCoordSeq_getY_r( geosinit.ctxt, cs, i, &y );
1265 GEOSCoordSeq_getZ_r( geosinit.ctxt, cs, i, &z );
1269 GEOSCoordSeq_getOrdinate_r( geosinit.ctxt, cs, i, 3, &m );
1305 int geosType = GEOS_GEOMETRYCOLLECTION;
1312 geosType = GEOS_MULTIPOINT;
1316 geosType = GEOS_MULTILINESTRING;
1320 geosType = GEOS_MULTIPOLYGON;
1341 return createGeosCollection( geosType, geomVector );
1348 return createGeosPoint( static_cast<const QgsPoint *>( geom ), coordDims, precision );
1352 return createGeosLinestring( static_cast<const QgsLineString *>( geom ), precision );
1356 return createGeosPolygon( static_cast<const QgsPolygon *>( geom ), precision );
1368 std::unique_ptr<QgsAbstractGeometry> QgsGeos::overlay(
const QgsAbstractGeometry *geom, Overlay op, QString *errorMsg )
const 1370 if ( !mGeos || !geom )
1386 case OverlayIntersection:
1387 opGeom.reset( GEOSIntersection_r( geosinit.ctxt, mGeos.get(), geosGeom.get() ) );
1389 case OverlayDifference:
1390 opGeom.reset( GEOSDifference_r( geosinit.ctxt, mGeos.get(), geosGeom.get() ) );
1394 geos::unique_ptr unionGeometry( GEOSUnion_r( geosinit.ctxt, mGeos.get(), geosGeom.get() ) );
1396 if ( unionGeometry && GEOSGeomTypeId_r( geosinit.ctxt, unionGeometry.get() ) == GEOS_MULTILINESTRING )
1398 geos::unique_ptr mergedLines( GEOSLineMerge_r( geosinit.ctxt, unionGeometry.get() ) );
1401 unionGeometry = std::move( mergedLines );
1405 opGeom = std::move( unionGeometry );
1408 case OverlaySymDifference:
1409 opGeom.reset( GEOSSymDifference_r( geosinit.ctxt, mGeos.get(), geosGeom.get() ) );
1416 catch ( GEOSException &e )
1420 *errorMsg = e.what();
1426 bool QgsGeos::relation(
const QgsAbstractGeometry *geom, Relation r, QString *errorMsg )
const 1428 if ( !mGeos || !geom )
1439 bool result =
false;
1442 if ( mGeosPrepared )
1446 case RelationIntersects:
1447 result = ( GEOSPreparedIntersects_r( geosinit.ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1449 case RelationTouches:
1450 result = ( GEOSPreparedTouches_r( geosinit.ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1452 case RelationCrosses:
1453 result = ( GEOSPreparedCrosses_r( geosinit.ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1455 case RelationWithin:
1456 result = ( GEOSPreparedWithin_r( geosinit.ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1458 case RelationContains:
1459 result = ( GEOSPreparedContains_r( geosinit.ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1461 case RelationDisjoint:
1462 result = ( GEOSPreparedDisjoint_r( geosinit.ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1464 case RelationOverlaps:
1465 result = ( GEOSPreparedOverlaps_r( geosinit.ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1475 case RelationIntersects:
1476 result = ( GEOSIntersects_r( geosinit.ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1478 case RelationTouches:
1479 result = ( GEOSTouches_r( geosinit.ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1481 case RelationCrosses:
1482 result = ( GEOSCrosses_r( geosinit.ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1484 case RelationWithin:
1485 result = ( GEOSWithin_r( geosinit.ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1487 case RelationContains:
1488 result = ( GEOSContains_r( geosinit.ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1490 case RelationDisjoint:
1491 result = ( GEOSDisjoint_r( geosinit.ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1493 case RelationOverlaps:
1494 result = ( GEOSOverlaps_r( geosinit.ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1500 catch ( GEOSException &e )
1504 *errorMsg = e.what();
1522 geos.reset( GEOSBuffer_r( geosinit.ctxt, mGeos.get(),
distance, segments ) );
1525 return fromGeos( geos.get() ).release();
1538 geos.reset( GEOSBufferWithStyle_r( geosinit.ctxt, mGeos.get(),
distance, segments, endCapStyle, joinStyle, miterLimit ) );
1541 return fromGeos( geos.get() ).release();
1553 geos.reset( GEOSTopologyPreserveSimplify_r( geosinit.ctxt, mGeos.get(), tolerance ) );
1556 return fromGeos( geos.get() ).release();
1568 geos.reset( GEOSInterpolate_r( geosinit.ctxt, mGeos.get(),
distance ) );
1571 return fromGeos( geos.get() ).release();
1587 geos.reset( GEOSGetCentroid_r( geosinit.ctxt, mGeos.get() ) );
1592 GEOSGeomGetX_r( geosinit.ctxt, geos.get(), &x );
1593 GEOSGeomGetY_r( geosinit.ctxt, geos.get(), &y );
1609 geos.reset( GEOSEnvelope_r( geosinit.ctxt, mGeos.get() ) );
1612 return fromGeos( geos.get() ).release();
1628 geos.reset( GEOSPointOnSurface_r( geosinit.ctxt, mGeos.get() ) );
1630 if ( !geos || GEOSisEmpty_r( geosinit.ctxt, geos.get() ) != 0 )
1635 GEOSGeomGetX_r( geosinit.ctxt, geos.get(), &x );
1636 GEOSGeomGetY_r( geosinit.ctxt, geos.get(), &y );
1653 std::unique_ptr< QgsAbstractGeometry > cHullGeom =
fromGeos( cHull.get() );
1654 return cHullGeom.release();
1668 return GEOSisValid_r( geosinit.ctxt, mGeos.get() );
1675 if ( !mGeos || !geom )
1687 bool equal = GEOSEquals_r( geosinit.ctxt, mGeos.get(), geosGeom.get() );
1702 return GEOSisEmpty_r( geosinit.ctxt, mGeos.get() );
1716 return GEOSisSimple_r( geosinit.ctxt, mGeos.get() );
1721 GEOSCoordSequence *QgsGeos::createCoordinateSequence(
const QgsCurve *curve,
double precision,
bool forceClose )
1723 std::unique_ptr< QgsLineString > segmentized;
1729 line = segmentized.get();
1737 bool hasZ = line->
is3D();
1751 int numOutPoints = numPoints;
1752 if ( forceClose && ( line->
pointN( 0 ) != line->
pointN( numPoints - 1 ) ) )
1757 GEOSCoordSequence *coordSeq =
nullptr;
1760 coordSeq = GEOSCoordSeq_create_r( geosinit.ctxt, numOutPoints, coordDims );
1763 QgsDebugMsg( QStringLiteral(
"GEOS Exception: Could not create coordinate sequence for %1 points in %2 dimensions" ).arg( numPoints ).arg( coordDims ) );
1767 const double *xData = line->
xData();
1768 const double *yData = line->
yData();
1769 const double *zData = hasZ ? line->
zData() :
nullptr;
1770 const double *mData = hasM ? line->
mData() :
nullptr;
1772 if ( precision > 0. )
1774 for (
int i = 0; i < numOutPoints; ++i )
1776 if ( i >= numPoints )
1779 xData = line->
xData();
1780 yData = line->
yData();
1781 zData = hasZ ? line->
zData() :
nullptr;
1782 mData = hasM ? line->
mData() :
nullptr;
1784 GEOSCoordSeq_setX_r( geosinit.ctxt, coordSeq, i, std::round( *xData++ / precision ) * precision );
1785 GEOSCoordSeq_setY_r( geosinit.ctxt, coordSeq, i, std::round( *yData++ / precision ) * precision );
1788 GEOSCoordSeq_setOrdinate_r( geosinit.ctxt, coordSeq, i, 2, std::round( *zData++ / precision ) * precision );
1792 GEOSCoordSeq_setOrdinate_r( geosinit.ctxt, coordSeq, i, 3, line->
mAt( *mData++ ) );
1798 for (
int i = 0; i < numOutPoints; ++i )
1800 if ( i >= numPoints )
1803 xData = line->
xData();
1804 yData = line->
yData();
1805 zData = hasZ ? line->
zData() :
nullptr;
1806 mData = hasM ? line->
mData() :
nullptr;
1808 GEOSCoordSeq_setX_r( geosinit.ctxt, coordSeq, i, *xData++ );
1809 GEOSCoordSeq_setY_r( geosinit.ctxt, coordSeq, i, *yData++ );
1812 GEOSCoordSeq_setOrdinate_r( geosinit.ctxt, coordSeq, i, 2, *zData++ );
1816 GEOSCoordSeq_setOrdinate_r( geosinit.ctxt, coordSeq, i, 3, *mData++ );
1832 return createGeosPointXY( pt->
x(), pt->
y(), pt->
is3D(), pt->
z(), pt->
isMeasure(), pt->
m(), coordDims, precision );
1835 geos::unique_ptr QgsGeos::createGeosPointXY(
double x,
double y,
bool hasZ,
double z,
bool hasM,
double m,
int coordDims,
double precision )
1844 GEOSCoordSequence *coordSeq = GEOSCoordSeq_create_r( geosinit.ctxt, 1, coordDims );
1847 QgsDebugMsg( QStringLiteral(
"GEOS Exception: Could not create coordinate sequence for point with %1 dimensions" ).arg( coordDims ) );
1850 if ( precision > 0. )
1852 GEOSCoordSeq_setX_r( geosinit.ctxt, coordSeq, 0, std::round( x / precision ) * precision );
1853 GEOSCoordSeq_setY_r( geosinit.ctxt, coordSeq, 0, std::round( y / precision ) * precision );
1856 GEOSCoordSeq_setOrdinate_r( geosinit.ctxt, coordSeq, 0, 2, std::round( z / precision ) * precision );
1861 GEOSCoordSeq_setX_r( geosinit.ctxt, coordSeq, 0, x );
1862 GEOSCoordSeq_setY_r( geosinit.ctxt, coordSeq, 0, y );
1865 GEOSCoordSeq_setOrdinate_r( geosinit.ctxt, coordSeq, 0, 2, z );
1868 #if 0 //disabled until geos supports m-coordinates 1871 GEOSCoordSeq_setOrdinate_r( geosinit.ctxt, coordSeq, 0, 3, m );
1874 geosPoint.reset( GEOSGeom_createPoint_r( geosinit.ctxt, coordSeq ) );
1886 GEOSCoordSequence *coordSeq = createCoordinateSequence( c, precision );
1893 geosGeom.reset( GEOSGeom_createLineString_r( geosinit.ctxt, coordSeq ) );
1906 if ( !exteriorRing )
1914 geos::unique_ptr exteriorRingGeos( GEOSGeom_createLinearRing_r( geosinit.ctxt, createCoordinateSequence( exteriorRing, precision,
true ) ) );
1917 GEOSGeometry **holes =
nullptr;
1920 holes =
new GEOSGeometry*[ nHoles ];
1923 for (
int i = 0; i < nHoles; ++i )
1926 holes[i] = GEOSGeom_createLinearRing_r( geosinit.ctxt, createCoordinateSequence( interiorRing, precision,
true ) );
1928 geosPolygon.reset( GEOSGeom_createPolygon_r( geosinit.ctxt, exteriorRingGeos.release(), holes, nHoles ) );
1944 offset.reset( GEOSOffsetCurve_r( geosinit.ctxt, mGeos.get(),
distance, segments, joinStyle, miterLimit ) );
1947 std::unique_ptr< QgsAbstractGeometry > offsetGeom =
fromGeos( offset.get() );
1948 return offsetGeom.release();
1962 GEOSBufferParams_setSingleSided_r( geosinit.ctxt, bp.get(), 1 );
1963 GEOSBufferParams_setQuadrantSegments_r( geosinit.ctxt, bp.get(), segments );
1964 GEOSBufferParams_setJoinStyle_r( geosinit.ctxt, bp.get(), joinStyle );
1965 GEOSBufferParams_setMitreLimit_r( geosinit.ctxt, bp.get(), miterLimit );
1971 geos.reset( GEOSBufferWithParams_r( geosinit.ctxt, mGeos.get(), bp.get(),
distance ) );
1991 geos::unique_ptr reshapeLineGeos = createGeosLinestring( &reshapeWithLine, mPrecision );
1994 int numGeoms = GEOSGetNumGeometries_r( geosinit.ctxt, mGeos.get() );
1995 if ( numGeoms == -1 )
2004 bool isMultiGeom =
false;
2005 int geosTypeId = GEOSGeomTypeId_r( geosinit.ctxt, mGeos.get() );
2006 if ( geosTypeId == GEOS_MULTILINESTRING || geosTypeId == GEOS_MULTIPOLYGON )
2016 reshapedGeometry = reshapeLine( mGeos.get(), reshapeLineGeos.get(), mPrecision );
2020 reshapedGeometry = reshapePolygon( mGeos.get(), reshapeLineGeos.get(), mPrecision );
2025 std::unique_ptr< QgsAbstractGeometry > reshapeResult =
fromGeos( reshapedGeometry.get() );
2026 return reshapeResult;
2033 bool reshapeTookPlace =
false;
2036 GEOSGeometry **newGeoms =
new GEOSGeometry*[numGeoms];
2038 for (
int i = 0; i < numGeoms; ++i )
2041 currentReshapeGeometry = reshapeLine( GEOSGetGeometryN_r( geosinit.ctxt, mGeos.get(), i ), reshapeLineGeos.get(), mPrecision );
2043 currentReshapeGeometry = reshapePolygon( GEOSGetGeometryN_r( geosinit.ctxt, mGeos.get(), i ), reshapeLineGeos.get(), mPrecision );
2045 if ( currentReshapeGeometry )
2047 newGeoms[i] = currentReshapeGeometry.release();
2048 reshapeTookPlace =
true;
2052 newGeoms[i] = GEOSGeom_clone_r( geosinit.ctxt, GEOSGetGeometryN_r( geosinit.ctxt, mGeos.get(), i ) );
2059 newMultiGeom.reset( GEOSGeom_createCollection_r( geosinit.ctxt, GEOS_MULTILINESTRING, newGeoms, numGeoms ) );
2063 newMultiGeom.reset( GEOSGeom_createCollection_r( geosinit.ctxt, GEOS_MULTIPOLYGON, newGeoms, numGeoms ) );
2067 if ( !newMultiGeom )
2073 if ( reshapeTookPlace )
2077 std::unique_ptr< QgsAbstractGeometry > reshapedMultiGeom =
fromGeos( newMultiGeom.get() );
2078 return reshapedMultiGeom;
2100 if ( GEOSGeomTypeId_r( geosinit.ctxt, mGeos.get() ) != GEOS_MULTILINESTRING )
2106 geos.reset( GEOSLineMerge_r( geosinit.ctxt, mGeos.get() ) );
2114 if ( !mGeos || other.
isNull() )
2131 ( void )GEOSCoordSeq_getX_r( geosinit.ctxt, nearestCoord.get(), 0, &nx );
2132 ( void )GEOSCoordSeq_getY_r( geosinit.ctxt, nearestCoord.get(), 0, &ny );
2134 catch ( GEOSException &e )
2138 *errorMsg = e.what();
2148 if ( !mGeos || other.
isNull() )
2167 ( void )GEOSCoordSeq_getX_r( geosinit.ctxt, nearestCoord.get(), 0, &nx1 );
2168 ( void )GEOSCoordSeq_getY_r( geosinit.ctxt, nearestCoord.get(), 0, &ny1 );
2169 ( void )GEOSCoordSeq_getX_r( geosinit.ctxt, nearestCoord.get(), 1, &nx2 );
2170 ( void )GEOSCoordSeq_getY_r( geosinit.ctxt, nearestCoord.get(), 1, &ny2 );
2172 catch ( GEOSException &e )
2176 *errorMsg = e.what();
2203 distance = GEOSProject_r( geosinit.ctxt, mGeos.get(), otherGeom.get() );
2205 catch ( GEOSException &e )
2209 *errorMsg = e.what();
2219 GEOSGeometry **
const lineGeosGeometries =
new GEOSGeometry*[ geometries.size()];
2226 lineGeosGeometries[validLines] = l.release();
2233 geos::unique_ptr result( GEOSPolygonize_r( geosinit.ctxt, lineGeosGeometries, validLines ) );
2234 for (
int i = 0; i < validLines; ++i )
2236 GEOSGeom_destroy_r( geosinit.ctxt, lineGeosGeometries[i] );
2238 delete[] lineGeosGeometries;
2241 catch ( GEOSException &e )
2245 *errorMsg = e.what();
2247 for (
int i = 0; i < validLines; ++i )
2249 GEOSGeom_destroy_r( geosinit.ctxt, lineGeosGeometries[i] );
2251 delete[] lineGeosGeometries;
2266 extentGeosGeom =
asGeos( extent, mPrecision );
2267 if ( !extentGeosGeom )
2276 geos.reset( GEOSVoronoiDiagram_r( geosinit.ctxt, mGeos.get(), extentGeosGeom.get(), tolerance, edgesOnly ) );
2278 if ( !geos || GEOSisEmpty_r( geosinit.ctxt, geos.get() ) != 0 )
2298 geos.reset( GEOSDelaunayTriangulation_r( geosinit.ctxt, mGeos.get(), tolerance, edgesOnly ) );
2300 if ( !geos || GEOSisEmpty_r( geosinit.ctxt, geos.get() ) != 0 )
2312 static bool _linestringEndpoints(
const GEOSGeometry *linestring,
double &x1,
double &y1,
double &x2,
double &y2 )
2314 const GEOSCoordSequence *coordSeq = GEOSGeom_getCoordSeq_r( geosinit.ctxt, linestring );
2318 unsigned int coordSeqSize;
2319 if ( GEOSCoordSeq_getSize_r( geosinit.ctxt, coordSeq, &coordSeqSize ) == 0 )
2322 if ( coordSeqSize < 2 )
2325 GEOSCoordSeq_getX_r( geosinit.ctxt, coordSeq, 0, &x1 );
2326 GEOSCoordSeq_getY_r( geosinit.ctxt, coordSeq, 0, &y1 );
2327 GEOSCoordSeq_getX_r( geosinit.ctxt, coordSeq, coordSeqSize - 1, &x2 );
2328 GEOSCoordSeq_getY_r( geosinit.ctxt, coordSeq, coordSeqSize - 1, &y2 );
2334 static geos::unique_ptr _mergeLinestrings(
const GEOSGeometry *line1,
const GEOSGeometry *line2,
const QgsPointXY &intersectionPoint )
2336 double x1, y1, x2, y2;
2337 if ( !_linestringEndpoints( line1, x1, y1, x2, y2 ) )
2340 double rx1, ry1, rx2, ry2;
2341 if ( !_linestringEndpoints( line2, rx1, ry1, rx2, ry2 ) )
2344 bool intersectionAtOrigLineEndpoint =
2345 ( intersectionPoint.
x() == x1 && intersectionPoint.
y() == y1 ) ||
2346 ( intersectionPoint.
x() == x2 && intersectionPoint.
y() == y2 );
2347 bool intersectionAtReshapeLineEndpoint =
2348 ( intersectionPoint.
x() == rx1 && intersectionPoint.
y() == ry1 ) ||
2349 ( intersectionPoint.
x() == rx2 && intersectionPoint.
y() == ry2 );
2352 if ( intersectionAtOrigLineEndpoint && intersectionAtReshapeLineEndpoint )
2356 GEOSGeometry *geoms[2] = { g1.release(), g2.release() };
2357 geos::unique_ptr multiGeom( GEOSGeom_createCollection_r( geosinit.ctxt, GEOS_MULTILINESTRING, geoms, 2 ) );
2366 geos::unique_ptr QgsGeos::reshapeLine(
const GEOSGeometry *line,
const GEOSGeometry *reshapeLineGeos,
double precision )
2368 if ( !line || !reshapeLineGeos )
2371 bool atLeastTwoIntersections =
false;
2372 bool oneIntersection =
false;
2378 geos::unique_ptr intersectGeom( GEOSIntersection_r( geosinit.ctxt, line, reshapeLineGeos ) );
2379 if ( intersectGeom )
2381 atLeastTwoIntersections = ( GEOSGeomTypeId_r( geosinit.ctxt, intersectGeom.get() ) == GEOS_MULTIPOINT
2382 && GEOSGetNumGeometries_r( geosinit.ctxt, intersectGeom.get() ) > 1 );
2384 if ( GEOSGeomTypeId_r( geosinit.ctxt, intersectGeom.get() ) == GEOS_POINT )
2386 const GEOSCoordSequence *intersectionCoordSeq = GEOSGeom_getCoordSeq_r( geosinit.ctxt, intersectGeom.get() );
2388 GEOSCoordSeq_getX_r( geosinit.ctxt, intersectionCoordSeq, 0, &xi );
2389 GEOSCoordSeq_getY_r( geosinit.ctxt, intersectionCoordSeq, 0, &yi );
2390 oneIntersection =
true;
2395 catch ( GEOSException & )
2397 atLeastTwoIntersections =
false;
2401 if ( oneIntersection )
2402 return _mergeLinestrings( line, reshapeLineGeos, oneIntersectionPoint );
2404 if ( !atLeastTwoIntersections )
2408 double x1, y1, x2, y2;
2409 if ( !_linestringEndpoints( line, x1, y1, x2, y2 ) )
2412 geos::unique_ptr beginLineVertex = createGeosPointXY( x1, y1,
false, 0,
false, 0, 2, precision );
2413 geos::unique_ptr endLineVertex = createGeosPointXY( x2, y2,
false, 0,
false, 0, 2, precision );
2415 bool isRing =
false;
2416 if ( GEOSGeomTypeId_r( geosinit.ctxt, line ) == GEOS_LINEARRING
2417 || GEOSEquals_r( geosinit.ctxt, beginLineVertex.get(), endLineVertex.get() ) == 1 )
2422 if ( !nodedGeometry )
2428 geos::unique_ptr mergedLines( GEOSLineMerge_r( geosinit.ctxt, nodedGeometry.get() ) );
2434 int numMergedLines = GEOSGetNumGeometries_r( geosinit.ctxt, mergedLines.get() );
2435 if ( numMergedLines < 2 )
2437 if ( numMergedLines == 1 )
2439 geos::unique_ptr result( GEOSGeom_clone_r( geosinit.ctxt, reshapeLineGeos ) );
2446 QVector<GEOSGeometry *> resultLineParts;
2447 QVector<GEOSGeometry *> probableParts;
2449 for (
int i = 0; i < numMergedLines; ++i )
2451 const GEOSGeometry *currentGeom =
nullptr;
2453 currentGeom = GEOSGetGeometryN_r( geosinit.ctxt, mergedLines.get(), i );
2454 const GEOSCoordSequence *currentCoordSeq = GEOSGeom_getCoordSeq_r( geosinit.ctxt, currentGeom );
2455 unsigned int currentCoordSeqSize;
2456 GEOSCoordSeq_getSize_r( geosinit.ctxt, currentCoordSeq, ¤tCoordSeqSize );
2457 if ( currentCoordSeqSize < 2 )
2461 double xBegin, xEnd, yBegin, yEnd;
2462 GEOSCoordSeq_getX_r( geosinit.ctxt, currentCoordSeq, 0, &xBegin );
2463 GEOSCoordSeq_getY_r( geosinit.ctxt, currentCoordSeq, 0, &yBegin );
2464 GEOSCoordSeq_getX_r( geosinit.ctxt, currentCoordSeq, currentCoordSeqSize - 1, &xEnd );
2465 GEOSCoordSeq_getY_r( geosinit.ctxt, currentCoordSeq, currentCoordSeqSize - 1, &yEnd );
2466 geos::unique_ptr beginCurrentGeomVertex = createGeosPointXY( xBegin, yBegin,
false, 0,
false, 0, 2, precision );
2467 geos::unique_ptr endCurrentGeomVertex = createGeosPointXY( xEnd, yEnd,
false, 0,
false, 0, 2, precision );
2470 int nEndpointsOnOriginalLine = 0;
2471 if ( pointContainedInLine( beginCurrentGeomVertex.get(), line ) == 1 )
2472 nEndpointsOnOriginalLine += 1;
2474 if ( pointContainedInLine( endCurrentGeomVertex.get(), line ) == 1 )
2475 nEndpointsOnOriginalLine += 1;
2478 int nEndpointsSameAsOriginalLine = 0;
2479 if ( GEOSEquals_r( geosinit.ctxt, beginCurrentGeomVertex.get(), beginLineVertex.get() ) == 1
2480 || GEOSEquals_r( geosinit.ctxt, beginCurrentGeomVertex.get(), endLineVertex.get() ) == 1 )
2481 nEndpointsSameAsOriginalLine += 1;
2483 if ( GEOSEquals_r( geosinit.ctxt, endCurrentGeomVertex.get(), beginLineVertex.get() ) == 1
2484 || GEOSEquals_r( geosinit.ctxt, endCurrentGeomVertex.get(), endLineVertex.get() ) == 1 )
2485 nEndpointsSameAsOriginalLine += 1;
2488 bool currentGeomOverlapsOriginalGeom =
false;
2489 bool currentGeomOverlapsReshapeLine =
false;
2490 if ( lineContainedInLine( currentGeom, line ) == 1 )
2491 currentGeomOverlapsOriginalGeom =
true;
2493 if ( lineContainedInLine( currentGeom, reshapeLineGeos ) == 1 )
2494 currentGeomOverlapsReshapeLine =
true;
2497 if ( !isRing && nEndpointsSameAsOriginalLine == 1 && nEndpointsOnOriginalLine == 2 && currentGeomOverlapsOriginalGeom )
2499 resultLineParts.push_back( GEOSGeom_clone_r( geosinit.ctxt, currentGeom ) );
2502 else if ( isRing && nEndpointsOnOriginalLine == 2 && currentGeomOverlapsOriginalGeom )
2504 probableParts.push_back( GEOSGeom_clone_r( geosinit.ctxt, currentGeom ) );
2506 else if ( nEndpointsOnOriginalLine == 2 && !currentGeomOverlapsOriginalGeom )
2508 resultLineParts.push_back( GEOSGeom_clone_r( geosinit.ctxt, currentGeom ) );
2510 else if ( nEndpointsSameAsOriginalLine == 2 && !currentGeomOverlapsOriginalGeom )
2512 resultLineParts.push_back( GEOSGeom_clone_r( geosinit.ctxt, currentGeom ) );
2514 else if ( currentGeomOverlapsOriginalGeom && currentGeomOverlapsReshapeLine )
2516 resultLineParts.push_back( GEOSGeom_clone_r( geosinit.ctxt, currentGeom ) );
2521 if ( isRing && !probableParts.isEmpty() )
2524 GEOSGeometry *currentGeom =
nullptr;
2525 double maxLength = -std::numeric_limits<double>::max();
2526 double currentLength = 0;
2527 for (
int i = 0; i < probableParts.size(); ++i )
2529 currentGeom = probableParts.at( i );
2530 GEOSLength_r( geosinit.ctxt, currentGeom, ¤tLength );
2531 if ( currentLength > maxLength )
2533 maxLength = currentLength;
2534 maxGeom.reset( currentGeom );
2538 GEOSGeom_destroy_r( geosinit.ctxt, currentGeom );
2541 resultLineParts.push_back( maxGeom.release() );
2545 if ( resultLineParts.empty() )
2548 if ( resultLineParts.size() == 1 )
2550 result.reset( resultLineParts[0] );
2554 GEOSGeometry **lineArray =
new GEOSGeometry*[resultLineParts.size()];
2555 for (
int i = 0; i < resultLineParts.size(); ++i )
2557 lineArray[i] = resultLineParts[i];
2561 geos::unique_ptr multiLineGeom( GEOSGeom_createCollection_r( geosinit.ctxt, GEOS_MULTILINESTRING, lineArray, resultLineParts.size() ) );
2562 delete [] lineArray;
2565 result.reset( GEOSLineMerge_r( geosinit.ctxt, multiLineGeom.get() ) );
2569 if ( GEOSGeomTypeId_r( geosinit.ctxt, result.get() ) != GEOS_LINESTRING )
2577 geos::unique_ptr QgsGeos::reshapePolygon(
const GEOSGeometry *polygon,
const GEOSGeometry *reshapeLineGeos,
double precision )
2580 int nIntersections = 0;
2581 int lastIntersectingRing = -2;
2582 const GEOSGeometry *lastIntersectingGeom =
nullptr;
2584 int nRings = GEOSGetNumInteriorRings_r( geosinit.ctxt, polygon );
2589 const GEOSGeometry *outerRing = GEOSGetExteriorRing_r( geosinit.ctxt, polygon );
2590 if ( GEOSIntersects_r( geosinit.ctxt, outerRing, reshapeLineGeos ) == 1 )
2593 lastIntersectingRing = -1;
2594 lastIntersectingGeom = outerRing;
2598 const GEOSGeometry **innerRings =
new const GEOSGeometry*[nRings];
2602 for (
int i = 0; i < nRings; ++i )
2604 innerRings[i] = GEOSGetInteriorRingN_r( geosinit.ctxt, polygon, i );
2605 if ( GEOSIntersects_r( geosinit.ctxt, innerRings[i], reshapeLineGeos ) == 1 )
2608 lastIntersectingRing = i;
2609 lastIntersectingGeom = innerRings[i];
2613 catch ( GEOSException & )
2618 if ( nIntersections != 1 )
2620 delete [] innerRings;
2625 geos::unique_ptr reshapeResult = reshapeLine( lastIntersectingGeom, reshapeLineGeos, precision );
2626 if ( !reshapeResult )
2628 delete [] innerRings;
2633 GEOSGeometry *newRing =
nullptr;
2634 const GEOSCoordSequence *reshapeSequence = GEOSGeom_getCoordSeq_r( geosinit.ctxt, reshapeResult.get() );
2635 GEOSCoordSequence *newCoordSequence = GEOSCoordSeq_clone_r( geosinit.ctxt, reshapeSequence );
2637 reshapeResult.reset();
2639 newRing = GEOSGeom_createLinearRing_r( geosinit.ctxt, newCoordSequence );
2642 delete [] innerRings;
2646 GEOSGeometry *newOuterRing =
nullptr;
2647 if ( lastIntersectingRing == -1 )
2648 newOuterRing = newRing;
2650 newOuterRing = GEOSGeom_clone_r( geosinit.ctxt, outerRing );
2653 QVector<GEOSGeometry *> ringList;
2656 GEOSGeometry *outerRingPoly = GEOSGeom_createPolygon_r( geosinit.ctxt, GEOSGeom_clone_r( geosinit.ctxt, newOuterRing ),
nullptr, 0 );
2657 if ( outerRingPoly )
2659 GEOSGeometry *currentRing =
nullptr;
2660 for (
int i = 0; i < nRings; ++i )
2662 if ( lastIntersectingRing == i )
2663 currentRing = newRing;
2665 currentRing = GEOSGeom_clone_r( geosinit.ctxt, innerRings[i] );
2668 if ( GEOSContains_r( geosinit.ctxt, outerRingPoly, currentRing ) == 1 )
2669 ringList.push_back( currentRing );
2671 GEOSGeom_destroy_r( geosinit.ctxt, currentRing );
2674 GEOSGeom_destroy_r( geosinit.ctxt, outerRingPoly );
2677 GEOSGeometry **newInnerRings =
new GEOSGeometry*[ringList.size()];
2678 for (
int i = 0; i < ringList.size(); ++i )
2679 newInnerRings[i] = ringList.at( i );
2681 delete [] innerRings;
2683 geos::unique_ptr reshapedPolygon( GEOSGeom_createPolygon_r( geosinit.ctxt, newOuterRing, newInnerRings, ringList.size() ) );
2684 delete[] newInnerRings;
2686 return reshapedPolygon;
2689 int QgsGeos::lineContainedInLine(
const GEOSGeometry *line1,
const GEOSGeometry *line2 )
2691 if ( !line1 || !line2 )
2696 double bufferDistance = std::pow( 10.0L, geomDigits( line2 ) - 11 );
2702 geos::unique_ptr intersectionGeom( GEOSIntersection_r( geosinit.ctxt, bufferGeom.get(), line1 ) );
2705 double intersectGeomLength;
2708 GEOSLength_r( geosinit.ctxt, intersectionGeom.get(), &intersectGeomLength );
2709 GEOSLength_r( geosinit.ctxt, line1, &line1Length );
2711 double intersectRatio = line1Length / intersectGeomLength;
2712 if ( intersectRatio > 0.9 && intersectRatio < 1.1 )
2718 int QgsGeos::pointContainedInLine(
const GEOSGeometry *point,
const GEOSGeometry *line )
2720 if ( !point || !line )
2723 double bufferDistance = std::pow( 10.0L, geomDigits( line ) - 11 );
2725 geos::unique_ptr lineBuffer( GEOSBuffer_r( geosinit.ctxt, line, bufferDistance, 8 ) );
2729 bool contained =
false;
2730 if ( GEOSContains_r( geosinit.ctxt, lineBuffer.get(), point ) == 1 )
2736 int QgsGeos::geomDigits(
const GEOSGeometry *geom )
2742 const GEOSGeometry *bBoxRing = GEOSGetExteriorRing_r( geosinit.ctxt, bbox.get() );
2746 const GEOSCoordSequence *bBoxCoordSeq = GEOSGeom_getCoordSeq_r( geosinit.ctxt, bBoxRing );
2748 if ( !bBoxCoordSeq )
2751 unsigned int nCoords = 0;
2752 if ( !GEOSCoordSeq_getSize_r( geosinit.ctxt, bBoxCoordSeq, &nCoords ) )
2756 for (
unsigned int i = 0; i < nCoords - 1; ++i )
2759 GEOSCoordSeq_getX_r( geosinit.ctxt, bBoxCoordSeq, i, &t );
2762 digits = std::ceil( std::log10( std::fabs( t ) ) );
2763 if ( digits > maxDigits )
2766 GEOSCoordSeq_getY_r( geosinit.ctxt, bBoxCoordSeq, i, &t );
2767 digits = std::ceil( std::log10( std::fabs( t ) ) );
2768 if ( digits > maxDigits )
2777 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 ...
bool isNull() const
Returns true if the geometry is null (ie, contains no underlying geometry accessible via geometry() )...
QgsGeos(const QgsAbstractGeometry *geometry, double precision=0)
GEOS geometry engine constructor.
void setXMaximum(double x)
Set the maximum x value.
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
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
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
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.