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(); \ 
   51static 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 );
 
   83static void printGEOSNotice( 
const char *fmt, ... )
 
   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 );
 
  170#if GEOS_VERSION_MAJOR==3 && GEOS_VERSION_MINOR<10 
  172    throw QgsNotSupportedException( QObject::tr( 
"The structured method to make geometries valid requires a QGIS build based on GEOS 3.10 or later" ) );
 
  175    throw QgsNotSupportedException( QObject::tr( 
"The keep collapsed option for making geometries valid requires a QGIS build based on GEOS 3.10 or later" ) );
 
  179    geos.reset( GEOSMakeValid_r( geosinit()->ctxt, mGeos.get() ) );
 
  184  GEOSMakeValidParams *params = GEOSMakeValidParams_create_r( geosinit()->ctxt );
 
  188      GEOSMakeValidParams_setMethod_r( geosinit()->ctxt, params, GEOS_MAKE_VALID_LINEWORK );
 
  192      GEOSMakeValidParams_setMethod_r( geosinit()->ctxt, params, GEOS_MAKE_VALID_STRUCTURE );
 
  196  GEOSMakeValidParams_setKeepCollapsed_r( geosinit()->ctxt,
 
  198                                          keepCollapsed ? 1 : 0 );
 
  203    geos.reset( GEOSMakeValidWithParams_r( geosinit()->ctxt, mGeos.get(), params ) );
 
  204    GEOSMakeValidParams_destroy_r( geosinit()->ctxt, params );
 
  206  catch ( GEOSException &e )
 
  210      *errorMsg = e.what();
 
  212    GEOSMakeValidParams_destroy_r( geosinit()->ctxt, params );
 
  241  std::unique_ptr< QgsAbstractGeometry > geom = 
fromGeos( newPart );
 
  248  mGeosPrepared.reset();
 
  261    mGeosPrepared.reset( GEOSPrepare_r( geosinit()->ctxt, mGeos.get() ) );
 
  265void QgsGeos::cacheGeos()
 const 
  282  return overlay( geom, OverlayIntersection, errorMsg, parameters ).release();
 
  287  return overlay( geom, OverlayDifference, errorMsg, parameters ).release();
 
  302  catch ( GEOSException &e )
 
  304    logError( QStringLiteral( 
"GEOS" ), e.what() );
 
  307      *errorMsg = e.what();
 
  318  int partType = GEOSGeomTypeId_r( geosinit()->ctxt, currentPart );
 
  321    if ( partType == GEOS_POINT )
 
  332  if ( partType == GEOS_MULTILINESTRING || partType == GEOS_MULTIPOLYGON || partType == GEOS_GEOMETRYCOLLECTION )
 
  334    int partCount = GEOSGetNumGeometries_r( geosinit()->ctxt, currentPart );
 
  335    for ( 
int i = 0; i < partCount; ++i )
 
  337      subdivideRecursive( GEOSGetGeometryN_r( geosinit()->ctxt, currentPart, i ), maxNodes, depth, parts, clipRect, gridSize );
 
  348  int vertexCount = GEOSGetNumCoordinates_r( geosinit()->ctxt, currentPart );
 
  349  if ( vertexCount == 0 )
 
  353  else if ( vertexCount < maxNodes )
 
  360  double width = clipRect.
width();
 
  361  double height = clipRect.
height();
 
  364  if ( width > height )
 
  377    halfClipRect1.
setYMinimum( halfClipRect1.
yMinimum() - std::numeric_limits<double>::epsilon() );
 
  378    halfClipRect2.
setYMinimum( halfClipRect2.
yMinimum() - std::numeric_limits<double>::epsilon() );
 
  379    halfClipRect1.
setYMaximum( halfClipRect1.
yMaximum() + std::numeric_limits<double>::epsilon() );
 
  380    halfClipRect2.
setYMaximum( halfClipRect2.
yMaximum() + std::numeric_limits<double>::epsilon() );
 
  384    halfClipRect1.
setXMinimum( halfClipRect1.
xMinimum() - std::numeric_limits<double>::epsilon() );
 
  385    halfClipRect2.
setXMinimum( halfClipRect2.
xMinimum() - std::numeric_limits<double>::epsilon() );
 
  386    halfClipRect1.
setXMaximum( halfClipRect1.
xMaximum() + std::numeric_limits<double>::epsilon() );
 
  387    halfClipRect2.
setXMaximum( halfClipRect2.
xMaximum() + std::numeric_limits<double>::epsilon() );
 
  399      clipPart1.reset( GEOSIntersectionPrec_r( geosinit()->ctxt, mGeos.get(), clipPart1.get(), gridSize ) );
 
  401    subdivideRecursive( clipPart1.get(), maxNodes, depth, parts, halfClipRect1, gridSize );
 
  407      clipPart2.reset( GEOSIntersectionPrec_r( geosinit()->ctxt, mGeos.get(), clipPart2.get(), gridSize ) );
 
  409    subdivideRecursive( clipPart2.get(), maxNodes, depth, parts, halfClipRect2, gridSize );
 
  421  maxNodes = std::max( maxNodes, 8 );
 
  430  return std::move( parts );
 
  435  return overlay( geom, OverlayUnion, errorMsg, parameters ).release();
 
  440  QVector< GEOSGeometry * > geosGeometries;
 
  441  geosGeometries.reserve( geomList.size() );
 
  447    geosGeometries << 
asGeos( g, mPrecision ).release();
 
  453    geos::unique_ptr geomCollection = createGeosCollection( GEOS_GEOMETRYCOLLECTION, geosGeometries );
 
  456      geomUnion.reset( GEOSUnaryUnionPrec_r( geosinit()->ctxt, geomCollection.get(), parameters.
gridSize() ) );
 
  460      geomUnion.reset( GEOSUnaryUnion_r( geosinit()->ctxt, geomCollection.get() ) );
 
  465  std::unique_ptr< QgsAbstractGeometry > result = 
fromGeos( geomUnion.get() );
 
  466  return result.release();
 
  471  QVector< GEOSGeometry * > geosGeometries;
 
  472  geosGeometries.reserve( geomList.size() );
 
  478    geosGeometries << 
asGeos( g.constGet(), mPrecision ).release();
 
  484    geos::unique_ptr geomCollection = createGeosCollection( GEOS_GEOMETRYCOLLECTION, geosGeometries );
 
  488      geomUnion.reset( GEOSUnaryUnionPrec_r( geosinit()->ctxt, geomCollection.get(), parameters.
gridSize() ) );
 
  492      geomUnion.reset( GEOSUnaryUnion_r( geosinit()->ctxt, geomCollection.get() ) );
 
  498  std::unique_ptr< QgsAbstractGeometry > result = 
fromGeos( geomUnion.get() );
 
  499  return result.release();
 
  504  return overlay( geom, OverlaySymDifference, errorMsg, parameters ).release();
 
  516  if ( !otherGeosGeom )
 
  525      GEOSPreparedDistance_r( geosinit()->ctxt, mGeosPrepared.get(), otherGeosGeom.get(), &
distance );
 
  529      GEOSDistance_r( geosinit()->ctxt, mGeos.get(), otherGeosGeom.get(), &
distance );
 
  545  geos::unique_ptr point = createGeosPointXY( x, y, 
false, 0, 
false, 0, 2, 0 );
 
  553      GEOSPreparedDistance_r( geosinit()->ctxt, mGeosPrepared.get(), point.get(), &
distance );
 
  557      GEOSDistance_r( geosinit()->ctxt, mGeos.get(), point.get(), &
distance );
 
  573  if ( !otherGeosGeom )
 
  588#if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=10 ) 
  589      return GEOSPreparedDistanceWithin_r( geosinit()->ctxt, mGeosPrepared.get(), otherGeosGeom.get(), maxdist );
 
  591      GEOSPreparedDistance_r( geosinit()->ctxt, mGeosPrepared.get(), otherGeosGeom.get(), &
distance );
 
  596#if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=10 ) 
  597      return GEOSDistanceWithin_r( geosinit()->ctxt, mGeos.get(), otherGeosGeom.get(), maxdist );
 
  599      GEOSDistance_r( geosinit()->ctxt, mGeos.get(), otherGeosGeom.get(), &
distance );
 
  610  geos::unique_ptr point = createGeosPointXY( x, y, 
false, 0, 
false, 0, 2, 0 );
 
  619      return GEOSPreparedContains_r( geosinit()->ctxt, mGeosPrepared.get(), point.get() ) == 1;
 
  622    result = ( GEOSContains_r( geosinit()->ctxt, mGeos.get(), point.get() ) == 1 );
 
  624  catch ( GEOSException &e )
 
  626    logError( QStringLiteral( 
"GEOS" ), e.what() );
 
  629      *errorMsg = e.what();
 
  646  if ( !otherGeosGeom )
 
  653    GEOSHausdorffDistance_r( geosinit()->ctxt, mGeos.get(), otherGeosGeom.get(), &
distance );
 
  669  if ( !otherGeosGeom )
 
  676    GEOSHausdorffDistanceDensify_r( geosinit()->ctxt, mGeos.get(), otherGeosGeom.get(), densifyFraction, &
distance );
 
  692  if ( !otherGeosGeom )
 
  699    GEOSFrechetDistance_r( geosinit()->ctxt, mGeos.get(), otherGeosGeom.get(), &
distance );
 
  715  if ( !otherGeosGeom )
 
  722    GEOSFrechetDistanceDensify_r( geosinit()->ctxt, mGeos.get(), otherGeosGeom.get(), densifyFraction, &
distance );
 
  731  return relation( geom, RelationIntersects, errorMsg );
 
  736  return relation( geom, RelationTouches, errorMsg );
 
  741  return relation( geom, RelationCrosses, errorMsg );
 
  746  return relation( geom, RelationWithin, errorMsg );
 
  751  return relation( geom, RelationOverlaps, errorMsg );
 
  756  return relation( geom, RelationContains, errorMsg );
 
  761  return relation( geom, RelationDisjoint, errorMsg );
 
  780    char *r = GEOSRelate_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() );
 
  783      result = QString( r );
 
  784      GEOSFree_r( geosinit()->ctxt, r );
 
  787  catch ( GEOSException &e )
 
  789    logError( QStringLiteral( 
"GEOS" ), e.what() );
 
  792      *errorMsg = e.what();
 
  801  if ( !mGeos || !geom )
 
  815    result = ( GEOSRelatePattern_r( geosinit()->ctxt, mGeos.get(), geosGeom.get(), pattern.toLocal8Bit().constData() ) == 1 );
 
  817  catch ( GEOSException &e )
 
  819    logError( QStringLiteral( 
"GEOS" ), e.what() );
 
  822      *errorMsg = e.what();
 
  839    if ( GEOSArea_r( geosinit()->ctxt, mGeos.get(), &
area ) != 1 )
 
  855    if ( GEOSLength_r( geosinit()->ctxt, mGeos.get(), &
length ) != 1 )
 
  863    QVector<QgsGeometry> &newGeometries,
 
  866    QString *errorMsg, 
bool skipIntersectionCheck )
 const 
  881  if ( !GEOSisValid_r( geosinit()->ctxt, mGeos.get() ) )
 
  889  newGeometries.clear();
 
  896      splitLineGeos = createGeosLinestring( &splitLine, mPrecision );
 
  900      splitLineGeos = createGeosPointXY( splitLine.
xAt( 0 ), splitLine.
yAt( 0 ), 
false, 0, 
false, 0, 2, mPrecision );
 
  907    if ( !GEOSisValid_r( geosinit()->ctxt, splitLineGeos.get() ) || !GEOSisSimple_r( geosinit()->ctxt, splitLineGeos.get() ) )
 
  915      if ( !topologicalTestPointsSplit( splitLineGeos.get(), topologyTestPoints ) )
 
  924      returnCode = splitLinearGeometry( splitLineGeos.get(), newGeometries, skipIntersectionCheck );
 
  928      returnCode = splitPolygonGeometry( splitLineGeos.get(), newGeometries, skipIntersectionCheck );
 
  956    geos::unique_ptr intersectionGeom( GEOSIntersection_r( geosinit()->ctxt, mGeos.get(), splitLine ) );
 
  957    if ( !intersectionGeom )
 
  961    int nIntersectGeoms = 1;
 
  962    if ( GEOSGeomTypeId_r( geosinit()->ctxt, intersectionGeom.get() ) == GEOS_LINESTRING
 
  963         || GEOSGeomTypeId_r( geosinit()->ctxt, intersectionGeom.get() ) == GEOS_POINT )
 
  967      nIntersectGeoms = GEOSGetNumGeometries_r( geosinit()->ctxt, intersectionGeom.get() );
 
  969    for ( 
int i = 0; i < nIntersectGeoms; ++i )
 
  973        currentIntersectGeom = intersectionGeom.get();
 
  975        currentIntersectGeom = GEOSGetGeometryN_r( geosinit()->ctxt, intersectionGeom.get(), i );
 
  977      const GEOSCoordSequence *lineSequence = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, currentIntersectGeom );
 
  978      unsigned int sequenceSize = 0;
 
  980      if ( GEOSCoordSeq_getSize_r( geosinit()->ctxt, lineSequence, &sequenceSize ) != 0 )
 
  982        for ( 
unsigned int i = 0; i < sequenceSize; ++i )
 
  984          if ( GEOSCoordSeq_getXYZ_r( geosinit()->ctxt, lineSequence, i, &x, &y, &z ) )
 
  986            testPoints.push_back( 
QgsPoint( x, y, z ) );
 
  999  int type = GEOSGeomTypeId_r( geosinit()->ctxt, mGeos.get() );
 
 1001  std::unique_ptr< QgsMultiCurve > multiCurve;
 
 1002  if ( type == GEOS_MULTILINESTRING )
 
 1004    multiCurve.reset( qgsgeometry_cast<QgsMultiCurve *>( 
mGeometry->
clone() ) );
 
 1006  else if ( type == GEOS_LINESTRING )
 
 1024  std::unique_ptr< QgsAbstractGeometry > splitGeom( 
fromGeos( GEOSsplitPoint ) );
 
 1025  std::unique_ptr< QgsMultiPoint > splitPoints( qgsgeometry_cast<QgsMultiPoint *>( splitGeom->clone() ) );
 
 1028    QgsPoint *splitPoint = qgsgeometry_cast<QgsPoint *>( splitGeom->clone() );
 
 1034    splitPoints->addGeometry( splitPoint );
 
 1040  for ( 
int i = 0; i < multiCurve->numGeometries(); ++i )
 
 1042    const QgsLineString *line = qgsgeometry_cast<const QgsLineString *>( multiCurve->geometryN( i ) );
 
 1045      const QgsCurve *curve = qgsgeometry_cast<const QgsCurve *>( multiCurve->geometryN( i ) );
 
 1053    QMap< int, QVector< QPair< double, QgsPoint > > >pointMap;
 
 1054    for ( 
int p = 0; p < splitPoints->numGeometries(); ++p )
 
 1056      const QgsPoint *intersectionPoint = splitPoints->pointN( p );
 
 1061      line->
closestSegment( *intersectionPoint, segmentPoint2D, nextVertex );
 
 1069      const QPair< double, QgsPoint > pair = qMakePair( 
distance, *correctSegmentPoint.get() );
 
 1070      if ( pointMap.contains( nextVertex.
vertex - 1 ) )
 
 1071        pointMap[ nextVertex.
vertex - 1 ].append( pair );
 
 1073        pointMap[ nextVertex.
vertex - 1 ] = QVector< QPair< double, QgsPoint > >() << pair;
 
 1078    for ( 
auto &p : pointMap )
 
 1080      std::sort( p.begin(), p.end(), []( 
const QPair< double, QgsPoint > &a, 
const QPair< double, QgsPoint > &b ) { return a.first < b.first; } );
 
 1087    for ( 
int j = 0; j < nVertices; ++j )
 
 1091      if ( pointMap.contains( j ) )
 
 1094        for ( 
int k = 0; k < pointMap[ j ].size(); ++k )
 
 1096          splitPoint = pointMap[ j ][k].second;
 
 1097          if ( splitPoint == currentPoint )
 
 1103          else if ( splitPoint == line->
pointN( j + 1 ) )
 
 1122  return asGeos( &lines, mPrecision );
 
 1127  Q_UNUSED( skipIntersectionCheck )
 
 1134  geos::unique_ptr intersectGeom( GEOSIntersection_r( geosinit()->ctxt, splitLine, mGeos.get() ) );
 
 1135  if ( !intersectGeom || GEOSisEmpty_r( geosinit()->ctxt, intersectGeom.get() ) )
 
 1139  int linearIntersect = GEOSRelatePattern_r( geosinit()->ctxt, mGeos.get(), splitLine, 
"1********" );
 
 1140  if ( linearIntersect > 0 )
 
 1144  splitGeom = linePointDifference( intersectGeom.get() );
 
 1149  QVector<GEOSGeometry *> lineGeoms;
 
 1151  int splitType = GEOSGeomTypeId_r( geosinit()->ctxt, splitGeom.get() );
 
 1152  if ( splitType == GEOS_MULTILINESTRING )
 
 1154    int nGeoms = GEOSGetNumGeometries_r( geosinit()->ctxt, splitGeom.get() );
 
 1155    lineGeoms.reserve( nGeoms );
 
 1156    for ( 
int i = 0; i < nGeoms; ++i )
 
 1157      lineGeoms << GEOSGeom_clone_r( geosinit()->ctxt, GEOSGetGeometryN_r( geosinit()->ctxt, splitGeom.get(), i ) );
 
 1162    lineGeoms << GEOSGeom_clone_r( geosinit()->ctxt, splitGeom.get() );
 
 1165  mergeGeometriesMultiTypeSplit( lineGeoms );
 
 1167  for ( 
int i = 0; i < lineGeoms.size(); ++i )
 
 1170    GEOSGeom_destroy_r( geosinit()->ctxt, lineGeoms[i] );
 
 1186  if ( !mGeosPrepared )
 
 1190  if ( !skipIntersectionCheck && !GEOSPreparedIntersects_r( geosinit()->ctxt, mGeosPrepared.get(), splitLine ) )
 
 1195  if ( !nodedGeometry )
 
 1199  geos::unique_ptr polygons( GEOSPolygonize_r( geosinit()->ctxt, &noded, 1 ) );
 
 1200  if ( !polygons || numberOfGeometries( polygons.get() ) == 0 )
 
 1207  QVector<GEOSGeometry *> testedGeometries;
 
 1212  for ( 
int i = 0; i < numberOfGeometries( polygons.get() ); i++ )
 
 1214    const GEOSGeometry *polygon = GEOSGetGeometryN_r( geosinit()->ctxt, polygons.get(), i );
 
 1218      testedGeometries << GEOSGeom_clone_r( geosinit()->ctxt, polygon );
 
 1221  int nGeometriesThis = numberOfGeometries( mGeos.get() ); 
 
 1222  if ( testedGeometries.empty() || testedGeometries.size() == nGeometriesThis )
 
 1225    for ( 
int i = 0; i < testedGeometries.size(); ++i )
 
 1227      GEOSGeom_destroy_r( geosinit()->ctxt, testedGeometries[i] );
 
 1236  mergeGeometriesMultiTypeSplit( testedGeometries );
 
 1239  for ( i = 0; i < testedGeometries.size() && GEOSisValid_r( geosinit()->ctxt, testedGeometries[i] ); ++i )
 
 1242  if ( i < testedGeometries.size() )
 
 1244    for ( i = 0; i < testedGeometries.size(); ++i )
 
 1245      GEOSGeom_destroy_r( geosinit()->ctxt, testedGeometries[i] );
 
 1250  for ( i = 0; i < testedGeometries.size(); ++i )
 
 1253    GEOSGeom_destroy_r( geosinit()->ctxt, testedGeometries[i] );
 
 1261  if ( !splitLine || !geom )
 
 1265  if ( GEOSGeomTypeId_r( geosinit()->ctxt, geom ) == GEOS_POLYGON || GEOSGeomTypeId_r( geosinit()->ctxt, geom ) == GEOS_MULTIPOLYGON )
 
 1266    geometryBoundary.reset( GEOSBoundary_r( geosinit()->ctxt, geom ) );
 
 1268    geometryBoundary.reset( GEOSGeom_clone_r( geosinit()->ctxt, geom ) );
 
 1270  geos::unique_ptr splitLineClone( GEOSGeom_clone_r( geosinit()->ctxt, splitLine ) );
 
 1271  geos::unique_ptr unionGeometry( GEOSUnion_r( geosinit()->ctxt, splitLineClone.get(), geometryBoundary.get() ) );
 
 1273  return unionGeometry;
 
 1276int QgsGeos::mergeGeometriesMultiTypeSplit( QVector<GEOSGeometry *> &splitResult )
 const 
 1282  int type = GEOSGeomTypeId_r( geosinit()->ctxt, mGeos.get() );
 
 1283  if ( type != GEOS_GEOMETRYCOLLECTION &&
 
 1284       type != GEOS_MULTILINESTRING &&
 
 1285       type != GEOS_MULTIPOLYGON &&
 
 1286       type != GEOS_MULTIPOINT )
 
 1289  QVector<GEOSGeometry *> copyList = splitResult;
 
 1290  splitResult.clear();
 
 1293  QVector<GEOSGeometry *> unionGeom;
 
 1295  for ( 
int i = 0; i < copyList.size(); ++i )
 
 1298    bool isPart = 
false;
 
 1299    for ( 
int j = 0; j < GEOSGetNumGeometries_r( geosinit()->ctxt, mGeos.get() ); j++ )
 
 1301      if ( GEOSEquals_r( geosinit()->ctxt, copyList[i], GEOSGetGeometryN_r( geosinit()->ctxt, mGeos.get(), j ) ) )
 
 1310      unionGeom << copyList[i];
 
 1314      QVector<GEOSGeometry *> geomVector;
 
 1315      geomVector << copyList[i];
 
 1317      if ( type == GEOS_MULTILINESTRING )
 
 1318        splitResult << createGeosCollection( GEOS_MULTILINESTRING, geomVector ).release();
 
 1319      else if ( type == GEOS_MULTIPOLYGON )
 
 1320        splitResult << createGeosCollection( GEOS_MULTIPOLYGON, geomVector ).release();
 
 1322        GEOSGeom_destroy_r( geosinit()->ctxt, copyList[i] );
 
 1327  if ( !unionGeom.isEmpty() )
 
 1329    if ( type == GEOS_MULTILINESTRING )
 
 1330      splitResult << createGeosCollection( GEOS_MULTILINESTRING, unionGeom ).release();
 
 1331    else if ( type == GEOS_MULTIPOLYGON )
 
 1332      splitResult << createGeosCollection( GEOS_MULTIPOLYGON, unionGeom ).release();
 
 1342geos::unique_ptr QgsGeos::createGeosCollection( 
int typeId, 
const QVector<GEOSGeometry *> &geoms )
 
 1344  int nNullGeoms = geoms.count( 
nullptr );
 
 1345  int nNotNullGeoms = geoms.size() - nNullGeoms;
 
 1354  QVector<GEOSGeometry *>::const_iterator geomIt = geoms.constBegin();
 
 1355  for ( ; geomIt != geoms.constEnd(); ++geomIt )
 
 1359      if ( GEOSisEmpty_r( geosinit()->ctxt, *geomIt ) )
 
 1364        GEOSGeom_destroy_r( geosinit()->ctxt, *geomIt );
 
 1368        geomarr[i] = *geomIt;
 
 1377    geom.reset( GEOSGeom_createCollection_r( geosinit()->ctxt, typeId, geomarr, nNotNullGeoms ) );
 
 1379  catch ( GEOSException & )
 
 1395  int nCoordDims = GEOSGeom_getCoordinateDimension_r( geosinit()->ctxt, 
geos );
 
 1396  int nDims = GEOSGeom_getDimensions_r( geosinit()->ctxt, 
geos );
 
 1397  bool hasZ = ( nCoordDims == 3 );
 
 1398  bool hasM = ( ( nDims - nCoordDims ) == 1 );
 
 1400  switch ( GEOSGeomTypeId_r( geosinit()->ctxt, 
geos ) )
 
 1404      if ( GEOSisEmpty_r( geosinit()->ctxt, 
geos ) )
 
 1407      const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, 
geos );
 
 1408      unsigned int nPoints = 0;
 
 1409      GEOSCoordSeq_getSize_r( geosinit()->ctxt, cs, &nPoints );
 
 1410      return nPoints > 0 ? std::unique_ptr<QgsAbstractGeometry>( 
coordSeqPoint( cs, 0, hasZ, hasM ).clone() ) : 
nullptr;
 
 1412    case GEOS_LINESTRING:
 
 1414      return sequenceToLinestring( 
geos, hasZ, hasM );
 
 1420    case GEOS_MULTIPOINT:
 
 1422      std::unique_ptr< QgsMultiPoint > multiPoint( 
new QgsMultiPoint() );
 
 1423      int nParts = GEOSGetNumGeometries_r( geosinit()->ctxt, 
geos );
 
 1424      multiPoint->reserve( nParts );
 
 1425      for ( 
int i = 0; i < nParts; ++i )
 
 1427        const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, GEOSGetGeometryN_r( geosinit()->ctxt, 
geos, i ) );
 
 1430          unsigned int nPoints = 0;
 
 1431          GEOSCoordSeq_getSize_r( geosinit()->ctxt, cs, &nPoints );
 
 1433            multiPoint->addGeometry( 
coordSeqPoint( cs, 0, hasZ, hasM ).clone() );
 
 1436      return std::move( multiPoint );
 
 1438    case GEOS_MULTILINESTRING:
 
 1441      int nParts = GEOSGetNumGeometries_r( geosinit()->ctxt, 
geos );
 
 1442      multiLineString->reserve( nParts );
 
 1443      for ( 
int i = 0; i < nParts; ++i )
 
 1445        std::unique_ptr< QgsLineString >line( sequenceToLinestring( GEOSGetGeometryN_r( geosinit()->ctxt, 
geos, i ), hasZ, hasM ) );
 
 1448          multiLineString->addGeometry( line.release() );
 
 1451      return std::move( multiLineString );
 
 1453    case GEOS_MULTIPOLYGON:
 
 1455      std::unique_ptr< QgsMultiPolygon > multiPolygon( 
new QgsMultiPolygon() );
 
 1457      int nParts = GEOSGetNumGeometries_r( geosinit()->ctxt, 
geos );
 
 1458      multiPolygon->reserve( nParts );
 
 1459      for ( 
int i = 0; i < nParts; ++i )
 
 1461        std::unique_ptr< QgsPolygon > poly = 
fromGeosPolygon( GEOSGetGeometryN_r( geosinit()->ctxt, 
geos, i ) );
 
 1464          multiPolygon->addGeometry( poly.release() );
 
 1467      return std::move( multiPolygon );
 
 1469    case GEOS_GEOMETRYCOLLECTION:
 
 1472      int nParts = GEOSGetNumGeometries_r( geosinit()->ctxt, 
geos );
 
 1473      geomCollection->reserve( nParts );
 
 1474      for ( 
int i = 0; i < nParts; ++i )
 
 1476        std::unique_ptr< QgsAbstractGeometry > geom( 
fromGeos( GEOSGetGeometryN_r( geosinit()->ctxt, 
geos, i ) ) );
 
 1479          geomCollection->addGeometry( geom.release() );
 
 1482      return std::move( geomCollection );
 
 1490  if ( GEOSGeomTypeId_r( geosinit()->ctxt, 
geos ) != GEOS_POLYGON )
 
 1495  int nCoordDims = GEOSGeom_getCoordinateDimension_r( geosinit()->ctxt, 
geos );
 
 1496  int nDims = GEOSGeom_getDimensions_r( geosinit()->ctxt, 
geos );
 
 1497  bool hasZ = ( nCoordDims == 3 );
 
 1498  bool hasM = ( ( nDims - nCoordDims ) == 1 );
 
 1500  std::unique_ptr< QgsPolygon > polygon( 
new QgsPolygon() );
 
 1502  const GEOSGeometry *ring = GEOSGetExteriorRing_r( geosinit()->ctxt, 
geos );
 
 1505    polygon->setExteriorRing( sequenceToLinestring( ring, hasZ, hasM ).release() );
 
 1508  QVector<QgsCurve *> interiorRings;
 
 1509  const int ringCount = GEOSGetNumInteriorRings_r( geosinit()->ctxt, 
geos );
 
 1510  interiorRings.reserve( ringCount );
 
 1511  for ( 
int i = 0; i < ringCount; ++i )
 
 1513    ring = GEOSGetInteriorRingN_r( geosinit()->ctxt, 
geos, i );
 
 1516      interiorRings.push_back( sequenceToLinestring( ring, hasZ, hasM ).release() );
 
 1519  polygon->setInteriorRings( interiorRings );
 
 1524std::unique_ptr<QgsLineString> QgsGeos::sequenceToLinestring( 
const GEOSGeometry *
geos, 
bool hasZ, 
bool hasM )
 
 1526  const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, 
geos );
 
 1528  unsigned int nPoints;
 
 1529  GEOSCoordSeq_getSize_r( geosinit()->ctxt, cs, &nPoints );
 
 1531  QVector< double > xOut( nPoints );
 
 1532  QVector< double > yOut( nPoints );
 
 1533  QVector< double > zOut;
 
 1535    zOut.resize( nPoints );
 
 1536  QVector< double > mOut;
 
 1538    mOut.resize( nPoints );
 
 1540  double *x = xOut.data();
 
 1541  double *y = yOut.data();
 
 1542  double *z = zOut.data();
 
 1543  double *m = mOut.data();
 
 1545#if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=10 ) 
 1546  GEOSCoordSeq_copyToArrays_r( geosinit()->ctxt, cs, x, y, hasZ ? z : 
nullptr, hasM ? m : 
nullptr );
 
 1548  for ( 
unsigned int i = 0; i < nPoints; ++i )
 
 1551      GEOSCoordSeq_getXYZ_r( geosinit()->ctxt, cs, i, x++, y++, z++ );
 
 1553      GEOSCoordSeq_getXY_r( geosinit()->ctxt, cs, i, x++, y++ );
 
 1556      GEOSCoordSeq_getOrdinate_r( geosinit()->ctxt, cs, i, 3, m++ );
 
 1560  std::unique_ptr< QgsLineString > line( 
new QgsLineString( xOut, yOut, zOut, mOut ) );
 
 1569  int geometryType = GEOSGeomTypeId_r( geosinit()->ctxt, g );
 
 1570  if ( geometryType == GEOS_POINT || geometryType == GEOS_LINESTRING || geometryType == GEOS_LINEARRING
 
 1571       || geometryType == GEOS_POLYGON )
 
 1575  return GEOSGetNumGeometries_r( geosinit()->ctxt, g );
 
 1589    GEOSCoordSeq_getXYZ_r( geosinit()->ctxt, cs, i, &x, &y, &z );
 
 1591    GEOSCoordSeq_getXY_r( geosinit()->ctxt, cs, i, &x, &y );
 
 1594    GEOSCoordSeq_getOrdinate_r( geosinit()->ctxt, cs, i, 3, &m );
 
 1630    int geosType = GEOS_GEOMETRYCOLLECTION;
 
 1636        case Qgis::GeometryType::Point:
 
 1637          geosType = GEOS_MULTIPOINT;
 
 1640        case Qgis::GeometryType::Line:
 
 1641          geosType = GEOS_MULTILINESTRING;
 
 1644        case Qgis::GeometryType::Polygon:
 
 1645          geosType = GEOS_MULTIPOLYGON;
 
 1648        case Qgis::GeometryType::Unknown:
 
 1649        case Qgis::GeometryType::Null:
 
 1660    QVector< GEOSGeometry * > geomVector( 
c->numGeometries() );
 
 1661    for ( 
int i = 0; i < 
c->numGeometries(); ++i )
 
 1665    return createGeosCollection( geosType, geomVector );
 
 1671      case Qgis::GeometryType::Point:
 
 1672        return createGeosPoint( 
static_cast<const QgsPoint *
>( geom ), coordDims, 
precision );
 
 1674      case Qgis::GeometryType::Line:
 
 1677      case Qgis::GeometryType::Polygon:
 
 1680      case Qgis::GeometryType::Unknown:
 
 1681      case Qgis::GeometryType::Null:
 
 1690  if ( !mGeos || !geom )
 
 1701  const double gridSize = parameters.
gridSize();
 
 1708      case OverlayIntersection:
 
 1711          opGeom.reset( GEOSIntersectionPrec_r( geosinit()->ctxt, mGeos.get(), geosGeom.get(), gridSize ) );
 
 1715          opGeom.reset( GEOSIntersection_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) );
 
 1719      case OverlayDifference:
 
 1722          opGeom.reset( GEOSDifferencePrec_r( geosinit()->ctxt, mGeos.get(), geosGeom.get(), gridSize ) );
 
 1726          opGeom.reset( GEOSDifference_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) );
 
 1735          unionGeometry.reset( GEOSUnionPrec_r( geosinit()->ctxt, mGeos.get(), geosGeom.get(), gridSize ) );
 
 1739          unionGeometry.reset( GEOSUnion_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) );
 
 1742        if ( unionGeometry && GEOSGeomTypeId_r( geosinit()->ctxt, unionGeometry.get() ) == GEOS_MULTILINESTRING )
 
 1744          geos::unique_ptr mergedLines( GEOSLineMerge_r( geosinit()->ctxt, unionGeometry.get() ) );
 
 1747            unionGeometry = std::move( mergedLines );
 
 1751        opGeom = std::move( unionGeometry );
 
 1755      case OverlaySymDifference:
 
 1758          opGeom.reset( GEOSSymDifferencePrec_r( geosinit()->ctxt, mGeos.get(), geosGeom.get(), gridSize ) );
 
 1762          opGeom.reset( GEOSSymDifference_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) );
 
 1768  catch ( GEOSException &e )
 
 1770    logError( QStringLiteral( 
"GEOS" ), e.what() );
 
 1773      *errorMsg = e.what();
 
 1779bool QgsGeos::relation( 
const QgsAbstractGeometry *geom, Relation r, QString *errorMsg )
 const 
 1781  if ( !mGeos || !geom )
 
 1792  bool result = 
false;
 
 1795    if ( mGeosPrepared ) 
 
 1799        case RelationIntersects:
 
 1800          result = ( GEOSPreparedIntersects_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
 
 1802        case RelationTouches:
 
 1803          result = ( GEOSPreparedTouches_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
 
 1805        case RelationCrosses:
 
 1806          result = ( GEOSPreparedCrosses_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
 
 1808        case RelationWithin:
 
 1809          result = ( GEOSPreparedWithin_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
 
 1811        case RelationContains:
 
 1812          result = ( GEOSPreparedContains_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
 
 1814        case RelationDisjoint:
 
 1815          result = ( GEOSPreparedDisjoint_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
 
 1817        case RelationOverlaps:
 
 1818          result = ( GEOSPreparedOverlaps_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
 
 1826      case RelationIntersects:
 
 1827        result = ( GEOSIntersects_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
 
 1829      case RelationTouches:
 
 1830        result = ( GEOSTouches_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
 
 1832      case RelationCrosses:
 
 1833        result = ( GEOSCrosses_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
 
 1835      case RelationWithin:
 
 1836        result = ( GEOSWithin_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
 
 1838      case RelationContains:
 
 1839        result = ( GEOSContains_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
 
 1841      case RelationDisjoint:
 
 1842        result = ( GEOSDisjoint_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
 
 1844      case RelationOverlaps:
 
 1845        result = ( GEOSOverlaps_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
 
 1849  catch ( GEOSException &e )
 
 1851    logError( QStringLiteral( 
"GEOS" ), e.what() );
 
 1854      *errorMsg = e.what();
 
 1872    geos.reset( GEOSBuffer_r( geosinit()->ctxt, mGeos.get(), 
distance, segments ) );
 
 1888    geos.reset( GEOSBufferWithStyle_r( geosinit()->ctxt, mGeos.get(), 
distance, segments, 
static_cast< int >( endCapStyle ), 
static_cast< int >( joinStyle ), miterLimit ) );
 
 1903    geos.reset( GEOSTopologyPreserveSimplify_r( geosinit()->ctxt, mGeos.get(), tolerance ) );
 
 1918    geos.reset( GEOSInterpolate_r( geosinit()->ctxt, mGeos.get(), 
distance ) );
 
 1937    geos.reset( GEOSGetCentroid_r( geosinit()->ctxt,  mGeos.get() ) );
 
 1942    GEOSGeomGetX_r( geosinit()->ctxt, 
geos.get(), &x );
 
 1943    GEOSGeomGetY_r( geosinit()->ctxt, 
geos.get(), &y );
 
 1959    geos.reset( GEOSEnvelope_r( geosinit()->ctxt, mGeos.get() ) );
 
 1978    geos.reset( GEOSPointOnSurface_r( geosinit()->ctxt, mGeos.get() ) );
 
 1980    if ( !
geos || GEOSisEmpty_r( geosinit()->ctxt, 
geos.get() ) != 0 )
 
 1985    GEOSGeomGetX_r( geosinit()->ctxt, 
geos.get(), &x );
 
 1986    GEOSGeomGetY_r( geosinit()->ctxt, 
geos.get(), &y );
 
 2002    geos::unique_ptr cHull( GEOSConvexHull_r( geosinit()->ctxt, mGeos.get() ) );
 
 2003    std::unique_ptr< QgsAbstractGeometry > cHullGeom = 
fromGeos( cHull.get() );
 
 2004    return cHullGeom.release();
 
 2011#if GEOS_VERSION_MAJOR==3 && GEOS_VERSION_MINOR<11 
 2013  ( void )targetPercent;
 
 2015  throw QgsNotSupportedException( QObject::tr( 
"Calculating concaveHull requires a QGIS build based on GEOS 3.11 or later" ) );
 
 2026    return concaveHullGeom.release();
 
 2043    char res = GEOSisValidDetail_r( geosinit()->ctxt, mGeos.get(), allowSelfTouchingHoles ? GEOSVALID_ALLOW_SELFTOUCHING_RING_FORMING_HOLE : 0, &r, &g1 );
 
 2044    const bool invalid = res != 1;
 
 2049      error = QString( r );
 
 2050      GEOSFree_r( geosinit()->ctxt, r );
 
 2053    if ( invalid && errorMsg )
 
 2057      if ( translatedErrors.empty() )
 
 2060        translatedErrors.insert( QStringLiteral( 
"topology validation error" ), QObject::tr( 
"Topology validation error", 
"GEOS Error" ) );
 
 2061        translatedErrors.insert( QStringLiteral( 
"repeated point" ), QObject::tr( 
"Repeated point", 
"GEOS Error" ) );
 
 2062        translatedErrors.insert( QStringLiteral( 
"hole lies outside shell" ), QObject::tr( 
"Hole lies outside shell", 
"GEOS Error" ) );
 
 2063        translatedErrors.insert( QStringLiteral( 
"holes are nested" ), QObject::tr( 
"Holes are nested", 
"GEOS Error" ) );
 
 2064        translatedErrors.insert( QStringLiteral( 
"interior is disconnected" ), QObject::tr( 
"Interior is disconnected", 
"GEOS Error" ) );
 
 2065        translatedErrors.insert( QStringLiteral( 
"self-intersection" ), QObject::tr( 
"Self-intersection", 
"GEOS Error" ) );
 
 2066        translatedErrors.insert( QStringLiteral( 
"ring self-intersection" ), QObject::tr( 
"Ring self-intersection", 
"GEOS Error" ) );
 
 2067        translatedErrors.insert( QStringLiteral( 
"nested shells" ), QObject::tr( 
"Nested shells", 
"GEOS Error" ) );
 
 2068        translatedErrors.insert( QStringLiteral( 
"duplicate rings" ), QObject::tr( 
"Duplicate rings", 
"GEOS Error" ) );
 
 2069        translatedErrors.insert( QStringLiteral( 
"too few points in geometry component" ), QObject::tr( 
"Too few points in geometry component", 
"GEOS Error" ) );
 
 2070        translatedErrors.insert( QStringLiteral( 
"invalid coordinate" ), QObject::tr( 
"Invalid coordinate", 
"GEOS Error" ) );
 
 2071        translatedErrors.insert( QStringLiteral( 
"ring is not closed" ), QObject::tr( 
"Ring is not closed", 
"GEOS Error" ) );
 
 2074      *errorMsg = translatedErrors.value( error.toLower(), error );
 
 2076      if ( g1 && errorLoc )
 
 2082        GEOSGeom_destroy_r( geosinit()->ctxt, g1 );
 
 2092  if ( !mGeos || !geom )
 
 2104    bool equal = GEOSEquals_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() );
 
 2119    return GEOSisEmpty_r( geosinit()->ctxt, mGeos.get() );
 
 2133    return GEOSisSimple_r( geosinit()->ctxt, mGeos.get() );
 
 2138GEOSCoordSequence *QgsGeos::createCoordinateSequence( 
const QgsCurve *curve, 
double precision, 
bool forceClose )
 
 2140  GEOSContextHandle_t ctxt = geosinit()->ctxt;
 
 2142  std::unique_ptr< QgsLineString > segmentized;
 
 2143  const QgsLineString *line = qgsgeometry_cast<const QgsLineString *>( curve );
 
 2148    line = segmentized.get();
 
 2155  GEOSCoordSequence *coordSeq = 
nullptr;
 
 2157  const int numPoints = line->
numPoints();
 
 2159  const bool hasZ = line->
is3D();
 
 2161#if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=10 ) 
 2164    if ( !forceClose || ( line->
pointN( 0 ) == line->
pointN( numPoints - 1 ) ) )
 
 2169        coordSeq = GEOSCoordSeq_copyFromArrays_r( ctxt, line->
xData(), line->
yData(), line->
zData(), 
nullptr, numPoints );
 
 2172          QgsDebugError( QStringLiteral( 
"GEOS Exception: Could not create coordinate sequence for %1 points" ).arg( numPoints ) );
 
 2180      QVector< double > x = line->
xVector();
 
 2181      if ( numPoints > 0 )
 
 2182        x.append( x.at( 0 ) );
 
 2183      QVector< double > y = line->
yVector();
 
 2184      if ( numPoints > 0 )
 
 2185        y.append( y.at( 0 ) );
 
 2186      QVector< double > z = line->
zVector();
 
 2187      if ( hasZ && numPoints > 0 )
 
 2188        z.append( z.at( 0 ) );
 
 2191        coordSeq = GEOSCoordSeq_copyFromArrays_r( ctxt, x.constData(), y.constData(), !hasZ ? 
nullptr : z.constData(), 
nullptr, numPoints + 1 );
 
 2194          QgsDebugError( QStringLiteral( 
"GEOS Exception: Could not create closed coordinate sequence for %1 points" ).arg( numPoints + 1 ) );
 
 2205  const bool hasM = 
false; 
 
 2216  int numOutPoints = numPoints;
 
 2217  if ( forceClose && ( line->
pointN( 0 ) != line->
pointN( numPoints - 1 ) ) )
 
 2224    coordSeq = GEOSCoordSeq_create_r( ctxt, numOutPoints, coordDims );
 
 2227      QgsDebugError( QStringLiteral( 
"GEOS Exception: Could not create coordinate sequence for %1 points in %2 dimensions" ).arg( numPoints ).arg( coordDims ) );
 
 2231    const double *xData = line->
xData();
 
 2232    const double *yData = line->
yData();
 
 2233    const double *zData = hasZ ? line->
zData() : 
nullptr;
 
 2234    const double *mData = hasM ? line->
mData() : 
nullptr;
 
 2238      for ( 
int i = 0; i < numOutPoints; ++i )
 
 2240        if ( i >= numPoints )
 
 2243          xData = line->
xData();
 
 2244          yData = line->
yData();
 
 2245          zData = hasZ ? line->
zData() : 
nullptr;
 
 2246          mData = hasM ? line->
mData() : 
nullptr;
 
 2258          GEOSCoordSeq_setOrdinate_r( ctxt, coordSeq, i, 3, *mData++ );
 
 2264      for ( 
int i = 0; i < numOutPoints; ++i )
 
 2266        if ( i >= numPoints )
 
 2269          xData = line->
xData();
 
 2270          yData = line->
yData();
 
 2271          zData = hasZ ? line->
zData() : 
nullptr;
 
 2272          mData = hasM ? line->
mData() : 
nullptr;
 
 2276          GEOSCoordSeq_setXYZ_r( ctxt, coordSeq, i, *xData++, *yData++, *zData++ );
 
 2280          GEOSCoordSeq_setXY_r( ctxt, coordSeq, i, *xData++, *yData++ );
 
 2284          GEOSCoordSeq_setOrdinate_r( ctxt, coordSeq, i, 3, *mData++ );
 
 2296  const QgsPoint *pt = qgsgeometry_cast<const QgsPoint *>( point );
 
 2303geos::unique_ptr QgsGeos::createGeosPointXY( 
double x, 
double y, 
bool hasZ, 
double z, 
bool hasM, 
double m, 
int coordDims, 
double precision )
 
 2311    if ( coordDims == 2 )
 
 2317        geosPoint.reset( GEOSGeom_createPointFromXY_r( geosinit()->ctxt, x, y ) );
 
 2321    GEOSCoordSequence *coordSeq = GEOSCoordSeq_create_r( geosinit()->ctxt, 1, coordDims );
 
 2324      QgsDebugError( QStringLiteral( 
"GEOS Exception: Could not create coordinate sequence for point with %1 dimensions" ).arg( coordDims ) );
 
 2329      GEOSCoordSeq_setX_r( geosinit()->ctxt, coordSeq, 0, std::round( x / 
precision ) * 
precision );
 
 2330      GEOSCoordSeq_setY_r( geosinit()->ctxt, coordSeq, 0, std::round( y / 
precision ) * 
precision );
 
 2333        GEOSCoordSeq_setOrdinate_r( geosinit()->ctxt, coordSeq, 0, 2, std::round( z / 
precision ) * 
precision );
 
 2338      GEOSCoordSeq_setX_r( geosinit()->ctxt, coordSeq, 0, x );
 
 2339      GEOSCoordSeq_setY_r( geosinit()->ctxt, coordSeq, 0, y );
 
 2342        GEOSCoordSeq_setOrdinate_r( geosinit()->ctxt, coordSeq, 0, 2, z );
 
 2348      GEOSCoordSeq_setOrdinate_r( geosinit()->ctxt, coordSeq, 0, 3, m );
 
 2351    geosPoint.reset( GEOSGeom_createPoint_r( geosinit()->ctxt, coordSeq ) );
 
 2359  const QgsCurve *
c = qgsgeometry_cast<const QgsCurve *>( curve );
 
 2363  GEOSCoordSequence *coordSeq = createCoordinateSequence( 
c, 
precision );
 
 2370    geosGeom.reset( GEOSGeom_createLineString_r( geosinit()->ctxt, coordSeq ) );
 
 2378  const QgsCurvePolygon *polygon = qgsgeometry_cast<const QgsCurvePolygon *>( poly );
 
 2383  if ( !exteriorRing )
 
 2391    geos::unique_ptr exteriorRingGeos( GEOSGeom_createLinearRing_r( geosinit()->ctxt, createCoordinateSequence( exteriorRing, 
precision, 
true ) ) );
 
 2400    for ( 
int i = 0; i < nHoles; ++i )
 
 2403      holes[i] = GEOSGeom_createLinearRing_r( geosinit()->ctxt, createCoordinateSequence( interiorRing, 
precision, 
true ) );
 
 2405    geosPolygon.reset( GEOSGeom_createPolygon_r( geosinit()->ctxt, exteriorRingGeos.release(), holes, nHoles ) );
 
 2425    offset.reset( GEOSOffsetCurve_r( geosinit()->ctxt, mGeos.get(), 
distance, segments, 
static_cast< int >( joinStyle ), miterLimit ) );
 
 2428  std::unique_ptr< QgsAbstractGeometry > offsetGeom = 
fromGeos( offset.get() );
 
 2429  return offsetGeom.release();
 
 2443    GEOSBufferParams_setSingleSided_r( geosinit()->ctxt, bp.get(), 1 );
 
 2444    GEOSBufferParams_setQuadrantSegments_r( geosinit()->ctxt, bp.get(), segments );
 
 2445    GEOSBufferParams_setJoinStyle_r( geosinit()->ctxt, bp.get(), 
static_cast< int >( joinStyle ) );
 
 2446    GEOSBufferParams_setMitreLimit_r( geosinit()->ctxt, bp.get(), miterLimit );  
 
 2448    if ( side == Qgis::BufferSide::Right )
 
 2452    geos.reset( GEOSBufferWithParams_r( geosinit()->ctxt, mGeos.get(), bp.get(), 
distance ) );
 
 2468    geos.reset( GEOSMaximumInscribedCircle_r( geosinit()->ctxt, mGeos.get(), tolerance ) );
 
 2486      boundaryGeos = 
asGeos( boundary );
 
 2488    geos.reset( GEOSLargestEmptyCircle_r( geosinit()->ctxt, mGeos.get(), boundaryGeos.get(), tolerance ) );
 
 2504    geos.reset( GEOSMinimumWidth_r( geosinit()->ctxt, mGeos.get() ) );
 
 2514    return std::numeric_limits< double >::quiet_NaN();
 
 2521    if ( GEOSMinimumClearance_r( geosinit()->ctxt, mGeos.get(), &res ) != 0 )
 
 2522      return std::numeric_limits< double >::quiet_NaN();
 
 2538    geos.reset( GEOSMinimumClearanceLine_r( geosinit()->ctxt, mGeos.get() ) );
 
 2554    geos.reset( GEOSNode_r( geosinit()->ctxt, mGeos.get() ) );
 
 2562  if ( !mGeos || !other )
 
 2574    geos.reset( GEOSSharedPaths_r( geosinit()->ctxt, mGeos.get(), otherGeos.get() ) );
 
 2594  geos::unique_ptr reshapeLineGeos = createGeosLinestring( &reshapeWithLine, mPrecision );
 
 2597  int numGeoms = GEOSGetNumGeometries_r( geosinit()->ctxt, mGeos.get() );
 
 2598  if ( numGeoms == -1 )
 
 2607  bool isMultiGeom = 
false;
 
 2608  int geosTypeId = GEOSGeomTypeId_r( geosinit()->ctxt, mGeos.get() );
 
 2609  if ( geosTypeId == GEOS_MULTILINESTRING || geosTypeId == GEOS_MULTIPOLYGON )
 
 2619      reshapedGeometry = reshapeLine( mGeos.get(), reshapeLineGeos.get(), mPrecision );
 
 2623      reshapedGeometry = reshapePolygon( mGeos.get(), reshapeLineGeos.get(), mPrecision );
 
 2628    std::unique_ptr< QgsAbstractGeometry > reshapeResult = 
fromGeos( reshapedGeometry.get() );
 
 2629    return reshapeResult;
 
 2636      bool reshapeTookPlace = 
false;
 
 2641      for ( 
int i = 0; i < numGeoms; ++i )
 
 2644          currentReshapeGeometry = reshapeLine( GEOSGetGeometryN_r( geosinit()->ctxt, mGeos.get(), i ), reshapeLineGeos.get(), mPrecision );
 
 2646          currentReshapeGeometry = reshapePolygon( GEOSGetGeometryN_r( geosinit()->ctxt, mGeos.get(), i ), reshapeLineGeos.get(), mPrecision );
 
 2648        if ( currentReshapeGeometry )
 
 2650          newGeoms[i] = currentReshapeGeometry.release();
 
 2651          reshapeTookPlace = 
true;
 
 2655          newGeoms[i] = GEOSGeom_clone_r( geosinit()->ctxt, GEOSGetGeometryN_r( geosinit()->ctxt, mGeos.get(), i ) );
 
 2662        newMultiGeom.reset( GEOSGeom_createCollection_r( geosinit()->ctxt, GEOS_MULTILINESTRING, newGeoms, numGeoms ) );
 
 2666        newMultiGeom.reset( GEOSGeom_createCollection_r( geosinit()->ctxt, GEOS_MULTIPOLYGON, newGeoms, numGeoms ) );
 
 2670      if ( !newMultiGeom )
 
 2676      if ( reshapeTookPlace )
 
 2680        std::unique_ptr< QgsAbstractGeometry > reshapedMultiGeom = 
fromGeos( newMultiGeom.get() );
 
 2681        return reshapedMultiGeom;
 
 2703  if ( GEOSGeomTypeId_r( geosinit()->ctxt, mGeos.get() ) != GEOS_MULTILINESTRING )
 
 2709    geos.reset( GEOSLineMerge_r( geosinit()->ctxt, mGeos.get() ) );
 
 2733    if ( mGeosPrepared ) 
 
 2735      nearestCoord.reset( GEOSPreparedNearestPoints_r( geosinit()->ctxt, mGeosPrepared.get(), otherGeom.get() ) );
 
 2739      nearestCoord.reset( GEOSNearestPoints_r( geosinit()->ctxt, mGeos.get(), otherGeom.get() ) );
 
 2742    ( void )GEOSCoordSeq_getX_r( geosinit()->ctxt, nearestCoord.get(), 0, &nx );
 
 2743    ( void )GEOSCoordSeq_getY_r( geosinit()->ctxt, nearestCoord.get(), 0, &ny );
 
 2745  catch ( GEOSException &e )
 
 2747    logError( QStringLiteral( 
"GEOS" ), e.what() );
 
 2750      *errorMsg = e.what();
 
 2760  if ( !mGeos || other.
isEmpty() )
 
 2770  if ( !other || other->
isEmpty() )
 
 2787    if ( !nearestCoord )
 
 2790        *errorMsg = QStringLiteral( 
"GEOS returned no nearest points" );
 
 2794    ( void )GEOSCoordSeq_getX_r( geosinit()->ctxt, nearestCoord.get(), 0, &nx1 );
 
 2795    ( void )GEOSCoordSeq_getY_r( geosinit()->ctxt, nearestCoord.get(), 0, &ny1 );
 
 2796    ( void )GEOSCoordSeq_getX_r( geosinit()->ctxt, nearestCoord.get(), 1, &nx2 );
 
 2797    ( void )GEOSCoordSeq_getY_r( geosinit()->ctxt, nearestCoord.get(), 1, &ny2 );
 
 2799  catch ( GEOSException &e )
 
 2801    logError( QStringLiteral( 
"GEOS" ), e.what() );
 
 2804      *errorMsg = e.what();
 
 2831    distance = GEOSProject_r( geosinit()->ctxt, mGeos.get(), otherGeom.get() );
 
 2833  catch ( GEOSException &e )
 
 2835    logError( QStringLiteral( 
"GEOS" ), e.what() );
 
 2838      *errorMsg = e.what();
 
 2853  geos::unique_ptr point = createGeosPointXY( x, y, 
false, 0, 
false, 0, 2, 0 );
 
 2860    distance = GEOSProject_r( geosinit()->ctxt, mGeos.get(), point.get() );
 
 2862  catch ( GEOSException &e )
 
 2864    logError( QStringLiteral( 
"GEOS" ), e.what() );
 
 2867      *errorMsg = e.what();
 
 2884      lineGeosGeometries[validLines] = l.release();
 
 2891    geos::unique_ptr result( GEOSPolygonize_r( geosinit()->ctxt, lineGeosGeometries, validLines ) );
 
 2892    for ( 
int i = 0; i < validLines; ++i )
 
 2894      GEOSGeom_destroy_r( geosinit()->ctxt, lineGeosGeometries[i] );
 
 2896    delete[] lineGeosGeometries;
 
 2899  catch ( GEOSException &e )
 
 2903      *errorMsg = e.what();
 
 2905    for ( 
int i = 0; i < validLines; ++i )
 
 2907      GEOSGeom_destroy_r( geosinit()->ctxt, lineGeosGeometries[i] );
 
 2909    delete[] lineGeosGeometries;
 
 2924    extentGeosGeom = 
asGeos( extent, mPrecision );
 
 2925    if ( !extentGeosGeom )
 
 2934    geos.reset( GEOSVoronoiDiagram_r( geosinit()->ctxt, mGeos.get(), extentGeosGeom.get(), tolerance, edgesOnly ) );
 
 2936    if ( !
geos || GEOSisEmpty_r( geosinit()->ctxt, 
geos.get() ) != 0 )
 
 2956    geos.reset( GEOSDelaunayTriangulation_r( geosinit()->ctxt, mGeos.get(), tolerance, edgesOnly ) );
 
 2958    if ( !
geos || GEOSisEmpty_r( geosinit()->ctxt, 
geos.get() ) != 0 )
 
 2970static bool _linestringEndpoints( 
const GEOSGeometry *linestring, 
double &x1, 
double &y1, 
double &x2, 
double &y2 )
 
 2972  const GEOSCoordSequence *coordSeq = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, linestring );
 
 2976  unsigned int coordSeqSize;
 
 2977  if ( GEOSCoordSeq_getSize_r( geosinit()->ctxt, coordSeq, &coordSeqSize ) == 0 )
 
 2980  if ( coordSeqSize < 2 )
 
 2983  GEOSCoordSeq_getX_r( geosinit()->ctxt, coordSeq, 0, &x1 );
 
 2984  GEOSCoordSeq_getY_r( geosinit()->ctxt, coordSeq, 0, &y1 );
 
 2985  GEOSCoordSeq_getX_r( geosinit()->ctxt, coordSeq, coordSeqSize - 1, &x2 );
 
 2986  GEOSCoordSeq_getY_r( geosinit()->ctxt, coordSeq, coordSeqSize - 1, &y2 );
 
 2994  double x1, y1, x2, y2;
 
 2995  if ( !_linestringEndpoints( line1, x1, y1, x2, y2 ) )
 
 2998  double rx1, ry1, rx2, ry2;
 
 2999  if ( !_linestringEndpoints( line2, rx1, ry1, rx2, ry2 ) )
 
 3002  bool intersectionAtOrigLineEndpoint =
 
 3003    ( intersectionPoint.
x() == x1 && intersectionPoint.
y() == y1 ) !=
 
 3004    ( intersectionPoint.
x() == x2 && intersectionPoint.
y() == y2 );
 
 3005  bool intersectionAtReshapeLineEndpoint =
 
 3006    ( intersectionPoint.
x() == rx1 && intersectionPoint.
y() == ry1 ) ||
 
 3007    ( intersectionPoint.
x() == rx2 && intersectionPoint.
y() == ry2 );
 
 3010  if ( intersectionAtOrigLineEndpoint && intersectionAtReshapeLineEndpoint )
 
 3014    GEOSGeometry *geoms[2] = { g1.release(), g2.release() };
 
 3015    geos::unique_ptr multiGeom( GEOSGeom_createCollection_r( geosinit()->ctxt, GEOS_MULTILINESTRING, geoms, 2 ) );
 
 3016    geos::unique_ptr res( GEOSLineMerge_r( geosinit()->ctxt, multiGeom.get() ) );
 
 3026  if ( !line || !reshapeLineGeos )
 
 3029  bool atLeastTwoIntersections = 
false;
 
 3030  bool oneIntersection = 
false;
 
 3036    geos::unique_ptr intersectGeom( GEOSIntersection_r( geosinit()->ctxt, line, reshapeLineGeos ) );
 
 3037    if ( intersectGeom )
 
 3039      const int geomType = GEOSGeomTypeId_r( geosinit()->ctxt, intersectGeom.get() );
 
 3040      atLeastTwoIntersections = ( geomType == GEOS_MULTIPOINT && GEOSGetNumGeometries_r( geosinit()->ctxt, intersectGeom.get() ) > 1 )
 
 3041                                || ( geomType == GEOS_GEOMETRYCOLLECTION && GEOSGetNumGeometries_r( geosinit()->ctxt, intersectGeom.get() ) > 0 ) 
 
 3042                                || ( geomType == GEOS_MULTILINESTRING && GEOSGetNumGeometries_r( geosinit()->ctxt, intersectGeom.get() ) > 0 );
 
 3044      if ( GEOSGeomTypeId_r( geosinit()->ctxt, intersectGeom.get() ) == GEOS_POINT )
 
 3046        const GEOSCoordSequence *intersectionCoordSeq = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, intersectGeom.get() );
 
 3048        GEOSCoordSeq_getX_r( geosinit()->ctxt, intersectionCoordSeq, 0, &xi );
 
 3049        GEOSCoordSeq_getY_r( geosinit()->ctxt, intersectionCoordSeq, 0, &yi );
 
 3050        oneIntersection = 
true;
 
 3055  catch ( GEOSException & )
 
 3057    atLeastTwoIntersections = 
false;
 
 3061  if ( oneIntersection )
 
 3062    return _mergeLinestrings( line, reshapeLineGeos, oneIntersectionPoint );
 
 3064  if ( !atLeastTwoIntersections )
 
 3068  double x1, y1, x2, y2;
 
 3069  if ( !_linestringEndpoints( line, x1, y1, x2, y2 ) )
 
 3075  bool isRing = 
false;
 
 3076  if ( GEOSGeomTypeId_r( geosinit()->ctxt, line ) == GEOS_LINEARRING
 
 3077       || GEOSEquals_r( geosinit()->ctxt, beginLineVertex.get(), endLineVertex.get() ) == 1 )
 
 3082  if ( !nodedGeometry )
 
 3088  geos::unique_ptr mergedLines( GEOSLineMerge_r( geosinit()->ctxt, nodedGeometry.get() ) );
 
 3094  int numMergedLines = GEOSGetNumGeometries_r( geosinit()->ctxt, mergedLines.get() );
 
 3095  if ( numMergedLines < 2 ) 
 
 3097    if ( numMergedLines == 1 ) 
 
 3099      geos::unique_ptr result( GEOSGeom_clone_r( geosinit()->ctxt, reshapeLineGeos ) );
 
 3106  QVector<GEOSGeometry *> resultLineParts; 
 
 3107  QVector<GEOSGeometry *> probableParts; 
 
 3109  for ( 
int i = 0; i < numMergedLines; ++i )
 
 3111    const GEOSGeometry *currentGeom = GEOSGetGeometryN_r( geosinit()->ctxt, mergedLines.get(), i );
 
 3114    bool alreadyAdded = 
false;
 
 3116    double bufferDistance = std::pow( 10.0L, geomDigits( currentGeom ) - 11 );
 
 3117    for ( 
const GEOSGeometry *other : std::as_const( resultLineParts ) )
 
 3119      GEOSHausdorffDistance_r( geosinit()->ctxt, currentGeom, other, &
distance );
 
 3122        alreadyAdded = 
true;
 
 3129    const GEOSCoordSequence *currentCoordSeq = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, currentGeom );
 
 3130    unsigned int currentCoordSeqSize;
 
 3131    GEOSCoordSeq_getSize_r( geosinit()->ctxt, currentCoordSeq, ¤tCoordSeqSize );
 
 3132    if ( currentCoordSeqSize < 2 )
 
 3136    double xBegin, xEnd, yBegin, yEnd;
 
 3137    GEOSCoordSeq_getX_r( geosinit()->ctxt, currentCoordSeq, 0, &xBegin );
 
 3138    GEOSCoordSeq_getY_r( geosinit()->ctxt, currentCoordSeq, 0, &yBegin );
 
 3139    GEOSCoordSeq_getX_r( geosinit()->ctxt, currentCoordSeq, currentCoordSeqSize - 1, &xEnd );
 
 3140    GEOSCoordSeq_getY_r( geosinit()->ctxt, currentCoordSeq, currentCoordSeqSize - 1, &yEnd );
 
 3145    int nEndpointsOnOriginalLine = 0;
 
 3146    if ( pointContainedInLine( beginCurrentGeomVertex.get(), line ) == 1 )
 
 3147      nEndpointsOnOriginalLine += 1;
 
 3149    if ( pointContainedInLine( endCurrentGeomVertex.get(), line ) == 1 )
 
 3150      nEndpointsOnOriginalLine += 1;
 
 3153    int nEndpointsSameAsOriginalLine = 0;
 
 3154    if ( GEOSEquals_r( geosinit()->ctxt, beginCurrentGeomVertex.get(), beginLineVertex.get() ) == 1
 
 3155         || GEOSEquals_r( geosinit()->ctxt, beginCurrentGeomVertex.get(), endLineVertex.get() ) == 1 )
 
 3156      nEndpointsSameAsOriginalLine += 1;
 
 3158    if ( GEOSEquals_r( geosinit()->ctxt, endCurrentGeomVertex.get(), beginLineVertex.get() ) == 1
 
 3159         || GEOSEquals_r( geosinit()->ctxt, endCurrentGeomVertex.get(), endLineVertex.get() ) == 1 )
 
 3160      nEndpointsSameAsOriginalLine += 1;
 
 3163    bool currentGeomOverlapsOriginalGeom = 
false;
 
 3164    bool currentGeomOverlapsReshapeLine = 
false;
 
 3165    if ( lineContainedInLine( currentGeom, line ) == 1 )
 
 3166      currentGeomOverlapsOriginalGeom = 
true;
 
 3168    if ( lineContainedInLine( currentGeom, reshapeLineGeos ) == 1 )
 
 3169      currentGeomOverlapsReshapeLine = 
true;
 
 3172    if ( !isRing && nEndpointsSameAsOriginalLine == 1 && nEndpointsOnOriginalLine == 2 && currentGeomOverlapsOriginalGeom )
 
 3174      resultLineParts.push_back( GEOSGeom_clone_r( geosinit()->ctxt, currentGeom ) );
 
 3177    else if ( isRing && nEndpointsOnOriginalLine == 2 && currentGeomOverlapsOriginalGeom )
 
 3179      probableParts.push_back( GEOSGeom_clone_r( geosinit()->ctxt, currentGeom ) );
 
 3181    else if ( nEndpointsOnOriginalLine == 2 && !currentGeomOverlapsOriginalGeom )
 
 3183      resultLineParts.push_back( GEOSGeom_clone_r( geosinit()->ctxt, currentGeom ) );
 
 3185    else if ( nEndpointsSameAsOriginalLine == 2 && !currentGeomOverlapsOriginalGeom )
 
 3187      resultLineParts.push_back( GEOSGeom_clone_r( geosinit()->ctxt, currentGeom ) );
 
 3189    else if ( currentGeomOverlapsOriginalGeom && currentGeomOverlapsReshapeLine )
 
 3191      resultLineParts.push_back( GEOSGeom_clone_r( geosinit()->ctxt, currentGeom ) );
 
 3196  if ( isRing && !probableParts.isEmpty() )
 
 3200    double maxLength = -std::numeric_limits<double>::max();
 
 3201    double currentLength = 0;
 
 3202    for ( 
int i = 0; i < probableParts.size(); ++i )
 
 3204      currentGeom = probableParts.at( i );
 
 3205      GEOSLength_r( geosinit()->ctxt, currentGeom, ¤tLength );
 
 3206      if ( currentLength > maxLength )
 
 3208        maxLength = currentLength;
 
 3209        maxGeom.reset( currentGeom );
 
 3213        GEOSGeom_destroy_r( geosinit()->ctxt, currentGeom );
 
 3216    resultLineParts.push_back( maxGeom.release() );
 
 3220  if ( resultLineParts.empty() )
 
 3223  if ( resultLineParts.size() == 1 ) 
 
 3225    result.reset( resultLineParts[0] );
 
 3230    for ( 
int i = 0; i < resultLineParts.size(); ++i )
 
 3232      lineArray[i] = resultLineParts[i];
 
 3236    geos::unique_ptr multiLineGeom( GEOSGeom_createCollection_r( geosinit()->ctxt, GEOS_MULTILINESTRING, lineArray, resultLineParts.size() ) );
 
 3237    delete [] lineArray;
 
 3240    result.reset( GEOSLineMerge_r( geosinit()->ctxt, multiLineGeom.get() ) );
 
 3244  if ( GEOSGeomTypeId_r( geosinit()->ctxt, result.get() ) != GEOS_LINESTRING )
 
 3255  int nIntersections = 0;
 
 3256  int lastIntersectingRing = -2;
 
 3259  int nRings = GEOSGetNumInteriorRings_r( geosinit()->ctxt, polygon );
 
 3264  const GEOSGeometry *outerRing = GEOSGetExteriorRing_r( geosinit()->ctxt, polygon );
 
 3265  if ( GEOSIntersects_r( geosinit()->ctxt, outerRing, reshapeLineGeos ) == 1 )
 
 3268    lastIntersectingRing = -1;
 
 3269    lastIntersectingGeom = outerRing;
 
 3277    for ( 
int i = 0; i < nRings; ++i )
 
 3279      innerRings[i] = GEOSGetInteriorRingN_r( geosinit()->ctxt, polygon, i );
 
 3280      if ( GEOSIntersects_r( geosinit()->ctxt, innerRings[i], reshapeLineGeos ) == 1 )
 
 3283        lastIntersectingRing = i;
 
 3284        lastIntersectingGeom = innerRings[i];
 
 3288  catch ( GEOSException & )
 
 3293  if ( nIntersections != 1 ) 
 
 3295    delete [] innerRings;
 
 3301  if ( !reshapeResult )
 
 3303    delete [] innerRings;
 
 3309  const GEOSCoordSequence *reshapeSequence = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, reshapeResult.get() );
 
 3310  GEOSCoordSequence *newCoordSequence = GEOSCoordSeq_clone_r( geosinit()->ctxt, reshapeSequence );
 
 3312  reshapeResult.reset();
 
 3314  newRing = GEOSGeom_createLinearRing_r( geosinit()->ctxt, newCoordSequence );
 
 3317    delete [] innerRings;
 
 3322  if ( lastIntersectingRing == -1 )
 
 3323    newOuterRing = newRing;
 
 3325    newOuterRing = GEOSGeom_clone_r( geosinit()->ctxt, outerRing );
 
 3328  QVector<GEOSGeometry *> ringList;
 
 3331    GEOSGeometry *outerRingPoly = GEOSGeom_createPolygon_r( geosinit()->ctxt, GEOSGeom_clone_r( geosinit()->ctxt, newOuterRing ), 
nullptr, 0 );
 
 3332    if ( outerRingPoly )
 
 3334      ringList.reserve( nRings );
 
 3336      for ( 
int i = 0; i < nRings; ++i )
 
 3338        if ( lastIntersectingRing == i )
 
 3339          currentRing = newRing;
 
 3341          currentRing = GEOSGeom_clone_r( geosinit()->ctxt, innerRings[i] );
 
 3344        if ( GEOSContains_r( geosinit()->ctxt, outerRingPoly, currentRing ) == 1 )
 
 3345          ringList.push_back( currentRing );
 
 3347          GEOSGeom_destroy_r( geosinit()->ctxt, currentRing );
 
 3350    GEOSGeom_destroy_r( geosinit()->ctxt, outerRingPoly );
 
 3354  for ( 
int i = 0; i < ringList.size(); ++i )
 
 3355    newInnerRings[i] = ringList.at( i );
 
 3357  delete [] innerRings;
 
 3359  geos::unique_ptr reshapedPolygon( GEOSGeom_createPolygon_r( geosinit()->ctxt, newOuterRing, newInnerRings, ringList.size() ) );
 
 3360  delete[] newInnerRings;
 
 3362  return reshapedPolygon;
 
 3367  if ( !line1 || !line2 )
 
 3372  double bufferDistance = std::pow( 10.0L, geomDigits( line2 ) - 11 );
 
 3378  geos::unique_ptr intersectionGeom( GEOSIntersection_r( geosinit()->ctxt, bufferGeom.get(), line1 ) );
 
 3381  double intersectGeomLength;
 
 3384  GEOSLength_r( geosinit()->ctxt, intersectionGeom.get(), &intersectGeomLength );
 
 3385  GEOSLength_r( geosinit()->ctxt, line1, &line1Length );
 
 3387  double intersectRatio = line1Length / intersectGeomLength;
 
 3388  if ( intersectRatio > 0.9 && intersectRatio < 1.1 )
 
 3396  if ( !point || !line )
 
 3399  double bufferDistance = std::pow( 10.0L, geomDigits( line ) - 11 );
 
 3401  geos::unique_ptr lineBuffer( GEOSBuffer_r( geosinit()->ctxt, line, bufferDistance, 8 ) );
 
 3405  bool contained = 
false;
 
 3406  if ( GEOSContains_r( geosinit()->ctxt, lineBuffer.get(), point ) == 1 )
 
 3418  const GEOSGeometry *bBoxRing = GEOSGetExteriorRing_r( geosinit()->ctxt, bbox.get() );
 
 3422  const GEOSCoordSequence *bBoxCoordSeq = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, bBoxRing );
 
 3424  if ( !bBoxCoordSeq )
 
 3427  unsigned int nCoords = 0;
 
 3428  if ( !GEOSCoordSeq_getSize_r( geosinit()->ctxt, bBoxCoordSeq, &nCoords ) )
 
 3432  for ( 
unsigned int i = 0; i < nCoords - 1; ++i )
 
 3435    GEOSCoordSeq_getX_r( geosinit()->ctxt, bBoxCoordSeq, i, &t );
 
 3438    digits = std::ceil( std::log10( std::fabs( t ) ) );
 
 3439    if ( digits > maxDigits )
 
 3442    GEOSCoordSeq_getY_r( geosinit()->ctxt, bBoxCoordSeq, i, &t );
 
 3443    digits = std::ceil( std::log10( std::fabs( t ) ) );
 
 3444    if ( digits > maxDigits )
 
 3453  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.
 
MakeValidMethod
Algorithms to use when repairing invalid geometries.
 
@ Linework
Combines all rings into a set of noded lines and then extracts valid polygons from that linework.
 
@ Structure
Structured method, first makes all rings valid and then merges shells and subtracts holes from shells...
 
WkbType
The WKB type describes the number of dimensions a geometry has.
 
@ GeometryCollection
GeometryCollection.
 
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 bool isEmpty() const
Returns true if the geometry is empty.
 
Qgis::WkbType 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.
 
virtual QgsAbstractGeometry * clone() const =0
Clones the geometry by performing a deep copy.
 
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(Qgis::WkbType type)
Returns a new geometry collection matching a specified WKB type.
 
Encapsulates parameters under which a geometry operation is performed.
 
double gridSize() const
Returns the grid size which will be used to snap vertices of a geometry.
 
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.
 
bool touches(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Checks if geom touches this.
 
QgsAbstractGeometry * symDifference(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr, const QgsGeometryParameters ¶meters=QgsGeometryParameters()) const override
Calculate the symmetric difference of this and geom.
 
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.
 
std::unique_ptr< QgsAbstractGeometry > subdivide(int maxNodes, QString *errorMsg=nullptr, const QgsGeometryParameters ¶meters=QgsGeometryParameters()) const
Subdivides the geometry.
 
QgsAbstractGeometry * intersection(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr, const QgsGeometryParameters ¶meters=QgsGeometryParameters()) const override
Calculate the intersection of this and geom.
 
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
 
QgsAbstractGeometry * concaveHull(double targetPercent, bool allowHoles=false, QString *errorMsg=nullptr) const
Returns a possibly concave geometry that encloses the input geometry.
 
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 * difference(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr, const QgsGeometryParameters ¶meters=QgsGeometryParameters()) const override
Calculate the difference 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.
 
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.
 
std::unique_ptr< QgsAbstractGeometry > makeValid(Qgis::MakeValidMethod method=Qgis::MakeValidMethod::Linework, bool keepCollapsed=false, QString *errorMsg=nullptr) const
Repairs the geometry using GEOS make valid routine.
 
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.
 
bool isSimple(QString *errorMsg=nullptr) const override
Determines whether the geometry is simple (according to OGC definition).
 
QgsAbstractGeometry * combine(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr, const QgsGeometryParameters ¶meters=QgsGeometryParameters()) const override
Calculate the combination of this and geom.
 
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.
 
bool contains(double x, double y, QString *errorMsg=nullptr) const
Returns true if the geometry contains the point at (x, y).
 
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...
 
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...
 
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.
 
const double * xData() const
Returns a const pointer to the x vertex data.
 
QVector< double > xVector() const
Returns the x vertex values as a vector.
 
const double * zData() const
Returns a const pointer to the z vertex data, or nullptr if the linestring does not have z values.
 
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.
 
QVector< double > yVector() const
Returns the y vertex values as a vector.
 
double yAt(int index) const override
Returns the y-coordinate of the specified node in the line string.
 
QVector< double > zVector() const
Returns the z vertex values as a vector.
 
double closestSegment(const QgsPoint &pt, QgsPoint &segmentPt, QgsVertexId &vertexAfter, int *leftOf=nullptr, double epsilon=4 *std::numeric_limits< double >::epsilon()) const override
Searches for the closest segment of the geometry to a given point.
 
const double * mData() const
Returns a const pointer to the m vertex data, or nullptr if the linestring does not have m values.
 
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.
 
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.
 
double distance(double x, double y) const SIP_HOLDGIL
Returns the Cartesian 2D distance between this point and a specified x, y coordinate.
 
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 Qgis::GeometryType geometryType(Qgis::WkbType type) SIP_HOLDGIL
Returns the geometry type for a WKB type, e.g., both MultiPolygon and CurvePolygon would have a Polyg...
 
static bool isMultiType(Qgis::WkbType type) SIP_HOLDGIL
Returns true if the WKB type is a multi type.
 
static Qgis::WkbType flatType(Qgis::WkbType 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)
 
#define QgsDebugError(str)
 
QLineF segment(int index, QRectF rect, double radius)
 
Utility class for identifying a unique vertex within a geometry.
 
void CORE_EXPORT operator()(GEOSGeometry *geom) const
Destroys the GEOS geometry geom, using the static QGIS geos context.
 
struct GEOSGeom_t GEOSGeometry