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 );
 
  163 #if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=8 ) 
  164 std::unique_ptr<QgsAbstractGeometry> QgsGeos::makeValid( QString *errorMsg )
 const 
  174     geos.reset( GEOSMakeValid_r( geosinit()->ctxt, mGeos.get() ) );
 
  202   std::unique_ptr< QgsAbstractGeometry > geom = 
fromGeos( newPart );
 
  209   mGeosPrepared.reset();
 
  222     mGeosPrepared.reset( GEOSPrepare_r( geosinit()->ctxt, mGeos.get() ) );
 
  226 void QgsGeos::cacheGeos()
 const 
  243   return overlay( geom, OverlayIntersection, errorMsg ).release();
 
  248   return overlay( geom, OverlayDifference, errorMsg ).release();
 
  263   catch ( GEOSException &e )
 
  265     logError( QStringLiteral( 
"GEOS" ), e.what() );
 
  268       *errorMsg = e.what();
 
  279   int partType = GEOSGeomTypeId_r( geosinit()->ctxt, currentPart );
 
  282     if ( partType == GEOS_POINT )
 
  293   if ( partType == GEOS_MULTILINESTRING || partType == GEOS_MULTIPOLYGON || partType == GEOS_GEOMETRYCOLLECTION )
 
  295     int partCount = GEOSGetNumGeometries_r( geosinit()->ctxt, currentPart );
 
  296     for ( 
int i = 0; i < partCount; ++i )
 
  298       subdivideRecursive( GEOSGetGeometryN_r( geosinit()->ctxt, currentPart, i ), maxNodes, depth, parts, clipRect );
 
  309   int vertexCount = GEOSGetNumCoordinates_r( geosinit()->ctxt, currentPart );
 
  310   if ( vertexCount == 0 )
 
  314   else if ( vertexCount < maxNodes )
 
  321   double width = clipRect.
width();
 
  322   double height = clipRect.
height();
 
  325   if ( width > height )
 
  338     halfClipRect1.
setYMinimum( halfClipRect1.
yMinimum() - std::numeric_limits<double>::epsilon() );
 
  339     halfClipRect2.
setYMinimum( halfClipRect2.
yMinimum() - std::numeric_limits<double>::epsilon() );
 
  340     halfClipRect1.
setYMaximum( halfClipRect1.
yMaximum() + std::numeric_limits<double>::epsilon() );
 
  341     halfClipRect2.
setYMaximum( halfClipRect2.
yMaximum() + std::numeric_limits<double>::epsilon() );
 
  345     halfClipRect1.
setXMinimum( halfClipRect1.
xMinimum() - std::numeric_limits<double>::epsilon() );
 
  346     halfClipRect2.
setXMinimum( halfClipRect2.
xMinimum() - std::numeric_limits<double>::epsilon() );
 
  347     halfClipRect1.
setXMaximum( halfClipRect1.
xMaximum() + std::numeric_limits<double>::epsilon() );
 
  348     halfClipRect2.
setXMaximum( halfClipRect2.
xMaximum() + std::numeric_limits<double>::epsilon() );
 
  358     subdivideRecursive( clipPart1.get(), maxNodes, depth, parts, halfClipRect1 );
 
  362     subdivideRecursive( clipPart2.get(), maxNodes, depth, parts, halfClipRect2 );
 
  374   maxNodes = std::max( maxNodes, 8 );
 
  383   return std::move( parts );
 
  388   return overlay( geom, OverlayUnion, errorMsg ).release();
 
  393   QVector< GEOSGeometry * > geosGeometries;
 
  394   geosGeometries.reserve( geomList.size() );
 
  400     geosGeometries << 
asGeos( g, mPrecision ).release();
 
  406     geos::unique_ptr geomCollection = createGeosCollection( GEOS_GEOMETRYCOLLECTION, geosGeometries );
 
  407     geomUnion.reset( GEOSUnaryUnion_r( geosinit()->ctxt, geomCollection.get() ) );
 
  411   std::unique_ptr< QgsAbstractGeometry > result = 
fromGeos( geomUnion.get() );
 
  412   return result.release();
 
  417   QVector< GEOSGeometry * > geosGeometries;
 
  418   geosGeometries.reserve( geomList.size() );
 
  424     geosGeometries << 
asGeos( g.constGet(), mPrecision ).release();
 
  430     geos::unique_ptr geomCollection = createGeosCollection( GEOS_GEOMETRYCOLLECTION, geosGeometries );
 
  431     geomUnion.reset( GEOSUnaryUnion_r( geosinit()->ctxt, geomCollection.get() ) );
 
  435   std::unique_ptr< QgsAbstractGeometry > result = 
fromGeos( geomUnion.get() );
 
  436   return result.release();
 
  441   return overlay( geom, OverlaySymDifference, errorMsg ).release();
 
  453   if ( !otherGeosGeom )
 
  460 #if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=9 ) 
  463       GEOSPreparedDistance_r( geosinit()->ctxt, mGeosPrepared.get(), otherGeosGeom.get(), &
distance );
 
  467       GEOSDistance_r( geosinit()->ctxt, mGeos.get(), otherGeosGeom.get(), &
distance );
 
  470     GEOSDistance_r( geosinit()->ctxt, mGeos.get(), otherGeosGeom.get(), &
distance );
 
  486   if ( !otherGeosGeom )
 
  499 #if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=9 ) 
  502 #if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=10 ) 
  503       return GEOSPreparedDistanceWithin_r( geosinit()->ctxt, mGeosPrepared.get(), otherGeosGeom.get(), maxdist );
 
  505       GEOSPreparedDistance_r( geosinit()->ctxt, mGeosPrepared.get(), otherGeosGeom.get(), &
distance );
 
  510 #if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=10 ) 
  511       return GEOSDistanceWithin_r( geosinit()->ctxt, mGeos.get(), otherGeosGeom.get(), maxdist );
 
  513       GEOSDistance_r( geosinit()->ctxt, mGeos.get(), otherGeosGeom.get(), &
distance );
 
  517     GEOSDistance_r( geosinit()->ctxt, mGeos.get(), otherGeosGeom.get(), &
distance );
 
  534   if ( !otherGeosGeom )
 
  541     GEOSHausdorffDistance_r( geosinit()->ctxt, mGeos.get(), otherGeosGeom.get(), &
distance );
 
  557   if ( !otherGeosGeom )
 
  564     GEOSHausdorffDistanceDensify_r( geosinit()->ctxt, mGeos.get(), otherGeosGeom.get(), densifyFraction, &
distance );
 
  573 #if GEOS_VERSION_MAJOR==3 && GEOS_VERSION_MINOR<7 
  576   throw QgsNotSupportedException( QStringLiteral( 
"Calculating frechetDistance requires a QGIS build based on GEOS 3.7 or later" ) );
 
  585   if ( !otherGeosGeom )
 
  592     GEOSFrechetDistance_r( geosinit()->ctxt, mGeos.get(), otherGeosGeom.get(), &
distance );
 
  602 #if GEOS_VERSION_MAJOR==3 && GEOS_VERSION_MINOR<7 
  604   ( void )densifyFraction;
 
  606   throw QgsNotSupportedException( QStringLiteral( 
"Calculating frechetDistanceDensify requires a QGIS build based on GEOS 3.7 or later" ) );
 
  615   if ( !otherGeosGeom )
 
  622     GEOSFrechetDistanceDensify_r( geosinit()->ctxt, mGeos.get(), otherGeosGeom.get(), densifyFraction, &
distance );
 
  632   return relation( geom, RelationIntersects, errorMsg );
 
  637   return relation( geom, RelationTouches, errorMsg );
 
  642   return relation( geom, RelationCrosses, errorMsg );
 
  647   return relation( geom, RelationWithin, errorMsg );
 
  652   return relation( geom, RelationOverlaps, errorMsg );
 
  657   return relation( geom, RelationContains, errorMsg );
 
  662   return relation( geom, RelationDisjoint, errorMsg );
 
  681     char *r = GEOSRelate_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() );
 
  684       result = QString( r );
 
  685       GEOSFree_r( geosinit()->ctxt, r );
 
  688   catch ( GEOSException &e )
 
  690     logError( QStringLiteral( 
"GEOS" ), e.what() );
 
  693       *errorMsg = e.what();
 
  702   if ( !mGeos || !geom )
 
  716     result = ( GEOSRelatePattern_r( geosinit()->ctxt, mGeos.get(), geosGeom.get(), pattern.toLocal8Bit().constData() ) == 1 );
 
  718   catch ( GEOSException &e )
 
  720     logError( QStringLiteral( 
"GEOS" ), e.what() );
 
  723       *errorMsg = e.what();
 
  740     if ( GEOSArea_r( geosinit()->ctxt, mGeos.get(), &
area ) != 1 )
 
  756     if ( GEOSLength_r( geosinit()->ctxt, mGeos.get(), &
length ) != 1 )
 
  764     QVector<QgsGeometry> &newGeometries,
 
  767     QString *errorMsg, 
bool skipIntersectionCheck )
 const 
  782   if ( !GEOSisValid_r( geosinit()->ctxt, mGeos.get() ) )
 
  790   newGeometries.clear();
 
  797       splitLineGeos = createGeosLinestring( &splitLine, mPrecision );
 
  801       splitLineGeos = createGeosPointXY( splitLine.
xAt( 0 ), splitLine.
yAt( 0 ), 
false, 0, 
false, 0, 2, mPrecision );
 
  808     if ( !GEOSisValid_r( geosinit()->ctxt, splitLineGeos.get() ) || !GEOSisSimple_r( geosinit()->ctxt, splitLineGeos.get() ) )
 
  816       if ( !topologicalTestPointsSplit( splitLineGeos.get(), topologyTestPoints ) )
 
  825       returnCode = splitLinearGeometry( splitLineGeos.get(), newGeometries, skipIntersectionCheck );
 
  829       returnCode = splitPolygonGeometry( splitLineGeos.get(), newGeometries, skipIntersectionCheck );
 
  843 bool QgsGeos::topologicalTestPointsSplit( 
const GEOSGeometry *splitLine, 
QgsPointSequence &testPoints, QString *errorMsg )
 const 
  857     geos::unique_ptr intersectionGeom( GEOSIntersection_r( geosinit()->ctxt, mGeos.get(), splitLine ) );
 
  858     if ( !intersectionGeom )
 
  862     int nIntersectGeoms = 1;
 
  863     if ( GEOSGeomTypeId_r( geosinit()->ctxt, intersectionGeom.get() ) == GEOS_LINESTRING
 
  864          || GEOSGeomTypeId_r( geosinit()->ctxt, intersectionGeom.get() ) == GEOS_POINT )
 
  868       nIntersectGeoms = GEOSGetNumGeometries_r( geosinit()->ctxt, intersectionGeom.get() );
 
  870     for ( 
int i = 0; i < nIntersectGeoms; ++i )
 
  872       const GEOSGeometry *currentIntersectGeom = 
nullptr;
 
  874         currentIntersectGeom = intersectionGeom.get();
 
  876         currentIntersectGeom = GEOSGetGeometryN_r( geosinit()->ctxt, intersectionGeom.get(), i );
 
  878       const GEOSCoordSequence *lineSequence = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, currentIntersectGeom );
 
  879       unsigned int sequenceSize = 0;
 
  881       if ( GEOSCoordSeq_getSize_r( geosinit()->ctxt, lineSequence, &sequenceSize ) != 0 )
 
  883         for ( 
unsigned int i = 0; i < sequenceSize; ++i )
 
  885           if ( GEOSCoordSeq_getX_r( geosinit()->ctxt, lineSequence, i, &x ) != 0 )
 
  887             if ( GEOSCoordSeq_getY_r( geosinit()->ctxt, lineSequence, i, &y ) != 0 )
 
  889               testPoints.push_back( 
QgsPoint( x, y ) );
 
  903   int type = GEOSGeomTypeId_r( geosinit()->ctxt, mGeos.get() );
 
  905   std::unique_ptr< QgsMultiCurve > multiCurve;
 
  906   if ( type == GEOS_MULTILINESTRING )
 
  908     multiCurve.reset( qgsgeometry_cast<QgsMultiCurve *>( 
mGeometry->
clone() ) );
 
  910   else if ( type == GEOS_LINESTRING )
 
  926   std::unique_ptr< QgsAbstractGeometry > splitGeom( 
fromGeos( GEOSsplitPoint ) );
 
  927   QgsPoint *splitPoint = qgsgeometry_cast<QgsPoint *>( splitGeom.get() );
 
  936   for ( 
int i = 0; i < multiCurve->numGeometries(); ++i )
 
  938     const QgsLineString *line = qgsgeometry_cast<const QgsLineString *>( multiCurve->geometryN( i ) );
 
  945       for ( 
int j = 1; j < ( nVertices - 1 ); ++j )
 
  949         if ( currentPoint == *splitPoint )
 
  961   return asGeos( &lines, mPrecision );
 
  973   if ( !skipIntersectionCheck && !GEOSIntersects_r( geosinit()->ctxt, splitLine, mGeos.get() ) )
 
  977   int linearIntersect = GEOSRelatePattern_r( geosinit()->ctxt, mGeos.get(), splitLine, 
"1********" );
 
  978   if ( linearIntersect > 0 )
 
  981   int splitGeomType = GEOSGeomTypeId_r( geosinit()->ctxt, splitLine );
 
  984   if ( splitGeomType == GEOS_POINT )
 
  986     splitGeom = linePointDifference( splitLine );
 
  990     splitGeom.reset( GEOSDifference_r( geosinit()->ctxt, mGeos.get(), splitLine ) );
 
  992   QVector<GEOSGeometry *> lineGeoms;
 
  994   int splitType = GEOSGeomTypeId_r( geosinit()->ctxt, splitGeom.get() );
 
  995   if ( splitType == GEOS_MULTILINESTRING )
 
  997     int nGeoms = GEOSGetNumGeometries_r( geosinit()->ctxt, splitGeom.get() );
 
  998     lineGeoms.reserve( nGeoms );
 
  999     for ( 
int i = 0; i < nGeoms; ++i )
 
 1000       lineGeoms << GEOSGeom_clone_r( geosinit()->ctxt, GEOSGetGeometryN_r( geosinit()->ctxt, splitGeom.get(), i ) );
 
 1005     lineGeoms << GEOSGeom_clone_r( geosinit()->ctxt, splitGeom.get() );
 
 1008   mergeGeometriesMultiTypeSplit( lineGeoms );
 
 1010   for ( 
int i = 0; i < lineGeoms.size(); ++i )
 
 1013     GEOSGeom_destroy_r( geosinit()->ctxt, lineGeoms[i] );
 
 1029   if ( !mGeosPrepared )
 
 1033   if ( !skipIntersectionCheck && !GEOSPreparedIntersects_r( geosinit()->ctxt, mGeosPrepared.get(), splitLine ) )
 
 1038   if ( !nodedGeometry )
 
 1041   const GEOSGeometry *noded = nodedGeometry.get();
 
 1042   geos::unique_ptr polygons( GEOSPolygonize_r( geosinit()->ctxt, &noded, 1 ) );
 
 1043   if ( !polygons || numberOfGeometries( polygons.get() ) == 0 )
 
 1050   QVector<GEOSGeometry *> testedGeometries;
 
 1055   for ( 
int i = 0; i < numberOfGeometries( polygons.get() ); i++ )
 
 1057     const GEOSGeometry *polygon = GEOSGetGeometryN_r( geosinit()->ctxt, polygons.get(), i );
 
 1061       testedGeometries << GEOSGeom_clone_r( geosinit()->ctxt, polygon );
 
 1064   int nGeometriesThis = numberOfGeometries( mGeos.get() ); 
 
 1065   if ( testedGeometries.empty() || testedGeometries.size() == nGeometriesThis )
 
 1068     for ( 
int i = 0; i < testedGeometries.size(); ++i )
 
 1070       GEOSGeom_destroy_r( geosinit()->ctxt, testedGeometries[i] );
 
 1079   mergeGeometriesMultiTypeSplit( testedGeometries );
 
 1082   for ( i = 0; i < testedGeometries.size() && GEOSisValid_r( geosinit()->ctxt, testedGeometries[i] ); ++i )
 
 1085   if ( i < testedGeometries.size() )
 
 1087     for ( i = 0; i < testedGeometries.size(); ++i )
 
 1088       GEOSGeom_destroy_r( geosinit()->ctxt, testedGeometries[i] );
 
 1093   for ( i = 0; i < testedGeometries.size(); ++i )
 
 1096     GEOSGeom_destroy_r( geosinit()->ctxt, testedGeometries[i] );
 
 1102 geos::unique_ptr QgsGeos::nodeGeometries( 
const GEOSGeometry *splitLine, 
const GEOSGeometry *geom )
 
 1104   if ( !splitLine || !geom )
 
 1108   if ( GEOSGeomTypeId_r( geosinit()->ctxt, geom ) == GEOS_POLYGON || GEOSGeomTypeId_r( geosinit()->ctxt, geom ) == GEOS_MULTIPOLYGON )
 
 1109     geometryBoundary.reset( GEOSBoundary_r( geosinit()->ctxt, geom ) );
 
 1111     geometryBoundary.reset( GEOSGeom_clone_r( geosinit()->ctxt, geom ) );
 
 1113   geos::unique_ptr splitLineClone( GEOSGeom_clone_r( geosinit()->ctxt, splitLine ) );
 
 1114   geos::unique_ptr unionGeometry( GEOSUnion_r( geosinit()->ctxt, splitLineClone.get(), geometryBoundary.get() ) );
 
 1116   return unionGeometry;
 
 1119 int QgsGeos::mergeGeometriesMultiTypeSplit( QVector<GEOSGeometry *> &splitResult )
 const 
 1125   int type = GEOSGeomTypeId_r( geosinit()->ctxt, mGeos.get() );
 
 1126   if ( type != GEOS_GEOMETRYCOLLECTION &&
 
 1127        type != GEOS_MULTILINESTRING &&
 
 1128        type != GEOS_MULTIPOLYGON &&
 
 1129        type != GEOS_MULTIPOINT )
 
 1132   QVector<GEOSGeometry *> copyList = splitResult;
 
 1133   splitResult.clear();
 
 1136   QVector<GEOSGeometry *> unionGeom;
 
 1138   for ( 
int i = 0; i < copyList.size(); ++i )
 
 1141     bool isPart = 
false;
 
 1142     for ( 
int j = 0; j < GEOSGetNumGeometries_r( geosinit()->ctxt, mGeos.get() ); j++ )
 
 1144       if ( GEOSEquals_r( geosinit()->ctxt, copyList[i], GEOSGetGeometryN_r( geosinit()->ctxt, mGeos.get(), j ) ) )
 
 1153       unionGeom << copyList[i];
 
 1157       QVector<GEOSGeometry *> geomVector;
 
 1158       geomVector << copyList[i];
 
 1160       if ( type == GEOS_MULTILINESTRING )
 
 1161         splitResult << createGeosCollection( GEOS_MULTILINESTRING, geomVector ).release();
 
 1162       else if ( type == GEOS_MULTIPOLYGON )
 
 1163         splitResult << createGeosCollection( GEOS_MULTIPOLYGON, geomVector ).release();
 
 1165         GEOSGeom_destroy_r( geosinit()->ctxt, copyList[i] );
 
 1170   if ( !unionGeom.isEmpty() )
 
 1172     if ( type == GEOS_MULTILINESTRING )
 
 1173       splitResult << createGeosCollection( GEOS_MULTILINESTRING, unionGeom ).release();
 
 1174     else if ( type == GEOS_MULTIPOLYGON )
 
 1175       splitResult << createGeosCollection( GEOS_MULTIPOLYGON, unionGeom ).release();
 
 1185 geos::unique_ptr QgsGeos::createGeosCollection( 
int typeId, 
const QVector<GEOSGeometry *> &geoms )
 
 1187   int nNullGeoms = geoms.count( 
nullptr );
 
 1188   int nNotNullGeoms = geoms.size() - nNullGeoms;
 
 1190   GEOSGeometry **geomarr = 
new GEOSGeometry*[ nNotNullGeoms ];
 
 1197   QVector<GEOSGeometry *>::const_iterator geomIt = geoms.constBegin();
 
 1198   for ( ; geomIt != geoms.constEnd(); ++geomIt )
 
 1202       if ( GEOSisEmpty_r( geosinit()->ctxt, *geomIt ) )
 
 1207         GEOSGeom_destroy_r( geosinit()->ctxt, *geomIt );
 
 1211         geomarr[i] = *geomIt;
 
 1220     geom.reset( GEOSGeom_createCollection_r( geosinit()->ctxt, typeId, geomarr, nNotNullGeoms ) );
 
 1222   catch ( GEOSException & )
 
 1238   int nCoordDims = GEOSGeom_getCoordinateDimension_r( geosinit()->ctxt, 
geos );
 
 1239   int nDims = GEOSGeom_getDimensions_r( geosinit()->ctxt, 
geos );
 
 1240   bool hasZ = ( nCoordDims == 3 );
 
 1241   bool hasM = ( ( nDims - nCoordDims ) == 1 );
 
 1243   switch ( GEOSGeomTypeId_r( geosinit()->ctxt, 
geos ) )
 
 1247       if ( GEOSisEmpty_r( geosinit()->ctxt, 
geos ) )
 
 1250       const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, 
geos );
 
 1251       unsigned int nPoints = 0;
 
 1252       GEOSCoordSeq_getSize_r( geosinit()->ctxt, cs, &nPoints );
 
 1253       return  nPoints > 0 ? std::unique_ptr<QgsAbstractGeometry>( 
coordSeqPoint( cs, 0, hasZ, hasM ).clone() ) : std::make_unique< QgsPoint >();
 
 1255     case GEOS_LINESTRING:
 
 1257       return sequenceToLinestring( 
geos, hasZ, hasM );
 
 1263     case GEOS_MULTIPOINT:
 
 1265       std::unique_ptr< QgsMultiPoint > multiPoint( 
new QgsMultiPoint() );
 
 1266       int nParts = GEOSGetNumGeometries_r( geosinit()->ctxt, 
geos );
 
 1267       multiPoint->reserve( nParts );
 
 1268       for ( 
int i = 0; i < nParts; ++i )
 
 1270         const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, GEOSGetGeometryN_r( geosinit()->ctxt, 
geos, i ) );
 
 1273           unsigned int nPoints = 0;
 
 1274           GEOSCoordSeq_getSize_r( geosinit()->ctxt, cs, &nPoints );
 
 1276             multiPoint->addGeometry( 
coordSeqPoint( cs, 0, hasZ, hasM ).clone() );
 
 1279       return std::move( multiPoint );
 
 1281     case GEOS_MULTILINESTRING:
 
 1284       int nParts = GEOSGetNumGeometries_r( geosinit()->ctxt, 
geos );
 
 1285       multiLineString->reserve( nParts );
 
 1286       for ( 
int i = 0; i < nParts; ++i )
 
 1288         std::unique_ptr< QgsLineString >line( sequenceToLinestring( GEOSGetGeometryN_r( geosinit()->ctxt, 
geos, i ), hasZ, hasM ) );
 
 1291           multiLineString->addGeometry( line.release() );
 
 1294       return std::move( multiLineString );
 
 1296     case GEOS_MULTIPOLYGON:
 
 1298       std::unique_ptr< QgsMultiPolygon > multiPolygon( 
new QgsMultiPolygon() );
 
 1300       int nParts = GEOSGetNumGeometries_r( geosinit()->ctxt, 
geos );
 
 1301       multiPolygon->reserve( nParts );
 
 1302       for ( 
int i = 0; i < nParts; ++i )
 
 1304         std::unique_ptr< QgsPolygon > poly = 
fromGeosPolygon( GEOSGetGeometryN_r( geosinit()->ctxt, 
geos, i ) );
 
 1307           multiPolygon->addGeometry( poly.release() );
 
 1310       return std::move( multiPolygon );
 
 1312     case GEOS_GEOMETRYCOLLECTION:
 
 1315       int nParts = GEOSGetNumGeometries_r( geosinit()->ctxt, 
geos );
 
 1316       geomCollection->reserve( nParts );
 
 1317       for ( 
int i = 0; i < nParts; ++i )
 
 1319         std::unique_ptr< QgsAbstractGeometry > geom( 
fromGeos( GEOSGetGeometryN_r( geosinit()->ctxt, 
geos, i ) ) );
 
 1322           geomCollection->addGeometry( geom.release() );
 
 1325       return std::move( geomCollection );
 
 1333   if ( GEOSGeomTypeId_r( geosinit()->ctxt, 
geos ) != GEOS_POLYGON )
 
 1338   int nCoordDims = GEOSGeom_getCoordinateDimension_r( geosinit()->ctxt, 
geos );
 
 1339   int nDims = GEOSGeom_getDimensions_r( geosinit()->ctxt, 
geos );
 
 1340   bool hasZ = ( nCoordDims == 3 );
 
 1341   bool hasM = ( ( nDims - nCoordDims ) == 1 );
 
 1343   std::unique_ptr< QgsPolygon > polygon( 
new QgsPolygon() );
 
 1345   const GEOSGeometry *ring = GEOSGetExteriorRing_r( geosinit()->ctxt, 
geos );
 
 1348     polygon->setExteriorRing( sequenceToLinestring( ring, hasZ, hasM ).release() );
 
 1351   QVector<QgsCurve *> interiorRings;
 
 1352   const int ringCount = GEOSGetNumInteriorRings_r( geosinit()->ctxt, 
geos );
 
 1353   interiorRings.reserve( ringCount );
 
 1354   for ( 
int i = 0; i < ringCount; ++i )
 
 1356     ring = GEOSGetInteriorRingN_r( geosinit()->ctxt, 
geos, i );
 
 1359       interiorRings.push_back( sequenceToLinestring( ring, hasZ, hasM ).release() );
 
 1362   polygon->setInteriorRings( interiorRings );
 
 1367 std::unique_ptr<QgsLineString> QgsGeos::sequenceToLinestring( 
const GEOSGeometry *
geos, 
bool hasZ, 
bool hasM )
 
 1369   const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, 
geos );
 
 1370   unsigned int nPoints;
 
 1371   GEOSCoordSeq_getSize_r( geosinit()->ctxt, cs, &nPoints );
 
 1372   QVector< double > xOut( nPoints );
 
 1373   QVector< double > yOut( nPoints );
 
 1374   QVector< double > zOut;
 
 1376     zOut.resize( nPoints );
 
 1377   QVector< double > mOut;
 
 1379     mOut.resize( nPoints );
 
 1380   double *x = xOut.data();
 
 1381   double *y = yOut.data();
 
 1382   double *z = zOut.data();
 
 1383   double *m = mOut.data();
 
 1384   for ( 
unsigned int i = 0; i < nPoints; ++i )
 
 1386 #if GEOS_VERSION_MAJOR>3 || GEOS_VERSION_MINOR>=8 
 1388       GEOSCoordSeq_getXYZ_r( geosinit()->ctxt, cs, i, x++, y++, z++ );
 
 1390       GEOSCoordSeq_getXY_r( geosinit()->ctxt, cs, i, x++, y++ );
 
 1392     GEOSCoordSeq_getX_r( geosinit()->ctxt, cs, i, x++ );
 
 1393     GEOSCoordSeq_getY_r( geosinit()->ctxt, cs, i, y++ );
 
 1396       GEOSCoordSeq_getZ_r( geosinit()->ctxt, cs, i, z++ );
 
 1401       GEOSCoordSeq_getOrdinate_r( geosinit()->ctxt, cs, i, 3, m++ );
 
 1404   std::unique_ptr< QgsLineString > line( 
new QgsLineString( xOut, yOut, zOut, mOut ) );
 
 1408 int QgsGeos::numberOfGeometries( GEOSGeometry *g )
 
 1413   int geometryType = GEOSGeomTypeId_r( geosinit()->ctxt, g );
 
 1414   if ( geometryType == GEOS_POINT || geometryType == GEOS_LINESTRING || geometryType == GEOS_LINEARRING
 
 1415        || geometryType == GEOS_POLYGON )
 
 1419   return GEOSGetNumGeometries_r( geosinit()->ctxt, g );
 
 1432 #if GEOS_VERSION_MAJOR>3 || GEOS_VERSION_MINOR>=8 
 1434     GEOSCoordSeq_getXYZ_r( geosinit()->ctxt, cs, i, &x, &y, &z );
 
 1436     GEOSCoordSeq_getXY_r( geosinit()->ctxt, cs, i, &x, &y );
 
 1438   GEOSCoordSeq_getX_r( geosinit()->ctxt, cs, i, &x );
 
 1439   GEOSCoordSeq_getY_r( geosinit()->ctxt, cs, i, &y );
 
 1442     GEOSCoordSeq_getZ_r( geosinit()->ctxt, cs, i, &z );
 
 1447     GEOSCoordSeq_getOrdinate_r( geosinit()->ctxt, cs, i, 3, &m );
 
 1483     int geosType = GEOS_GEOMETRYCOLLECTION;
 
 1490           geosType = GEOS_MULTIPOINT;
 
 1494           geosType = GEOS_MULTILINESTRING;
 
 1498           geosType = GEOS_MULTIPOLYGON;
 
 1513     QVector< GEOSGeometry * > geomVector( 
c->numGeometries() );
 
 1514     for ( 
int i = 0; i < 
c->numGeometries(); ++i )
 
 1518     return createGeosCollection( geosType, geomVector );
 
 1525         return createGeosPoint( 
static_cast<const QgsPoint *
>( geom ), coordDims, 
precision );
 
 1541 std::unique_ptr<QgsAbstractGeometry> QgsGeos::overlay( 
const QgsAbstractGeometry *geom, Overlay op, QString *errorMsg )
 const 
 1543   if ( !mGeos || !geom )
 
 1559       case OverlayIntersection:
 
 1560         opGeom.reset( GEOSIntersection_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) );
 
 1563       case OverlayDifference:
 
 1564         opGeom.reset( GEOSDifference_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) );
 
 1569         geos::unique_ptr unionGeometry( GEOSUnion_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) );
 
 1571         if ( unionGeometry && GEOSGeomTypeId_r( geosinit()->ctxt, unionGeometry.get() ) == GEOS_MULTILINESTRING )
 
 1573           geos::unique_ptr mergedLines( GEOSLineMerge_r( geosinit()->ctxt, unionGeometry.get() ) );
 
 1576             unionGeometry = std::move( mergedLines );
 
 1580         opGeom = std::move( unionGeometry );
 
 1584       case OverlaySymDifference:
 
 1585         opGeom.reset( GEOSSymDifference_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) );
 
 1590   catch ( GEOSException &e )
 
 1592     logError( QStringLiteral( 
"GEOS" ), e.what() );
 
 1595       *errorMsg = e.what();
 
 1601 bool QgsGeos::relation( 
const QgsAbstractGeometry *geom, Relation r, QString *errorMsg )
 const 
 1603   if ( !mGeos || !geom )
 
 1614   bool result = 
false;
 
 1617     if ( mGeosPrepared ) 
 
 1621         case RelationIntersects:
 
 1622           result = ( GEOSPreparedIntersects_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
 
 1624         case RelationTouches:
 
 1625           result = ( GEOSPreparedTouches_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
 
 1627         case RelationCrosses:
 
 1628           result = ( GEOSPreparedCrosses_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
 
 1630         case RelationWithin:
 
 1631           result = ( GEOSPreparedWithin_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
 
 1633         case RelationContains:
 
 1634           result = ( GEOSPreparedContains_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
 
 1636         case RelationDisjoint:
 
 1637           result = ( GEOSPreparedDisjoint_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
 
 1639         case RelationOverlaps:
 
 1640           result = ( GEOSPreparedOverlaps_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
 
 1648       case RelationIntersects:
 
 1649         result = ( GEOSIntersects_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
 
 1651       case RelationTouches:
 
 1652         result = ( GEOSTouches_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
 
 1654       case RelationCrosses:
 
 1655         result = ( GEOSCrosses_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
 
 1657       case RelationWithin:
 
 1658         result = ( GEOSWithin_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
 
 1660       case RelationContains:
 
 1661         result = ( GEOSContains_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
 
 1663       case RelationDisjoint:
 
 1664         result = ( GEOSDisjoint_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
 
 1666       case RelationOverlaps:
 
 1667         result = ( GEOSOverlaps_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
 
 1671   catch ( GEOSException &e )
 
 1673     logError( QStringLiteral( 
"GEOS" ), e.what() );
 
 1676       *errorMsg = e.what();
 
 1694     geos.reset( GEOSBuffer_r( geosinit()->ctxt, mGeos.get(), 
distance, segments ) );
 
 1710     geos.reset( GEOSBufferWithStyle_r( geosinit()->ctxt, mGeos.get(), 
distance, segments, 
static_cast< int >( endCapStyle ), 
static_cast< int >( joinStyle ), miterLimit ) );
 
 1725     geos.reset( GEOSTopologyPreserveSimplify_r( geosinit()->ctxt, mGeos.get(), tolerance ) );
 
 1740     geos.reset( GEOSInterpolate_r( geosinit()->ctxt, mGeos.get(), 
distance ) );
 
 1759     geos.reset( GEOSGetCentroid_r( geosinit()->ctxt,  mGeos.get() ) );
 
 1764     GEOSGeomGetX_r( geosinit()->ctxt, 
geos.get(), &x );
 
 1765     GEOSGeomGetY_r( geosinit()->ctxt, 
geos.get(), &y );
 
 1781     geos.reset( GEOSEnvelope_r( geosinit()->ctxt, mGeos.get() ) );
 
 1800     geos.reset( GEOSPointOnSurface_r( geosinit()->ctxt, mGeos.get() ) );
 
 1802     if ( !
geos || GEOSisEmpty_r( geosinit()->ctxt, 
geos.get() ) != 0 )
 
 1807     GEOSGeomGetX_r( geosinit()->ctxt, 
geos.get(), &x );
 
 1808     GEOSGeomGetY_r( geosinit()->ctxt, 
geos.get(), &y );
 
 1824     geos::unique_ptr cHull( GEOSConvexHull_r( geosinit()->ctxt, mGeos.get() ) );
 
 1825     std::unique_ptr< QgsAbstractGeometry > cHullGeom = 
fromGeos( cHull.get() );
 
 1826     return cHullGeom.release();
 
 1840     GEOSGeometry *g1 = 
nullptr;
 
 1842     char res = GEOSisValidDetail_r( geosinit()->ctxt, mGeos.get(), allowSelfTouchingHoles ? GEOSVALID_ALLOW_SELFTOUCHING_RING_FORMING_HOLE : 0, &r, &g1 );
 
 1843     const bool invalid = res != 1;
 
 1848       error = QString( r );
 
 1849       GEOSFree_r( geosinit()->ctxt, r );
 
 1852     if ( invalid && errorMsg )
 
 1856       if ( translatedErrors.empty() )
 
 1859         translatedErrors.insert( QStringLiteral( 
"topology validation error" ), QObject::tr( 
"Topology validation error", 
"GEOS Error" ) );
 
 1860         translatedErrors.insert( QStringLiteral( 
"repeated point" ), QObject::tr( 
"Repeated point", 
"GEOS Error" ) );
 
 1861         translatedErrors.insert( QStringLiteral( 
"hole lies outside shell" ), QObject::tr( 
"Hole lies outside shell", 
"GEOS Error" ) );
 
 1862         translatedErrors.insert( QStringLiteral( 
"holes are nested" ), QObject::tr( 
"Holes are nested", 
"GEOS Error" ) );
 
 1863         translatedErrors.insert( QStringLiteral( 
"interior is disconnected" ), QObject::tr( 
"Interior is disconnected", 
"GEOS Error" ) );
 
 1864         translatedErrors.insert( QStringLiteral( 
"self-intersection" ), QObject::tr( 
"Self-intersection", 
"GEOS Error" ) );
 
 1865         translatedErrors.insert( QStringLiteral( 
"ring self-intersection" ), QObject::tr( 
"Ring self-intersection", 
"GEOS Error" ) );
 
 1866         translatedErrors.insert( QStringLiteral( 
"nested shells" ), QObject::tr( 
"Nested shells", 
"GEOS Error" ) );
 
 1867         translatedErrors.insert( QStringLiteral( 
"duplicate rings" ), QObject::tr( 
"Duplicate rings", 
"GEOS Error" ) );
 
 1868         translatedErrors.insert( QStringLiteral( 
"too few points in geometry component" ), QObject::tr( 
"Too few points in geometry component", 
"GEOS Error" ) );
 
 1869         translatedErrors.insert( QStringLiteral( 
"invalid coordinate" ), QObject::tr( 
"Invalid coordinate", 
"GEOS Error" ) );
 
 1870         translatedErrors.insert( QStringLiteral( 
"ring is not closed" ), QObject::tr( 
"Ring is not closed", 
"GEOS Error" ) );
 
 1873       *errorMsg = translatedErrors.value( error.toLower(), error );
 
 1875       if ( g1 && errorLoc )
 
 1881         GEOSGeom_destroy_r( geosinit()->ctxt, g1 );
 
 1891   if ( !mGeos || !geom )
 
 1903     bool equal = GEOSEquals_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() );
 
 1918     return GEOSisEmpty_r( geosinit()->ctxt, mGeos.get() );
 
 1932     return GEOSisSimple_r( geosinit()->ctxt, mGeos.get() );
 
 1937 GEOSCoordSequence *QgsGeos::createCoordinateSequence( 
const QgsCurve *curve, 
double precision, 
bool forceClose )
 
 1939   std::unique_ptr< QgsLineString > segmentized;
 
 1940   const QgsLineString *line = qgsgeometry_cast<const QgsLineString *>( curve );
 
 1945     line = segmentized.get();
 
 1953   bool hasZ = line->
is3D();
 
 1967   int numOutPoints = numPoints;
 
 1968   if ( forceClose && ( line->
pointN( 0 ) != line->
pointN( numPoints - 1 ) ) )
 
 1973   GEOSCoordSequence *coordSeq = 
nullptr;
 
 1976     coordSeq = GEOSCoordSeq_create_r( geosinit()->ctxt, numOutPoints, coordDims );
 
 1979       QgsDebugMsg( QStringLiteral( 
"GEOS Exception: Could not create coordinate sequence for %1 points in %2 dimensions" ).arg( numPoints ).arg( coordDims ) );
 
 1983     const double *xData = line->
xData();
 
 1984     const double *yData = line->
yData();
 
 1985     const double *zData = hasZ ? line->
zData() : 
nullptr;
 
 1986     const double *mData = hasM ? line->
mData() : 
nullptr;
 
 1990       for ( 
int i = 0; i < numOutPoints; ++i )
 
 1992         if ( i >= numPoints )
 
 1995           xData = line->
xData();
 
 1996           yData = line->
yData();
 
 1997           zData = hasZ ? line->
zData() : 
nullptr;
 
 1998           mData = hasM ? line->
mData() : 
nullptr;
 
 2000 #if GEOS_VERSION_MAJOR>3 || GEOS_VERSION_MINOR>=8 
 2010         GEOSCoordSeq_setX_r( geosinit()->ctxt, coordSeq, i, std::round( *xData++ / 
precision ) * 
precision );
 
 2011         GEOSCoordSeq_setY_r( geosinit()->ctxt, coordSeq, i, std::round( *yData++ / 
precision ) * 
precision );
 
 2014           GEOSCoordSeq_setOrdinate_r( geosinit()->ctxt, coordSeq, i, 2, std::round( *zData++ / 
precision ) * 
precision );
 
 2019           GEOSCoordSeq_setOrdinate_r( geosinit()->ctxt, coordSeq, i, 3, line->
mAt( *mData++ ) );
 
 2025       for ( 
int i = 0; i < numOutPoints; ++i )
 
 2027         if ( i >= numPoints )
 
 2030           xData = line->
xData();
 
 2031           yData = line->
yData();
 
 2032           zData = hasZ ? line->
zData() : 
nullptr;
 
 2033           mData = hasM ? line->
mData() : 
nullptr;
 
 2035 #if GEOS_VERSION_MAJOR>3 || GEOS_VERSION_MINOR>=8 
 2038           GEOSCoordSeq_setXYZ_r( geosinit()->ctxt, coordSeq, i, *xData++, *yData++, *zData++ );
 
 2042           GEOSCoordSeq_setXY_r( geosinit()->ctxt, coordSeq, i, *xData++, *yData++ );
 
 2045         GEOSCoordSeq_setX_r( geosinit()->ctxt, coordSeq, i, *xData++ );
 
 2046         GEOSCoordSeq_setY_r( geosinit()->ctxt, coordSeq, i, *yData++ );
 
 2049           GEOSCoordSeq_setOrdinate_r( geosinit()->ctxt, coordSeq, i, 2, *zData++ );
 
 2054           GEOSCoordSeq_setOrdinate_r( geosinit()->ctxt, coordSeq, i, 3, *mData++ );
 
 2066   const QgsPoint *pt = qgsgeometry_cast<const QgsPoint *>( point );
 
 2073 geos::unique_ptr QgsGeos::createGeosPointXY( 
double x, 
double y, 
bool hasZ, 
double z, 
bool hasM, 
double m, 
int coordDims, 
double precision )
 
 2081 #if GEOS_VERSION_MAJOR>3 || GEOS_VERSION_MINOR>=8 
 2082     if ( coordDims == 2 )
 
 2088         geosPoint.reset( GEOSGeom_createPointFromXY_r( geosinit()->ctxt, x, y ) );
 
 2093     GEOSCoordSequence *coordSeq = GEOSCoordSeq_create_r( geosinit()->ctxt, 1, coordDims );
 
 2096       QgsDebugMsg( QStringLiteral( 
"GEOS Exception: Could not create coordinate sequence for point with %1 dimensions" ).arg( coordDims ) );
 
 2101       GEOSCoordSeq_setX_r( geosinit()->ctxt, coordSeq, 0, std::round( x / 
precision ) * 
precision );
 
 2102       GEOSCoordSeq_setY_r( geosinit()->ctxt, coordSeq, 0, std::round( y / 
precision ) * 
precision );
 
 2105         GEOSCoordSeq_setOrdinate_r( geosinit()->ctxt, coordSeq, 0, 2, std::round( z / 
precision ) * 
precision );
 
 2110       GEOSCoordSeq_setX_r( geosinit()->ctxt, coordSeq, 0, x );
 
 2111       GEOSCoordSeq_setY_r( geosinit()->ctxt, coordSeq, 0, y );
 
 2114         GEOSCoordSeq_setOrdinate_r( geosinit()->ctxt, coordSeq, 0, 2, z );
 
 2120       GEOSCoordSeq_setOrdinate_r( geosinit()->ctxt, coordSeq, 0, 3, m );
 
 2123     geosPoint.reset( GEOSGeom_createPoint_r( geosinit()->ctxt, coordSeq ) );
 
 2131   const QgsCurve *
c = qgsgeometry_cast<const QgsCurve *>( curve );
 
 2135   GEOSCoordSequence *coordSeq = createCoordinateSequence( 
c, 
precision );
 
 2142     geosGeom.reset( GEOSGeom_createLineString_r( geosinit()->ctxt, coordSeq ) );
 
 2150   const QgsCurvePolygon *polygon = qgsgeometry_cast<const QgsCurvePolygon *>( poly );
 
 2155   if ( !exteriorRing )
 
 2163     geos::unique_ptr exteriorRingGeos( GEOSGeom_createLinearRing_r( geosinit()->ctxt, createCoordinateSequence( exteriorRing, 
precision, 
true ) ) );
 
 2166     GEOSGeometry **holes = 
nullptr;
 
 2169       holes = 
new GEOSGeometry*[ nHoles ];
 
 2172     for ( 
int i = 0; i < nHoles; ++i )
 
 2175       holes[i] = GEOSGeom_createLinearRing_r( geosinit()->ctxt, createCoordinateSequence( interiorRing, 
precision, 
true ) );
 
 2177     geosPolygon.reset( GEOSGeom_createPolygon_r( geosinit()->ctxt, exteriorRingGeos.release(), holes, nHoles ) );
 
 2193     offset.reset( GEOSOffsetCurve_r( geosinit()->ctxt, mGeos.get(), 
distance, segments, 
static_cast< int >( joinStyle ), miterLimit ) );
 
 2196   std::unique_ptr< QgsAbstractGeometry > offsetGeom = 
fromGeos( offset.get() );
 
 2197   return offsetGeom.release();
 
 2211     GEOSBufferParams_setSingleSided_r( geosinit()->ctxt, bp.get(), 1 );
 
 2212     GEOSBufferParams_setQuadrantSegments_r( geosinit()->ctxt, bp.get(), segments );
 
 2213     GEOSBufferParams_setJoinStyle_r( geosinit()->ctxt, bp.get(), 
static_cast< int >( joinStyle ) );
 
 2214     GEOSBufferParams_setMitreLimit_r( geosinit()->ctxt, bp.get(), miterLimit );  
 
 2216     if ( side == Qgis::BufferSide::Right )
 
 2220     geos.reset( GEOSBufferWithParams_r( geosinit()->ctxt, mGeos.get(), bp.get(), 
distance ) );
 
 2228 #if GEOS_VERSION_MAJOR==3 && GEOS_VERSION_MINOR<9 
 2231   throw QgsNotSupportedException( QStringLiteral( 
"Calculating maximumInscribedCircle requires a QGIS build based on GEOS 3.9 or later" ) );
 
 2241     geos.reset( GEOSMaximumInscribedCircle_r( geosinit()->ctxt, mGeos.get(), tolerance ) );
 
 2250 #if GEOS_VERSION_MAJOR==3 && GEOS_VERSION_MINOR<9 
 2254   throw QgsNotSupportedException( QStringLiteral( 
"Calculating largestEmptyCircle requires a QGIS build based on GEOS 3.9 or later" ) );
 
 2266       boundaryGeos = 
asGeos( boundary );
 
 2268     geos.reset( GEOSLargestEmptyCircle_r( geosinit()->ctxt, mGeos.get(), boundaryGeos.get(), tolerance ) );
 
 2277 #if GEOS_VERSION_MAJOR==3 && GEOS_VERSION_MINOR<6 
 2279   throw QgsNotSupportedException( QStringLiteral( 
"Calculating minimumWidth requires a QGIS build based on GEOS 3.6 or later" ) );
 
 2289     geos.reset( GEOSMinimumWidth_r( geosinit()->ctxt, mGeos.get() ) );
 
 2298 #if GEOS_VERSION_MAJOR==3 && GEOS_VERSION_MINOR<6 
 2300   throw QgsNotSupportedException( QStringLiteral( 
"Calculating minimumClearance requires a QGIS build based on GEOS 3.6 or later" ) );
 
 2304     return std::numeric_limits< double >::quiet_NaN();
 
 2311     if ( GEOSMinimumClearance_r( geosinit()->ctxt, mGeos.get(), &res ) != 0 )
 
 2312       return std::numeric_limits< double >::quiet_NaN();
 
 2321 #if GEOS_VERSION_MAJOR==3 && GEOS_VERSION_MINOR<6 
 2323   throw QgsNotSupportedException( QStringLiteral( 
"Calculating minimumClearanceLine requires a QGIS build based on GEOS 3.6 or later" ) );
 
 2333     geos.reset( GEOSMinimumClearanceLine_r( geosinit()->ctxt, mGeos.get() ) );
 
 2350     geos.reset( GEOSNode_r( geosinit()->ctxt, mGeos.get() ) );
 
 2358   if ( !mGeos || !other )
 
 2370     geos.reset( GEOSSharedPaths_r( geosinit()->ctxt, mGeos.get(), otherGeos.get() ) );
 
 2390   geos::unique_ptr reshapeLineGeos = createGeosLinestring( &reshapeWithLine, mPrecision );
 
 2393   int numGeoms = GEOSGetNumGeometries_r( geosinit()->ctxt, mGeos.get() );
 
 2394   if ( numGeoms == -1 )
 
 2403   bool isMultiGeom = 
false;
 
 2404   int geosTypeId = GEOSGeomTypeId_r( geosinit()->ctxt, mGeos.get() );
 
 2405   if ( geosTypeId == GEOS_MULTILINESTRING || geosTypeId == GEOS_MULTIPOLYGON )
 
 2415       reshapedGeometry = reshapeLine( mGeos.get(), reshapeLineGeos.get(), mPrecision );
 
 2419       reshapedGeometry = reshapePolygon( mGeos.get(), reshapeLineGeos.get(), mPrecision );
 
 2424     std::unique_ptr< QgsAbstractGeometry > reshapeResult = 
fromGeos( reshapedGeometry.get() );
 
 2425     return reshapeResult;
 
 2432       bool reshapeTookPlace = 
false;
 
 2435       GEOSGeometry **newGeoms = 
new GEOSGeometry*[numGeoms];
 
 2437       for ( 
int i = 0; i < numGeoms; ++i )
 
 2440           currentReshapeGeometry = reshapeLine( GEOSGetGeometryN_r( geosinit()->ctxt, mGeos.get(), i ), reshapeLineGeos.get(), mPrecision );
 
 2442           currentReshapeGeometry = reshapePolygon( GEOSGetGeometryN_r( geosinit()->ctxt, mGeos.get(), i ), reshapeLineGeos.get(), mPrecision );
 
 2444         if ( currentReshapeGeometry )
 
 2446           newGeoms[i] = currentReshapeGeometry.release();
 
 2447           reshapeTookPlace = 
true;
 
 2451           newGeoms[i] = GEOSGeom_clone_r( geosinit()->ctxt, GEOSGetGeometryN_r( geosinit()->ctxt, mGeos.get(), i ) );
 
 2458         newMultiGeom.reset( GEOSGeom_createCollection_r( geosinit()->ctxt, GEOS_MULTILINESTRING, newGeoms, numGeoms ) );
 
 2462         newMultiGeom.reset( GEOSGeom_createCollection_r( geosinit()->ctxt, GEOS_MULTIPOLYGON, newGeoms, numGeoms ) );
 
 2466       if ( !newMultiGeom )
 
 2472       if ( reshapeTookPlace )
 
 2476         std::unique_ptr< QgsAbstractGeometry > reshapedMultiGeom = 
fromGeos( newMultiGeom.get() );
 
 2477         return reshapedMultiGeom;
 
 2499   if ( GEOSGeomTypeId_r( geosinit()->ctxt, mGeos.get() ) != GEOS_MULTILINESTRING )
 
 2505     geos.reset( GEOSLineMerge_r( geosinit()->ctxt, mGeos.get() ) );
 
 2528 #if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=9 ) 
 2530     if ( mGeosPrepared ) 
 
 2532       nearestCoord.reset( GEOSPreparedNearestPoints_r( geosinit()->ctxt, mGeosPrepared.get(), otherGeom.get() ) );
 
 2536       nearestCoord.reset( GEOSNearestPoints_r( geosinit()->ctxt, mGeos.get(), otherGeom.get() ) );
 
 2542     ( void )GEOSCoordSeq_getX_r( geosinit()->ctxt, nearestCoord.get(), 0, &nx );
 
 2543     ( void )GEOSCoordSeq_getY_r( geosinit()->ctxt, nearestCoord.get(), 0, &ny );
 
 2545   catch ( GEOSException &e )
 
 2547     logError( QStringLiteral( 
"GEOS" ), e.what() );
 
 2550       *errorMsg = e.what();
 
 2560   if ( !mGeos || other.
isEmpty() )
 
 2570   if ( !other || other->
isEmpty() )
 
 2587     if ( !nearestCoord )
 
 2590         *errorMsg = QStringLiteral( 
"GEOS returned no nearest points" );
 
 2594     ( void )GEOSCoordSeq_getX_r( geosinit()->ctxt, nearestCoord.get(), 0, &nx1 );
 
 2595     ( void )GEOSCoordSeq_getY_r( geosinit()->ctxt, nearestCoord.get(), 0, &ny1 );
 
 2596     ( void )GEOSCoordSeq_getX_r( geosinit()->ctxt, nearestCoord.get(), 1, &nx2 );
 
 2597     ( void )GEOSCoordSeq_getY_r( geosinit()->ctxt, nearestCoord.get(), 1, &ny2 );
 
 2599   catch ( GEOSException &e )
 
 2601     logError( QStringLiteral( 
"GEOS" ), e.what() );
 
 2604       *errorMsg = e.what();
 
 2631     distance = GEOSProject_r( geosinit()->ctxt, mGeos.get(), otherGeom.get() );
 
 2633   catch ( GEOSException &e )
 
 2635     logError( QStringLiteral( 
"GEOS" ), e.what() );
 
 2638       *errorMsg = e.what();
 
 2648   GEOSGeometry **
const lineGeosGeometries = 
new GEOSGeometry*[ geometries.size()];
 
 2655       lineGeosGeometries[validLines] = l.release();
 
 2662     geos::unique_ptr result( GEOSPolygonize_r( geosinit()->ctxt, lineGeosGeometries, validLines ) );
 
 2663     for ( 
int i = 0; i < validLines; ++i )
 
 2665       GEOSGeom_destroy_r( geosinit()->ctxt, lineGeosGeometries[i] );
 
 2667     delete[] lineGeosGeometries;
 
 2670   catch ( GEOSException &e )
 
 2674       *errorMsg = e.what();
 
 2676     for ( 
int i = 0; i < validLines; ++i )
 
 2678       GEOSGeom_destroy_r( geosinit()->ctxt, lineGeosGeometries[i] );
 
 2680     delete[] lineGeosGeometries;
 
 2695     extentGeosGeom = 
asGeos( extent, mPrecision );
 
 2696     if ( !extentGeosGeom )
 
 2705     geos.reset( GEOSVoronoiDiagram_r( geosinit()->ctxt, mGeos.get(), extentGeosGeom.get(), tolerance, edgesOnly ) );
 
 2707     if ( !
geos || GEOSisEmpty_r( geosinit()->ctxt, 
geos.get() ) != 0 )
 
 2727     geos.reset( GEOSDelaunayTriangulation_r( geosinit()->ctxt, mGeos.get(), tolerance, edgesOnly ) );
 
 2729     if ( !
geos || GEOSisEmpty_r( geosinit()->ctxt, 
geos.get() ) != 0 )
 
 2741 static bool _linestringEndpoints( 
const GEOSGeometry *linestring, 
double &x1, 
double &y1, 
double &x2, 
double &y2 )
 
 2743   const GEOSCoordSequence *coordSeq = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, linestring );
 
 2747   unsigned int coordSeqSize;
 
 2748   if ( GEOSCoordSeq_getSize_r( geosinit()->ctxt, coordSeq, &coordSeqSize ) == 0 )
 
 2751   if ( coordSeqSize < 2 )
 
 2754   GEOSCoordSeq_getX_r( geosinit()->ctxt, coordSeq, 0, &x1 );
 
 2755   GEOSCoordSeq_getY_r( geosinit()->ctxt, coordSeq, 0, &y1 );
 
 2756   GEOSCoordSeq_getX_r( geosinit()->ctxt, coordSeq, coordSeqSize - 1, &x2 );
 
 2757   GEOSCoordSeq_getY_r( geosinit()->ctxt, coordSeq, coordSeqSize - 1, &y2 );
 
 2763 static geos::unique_ptr _mergeLinestrings( 
const GEOSGeometry *line1, 
const GEOSGeometry *line2, 
const QgsPointXY &intersectionPoint )
 
 2765   double x1, y1, x2, y2;
 
 2766   if ( !_linestringEndpoints( line1, x1, y1, x2, y2 ) )
 
 2769   double rx1, ry1, rx2, ry2;
 
 2770   if ( !_linestringEndpoints( line2, rx1, ry1, rx2, ry2 ) )
 
 2773   bool intersectionAtOrigLineEndpoint =
 
 2774     ( intersectionPoint.
x() == x1 && intersectionPoint.
y() == y1 ) !=
 
 2775     ( intersectionPoint.
x() == x2 && intersectionPoint.
y() == y2 );
 
 2776   bool intersectionAtReshapeLineEndpoint =
 
 2777     ( intersectionPoint.
x() == rx1 && intersectionPoint.
y() == ry1 ) ||
 
 2778     ( intersectionPoint.
x() == rx2 && intersectionPoint.
y() == ry2 );
 
 2781   if ( intersectionAtOrigLineEndpoint && intersectionAtReshapeLineEndpoint )
 
 2785     GEOSGeometry *geoms[2] = { g1.release(), g2.release() };
 
 2786     geos::unique_ptr multiGeom( GEOSGeom_createCollection_r( geosinit()->ctxt, GEOS_MULTILINESTRING, geoms, 2 ) );
 
 2787     geos::unique_ptr res( GEOSLineMerge_r( geosinit()->ctxt, multiGeom.get() ) );
 
 2795 geos::unique_ptr QgsGeos::reshapeLine( 
const GEOSGeometry *line, 
const GEOSGeometry *reshapeLineGeos, 
double precision )
 
 2797   if ( !line || !reshapeLineGeos )
 
 2800   bool atLeastTwoIntersections = 
false;
 
 2801   bool oneIntersection = 
false;
 
 2807     geos::unique_ptr intersectGeom( GEOSIntersection_r( geosinit()->ctxt, line, reshapeLineGeos ) );
 
 2808     if ( intersectGeom )
 
 2810       const int geomType = GEOSGeomTypeId_r( geosinit()->ctxt, intersectGeom.get() );
 
 2811       atLeastTwoIntersections = ( geomType == GEOS_MULTIPOINT && GEOSGetNumGeometries_r( geosinit()->ctxt, intersectGeom.get() ) > 1 )
 
 2812                                 || ( geomType == GEOS_GEOMETRYCOLLECTION && GEOSGetNumGeometries_r( geosinit()->ctxt, intersectGeom.get() ) > 0 ) 
 
 2813                                 || ( geomType == GEOS_MULTILINESTRING && GEOSGetNumGeometries_r( geosinit()->ctxt, intersectGeom.get() ) > 0 );
 
 2815       if ( GEOSGeomTypeId_r( geosinit()->ctxt, intersectGeom.get() ) == GEOS_POINT )
 
 2817         const GEOSCoordSequence *intersectionCoordSeq = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, intersectGeom.get() );
 
 2819         GEOSCoordSeq_getX_r( geosinit()->ctxt, intersectionCoordSeq, 0, &xi );
 
 2820         GEOSCoordSeq_getY_r( geosinit()->ctxt, intersectionCoordSeq, 0, &yi );
 
 2821         oneIntersection = 
true;
 
 2826   catch ( GEOSException & )
 
 2828     atLeastTwoIntersections = 
false;
 
 2832   if ( oneIntersection )
 
 2833     return _mergeLinestrings( line, reshapeLineGeos, oneIntersectionPoint );
 
 2835   if ( !atLeastTwoIntersections )
 
 2839   double x1, y1, x2, y2;
 
 2840   if ( !_linestringEndpoints( line, x1, y1, x2, y2 ) )
 
 2846   bool isRing = 
false;
 
 2847   if ( GEOSGeomTypeId_r( geosinit()->ctxt, line ) == GEOS_LINEARRING
 
 2848        || GEOSEquals_r( geosinit()->ctxt, beginLineVertex.get(), endLineVertex.get() ) == 1 )
 
 2853   if ( !nodedGeometry )
 
 2859   geos::unique_ptr mergedLines( GEOSLineMerge_r( geosinit()->ctxt, nodedGeometry.get() ) );
 
 2865   int numMergedLines = GEOSGetNumGeometries_r( geosinit()->ctxt, mergedLines.get() );
 
 2866   if ( numMergedLines < 2 ) 
 
 2868     if ( numMergedLines == 1 ) 
 
 2870       geos::unique_ptr result( GEOSGeom_clone_r( geosinit()->ctxt, reshapeLineGeos ) );
 
 2877   QVector<GEOSGeometry *> resultLineParts; 
 
 2878   QVector<GEOSGeometry *> probableParts; 
 
 2880   for ( 
int i = 0; i < numMergedLines; ++i )
 
 2882     const GEOSGeometry *currentGeom = GEOSGetGeometryN_r( geosinit()->ctxt, mergedLines.get(), i );
 
 2885     bool alreadyAdded = 
false;
 
 2887     double bufferDistance = std::pow( 10.0L, geomDigits( currentGeom ) - 11 );
 
 2888     for ( 
const GEOSGeometry *other : std::as_const( resultLineParts ) )
 
 2890       GEOSHausdorffDistance_r( geosinit()->ctxt, currentGeom, other, &
distance );
 
 2893         alreadyAdded = 
true;
 
 2900     const GEOSCoordSequence *currentCoordSeq = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, currentGeom );
 
 2901     unsigned int currentCoordSeqSize;
 
 2902     GEOSCoordSeq_getSize_r( geosinit()->ctxt, currentCoordSeq, ¤tCoordSeqSize );
 
 2903     if ( currentCoordSeqSize < 2 )
 
 2907     double xBegin, xEnd, yBegin, yEnd;
 
 2908     GEOSCoordSeq_getX_r( geosinit()->ctxt, currentCoordSeq, 0, &xBegin );
 
 2909     GEOSCoordSeq_getY_r( geosinit()->ctxt, currentCoordSeq, 0, &yBegin );
 
 2910     GEOSCoordSeq_getX_r( geosinit()->ctxt, currentCoordSeq, currentCoordSeqSize - 1, &xEnd );
 
 2911     GEOSCoordSeq_getY_r( geosinit()->ctxt, currentCoordSeq, currentCoordSeqSize - 1, &yEnd );
 
 2916     int nEndpointsOnOriginalLine = 0;
 
 2917     if ( pointContainedInLine( beginCurrentGeomVertex.get(), line ) == 1 )
 
 2918       nEndpointsOnOriginalLine += 1;
 
 2920     if ( pointContainedInLine( endCurrentGeomVertex.get(), line ) == 1 )
 
 2921       nEndpointsOnOriginalLine += 1;
 
 2924     int nEndpointsSameAsOriginalLine = 0;
 
 2925     if ( GEOSEquals_r( geosinit()->ctxt, beginCurrentGeomVertex.get(), beginLineVertex.get() ) == 1
 
 2926          || GEOSEquals_r( geosinit()->ctxt, beginCurrentGeomVertex.get(), endLineVertex.get() ) == 1 )
 
 2927       nEndpointsSameAsOriginalLine += 1;
 
 2929     if ( GEOSEquals_r( geosinit()->ctxt, endCurrentGeomVertex.get(), beginLineVertex.get() ) == 1
 
 2930          || GEOSEquals_r( geosinit()->ctxt, endCurrentGeomVertex.get(), endLineVertex.get() ) == 1 )
 
 2931       nEndpointsSameAsOriginalLine += 1;
 
 2934     bool currentGeomOverlapsOriginalGeom = 
false;
 
 2935     bool currentGeomOverlapsReshapeLine = 
false;
 
 2936     if ( lineContainedInLine( currentGeom, line ) == 1 )
 
 2937       currentGeomOverlapsOriginalGeom = 
true;
 
 2939     if ( lineContainedInLine( currentGeom, reshapeLineGeos ) == 1 )
 
 2940       currentGeomOverlapsReshapeLine = 
true;
 
 2943     if ( !isRing && nEndpointsSameAsOriginalLine == 1 && nEndpointsOnOriginalLine == 2 && currentGeomOverlapsOriginalGeom )
 
 2945       resultLineParts.push_back( GEOSGeom_clone_r( geosinit()->ctxt, currentGeom ) );
 
 2948     else if ( isRing && nEndpointsOnOriginalLine == 2 && currentGeomOverlapsOriginalGeom )
 
 2950       probableParts.push_back( GEOSGeom_clone_r( geosinit()->ctxt, currentGeom ) );
 
 2952     else if ( nEndpointsOnOriginalLine == 2 && !currentGeomOverlapsOriginalGeom )
 
 2954       resultLineParts.push_back( GEOSGeom_clone_r( geosinit()->ctxt, currentGeom ) );
 
 2956     else if ( nEndpointsSameAsOriginalLine == 2 && !currentGeomOverlapsOriginalGeom )
 
 2958       resultLineParts.push_back( GEOSGeom_clone_r( geosinit()->ctxt, currentGeom ) );
 
 2960     else if ( currentGeomOverlapsOriginalGeom && currentGeomOverlapsReshapeLine )
 
 2962       resultLineParts.push_back( GEOSGeom_clone_r( geosinit()->ctxt, currentGeom ) );
 
 2967   if ( isRing && !probableParts.isEmpty() )
 
 2970     GEOSGeometry *currentGeom = 
nullptr;
 
 2971     double maxLength = -std::numeric_limits<double>::max();
 
 2972     double currentLength = 0;
 
 2973     for ( 
int i = 0; i < probableParts.size(); ++i )
 
 2975       currentGeom = probableParts.at( i );
 
 2976       GEOSLength_r( geosinit()->ctxt, currentGeom, ¤tLength );
 
 2977       if ( currentLength > maxLength )
 
 2979         maxLength = currentLength;
 
 2980         maxGeom.reset( currentGeom );
 
 2984         GEOSGeom_destroy_r( geosinit()->ctxt, currentGeom );
 
 2987     resultLineParts.push_back( maxGeom.release() );
 
 2991   if ( resultLineParts.empty() )
 
 2994   if ( resultLineParts.size() == 1 ) 
 
 2996     result.reset( resultLineParts[0] );
 
 3000     GEOSGeometry **lineArray = 
new GEOSGeometry*[resultLineParts.size()];
 
 3001     for ( 
int i = 0; i < resultLineParts.size(); ++i )
 
 3003       lineArray[i] = resultLineParts[i];
 
 3007     geos::unique_ptr multiLineGeom( GEOSGeom_createCollection_r( geosinit()->ctxt, GEOS_MULTILINESTRING, lineArray, resultLineParts.size() ) );
 
 3008     delete [] lineArray;
 
 3011     result.reset( GEOSLineMerge_r( geosinit()->ctxt, multiLineGeom.get() ) );
 
 3015   if ( GEOSGeomTypeId_r( geosinit()->ctxt, result.get() ) != GEOS_LINESTRING )
 
 3023 geos::unique_ptr QgsGeos::reshapePolygon( 
const GEOSGeometry *polygon, 
const GEOSGeometry *reshapeLineGeos, 
double precision )
 
 3026   int nIntersections = 0;
 
 3027   int lastIntersectingRing = -2;
 
 3028   const GEOSGeometry *lastIntersectingGeom = 
nullptr;
 
 3030   int nRings = GEOSGetNumInteriorRings_r( geosinit()->ctxt, polygon );
 
 3035   const GEOSGeometry *outerRing = GEOSGetExteriorRing_r( geosinit()->ctxt, polygon );
 
 3036   if ( GEOSIntersects_r( geosinit()->ctxt, outerRing, reshapeLineGeos ) == 1 )
 
 3039     lastIntersectingRing = -1;
 
 3040     lastIntersectingGeom = outerRing;
 
 3044   const GEOSGeometry **innerRings = 
new const GEOSGeometry*[nRings];
 
 3048     for ( 
int i = 0; i < nRings; ++i )
 
 3050       innerRings[i] = GEOSGetInteriorRingN_r( geosinit()->ctxt, polygon, i );
 
 3051       if ( GEOSIntersects_r( geosinit()->ctxt, innerRings[i], reshapeLineGeos ) == 1 )
 
 3054         lastIntersectingRing = i;
 
 3055         lastIntersectingGeom = innerRings[i];
 
 3059   catch ( GEOSException & )
 
 3064   if ( nIntersections != 1 ) 
 
 3066     delete [] innerRings;
 
 3072   if ( !reshapeResult )
 
 3074     delete [] innerRings;
 
 3079   GEOSGeometry *newRing = 
nullptr;
 
 3080   const GEOSCoordSequence *reshapeSequence = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, reshapeResult.get() );
 
 3081   GEOSCoordSequence *newCoordSequence = GEOSCoordSeq_clone_r( geosinit()->ctxt, reshapeSequence );
 
 3083   reshapeResult.reset();
 
 3085   newRing = GEOSGeom_createLinearRing_r( geosinit()->ctxt, newCoordSequence );
 
 3088     delete [] innerRings;
 
 3092   GEOSGeometry *newOuterRing = 
nullptr;
 
 3093   if ( lastIntersectingRing == -1 )
 
 3094     newOuterRing = newRing;
 
 3096     newOuterRing = GEOSGeom_clone_r( geosinit()->ctxt, outerRing );
 
 3099   QVector<GEOSGeometry *> ringList;
 
 3102     GEOSGeometry *outerRingPoly = GEOSGeom_createPolygon_r( geosinit()->ctxt, GEOSGeom_clone_r( geosinit()->ctxt, newOuterRing ), 
nullptr, 0 );
 
 3103     if ( outerRingPoly )
 
 3105       ringList.reserve( nRings );
 
 3106       GEOSGeometry *currentRing = 
nullptr;
 
 3107       for ( 
int i = 0; i < nRings; ++i )
 
 3109         if ( lastIntersectingRing == i )
 
 3110           currentRing = newRing;
 
 3112           currentRing = GEOSGeom_clone_r( geosinit()->ctxt, innerRings[i] );
 
 3115         if ( GEOSContains_r( geosinit()->ctxt, outerRingPoly, currentRing ) == 1 )
 
 3116           ringList.push_back( currentRing );
 
 3118           GEOSGeom_destroy_r( geosinit()->ctxt, currentRing );
 
 3121     GEOSGeom_destroy_r( geosinit()->ctxt, outerRingPoly );
 
 3124   GEOSGeometry **newInnerRings = 
new GEOSGeometry*[ringList.size()];
 
 3125   for ( 
int i = 0; i < ringList.size(); ++i )
 
 3126     newInnerRings[i] = ringList.at( i );
 
 3128   delete [] innerRings;
 
 3130   geos::unique_ptr reshapedPolygon( GEOSGeom_createPolygon_r( geosinit()->ctxt, newOuterRing, newInnerRings, ringList.size() ) );
 
 3131   delete[] newInnerRings;
 
 3133   return reshapedPolygon;
 
 3136 int QgsGeos::lineContainedInLine( 
const GEOSGeometry *line1, 
const GEOSGeometry *line2 )
 
 3138   if ( !line1 || !line2 )
 
 3143   double bufferDistance = std::pow( 10.0L, geomDigits( line2 ) - 11 );
 
 3149   geos::unique_ptr intersectionGeom( GEOSIntersection_r( geosinit()->ctxt, bufferGeom.get(), line1 ) );
 
 3152   double intersectGeomLength;
 
 3155   GEOSLength_r( geosinit()->ctxt, intersectionGeom.get(), &intersectGeomLength );
 
 3156   GEOSLength_r( geosinit()->ctxt, line1, &line1Length );
 
 3158   double intersectRatio = line1Length / intersectGeomLength;
 
 3159   if ( intersectRatio > 0.9 && intersectRatio < 1.1 )
 
 3165 int QgsGeos::pointContainedInLine( 
const GEOSGeometry *point, 
const GEOSGeometry *line )
 
 3167   if ( !point || !line )
 
 3170   double bufferDistance = std::pow( 10.0L, geomDigits( line ) - 11 );
 
 3172   geos::unique_ptr lineBuffer( GEOSBuffer_r( geosinit()->ctxt, line, bufferDistance, 8 ) );
 
 3176   bool contained = 
false;
 
 3177   if ( GEOSContains_r( geosinit()->ctxt, lineBuffer.get(), point ) == 1 )
 
 3183 int QgsGeos::geomDigits( 
const GEOSGeometry *geom )
 
 3189   const GEOSGeometry *bBoxRing = GEOSGetExteriorRing_r( geosinit()->ctxt, bbox.get() );
 
 3193   const GEOSCoordSequence *bBoxCoordSeq = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, bBoxRing );
 
 3195   if ( !bBoxCoordSeq )
 
 3198   unsigned int nCoords = 0;
 
 3199   if ( !GEOSCoordSeq_getSize_r( geosinit()->ctxt, bBoxCoordSeq, &nCoords ) )
 
 3203   for ( 
unsigned int i = 0; i < nCoords - 1; ++i )
 
 3206     GEOSCoordSeq_getX_r( geosinit()->ctxt, bBoxCoordSeq, i, &t );
 
 3209     digits = std::ceil( std::log10( std::fabs( t ) ) );
 
 3210     if ( digits > maxDigits )
 
 3213     GEOSCoordSeq_getY_r( geosinit()->ctxt, bBoxCoordSeq, i, &t );
 
 3214     digits = std::ceil( std::log10( std::fabs( t ) ) );
 
 3215     if ( digits > maxDigits )
 
 3224   return geosinit()->ctxt;
 
The Qgis class provides global constants for use throughout the application.
BufferSide
Side of line to buffer.
GeometryOperationResult
Success or failure of a geometry operation.
@ AddPartNotMultiGeometry
The source geometry is not multi.
@ InvalidBaseGeometry
The base geometry on which the operation is done is invalid or empty.
JoinStyle
Join styles for buffers.
EndCapStyle
End cap styles for buffers.
Abstract base class for all geometries.
bool is3D() const SIP_HOLDGIL
Returns true if the geometry is 3D and contains a z-value.
virtual QgsRectangle boundingBox() const =0
Returns the minimal bounding box for the geometry.
virtual QgsAbstractGeometry * clone() const =0
Clones the geometry by performing a deep copy.
virtual bool isEmpty() const
Returns true if the geometry is empty.
QgsWkbTypes::Type wkbType() const SIP_HOLDGIL
Returns the WKB type of the geometry.
virtual int dimension() const =0
Returns the inherent dimension of the geometry.
bool isMeasure() const SIP_HOLDGIL
Returns true if the geometry contains m values.
Curve polygon geometry type.
const QgsCurve * interiorRing(int i) const SIP_HOLDGIL
Retrieves an interior ring from the curve polygon.
const QgsCurve * exteriorRing() const SIP_HOLDGIL
Returns the curve polygon's exterior ring.
int numInteriorRings() const SIP_HOLDGIL
Returns the number of interior rings contained with the curve polygon.
Abstract base class for curved geometry type.
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.
virtual bool addGeometry(QgsAbstractGeometry *g)
Adds a geometry and takes ownership. Returns true in case of success.
static Qgis::GeometryOperationResult addPart(QgsAbstractGeometry *geometry, std::unique_ptr< QgsAbstractGeometry > part)
Add a part to multi type geometry.
A geometry engine is a low-level representation of a QgsAbstractGeometry object, optimised for use wi...
const QgsAbstractGeometry * mGeometry
EngineOperationResult
Success or failure of a geometry operation.
@ NothingHappened
Nothing happened, without any error.
@ InvalidBaseGeometry
The geometry on which the operation occurs is not valid.
@ InvalidInput
The input is not valid.
@ NodedGeometryError
Error occurred while creating a noded geometry.
@ EngineError
Error occurred in the geometry engine.
@ SplitCannotSplitPoint
Points cannot be split.
@ Success
Operation succeeded.
void logError(const QString &engineName, const QString &message) const
Logs an error message encountered during an operation.
static std::unique_ptr< QgsGeometryCollection > createCollectionOfType(QgsWkbTypes::Type type)
Returns a new geometry collection matching a specified WKB type.
A geometry is the spatial representation of a feature.
const QgsAbstractGeometry * constGet() const SIP_HOLDGIL
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
QgsAbstractGeometry * get()
Returns a modifiable (non-const) reference to the underlying abstract geometry primitive.
bool isEmpty() const
Returns true if the geometry is empty (eg a linestring with no vertices, or a collection with no geom...
Does vector analysis using the geos library and handles import, export, exception handling*.
QgsGeometry delaunayTriangulation(double tolerance=0.0, bool edgesOnly=false, QString *errorMsg=nullptr) const
Returns the Delaunay triangulation for the vertices of the geometry.
QgsAbstractGeometry * intersection(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Calculate the intersection of this and geom.
bool touches(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Checks if geom touches this.
double hausdorffDistanceDensify(const QgsAbstractGeometry *geom, double densifyFraction, QString *errorMsg=nullptr) const
Returns the Hausdorff distance between this geometry and geom.
bool isValid(QString *errorMsg=nullptr, bool allowSelfTouchingHoles=false, QgsGeometry *errorLoc=nullptr) const override
Returns true if the geometry is valid.
double hausdorffDistance(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const
Returns the Hausdorff distance between this geometry and geom.
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...
QgsAbstractGeometry * buffer(double distance, int segments, 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.
std::unique_ptr< QgsAbstractGeometry > maximumInscribedCircle(double tolerance, QString *errorMsg=nullptr) const
Returns the maximum inscribed circle.
QgsAbstractGeometry * combine(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Calculate the combination of this and geom.
EngineOperationResult splitGeometry(const QgsLineString &splitLine, QVector< QgsGeometry > &newGeometries, bool topological, QgsPointSequence &topologyTestPoints, QString *errorMsg=nullptr, bool skipIntersectionCheck=false) const override
Splits this geometry according to a given line.
std::unique_ptr< QgsAbstractGeometry > sharedPaths(const QgsAbstractGeometry *other, QString *errorMsg=nullptr) const
Find paths shared between the two given lineal geometries (this and other).
std::unique_ptr< QgsAbstractGeometry > clip(const QgsRectangle &rectangle, QString *errorMsg=nullptr) const
Performs a fast, non-robust intersection between the geometry and a rectangle.
std::unique_ptr< QgsAbstractGeometry > node(QString *errorMsg=nullptr) const
Returns a (Multi)LineString representing the fully noded version of a collection of linestrings.
bool contains(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Checks if geom contains this.
double minimumClearance(QString *errorMsg=nullptr) const
Computes the minimum clearance of a geometry.
std::unique_ptr< QgsAbstractGeometry > singleSidedBuffer(double distance, int segments, Qgis::BufferSide side, Qgis::JoinStyle joinStyle, double miterLimit, QString *errorMsg=nullptr) const
Returns a single sided buffer for a geometry.
bool disjoint(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Checks if geom is disjoint from this.
QgsGeos(const QgsAbstractGeometry *geometry, double precision=0)
GEOS geometry engine constructor.
QgsGeometry shortestLine(const QgsGeometry &other, QString *errorMsg=nullptr) const
Returns the shortest line joining this geometry to the other geometry.
QgsAbstractGeometry * simplify(double tolerance, QString *errorMsg=nullptr) const override
QgsGeometry closestPoint(const QgsGeometry &other, QString *errorMsg=nullptr) const
Returns the closest point on the geometry to the other geometry.
static std::unique_ptr< QgsPolygon > fromGeosPolygon(const GEOSGeometry *geos)
std::unique_ptr< QgsAbstractGeometry > minimumClearanceLine(QString *errorMsg=nullptr) const
Returns a LineString whose endpoints define the minimum clearance of a geometry.
QgsAbstractGeometry * envelope(QString *errorMsg=nullptr) const override
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 crosses(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Checks if geom crosses this.
QgsAbstractGeometry * convexHull(QString *errorMsg=nullptr) const override
Calculate the convex hull of this.
double distance(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Calculates the distance between this and geom.
std::unique_ptr< QgsAbstractGeometry > minimumWidth(QString *errorMsg=nullptr) const
Returns a linestring geometry which represents the minimum diameter of the geometry.
QgsAbstractGeometry * symDifference(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Calculate the symmetric difference of this and geom.
bool isSimple(QString *errorMsg=nullptr) const override
Determines whether the geometry is simple (according to OGC definition).
bool within(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Checks if geom is within this.
void prepareGeometry() override
Prepares the geometry, so that subsequent calls to spatial relation methods are much faster.
static std::unique_ptr< QgsAbstractGeometry > fromGeos(const GEOSGeometry *geos)
Create a geometry from a GEOSGeometry.
QgsAbstractGeometry * interpolate(double distance, QString *errorMsg=nullptr) const override
bool distanceWithin(const QgsAbstractGeometry *geom, double maxdistance, QString *errorMsg=nullptr) const override
Checks if geom is within maxdistance distance from this geometry.
bool isEqual(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Checks if this is equal to geom.
QgsGeometry mergeLines(QString *errorMsg=nullptr) const
Merges any connected lines in a LineString/MultiLineString geometry and converts them to single line ...
static QgsGeometry polygonize(const QVector< const QgsAbstractGeometry * > &geometries, QString *errorMsg=nullptr)
Creates a GeometryCollection geometry containing possible polygons formed from the constituent linewo...
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...
QgsAbstractGeometry * offsetCurve(double distance, int segments, Qgis::JoinStyle joinStyle, double miterLimit, QString *errorMsg=nullptr) const override
Offsets a curve.
static GEOSContextHandle_t getGEOSHandler()
QgsPoint * centroid(QString *errorMsg=nullptr) const override
Calculates the centroid of this.
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...
bool isEmpty(QString *errorMsg=nullptr) const override
static Qgis::GeometryOperationResult addPart(QgsGeometry &geometry, GEOSGeometry *newPart)
Adds a new island polygon to a multipolygon feature.
double frechetDistance(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const
Returns the Fréchet distance between this geometry and geom, restricted to discrete points for both g...
std::unique_ptr< QgsAbstractGeometry > subdivide(int maxNodes, QString *errorMsg=nullptr) const
Subdivides the geometry.
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.
bool intersects(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Checks if geom intersects this.
void geometryChanged() override
Should be called whenever the geometry associated with the engine has been modified and the engine mu...
bool overlaps(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Checks if geom overlaps this.
double area(QString *errorMsg=nullptr) const override
double length(QString *errorMsg=nullptr) const override
std::unique_ptr< QgsAbstractGeometry > largestEmptyCircle(double tolerance, const QgsAbstractGeometry *boundary=nullptr, QString *errorMsg=nullptr) const
Constructs the Largest Empty Circle for a set of obstacle geometries, up to a specified tolerance.
double frechetDistanceDensify(const QgsAbstractGeometry *geom, double densifyFraction, QString *errorMsg=nullptr) const
Returns the Fréchet distance between this geometry and geom, restricted to discrete points for both g...
QgsAbstractGeometry * difference(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Calculate the difference of this and geom.
static QgsPoint coordSeqPoint(const GEOSCoordSequence *cs, int i, bool hasZ, bool hasM)
QgsPoint * pointOnSurface(QString *errorMsg=nullptr) const override
Calculate a point that is guaranteed to be on the surface of this.
static QgsGeometry geometryFromGeos(GEOSGeometry *geos)
Creates a new QgsGeometry object, feeding in a geometry in GEOS format.
Line string geometry type, with support for z-dimension and m-values.
const double * yData() const
Returns a const pointer to the y vertex data.
int numPoints() const override SIP_HOLDGIL
Returns the number of points in the curve.
QgsPoint pointN(int i) const
Returns the specified point from inside the line string.
const double * mData() const
Returns a const pointer to the m vertex data, or nullptr if the linestring does not have m values.
double yAt(int index) const override
Returns the y-coordinate of the specified node in the line string.
double mAt(int index) const
Returns the m value of the specified node in the line string.
void addVertex(const QgsPoint &pt)
Adds a new vertex to the end of the line string.
QgsLineString * clone() const override
Clones the geometry by performing a deep copy.
const double * xData() const
Returns a const pointer to the x vertex data.
const double * zData() const
Returns a const pointer to the z vertex data, or nullptr if the linestring does not have z values.
double xAt(int index) const override
Returns the x-coordinate of the specified node in the line string.
Multi curve geometry collection.
bool addGeometry(QgsAbstractGeometry *g) override
Adds a geometry and takes ownership. Returns true in case of success.
Multi line string geometry collection.
Multi point geometry collection.
Multi polygon geometry collection.
Custom exception class which is raised when an operation is not supported.
A class to represent a 2D point.
Point geometry type, with support for z-dimension and m-values.
A rectangle specified with double values.
double yMaximum() const SIP_HOLDGIL
Returns the y maximum value (top side of rectangle).
double xMaximum() const SIP_HOLDGIL
Returns the x maximum value (right side of rectangle).
double xMinimum() const SIP_HOLDGIL
Returns the x minimum value (left side of rectangle).
double yMinimum() const SIP_HOLDGIL
Returns the y minimum value (bottom side of rectangle).
void setYMinimum(double y) SIP_HOLDGIL
Set the minimum y value.
bool isNull() const
Test if the rectangle is null (all coordinates zero or after call to setMinimal()).
void setXMaximum(double x) SIP_HOLDGIL
Set the maximum x value.
void setXMinimum(double x) SIP_HOLDGIL
Set the minimum x value.
double height() const SIP_HOLDGIL
Returns the height of the rectangle.
void setYMaximum(double y) SIP_HOLDGIL
Set the maximum y value.
double width() const SIP_HOLDGIL
Returns the width of the rectangle.
bool isEmpty() const
Returns true if the rectangle is empty.
static GeometryType geometryType(Type type) SIP_HOLDGIL
Returns the geometry type for a WKB type, e.g., both MultiPolygon and CurvePolygon would have a Polyg...
static bool isMultiType(Type type) SIP_HOLDGIL
Returns true if the WKB type is a multi type.
Type
The WKB type describes the number of dimensions a geometry has.
static Type flatType(Type type) SIP_HOLDGIL
Returns the flat type for a WKB type.
Contains geos related utilities and functions.
std::unique_ptr< GEOSGeometry, GeosDeleter > unique_ptr
Scoped GEOS pointer.
std::unique_ptr< GEOSCoordSequence, GeosDeleter > coord_sequence_unique_ptr
Scoped GEOS coordinate sequence pointer.
std::unique_ptr< GEOSBufferParams, GeosDeleter > buffer_params_unique_ptr
Scoped GEOS buffer params pointer.
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 qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
QMap< QString, QString > QgsStringMap
QVector< QgsPoint > QgsPointSequence
Q_GLOBAL_STATIC(QReadWriteLock, sDefinitionCacheLock)
#define DEFAULT_QUADRANT_SEGMENTS
#define CATCH_GEOS_WITH_ERRMSG(r)
void CORE_EXPORT operator()(GEOSGeometry *geom)
Destroys the GEOS geometry geom, using the static QGIS geos context.