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 QString message = QString::fromUtf8( buffer );
70 throw GEOSException( message );
78 throw GEOSException( message );
83 static void printGEOSNotice(
const char *fmt, ... )
85 #if defined(QGISDEBUG)
90 vsnprintf( buffer,
sizeof buffer, fmt, ap );
100 GEOSContextHandle_t ctxt;
104 ctxt = initGEOS_r( printGEOSNotice, throwGEOSException );
109 finishGEOS_r( ctxt );
112 GEOSInit(
const GEOSInit &rh ) =
delete;
113 GEOSInit &operator=(
const GEOSInit &rh ) =
delete;
120 GEOSGeom_destroy_r( geosinit()->ctxt, geom );
125 GEOSPreparedGeom_destroy_r( geosinit()->ctxt, geom );
130 GEOSBufferParams_destroy_r( geosinit()->ctxt, params );
135 GEOSCoordSeq_destroy_r( geosinit()->ctxt, sequence );
184 std::unique_ptr< QgsAbstractGeometry > geom =
fromGeos( newPart );
191 mGeosPrepared.reset();
197 mGeosPrepared.reset();
200 mGeosPrepared.reset( GEOSPrepare_r( geosinit()->ctxt, mGeos.get() ) );
204 void QgsGeos::cacheGeos()
const
216 return overlay( geom, OverlayIntersection, errorMsg ).release();
221 return overlay( geom, OverlayDifference, errorMsg ).release();
236 catch ( GEOSException &e )
238 logError( QStringLiteral(
"GEOS" ), e.what() );
241 *errorMsg = e.what();
252 int partType = GEOSGeomTypeId_r( geosinit()->ctxt, currentPart );
255 if ( partType == GEOS_POINT )
266 if ( partType == GEOS_MULTILINESTRING || partType == GEOS_MULTIPOLYGON || partType == GEOS_GEOMETRYCOLLECTION )
268 int partCount = GEOSGetNumGeometries_r( geosinit()->ctxt, currentPart );
269 for (
int i = 0; i < partCount; ++i )
271 subdivideRecursive( GEOSGetGeometryN_r( geosinit()->ctxt, currentPart, i ), maxNodes, depth, parts, clipRect );
282 int vertexCount = GEOSGetNumCoordinates_r( geosinit()->ctxt, currentPart );
283 if ( vertexCount == 0 )
287 else if ( vertexCount < maxNodes )
294 double width = clipRect.
width();
295 double height = clipRect.
height();
298 if ( width > height )
311 halfClipRect1.
setYMinimum( halfClipRect1.
yMinimum() - std::numeric_limits<double>::epsilon() );
312 halfClipRect2.
setYMinimum( halfClipRect2.
yMinimum() - std::numeric_limits<double>::epsilon() );
313 halfClipRect1.
setYMaximum( halfClipRect1.
yMaximum() + std::numeric_limits<double>::epsilon() );
314 halfClipRect2.
setYMaximum( halfClipRect2.
yMaximum() + std::numeric_limits<double>::epsilon() );
318 halfClipRect1.
setXMinimum( halfClipRect1.
xMinimum() - std::numeric_limits<double>::epsilon() );
319 halfClipRect2.
setXMinimum( halfClipRect2.
xMinimum() - std::numeric_limits<double>::epsilon() );
320 halfClipRect1.
setXMaximum( halfClipRect1.
xMaximum() + std::numeric_limits<double>::epsilon() );
321 halfClipRect2.
setXMaximum( halfClipRect2.
xMaximum() + std::numeric_limits<double>::epsilon() );
331 subdivideRecursive( clipPart1.get(), maxNodes, depth, parts, halfClipRect1 );
335 subdivideRecursive( clipPart2.get(), maxNodes, depth, parts, halfClipRect2 );
347 maxNodes = std::max( maxNodes, 8 );
356 return std::move( parts );
361 return overlay( geom, OverlayUnion, errorMsg ).release();
366 QVector< GEOSGeometry * > geosGeometries;
367 geosGeometries.reserve( geomList.size() );
373 geosGeometries <<
asGeos( g, mPrecision ).release();
379 geos::unique_ptr geomCollection = createGeosCollection( GEOS_GEOMETRYCOLLECTION, geosGeometries );
380 geomUnion.reset( GEOSUnaryUnion_r( geosinit()->ctxt, geomCollection.get() ) );
384 std::unique_ptr< QgsAbstractGeometry > result =
fromGeos( geomUnion.get() );
385 return result.release();
390 QVector< GEOSGeometry * > geosGeometries;
391 geosGeometries.reserve( geomList.size() );
397 geosGeometries <<
asGeos( g.constGet(), mPrecision ).release();
403 geos::unique_ptr geomCollection = createGeosCollection( GEOS_GEOMETRYCOLLECTION, geosGeometries );
404 geomUnion.reset( GEOSUnaryUnion_r( geosinit()->ctxt, geomCollection.get() ) );
408 std::unique_ptr< QgsAbstractGeometry > result =
fromGeos( geomUnion.get() );
409 return result.release();
414 return overlay( geom, OverlaySymDifference, errorMsg ).release();
426 if ( !otherGeosGeom )
433 GEOSDistance_r( geosinit()->ctxt, mGeos.get(), otherGeosGeom.get(), &
distance );
449 if ( !otherGeosGeom )
456 GEOSHausdorffDistance_r( geosinit()->ctxt, mGeos.get(), otherGeosGeom.get(), &
distance );
472 if ( !otherGeosGeom )
479 GEOSHausdorffDistanceDensify_r( geosinit()->ctxt, mGeos.get(), otherGeosGeom.get(), densifyFraction, &
distance );
488 return relation( geom, RelationIntersects, errorMsg );
493 return relation( geom, RelationTouches, errorMsg );
498 return relation( geom, RelationCrosses, errorMsg );
503 return relation( geom, RelationWithin, errorMsg );
508 return relation( geom, RelationOverlaps, errorMsg );
513 return relation( geom, RelationContains, errorMsg );
518 return relation( geom, RelationDisjoint, errorMsg );
537 char *r = GEOSRelate_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() );
540 result = QString( r );
541 GEOSFree_r( geosinit()->ctxt, r );
544 catch ( GEOSException &e )
546 logError( QStringLiteral(
"GEOS" ), e.what() );
549 *errorMsg = e.what();
558 if ( !mGeos || !geom )
572 result = ( GEOSRelatePattern_r( geosinit()->ctxt, mGeos.get(), geosGeom.get(), pattern.toLocal8Bit().constData() ) == 1 );
574 catch ( GEOSException &e )
576 logError( QStringLiteral(
"GEOS" ), e.what() );
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,
bool skipIntersectionCheck )
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, skipIntersectionCheck );
685 returnCode = splitPolygonGeometry( splitLineGeos.get(), newGeometries, skipIntersectionCheck );
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 ) );
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 ) );
783 QgsPoint *splitPoint = qgsgeometry_cast<QgsPoint *>( splitGeom.get() );
792 for (
int i = 0; i < multiCurve->numGeometries(); ++i )
794 const QgsLineString *line = qgsgeometry_cast<const QgsLineString *>( multiCurve->geometryN( i ) );
801 for (
int j = 1; j < ( nVertices - 1 ); ++j )
805 if ( currentPoint == *splitPoint )
817 return asGeos( &lines, mPrecision );
829 if ( !skipIntersectionCheck && !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] );
885 if ( !mGeosPrepared )
889 if ( !skipIntersectionCheck && !GEOSPreparedIntersects_r( geosinit()->ctxt, mGeosPrepared.get(), splitLine ) )
894 if ( !nodedGeometry )
897 const GEOSGeometry *noded = nodedGeometry.get();
898 geos::unique_ptr polygons( GEOSPolygonize_r( geosinit()->ctxt, &noded, 1 ) );
899 if ( !polygons || numberOfGeometries( polygons.get() ) == 0 )
906 QVector<GEOSGeometry *> testedGeometries;
911 for (
int i = 0; i < numberOfGeometries( polygons.get() ); i++ )
913 const GEOSGeometry *polygon = GEOSGetGeometryN_r( geosinit()->ctxt, polygons.get(), i );
917 testedGeometries << GEOSGeom_clone_r( geosinit()->ctxt, polygon );
920 int nGeometriesThis = numberOfGeometries( mGeos.get() );
921 if ( testedGeometries.empty() || testedGeometries.size() == nGeometriesThis )
924 for (
int i = 0; i < testedGeometries.size(); ++i )
926 GEOSGeom_destroy_r( geosinit()->ctxt, testedGeometries[i] );
935 mergeGeometriesMultiTypeSplit( testedGeometries );
938 for ( i = 0; i < testedGeometries.size() && GEOSisValid_r( geosinit()->ctxt, testedGeometries[i] ); ++i )
941 if ( i < testedGeometries.size() )
943 for ( i = 0; i < testedGeometries.size(); ++i )
944 GEOSGeom_destroy_r( geosinit()->ctxt, testedGeometries[i] );
949 for ( i = 0; i < testedGeometries.size(); ++i )
952 GEOSGeom_destroy_r( geosinit()->ctxt, testedGeometries[i] );
958 geos::unique_ptr QgsGeos::nodeGeometries(
const GEOSGeometry *splitLine,
const GEOSGeometry *geom )
960 if ( !splitLine || !geom )
964 if ( GEOSGeomTypeId_r( geosinit()->ctxt, geom ) == GEOS_POLYGON || GEOSGeomTypeId_r( geosinit()->ctxt, geom ) == GEOS_MULTIPOLYGON )
965 geometryBoundary.reset( GEOSBoundary_r( geosinit()->ctxt, geom ) );
967 geometryBoundary.reset( GEOSGeom_clone_r( geosinit()->ctxt, geom ) );
969 geos::unique_ptr splitLineClone( GEOSGeom_clone_r( geosinit()->ctxt, splitLine ) );
970 geos::unique_ptr unionGeometry( GEOSUnion_r( geosinit()->ctxt, splitLineClone.get(), geometryBoundary.get() ) );
972 return unionGeometry;
975 int QgsGeos::mergeGeometriesMultiTypeSplit( QVector<GEOSGeometry *> &splitResult )
const
981 int type = GEOSGeomTypeId_r( geosinit()->ctxt, mGeos.get() );
982 if ( type != GEOS_GEOMETRYCOLLECTION &&
983 type != GEOS_MULTILINESTRING &&
984 type != GEOS_MULTIPOLYGON &&
985 type != GEOS_MULTIPOINT )
988 QVector<GEOSGeometry *> copyList = splitResult;
992 QVector<GEOSGeometry *> unionGeom;
994 for (
int i = 0; i < copyList.size(); ++i )
998 for (
int j = 0; j < GEOSGetNumGeometries_r( geosinit()->ctxt, mGeos.get() ); j++ )
1000 if ( GEOSEquals_r( geosinit()->ctxt, copyList[i], GEOSGetGeometryN_r( geosinit()->ctxt, mGeos.get(), j ) ) )
1009 unionGeom << copyList[i];
1013 QVector<GEOSGeometry *> geomVector;
1014 geomVector << copyList[i];
1016 if ( type == GEOS_MULTILINESTRING )
1017 splitResult << createGeosCollection( GEOS_MULTILINESTRING, geomVector ).release();
1018 else if ( type == GEOS_MULTIPOLYGON )
1019 splitResult << createGeosCollection( GEOS_MULTIPOLYGON, geomVector ).release();
1021 GEOSGeom_destroy_r( geosinit()->ctxt, copyList[i] );
1026 if ( !unionGeom.isEmpty() )
1028 if ( type == GEOS_MULTILINESTRING )
1029 splitResult << createGeosCollection( GEOS_MULTILINESTRING, unionGeom ).release();
1030 else if ( type == GEOS_MULTIPOLYGON )
1031 splitResult << createGeosCollection( GEOS_MULTIPOLYGON, unionGeom ).release();
1041 geos::unique_ptr QgsGeos::createGeosCollection(
int typeId,
const QVector<GEOSGeometry *> &geoms )
1043 int nNullGeoms = geoms.count(
nullptr );
1044 int nNotNullGeoms = geoms.size() - nNullGeoms;
1046 GEOSGeometry **geomarr =
new GEOSGeometry*[ nNotNullGeoms ];
1053 QVector<GEOSGeometry *>::const_iterator geomIt = geoms.constBegin();
1054 for ( ; geomIt != geoms.constEnd(); ++geomIt )
1058 if ( GEOSisEmpty_r( geosinit()->ctxt, *geomIt ) )
1063 GEOSGeom_destroy_r( geosinit()->ctxt, *geomIt );
1067 geomarr[i] = *geomIt;
1076 geom.reset( GEOSGeom_createCollection_r( geosinit()->ctxt, typeId, geomarr, nNotNullGeoms ) );
1078 catch ( GEOSException & )
1094 int nCoordDims = GEOSGeom_getCoordinateDimension_r( geosinit()->ctxt,
geos );
1095 int nDims = GEOSGeom_getDimensions_r( geosinit()->ctxt,
geos );
1096 bool hasZ = ( nCoordDims == 3 );
1097 bool hasM = ( ( nDims - nCoordDims ) == 1 );
1099 switch ( GEOSGeomTypeId_r( geosinit()->ctxt,
geos ) )
1103 const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq_r( geosinit()->ctxt,
geos );
1104 unsigned int nPoints = 0;
1105 GEOSCoordSeq_getSize_r( geosinit()->ctxt, cs, &nPoints );
1106 return nPoints > 0 ? std::unique_ptr<QgsAbstractGeometry>(
coordSeqPoint( cs, 0, hasZ, hasM ).clone() ) : qgis::make_unique< QgsPoint >();
1108 case GEOS_LINESTRING:
1110 return sequenceToLinestring(
geos, hasZ, hasM );
1116 case GEOS_MULTIPOINT:
1118 std::unique_ptr< QgsMultiPoint > multiPoint(
new QgsMultiPoint() );
1119 int nParts = GEOSGetNumGeometries_r( geosinit()->ctxt,
geos );
1120 multiPoint->reserve( nParts );
1121 for (
int i = 0; i < nParts; ++i )
1123 const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, GEOSGetGeometryN_r( geosinit()->ctxt,
geos, i ) );
1126 unsigned int nPoints = 0;
1127 GEOSCoordSeq_getSize_r( geosinit()->ctxt, cs, &nPoints );
1129 multiPoint->addGeometry(
coordSeqPoint( cs, 0, hasZ, hasM ).clone() );
1132 return std::move( multiPoint );
1134 case GEOS_MULTILINESTRING:
1137 int nParts = GEOSGetNumGeometries_r( geosinit()->ctxt,
geos );
1138 multiLineString->reserve( nParts );
1139 for (
int i = 0; i < nParts; ++i )
1141 std::unique_ptr< QgsLineString >line( sequenceToLinestring( GEOSGetGeometryN_r( geosinit()->ctxt,
geos, i ), hasZ, hasM ) );
1144 multiLineString->addGeometry( line.release() );
1147 return std::move( multiLineString );
1149 case GEOS_MULTIPOLYGON:
1151 std::unique_ptr< QgsMultiPolygon > multiPolygon(
new QgsMultiPolygon() );
1153 int nParts = GEOSGetNumGeometries_r( geosinit()->ctxt,
geos );
1154 multiPolygon->reserve( nParts );
1155 for (
int i = 0; i < nParts; ++i )
1157 std::unique_ptr< QgsPolygon > poly =
fromGeosPolygon( GEOSGetGeometryN_r( geosinit()->ctxt,
geos, i ) );
1160 multiPolygon->addGeometry( poly.release() );
1163 return std::move( multiPolygon );
1165 case GEOS_GEOMETRYCOLLECTION:
1168 int nParts = GEOSGetNumGeometries_r( geosinit()->ctxt,
geos );
1169 geomCollection->reserve( nParts );
1170 for (
int i = 0; i < nParts; ++i )
1172 std::unique_ptr< QgsAbstractGeometry > geom(
fromGeos( GEOSGetGeometryN_r( geosinit()->ctxt,
geos, i ) ) );
1175 geomCollection->addGeometry( geom.release() );
1178 return std::move( geomCollection );
1186 if ( GEOSGeomTypeId_r( geosinit()->ctxt,
geos ) != GEOS_POLYGON )
1191 int nCoordDims = GEOSGeom_getCoordinateDimension_r( geosinit()->ctxt,
geos );
1192 int nDims = GEOSGeom_getDimensions_r( geosinit()->ctxt,
geos );
1193 bool hasZ = ( nCoordDims == 3 );
1194 bool hasM = ( ( nDims - nCoordDims ) == 1 );
1196 std::unique_ptr< QgsPolygon > polygon(
new QgsPolygon() );
1198 const GEOSGeometry *ring = GEOSGetExteriorRing_r( geosinit()->ctxt,
geos );
1201 polygon->setExteriorRing( sequenceToLinestring( ring, hasZ, hasM ).release() );
1204 QVector<QgsCurve *> interiorRings;
1205 const int ringCount = GEOSGetNumInteriorRings_r( geosinit()->ctxt,
geos );
1206 interiorRings.reserve( ringCount );
1207 for (
int i = 0; i < ringCount; ++i )
1209 ring = GEOSGetInteriorRingN_r( geosinit()->ctxt,
geos, i );
1212 interiorRings.push_back( sequenceToLinestring( ring, hasZ, hasM ).release() );
1215 polygon->setInteriorRings( interiorRings );
1220 std::unique_ptr<QgsLineString> QgsGeos::sequenceToLinestring(
const GEOSGeometry *
geos,
bool hasZ,
bool hasM )
1222 const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq_r( geosinit()->ctxt,
geos );
1223 unsigned int nPoints;
1224 GEOSCoordSeq_getSize_r( geosinit()->ctxt, cs, &nPoints );
1225 QVector< double > xOut( nPoints );
1226 QVector< double > yOut( nPoints );
1227 QVector< double > zOut;
1229 zOut.resize( nPoints );
1230 QVector< double > mOut;
1232 mOut.resize( nPoints );
1233 double *x = xOut.data();
1234 double *y = yOut.data();
1235 double *z = zOut.data();
1236 double *m = mOut.data();
1237 for (
unsigned int i = 0; i < nPoints; ++i )
1239 #if GEOS_VERSION_MAJOR>3 || GEOS_VERSION_MINOR>=8
1241 GEOSCoordSeq_getXYZ_r( geosinit()->ctxt, cs, i, x++, y++, z++ );
1243 GEOSCoordSeq_getXY_r( geosinit()->ctxt, cs, i, x++, y++ );
1245 GEOSCoordSeq_getX_r( geosinit()->ctxt, cs, i, x++ );
1246 GEOSCoordSeq_getY_r( geosinit()->ctxt, cs, i, y++ );
1249 GEOSCoordSeq_getZ_r( geosinit()->ctxt, cs, i, z++ );
1254 GEOSCoordSeq_getOrdinate_r( geosinit()->ctxt, cs, i, 3, m++ );
1257 std::unique_ptr< QgsLineString > line(
new QgsLineString( xOut, yOut, zOut, mOut ) );
1261 int QgsGeos::numberOfGeometries( GEOSGeometry *g )
1266 int geometryType = GEOSGeomTypeId_r( geosinit()->ctxt, g );
1267 if ( geometryType == GEOS_POINT || geometryType == GEOS_LINESTRING || geometryType == GEOS_LINEARRING
1268 || geometryType == GEOS_POLYGON )
1272 return GEOSGetNumGeometries_r( geosinit()->ctxt, g );
1285 #if GEOS_VERSION_MAJOR>3 || GEOS_VERSION_MINOR>=8
1287 GEOSCoordSeq_getXYZ_r( geosinit()->ctxt, cs, i, &x, &y, &z );
1289 GEOSCoordSeq_getXY_r( geosinit()->ctxt, cs, i, &x, &y );
1291 GEOSCoordSeq_getX_r( geosinit()->ctxt, cs, i, &x );
1292 GEOSCoordSeq_getY_r( geosinit()->ctxt, cs, i, &y );
1295 GEOSCoordSeq_getZ_r( geosinit()->ctxt, cs, i, &z );
1300 GEOSCoordSeq_getOrdinate_r( geosinit()->ctxt, cs, i, 3, &m );
1336 int geosType = GEOS_GEOMETRYCOLLECTION;
1343 geosType = GEOS_MULTIPOINT;
1347 geosType = GEOS_MULTILINESTRING;
1351 geosType = GEOS_MULTIPOLYGON;
1367 QVector< GEOSGeometry * > geomVector(
c->numGeometries() );
1368 for (
int i = 0; i <
c->numGeometries(); ++i )
1372 return createGeosCollection( geosType, geomVector );
1379 return createGeosPoint(
static_cast<const QgsPoint *
>( geom ), coordDims,
precision );
1399 std::unique_ptr<QgsAbstractGeometry> QgsGeos::overlay(
const QgsAbstractGeometry *geom, Overlay op, QString *errorMsg )
const
1401 if ( !mGeos || !geom )
1417 case OverlayIntersection:
1418 opGeom.reset( GEOSIntersection_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) );
1420 case OverlayDifference:
1421 opGeom.reset( GEOSDifference_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) );
1425 geos::unique_ptr unionGeometry( GEOSUnion_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) );
1427 if ( unionGeometry && GEOSGeomTypeId_r( geosinit()->ctxt, unionGeometry.get() ) == GEOS_MULTILINESTRING )
1429 geos::unique_ptr mergedLines( GEOSLineMerge_r( geosinit()->ctxt, unionGeometry.get() ) );
1432 unionGeometry = std::move( mergedLines );
1436 opGeom = std::move( unionGeometry );
1439 case OverlaySymDifference:
1440 opGeom.reset( GEOSSymDifference_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) );
1447 catch ( GEOSException &e )
1449 logError( QStringLiteral(
"GEOS" ), e.what() );
1452 *errorMsg = e.what();
1458 bool QgsGeos::relation(
const QgsAbstractGeometry *geom, Relation r, QString *errorMsg )
const
1460 if ( !mGeos || !geom )
1471 bool result =
false;
1474 if ( mGeosPrepared )
1478 case RelationIntersects:
1479 result = ( GEOSPreparedIntersects_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1481 case RelationTouches:
1482 result = ( GEOSPreparedTouches_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1484 case RelationCrosses:
1485 result = ( GEOSPreparedCrosses_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1487 case RelationWithin:
1488 result = ( GEOSPreparedWithin_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1490 case RelationContains:
1491 result = ( GEOSPreparedContains_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1493 case RelationDisjoint:
1494 result = ( GEOSPreparedDisjoint_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1496 case RelationOverlaps:
1497 result = ( GEOSPreparedOverlaps_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
1507 case RelationIntersects:
1508 result = ( GEOSIntersects_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1510 case RelationTouches:
1511 result = ( GEOSTouches_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1513 case RelationCrosses:
1514 result = ( GEOSCrosses_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1516 case RelationWithin:
1517 result = ( GEOSWithin_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1519 case RelationContains:
1520 result = ( GEOSContains_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1522 case RelationDisjoint:
1523 result = ( GEOSDisjoint_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1525 case RelationOverlaps:
1526 result = ( GEOSOverlaps_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
1532 catch ( GEOSException &e )
1534 logError( QStringLiteral(
"GEOS" ), e.what() );
1537 *errorMsg = e.what();
1555 geos.reset( GEOSBuffer_r( geosinit()->ctxt, mGeos.get(),
distance, segments ) );
1571 geos.reset( GEOSBufferWithStyle_r( geosinit()->ctxt, mGeos.get(),
distance, segments, endCapStyle, joinStyle, miterLimit ) );
1586 geos.reset( GEOSTopologyPreserveSimplify_r( geosinit()->ctxt, mGeos.get(), tolerance ) );
1601 geos.reset( GEOSInterpolate_r( geosinit()->ctxt, mGeos.get(),
distance ) );
1620 geos.reset( GEOSGetCentroid_r( geosinit()->ctxt, mGeos.get() ) );
1625 GEOSGeomGetX_r( geosinit()->ctxt,
geos.get(), &x );
1626 GEOSGeomGetY_r( geosinit()->ctxt,
geos.get(), &y );
1642 geos.reset( GEOSEnvelope_r( geosinit()->ctxt, mGeos.get() ) );
1661 geos.reset( GEOSPointOnSurface_r( geosinit()->ctxt, mGeos.get() ) );
1663 if ( !
geos || GEOSisEmpty_r( geosinit()->ctxt,
geos.get() ) != 0 )
1668 GEOSGeomGetX_r( geosinit()->ctxt,
geos.get(), &x );
1669 GEOSGeomGetY_r( geosinit()->ctxt,
geos.get(), &y );
1685 geos::unique_ptr cHull( GEOSConvexHull_r( geosinit()->ctxt, mGeos.get() ) );
1686 std::unique_ptr< QgsAbstractGeometry > cHullGeom =
fromGeos( cHull.get() );
1687 return cHullGeom.release();
1701 GEOSGeometry *g1 =
nullptr;
1703 char res = GEOSisValidDetail_r( geosinit()->ctxt, mGeos.get(), allowSelfTouchingHoles ? GEOSVALID_ALLOW_SELFTOUCHING_RING_FORMING_HOLE : 0, &r, &g1 );
1704 const bool invalid = res != 1;
1709 error = QString( r );
1710 GEOSFree_r( geosinit()->ctxt, r );
1713 if ( invalid && errorMsg )
1717 if ( translatedErrors.empty() )
1720 translatedErrors.insert( QStringLiteral(
"topology validation error" ), QObject::tr(
"Topology validation error",
"GEOS Error" ) );
1721 translatedErrors.insert( QStringLiteral(
"repeated point" ), QObject::tr(
"Repeated point",
"GEOS Error" ) );
1722 translatedErrors.insert( QStringLiteral(
"hole lies outside shell" ), QObject::tr(
"Hole lies outside shell",
"GEOS Error" ) );
1723 translatedErrors.insert( QStringLiteral(
"holes are nested" ), QObject::tr(
"Holes are nested",
"GEOS Error" ) );
1724 translatedErrors.insert( QStringLiteral(
"interior is disconnected" ), QObject::tr(
"Interior is disconnected",
"GEOS Error" ) );
1725 translatedErrors.insert( QStringLiteral(
"self-intersection" ), QObject::tr(
"Self-intersection",
"GEOS Error" ) );
1726 translatedErrors.insert( QStringLiteral(
"ring self-intersection" ), QObject::tr(
"Ring self-intersection",
"GEOS Error" ) );
1727 translatedErrors.insert( QStringLiteral(
"nested shells" ), QObject::tr(
"Nested shells",
"GEOS Error" ) );
1728 translatedErrors.insert( QStringLiteral(
"duplicate rings" ), QObject::tr(
"Duplicate rings",
"GEOS Error" ) );
1729 translatedErrors.insert( QStringLiteral(
"too few points in geometry component" ), QObject::tr(
"Too few points in geometry component",
"GEOS Error" ) );
1730 translatedErrors.insert( QStringLiteral(
"invalid coordinate" ), QObject::tr(
"Invalid coordinate",
"GEOS Error" ) );
1731 translatedErrors.insert( QStringLiteral(
"ring is not closed" ), QObject::tr(
"Ring is not closed",
"GEOS Error" ) );
1734 *errorMsg = translatedErrors.value( error.toLower(), error );
1736 if ( g1 && errorLoc )
1742 GEOSGeom_destroy_r( geosinit()->ctxt, g1 );
1752 if ( !mGeos || !geom )
1764 bool equal = GEOSEquals_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() );
1779 return GEOSisEmpty_r( geosinit()->ctxt, mGeos.get() );
1793 return GEOSisSimple_r( geosinit()->ctxt, mGeos.get() );
1798 GEOSCoordSequence *QgsGeos::createCoordinateSequence(
const QgsCurve *curve,
double precision,
bool forceClose )
1800 std::unique_ptr< QgsLineString > segmentized;
1801 const QgsLineString *line = qgsgeometry_cast<const QgsLineString *>( curve );
1806 line = segmentized.get();
1814 bool hasZ = line->
is3D();
1828 int numOutPoints = numPoints;
1829 if ( forceClose && ( line->
pointN( 0 ) != line->
pointN( numPoints - 1 ) ) )
1834 GEOSCoordSequence *coordSeq =
nullptr;
1837 coordSeq = GEOSCoordSeq_create_r( geosinit()->ctxt, numOutPoints, coordDims );
1840 QgsDebugMsg( QStringLiteral(
"GEOS Exception: Could not create coordinate sequence for %1 points in %2 dimensions" ).arg( numPoints ).arg( coordDims ) );
1844 const double *xData = line->
xData();
1845 const double *yData = line->
yData();
1846 const double *zData = hasZ ? line->
zData() :
nullptr;
1847 const double *mData = hasM ? line->
mData() :
nullptr;
1851 for (
int i = 0; i < numOutPoints; ++i )
1853 if ( i >= numPoints )
1856 xData = line->
xData();
1857 yData = line->
yData();
1858 zData = hasZ ? line->
zData() :
nullptr;
1859 mData = hasM ? line->
mData() :
nullptr;
1861 #if GEOS_VERSION_MAJOR>3 || GEOS_VERSION_MINOR>=8
1871 GEOSCoordSeq_setX_r( geosinit()->ctxt, coordSeq, i, std::round( *xData++ /
precision ) *
precision );
1872 GEOSCoordSeq_setY_r( geosinit()->ctxt, coordSeq, i, std::round( *yData++ /
precision ) *
precision );
1875 GEOSCoordSeq_setOrdinate_r( geosinit()->ctxt, coordSeq, i, 2, std::round( *zData++ /
precision ) *
precision );
1880 GEOSCoordSeq_setOrdinate_r( geosinit()->ctxt, coordSeq, i, 3, line->
mAt( *mData++ ) );
1886 for (
int i = 0; i < numOutPoints; ++i )
1888 if ( i >= numPoints )
1891 xData = line->
xData();
1892 yData = line->
yData();
1893 zData = hasZ ? line->
zData() :
nullptr;
1894 mData = hasM ? line->
mData() :
nullptr;
1896 #if GEOS_VERSION_MAJOR>3 || GEOS_VERSION_MINOR>=8
1899 GEOSCoordSeq_setXYZ_r( geosinit()->ctxt, coordSeq, i, *xData++, *yData++, *zData++ );
1903 GEOSCoordSeq_setXY_r( geosinit()->ctxt, coordSeq, i, *xData++, *yData++ );
1906 GEOSCoordSeq_setX_r( geosinit()->ctxt, coordSeq, i, *xData++ );
1907 GEOSCoordSeq_setY_r( geosinit()->ctxt, coordSeq, i, *yData++ );
1910 GEOSCoordSeq_setOrdinate_r( geosinit()->ctxt, coordSeq, i, 2, *zData++ );
1915 GEOSCoordSeq_setOrdinate_r( geosinit()->ctxt, coordSeq, i, 3, *mData++ );
1927 const QgsPoint *pt = qgsgeometry_cast<const QgsPoint *>( point );
1934 geos::unique_ptr QgsGeos::createGeosPointXY(
double x,
double y,
bool hasZ,
double z,
bool hasM,
double m,
int coordDims,
double precision )
1942 #if GEOS_VERSION_MAJOR>3 || GEOS_VERSION_MINOR>=8
1943 if ( coordDims == 2 )
1949 geosPoint.reset( GEOSGeom_createPointFromXY_r( geosinit()->ctxt, x, y ) );
1954 GEOSCoordSequence *coordSeq = GEOSCoordSeq_create_r( geosinit()->ctxt, 1, coordDims );
1957 QgsDebugMsg( QStringLiteral(
"GEOS Exception: Could not create coordinate sequence for point with %1 dimensions" ).arg( coordDims ) );
1962 GEOSCoordSeq_setX_r( geosinit()->ctxt, coordSeq, 0, std::round( x /
precision ) *
precision );
1963 GEOSCoordSeq_setY_r( geosinit()->ctxt, coordSeq, 0, std::round( y /
precision ) *
precision );
1966 GEOSCoordSeq_setOrdinate_r( geosinit()->ctxt, coordSeq, 0, 2, std::round( z /
precision ) *
precision );
1971 GEOSCoordSeq_setX_r( geosinit()->ctxt, coordSeq, 0, x );
1972 GEOSCoordSeq_setY_r( geosinit()->ctxt, coordSeq, 0, y );
1975 GEOSCoordSeq_setOrdinate_r( geosinit()->ctxt, coordSeq, 0, 2, z );
1978 #if 0 //disabled until geos supports m-coordinates
1981 GEOSCoordSeq_setOrdinate_r( geosinit()->ctxt, coordSeq, 0, 3, m );
1984 geosPoint.reset( GEOSGeom_createPoint_r( geosinit()->ctxt, coordSeq ) );
1992 const QgsCurve *
c = qgsgeometry_cast<const QgsCurve *>( curve );
1996 GEOSCoordSequence *coordSeq = createCoordinateSequence(
c,
precision );
2003 geosGeom.reset( GEOSGeom_createLineString_r( geosinit()->ctxt, coordSeq ) );
2011 const QgsCurvePolygon *polygon = qgsgeometry_cast<const QgsCurvePolygon *>( poly );
2016 if ( !exteriorRing )
2024 geos::unique_ptr exteriorRingGeos( GEOSGeom_createLinearRing_r( geosinit()->ctxt, createCoordinateSequence( exteriorRing,
precision,
true ) ) );
2027 GEOSGeometry **holes =
nullptr;
2030 holes =
new GEOSGeometry*[ nHoles ];
2033 for (
int i = 0; i < nHoles; ++i )
2036 holes[i] = GEOSGeom_createLinearRing_r( geosinit()->ctxt, createCoordinateSequence( interiorRing,
precision,
true ) );
2038 geosPolygon.reset( GEOSGeom_createPolygon_r( geosinit()->ctxt, exteriorRingGeos.release(), holes, nHoles ) );
2054 offset.reset( GEOSOffsetCurve_r( geosinit()->ctxt, mGeos.get(),
distance, segments, joinStyle, miterLimit ) );
2057 std::unique_ptr< QgsAbstractGeometry > offsetGeom =
fromGeos( offset.get() );
2058 return offsetGeom.release();
2072 GEOSBufferParams_setSingleSided_r( geosinit()->ctxt, bp.get(), 1 );
2073 GEOSBufferParams_setQuadrantSegments_r( geosinit()->ctxt, bp.get(), segments );
2074 GEOSBufferParams_setJoinStyle_r( geosinit()->ctxt, bp.get(), joinStyle );
2075 GEOSBufferParams_setMitreLimit_r( geosinit()->ctxt, bp.get(), miterLimit );
2081 geos.reset( GEOSBufferWithParams_r( geosinit()->ctxt, mGeos.get(), bp.get(),
distance ) );
2101 geos::unique_ptr reshapeLineGeos = createGeosLinestring( &reshapeWithLine, mPrecision );
2104 int numGeoms = GEOSGetNumGeometries_r( geosinit()->ctxt, mGeos.get() );
2105 if ( numGeoms == -1 )
2114 bool isMultiGeom =
false;
2115 int geosTypeId = GEOSGeomTypeId_r( geosinit()->ctxt, mGeos.get() );
2116 if ( geosTypeId == GEOS_MULTILINESTRING || geosTypeId == GEOS_MULTIPOLYGON )
2126 reshapedGeometry = reshapeLine( mGeos.get(), reshapeLineGeos.get(), mPrecision );
2130 reshapedGeometry = reshapePolygon( mGeos.get(), reshapeLineGeos.get(), mPrecision );
2135 std::unique_ptr< QgsAbstractGeometry > reshapeResult =
fromGeos( reshapedGeometry.get() );
2136 return reshapeResult;
2143 bool reshapeTookPlace =
false;
2146 GEOSGeometry **newGeoms =
new GEOSGeometry*[numGeoms];
2148 for (
int i = 0; i < numGeoms; ++i )
2151 currentReshapeGeometry = reshapeLine( GEOSGetGeometryN_r( geosinit()->ctxt, mGeos.get(), i ), reshapeLineGeos.get(), mPrecision );
2153 currentReshapeGeometry = reshapePolygon( GEOSGetGeometryN_r( geosinit()->ctxt, mGeos.get(), i ), reshapeLineGeos.get(), mPrecision );
2155 if ( currentReshapeGeometry )
2157 newGeoms[i] = currentReshapeGeometry.release();
2158 reshapeTookPlace =
true;
2162 newGeoms[i] = GEOSGeom_clone_r( geosinit()->ctxt, GEOSGetGeometryN_r( geosinit()->ctxt, mGeos.get(), i ) );
2169 newMultiGeom.reset( GEOSGeom_createCollection_r( geosinit()->ctxt, GEOS_MULTILINESTRING, newGeoms, numGeoms ) );
2173 newMultiGeom.reset( GEOSGeom_createCollection_r( geosinit()->ctxt, GEOS_MULTIPOLYGON, newGeoms, numGeoms ) );
2177 if ( !newMultiGeom )
2183 if ( reshapeTookPlace )
2187 std::unique_ptr< QgsAbstractGeometry > reshapedMultiGeom =
fromGeos( newMultiGeom.get() );
2188 return reshapedMultiGeom;
2210 if ( GEOSGeomTypeId_r( geosinit()->ctxt, mGeos.get() ) != GEOS_MULTILINESTRING )
2216 geos.reset( GEOSLineMerge_r( geosinit()->ctxt, mGeos.get() ) );
2241 ( void )GEOSCoordSeq_getX_r( geosinit()->ctxt, nearestCoord.get(), 0, &nx );
2242 ( void )GEOSCoordSeq_getY_r( geosinit()->ctxt, nearestCoord.get(), 0, &ny );
2244 catch ( GEOSException &e )
2246 logError( QStringLiteral(
"GEOS" ), e.what() );
2249 *errorMsg = e.what();
2259 if ( !mGeos || other.
isNull() )
2278 ( void )GEOSCoordSeq_getX_r( geosinit()->ctxt, nearestCoord.get(), 0, &nx1 );
2279 ( void )GEOSCoordSeq_getY_r( geosinit()->ctxt, nearestCoord.get(), 0, &ny1 );
2280 ( void )GEOSCoordSeq_getX_r( geosinit()->ctxt, nearestCoord.get(), 1, &nx2 );
2281 ( void )GEOSCoordSeq_getY_r( geosinit()->ctxt, nearestCoord.get(), 1, &ny2 );
2283 catch ( GEOSException &e )
2285 logError( QStringLiteral(
"GEOS" ), e.what() );
2288 *errorMsg = e.what();
2315 distance = GEOSProject_r( geosinit()->ctxt, mGeos.get(), otherGeom.get() );
2317 catch ( GEOSException &e )
2319 logError( QStringLiteral(
"GEOS" ), e.what() );
2322 *errorMsg = e.what();
2332 GEOSGeometry **
const lineGeosGeometries =
new GEOSGeometry*[ geometries.size()];
2339 lineGeosGeometries[validLines] = l.release();
2346 geos::unique_ptr result( GEOSPolygonize_r( geosinit()->ctxt, lineGeosGeometries, validLines ) );
2347 for (
int i = 0; i < validLines; ++i )
2349 GEOSGeom_destroy_r( geosinit()->ctxt, lineGeosGeometries[i] );
2351 delete[] lineGeosGeometries;
2354 catch ( GEOSException &e )
2358 *errorMsg = e.what();
2360 for (
int i = 0; i < validLines; ++i )
2362 GEOSGeom_destroy_r( geosinit()->ctxt, lineGeosGeometries[i] );
2364 delete[] lineGeosGeometries;
2379 extentGeosGeom =
asGeos( extent, mPrecision );
2380 if ( !extentGeosGeom )
2389 geos.reset( GEOSVoronoiDiagram_r( geosinit()->ctxt, mGeos.get(), extentGeosGeom.get(), tolerance, edgesOnly ) );
2391 if ( !
geos || GEOSisEmpty_r( geosinit()->ctxt,
geos.get() ) != 0 )
2411 geos.reset( GEOSDelaunayTriangulation_r( geosinit()->ctxt, mGeos.get(), tolerance, edgesOnly ) );
2413 if ( !
geos || GEOSisEmpty_r( geosinit()->ctxt,
geos.get() ) != 0 )
2425 static bool _linestringEndpoints(
const GEOSGeometry *linestring,
double &x1,
double &y1,
double &x2,
double &y2 )
2427 const GEOSCoordSequence *coordSeq = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, linestring );
2431 unsigned int coordSeqSize;
2432 if ( GEOSCoordSeq_getSize_r( geosinit()->ctxt, coordSeq, &coordSeqSize ) == 0 )
2435 if ( coordSeqSize < 2 )
2438 GEOSCoordSeq_getX_r( geosinit()->ctxt, coordSeq, 0, &x1 );
2439 GEOSCoordSeq_getY_r( geosinit()->ctxt, coordSeq, 0, &y1 );
2440 GEOSCoordSeq_getX_r( geosinit()->ctxt, coordSeq, coordSeqSize - 1, &x2 );
2441 GEOSCoordSeq_getY_r( geosinit()->ctxt, coordSeq, coordSeqSize - 1, &y2 );
2447 static geos::unique_ptr _mergeLinestrings(
const GEOSGeometry *line1,
const GEOSGeometry *line2,
const QgsPointXY &intersectionPoint )
2449 double x1, y1, x2, y2;
2450 if ( !_linestringEndpoints( line1, x1, y1, x2, y2 ) )
2453 double rx1, ry1, rx2, ry2;
2454 if ( !_linestringEndpoints( line2, rx1, ry1, rx2, ry2 ) )
2457 bool intersectionAtOrigLineEndpoint =
2458 ( intersectionPoint.
x() == x1 && intersectionPoint.
y() == y1 ) !=
2459 ( intersectionPoint.
x() == x2 && intersectionPoint.
y() == y2 );
2460 bool intersectionAtReshapeLineEndpoint =
2461 ( intersectionPoint.
x() == rx1 && intersectionPoint.
y() == ry1 ) ||
2462 ( intersectionPoint.
x() == rx2 && intersectionPoint.
y() == ry2 );
2465 if ( intersectionAtOrigLineEndpoint && intersectionAtReshapeLineEndpoint )
2469 GEOSGeometry *geoms[2] = { g1.release(), g2.release() };
2470 geos::unique_ptr multiGeom( GEOSGeom_createCollection_r( geosinit()->ctxt, GEOS_MULTILINESTRING, geoms, 2 ) );
2471 geos::unique_ptr res( GEOSLineMerge_r( geosinit()->ctxt, multiGeom.get() ) );
2479 geos::unique_ptr QgsGeos::reshapeLine(
const GEOSGeometry *line,
const GEOSGeometry *reshapeLineGeos,
double precision )
2481 if ( !line || !reshapeLineGeos )
2484 bool atLeastTwoIntersections =
false;
2485 bool oneIntersection =
false;
2491 geos::unique_ptr intersectGeom( GEOSIntersection_r( geosinit()->ctxt, line, reshapeLineGeos ) );
2492 if ( intersectGeom )
2494 atLeastTwoIntersections = ( GEOSGeomTypeId_r( geosinit()->ctxt, intersectGeom.get() ) == GEOS_MULTIPOINT
2495 && GEOSGetNumGeometries_r( geosinit()->ctxt, intersectGeom.get() ) > 1 );
2497 if ( GEOSGeomTypeId_r( geosinit()->ctxt, intersectGeom.get() ) == GEOS_POINT )
2499 const GEOSCoordSequence *intersectionCoordSeq = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, intersectGeom.get() );
2501 GEOSCoordSeq_getX_r( geosinit()->ctxt, intersectionCoordSeq, 0, &xi );
2502 GEOSCoordSeq_getY_r( geosinit()->ctxt, intersectionCoordSeq, 0, &yi );
2503 oneIntersection =
true;
2508 catch ( GEOSException & )
2510 atLeastTwoIntersections =
false;
2514 if ( oneIntersection )
2515 return _mergeLinestrings( line, reshapeLineGeos, oneIntersectionPoint );
2517 if ( !atLeastTwoIntersections )
2521 double x1, y1, x2, y2;
2522 if ( !_linestringEndpoints( line, x1, y1, x2, y2 ) )
2528 bool isRing =
false;
2529 if ( GEOSGeomTypeId_r( geosinit()->ctxt, line ) == GEOS_LINEARRING
2530 || GEOSEquals_r( geosinit()->ctxt, beginLineVertex.get(), endLineVertex.get() ) == 1 )
2535 if ( !nodedGeometry )
2541 geos::unique_ptr mergedLines( GEOSLineMerge_r( geosinit()->ctxt, nodedGeometry.get() ) );
2547 int numMergedLines = GEOSGetNumGeometries_r( geosinit()->ctxt, mergedLines.get() );
2548 if ( numMergedLines < 2 )
2550 if ( numMergedLines == 1 )
2552 geos::unique_ptr result( GEOSGeom_clone_r( geosinit()->ctxt, reshapeLineGeos ) );
2559 QVector<GEOSGeometry *> resultLineParts;
2560 QVector<GEOSGeometry *> probableParts;
2562 for (
int i = 0; i < numMergedLines; ++i )
2564 const GEOSGeometry *currentGeom =
nullptr;
2566 currentGeom = GEOSGetGeometryN_r( geosinit()->ctxt, mergedLines.get(), i );
2567 const GEOSCoordSequence *currentCoordSeq = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, currentGeom );
2568 unsigned int currentCoordSeqSize;
2569 GEOSCoordSeq_getSize_r( geosinit()->ctxt, currentCoordSeq, ¤tCoordSeqSize );
2570 if ( currentCoordSeqSize < 2 )
2574 double xBegin, xEnd, yBegin, yEnd;
2575 GEOSCoordSeq_getX_r( geosinit()->ctxt, currentCoordSeq, 0, &xBegin );
2576 GEOSCoordSeq_getY_r( geosinit()->ctxt, currentCoordSeq, 0, &yBegin );
2577 GEOSCoordSeq_getX_r( geosinit()->ctxt, currentCoordSeq, currentCoordSeqSize - 1, &xEnd );
2578 GEOSCoordSeq_getY_r( geosinit()->ctxt, currentCoordSeq, currentCoordSeqSize - 1, &yEnd );
2583 int nEndpointsOnOriginalLine = 0;
2584 if ( pointContainedInLine( beginCurrentGeomVertex.get(), line ) == 1 )
2585 nEndpointsOnOriginalLine += 1;
2587 if ( pointContainedInLine( endCurrentGeomVertex.get(), line ) == 1 )
2588 nEndpointsOnOriginalLine += 1;
2591 int nEndpointsSameAsOriginalLine = 0;
2592 if ( GEOSEquals_r( geosinit()->ctxt, beginCurrentGeomVertex.get(), beginLineVertex.get() ) == 1
2593 || GEOSEquals_r( geosinit()->ctxt, beginCurrentGeomVertex.get(), endLineVertex.get() ) == 1 )
2594 nEndpointsSameAsOriginalLine += 1;
2596 if ( GEOSEquals_r( geosinit()->ctxt, endCurrentGeomVertex.get(), beginLineVertex.get() ) == 1
2597 || GEOSEquals_r( geosinit()->ctxt, endCurrentGeomVertex.get(), endLineVertex.get() ) == 1 )
2598 nEndpointsSameAsOriginalLine += 1;
2601 bool currentGeomOverlapsOriginalGeom =
false;
2602 bool currentGeomOverlapsReshapeLine =
false;
2603 if ( lineContainedInLine( currentGeom, line ) == 1 )
2604 currentGeomOverlapsOriginalGeom =
true;
2606 if ( lineContainedInLine( currentGeom, reshapeLineGeos ) == 1 )
2607 currentGeomOverlapsReshapeLine =
true;
2610 if ( !isRing && nEndpointsSameAsOriginalLine == 1 && nEndpointsOnOriginalLine == 2 && currentGeomOverlapsOriginalGeom )
2612 resultLineParts.push_back( GEOSGeom_clone_r( geosinit()->ctxt, currentGeom ) );
2615 else if ( isRing && nEndpointsOnOriginalLine == 2 && currentGeomOverlapsOriginalGeom )
2617 probableParts.push_back( GEOSGeom_clone_r( geosinit()->ctxt, currentGeom ) );
2619 else if ( nEndpointsOnOriginalLine == 2 && !currentGeomOverlapsOriginalGeom )
2621 resultLineParts.push_back( GEOSGeom_clone_r( geosinit()->ctxt, currentGeom ) );
2623 else if ( nEndpointsSameAsOriginalLine == 2 && !currentGeomOverlapsOriginalGeom )
2625 resultLineParts.push_back( GEOSGeom_clone_r( geosinit()->ctxt, currentGeom ) );
2627 else if ( currentGeomOverlapsOriginalGeom && currentGeomOverlapsReshapeLine )
2629 resultLineParts.push_back( GEOSGeom_clone_r( geosinit()->ctxt, currentGeom ) );
2634 if ( isRing && !probableParts.isEmpty() )
2637 GEOSGeometry *currentGeom =
nullptr;
2638 double maxLength = -std::numeric_limits<double>::max();
2639 double currentLength = 0;
2640 for (
int i = 0; i < probableParts.size(); ++i )
2642 currentGeom = probableParts.at( i );
2643 GEOSLength_r( geosinit()->ctxt, currentGeom, ¤tLength );
2644 if ( currentLength > maxLength )
2646 maxLength = currentLength;
2647 maxGeom.reset( currentGeom );
2651 GEOSGeom_destroy_r( geosinit()->ctxt, currentGeom );
2654 resultLineParts.push_back( maxGeom.release() );
2658 if ( resultLineParts.empty() )
2661 if ( resultLineParts.size() == 1 )
2663 result.reset( resultLineParts[0] );
2667 GEOSGeometry **lineArray =
new GEOSGeometry*[resultLineParts.size()];
2668 for (
int i = 0; i < resultLineParts.size(); ++i )
2670 lineArray[i] = resultLineParts[i];
2674 geos::unique_ptr multiLineGeom( GEOSGeom_createCollection_r( geosinit()->ctxt, GEOS_MULTILINESTRING, lineArray, resultLineParts.size() ) );
2675 delete [] lineArray;
2678 result.reset( GEOSLineMerge_r( geosinit()->ctxt, multiLineGeom.get() ) );
2682 if ( GEOSGeomTypeId_r( geosinit()->ctxt, result.get() ) != GEOS_LINESTRING )
2690 geos::unique_ptr QgsGeos::reshapePolygon(
const GEOSGeometry *polygon,
const GEOSGeometry *reshapeLineGeos,
double precision )
2693 int nIntersections = 0;
2694 int lastIntersectingRing = -2;
2695 const GEOSGeometry *lastIntersectingGeom =
nullptr;
2697 int nRings = GEOSGetNumInteriorRings_r( geosinit()->ctxt, polygon );
2702 const GEOSGeometry *outerRing = GEOSGetExteriorRing_r( geosinit()->ctxt, polygon );
2703 if ( GEOSIntersects_r( geosinit()->ctxt, outerRing, reshapeLineGeos ) == 1 )
2706 lastIntersectingRing = -1;
2707 lastIntersectingGeom = outerRing;
2711 const GEOSGeometry **innerRings =
new const GEOSGeometry*[nRings];
2715 for (
int i = 0; i < nRings; ++i )
2717 innerRings[i] = GEOSGetInteriorRingN_r( geosinit()->ctxt, polygon, i );
2718 if ( GEOSIntersects_r( geosinit()->ctxt, innerRings[i], reshapeLineGeos ) == 1 )
2721 lastIntersectingRing = i;
2722 lastIntersectingGeom = innerRings[i];
2726 catch ( GEOSException & )
2731 if ( nIntersections != 1 )
2733 delete [] innerRings;
2739 if ( !reshapeResult )
2741 delete [] innerRings;
2746 GEOSGeometry *newRing =
nullptr;
2747 const GEOSCoordSequence *reshapeSequence = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, reshapeResult.get() );
2748 GEOSCoordSequence *newCoordSequence = GEOSCoordSeq_clone_r( geosinit()->ctxt, reshapeSequence );
2750 reshapeResult.reset();
2752 newRing = GEOSGeom_createLinearRing_r( geosinit()->ctxt, newCoordSequence );
2755 delete [] innerRings;
2759 GEOSGeometry *newOuterRing =
nullptr;
2760 if ( lastIntersectingRing == -1 )
2761 newOuterRing = newRing;
2763 newOuterRing = GEOSGeom_clone_r( geosinit()->ctxt, outerRing );
2766 QVector<GEOSGeometry *> ringList;
2769 GEOSGeometry *outerRingPoly = GEOSGeom_createPolygon_r( geosinit()->ctxt, GEOSGeom_clone_r( geosinit()->ctxt, newOuterRing ),
nullptr, 0 );
2770 if ( outerRingPoly )
2772 GEOSGeometry *currentRing =
nullptr;
2773 for (
int i = 0; i < nRings; ++i )
2775 if ( lastIntersectingRing == i )
2776 currentRing = newRing;
2778 currentRing = GEOSGeom_clone_r( geosinit()->ctxt, innerRings[i] );
2781 if ( GEOSContains_r( geosinit()->ctxt, outerRingPoly, currentRing ) == 1 )
2782 ringList.push_back( currentRing );
2784 GEOSGeom_destroy_r( geosinit()->ctxt, currentRing );
2787 GEOSGeom_destroy_r( geosinit()->ctxt, outerRingPoly );
2790 GEOSGeometry **newInnerRings =
new GEOSGeometry*[ringList.size()];
2791 for (
int i = 0; i < ringList.size(); ++i )
2792 newInnerRings[i] = ringList.at( i );
2794 delete [] innerRings;
2796 geos::unique_ptr reshapedPolygon( GEOSGeom_createPolygon_r( geosinit()->ctxt, newOuterRing, newInnerRings, ringList.size() ) );
2797 delete[] newInnerRings;
2799 return reshapedPolygon;
2802 int QgsGeos::lineContainedInLine(
const GEOSGeometry *line1,
const GEOSGeometry *line2 )
2804 if ( !line1 || !line2 )
2809 double bufferDistance = std::pow( 10.0L, geomDigits( line2 ) - 11 );
2815 geos::unique_ptr intersectionGeom( GEOSIntersection_r( geosinit()->ctxt, bufferGeom.get(), line1 ) );
2818 double intersectGeomLength;
2821 GEOSLength_r( geosinit()->ctxt, intersectionGeom.get(), &intersectGeomLength );
2822 GEOSLength_r( geosinit()->ctxt, line1, &line1Length );
2824 double intersectRatio = line1Length / intersectGeomLength;
2825 if ( intersectRatio > 0.9 && intersectRatio < 1.1 )
2831 int QgsGeos::pointContainedInLine(
const GEOSGeometry *point,
const GEOSGeometry *line )
2833 if ( !point || !line )
2836 double bufferDistance = std::pow( 10.0L, geomDigits( line ) - 11 );
2838 geos::unique_ptr lineBuffer( GEOSBuffer_r( geosinit()->ctxt, line, bufferDistance, 8 ) );
2842 bool contained =
false;
2843 if ( GEOSContains_r( geosinit()->ctxt, lineBuffer.get(), point ) == 1 )
2849 int QgsGeos::geomDigits(
const GEOSGeometry *geom )
2855 const GEOSGeometry *bBoxRing = GEOSGetExteriorRing_r( geosinit()->ctxt, bbox.get() );
2859 const GEOSCoordSequence *bBoxCoordSeq = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, bBoxRing );
2861 if ( !bBoxCoordSeq )
2864 unsigned int nCoords = 0;
2865 if ( !GEOSCoordSeq_getSize_r( geosinit()->ctxt, bBoxCoordSeq, &nCoords ) )
2869 for (
unsigned int i = 0; i < nCoords - 1; ++i )
2872 GEOSCoordSeq_getX_r( geosinit()->ctxt, bBoxCoordSeq, i, &t );
2875 digits = std::ceil( std::log10( std::fabs( t ) ) );
2876 if ( digits > maxDigits )
2879 GEOSCoordSeq_getY_r( geosinit()->ctxt, bBoxCoordSeq, i, &t );
2880 digits = std::ceil( std::log10( std::fabs( t ) ) );
2881 if ( digits > maxDigits )
2890 return geosinit()->ctxt;