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;
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();
893 geos::unique_ptr polygons( GEOSPolygonize_r( geosinit()->ctxt, &noded, 1 ) );
894 if ( !polygons || numberOfGeometries( polygons.get() ) == 0 )
901 QVector<GEOSGeometry *> testedGeometries;
907 for (
int i = 0; i < numberOfGeometries( polygons.get() ); i++ )
909 const GEOSGeometry *polygon = GEOSGetGeometryN_r( geosinit()->ctxt, polygons.get(), i );
910 intersectGeometry.reset( GEOSIntersection_r( geosinit()->ctxt, mGeos.get(), polygon ) );
911 if ( !intersectGeometry )
913 QgsDebugMsg( QStringLiteral(
"intersectGeometry is nullptr" ) );
917 double intersectionArea;
918 GEOSArea_r( geosinit()->ctxt, intersectGeometry.get(), &intersectionArea );
921 GEOSArea_r( geosinit()->ctxt, polygon, &polygonArea );
923 const double areaRatio = intersectionArea / polygonArea;
924 if ( areaRatio > 0.99 && areaRatio < 1.01 )
925 testedGeometries << GEOSGeom_clone_r( geosinit()->ctxt, polygon );
928 int nGeometriesThis = numberOfGeometries( mGeos.get() );
929 if ( testedGeometries.empty() || testedGeometries.size() == nGeometriesThis )
932 for (
int i = 0; i < testedGeometries.size(); ++i )
934 GEOSGeom_destroy_r( geosinit()->ctxt, testedGeometries[i] );
939 mergeGeometriesMultiTypeSplit( testedGeometries );
942 for ( i = 0; i < testedGeometries.size() && GEOSisValid_r( geosinit()->ctxt, testedGeometries[i] ); ++i )
945 if ( i < testedGeometries.size() )
947 for ( i = 0; i < testedGeometries.size(); ++i )
948 GEOSGeom_destroy_r( geosinit()->ctxt, testedGeometries[i] );
953 for ( i = 0; i < testedGeometries.size(); ++i )
956 GEOSGeom_destroy_r( geosinit()->ctxt, testedGeometries[i] );
962 geos::unique_ptr QgsGeos::nodeGeometries(
const GEOSGeometry *splitLine,
const GEOSGeometry *geom )
964 if ( !splitLine || !geom )
968 if ( GEOSGeomTypeId_r( geosinit()->ctxt, geom ) == GEOS_POLYGON || GEOSGeomTypeId_r( geosinit()->ctxt, geom ) == GEOS_MULTIPOLYGON )
969 geometryBoundary.reset( GEOSBoundary_r( geosinit()->ctxt, geom ) );
971 geometryBoundary.reset( GEOSGeom_clone_r( geosinit()->ctxt, geom ) );
973 geos::unique_ptr splitLineClone( GEOSGeom_clone_r( geosinit()->ctxt, splitLine ) );
974 geos::unique_ptr unionGeometry( GEOSUnion_r( geosinit()->ctxt, splitLineClone.get(), geometryBoundary.get() ) );
976 return unionGeometry;
979 int QgsGeos::mergeGeometriesMultiTypeSplit( QVector<GEOSGeometry *> &splitResult )
const 985 int type = GEOSGeomTypeId_r( geosinit()->ctxt, mGeos.get() );
986 if ( type != GEOS_GEOMETRYCOLLECTION &&
987 type != GEOS_MULTILINESTRING &&
988 type != GEOS_MULTIPOLYGON &&
989 type != GEOS_MULTIPOINT )
992 QVector<GEOSGeometry *> copyList = splitResult;
996 QVector<GEOSGeometry *> unionGeom;
998 for (
int i = 0; i < copyList.size(); ++i )
1001 bool isPart =
false;
1002 for (
int j = 0; j < GEOSGetNumGeometries_r( geosinit()->ctxt, mGeos.get() ); j++ )
1004 if ( GEOSEquals_r( geosinit()->ctxt, copyList[i], GEOSGetGeometryN_r( geosinit()->ctxt, mGeos.get(), j ) ) )
1013 unionGeom << copyList[i];
1017 QVector<GEOSGeometry *> geomVector;
1018 geomVector << copyList[i];
1020 if ( type == GEOS_MULTILINESTRING )
1021 splitResult << createGeosCollection( GEOS_MULTILINESTRING, geomVector ).release();
1022 else if ( type == GEOS_MULTIPOLYGON )
1023 splitResult << createGeosCollection( GEOS_MULTIPOLYGON, geomVector ).release();
1025 GEOSGeom_destroy_r( geosinit()->ctxt, copyList[i] );
1030 if ( !unionGeom.isEmpty() )
1032 if ( type == GEOS_MULTILINESTRING )
1033 splitResult << createGeosCollection( GEOS_MULTILINESTRING, unionGeom ).release();
1034 else if ( type == GEOS_MULTIPOLYGON )
1035 splitResult << createGeosCollection( GEOS_MULTIPOLYGON, unionGeom ).release();
1045 geos::unique_ptr QgsGeos::createGeosCollection(
int typeId,
const QVector<GEOSGeometry *> &geoms )
1047 int nNullGeoms = geoms.count(
nullptr );
1048 int nNotNullGeoms = geoms.size() - nNullGeoms;
1050 GEOSGeometry **geomarr =
new GEOSGeometry*[ nNotNullGeoms ];
1057 QVector<GEOSGeometry *>::const_iterator geomIt = geoms.constBegin();
1058 for ( ; geomIt != geoms.constEnd(); ++geomIt )
1062 geomarr[i] = *geomIt;
1070 geom.reset( GEOSGeom_createCollection_r( geosinit()->ctxt, typeId, geomarr, nNotNullGeoms ) );
1072 catch ( GEOSException & )
1088 int nCoordDims = GEOSGeom_getCoordinateDimension_r( geosinit()->ctxt, geos );
1089 int nDims = GEOSGeom_getDimensions_r( geosinit()->ctxt, geos );
1090 bool hasZ = ( nCoordDims == 3 );
1091 bool hasM = ( ( nDims - nCoordDims ) == 1 );
1093 switch ( GEOSGeomTypeId_r( geosinit()->ctxt, geos ) )
1097 const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, geos );
1098 return std::unique_ptr<QgsAbstractGeometry>(
coordSeqPoint( cs, 0, hasZ, hasM ).
clone() );
1100 case GEOS_LINESTRING:
1102 return sequenceToLinestring( geos, hasZ, hasM );
1108 case GEOS_MULTIPOINT:
1110 std::unique_ptr< QgsMultiPoint > multiPoint(
new QgsMultiPoint() );
1111 int nParts = GEOSGetNumGeometries_r( geosinit()->ctxt, geos );
1112 multiPoint->reserve( nParts );
1113 for (
int i = 0; i < nParts; ++i )
1115 const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, GEOSGetGeometryN_r( geosinit()->ctxt, geos, i ) );
1118 multiPoint->addGeometry(
coordSeqPoint( cs, 0, hasZ, hasM ).clone() );
1121 return std::move( multiPoint );
1123 case GEOS_MULTILINESTRING:
1126 int nParts = GEOSGetNumGeometries_r( geosinit()->ctxt, geos );
1127 multiLineString->reserve( nParts );
1128 for (
int i = 0; i < nParts; ++i )
1130 std::unique_ptr< QgsLineString >line( sequenceToLinestring( GEOSGetGeometryN_r( geosinit()->ctxt, geos, i ), hasZ, hasM ) );
1133 multiLineString->addGeometry( line.release() );
1136 return std::move( multiLineString );
1138 case GEOS_MULTIPOLYGON:
1140 std::unique_ptr< QgsMultiPolygon > multiPolygon(
new QgsMultiPolygon() );
1142 int nParts = GEOSGetNumGeometries_r( geosinit()->ctxt, geos );
1143 multiPolygon->reserve( nParts );
1144 for (
int i = 0; i < nParts; ++i )
1146 std::unique_ptr< QgsPolygon > poly =
fromGeosPolygon( GEOSGetGeometryN_r( geosinit()->ctxt, geos, i ) );
1149 multiPolygon->addGeometry( poly.release() );
1152 return std::move( multiPolygon );
1154 case GEOS_GEOMETRYCOLLECTION:
1157 int nParts = GEOSGetNumGeometries_r( geosinit()->ctxt, geos );
1158 geomCollection->reserve( nParts );
1159 for (
int i = 0; i < nParts; ++i )
1161 std::unique_ptr< QgsAbstractGeometry > geom(
fromGeos( GEOSGetGeometryN_r( geosinit()->ctxt, geos, i ) ) );
1164 geomCollection->addGeometry( geom.release() );
1167 return std::move( geomCollection );
1175 if ( GEOSGeomTypeId_r( geosinit()->ctxt, geos ) != GEOS_POLYGON )
1180 int nCoordDims = GEOSGeom_getCoordinateDimension_r( geosinit()->ctxt, geos );
1181 int nDims = GEOSGeom_getDimensions_r( geosinit()->ctxt, geos );
1182 bool hasZ = ( nCoordDims == 3 );
1183 bool hasM = ( ( nDims - nCoordDims ) == 1 );
1185 std::unique_ptr< QgsPolygon > polygon(
new QgsPolygon() );
1187 const GEOSGeometry *ring = GEOSGetExteriorRing_r( geosinit()->ctxt, geos );
1190 polygon->setExteriorRing( sequenceToLinestring( ring, hasZ, hasM ).release() );
1193 QVector<QgsCurve *> interiorRings;
1194 const int ringCount = GEOSGetNumInteriorRings_r( geosinit()->ctxt, geos );
1195 interiorRings.reserve( ringCount );
1196 for (
int i = 0; i < ringCount; ++i )
1198 ring = GEOSGetInteriorRingN_r( geosinit()->ctxt, geos, i );
1201 interiorRings.push_back( sequenceToLinestring( ring, hasZ, hasM ).release() );
1204 polygon->setInteriorRings( interiorRings );
1209 std::unique_ptr<QgsLineString> QgsGeos::sequenceToLinestring(
const GEOSGeometry *
geos,
bool hasZ,
bool hasM )
1211 const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq_r( geosinit()->ctxt,
geos );
1212 unsigned int nPoints;
1213 GEOSCoordSeq_getSize_r( geosinit()->ctxt, cs, &nPoints );
1214 QVector< double > xOut( nPoints );
1215 QVector< double > yOut( nPoints );
1216 QVector< double > zOut;
1218 zOut.resize( nPoints );
1219 QVector< double > mOut;
1221 mOut.resize( nPoints );
1222 double *x = xOut.data();
1223 double *y = yOut.data();
1224 double *z = zOut.data();
1225 double *m = mOut.data();
1226 for (
unsigned int i = 0; i < nPoints; ++i )
1228 #if GEOS_VERSION_MAJOR>3 || GEOS_VERSION_MINOR>=8 1230 GEOSCoordSeq_getXYZ_r( geosinit()->ctxt, cs, i, x++, y++, z++ );
1232 GEOSCoordSeq_getXY_r( geosinit()->ctxt, cs, i, x++, y++ );
1234 GEOSCoordSeq_getX_r( geosinit()->ctxt, cs, i, x++ );
1235 GEOSCoordSeq_getY_r( geosinit()->ctxt, cs, i, y++ );
1238 GEOSCoordSeq_getZ_r( geosinit()->ctxt, cs, i, z++ );
1243 GEOSCoordSeq_getOrdinate_r( geosinit()->ctxt, cs, i, 3, m++ );
1246 std::unique_ptr< QgsLineString > line(
new QgsLineString( xOut, yOut, zOut, mOut ) );
1250 int QgsGeos::numberOfGeometries( GEOSGeometry *g )
1255 int geometryType = GEOSGeomTypeId_r( geosinit()->ctxt, g );
1256 if ( geometryType == GEOS_POINT || geometryType == GEOS_LINESTRING || geometryType == GEOS_LINEARRING
1257 || geometryType == GEOS_POLYGON )
1261 return GEOSGetNumGeometries_r( geosinit()->ctxt, g );
1274 #if GEOS_VERSION_MAJOR>3 || GEOS_VERSION_MINOR>=8 1276 GEOSCoordSeq_getXYZ_r( geosinit()->ctxt, cs, i, &x, &y, &z );
1278 GEOSCoordSeq_getXY_r( geosinit()->ctxt, cs, i, &x, &y );
1280 GEOSCoordSeq_getX_r( geosinit()->ctxt, cs, i, &x );
1281 GEOSCoordSeq_getY_r( geosinit()->ctxt, cs, i, &y );
1284 GEOSCoordSeq_getZ_r( geosinit()->ctxt, cs, i, &z );
1289 GEOSCoordSeq_getOrdinate_r( geosinit()->ctxt, cs, i, 3, &m );
1325 int geosType = GEOS_GEOMETRYCOLLECTION;
1332 geosType = GEOS_MULTIPOINT;
1336 geosType = GEOS_MULTILINESTRING;
1340 geosType = GEOS_MULTIPOLYGON;
1361 return createGeosCollection( geosType, geomVector );
1368 return createGeosPoint( static_cast<const QgsPoint *>( geom ), coordDims, precision );
1372 return createGeosLinestring( static_cast<const QgsLineString *>( geom ), precision );
1376 return createGeosPolygon( static_cast<const QgsPolygon *>( geom ), precision );
1388 std::unique_ptr<QgsAbstractGeometry> QgsGeos::overlay(
const QgsAbstractGeometry *geom, Overlay op, QString *errorMsg )
const 1390 if ( !mGeos || !geom )
1406 case OverlayIntersection:
1407 opGeom.reset( GEOSIntersection_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) );
1409 case OverlayDifference:
1410 opGeom.reset( GEOSDifference_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) );
1414 geos::unique_ptr unionGeometry( GEOSUnion_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) );
1416 if ( unionGeometry && GEOSGeomTypeId_r( geosinit()->ctxt, unionGeometry.get() ) == GEOS_MULTILINESTRING )
1418 geos::unique_ptr mergedLines( GEOSLineMerge_r( geosinit()->ctxt, unionGeometry.get() ) );
1421 unionGeometry = std::move( mergedLines );
1425 opGeom = std::move( unionGeometry );
1428 case OverlaySymDifference:
1429 opGeom.reset( GEOSSymDifference_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) );
1436 catch ( GEOSException &e )
1440 *errorMsg = e.what();
1446 bool QgsGeos::relation(
const QgsAbstractGeometry *geom, Relation r, QString *errorMsg )
const 1448 if ( !mGeos || !geom )
1459 bool result =
false;
1462 if ( mGeosPrepared )
1466 case RelationIntersects:
1467 result = ( GEOSPreparedIntersects_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1469 case RelationTouches:
1470 result = ( GEOSPreparedTouches_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1472 case RelationCrosses:
1473 result = ( GEOSPreparedCrosses_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1475 case RelationWithin:
1476 result = ( GEOSPreparedWithin_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1478 case RelationContains:
1479 result = ( GEOSPreparedContains_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1481 case RelationDisjoint:
1482 result = ( GEOSPreparedDisjoint_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1484 case RelationOverlaps:
1485 result = ( GEOSPreparedOverlaps_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1495 case RelationIntersects:
1496 result = ( GEOSIntersects_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1498 case RelationTouches:
1499 result = ( GEOSTouches_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1501 case RelationCrosses:
1502 result = ( GEOSCrosses_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1504 case RelationWithin:
1505 result = ( GEOSWithin_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1507 case RelationContains:
1508 result = ( GEOSContains_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1510 case RelationDisjoint:
1511 result = ( GEOSDisjoint_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1513 case RelationOverlaps:
1514 result = ( GEOSOverlaps_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1520 catch ( GEOSException &e )
1524 *errorMsg = e.what();
1542 geos.reset( GEOSBuffer_r( geosinit()->ctxt, mGeos.get(),
distance, segments ) );
1545 return fromGeos( geos.get() ).release();
1558 geos.reset( GEOSBufferWithStyle_r( geosinit()->ctxt, mGeos.get(),
distance, segments, endCapStyle, joinStyle, miterLimit ) );
1561 return fromGeos( geos.get() ).release();
1573 geos.reset( GEOSTopologyPreserveSimplify_r( geosinit()->ctxt, mGeos.get(), tolerance ) );
1576 return fromGeos( geos.get() ).release();
1588 geos.reset( GEOSInterpolate_r( geosinit()->ctxt, mGeos.get(),
distance ) );
1591 return fromGeos( geos.get() ).release();
1607 geos.reset( GEOSGetCentroid_r( geosinit()->ctxt, mGeos.get() ) );
1612 GEOSGeomGetX_r( geosinit()->ctxt, geos.get(), &x );
1613 GEOSGeomGetY_r( geosinit()->ctxt, geos.get(), &y );
1629 geos.reset( GEOSEnvelope_r( geosinit()->ctxt, mGeos.get() ) );
1632 return fromGeos( geos.get() ).release();
1648 geos.reset( GEOSPointOnSurface_r( geosinit()->ctxt, mGeos.get() ) );
1650 if ( !geos || GEOSisEmpty_r( geosinit()->ctxt, geos.get() ) != 0 )
1655 GEOSGeomGetX_r( geosinit()->ctxt, geos.get(), &x );
1656 GEOSGeomGetY_r( geosinit()->ctxt, geos.get(), &y );
1672 geos::unique_ptr cHull( GEOSConvexHull_r( geosinit()->ctxt, mGeos.get() ) );
1673 std::unique_ptr< QgsAbstractGeometry > cHullGeom =
fromGeos( cHull.get() );
1674 return cHullGeom.release();
1688 GEOSGeometry *g1 =
nullptr;
1690 char res = GEOSisValidDetail_r( geosinit()->ctxt, mGeos.get(), allowSelfTouchingHoles ? GEOSVALID_ALLOW_SELFTOUCHING_RING_FORMING_HOLE : 0, &r, &g1 );
1691 const bool invalid = res != 1;
1696 error = QString( r );
1697 GEOSFree_r( geosinit()->ctxt, r );
1700 if ( invalid && errorMsg )
1704 if ( translatedErrors.empty() )
1707 translatedErrors.insert( QStringLiteral(
"topology validation error" ), QObject::tr(
"Topology validation error",
"GEOS Error" ) );
1708 translatedErrors.insert( QStringLiteral(
"repeated point" ), QObject::tr(
"Repeated point",
"GEOS Error" ) );
1709 translatedErrors.insert( QStringLiteral(
"hole lies outside shell" ), QObject::tr(
"Hole lies outside shell",
"GEOS Error" ) );
1710 translatedErrors.insert( QStringLiteral(
"holes are nested" ), QObject::tr(
"Holes are nested",
"GEOS Error" ) );
1711 translatedErrors.insert( QStringLiteral(
"interior is disconnected" ), QObject::tr(
"Interior is disconnected",
"GEOS Error" ) );
1712 translatedErrors.insert( QStringLiteral(
"self-intersection" ), QObject::tr(
"Self-intersection",
"GEOS Error" ) );
1713 translatedErrors.insert( QStringLiteral(
"ring self-intersection" ), QObject::tr(
"Ring self-intersection",
"GEOS Error" ) );
1714 translatedErrors.insert( QStringLiteral(
"nested shells" ), QObject::tr(
"Nested shells",
"GEOS Error" ) );
1715 translatedErrors.insert( QStringLiteral(
"duplicate rings" ), QObject::tr(
"Duplicate rings",
"GEOS Error" ) );
1716 translatedErrors.insert( QStringLiteral(
"too few points in geometry component" ), QObject::tr(
"Too few points in geometry component",
"GEOS Error" ) );
1717 translatedErrors.insert( QStringLiteral(
"invalid coordinate" ), QObject::tr(
"Invalid coordinate",
"GEOS Error" ) );
1718 translatedErrors.insert( QStringLiteral(
"ring is not closed" ), QObject::tr(
"Ring is not closed",
"GEOS Error" ) );
1721 *errorMsg = translatedErrors.value( error.toLower(), error );
1723 if ( g1 && errorLoc )
1729 GEOSGeom_destroy_r( geosinit()->ctxt, g1 );
1739 if ( !mGeos || !geom )
1751 bool equal = GEOSEquals_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() );
1766 return GEOSisEmpty_r( geosinit()->ctxt, mGeos.get() );
1780 return GEOSisSimple_r( geosinit()->ctxt, mGeos.get() );
1785 GEOSCoordSequence *QgsGeos::createCoordinateSequence(
const QgsCurve *curve,
double precision,
bool forceClose )
1787 std::unique_ptr< QgsLineString > segmentized;
1793 line = segmentized.get();
1801 bool hasZ = line->
is3D();
1815 int numOutPoints = numPoints;
1816 if ( forceClose && ( line->
pointN( 0 ) != line->
pointN( numPoints - 1 ) ) )
1821 GEOSCoordSequence *coordSeq =
nullptr;
1824 coordSeq = GEOSCoordSeq_create_r( geosinit()->ctxt, numOutPoints, coordDims );
1827 QgsDebugMsg( QStringLiteral(
"GEOS Exception: Could not create coordinate sequence for %1 points in %2 dimensions" ).arg( numPoints ).arg( coordDims ) );
1831 const double *xData = line->
xData();
1832 const double *yData = line->
yData();
1833 const double *zData = hasZ ? line->
zData() :
nullptr;
1834 const double *mData = hasM ? line->
mData() :
nullptr;
1838 for (
int i = 0; i < numOutPoints; ++i )
1840 if ( i >= numPoints )
1843 xData = line->
xData();
1844 yData = line->
yData();
1845 zData = hasZ ? line->
zData() :
nullptr;
1846 mData = hasM ? line->
mData() :
nullptr;
1848 #if GEOS_VERSION_MAJOR>3 || GEOS_VERSION_MINOR>=8 1851 GEOSCoordSeq_setXYZ_r( geosinit()->ctxt, coordSeq, i, std::round( *xData++ /
precision ) *
precision, std::round( *yData++ / precision ) * precision, std::round( *zData++ / precision ) * precision );
1855 GEOSCoordSeq_setXY_r( geosinit()->ctxt, coordSeq, i, std::round( *xData++ /
precision ) *
precision, std::round( *yData++ / precision ) * precision );
1858 GEOSCoordSeq_setX_r( geosinit()->ctxt, coordSeq, i, std::round( *xData++ /
precision ) *
precision );
1859 GEOSCoordSeq_setY_r( geosinit()->ctxt, coordSeq, i, std::round( *yData++ / precision ) * precision );
1862 GEOSCoordSeq_setOrdinate_r( geosinit()->ctxt, coordSeq, i, 2, std::round( *zData++ / precision ) * precision );
1867 GEOSCoordSeq_setOrdinate_r( geosinit()->ctxt, coordSeq, i, 3, line->
mAt( *mData++ ) );
1873 for (
int i = 0; i < numOutPoints; ++i )
1875 if ( i >= numPoints )
1878 xData = line->
xData();
1879 yData = line->
yData();
1880 zData = hasZ ? line->
zData() :
nullptr;
1881 mData = hasM ? line->
mData() :
nullptr;
1883 #if GEOS_VERSION_MAJOR>3 || GEOS_VERSION_MINOR>=8 1886 GEOSCoordSeq_setXYZ_r( geosinit()->ctxt, coordSeq, i, *xData++, *yData++, *zData++ );
1890 GEOSCoordSeq_setXY_r( geosinit()->ctxt, coordSeq, i, *xData++, *yData++ );
1893 GEOSCoordSeq_setX_r( geosinit()->ctxt, coordSeq, i, *xData++ );
1894 GEOSCoordSeq_setY_r( geosinit()->ctxt, coordSeq, i, *yData++ );
1897 GEOSCoordSeq_setOrdinate_r( geosinit()->ctxt, coordSeq, i, 2, *zData++ );
1902 GEOSCoordSeq_setOrdinate_r( geosinit()->ctxt, coordSeq, i, 3, *mData++ );
1921 geos::unique_ptr QgsGeos::createGeosPointXY(
double x,
double y,
bool hasZ,
double z,
bool hasM,
double m,
int coordDims,
double precision )
1929 #if GEOS_VERSION_MAJOR>3 || GEOS_VERSION_MINOR>=8 1930 if ( coordDims == 2 )
1933 if ( precision > 0. )
1934 geosPoint.reset( GEOSGeom_createPointFromXY_r( geosinit()->ctxt, std::round( x / precision ) * precision, std::round( y / precision ) * precision ) );
1936 geosPoint.reset( GEOSGeom_createPointFromXY_r( geosinit()->ctxt, x, y ) );
1941 GEOSCoordSequence *coordSeq = GEOSCoordSeq_create_r( geosinit()->ctxt, 1, coordDims );
1944 QgsDebugMsg( QStringLiteral(
"GEOS Exception: Could not create coordinate sequence for point with %1 dimensions" ).arg( coordDims ) );
1947 if ( precision > 0. )
1949 GEOSCoordSeq_setX_r( geosinit()->ctxt, coordSeq, 0, std::round( x / precision ) * precision );
1950 GEOSCoordSeq_setY_r( geosinit()->ctxt, coordSeq, 0, std::round( y / precision ) * precision );
1953 GEOSCoordSeq_setOrdinate_r( geosinit()->ctxt, coordSeq, 0, 2, std::round( z / precision ) * precision );
1958 GEOSCoordSeq_setX_r( geosinit()->ctxt, coordSeq, 0, x );
1959 GEOSCoordSeq_setY_r( geosinit()->ctxt, coordSeq, 0, y );
1962 GEOSCoordSeq_setOrdinate_r( geosinit()->ctxt, coordSeq, 0, 2, z );
1965 #if 0 //disabled until geos supports m-coordinates 1968 GEOSCoordSeq_setOrdinate_r( geosinit()->ctxt, coordSeq, 0, 3, m );
1971 geosPoint.reset( GEOSGeom_createPoint_r( geosinit()->ctxt, coordSeq ) );
1983 GEOSCoordSequence *coordSeq = createCoordinateSequence( c, precision );
1990 geosGeom.reset( GEOSGeom_createLineString_r( geosinit()->ctxt, coordSeq ) );
2003 if ( !exteriorRing )
2011 geos::unique_ptr exteriorRingGeos( GEOSGeom_createLinearRing_r( geosinit()->ctxt, createCoordinateSequence( exteriorRing, precision,
true ) ) );
2014 GEOSGeometry **holes =
nullptr;
2017 holes =
new GEOSGeometry*[ nHoles ];
2020 for (
int i = 0; i < nHoles; ++i )
2023 holes[i] = GEOSGeom_createLinearRing_r( geosinit()->ctxt, createCoordinateSequence( interiorRing, precision,
true ) );
2025 geosPolygon.reset( GEOSGeom_createPolygon_r( geosinit()->ctxt, exteriorRingGeos.release(), holes, nHoles ) );
2041 offset.reset( GEOSOffsetCurve_r( geosinit()->ctxt, mGeos.get(),
distance, segments, joinStyle, miterLimit ) );
2044 std::unique_ptr< QgsAbstractGeometry > offsetGeom =
fromGeos( offset.get() );
2045 return offsetGeom.release();
2059 GEOSBufferParams_setSingleSided_r( geosinit()->ctxt, bp.get(), 1 );
2060 GEOSBufferParams_setQuadrantSegments_r( geosinit()->ctxt, bp.get(), segments );
2061 GEOSBufferParams_setJoinStyle_r( geosinit()->ctxt, bp.get(), joinStyle );
2062 GEOSBufferParams_setMitreLimit_r( geosinit()->ctxt, bp.get(), miterLimit );
2068 geos.reset( GEOSBufferWithParams_r( geosinit()->ctxt, mGeos.get(), bp.get(),
distance ) );
2088 geos::unique_ptr reshapeLineGeos = createGeosLinestring( &reshapeWithLine, mPrecision );
2091 int numGeoms = GEOSGetNumGeometries_r( geosinit()->ctxt, mGeos.get() );
2092 if ( numGeoms == -1 )
2101 bool isMultiGeom =
false;
2102 int geosTypeId = GEOSGeomTypeId_r( geosinit()->ctxt, mGeos.get() );
2103 if ( geosTypeId == GEOS_MULTILINESTRING || geosTypeId == GEOS_MULTIPOLYGON )
2113 reshapedGeometry = reshapeLine( mGeos.get(), reshapeLineGeos.get(), mPrecision );
2117 reshapedGeometry = reshapePolygon( mGeos.get(), reshapeLineGeos.get(), mPrecision );
2122 std::unique_ptr< QgsAbstractGeometry > reshapeResult =
fromGeos( reshapedGeometry.get() );
2123 return reshapeResult;
2130 bool reshapeTookPlace =
false;
2133 GEOSGeometry **newGeoms =
new GEOSGeometry*[numGeoms];
2135 for (
int i = 0; i < numGeoms; ++i )
2138 currentReshapeGeometry = reshapeLine( GEOSGetGeometryN_r( geosinit()->ctxt, mGeos.get(), i ), reshapeLineGeos.get(), mPrecision );
2140 currentReshapeGeometry = reshapePolygon( GEOSGetGeometryN_r( geosinit()->ctxt, mGeos.get(), i ), reshapeLineGeos.get(), mPrecision );
2142 if ( currentReshapeGeometry )
2144 newGeoms[i] = currentReshapeGeometry.release();
2145 reshapeTookPlace =
true;
2149 newGeoms[i] = GEOSGeom_clone_r( geosinit()->ctxt, GEOSGetGeometryN_r( geosinit()->ctxt, mGeos.get(), i ) );
2156 newMultiGeom.reset( GEOSGeom_createCollection_r( geosinit()->ctxt, GEOS_MULTILINESTRING, newGeoms, numGeoms ) );
2160 newMultiGeom.reset( GEOSGeom_createCollection_r( geosinit()->ctxt, GEOS_MULTIPOLYGON, newGeoms, numGeoms ) );
2164 if ( !newMultiGeom )
2170 if ( reshapeTookPlace )
2174 std::unique_ptr< QgsAbstractGeometry > reshapedMultiGeom =
fromGeos( newMultiGeom.get() );
2175 return reshapedMultiGeom;
2197 if ( GEOSGeomTypeId_r( geosinit()->ctxt, mGeos.get() ) != GEOS_MULTILINESTRING )
2203 geos.reset( GEOSLineMerge_r( geosinit()->ctxt, mGeos.get() ) );
2211 if ( !mGeos || other.
isNull() )
2228 ( void )GEOSCoordSeq_getX_r( geosinit()->ctxt, nearestCoord.get(), 0, &nx );
2229 ( void )GEOSCoordSeq_getY_r( geosinit()->ctxt, nearestCoord.get(), 0, &ny );
2231 catch ( GEOSException &e )
2235 *errorMsg = e.what();
2245 if ( !mGeos || other.
isNull() )
2264 ( void )GEOSCoordSeq_getX_r( geosinit()->ctxt, nearestCoord.get(), 0, &nx1 );
2265 ( void )GEOSCoordSeq_getY_r( geosinit()->ctxt, nearestCoord.get(), 0, &ny1 );
2266 ( void )GEOSCoordSeq_getX_r( geosinit()->ctxt, nearestCoord.get(), 1, &nx2 );
2267 ( void )GEOSCoordSeq_getY_r( geosinit()->ctxt, nearestCoord.get(), 1, &ny2 );
2269 catch ( GEOSException &e )
2273 *errorMsg = e.what();
2300 distance = GEOSProject_r( geosinit()->ctxt, mGeos.get(), otherGeom.get() );
2302 catch ( GEOSException &e )
2306 *errorMsg = e.what();
2316 GEOSGeometry **
const lineGeosGeometries =
new GEOSGeometry*[ geometries.size()];
2323 lineGeosGeometries[validLines] = l.release();
2330 geos::unique_ptr result( GEOSPolygonize_r( geosinit()->ctxt, lineGeosGeometries, validLines ) );
2331 for (
int i = 0; i < validLines; ++i )
2333 GEOSGeom_destroy_r( geosinit()->ctxt, lineGeosGeometries[i] );
2335 delete[] lineGeosGeometries;
2338 catch ( GEOSException &e )
2342 *errorMsg = e.what();
2344 for (
int i = 0; i < validLines; ++i )
2346 GEOSGeom_destroy_r( geosinit()->ctxt, lineGeosGeometries[i] );
2348 delete[] lineGeosGeometries;
2363 extentGeosGeom =
asGeos( extent, mPrecision );
2364 if ( !extentGeosGeom )
2373 geos.reset( GEOSVoronoiDiagram_r( geosinit()->ctxt, mGeos.get(), extentGeosGeom.get(), tolerance, edgesOnly ) );
2375 if ( !geos || GEOSisEmpty_r( geosinit()->ctxt, geos.get() ) != 0 )
2395 geos.reset( GEOSDelaunayTriangulation_r( geosinit()->ctxt, mGeos.get(), tolerance, edgesOnly ) );
2397 if ( !geos || GEOSisEmpty_r( geosinit()->ctxt, geos.get() ) != 0 )
2409 static bool _linestringEndpoints(
const GEOSGeometry *linestring,
double &x1,
double &y1,
double &x2,
double &y2 )
2411 const GEOSCoordSequence *coordSeq = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, linestring );
2415 unsigned int coordSeqSize;
2416 if ( GEOSCoordSeq_getSize_r( geosinit()->ctxt, coordSeq, &coordSeqSize ) == 0 )
2419 if ( coordSeqSize < 2 )
2422 GEOSCoordSeq_getX_r( geosinit()->ctxt, coordSeq, 0, &x1 );
2423 GEOSCoordSeq_getY_r( geosinit()->ctxt, coordSeq, 0, &y1 );
2424 GEOSCoordSeq_getX_r( geosinit()->ctxt, coordSeq, coordSeqSize - 1, &x2 );
2425 GEOSCoordSeq_getY_r( geosinit()->ctxt, coordSeq, coordSeqSize - 1, &y2 );
2431 static geos::unique_ptr _mergeLinestrings(
const GEOSGeometry *line1,
const GEOSGeometry *line2,
const QgsPointXY &intersectionPoint )
2433 double x1, y1, x2, y2;
2434 if ( !_linestringEndpoints( line1, x1, y1, x2, y2 ) )
2437 double rx1, ry1, rx2, ry2;
2438 if ( !_linestringEndpoints( line2, rx1, ry1, rx2, ry2 ) )
2441 bool intersectionAtOrigLineEndpoint =
2442 ( intersectionPoint.
x() == x1 && intersectionPoint.
y() == y1 ) !=
2443 ( intersectionPoint.
x() == x2 && intersectionPoint.
y() == y2 );
2444 bool intersectionAtReshapeLineEndpoint =
2445 ( intersectionPoint.
x() == rx1 && intersectionPoint.
y() == ry1 ) ||
2446 ( intersectionPoint.
x() == rx2 && intersectionPoint.
y() == ry2 );
2449 if ( intersectionAtOrigLineEndpoint && intersectionAtReshapeLineEndpoint )
2453 GEOSGeometry *geoms[2] = { g1.release(), g2.release() };
2454 geos::unique_ptr multiGeom( GEOSGeom_createCollection_r( geosinit()->ctxt, GEOS_MULTILINESTRING, geoms, 2 ) );
2455 geos::unique_ptr res( GEOSLineMerge_r( geosinit()->ctxt, multiGeom.get() ) );
2463 geos::unique_ptr QgsGeos::reshapeLine(
const GEOSGeometry *line,
const GEOSGeometry *reshapeLineGeos,
double precision )
2465 if ( !line || !reshapeLineGeos )
2468 bool atLeastTwoIntersections =
false;
2469 bool oneIntersection =
false;
2475 geos::unique_ptr intersectGeom( GEOSIntersection_r( geosinit()->ctxt, line, reshapeLineGeos ) );
2476 if ( intersectGeom )
2478 atLeastTwoIntersections = ( GEOSGeomTypeId_r( geosinit()->ctxt, intersectGeom.get() ) == GEOS_MULTIPOINT
2479 && GEOSGetNumGeometries_r( geosinit()->ctxt, intersectGeom.get() ) > 1 );
2481 if ( GEOSGeomTypeId_r( geosinit()->ctxt, intersectGeom.get() ) == GEOS_POINT )
2483 const GEOSCoordSequence *intersectionCoordSeq = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, intersectGeom.get() );
2485 GEOSCoordSeq_getX_r( geosinit()->ctxt, intersectionCoordSeq, 0, &xi );
2486 GEOSCoordSeq_getY_r( geosinit()->ctxt, intersectionCoordSeq, 0, &yi );
2487 oneIntersection =
true;
2492 catch ( GEOSException & )
2494 atLeastTwoIntersections =
false;
2498 if ( oneIntersection )
2499 return _mergeLinestrings( line, reshapeLineGeos, oneIntersectionPoint );
2501 if ( !atLeastTwoIntersections )
2505 double x1, y1, x2, y2;
2506 if ( !_linestringEndpoints( line, x1, y1, x2, y2 ) )
2509 geos::unique_ptr beginLineVertex = createGeosPointXY( x1, y1,
false, 0,
false, 0, 2, precision );
2510 geos::unique_ptr endLineVertex = createGeosPointXY( x2, y2,
false, 0,
false, 0, 2, precision );
2512 bool isRing =
false;
2513 if ( GEOSGeomTypeId_r( geosinit()->ctxt, line ) == GEOS_LINEARRING
2514 || GEOSEquals_r( geosinit()->ctxt, beginLineVertex.get(), endLineVertex.get() ) == 1 )
2519 if ( !nodedGeometry )
2525 geos::unique_ptr mergedLines( GEOSLineMerge_r( geosinit()->ctxt, nodedGeometry.get() ) );
2531 int numMergedLines = GEOSGetNumGeometries_r( geosinit()->ctxt, mergedLines.get() );
2532 if ( numMergedLines < 2 )
2534 if ( numMergedLines == 1 )
2536 geos::unique_ptr result( GEOSGeom_clone_r( geosinit()->ctxt, reshapeLineGeos ) );
2543 QVector<GEOSGeometry *> resultLineParts;
2544 QVector<GEOSGeometry *> probableParts;
2546 for (
int i = 0; i < numMergedLines; ++i )
2548 const GEOSGeometry *currentGeom =
nullptr;
2550 currentGeom = GEOSGetGeometryN_r( geosinit()->ctxt, mergedLines.get(), i );
2551 const GEOSCoordSequence *currentCoordSeq = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, currentGeom );
2552 unsigned int currentCoordSeqSize;
2553 GEOSCoordSeq_getSize_r( geosinit()->ctxt, currentCoordSeq, ¤tCoordSeqSize );
2554 if ( currentCoordSeqSize < 2 )
2558 double xBegin, xEnd, yBegin, yEnd;
2559 GEOSCoordSeq_getX_r( geosinit()->ctxt, currentCoordSeq, 0, &xBegin );
2560 GEOSCoordSeq_getY_r( geosinit()->ctxt, currentCoordSeq, 0, &yBegin );
2561 GEOSCoordSeq_getX_r( geosinit()->ctxt, currentCoordSeq, currentCoordSeqSize - 1, &xEnd );
2562 GEOSCoordSeq_getY_r( geosinit()->ctxt, currentCoordSeq, currentCoordSeqSize - 1, &yEnd );
2563 geos::unique_ptr beginCurrentGeomVertex = createGeosPointXY( xBegin, yBegin,
false, 0,
false, 0, 2, precision );
2564 geos::unique_ptr endCurrentGeomVertex = createGeosPointXY( xEnd, yEnd,
false, 0,
false, 0, 2, precision );
2567 int nEndpointsOnOriginalLine = 0;
2568 if ( pointContainedInLine( beginCurrentGeomVertex.get(), line ) == 1 )
2569 nEndpointsOnOriginalLine += 1;
2571 if ( pointContainedInLine( endCurrentGeomVertex.get(), line ) == 1 )
2572 nEndpointsOnOriginalLine += 1;
2575 int nEndpointsSameAsOriginalLine = 0;
2576 if ( GEOSEquals_r( geosinit()->ctxt, beginCurrentGeomVertex.get(), beginLineVertex.get() ) == 1
2577 || GEOSEquals_r( geosinit()->ctxt, beginCurrentGeomVertex.get(), endLineVertex.get() ) == 1 )
2578 nEndpointsSameAsOriginalLine += 1;
2580 if ( GEOSEquals_r( geosinit()->ctxt, endCurrentGeomVertex.get(), beginLineVertex.get() ) == 1
2581 || GEOSEquals_r( geosinit()->ctxt, endCurrentGeomVertex.get(), endLineVertex.get() ) == 1 )
2582 nEndpointsSameAsOriginalLine += 1;
2585 bool currentGeomOverlapsOriginalGeom =
false;
2586 bool currentGeomOverlapsReshapeLine =
false;
2587 if ( lineContainedInLine( currentGeom, line ) == 1 )
2588 currentGeomOverlapsOriginalGeom =
true;
2590 if ( lineContainedInLine( currentGeom, reshapeLineGeos ) == 1 )
2591 currentGeomOverlapsReshapeLine =
true;
2594 if ( !isRing && nEndpointsSameAsOriginalLine == 1 && nEndpointsOnOriginalLine == 2 && currentGeomOverlapsOriginalGeom )
2596 resultLineParts.push_back( GEOSGeom_clone_r( geosinit()->ctxt, currentGeom ) );
2599 else if ( isRing && nEndpointsOnOriginalLine == 2 && currentGeomOverlapsOriginalGeom )
2601 probableParts.push_back( GEOSGeom_clone_r( geosinit()->ctxt, currentGeom ) );
2603 else if ( nEndpointsOnOriginalLine == 2 && !currentGeomOverlapsOriginalGeom )
2605 resultLineParts.push_back( GEOSGeom_clone_r( geosinit()->ctxt, currentGeom ) );
2607 else if ( nEndpointsSameAsOriginalLine == 2 && !currentGeomOverlapsOriginalGeom )
2609 resultLineParts.push_back( GEOSGeom_clone_r( geosinit()->ctxt, currentGeom ) );
2611 else if ( currentGeomOverlapsOriginalGeom && currentGeomOverlapsReshapeLine )
2613 resultLineParts.push_back( GEOSGeom_clone_r( geosinit()->ctxt, currentGeom ) );
2618 if ( isRing && !probableParts.isEmpty() )
2621 GEOSGeometry *currentGeom =
nullptr;
2622 double maxLength = -std::numeric_limits<double>::max();
2623 double currentLength = 0;
2624 for (
int i = 0; i < probableParts.size(); ++i )
2626 currentGeom = probableParts.at( i );
2627 GEOSLength_r( geosinit()->ctxt, currentGeom, ¤tLength );
2628 if ( currentLength > maxLength )
2630 maxLength = currentLength;
2631 maxGeom.reset( currentGeom );
2635 GEOSGeom_destroy_r( geosinit()->ctxt, currentGeom );
2638 resultLineParts.push_back( maxGeom.release() );
2642 if ( resultLineParts.empty() )
2645 if ( resultLineParts.size() == 1 )
2647 result.reset( resultLineParts[0] );
2651 GEOSGeometry **lineArray =
new GEOSGeometry*[resultLineParts.size()];
2652 for (
int i = 0; i < resultLineParts.size(); ++i )
2654 lineArray[i] = resultLineParts[i];
2658 geos::unique_ptr multiLineGeom( GEOSGeom_createCollection_r( geosinit()->ctxt, GEOS_MULTILINESTRING, lineArray, resultLineParts.size() ) );
2659 delete [] lineArray;
2662 result.reset( GEOSLineMerge_r( geosinit()->ctxt, multiLineGeom.get() ) );
2666 if ( GEOSGeomTypeId_r( geosinit()->ctxt, result.get() ) != GEOS_LINESTRING )
2674 geos::unique_ptr QgsGeos::reshapePolygon(
const GEOSGeometry *polygon,
const GEOSGeometry *reshapeLineGeos,
double precision )
2677 int nIntersections = 0;
2678 int lastIntersectingRing = -2;
2679 const GEOSGeometry *lastIntersectingGeom =
nullptr;
2681 int nRings = GEOSGetNumInteriorRings_r( geosinit()->ctxt, polygon );
2686 const GEOSGeometry *outerRing = GEOSGetExteriorRing_r( geosinit()->ctxt, polygon );
2687 if ( GEOSIntersects_r( geosinit()->ctxt, outerRing, reshapeLineGeos ) == 1 )
2690 lastIntersectingRing = -1;
2691 lastIntersectingGeom = outerRing;
2695 const GEOSGeometry **innerRings =
new const GEOSGeometry*[nRings];
2699 for (
int i = 0; i < nRings; ++i )
2701 innerRings[i] = GEOSGetInteriorRingN_r( geosinit()->ctxt, polygon, i );
2702 if ( GEOSIntersects_r( geosinit()->ctxt, innerRings[i], reshapeLineGeos ) == 1 )
2705 lastIntersectingRing = i;
2706 lastIntersectingGeom = innerRings[i];
2710 catch ( GEOSException & )
2715 if ( nIntersections != 1 )
2717 delete [] innerRings;
2722 geos::unique_ptr reshapeResult = reshapeLine( lastIntersectingGeom, reshapeLineGeos, precision );
2723 if ( !reshapeResult )
2725 delete [] innerRings;
2730 GEOSGeometry *newRing =
nullptr;
2731 const GEOSCoordSequence *reshapeSequence = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, reshapeResult.get() );
2732 GEOSCoordSequence *newCoordSequence = GEOSCoordSeq_clone_r( geosinit()->ctxt, reshapeSequence );
2734 reshapeResult.reset();
2736 newRing = GEOSGeom_createLinearRing_r( geosinit()->ctxt, newCoordSequence );
2739 delete [] innerRings;
2743 GEOSGeometry *newOuterRing =
nullptr;
2744 if ( lastIntersectingRing == -1 )
2745 newOuterRing = newRing;
2747 newOuterRing = GEOSGeom_clone_r( geosinit()->ctxt, outerRing );
2750 QVector<GEOSGeometry *> ringList;
2753 GEOSGeometry *outerRingPoly = GEOSGeom_createPolygon_r( geosinit()->ctxt, GEOSGeom_clone_r( geosinit()->ctxt, newOuterRing ),
nullptr, 0 );
2754 if ( outerRingPoly )
2756 GEOSGeometry *currentRing =
nullptr;
2757 for (
int i = 0; i < nRings; ++i )
2759 if ( lastIntersectingRing == i )
2760 currentRing = newRing;
2762 currentRing = GEOSGeom_clone_r( geosinit()->ctxt, innerRings[i] );
2765 if ( GEOSContains_r( geosinit()->ctxt, outerRingPoly, currentRing ) == 1 )
2766 ringList.push_back( currentRing );
2768 GEOSGeom_destroy_r( geosinit()->ctxt, currentRing );
2771 GEOSGeom_destroy_r( geosinit()->ctxt, outerRingPoly );
2774 GEOSGeometry **newInnerRings =
new GEOSGeometry*[ringList.size()];
2775 for (
int i = 0; i < ringList.size(); ++i )
2776 newInnerRings[i] = ringList.at( i );
2778 delete [] innerRings;
2780 geos::unique_ptr reshapedPolygon( GEOSGeom_createPolygon_r( geosinit()->ctxt, newOuterRing, newInnerRings, ringList.size() ) );
2781 delete[] newInnerRings;
2783 return reshapedPolygon;
2786 int QgsGeos::lineContainedInLine(
const GEOSGeometry *line1,
const GEOSGeometry *line2 )
2788 if ( !line1 || !line2 )
2793 double bufferDistance = std::pow( 10.0L, geomDigits( line2 ) - 11 );
2799 geos::unique_ptr intersectionGeom( GEOSIntersection_r( geosinit()->ctxt, bufferGeom.get(), line1 ) );
2802 double intersectGeomLength;
2805 GEOSLength_r( geosinit()->ctxt, intersectionGeom.get(), &intersectGeomLength );
2806 GEOSLength_r( geosinit()->ctxt, line1, &line1Length );
2808 double intersectRatio = line1Length / intersectGeomLength;
2809 if ( intersectRatio > 0.9 && intersectRatio < 1.1 )
2815 int QgsGeos::pointContainedInLine(
const GEOSGeometry *point,
const GEOSGeometry *line )
2817 if ( !point || !line )
2820 double bufferDistance = std::pow( 10.0L, geomDigits( line ) - 11 );
2822 geos::unique_ptr lineBuffer( GEOSBuffer_r( geosinit()->ctxt, line, bufferDistance, 8 ) );
2826 bool contained =
false;
2827 if ( GEOSContains_r( geosinit()->ctxt, lineBuffer.get(), point ) == 1 )
2833 int QgsGeos::geomDigits(
const GEOSGeometry *geom )
2839 const GEOSGeometry *bBoxRing = GEOSGetExteriorRing_r( geosinit()->ctxt, bbox.get() );
2843 const GEOSCoordSequence *bBoxCoordSeq = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, bBoxRing );
2845 if ( !bBoxCoordSeq )
2848 unsigned int nCoords = 0;
2849 if ( !GEOSCoordSeq_getSize_r( geosinit()->ctxt, bBoxCoordSeq, &nCoords ) )
2853 for (
unsigned int i = 0; i < nCoords - 1; ++i )
2856 GEOSCoordSeq_getX_r( geosinit()->ctxt, bBoxCoordSeq, i, &t );
2859 digits = std::ceil( std::log10( std::fabs( t ) ) );
2860 if ( digits > maxDigits )
2863 GEOSCoordSeq_getY_r( geosinit()->ctxt, bBoxCoordSeq, i, &t );
2864 digits = std::ceil( std::log10( std::fabs( t ) ) );
2865 if ( digits > maxDigits )
2874 return geosinit()->ctxt;
bool isMeasure() const
Returns true if the geometry contains m values.
A rectangle specified with double values.
bool disjoint(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Checks if geom is disjoint from this.
QgsAbstractGeometry * intersection(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Calculate the intersection of this and geom.
QgsGeometry mergeLines(QString *errorMsg=nullptr) const
Merges any connected lines in a LineString/MultiLineString geometry and converts them to single line ...
QgsGeos(const QgsAbstractGeometry *geometry, double precision=0)
GEOS geometry engine constructor.
void setXMaximum(double x)
Set the maximum x value.
const double * mData() const
Returns a const pointer to the m vertex data, or nullptr if the linestring does not have m values...
Multi point geometry collection.
static bool isMultiType(Type type)
Returns true if the WKB type is a multi type.
The source geometry is not multi.
bool isEmpty(QString *errorMsg=nullptr) const override
QgsPoint * pointOnSurface(QString *errorMsg=nullptr) const override
Calculate a point that is guaranteed to be on the surface of this.
QgsGeometry shortestLine(const QgsGeometry &other, QString *errorMsg=nullptr) const
Returns the shortest line joining this geometry to the other geometry.
double area(QString *errorMsg=nullptr) const override
A class to represent a 2D point.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
const QgsAbstractGeometry * mGeometry
const QgsCurve * interiorRing(int i) const
Retrieves an interior ring from the curve polygon.
QgsAbstractGeometry * buffer(double distance, int segments, QString *errorMsg=nullptr) const override
bool isValid(QString *errorMsg=nullptr, bool allowSelfTouchingHoles=false, QgsGeometry *errorLoc=nullptr) const override
Returns true if the geometry is valid.
Multi line string geometry collection.
Curve polygon geometry type.
static std::unique_ptr< QgsGeometryCollection > createCollectionOfType(QgsWkbTypes::Type type)
Returns a new geometry collection matching a specified WKB type.
double length(QString *errorMsg=nullptr) const override
A geometry is the spatial representation of a feature.
bool isEqual(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Checks if this is equal to geom.
QgsGeometry closestPoint(const QgsGeometry &other, QString *errorMsg=nullptr) const
Returns the closest point on the geometry to the other geometry.
virtual QgsRectangle boundingBox() const =0
Returns the minimal bounding box for the geometry.
static QgsGeometry::OperationResult addPart(QgsGeometry &geometry, GEOSGeometry *newPart)
Adds a new island polygon to a multipolygon feature.
void CORE_EXPORT operator()(GEOSGeometry *geom)
Destroys the GEOS geometry geom, using the static QGIS geos context.
virtual QgsAbstractGeometry * clone() const =0
Clones the geometry by performing a deep copy.
QMap< QString, QString > QgsStringMap
OperationResult
Success or failure of a geometry operation.
std::unique_ptr< QgsAbstractGeometry > singleSidedBuffer(double distance, int segments, int side, int joinStyle, double miterLimit, QString *errorMsg=nullptr) const
Returns a single sided buffer for a geometry.
static GEOSContextHandle_t getGEOSHandler()
int numPoints() const override
Returns the number of points in the curve.
QgsAbstractGeometry * interpolate(double distance, QString *errorMsg=nullptr) const override
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
bool within(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Checks if geom is within this.
const double * xData() const
Returns a const pointer to the x vertex data.
#define CATCH_GEOS_WITH_ERRMSG(r)
int numInteriorRings() const
Returns the number of interior rings contained with the curve polygon.
Nothing happened, without any error.
Type
The WKB type describes the number of dimensions a geometry has.
QgsAbstractGeometry * envelope(QString *errorMsg=nullptr) const override
std::unique_ptr< QgsAbstractGeometry > reshapeGeometry(const QgsLineString &reshapeWithLine, EngineOperationResult *errorCode, QString *errorMsg=nullptr) const
Reshapes the geometry using a line.
static std::unique_ptr< QgsAbstractGeometry > fromGeos(const GEOSGeometry *geos)
Create a geometry from a GEOSGeometry.
void addVertex(const QgsPoint &pt)
Adds a new vertex to the end of the line string.
bool touches(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Checks if geom touches this.
Q_GLOBAL_STATIC(QReadWriteLock, sDefinitionCacheLock)
bool isEmpty() const
Returns true if the rectangle is empty.
double lineLocatePoint(const QgsPoint &point, QString *errorMsg=nullptr) const
Returns a distance representing the location along this linestring of the closest point on this lines...
void prepareGeometry() override
Prepares the geometry, so that subsequent calls to spatial relation methods are much faster...
double width() const
Returns the width of the rectangle.
double mAt(int index) const
Returns the m value of the specified node in the line string.
void setYMinimum(double y)
Set the minimum y value.
std::unique_ptr< GEOSGeometry, GeosDeleter > unique_ptr
Scoped GEOS pointer.
double yAt(int index) const override
Returns the y-coordinate of the specified node in the line string.
static GeometryType geometryType(Type type)
Returns the geometry type for a WKB type, e.g., both MultiPolygon and CurvePolygon would have a Polyg...
double hausdorffDistanceDensify(const QgsAbstractGeometry *geom, double densifyFraction, QString *errorMsg=nullptr) const
Returns the Hausdorff distance between this geometry and geom.
bool relatePattern(const QgsAbstractGeometry *geom, const QString &pattern, QString *errorMsg=nullptr) const override
Tests whether two geometries are related by a specified Dimensional Extended 9 Intersection Model (DE...
QgsPoint * centroid(QString *errorMsg=nullptr) const override
Calculates the centroid of this.
T qgsgeometry_cast(const QgsAbstractGeometry *geom)
Multi curve geometry collection.
double distance(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Calculates the distance between this and geom.
static QgsGeometry polygonize(const QVector< const QgsAbstractGeometry *> &geometries, QString *errorMsg=nullptr)
Creates a GeometryCollection geometry containing possible polygons formed from the constituent linewo...
QgsPoint * clone() const override
Clones the geometry by performing a deep copy.
Abstract base class for curved geometry type.
Abstract base class for all geometries.
virtual int dimension() const =0
Returns the inherent dimension of the geometry.
std::unique_ptr< GEOSBufferParams, GeosDeleter > buffer_params_unique_ptr
Scoped GEOS buffer params pointer.
QgsWkbTypes::Type wkbType() const
Returns the WKB type of the geometry.
Point geometry type, with support for z-dimension and m-values.
QgsGeometry delaunayTriangulation(double tolerance=0.0, bool edgesOnly=false, QString *errorMsg=nullptr) const
Returns the Delaunay triangulation for the vertices of the geometry.
const double * yData() const
Returns a const pointer to the y vertex data.
Error occurred while creating a noded geometry.
QgsLineString * clone() const override
Clones the geometry by performing a deep copy.
Error occurred in the geometry engine.
const double * zData() const
Returns a const pointer to the z vertex data, or nullptr if the linestring does not have z values...
int numGeometries() const
Returns the number of geometries within the collection.
QgsAbstractGeometry * symDifference(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Calculate the symmetric difference of this and geom.
Contains geos related utilities and functions.
std::unique_ptr< QgsAbstractGeometry > clip(const QgsRectangle &rectangle, QString *errorMsg=nullptr) const
Performs a fast, non-robust intersection between the geometry and a rectangle.
QgsAbstractGeometry * get()
Returns a modifiable (non-const) reference to the underlying abstract geometry primitive.
const QgsAbstractGeometry * constGet() const
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
QgsAbstractGeometry * combine(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Calculate the combination of this and geom.
double xMaximum() const
Returns the x maximum value (right side of rectangle).
void geometryChanged() override
Should be called whenever the geometry associated with the engine has been modified and the engine mu...
QVector< QgsPoint > QgsPointSequence
static QgsPoint coordSeqPoint(const GEOSCoordSequence *cs, int i, bool hasZ, bool hasM)
static QgsGeometry::OperationResult addPart(QgsAbstractGeometry *geometry, std::unique_ptr< QgsAbstractGeometry > part)
Add a part to multi type geometry.
QgsAbstractGeometry * offsetCurve(double distance, int segments, int joinStyle, double miterLimit, QString *errorMsg=nullptr) const override
QgsAbstractGeometry * convexHull(QString *errorMsg=nullptr) const override
Calculate the convex hull of this.
static geos::unique_ptr asGeos(const QgsGeometry &geometry, double precision=0)
Returns a geos geometry - caller takes ownership of the object (should be deleted with GEOSGeom_destr...
The base geometry on which the operation is done is invalid or empty.
Multi polygon geometry collection.
bool addGeometry(QgsAbstractGeometry *g) override
Adds a geometry and takes ownership. Returns true in case of success.
bool contains(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Checks if geom contains this.
void setYMaximum(double y)
Set the maximum y value.
std::unique_ptr< QgsAbstractGeometry > subdivide(int maxNodes, QString *errorMsg=nullptr) const
Subdivides the geometry.
Line string geometry type, with support for z-dimension and m-values.
virtual QgsLineString * curveToLine(double tolerance=M_PI_2/90, SegmentationToleranceType toleranceType=MaximumAngle) const =0
Returns a new line string geometry corresponding to a segmentized approximation of the curve...
const QgsAbstractGeometry * geometryN(int n) const
Returns a const reference to a geometry from within the collection.
QString relate(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Returns the Dimensional Extended 9 Intersection Model (DE-9IM) representation of the relationship bet...
bool isNull() const
Test if the rectangle is null (all coordinates zero or after call to setMinimal()).
QgsPoint pointN(int i) const
Returns the specified point from inside the line string.
EngineOperationResult splitGeometry(const QgsLineString &splitLine, QVector< QgsGeometry > &newGeometries, bool topological, QgsPointSequence &topologyTestPoints, QString *errorMsg=nullptr) const override
Splits this geometry according to a given line.
bool intersects(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Checks if geom intersects this.
double xMinimum() const
Returns the x minimum value (left side of rectangle).
double hausdorffDistance(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const
Returns the Hausdorff distance between this geometry and geom.
double xAt(int index) const override
Returns the x-coordinate of the specified node in the line string.
QgsAbstractGeometry * difference(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Calculate the difference of this and geom.
bool overlaps(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Checks if geom overlaps this.
Contains geometry relation and modification algorithms.
double yMaximum() const
Returns the y maximum value (top side of rectangle).
static std::unique_ptr< QgsPolygon > fromGeosPolygon(const GEOSGeometry *geos)
std::unique_ptr< GEOSCoordSequence, GeosDeleter > coord_sequence_unique_ptr
Scoped GEOS coordinate sequence pointer.
EngineOperationResult
Success or failure of a geometry operation.
QgsGeometry voronoiDiagram(const QgsAbstractGeometry *extent=nullptr, double tolerance=0.0, bool edgesOnly=false, QString *errorMsg=nullptr) const
Creates a Voronoi diagram for the nodes contained within the geometry.
static QgsGeometry geometryFromGeos(GEOSGeometry *geos)
Creates a new QgsGeometry object, feeding in a geometry in GEOS format.
const QgsCurve * exteriorRing() const
Returns the curve polygon's exterior ring.
static Type flatType(Type type)
Returns the flat type for a WKB type.
The geometry on which the operation occurs is not valid.
#define DEFAULT_QUADRANT_SEGMENTS
bool is3D() const
Returns true if the geometry is 3D and contains a z-value.
bool isSimple(QString *errorMsg=nullptr) const override
Determines whether the geometry is simple (according to OGC definition).
bool crosses(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Checks if geom crosses this.
void setXMinimum(double x)
Set the minimum x value.
QgsAbstractGeometry * simplify(double tolerance, QString *errorMsg=nullptr) const override
virtual bool addGeometry(QgsAbstractGeometry *g)
Adds a geometry and takes ownership. Returns true in case of success.
double height() const
Returns the height of the rectangle.