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();
 
  215   mGeosPrepared.reset();
 
  218     mGeosPrepared.reset( GEOSPrepare_r( geosinit()->ctxt, mGeos.get() ) );
 
  222 void QgsGeos::cacheGeos()
 const 
  234   return overlay( geom, OverlayIntersection, errorMsg ).release();
 
  239   return overlay( geom, OverlayDifference, errorMsg ).release();
 
  254   catch ( GEOSException &e )
 
  256     logError( QStringLiteral( 
"GEOS" ), e.what() );
 
  259       *errorMsg = e.what();
 
  270   int partType = GEOSGeomTypeId_r( geosinit()->ctxt, currentPart );
 
  273     if ( partType == GEOS_POINT )
 
  284   if ( partType == GEOS_MULTILINESTRING || partType == GEOS_MULTIPOLYGON || partType == GEOS_GEOMETRYCOLLECTION )
 
  286     int partCount = GEOSGetNumGeometries_r( geosinit()->ctxt, currentPart );
 
  287     for ( 
int i = 0; i < partCount; ++i )
 
  289       subdivideRecursive( GEOSGetGeometryN_r( geosinit()->ctxt, currentPart, i ), maxNodes, depth, parts, clipRect );
 
  300   int vertexCount = GEOSGetNumCoordinates_r( geosinit()->ctxt, currentPart );
 
  301   if ( vertexCount == 0 )
 
  305   else if ( vertexCount < maxNodes )
 
  312   double width = clipRect.
width();
 
  313   double height = clipRect.
height();
 
  316   if ( width > height )
 
  329     halfClipRect1.
setYMinimum( halfClipRect1.
yMinimum() - std::numeric_limits<double>::epsilon() );
 
  330     halfClipRect2.
setYMinimum( halfClipRect2.
yMinimum() - std::numeric_limits<double>::epsilon() );
 
  331     halfClipRect1.
setYMaximum( halfClipRect1.
yMaximum() + std::numeric_limits<double>::epsilon() );
 
  332     halfClipRect2.
setYMaximum( halfClipRect2.
yMaximum() + std::numeric_limits<double>::epsilon() );
 
  336     halfClipRect1.
setXMinimum( halfClipRect1.
xMinimum() - std::numeric_limits<double>::epsilon() );
 
  337     halfClipRect2.
setXMinimum( halfClipRect2.
xMinimum() - std::numeric_limits<double>::epsilon() );
 
  338     halfClipRect1.
setXMaximum( halfClipRect1.
xMaximum() + std::numeric_limits<double>::epsilon() );
 
  339     halfClipRect2.
setXMaximum( halfClipRect2.
xMaximum() + std::numeric_limits<double>::epsilon() );
 
  349     subdivideRecursive( clipPart1.get(), maxNodes, depth, parts, halfClipRect1 );
 
  353     subdivideRecursive( clipPart2.get(), maxNodes, depth, parts, halfClipRect2 );
 
  365   maxNodes = std::max( maxNodes, 8 );
 
  374   return std::move( parts );
 
  379   return overlay( geom, OverlayUnion, errorMsg ).release();
 
  384   QVector< GEOSGeometry * > geosGeometries;
 
  385   geosGeometries.reserve( geomList.size() );
 
  391     geosGeometries << 
asGeos( g, mPrecision ).release();
 
  397     geos::unique_ptr geomCollection = createGeosCollection( GEOS_GEOMETRYCOLLECTION, geosGeometries );
 
  398     geomUnion.reset( GEOSUnaryUnion_r( geosinit()->ctxt, geomCollection.get() ) );
 
  402   std::unique_ptr< QgsAbstractGeometry > result = 
fromGeos( geomUnion.get() );
 
  403   return result.release();
 
  408   QVector< GEOSGeometry * > geosGeometries;
 
  409   geosGeometries.reserve( geomList.size() );
 
  415     geosGeometries << 
asGeos( g.constGet(), mPrecision ).release();
 
  421     geos::unique_ptr geomCollection = createGeosCollection( GEOS_GEOMETRYCOLLECTION, geosGeometries );
 
  422     geomUnion.reset( GEOSUnaryUnion_r( geosinit()->ctxt, geomCollection.get() ) );
 
  426   std::unique_ptr< QgsAbstractGeometry > result = 
fromGeos( geomUnion.get() );
 
  427   return result.release();
 
  432   return overlay( geom, OverlaySymDifference, errorMsg ).release();
 
  444   if ( !otherGeosGeom )
 
  451 #if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=9 ) 
  454       GEOSPreparedDistance_r( geosinit()->ctxt, mGeosPrepared.get(), otherGeosGeom.get(), &
distance );
 
  458       GEOSDistance_r( geosinit()->ctxt, mGeos.get(), otherGeosGeom.get(), &
distance );
 
  461     GEOSDistance_r( geosinit()->ctxt, mGeos.get(), otherGeosGeom.get(), &
distance );
 
  478   if ( !otherGeosGeom )
 
  485     GEOSHausdorffDistance_r( geosinit()->ctxt, mGeos.get(), otherGeosGeom.get(), &
distance );
 
  501   if ( !otherGeosGeom )
 
  508     GEOSHausdorffDistanceDensify_r( geosinit()->ctxt, mGeos.get(), otherGeosGeom.get(), densifyFraction, &
distance );
 
  517 #if GEOS_VERSION_MAJOR==3 && GEOS_VERSION_MINOR<7 
  520   throw QgsNotSupportedException( QStringLiteral( 
"Calculating frechetDistance requires a QGIS build based on GEOS 3.7 or later" ) );
 
  529   if ( !otherGeosGeom )
 
  536     GEOSFrechetDistance_r( geosinit()->ctxt, mGeos.get(), otherGeosGeom.get(), &
distance );
 
  546 #if GEOS_VERSION_MAJOR==3 && GEOS_VERSION_MINOR<7 
  548   ( void )densifyFraction;
 
  550   throw QgsNotSupportedException( QStringLiteral( 
"Calculating frechetDistanceDensify requires a QGIS build based on GEOS 3.7 or later" ) );
 
  559   if ( !otherGeosGeom )
 
  566     GEOSFrechetDistanceDensify_r( geosinit()->ctxt, mGeos.get(), otherGeosGeom.get(), densifyFraction, &
distance );
 
  576   return relation( geom, RelationIntersects, errorMsg );
 
  581   return relation( geom, RelationTouches, errorMsg );
 
  586   return relation( geom, RelationCrosses, errorMsg );
 
  591   return relation( geom, RelationWithin, errorMsg );
 
  596   return relation( geom, RelationOverlaps, errorMsg );
 
  601   return relation( geom, RelationContains, errorMsg );
 
  606   return relation( geom, RelationDisjoint, errorMsg );
 
  625     char *r = GEOSRelate_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() );
 
  628       result = QString( r );
 
  629       GEOSFree_r( geosinit()->ctxt, r );
 
  632   catch ( GEOSException &e )
 
  634     logError( QStringLiteral( 
"GEOS" ), e.what() );
 
  637       *errorMsg = e.what();
 
  646   if ( !mGeos || !geom )
 
  660     result = ( GEOSRelatePattern_r( geosinit()->ctxt, mGeos.get(), geosGeom.get(), pattern.toLocal8Bit().constData() ) == 1 );
 
  662   catch ( GEOSException &e )
 
  664     logError( QStringLiteral( 
"GEOS" ), e.what() );
 
  667       *errorMsg = e.what();
 
  684     if ( GEOSArea_r( geosinit()->ctxt, mGeos.get(), &
area ) != 1 )
 
  700     if ( GEOSLength_r( geosinit()->ctxt, mGeos.get(), &
length ) != 1 )
 
  708     QVector<QgsGeometry> &newGeometries,
 
  711     QString *errorMsg, 
bool skipIntersectionCheck )
 const 
  726   if ( !GEOSisValid_r( geosinit()->ctxt, mGeos.get() ) )
 
  734   newGeometries.clear();
 
  741       splitLineGeos = createGeosLinestring( &splitLine, mPrecision );
 
  745       splitLineGeos = createGeosPointXY( splitLine.
xAt( 0 ), splitLine.
yAt( 0 ), 
false, 0, 
false, 0, 2, mPrecision );
 
  752     if ( !GEOSisValid_r( geosinit()->ctxt, splitLineGeos.get() ) || !GEOSisSimple_r( geosinit()->ctxt, splitLineGeos.get() ) )
 
  760       if ( !topologicalTestPointsSplit( splitLineGeos.get(), topologyTestPoints ) )
 
  769       returnCode = splitLinearGeometry( splitLineGeos.get(), newGeometries, skipIntersectionCheck );
 
  773       returnCode = splitPolygonGeometry( splitLineGeos.get(), newGeometries, skipIntersectionCheck );
 
  787 bool QgsGeos::topologicalTestPointsSplit( 
const GEOSGeometry *splitLine, 
QgsPointSequence &testPoints, QString *errorMsg )
 const 
  801     geos::unique_ptr intersectionGeom( GEOSIntersection_r( geosinit()->ctxt, mGeos.get(), splitLine ) );
 
  802     if ( !intersectionGeom )
 
  806     int nIntersectGeoms = 1;
 
  807     if ( GEOSGeomTypeId_r( geosinit()->ctxt, intersectionGeom.get() ) == GEOS_LINESTRING
 
  808          || GEOSGeomTypeId_r( geosinit()->ctxt, intersectionGeom.get() ) == GEOS_POINT )
 
  812       nIntersectGeoms = GEOSGetNumGeometries_r( geosinit()->ctxt, intersectionGeom.get() );
 
  814     for ( 
int i = 0; i < nIntersectGeoms; ++i )
 
  816       const GEOSGeometry *currentIntersectGeom = 
nullptr;
 
  818         currentIntersectGeom = intersectionGeom.get();
 
  820         currentIntersectGeom = GEOSGetGeometryN_r( geosinit()->ctxt, intersectionGeom.get(), i );
 
  822       const GEOSCoordSequence *lineSequence = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, currentIntersectGeom );
 
  823       unsigned int sequenceSize = 0;
 
  825       if ( GEOSCoordSeq_getSize_r( geosinit()->ctxt, lineSequence, &sequenceSize ) != 0 )
 
  827         for ( 
unsigned int i = 0; i < sequenceSize; ++i )
 
  829           if ( GEOSCoordSeq_getX_r( geosinit()->ctxt, lineSequence, i, &x ) != 0 )
 
  831             if ( GEOSCoordSeq_getY_r( geosinit()->ctxt, lineSequence, i, &y ) != 0 )
 
  833               testPoints.push_back( 
QgsPoint( x, y ) );
 
  847   int type = GEOSGeomTypeId_r( geosinit()->ctxt, mGeos.get() );
 
  849   std::unique_ptr< QgsMultiCurve > multiCurve;
 
  850   if ( type == GEOS_MULTILINESTRING )
 
  852     multiCurve.reset( qgsgeometry_cast<QgsMultiCurve *>( 
mGeometry->
clone() ) );
 
  854   else if ( type == GEOS_LINESTRING )
 
  870   std::unique_ptr< QgsAbstractGeometry > splitGeom( 
fromGeos( GEOSsplitPoint ) );
 
  871   QgsPoint *splitPoint = qgsgeometry_cast<QgsPoint *>( splitGeom.get() );
 
  880   for ( 
int i = 0; i < multiCurve->numGeometries(); ++i )
 
  882     const QgsLineString *line = qgsgeometry_cast<const QgsLineString *>( multiCurve->geometryN( i ) );
 
  889       for ( 
int j = 1; j < ( nVertices - 1 ); ++j )
 
  893         if ( currentPoint == *splitPoint )
 
  905   return asGeos( &lines, mPrecision );
 
  917   if ( !skipIntersectionCheck && !GEOSIntersects_r( geosinit()->ctxt, splitLine, mGeos.get() ) )
 
  921   int linearIntersect = GEOSRelatePattern_r( geosinit()->ctxt, mGeos.get(), splitLine, 
"1********" );
 
  922   if ( linearIntersect > 0 )
 
  925   int splitGeomType = GEOSGeomTypeId_r( geosinit()->ctxt, splitLine );
 
  928   if ( splitGeomType == GEOS_POINT )
 
  930     splitGeom = linePointDifference( splitLine );
 
  934     splitGeom.reset( GEOSDifference_r( geosinit()->ctxt, mGeos.get(), splitLine ) );
 
  936   QVector<GEOSGeometry *> lineGeoms;
 
  938   int splitType = GEOSGeomTypeId_r( geosinit()->ctxt, splitGeom.get() );
 
  939   if ( splitType == GEOS_MULTILINESTRING )
 
  941     int nGeoms = GEOSGetNumGeometries_r( geosinit()->ctxt, splitGeom.get() );
 
  942     lineGeoms.reserve( nGeoms );
 
  943     for ( 
int i = 0; i < nGeoms; ++i )
 
  944       lineGeoms << GEOSGeom_clone_r( geosinit()->ctxt, GEOSGetGeometryN_r( geosinit()->ctxt, splitGeom.get(), i ) );
 
  949     lineGeoms << GEOSGeom_clone_r( geosinit()->ctxt, splitGeom.get() );
 
  952   mergeGeometriesMultiTypeSplit( lineGeoms );
 
  954   for ( 
int i = 0; i < lineGeoms.size(); ++i )
 
  957     GEOSGeom_destroy_r( geosinit()->ctxt, lineGeoms[i] );
 
  973   if ( !mGeosPrepared )
 
  977   if ( !skipIntersectionCheck && !GEOSPreparedIntersects_r( geosinit()->ctxt, mGeosPrepared.get(), splitLine ) )
 
  982   if ( !nodedGeometry )
 
  985   const GEOSGeometry *noded = nodedGeometry.get();
 
  986   geos::unique_ptr polygons( GEOSPolygonize_r( geosinit()->ctxt, &noded, 1 ) );
 
  987   if ( !polygons || numberOfGeometries( polygons.get() ) == 0 )
 
  994   QVector<GEOSGeometry *> testedGeometries;
 
  999   for ( 
int i = 0; i < numberOfGeometries( polygons.get() ); i++ )
 
 1001     const GEOSGeometry *polygon = GEOSGetGeometryN_r( geosinit()->ctxt, polygons.get(), i );
 
 1005       testedGeometries << GEOSGeom_clone_r( geosinit()->ctxt, polygon );
 
 1008   int nGeometriesThis = numberOfGeometries( mGeos.get() ); 
 
 1009   if ( testedGeometries.empty() || testedGeometries.size() == nGeometriesThis )
 
 1012     for ( 
int i = 0; i < testedGeometries.size(); ++i )
 
 1014       GEOSGeom_destroy_r( geosinit()->ctxt, testedGeometries[i] );
 
 1023   mergeGeometriesMultiTypeSplit( testedGeometries );
 
 1026   for ( i = 0; i < testedGeometries.size() && GEOSisValid_r( geosinit()->ctxt, testedGeometries[i] ); ++i )
 
 1029   if ( i < testedGeometries.size() )
 
 1031     for ( i = 0; i < testedGeometries.size(); ++i )
 
 1032       GEOSGeom_destroy_r( geosinit()->ctxt, testedGeometries[i] );
 
 1037   for ( i = 0; i < testedGeometries.size(); ++i )
 
 1040     GEOSGeom_destroy_r( geosinit()->ctxt, testedGeometries[i] );
 
 1046 geos::unique_ptr QgsGeos::nodeGeometries( 
const GEOSGeometry *splitLine, 
const GEOSGeometry *geom )
 
 1048   if ( !splitLine || !geom )
 
 1052   if ( GEOSGeomTypeId_r( geosinit()->ctxt, geom ) == GEOS_POLYGON || GEOSGeomTypeId_r( geosinit()->ctxt, geom ) == GEOS_MULTIPOLYGON )
 
 1053     geometryBoundary.reset( GEOSBoundary_r( geosinit()->ctxt, geom ) );
 
 1055     geometryBoundary.reset( GEOSGeom_clone_r( geosinit()->ctxt, geom ) );
 
 1057   geos::unique_ptr splitLineClone( GEOSGeom_clone_r( geosinit()->ctxt, splitLine ) );
 
 1058   geos::unique_ptr unionGeometry( GEOSUnion_r( geosinit()->ctxt, splitLineClone.get(), geometryBoundary.get() ) );
 
 1060   return unionGeometry;
 
 1063 int QgsGeos::mergeGeometriesMultiTypeSplit( QVector<GEOSGeometry *> &splitResult )
 const 
 1069   int type = GEOSGeomTypeId_r( geosinit()->ctxt, mGeos.get() );
 
 1070   if ( type != GEOS_GEOMETRYCOLLECTION &&
 
 1071        type != GEOS_MULTILINESTRING &&
 
 1072        type != GEOS_MULTIPOLYGON &&
 
 1073        type != GEOS_MULTIPOINT )
 
 1076   QVector<GEOSGeometry *> copyList = splitResult;
 
 1077   splitResult.clear();
 
 1080   QVector<GEOSGeometry *> unionGeom;
 
 1082   for ( 
int i = 0; i < copyList.size(); ++i )
 
 1085     bool isPart = 
false;
 
 1086     for ( 
int j = 0; j < GEOSGetNumGeometries_r( geosinit()->ctxt, mGeos.get() ); j++ )
 
 1088       if ( GEOSEquals_r( geosinit()->ctxt, copyList[i], GEOSGetGeometryN_r( geosinit()->ctxt, mGeos.get(), j ) ) )
 
 1097       unionGeom << copyList[i];
 
 1101       QVector<GEOSGeometry *> geomVector;
 
 1102       geomVector << copyList[i];
 
 1104       if ( type == GEOS_MULTILINESTRING )
 
 1105         splitResult << createGeosCollection( GEOS_MULTILINESTRING, geomVector ).release();
 
 1106       else if ( type == GEOS_MULTIPOLYGON )
 
 1107         splitResult << createGeosCollection( GEOS_MULTIPOLYGON, geomVector ).release();
 
 1109         GEOSGeom_destroy_r( geosinit()->ctxt, copyList[i] );
 
 1114   if ( !unionGeom.isEmpty() )
 
 1116     if ( type == GEOS_MULTILINESTRING )
 
 1117       splitResult << createGeosCollection( GEOS_MULTILINESTRING, unionGeom ).release();
 
 1118     else if ( type == GEOS_MULTIPOLYGON )
 
 1119       splitResult << createGeosCollection( GEOS_MULTIPOLYGON, unionGeom ).release();
 
 1129 geos::unique_ptr QgsGeos::createGeosCollection( 
int typeId, 
const QVector<GEOSGeometry *> &geoms )
 
 1131   int nNullGeoms = geoms.count( 
nullptr );
 
 1132   int nNotNullGeoms = geoms.size() - nNullGeoms;
 
 1134   GEOSGeometry **geomarr = 
new GEOSGeometry*[ nNotNullGeoms ];
 
 1141   QVector<GEOSGeometry *>::const_iterator geomIt = geoms.constBegin();
 
 1142   for ( ; geomIt != geoms.constEnd(); ++geomIt )
 
 1146       if ( GEOSisEmpty_r( geosinit()->ctxt, *geomIt ) )
 
 1151         GEOSGeom_destroy_r( geosinit()->ctxt, *geomIt );
 
 1155         geomarr[i] = *geomIt;
 
 1164     geom.reset( GEOSGeom_createCollection_r( geosinit()->ctxt, typeId, geomarr, nNotNullGeoms ) );
 
 1166   catch ( GEOSException & )
 
 1182   int nCoordDims = GEOSGeom_getCoordinateDimension_r( geosinit()->ctxt, 
geos );
 
 1183   int nDims = GEOSGeom_getDimensions_r( geosinit()->ctxt, 
geos );
 
 1184   bool hasZ = ( nCoordDims == 3 );
 
 1185   bool hasM = ( ( nDims - nCoordDims ) == 1 );
 
 1187   switch ( GEOSGeomTypeId_r( geosinit()->ctxt, 
geos ) )
 
 1191       if ( GEOSisEmpty_r( geosinit()->ctxt, 
geos ) )
 
 1194       const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, 
geos );
 
 1195       unsigned int nPoints = 0;
 
 1196       GEOSCoordSeq_getSize_r( geosinit()->ctxt, cs, &nPoints );
 
 1197       return  nPoints > 0 ? std::unique_ptr<QgsAbstractGeometry>( 
coordSeqPoint( cs, 0, hasZ, hasM ).clone() ) : std::make_unique< QgsPoint >();
 
 1199     case GEOS_LINESTRING:
 
 1201       return sequenceToLinestring( 
geos, hasZ, hasM );
 
 1207     case GEOS_MULTIPOINT:
 
 1209       std::unique_ptr< QgsMultiPoint > multiPoint( 
new QgsMultiPoint() );
 
 1210       int nParts = GEOSGetNumGeometries_r( geosinit()->ctxt, 
geos );
 
 1211       multiPoint->reserve( nParts );
 
 1212       for ( 
int i = 0; i < nParts; ++i )
 
 1214         const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, GEOSGetGeometryN_r( geosinit()->ctxt, 
geos, i ) );
 
 1217           unsigned int nPoints = 0;
 
 1218           GEOSCoordSeq_getSize_r( geosinit()->ctxt, cs, &nPoints );
 
 1220             multiPoint->addGeometry( 
coordSeqPoint( cs, 0, hasZ, hasM ).clone() );
 
 1223       return std::move( multiPoint );
 
 1225     case GEOS_MULTILINESTRING:
 
 1228       int nParts = GEOSGetNumGeometries_r( geosinit()->ctxt, 
geos );
 
 1229       multiLineString->reserve( nParts );
 
 1230       for ( 
int i = 0; i < nParts; ++i )
 
 1232         std::unique_ptr< QgsLineString >line( sequenceToLinestring( GEOSGetGeometryN_r( geosinit()->ctxt, 
geos, i ), hasZ, hasM ) );
 
 1235           multiLineString->addGeometry( line.release() );
 
 1238       return std::move( multiLineString );
 
 1240     case GEOS_MULTIPOLYGON:
 
 1242       std::unique_ptr< QgsMultiPolygon > multiPolygon( 
new QgsMultiPolygon() );
 
 1244       int nParts = GEOSGetNumGeometries_r( geosinit()->ctxt, 
geos );
 
 1245       multiPolygon->reserve( nParts );
 
 1246       for ( 
int i = 0; i < nParts; ++i )
 
 1248         std::unique_ptr< QgsPolygon > poly = 
fromGeosPolygon( GEOSGetGeometryN_r( geosinit()->ctxt, 
geos, i ) );
 
 1251           multiPolygon->addGeometry( poly.release() );
 
 1254       return std::move( multiPolygon );
 
 1256     case GEOS_GEOMETRYCOLLECTION:
 
 1259       int nParts = GEOSGetNumGeometries_r( geosinit()->ctxt, 
geos );
 
 1260       geomCollection->reserve( nParts );
 
 1261       for ( 
int i = 0; i < nParts; ++i )
 
 1263         std::unique_ptr< QgsAbstractGeometry > geom( 
fromGeos( GEOSGetGeometryN_r( geosinit()->ctxt, 
geos, i ) ) );
 
 1266           geomCollection->addGeometry( geom.release() );
 
 1269       return std::move( geomCollection );
 
 1277   if ( GEOSGeomTypeId_r( geosinit()->ctxt, 
geos ) != GEOS_POLYGON )
 
 1282   int nCoordDims = GEOSGeom_getCoordinateDimension_r( geosinit()->ctxt, 
geos );
 
 1283   int nDims = GEOSGeom_getDimensions_r( geosinit()->ctxt, 
geos );
 
 1284   bool hasZ = ( nCoordDims == 3 );
 
 1285   bool hasM = ( ( nDims - nCoordDims ) == 1 );
 
 1287   std::unique_ptr< QgsPolygon > polygon( 
new QgsPolygon() );
 
 1289   const GEOSGeometry *ring = GEOSGetExteriorRing_r( geosinit()->ctxt, 
geos );
 
 1292     polygon->setExteriorRing( sequenceToLinestring( ring, hasZ, hasM ).release() );
 
 1295   QVector<QgsCurve *> interiorRings;
 
 1296   const int ringCount = GEOSGetNumInteriorRings_r( geosinit()->ctxt, 
geos );
 
 1297   interiorRings.reserve( ringCount );
 
 1298   for ( 
int i = 0; i < ringCount; ++i )
 
 1300     ring = GEOSGetInteriorRingN_r( geosinit()->ctxt, 
geos, i );
 
 1303       interiorRings.push_back( sequenceToLinestring( ring, hasZ, hasM ).release() );
 
 1306   polygon->setInteriorRings( interiorRings );
 
 1311 std::unique_ptr<QgsLineString> QgsGeos::sequenceToLinestring( 
const GEOSGeometry *
geos, 
bool hasZ, 
bool hasM )
 
 1313   const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, 
geos );
 
 1314   unsigned int nPoints;
 
 1315   GEOSCoordSeq_getSize_r( geosinit()->ctxt, cs, &nPoints );
 
 1316   QVector< double > xOut( nPoints );
 
 1317   QVector< double > yOut( nPoints );
 
 1318   QVector< double > zOut;
 
 1320     zOut.resize( nPoints );
 
 1321   QVector< double > mOut;
 
 1323     mOut.resize( nPoints );
 
 1324   double *x = xOut.data();
 
 1325   double *y = yOut.data();
 
 1326   double *z = zOut.data();
 
 1327   double *m = mOut.data();
 
 1328   for ( 
unsigned int i = 0; i < nPoints; ++i )
 
 1330 #if GEOS_VERSION_MAJOR>3 || GEOS_VERSION_MINOR>=8 
 1332       GEOSCoordSeq_getXYZ_r( geosinit()->ctxt, cs, i, x++, y++, z++ );
 
 1334       GEOSCoordSeq_getXY_r( geosinit()->ctxt, cs, i, x++, y++ );
 
 1336     GEOSCoordSeq_getX_r( geosinit()->ctxt, cs, i, x++ );
 
 1337     GEOSCoordSeq_getY_r( geosinit()->ctxt, cs, i, y++ );
 
 1340       GEOSCoordSeq_getZ_r( geosinit()->ctxt, cs, i, z++ );
 
 1345       GEOSCoordSeq_getOrdinate_r( geosinit()->ctxt, cs, i, 3, m++ );
 
 1348   std::unique_ptr< QgsLineString > line( 
new QgsLineString( xOut, yOut, zOut, mOut ) );
 
 1352 int QgsGeos::numberOfGeometries( GEOSGeometry *g )
 
 1357   int geometryType = GEOSGeomTypeId_r( geosinit()->ctxt, g );
 
 1358   if ( geometryType == GEOS_POINT || geometryType == GEOS_LINESTRING || geometryType == GEOS_LINEARRING
 
 1359        || geometryType == GEOS_POLYGON )
 
 1363   return GEOSGetNumGeometries_r( geosinit()->ctxt, g );
 
 1376 #if GEOS_VERSION_MAJOR>3 || GEOS_VERSION_MINOR>=8 
 1378     GEOSCoordSeq_getXYZ_r( geosinit()->ctxt, cs, i, &x, &y, &z );
 
 1380     GEOSCoordSeq_getXY_r( geosinit()->ctxt, cs, i, &x, &y );
 
 1382   GEOSCoordSeq_getX_r( geosinit()->ctxt, cs, i, &x );
 
 1383   GEOSCoordSeq_getY_r( geosinit()->ctxt, cs, i, &y );
 
 1386     GEOSCoordSeq_getZ_r( geosinit()->ctxt, cs, i, &z );
 
 1391     GEOSCoordSeq_getOrdinate_r( geosinit()->ctxt, cs, i, 3, &m );
 
 1427     int geosType = GEOS_GEOMETRYCOLLECTION;
 
 1434           geosType = GEOS_MULTIPOINT;
 
 1438           geosType = GEOS_MULTILINESTRING;
 
 1442           geosType = GEOS_MULTIPOLYGON;
 
 1457     QVector< GEOSGeometry * > geomVector( 
c->numGeometries() );
 
 1458     for ( 
int i = 0; i < 
c->numGeometries(); ++i )
 
 1462     return createGeosCollection( geosType, geomVector );
 
 1469         return createGeosPoint( 
static_cast<const QgsPoint *
>( geom ), coordDims, 
precision );
 
 1485 std::unique_ptr<QgsAbstractGeometry> QgsGeos::overlay( 
const QgsAbstractGeometry *geom, Overlay op, QString *errorMsg )
 const 
 1487   if ( !mGeos || !geom )
 
 1503       case OverlayIntersection:
 
 1504         opGeom.reset( GEOSIntersection_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) );
 
 1507       case OverlayDifference:
 
 1508         opGeom.reset( GEOSDifference_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) );
 
 1513         geos::unique_ptr unionGeometry( GEOSUnion_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) );
 
 1515         if ( unionGeometry && GEOSGeomTypeId_r( geosinit()->ctxt, unionGeometry.get() ) == GEOS_MULTILINESTRING )
 
 1517           geos::unique_ptr mergedLines( GEOSLineMerge_r( geosinit()->ctxt, unionGeometry.get() ) );
 
 1520             unionGeometry = std::move( mergedLines );
 
 1524         opGeom = std::move( unionGeometry );
 
 1528       case OverlaySymDifference:
 
 1529         opGeom.reset( GEOSSymDifference_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) );
 
 1534   catch ( GEOSException &e )
 
 1536     logError( QStringLiteral( 
"GEOS" ), e.what() );
 
 1539       *errorMsg = e.what();
 
 1545 bool QgsGeos::relation( 
const QgsAbstractGeometry *geom, Relation r, QString *errorMsg )
 const 
 1547   if ( !mGeos || !geom )
 
 1558   bool result = 
false;
 
 1561     if ( mGeosPrepared ) 
 
 1565         case RelationIntersects:
 
 1566           result = ( GEOSPreparedIntersects_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
 
 1568         case RelationTouches:
 
 1569           result = ( GEOSPreparedTouches_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
 
 1571         case RelationCrosses:
 
 1572           result = ( GEOSPreparedCrosses_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
 
 1574         case RelationWithin:
 
 1575           result = ( GEOSPreparedWithin_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
 
 1577         case RelationContains:
 
 1578           result = ( GEOSPreparedContains_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
 
 1580         case RelationDisjoint:
 
 1581           result = ( GEOSPreparedDisjoint_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
 
 1583         case RelationOverlaps:
 
 1584           result = ( GEOSPreparedOverlaps_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
 
 1592       case RelationIntersects:
 
 1593         result = ( GEOSIntersects_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
 
 1595       case RelationTouches:
 
 1596         result = ( GEOSTouches_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
 
 1598       case RelationCrosses:
 
 1599         result = ( GEOSCrosses_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
 
 1601       case RelationWithin:
 
 1602         result = ( GEOSWithin_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
 
 1604       case RelationContains:
 
 1605         result = ( GEOSContains_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
 
 1607       case RelationDisjoint:
 
 1608         result = ( GEOSDisjoint_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
 
 1610       case RelationOverlaps:
 
 1611         result = ( GEOSOverlaps_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
 
 1615   catch ( GEOSException &e )
 
 1617     logError( QStringLiteral( 
"GEOS" ), e.what() );
 
 1620       *errorMsg = e.what();
 
 1638     geos.reset( GEOSBuffer_r( geosinit()->ctxt, mGeos.get(), 
distance, segments ) );
 
 1654     geos.reset( GEOSBufferWithStyle_r( geosinit()->ctxt, mGeos.get(), 
distance, segments, endCapStyle, joinStyle, miterLimit ) );
 
 1669     geos.reset( GEOSTopologyPreserveSimplify_r( geosinit()->ctxt, mGeos.get(), tolerance ) );
 
 1684     geos.reset( GEOSInterpolate_r( geosinit()->ctxt, mGeos.get(), 
distance ) );
 
 1703     geos.reset( GEOSGetCentroid_r( geosinit()->ctxt,  mGeos.get() ) );
 
 1708     GEOSGeomGetX_r( geosinit()->ctxt, 
geos.get(), &x );
 
 1709     GEOSGeomGetY_r( geosinit()->ctxt, 
geos.get(), &y );
 
 1725     geos.reset( GEOSEnvelope_r( geosinit()->ctxt, mGeos.get() ) );
 
 1744     geos.reset( GEOSPointOnSurface_r( geosinit()->ctxt, mGeos.get() ) );
 
 1746     if ( !
geos || GEOSisEmpty_r( geosinit()->ctxt, 
geos.get() ) != 0 )
 
 1751     GEOSGeomGetX_r( geosinit()->ctxt, 
geos.get(), &x );
 
 1752     GEOSGeomGetY_r( geosinit()->ctxt, 
geos.get(), &y );
 
 1768     geos::unique_ptr cHull( GEOSConvexHull_r( geosinit()->ctxt, mGeos.get() ) );
 
 1769     std::unique_ptr< QgsAbstractGeometry > cHullGeom = 
fromGeos( cHull.get() );
 
 1770     return cHullGeom.release();
 
 1784     GEOSGeometry *g1 = 
nullptr;
 
 1786     char res = GEOSisValidDetail_r( geosinit()->ctxt, mGeos.get(), allowSelfTouchingHoles ? GEOSVALID_ALLOW_SELFTOUCHING_RING_FORMING_HOLE : 0, &r, &g1 );
 
 1787     const bool invalid = res != 1;
 
 1792       error = QString( r );
 
 1793       GEOSFree_r( geosinit()->ctxt, r );
 
 1796     if ( invalid && errorMsg )
 
 1800       if ( translatedErrors.empty() )
 
 1803         translatedErrors.insert( QStringLiteral( 
"topology validation error" ), QObject::tr( 
"Topology validation error", 
"GEOS Error" ) );
 
 1804         translatedErrors.insert( QStringLiteral( 
"repeated point" ), QObject::tr( 
"Repeated point", 
"GEOS Error" ) );
 
 1805         translatedErrors.insert( QStringLiteral( 
"hole lies outside shell" ), QObject::tr( 
"Hole lies outside shell", 
"GEOS Error" ) );
 
 1806         translatedErrors.insert( QStringLiteral( 
"holes are nested" ), QObject::tr( 
"Holes are nested", 
"GEOS Error" ) );
 
 1807         translatedErrors.insert( QStringLiteral( 
"interior is disconnected" ), QObject::tr( 
"Interior is disconnected", 
"GEOS Error" ) );
 
 1808         translatedErrors.insert( QStringLiteral( 
"self-intersection" ), QObject::tr( 
"Self-intersection", 
"GEOS Error" ) );
 
 1809         translatedErrors.insert( QStringLiteral( 
"ring self-intersection" ), QObject::tr( 
"Ring self-intersection", 
"GEOS Error" ) );
 
 1810         translatedErrors.insert( QStringLiteral( 
"nested shells" ), QObject::tr( 
"Nested shells", 
"GEOS Error" ) );
 
 1811         translatedErrors.insert( QStringLiteral( 
"duplicate rings" ), QObject::tr( 
"Duplicate rings", 
"GEOS Error" ) );
 
 1812         translatedErrors.insert( QStringLiteral( 
"too few points in geometry component" ), QObject::tr( 
"Too few points in geometry component", 
"GEOS Error" ) );
 
 1813         translatedErrors.insert( QStringLiteral( 
"invalid coordinate" ), QObject::tr( 
"Invalid coordinate", 
"GEOS Error" ) );
 
 1814         translatedErrors.insert( QStringLiteral( 
"ring is not closed" ), QObject::tr( 
"Ring is not closed", 
"GEOS Error" ) );
 
 1817       *errorMsg = translatedErrors.value( error.toLower(), error );
 
 1819       if ( g1 && errorLoc )
 
 1825         GEOSGeom_destroy_r( geosinit()->ctxt, g1 );
 
 1835   if ( !mGeos || !geom )
 
 1847     bool equal = GEOSEquals_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() );
 
 1862     return GEOSisEmpty_r( geosinit()->ctxt, mGeos.get() );
 
 1876     return GEOSisSimple_r( geosinit()->ctxt, mGeos.get() );
 
 1881 GEOSCoordSequence *QgsGeos::createCoordinateSequence( 
const QgsCurve *curve, 
double precision, 
bool forceClose )
 
 1883   std::unique_ptr< QgsLineString > segmentized;
 
 1884   const QgsLineString *line = qgsgeometry_cast<const QgsLineString *>( curve );
 
 1889     line = segmentized.get();
 
 1897   bool hasZ = line->
is3D();
 
 1911   int numOutPoints = numPoints;
 
 1912   if ( forceClose && ( line->
pointN( 0 ) != line->
pointN( numPoints - 1 ) ) )
 
 1917   GEOSCoordSequence *coordSeq = 
nullptr;
 
 1920     coordSeq = GEOSCoordSeq_create_r( geosinit()->ctxt, numOutPoints, coordDims );
 
 1923       QgsDebugMsg( QStringLiteral( 
"GEOS Exception: Could not create coordinate sequence for %1 points in %2 dimensions" ).arg( numPoints ).arg( coordDims ) );
 
 1927     const double *xData = line->
xData();
 
 1928     const double *yData = line->
yData();
 
 1929     const double *zData = hasZ ? line->
zData() : 
nullptr;
 
 1930     const double *mData = hasM ? line->
mData() : 
nullptr;
 
 1934       for ( 
int i = 0; i < numOutPoints; ++i )
 
 1936         if ( i >= numPoints )
 
 1939           xData = line->
xData();
 
 1940           yData = line->
yData();
 
 1941           zData = hasZ ? line->
zData() : 
nullptr;
 
 1942           mData = hasM ? line->
mData() : 
nullptr;
 
 1944 #if GEOS_VERSION_MAJOR>3 || GEOS_VERSION_MINOR>=8 
 1954         GEOSCoordSeq_setX_r( geosinit()->ctxt, coordSeq, i, std::round( *xData++ / 
precision ) * 
precision );
 
 1955         GEOSCoordSeq_setY_r( geosinit()->ctxt, coordSeq, i, std::round( *yData++ / 
precision ) * 
precision );
 
 1958           GEOSCoordSeq_setOrdinate_r( geosinit()->ctxt, coordSeq, i, 2, std::round( *zData++ / 
precision ) * 
precision );
 
 1963           GEOSCoordSeq_setOrdinate_r( geosinit()->ctxt, coordSeq, i, 3, line->
mAt( *mData++ ) );
 
 1969       for ( 
int i = 0; i < numOutPoints; ++i )
 
 1971         if ( i >= numPoints )
 
 1974           xData = line->
xData();
 
 1975           yData = line->
yData();
 
 1976           zData = hasZ ? line->
zData() : 
nullptr;
 
 1977           mData = hasM ? line->
mData() : 
nullptr;
 
 1979 #if GEOS_VERSION_MAJOR>3 || GEOS_VERSION_MINOR>=8 
 1982           GEOSCoordSeq_setXYZ_r( geosinit()->ctxt, coordSeq, i, *xData++, *yData++, *zData++ );
 
 1986           GEOSCoordSeq_setXY_r( geosinit()->ctxt, coordSeq, i, *xData++, *yData++ );
 
 1989         GEOSCoordSeq_setX_r( geosinit()->ctxt, coordSeq, i, *xData++ );
 
 1990         GEOSCoordSeq_setY_r( geosinit()->ctxt, coordSeq, i, *yData++ );
 
 1993           GEOSCoordSeq_setOrdinate_r( geosinit()->ctxt, coordSeq, i, 2, *zData++ );
 
 1998           GEOSCoordSeq_setOrdinate_r( geosinit()->ctxt, coordSeq, i, 3, *mData++ );
 
 2010   const QgsPoint *pt = qgsgeometry_cast<const QgsPoint *>( point );
 
 2017 geos::unique_ptr QgsGeos::createGeosPointXY( 
double x, 
double y, 
bool hasZ, 
double z, 
bool hasM, 
double m, 
int coordDims, 
double precision )
 
 2025 #if GEOS_VERSION_MAJOR>3 || GEOS_VERSION_MINOR>=8 
 2026     if ( coordDims == 2 )
 
 2032         geosPoint.reset( GEOSGeom_createPointFromXY_r( geosinit()->ctxt, x, y ) );
 
 2037     GEOSCoordSequence *coordSeq = GEOSCoordSeq_create_r( geosinit()->ctxt, 1, coordDims );
 
 2040       QgsDebugMsg( QStringLiteral( 
"GEOS Exception: Could not create coordinate sequence for point with %1 dimensions" ).arg( coordDims ) );
 
 2045       GEOSCoordSeq_setX_r( geosinit()->ctxt, coordSeq, 0, std::round( x / 
precision ) * 
precision );
 
 2046       GEOSCoordSeq_setY_r( geosinit()->ctxt, coordSeq, 0, std::round( y / 
precision ) * 
precision );
 
 2049         GEOSCoordSeq_setOrdinate_r( geosinit()->ctxt, coordSeq, 0, 2, std::round( z / 
precision ) * 
precision );
 
 2054       GEOSCoordSeq_setX_r( geosinit()->ctxt, coordSeq, 0, x );
 
 2055       GEOSCoordSeq_setY_r( geosinit()->ctxt, coordSeq, 0, y );
 
 2058         GEOSCoordSeq_setOrdinate_r( geosinit()->ctxt, coordSeq, 0, 2, z );
 
 2064       GEOSCoordSeq_setOrdinate_r( geosinit()->ctxt, coordSeq, 0, 3, m );
 
 2067     geosPoint.reset( GEOSGeom_createPoint_r( geosinit()->ctxt, coordSeq ) );
 
 2075   const QgsCurve *
c = qgsgeometry_cast<const QgsCurve *>( curve );
 
 2079   GEOSCoordSequence *coordSeq = createCoordinateSequence( 
c, 
precision );
 
 2086     geosGeom.reset( GEOSGeom_createLineString_r( geosinit()->ctxt, coordSeq ) );
 
 2094   const QgsCurvePolygon *polygon = qgsgeometry_cast<const QgsCurvePolygon *>( poly );
 
 2099   if ( !exteriorRing )
 
 2107     geos::unique_ptr exteriorRingGeos( GEOSGeom_createLinearRing_r( geosinit()->ctxt, createCoordinateSequence( exteriorRing, 
precision, 
true ) ) );
 
 2110     GEOSGeometry **holes = 
nullptr;
 
 2113       holes = 
new GEOSGeometry*[ nHoles ];
 
 2116     for ( 
int i = 0; i < nHoles; ++i )
 
 2119       holes[i] = GEOSGeom_createLinearRing_r( geosinit()->ctxt, createCoordinateSequence( interiorRing, 
precision, 
true ) );
 
 2121     geosPolygon.reset( GEOSGeom_createPolygon_r( geosinit()->ctxt, exteriorRingGeos.release(), holes, nHoles ) );
 
 2137     offset.reset( GEOSOffsetCurve_r( geosinit()->ctxt, mGeos.get(), 
distance, segments, joinStyle, miterLimit ) );
 
 2140   std::unique_ptr< QgsAbstractGeometry > offsetGeom = 
fromGeos( offset.get() );
 
 2141   return offsetGeom.release();
 
 2155     GEOSBufferParams_setSingleSided_r( geosinit()->ctxt, bp.get(), 1 );
 
 2156     GEOSBufferParams_setQuadrantSegments_r( geosinit()->ctxt, bp.get(), segments );
 
 2157     GEOSBufferParams_setJoinStyle_r( geosinit()->ctxt, bp.get(), joinStyle );
 
 2158     GEOSBufferParams_setMitreLimit_r( geosinit()->ctxt, bp.get(), miterLimit );  
 
 2164     geos.reset( GEOSBufferWithParams_r( geosinit()->ctxt, mGeos.get(), bp.get(), 
distance ) );
 
 2172 #if GEOS_VERSION_MAJOR==3 && GEOS_VERSION_MINOR<9 
 2175   throw QgsNotSupportedException( QStringLiteral( 
"Calculating maximumInscribedCircle requires a QGIS build based on GEOS 3.9 or later" ) );
 
 2185     geos.reset( GEOSMaximumInscribedCircle_r( geosinit()->ctxt, mGeos.get(), tolerance ) );
 
 2194 #if GEOS_VERSION_MAJOR==3 && GEOS_VERSION_MINOR<9 
 2198   throw QgsNotSupportedException( QStringLiteral( 
"Calculating largestEmptyCircle requires a QGIS build based on GEOS 3.9 or later" ) );
 
 2210       boundaryGeos = 
asGeos( boundary );
 
 2212     geos.reset( GEOSLargestEmptyCircle_r( geosinit()->ctxt, mGeos.get(), boundaryGeos.get(), tolerance ) );
 
 2221 #if GEOS_VERSION_MAJOR==3 && GEOS_VERSION_MINOR<6 
 2223   throw QgsNotSupportedException( QStringLiteral( 
"Calculating minimumWidth requires a QGIS build based on GEOS 3.6 or later" ) );
 
 2233     geos.reset( GEOSMinimumWidth_r( geosinit()->ctxt, mGeos.get() ) );
 
 2242 #if GEOS_VERSION_MAJOR==3 && GEOS_VERSION_MINOR<6 
 2244   throw QgsNotSupportedException( QStringLiteral( 
"Calculating minimumClearance requires a QGIS build based on GEOS 3.6 or later" ) );
 
 2248     return std::numeric_limits< double >::quiet_NaN();
 
 2255     if ( GEOSMinimumClearance_r( geosinit()->ctxt, mGeos.get(), &res ) != 0 )
 
 2256       return std::numeric_limits< double >::quiet_NaN();
 
 2265 #if GEOS_VERSION_MAJOR==3 && GEOS_VERSION_MINOR<6 
 2267   throw QgsNotSupportedException( QStringLiteral( 
"Calculating minimumClearanceLine requires a QGIS build based on GEOS 3.6 or later" ) );
 
 2277     geos.reset( GEOSMinimumClearanceLine_r( geosinit()->ctxt, mGeos.get() ) );
 
 2294     geos.reset( GEOSNode_r( geosinit()->ctxt, mGeos.get() ) );
 
 2302   if ( !mGeos || !other )
 
 2314     geos.reset( GEOSSharedPaths_r( geosinit()->ctxt, mGeos.get(), otherGeos.get() ) );
 
 2334   geos::unique_ptr reshapeLineGeos = createGeosLinestring( &reshapeWithLine, mPrecision );
 
 2337   int numGeoms = GEOSGetNumGeometries_r( geosinit()->ctxt, mGeos.get() );
 
 2338   if ( numGeoms == -1 )
 
 2347   bool isMultiGeom = 
false;
 
 2348   int geosTypeId = GEOSGeomTypeId_r( geosinit()->ctxt, mGeos.get() );
 
 2349   if ( geosTypeId == GEOS_MULTILINESTRING || geosTypeId == GEOS_MULTIPOLYGON )
 
 2359       reshapedGeometry = reshapeLine( mGeos.get(), reshapeLineGeos.get(), mPrecision );
 
 2363       reshapedGeometry = reshapePolygon( mGeos.get(), reshapeLineGeos.get(), mPrecision );
 
 2368     std::unique_ptr< QgsAbstractGeometry > reshapeResult = 
fromGeos( reshapedGeometry.get() );
 
 2369     return reshapeResult;
 
 2376       bool reshapeTookPlace = 
false;
 
 2379       GEOSGeometry **newGeoms = 
new GEOSGeometry*[numGeoms];
 
 2381       for ( 
int i = 0; i < numGeoms; ++i )
 
 2384           currentReshapeGeometry = reshapeLine( GEOSGetGeometryN_r( geosinit()->ctxt, mGeos.get(), i ), reshapeLineGeos.get(), mPrecision );
 
 2386           currentReshapeGeometry = reshapePolygon( GEOSGetGeometryN_r( geosinit()->ctxt, mGeos.get(), i ), reshapeLineGeos.get(), mPrecision );
 
 2388         if ( currentReshapeGeometry )
 
 2390           newGeoms[i] = currentReshapeGeometry.release();
 
 2391           reshapeTookPlace = 
true;
 
 2395           newGeoms[i] = GEOSGeom_clone_r( geosinit()->ctxt, GEOSGetGeometryN_r( geosinit()->ctxt, mGeos.get(), i ) );
 
 2402         newMultiGeom.reset( GEOSGeom_createCollection_r( geosinit()->ctxt, GEOS_MULTILINESTRING, newGeoms, numGeoms ) );
 
 2406         newMultiGeom.reset( GEOSGeom_createCollection_r( geosinit()->ctxt, GEOS_MULTIPOLYGON, newGeoms, numGeoms ) );
 
 2410       if ( !newMultiGeom )
 
 2416       if ( reshapeTookPlace )
 
 2420         std::unique_ptr< QgsAbstractGeometry > reshapedMultiGeom = 
fromGeos( newMultiGeom.get() );
 
 2421         return reshapedMultiGeom;
 
 2443   if ( GEOSGeomTypeId_r( geosinit()->ctxt, mGeos.get() ) != GEOS_MULTILINESTRING )
 
 2449     geos.reset( GEOSLineMerge_r( geosinit()->ctxt, mGeos.get() ) );
 
 2472 #if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=9 ) 
 2474     if ( mGeosPrepared ) 
 
 2476       nearestCoord.reset( GEOSPreparedNearestPoints_r( geosinit()->ctxt, mGeosPrepared.get(), otherGeom.get() ) );
 
 2480       nearestCoord.reset( GEOSNearestPoints_r( geosinit()->ctxt, mGeos.get(), otherGeom.get() ) );
 
 2486     ( void )GEOSCoordSeq_getX_r( geosinit()->ctxt, nearestCoord.get(), 0, &nx );
 
 2487     ( void )GEOSCoordSeq_getY_r( geosinit()->ctxt, nearestCoord.get(), 0, &ny );
 
 2489   catch ( GEOSException &e )
 
 2491     logError( QStringLiteral( 
"GEOS" ), e.what() );
 
 2494       *errorMsg = e.what();
 
 2504   if ( !mGeos || other.
isEmpty() )
 
 2514   if ( !other || other->
isEmpty() )
 
 2531     if ( !nearestCoord )
 
 2534         *errorMsg = QStringLiteral( 
"GEOS returned no nearest points" );
 
 2538     ( void )GEOSCoordSeq_getX_r( geosinit()->ctxt, nearestCoord.get(), 0, &nx1 );
 
 2539     ( void )GEOSCoordSeq_getY_r( geosinit()->ctxt, nearestCoord.get(), 0, &ny1 );
 
 2540     ( void )GEOSCoordSeq_getX_r( geosinit()->ctxt, nearestCoord.get(), 1, &nx2 );
 
 2541     ( void )GEOSCoordSeq_getY_r( geosinit()->ctxt, nearestCoord.get(), 1, &ny2 );
 
 2543   catch ( GEOSException &e )
 
 2545     logError( QStringLiteral( 
"GEOS" ), e.what() );
 
 2548       *errorMsg = e.what();
 
 2575     distance = GEOSProject_r( geosinit()->ctxt, mGeos.get(), otherGeom.get() );
 
 2577   catch ( GEOSException &e )
 
 2579     logError( QStringLiteral( 
"GEOS" ), e.what() );
 
 2582       *errorMsg = e.what();
 
 2592   GEOSGeometry **
const lineGeosGeometries = 
new GEOSGeometry*[ geometries.size()];
 
 2599       lineGeosGeometries[validLines] = l.release();
 
 2606     geos::unique_ptr result( GEOSPolygonize_r( geosinit()->ctxt, lineGeosGeometries, validLines ) );
 
 2607     for ( 
int i = 0; i < validLines; ++i )
 
 2609       GEOSGeom_destroy_r( geosinit()->ctxt, lineGeosGeometries[i] );
 
 2611     delete[] lineGeosGeometries;
 
 2614   catch ( GEOSException &e )
 
 2618       *errorMsg = e.what();
 
 2620     for ( 
int i = 0; i < validLines; ++i )
 
 2622       GEOSGeom_destroy_r( geosinit()->ctxt, lineGeosGeometries[i] );
 
 2624     delete[] lineGeosGeometries;
 
 2639     extentGeosGeom = 
asGeos( extent, mPrecision );
 
 2640     if ( !extentGeosGeom )
 
 2649     geos.reset( GEOSVoronoiDiagram_r( geosinit()->ctxt, mGeos.get(), extentGeosGeom.get(), tolerance, edgesOnly ) );
 
 2651     if ( !
geos || GEOSisEmpty_r( geosinit()->ctxt, 
geos.get() ) != 0 )
 
 2671     geos.reset( GEOSDelaunayTriangulation_r( geosinit()->ctxt, mGeos.get(), tolerance, edgesOnly ) );
 
 2673     if ( !
geos || GEOSisEmpty_r( geosinit()->ctxt, 
geos.get() ) != 0 )
 
 2685 static bool _linestringEndpoints( 
const GEOSGeometry *linestring, 
double &x1, 
double &y1, 
double &x2, 
double &y2 )
 
 2687   const GEOSCoordSequence *coordSeq = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, linestring );
 
 2691   unsigned int coordSeqSize;
 
 2692   if ( GEOSCoordSeq_getSize_r( geosinit()->ctxt, coordSeq, &coordSeqSize ) == 0 )
 
 2695   if ( coordSeqSize < 2 )
 
 2698   GEOSCoordSeq_getX_r( geosinit()->ctxt, coordSeq, 0, &x1 );
 
 2699   GEOSCoordSeq_getY_r( geosinit()->ctxt, coordSeq, 0, &y1 );
 
 2700   GEOSCoordSeq_getX_r( geosinit()->ctxt, coordSeq, coordSeqSize - 1, &x2 );
 
 2701   GEOSCoordSeq_getY_r( geosinit()->ctxt, coordSeq, coordSeqSize - 1, &y2 );
 
 2707 static geos::unique_ptr _mergeLinestrings( 
const GEOSGeometry *line1, 
const GEOSGeometry *line2, 
const QgsPointXY &intersectionPoint )
 
 2709   double x1, y1, x2, y2;
 
 2710   if ( !_linestringEndpoints( line1, x1, y1, x2, y2 ) )
 
 2713   double rx1, ry1, rx2, ry2;
 
 2714   if ( !_linestringEndpoints( line2, rx1, ry1, rx2, ry2 ) )
 
 2717   bool intersectionAtOrigLineEndpoint =
 
 2718     ( intersectionPoint.
x() == x1 && intersectionPoint.
y() == y1 ) !=
 
 2719     ( intersectionPoint.
x() == x2 && intersectionPoint.
y() == y2 );
 
 2720   bool intersectionAtReshapeLineEndpoint =
 
 2721     ( intersectionPoint.
x() == rx1 && intersectionPoint.
y() == ry1 ) ||
 
 2722     ( intersectionPoint.
x() == rx2 && intersectionPoint.
y() == ry2 );
 
 2725   if ( intersectionAtOrigLineEndpoint && intersectionAtReshapeLineEndpoint )
 
 2729     GEOSGeometry *geoms[2] = { g1.release(), g2.release() };
 
 2730     geos::unique_ptr multiGeom( GEOSGeom_createCollection_r( geosinit()->ctxt, GEOS_MULTILINESTRING, geoms, 2 ) );
 
 2731     geos::unique_ptr res( GEOSLineMerge_r( geosinit()->ctxt, multiGeom.get() ) );
 
 2739 geos::unique_ptr QgsGeos::reshapeLine( 
const GEOSGeometry *line, 
const GEOSGeometry *reshapeLineGeos, 
double precision )
 
 2741   if ( !line || !reshapeLineGeos )
 
 2744   bool atLeastTwoIntersections = 
false;
 
 2745   bool oneIntersection = 
false;
 
 2751     geos::unique_ptr intersectGeom( GEOSIntersection_r( geosinit()->ctxt, line, reshapeLineGeos ) );
 
 2752     if ( intersectGeom )
 
 2754       const int geomType = GEOSGeomTypeId_r( geosinit()->ctxt, intersectGeom.get() );
 
 2755       atLeastTwoIntersections = ( geomType == GEOS_MULTIPOINT && GEOSGetNumGeometries_r( geosinit()->ctxt, intersectGeom.get() ) > 1 )
 
 2756                                 || ( geomType == GEOS_GEOMETRYCOLLECTION && GEOSGetNumGeometries_r( geosinit()->ctxt, intersectGeom.get() ) > 0 ) 
 
 2757                                 || ( geomType == GEOS_MULTILINESTRING && GEOSGetNumGeometries_r( geosinit()->ctxt, intersectGeom.get() ) > 0 );
 
 2759       if ( GEOSGeomTypeId_r( geosinit()->ctxt, intersectGeom.get() ) == GEOS_POINT )
 
 2761         const GEOSCoordSequence *intersectionCoordSeq = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, intersectGeom.get() );
 
 2763         GEOSCoordSeq_getX_r( geosinit()->ctxt, intersectionCoordSeq, 0, &xi );
 
 2764         GEOSCoordSeq_getY_r( geosinit()->ctxt, intersectionCoordSeq, 0, &yi );
 
 2765         oneIntersection = 
true;
 
 2770   catch ( GEOSException & )
 
 2772     atLeastTwoIntersections = 
false;
 
 2776   if ( oneIntersection )
 
 2777     return _mergeLinestrings( line, reshapeLineGeos, oneIntersectionPoint );
 
 2779   if ( !atLeastTwoIntersections )
 
 2783   double x1, y1, x2, y2;
 
 2784   if ( !_linestringEndpoints( line, x1, y1, x2, y2 ) )
 
 2790   bool isRing = 
false;
 
 2791   if ( GEOSGeomTypeId_r( geosinit()->ctxt, line ) == GEOS_LINEARRING
 
 2792        || GEOSEquals_r( geosinit()->ctxt, beginLineVertex.get(), endLineVertex.get() ) == 1 )
 
 2797   if ( !nodedGeometry )
 
 2803   geos::unique_ptr mergedLines( GEOSLineMerge_r( geosinit()->ctxt, nodedGeometry.get() ) );
 
 2809   int numMergedLines = GEOSGetNumGeometries_r( geosinit()->ctxt, mergedLines.get() );
 
 2810   if ( numMergedLines < 2 ) 
 
 2812     if ( numMergedLines == 1 ) 
 
 2814       geos::unique_ptr result( GEOSGeom_clone_r( geosinit()->ctxt, reshapeLineGeos ) );
 
 2821   QVector<GEOSGeometry *> resultLineParts; 
 
 2822   QVector<GEOSGeometry *> probableParts; 
 
 2824   for ( 
int i = 0; i < numMergedLines; ++i )
 
 2826     const GEOSGeometry *currentGeom = GEOSGetGeometryN_r( geosinit()->ctxt, mergedLines.get(), i );
 
 2829     bool alreadyAdded = 
false;
 
 2831     double bufferDistance = std::pow( 10.0L, geomDigits( currentGeom ) - 11 );
 
 2832     for ( 
const GEOSGeometry *other : std::as_const( resultLineParts ) )
 
 2834       GEOSHausdorffDistance_r( geosinit()->ctxt, currentGeom, other, &
distance );
 
 2837         alreadyAdded = 
true;
 
 2844     const GEOSCoordSequence *currentCoordSeq = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, currentGeom );
 
 2845     unsigned int currentCoordSeqSize;
 
 2846     GEOSCoordSeq_getSize_r( geosinit()->ctxt, currentCoordSeq, ¤tCoordSeqSize );
 
 2847     if ( currentCoordSeqSize < 2 )
 
 2851     double xBegin, xEnd, yBegin, yEnd;
 
 2852     GEOSCoordSeq_getX_r( geosinit()->ctxt, currentCoordSeq, 0, &xBegin );
 
 2853     GEOSCoordSeq_getY_r( geosinit()->ctxt, currentCoordSeq, 0, &yBegin );
 
 2854     GEOSCoordSeq_getX_r( geosinit()->ctxt, currentCoordSeq, currentCoordSeqSize - 1, &xEnd );
 
 2855     GEOSCoordSeq_getY_r( geosinit()->ctxt, currentCoordSeq, currentCoordSeqSize - 1, &yEnd );
 
 2860     int nEndpointsOnOriginalLine = 0;
 
 2861     if ( pointContainedInLine( beginCurrentGeomVertex.get(), line ) == 1 )
 
 2862       nEndpointsOnOriginalLine += 1;
 
 2864     if ( pointContainedInLine( endCurrentGeomVertex.get(), line ) == 1 )
 
 2865       nEndpointsOnOriginalLine += 1;
 
 2868     int nEndpointsSameAsOriginalLine = 0;
 
 2869     if ( GEOSEquals_r( geosinit()->ctxt, beginCurrentGeomVertex.get(), beginLineVertex.get() ) == 1
 
 2870          || GEOSEquals_r( geosinit()->ctxt, beginCurrentGeomVertex.get(), endLineVertex.get() ) == 1 )
 
 2871       nEndpointsSameAsOriginalLine += 1;
 
 2873     if ( GEOSEquals_r( geosinit()->ctxt, endCurrentGeomVertex.get(), beginLineVertex.get() ) == 1
 
 2874          || GEOSEquals_r( geosinit()->ctxt, endCurrentGeomVertex.get(), endLineVertex.get() ) == 1 )
 
 2875       nEndpointsSameAsOriginalLine += 1;
 
 2878     bool currentGeomOverlapsOriginalGeom = 
false;
 
 2879     bool currentGeomOverlapsReshapeLine = 
false;
 
 2880     if ( lineContainedInLine( currentGeom, line ) == 1 )
 
 2881       currentGeomOverlapsOriginalGeom = 
true;
 
 2883     if ( lineContainedInLine( currentGeom, reshapeLineGeos ) == 1 )
 
 2884       currentGeomOverlapsReshapeLine = 
true;
 
 2887     if ( !isRing && nEndpointsSameAsOriginalLine == 1 && nEndpointsOnOriginalLine == 2 && currentGeomOverlapsOriginalGeom )
 
 2889       resultLineParts.push_back( GEOSGeom_clone_r( geosinit()->ctxt, currentGeom ) );
 
 2892     else if ( isRing && nEndpointsOnOriginalLine == 2 && currentGeomOverlapsOriginalGeom )
 
 2894       probableParts.push_back( GEOSGeom_clone_r( geosinit()->ctxt, currentGeom ) );
 
 2896     else if ( nEndpointsOnOriginalLine == 2 && !currentGeomOverlapsOriginalGeom )
 
 2898       resultLineParts.push_back( GEOSGeom_clone_r( geosinit()->ctxt, currentGeom ) );
 
 2900     else if ( nEndpointsSameAsOriginalLine == 2 && !currentGeomOverlapsOriginalGeom )
 
 2902       resultLineParts.push_back( GEOSGeom_clone_r( geosinit()->ctxt, currentGeom ) );
 
 2904     else if ( currentGeomOverlapsOriginalGeom && currentGeomOverlapsReshapeLine )
 
 2906       resultLineParts.push_back( GEOSGeom_clone_r( geosinit()->ctxt, currentGeom ) );
 
 2911   if ( isRing && !probableParts.isEmpty() )
 
 2914     GEOSGeometry *currentGeom = 
nullptr;
 
 2915     double maxLength = -std::numeric_limits<double>::max();
 
 2916     double currentLength = 0;
 
 2917     for ( 
int i = 0; i < probableParts.size(); ++i )
 
 2919       currentGeom = probableParts.at( i );
 
 2920       GEOSLength_r( geosinit()->ctxt, currentGeom, ¤tLength );
 
 2921       if ( currentLength > maxLength )
 
 2923         maxLength = currentLength;
 
 2924         maxGeom.reset( currentGeom );
 
 2928         GEOSGeom_destroy_r( geosinit()->ctxt, currentGeom );
 
 2931     resultLineParts.push_back( maxGeom.release() );
 
 2935   if ( resultLineParts.empty() )
 
 2938   if ( resultLineParts.size() == 1 ) 
 
 2940     result.reset( resultLineParts[0] );
 
 2944     GEOSGeometry **lineArray = 
new GEOSGeometry*[resultLineParts.size()];
 
 2945     for ( 
int i = 0; i < resultLineParts.size(); ++i )
 
 2947       lineArray[i] = resultLineParts[i];
 
 2951     geos::unique_ptr multiLineGeom( GEOSGeom_createCollection_r( geosinit()->ctxt, GEOS_MULTILINESTRING, lineArray, resultLineParts.size() ) );
 
 2952     delete [] lineArray;
 
 2955     result.reset( GEOSLineMerge_r( geosinit()->ctxt, multiLineGeom.get() ) );
 
 2959   if ( GEOSGeomTypeId_r( geosinit()->ctxt, result.get() ) != GEOS_LINESTRING )
 
 2967 geos::unique_ptr QgsGeos::reshapePolygon( 
const GEOSGeometry *polygon, 
const GEOSGeometry *reshapeLineGeos, 
double precision )
 
 2970   int nIntersections = 0;
 
 2971   int lastIntersectingRing = -2;
 
 2972   const GEOSGeometry *lastIntersectingGeom = 
nullptr;
 
 2974   int nRings = GEOSGetNumInteriorRings_r( geosinit()->ctxt, polygon );
 
 2979   const GEOSGeometry *outerRing = GEOSGetExteriorRing_r( geosinit()->ctxt, polygon );
 
 2980   if ( GEOSIntersects_r( geosinit()->ctxt, outerRing, reshapeLineGeos ) == 1 )
 
 2983     lastIntersectingRing = -1;
 
 2984     lastIntersectingGeom = outerRing;
 
 2988   const GEOSGeometry **innerRings = 
new const GEOSGeometry*[nRings];
 
 2992     for ( 
int i = 0; i < nRings; ++i )
 
 2994       innerRings[i] = GEOSGetInteriorRingN_r( geosinit()->ctxt, polygon, i );
 
 2995       if ( GEOSIntersects_r( geosinit()->ctxt, innerRings[i], reshapeLineGeos ) == 1 )
 
 2998         lastIntersectingRing = i;
 
 2999         lastIntersectingGeom = innerRings[i];
 
 3003   catch ( GEOSException & )
 
 3008   if ( nIntersections != 1 ) 
 
 3010     delete [] innerRings;
 
 3016   if ( !reshapeResult )
 
 3018     delete [] innerRings;
 
 3023   GEOSGeometry *newRing = 
nullptr;
 
 3024   const GEOSCoordSequence *reshapeSequence = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, reshapeResult.get() );
 
 3025   GEOSCoordSequence *newCoordSequence = GEOSCoordSeq_clone_r( geosinit()->ctxt, reshapeSequence );
 
 3027   reshapeResult.reset();
 
 3029   newRing = GEOSGeom_createLinearRing_r( geosinit()->ctxt, newCoordSequence );
 
 3032     delete [] innerRings;
 
 3036   GEOSGeometry *newOuterRing = 
nullptr;
 
 3037   if ( lastIntersectingRing == -1 )
 
 3038     newOuterRing = newRing;
 
 3040     newOuterRing = GEOSGeom_clone_r( geosinit()->ctxt, outerRing );
 
 3043   QVector<GEOSGeometry *> ringList;
 
 3046     GEOSGeometry *outerRingPoly = GEOSGeom_createPolygon_r( geosinit()->ctxt, GEOSGeom_clone_r( geosinit()->ctxt, newOuterRing ), 
nullptr, 0 );
 
 3047     if ( outerRingPoly )
 
 3049       ringList.reserve( nRings );
 
 3050       GEOSGeometry *currentRing = 
nullptr;
 
 3051       for ( 
int i = 0; i < nRings; ++i )
 
 3053         if ( lastIntersectingRing == i )
 
 3054           currentRing = newRing;
 
 3056           currentRing = GEOSGeom_clone_r( geosinit()->ctxt, innerRings[i] );
 
 3059         if ( GEOSContains_r( geosinit()->ctxt, outerRingPoly, currentRing ) == 1 )
 
 3060           ringList.push_back( currentRing );
 
 3062           GEOSGeom_destroy_r( geosinit()->ctxt, currentRing );
 
 3065     GEOSGeom_destroy_r( geosinit()->ctxt, outerRingPoly );
 
 3068   GEOSGeometry **newInnerRings = 
new GEOSGeometry*[ringList.size()];
 
 3069   for ( 
int i = 0; i < ringList.size(); ++i )
 
 3070     newInnerRings[i] = ringList.at( i );
 
 3072   delete [] innerRings;
 
 3074   geos::unique_ptr reshapedPolygon( GEOSGeom_createPolygon_r( geosinit()->ctxt, newOuterRing, newInnerRings, ringList.size() ) );
 
 3075   delete[] newInnerRings;
 
 3077   return reshapedPolygon;
 
 3080 int QgsGeos::lineContainedInLine( 
const GEOSGeometry *line1, 
const GEOSGeometry *line2 )
 
 3082   if ( !line1 || !line2 )
 
 3087   double bufferDistance = std::pow( 10.0L, geomDigits( line2 ) - 11 );
 
 3093   geos::unique_ptr intersectionGeom( GEOSIntersection_r( geosinit()->ctxt, bufferGeom.get(), line1 ) );
 
 3096   double intersectGeomLength;
 
 3099   GEOSLength_r( geosinit()->ctxt, intersectionGeom.get(), &intersectGeomLength );
 
 3100   GEOSLength_r( geosinit()->ctxt, line1, &line1Length );
 
 3102   double intersectRatio = line1Length / intersectGeomLength;
 
 3103   if ( intersectRatio > 0.9 && intersectRatio < 1.1 )
 
 3109 int QgsGeos::pointContainedInLine( 
const GEOSGeometry *point, 
const GEOSGeometry *line )
 
 3111   if ( !point || !line )
 
 3114   double bufferDistance = std::pow( 10.0L, geomDigits( line ) - 11 );
 
 3116   geos::unique_ptr lineBuffer( GEOSBuffer_r( geosinit()->ctxt, line, bufferDistance, 8 ) );
 
 3120   bool contained = 
false;
 
 3121   if ( GEOSContains_r( geosinit()->ctxt, lineBuffer.get(), point ) == 1 )
 
 3127 int QgsGeos::geomDigits( 
const GEOSGeometry *geom )
 
 3133   const GEOSGeometry *bBoxRing = GEOSGetExteriorRing_r( geosinit()->ctxt, bbox.get() );
 
 3137   const GEOSCoordSequence *bBoxCoordSeq = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, bBoxRing );
 
 3139   if ( !bBoxCoordSeq )
 
 3142   unsigned int nCoords = 0;
 
 3143   if ( !GEOSCoordSeq_getSize_r( geosinit()->ctxt, bBoxCoordSeq, &nCoords ) )
 
 3147   for ( 
unsigned int i = 0; i < nCoords - 1; ++i )
 
 3150     GEOSCoordSeq_getX_r( geosinit()->ctxt, bBoxCoordSeq, i, &t );
 
 3153     digits = std::ceil( std::log10( std::fabs( t ) ) );
 
 3154     if ( digits > maxDigits )
 
 3157     GEOSCoordSeq_getY_r( geosinit()->ctxt, bBoxCoordSeq, i, &t );
 
 3158     digits = std::ceil( std::log10( std::fabs( t ) ) );
 
 3159     if ( digits > maxDigits )
 
 3168   return geosinit()->ctxt;
 
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 QgsGeometry::OperationResult 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.
OperationResult
Success or failure of a geometry operation.
@ InvalidBaseGeometry
The base geometry on which the operation is done is invalid or empty.
@ AddPartNotMultiGeometry
The source geometry is not multi.
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.
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.
static QgsGeometry::OperationResult addPart(QgsGeometry &geometry, GEOSGeometry *newPart)
Adds a new island polygon to a multipolygon feature.
QgsGeometry shortestLine(const QgsGeometry &other, QString *errorMsg=nullptr) const
Returns the shortest line joining this geometry to the other geometry.
QgsAbstractGeometry * offsetCurve(double distance, int segments, int joinStyle, double miterLimit, QString *errorMsg=nullptr) const override
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.
std::unique_ptr< QgsAbstractGeometry > singleSidedBuffer(double distance, int segments, int side, int joinStyle, double miterLimit, QString *errorMsg=nullptr) const
Returns a single sided buffer for a geometry.
static std::unique_ptr< QgsAbstractGeometry > fromGeos(const GEOSGeometry *geos)
Create a geometry from a GEOSGeometry.
QgsAbstractGeometry * interpolate(double distance, QString *errorMsg=nullptr) const override
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...
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
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.