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();
 
  316void QgsGeos::subdivideRecursive( 
const GEOSGeometry *currentPart, 
int maxNodes, 
int depth, 
QgsGeometryCollection *parts, 
const QgsRectangle &clipRect, 
double gridSize )
 const 
  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 );
 
  942bool QgsGeos::topologicalTestPointsSplit( 
const GEOSGeometry *splitLine, 
QgsPointSequence &testPoints, QString *errorMsg )
 const 
  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 )
 
  971      const GEOSGeometry *currentIntersectGeom = 
nullptr;
 
  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_getX_r( geosinit()->ctxt, lineSequence, i, &x ) != 0 )
 
  986            if ( GEOSCoordSeq_getY_r( geosinit()->ctxt, lineSequence, i, &y ) != 0 )
 
  988              testPoints.push_back( 
QgsPoint( x, y ) );
 
 1002  int type = GEOSGeomTypeId_r( geosinit()->ctxt, mGeos.get() );
 
 1004  std::unique_ptr< QgsMultiCurve > multiCurve;
 
 1005  if ( type == GEOS_MULTILINESTRING )
 
 1007    multiCurve.reset( qgsgeometry_cast<QgsMultiCurve *>( 
mGeometry->
clone() ) );
 
 1009  else if ( type == GEOS_LINESTRING )
 
 1027  std::unique_ptr< QgsAbstractGeometry > splitGeom( 
fromGeos( GEOSsplitPoint ) );
 
 1028  std::unique_ptr< QgsMultiPoint > splitPoints( qgsgeometry_cast<QgsMultiPoint *>( splitGeom->clone() ) );
 
 1031    QgsPoint *splitPoint = qgsgeometry_cast<QgsPoint *>( splitGeom->clone() );
 
 1037    splitPoints->addGeometry( splitPoint );
 
 1043  for ( 
int i = 0; i < multiCurve->numGeometries(); ++i )
 
 1045    const QgsLineString *line = qgsgeometry_cast<const QgsLineString *>( multiCurve->geometryN( i ) );
 
 1048      const QgsCurve *curve = qgsgeometry_cast<const QgsCurve *>( multiCurve->geometryN( i ) );
 
 1056    QMap< int, QVector< QPair< double, QgsPoint > > >pointMap;
 
 1057    for ( 
int p = 0; p < splitPoints->numGeometries(); ++p )
 
 1059      const QgsPoint *intersectionPoint = splitPoints->pointN( p );
 
 1064      line->
closestSegment( *intersectionPoint, segmentPoint2D, nextVertex );
 
 1067      std::unique_ptr< QgsPoint > correctSegmentPoint( 
segment.interpolatePoint( 
distance ) );
 
 1068      const QPair< double, QgsPoint > pair = qMakePair( 
distance, *correctSegmentPoint.get() );
 
 1069      if ( pointMap.contains( nextVertex.
vertex - 1 ) )
 
 1070        pointMap[ nextVertex.
vertex - 1 ].append( pair );
 
 1072        pointMap[ nextVertex.
vertex - 1 ] = QVector< QPair< double, QgsPoint > >() << pair;
 
 1077    for ( 
auto &p : pointMap )
 
 1079      std::sort( p.begin(), p.end(), []( 
const QPair< double, QgsPoint > &a, 
const QPair< double, QgsPoint > &b ) { return a.first < b.first; } );
 
 1086    for ( 
int j = 0; j < nVertices; ++j )
 
 1090      if ( pointMap.contains( j ) )
 
 1093        for ( 
int k = 0; k < pointMap[ j ].size(); ++k )
 
 1095          splitPoint = pointMap[ j ][k].second;
 
 1096          if ( splitPoint == currentPoint )
 
 1102          else if ( splitPoint == line->
pointN( j + 1 ) )
 
 1121  return asGeos( &lines, mPrecision );
 
 1126  Q_UNUSED( skipIntersectionCheck )
 
 1133  geos::unique_ptr intersectGeom( GEOSIntersection_r( geosinit()->ctxt, splitLine, mGeos.get() ) );
 
 1134  if ( !intersectGeom )
 
 1138  int linearIntersect = GEOSRelatePattern_r( geosinit()->ctxt, mGeos.get(), splitLine, 
"1********" );
 
 1139  if ( linearIntersect > 0 )
 
 1143  splitGeom = linePointDifference( intersectGeom.get() );
 
 1148  QVector<GEOSGeometry *> lineGeoms;
 
 1150  int splitType = GEOSGeomTypeId_r( geosinit()->ctxt, splitGeom.get() );
 
 1151  if ( splitType == GEOS_MULTILINESTRING )
 
 1153    int nGeoms = GEOSGetNumGeometries_r( geosinit()->ctxt, splitGeom.get() );
 
 1154    lineGeoms.reserve( nGeoms );
 
 1155    for ( 
int i = 0; i < nGeoms; ++i )
 
 1156      lineGeoms << GEOSGeom_clone_r( geosinit()->ctxt, GEOSGetGeometryN_r( geosinit()->ctxt, splitGeom.get(), i ) );
 
 1161    lineGeoms << GEOSGeom_clone_r( geosinit()->ctxt, splitGeom.get() );
 
 1164  mergeGeometriesMultiTypeSplit( lineGeoms );
 
 1166  for ( 
int i = 0; i < lineGeoms.size(); ++i )
 
 1169    GEOSGeom_destroy_r( geosinit()->ctxt, lineGeoms[i] );
 
 1185  if ( !mGeosPrepared )
 
 1189  if ( !skipIntersectionCheck && !GEOSPreparedIntersects_r( geosinit()->ctxt, mGeosPrepared.get(), splitLine ) )
 
 1194  if ( !nodedGeometry )
 
 1197  const GEOSGeometry *noded = nodedGeometry.get();
 
 1198  geos::unique_ptr polygons( GEOSPolygonize_r( geosinit()->ctxt, &noded, 1 ) );
 
 1199  if ( !polygons || numberOfGeometries( polygons.get() ) == 0 )
 
 1206  QVector<GEOSGeometry *> testedGeometries;
 
 1211  for ( 
int i = 0; i < numberOfGeometries( polygons.get() ); i++ )
 
 1213    const GEOSGeometry *polygon = GEOSGetGeometryN_r( geosinit()->ctxt, polygons.get(), i );
 
 1217      testedGeometries << GEOSGeom_clone_r( geosinit()->ctxt, polygon );
 
 1220  int nGeometriesThis = numberOfGeometries( mGeos.get() ); 
 
 1221  if ( testedGeometries.empty() || testedGeometries.size() == nGeometriesThis )
 
 1224    for ( 
int i = 0; i < testedGeometries.size(); ++i )
 
 1226      GEOSGeom_destroy_r( geosinit()->ctxt, testedGeometries[i] );
 
 1235  mergeGeometriesMultiTypeSplit( testedGeometries );
 
 1238  for ( i = 0; i < testedGeometries.size() && GEOSisValid_r( geosinit()->ctxt, testedGeometries[i] ); ++i )
 
 1241  if ( i < testedGeometries.size() )
 
 1243    for ( i = 0; i < testedGeometries.size(); ++i )
 
 1244      GEOSGeom_destroy_r( geosinit()->ctxt, testedGeometries[i] );
 
 1249  for ( i = 0; i < testedGeometries.size(); ++i )
 
 1252    GEOSGeom_destroy_r( geosinit()->ctxt, testedGeometries[i] );
 
 1258geos::unique_ptr QgsGeos::nodeGeometries( 
const GEOSGeometry *splitLine, 
const GEOSGeometry *geom )
 
 1260  if ( !splitLine || !geom )
 
 1264  if ( GEOSGeomTypeId_r( geosinit()->ctxt, geom ) == GEOS_POLYGON || GEOSGeomTypeId_r( geosinit()->ctxt, geom ) == GEOS_MULTIPOLYGON )
 
 1265    geometryBoundary.reset( GEOSBoundary_r( geosinit()->ctxt, geom ) );
 
 1267    geometryBoundary.reset( GEOSGeom_clone_r( geosinit()->ctxt, geom ) );
 
 1269  geos::unique_ptr splitLineClone( GEOSGeom_clone_r( geosinit()->ctxt, splitLine ) );
 
 1270  geos::unique_ptr unionGeometry( GEOSUnion_r( geosinit()->ctxt, splitLineClone.get(), geometryBoundary.get() ) );
 
 1272  return unionGeometry;
 
 1275int QgsGeos::mergeGeometriesMultiTypeSplit( QVector<GEOSGeometry *> &splitResult )
 const 
 1281  int type = GEOSGeomTypeId_r( geosinit()->ctxt, mGeos.get() );
 
 1282  if ( type != GEOS_GEOMETRYCOLLECTION &&
 
 1283       type != GEOS_MULTILINESTRING &&
 
 1284       type != GEOS_MULTIPOLYGON &&
 
 1285       type != GEOS_MULTIPOINT )
 
 1288  QVector<GEOSGeometry *> copyList = splitResult;
 
 1289  splitResult.clear();
 
 1292  QVector<GEOSGeometry *> unionGeom;
 
 1294  for ( 
int i = 0; i < copyList.size(); ++i )
 
 1297    bool isPart = 
false;
 
 1298    for ( 
int j = 0; j < GEOSGetNumGeometries_r( geosinit()->ctxt, mGeos.get() ); j++ )
 
 1300      if ( GEOSEquals_r( geosinit()->ctxt, copyList[i], GEOSGetGeometryN_r( geosinit()->ctxt, mGeos.get(), j ) ) )
 
 1309      unionGeom << copyList[i];
 
 1313      QVector<GEOSGeometry *> geomVector;
 
 1314      geomVector << copyList[i];
 
 1316      if ( type == GEOS_MULTILINESTRING )
 
 1317        splitResult << createGeosCollection( GEOS_MULTILINESTRING, geomVector ).release();
 
 1318      else if ( type == GEOS_MULTIPOLYGON )
 
 1319        splitResult << createGeosCollection( GEOS_MULTIPOLYGON, geomVector ).release();
 
 1321        GEOSGeom_destroy_r( geosinit()->ctxt, copyList[i] );
 
 1326  if ( !unionGeom.isEmpty() )
 
 1328    if ( type == GEOS_MULTILINESTRING )
 
 1329      splitResult << createGeosCollection( GEOS_MULTILINESTRING, unionGeom ).release();
 
 1330    else if ( type == GEOS_MULTIPOLYGON )
 
 1331      splitResult << createGeosCollection( GEOS_MULTIPOLYGON, unionGeom ).release();
 
 1341geos::unique_ptr QgsGeos::createGeosCollection( 
int typeId, 
const QVector<GEOSGeometry *> &geoms )
 
 1343  int nNullGeoms = geoms.count( 
nullptr );
 
 1344  int nNotNullGeoms = geoms.size() - nNullGeoms;
 
 1346  GEOSGeometry **geomarr = 
new GEOSGeometry*[ nNotNullGeoms ];
 
 1353  QVector<GEOSGeometry *>::const_iterator geomIt = geoms.constBegin();
 
 1354  for ( ; geomIt != geoms.constEnd(); ++geomIt )
 
 1358      if ( GEOSisEmpty_r( geosinit()->ctxt, *geomIt ) )
 
 1363        GEOSGeom_destroy_r( geosinit()->ctxt, *geomIt );
 
 1367        geomarr[i] = *geomIt;
 
 1376    geom.reset( GEOSGeom_createCollection_r( geosinit()->ctxt, typeId, geomarr, nNotNullGeoms ) );
 
 1378  catch ( GEOSException & )
 
 1394  int nCoordDims = GEOSGeom_getCoordinateDimension_r( geosinit()->ctxt, 
geos );
 
 1395  int nDims = GEOSGeom_getDimensions_r( geosinit()->ctxt, 
geos );
 
 1396  bool hasZ = ( nCoordDims == 3 );
 
 1397  bool hasM = ( ( nDims - nCoordDims ) == 1 );
 
 1399  switch ( GEOSGeomTypeId_r( geosinit()->ctxt, 
geos ) )
 
 1403      if ( GEOSisEmpty_r( geosinit()->ctxt, 
geos ) )
 
 1406      const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, 
geos );
 
 1407      unsigned int nPoints = 0;
 
 1408      GEOSCoordSeq_getSize_r( geosinit()->ctxt, cs, &nPoints );
 
 1409      return nPoints > 0 ? std::unique_ptr<QgsAbstractGeometry>( 
coordSeqPoint( cs, 0, hasZ, hasM ).clone() ) : 
nullptr;
 
 1411    case GEOS_LINESTRING:
 
 1413      return sequenceToLinestring( 
geos, hasZ, hasM );
 
 1419    case GEOS_MULTIPOINT:
 
 1421      std::unique_ptr< QgsMultiPoint > multiPoint( 
new QgsMultiPoint() );
 
 1422      int nParts = GEOSGetNumGeometries_r( geosinit()->ctxt, 
geos );
 
 1423      multiPoint->reserve( nParts );
 
 1424      for ( 
int i = 0; i < nParts; ++i )
 
 1426        const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, GEOSGetGeometryN_r( geosinit()->ctxt, 
geos, i ) );
 
 1429          unsigned int nPoints = 0;
 
 1430          GEOSCoordSeq_getSize_r( geosinit()->ctxt, cs, &nPoints );
 
 1432            multiPoint->addGeometry( 
coordSeqPoint( cs, 0, hasZ, hasM ).clone() );
 
 1435      return std::move( multiPoint );
 
 1437    case GEOS_MULTILINESTRING:
 
 1440      int nParts = GEOSGetNumGeometries_r( geosinit()->ctxt, 
geos );
 
 1441      multiLineString->reserve( nParts );
 
 1442      for ( 
int i = 0; i < nParts; ++i )
 
 1444        std::unique_ptr< QgsLineString >line( sequenceToLinestring( GEOSGetGeometryN_r( geosinit()->ctxt, 
geos, i ), hasZ, hasM ) );
 
 1447          multiLineString->addGeometry( line.release() );
 
 1450      return std::move( multiLineString );
 
 1452    case GEOS_MULTIPOLYGON:
 
 1454      std::unique_ptr< QgsMultiPolygon > multiPolygon( 
new QgsMultiPolygon() );
 
 1456      int nParts = GEOSGetNumGeometries_r( geosinit()->ctxt, 
geos );
 
 1457      multiPolygon->reserve( nParts );
 
 1458      for ( 
int i = 0; i < nParts; ++i )
 
 1460        std::unique_ptr< QgsPolygon > poly = 
fromGeosPolygon( GEOSGetGeometryN_r( geosinit()->ctxt, 
geos, i ) );
 
 1463          multiPolygon->addGeometry( poly.release() );
 
 1466      return std::move( multiPolygon );
 
 1468    case GEOS_GEOMETRYCOLLECTION:
 
 1471      int nParts = GEOSGetNumGeometries_r( geosinit()->ctxt, 
geos );
 
 1472      geomCollection->reserve( nParts );
 
 1473      for ( 
int i = 0; i < nParts; ++i )
 
 1475        std::unique_ptr< QgsAbstractGeometry > geom( 
fromGeos( GEOSGetGeometryN_r( geosinit()->ctxt, 
geos, i ) ) );
 
 1478          geomCollection->addGeometry( geom.release() );
 
 1481      return std::move( geomCollection );
 
 1489  if ( GEOSGeomTypeId_r( geosinit()->ctxt, 
geos ) != GEOS_POLYGON )
 
 1494  int nCoordDims = GEOSGeom_getCoordinateDimension_r( geosinit()->ctxt, 
geos );
 
 1495  int nDims = GEOSGeom_getDimensions_r( geosinit()->ctxt, 
geos );
 
 1496  bool hasZ = ( nCoordDims == 3 );
 
 1497  bool hasM = ( ( nDims - nCoordDims ) == 1 );
 
 1499  std::unique_ptr< QgsPolygon > polygon( 
new QgsPolygon() );
 
 1501  const GEOSGeometry *ring = GEOSGetExteriorRing_r( geosinit()->ctxt, 
geos );
 
 1504    polygon->setExteriorRing( sequenceToLinestring( ring, hasZ, hasM ).release() );
 
 1507  QVector<QgsCurve *> interiorRings;
 
 1508  const int ringCount = GEOSGetNumInteriorRings_r( geosinit()->ctxt, 
geos );
 
 1509  interiorRings.reserve( ringCount );
 
 1510  for ( 
int i = 0; i < ringCount; ++i )
 
 1512    ring = GEOSGetInteriorRingN_r( geosinit()->ctxt, 
geos, i );
 
 1515      interiorRings.push_back( sequenceToLinestring( ring, hasZ, hasM ).release() );
 
 1518  polygon->setInteriorRings( interiorRings );
 
 1523std::unique_ptr<QgsLineString> QgsGeos::sequenceToLinestring( 
const GEOSGeometry *
geos, 
bool hasZ, 
bool hasM )
 
 1525  const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, 
geos );
 
 1527  unsigned int nPoints;
 
 1528  GEOSCoordSeq_getSize_r( geosinit()->ctxt, cs, &nPoints );
 
 1530  QVector< double > xOut( nPoints );
 
 1531  QVector< double > yOut( nPoints );
 
 1532  QVector< double > zOut;
 
 1534    zOut.resize( nPoints );
 
 1535  QVector< double > mOut;
 
 1537    mOut.resize( nPoints );
 
 1539  double *x = xOut.data();
 
 1540  double *y = yOut.data();
 
 1541  double *z = zOut.data();
 
 1542  double *m = mOut.data();
 
 1544#if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=10 ) 
 1545  GEOSCoordSeq_copyToArrays_r( geosinit()->ctxt, cs, x, y, hasZ ? z : 
nullptr, hasM ? m : 
nullptr );
 
 1547  for ( 
unsigned int i = 0; i < nPoints; ++i )
 
 1550      GEOSCoordSeq_getXYZ_r( geosinit()->ctxt, cs, i, x++, y++, z++ );
 
 1552      GEOSCoordSeq_getXY_r( geosinit()->ctxt, cs, i, x++, y++ );
 
 1555      GEOSCoordSeq_getOrdinate_r( geosinit()->ctxt, cs, i, 3, m++ );
 
 1559  std::unique_ptr< QgsLineString > line( 
new QgsLineString( xOut, yOut, zOut, mOut ) );
 
 1563int QgsGeos::numberOfGeometries( GEOSGeometry *g )
 
 1568  int geometryType = GEOSGeomTypeId_r( geosinit()->ctxt, g );
 
 1569  if ( geometryType == GEOS_POINT || geometryType == GEOS_LINESTRING || geometryType == GEOS_LINEARRING
 
 1570       || geometryType == GEOS_POLYGON )
 
 1574  return GEOSGetNumGeometries_r( geosinit()->ctxt, g );
 
 1588    GEOSCoordSeq_getXYZ_r( geosinit()->ctxt, cs, i, &x, &y, &z );
 
 1590    GEOSCoordSeq_getXY_r( geosinit()->ctxt, cs, i, &x, &y );
 
 1593    GEOSCoordSeq_getOrdinate_r( geosinit()->ctxt, cs, i, 3, &m );
 
 1629    int geosType = GEOS_GEOMETRYCOLLECTION;
 
 1636          geosType = GEOS_MULTIPOINT;
 
 1640          geosType = GEOS_MULTILINESTRING;
 
 1644          geosType = GEOS_MULTIPOLYGON;
 
 1659    QVector< GEOSGeometry * > geomVector( 
c->numGeometries() );
 
 1660    for ( 
int i = 0; i < 
c->numGeometries(); ++i )
 
 1664    return createGeosCollection( geosType, geomVector );
 
 1671        return createGeosPoint( 
static_cast<const QgsPoint *
>( geom ), coordDims, 
precision );
 
 1689  if ( !mGeos || !geom )
 
 1700  const double gridSize = parameters.
gridSize();
 
 1707      case OverlayIntersection:
 
 1710          opGeom.reset( GEOSIntersectionPrec_r( geosinit()->ctxt, mGeos.get(), geosGeom.get(), gridSize ) );
 
 1714          opGeom.reset( GEOSIntersection_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) );
 
 1718      case OverlayDifference:
 
 1721          opGeom.reset( GEOSDifferencePrec_r( geosinit()->ctxt, mGeos.get(), geosGeom.get(), gridSize ) );
 
 1725          opGeom.reset( GEOSDifference_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) );
 
 1734          unionGeometry.reset( GEOSUnionPrec_r( geosinit()->ctxt, mGeos.get(), geosGeom.get(), gridSize ) );
 
 1738          unionGeometry.reset( GEOSUnion_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) );
 
 1741        if ( unionGeometry && GEOSGeomTypeId_r( geosinit()->ctxt, unionGeometry.get() ) == GEOS_MULTILINESTRING )
 
 1743          geos::unique_ptr mergedLines( GEOSLineMerge_r( geosinit()->ctxt, unionGeometry.get() ) );
 
 1746            unionGeometry = std::move( mergedLines );
 
 1750        opGeom = std::move( unionGeometry );
 
 1754      case OverlaySymDifference:
 
 1757          opGeom.reset( GEOSSymDifferencePrec_r( geosinit()->ctxt, mGeos.get(), geosGeom.get(), gridSize ) );
 
 1761          opGeom.reset( GEOSSymDifference_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) );
 
 1767  catch ( GEOSException &e )
 
 1769    logError( QStringLiteral( 
"GEOS" ), e.what() );
 
 1772      *errorMsg = e.what();
 
 1778bool QgsGeos::relation( 
const QgsAbstractGeometry *geom, Relation r, QString *errorMsg )
 const 
 1780  if ( !mGeos || !geom )
 
 1791  bool result = 
false;
 
 1794    if ( mGeosPrepared ) 
 
 1798        case RelationIntersects:
 
 1799          result = ( GEOSPreparedIntersects_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
 
 1801        case RelationTouches:
 
 1802          result = ( GEOSPreparedTouches_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
 
 1804        case RelationCrosses:
 
 1805          result = ( GEOSPreparedCrosses_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
 
 1807        case RelationWithin:
 
 1808          result = ( GEOSPreparedWithin_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
 
 1810        case RelationContains:
 
 1811          result = ( GEOSPreparedContains_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
 
 1813        case RelationDisjoint:
 
 1814          result = ( GEOSPreparedDisjoint_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
 
 1816        case RelationOverlaps:
 
 1817          result = ( GEOSPreparedOverlaps_r( geosinit()->ctxt, mGeosPrepared.get(), geosGeom.get() ) == 1 );
 
 1825      case RelationIntersects:
 
 1826        result = ( GEOSIntersects_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
 
 1828      case RelationTouches:
 
 1829        result = ( GEOSTouches_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
 
 1831      case RelationCrosses:
 
 1832        result = ( GEOSCrosses_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
 
 1834      case RelationWithin:
 
 1835        result = ( GEOSWithin_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
 
 1837      case RelationContains:
 
 1838        result = ( GEOSContains_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
 
 1840      case RelationDisjoint:
 
 1841        result = ( GEOSDisjoint_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
 
 1843      case RelationOverlaps:
 
 1844        result = ( GEOSOverlaps_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() ) == 1 );
 
 1848  catch ( GEOSException &e )
 
 1850    logError( QStringLiteral( 
"GEOS" ), e.what() );
 
 1853      *errorMsg = e.what();
 
 1871    geos.reset( GEOSBuffer_r( geosinit()->ctxt, mGeos.get(), 
distance, segments ) );
 
 1887    geos.reset( GEOSBufferWithStyle_r( geosinit()->ctxt, mGeos.get(), 
distance, segments, 
static_cast< int >( endCapStyle ), 
static_cast< int >( joinStyle ), miterLimit ) );
 
 1902    geos.reset( GEOSTopologyPreserveSimplify_r( geosinit()->ctxt, mGeos.get(), tolerance ) );
 
 1917    geos.reset( GEOSInterpolate_r( geosinit()->ctxt, mGeos.get(), 
distance ) );
 
 1936    geos.reset( GEOSGetCentroid_r( geosinit()->ctxt,  mGeos.get() ) );
 
 1941    GEOSGeomGetX_r( geosinit()->ctxt, 
geos.get(), &x );
 
 1942    GEOSGeomGetY_r( geosinit()->ctxt, 
geos.get(), &y );
 
 1958    geos.reset( GEOSEnvelope_r( geosinit()->ctxt, mGeos.get() ) );
 
 1977    geos.reset( GEOSPointOnSurface_r( geosinit()->ctxt, mGeos.get() ) );
 
 1979    if ( !
geos || GEOSisEmpty_r( geosinit()->ctxt, 
geos.get() ) != 0 )
 
 1984    GEOSGeomGetX_r( geosinit()->ctxt, 
geos.get(), &x );
 
 1985    GEOSGeomGetY_r( geosinit()->ctxt, 
geos.get(), &y );
 
 2001    geos::unique_ptr cHull( GEOSConvexHull_r( geosinit()->ctxt, mGeos.get() ) );
 
 2002    std::unique_ptr< QgsAbstractGeometry > cHullGeom = 
fromGeos( cHull.get() );
 
 2003    return cHullGeom.release();
 
 2010#if GEOS_VERSION_MAJOR==3 && GEOS_VERSION_MINOR<11 
 2012  ( void )targetPercent;
 
 2014  throw QgsNotSupportedException( QObject::tr( 
"Calculating concaveHull requires a QGIS build based on GEOS 3.11 or later" ) );
 
 2025    return concaveHullGeom.release();
 
 2040    GEOSGeometry *g1 = 
nullptr;
 
 2042    char res = GEOSisValidDetail_r( geosinit()->ctxt, mGeos.get(), allowSelfTouchingHoles ? GEOSVALID_ALLOW_SELFTOUCHING_RING_FORMING_HOLE : 0, &r, &g1 );
 
 2043    const bool invalid = res != 1;
 
 2048      error = QString( r );
 
 2049      GEOSFree_r( geosinit()->ctxt, r );
 
 2052    if ( invalid && errorMsg )
 
 2056      if ( translatedErrors.empty() )
 
 2059        translatedErrors.insert( QStringLiteral( 
"topology validation error" ), QObject::tr( 
"Topology validation error", 
"GEOS Error" ) );
 
 2060        translatedErrors.insert( QStringLiteral( 
"repeated point" ), QObject::tr( 
"Repeated point", 
"GEOS Error" ) );
 
 2061        translatedErrors.insert( QStringLiteral( 
"hole lies outside shell" ), QObject::tr( 
"Hole lies outside shell", 
"GEOS Error" ) );
 
 2062        translatedErrors.insert( QStringLiteral( 
"holes are nested" ), QObject::tr( 
"Holes are nested", 
"GEOS Error" ) );
 
 2063        translatedErrors.insert( QStringLiteral( 
"interior is disconnected" ), QObject::tr( 
"Interior is disconnected", 
"GEOS Error" ) );
 
 2064        translatedErrors.insert( QStringLiteral( 
"self-intersection" ), QObject::tr( 
"Self-intersection", 
"GEOS Error" ) );
 
 2065        translatedErrors.insert( QStringLiteral( 
"ring self-intersection" ), QObject::tr( 
"Ring self-intersection", 
"GEOS Error" ) );
 
 2066        translatedErrors.insert( QStringLiteral( 
"nested shells" ), QObject::tr( 
"Nested shells", 
"GEOS Error" ) );
 
 2067        translatedErrors.insert( QStringLiteral( 
"duplicate rings" ), QObject::tr( 
"Duplicate rings", 
"GEOS Error" ) );
 
 2068        translatedErrors.insert( QStringLiteral( 
"too few points in geometry component" ), QObject::tr( 
"Too few points in geometry component", 
"GEOS Error" ) );
 
 2069        translatedErrors.insert( QStringLiteral( 
"invalid coordinate" ), QObject::tr( 
"Invalid coordinate", 
"GEOS Error" ) );
 
 2070        translatedErrors.insert( QStringLiteral( 
"ring is not closed" ), QObject::tr( 
"Ring is not closed", 
"GEOS Error" ) );
 
 2073      *errorMsg = translatedErrors.value( error.toLower(), error );
 
 2075      if ( g1 && errorLoc )
 
 2081        GEOSGeom_destroy_r( geosinit()->ctxt, g1 );
 
 2091  if ( !mGeos || !geom )
 
 2103    bool equal = GEOSEquals_r( geosinit()->ctxt, mGeos.get(), geosGeom.get() );
 
 2118    return GEOSisEmpty_r( geosinit()->ctxt, mGeos.get() );
 
 2132    return GEOSisSimple_r( geosinit()->ctxt, mGeos.get() );
 
 2137GEOSCoordSequence *QgsGeos::createCoordinateSequence( 
const QgsCurve *curve, 
double precision, 
bool forceClose )
 
 2139  GEOSContextHandle_t ctxt = geosinit()->ctxt;
 
 2141  std::unique_ptr< QgsLineString > segmentized;
 
 2142  const QgsLineString *line = qgsgeometry_cast<const QgsLineString *>( curve );
 
 2147    line = segmentized.get();
 
 2154  GEOSCoordSequence *coordSeq = 
nullptr;
 
 2156  const int numPoints = line->
numPoints();
 
 2158  const bool hasZ = line->
is3D();
 
 2160#if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=10 ) 
 2163    if ( !forceClose || ( line->
pointN( 0 ) == line->
pointN( numPoints - 1 ) ) )
 
 2168        coordSeq = GEOSCoordSeq_copyFromArrays_r( ctxt, line->
xData(), line->
yData(), line->
zData(), 
nullptr, numPoints );
 
 2171          QgsDebugMsg( QStringLiteral( 
"GEOS Exception: Could not create coordinate sequence for %1 points" ).arg( numPoints ) );
 
 2179      QVector< double > x = line->
xVector();
 
 2180      if ( numPoints > 0 )
 
 2181        x.append( x.at( 0 ) );
 
 2182      QVector< double > y = line->
yVector();
 
 2183      if ( numPoints > 0 )
 
 2184        y.append( y.at( 0 ) );
 
 2185      QVector< double > z = line->
zVector();
 
 2186      if ( hasZ && numPoints > 0 )
 
 2187        z.append( z.at( 0 ) );
 
 2190        coordSeq = GEOSCoordSeq_copyFromArrays_r( ctxt, x.constData(), y.constData(), !hasZ ? 
nullptr : z.constData(), 
nullptr, numPoints + 1 );
 
 2193          QgsDebugMsg( QStringLiteral( 
"GEOS Exception: Could not create closed coordinate sequence for %1 points" ).arg( numPoints + 1 ) );
 
 2204  const bool hasM = 
false; 
 
 2215  int numOutPoints = numPoints;
 
 2216  if ( forceClose && ( line->
pointN( 0 ) != line->
pointN( numPoints - 1 ) ) )
 
 2223    coordSeq = GEOSCoordSeq_create_r( ctxt, numOutPoints, coordDims );
 
 2226      QgsDebugMsg( QStringLiteral( 
"GEOS Exception: Could not create coordinate sequence for %1 points in %2 dimensions" ).arg( numPoints ).arg( coordDims ) );
 
 2230    const double *xData = line->
xData();
 
 2231    const double *yData = line->
yData();
 
 2232    const double *zData = hasZ ? line->
zData() : 
nullptr;
 
 2233    const double *mData = hasM ? line->
mData() : 
nullptr;
 
 2237      for ( 
int i = 0; i < numOutPoints; ++i )
 
 2239        if ( i >= numPoints )
 
 2242          xData = line->
xData();
 
 2243          yData = line->
yData();
 
 2244          zData = hasZ ? line->
zData() : 
nullptr;
 
 2245          mData = hasM ? line->
mData() : 
nullptr;
 
 2257          GEOSCoordSeq_setOrdinate_r( ctxt, coordSeq, i, 3, *mData++ );
 
 2263      for ( 
int i = 0; i < numOutPoints; ++i )
 
 2265        if ( i >= numPoints )
 
 2268          xData = line->
xData();
 
 2269          yData = line->
yData();
 
 2270          zData = hasZ ? line->
zData() : 
nullptr;
 
 2271          mData = hasM ? line->
mData() : 
nullptr;
 
 2275          GEOSCoordSeq_setXYZ_r( ctxt, coordSeq, i, *xData++, *yData++, *zData++ );
 
 2279          GEOSCoordSeq_setXY_r( ctxt, coordSeq, i, *xData++, *yData++ );
 
 2283          GEOSCoordSeq_setOrdinate_r( ctxt, coordSeq, i, 3, *mData++ );
 
 2295  const QgsPoint *pt = qgsgeometry_cast<const QgsPoint *>( point );
 
 2302geos::unique_ptr QgsGeos::createGeosPointXY( 
double x, 
double y, 
bool hasZ, 
double z, 
bool hasM, 
double m, 
int coordDims, 
double precision )
 
 2310    if ( coordDims == 2 )
 
 2316        geosPoint.reset( GEOSGeom_createPointFromXY_r( geosinit()->ctxt, x, y ) );
 
 2320    GEOSCoordSequence *coordSeq = GEOSCoordSeq_create_r( geosinit()->ctxt, 1, coordDims );
 
 2323      QgsDebugMsg( QStringLiteral( 
"GEOS Exception: Could not create coordinate sequence for point with %1 dimensions" ).arg( coordDims ) );
 
 2328      GEOSCoordSeq_setX_r( geosinit()->ctxt, coordSeq, 0, std::round( x / 
precision ) * 
precision );
 
 2329      GEOSCoordSeq_setY_r( geosinit()->ctxt, coordSeq, 0, std::round( y / 
precision ) * 
precision );
 
 2332        GEOSCoordSeq_setOrdinate_r( geosinit()->ctxt, coordSeq, 0, 2, std::round( z / 
precision ) * 
precision );
 
 2337      GEOSCoordSeq_setX_r( geosinit()->ctxt, coordSeq, 0, x );
 
 2338      GEOSCoordSeq_setY_r( geosinit()->ctxt, coordSeq, 0, y );
 
 2341        GEOSCoordSeq_setOrdinate_r( geosinit()->ctxt, coordSeq, 0, 2, z );
 
 2347      GEOSCoordSeq_setOrdinate_r( geosinit()->ctxt, coordSeq, 0, 3, m );
 
 2350    geosPoint.reset( GEOSGeom_createPoint_r( geosinit()->ctxt, coordSeq ) );
 
 2358  const QgsCurve *
c = qgsgeometry_cast<const QgsCurve *>( curve );
 
 2362  GEOSCoordSequence *coordSeq = createCoordinateSequence( 
c, 
precision );
 
 2369    geosGeom.reset( GEOSGeom_createLineString_r( geosinit()->ctxt, coordSeq ) );
 
 2377  const QgsCurvePolygon *polygon = qgsgeometry_cast<const QgsCurvePolygon *>( poly );
 
 2382  if ( !exteriorRing )
 
 2390    geos::unique_ptr exteriorRingGeos( GEOSGeom_createLinearRing_r( geosinit()->ctxt, createCoordinateSequence( exteriorRing, 
precision, 
true ) ) );
 
 2393    GEOSGeometry **holes = 
nullptr;
 
 2396      holes = 
new GEOSGeometry*[ nHoles ];
 
 2399    for ( 
int i = 0; i < nHoles; ++i )
 
 2402      holes[i] = GEOSGeom_createLinearRing_r( geosinit()->ctxt, createCoordinateSequence( interiorRing, 
precision, 
true ) );
 
 2404    geosPolygon.reset( GEOSGeom_createPolygon_r( geosinit()->ctxt, exteriorRingGeos.release(), holes, nHoles ) );
 
 2420    offset.reset( GEOSOffsetCurve_r( geosinit()->ctxt, mGeos.get(), 
distance, segments, 
static_cast< int >( joinStyle ), miterLimit ) );
 
 2423  std::unique_ptr< QgsAbstractGeometry > offsetGeom = 
fromGeos( offset.get() );
 
 2424  return offsetGeom.release();
 
 2438    GEOSBufferParams_setSingleSided_r( geosinit()->ctxt, bp.get(), 1 );
 
 2439    GEOSBufferParams_setQuadrantSegments_r( geosinit()->ctxt, bp.get(), segments );
 
 2440    GEOSBufferParams_setJoinStyle_r( geosinit()->ctxt, bp.get(), 
static_cast< int >( joinStyle ) );
 
 2441    GEOSBufferParams_setMitreLimit_r( geosinit()->ctxt, bp.get(), miterLimit );  
 
 2443    if ( side == Qgis::BufferSide::Right )
 
 2447    geos.reset( GEOSBufferWithParams_r( geosinit()->ctxt, mGeos.get(), bp.get(), 
distance ) );
 
 2463    geos.reset( GEOSMaximumInscribedCircle_r( geosinit()->ctxt, mGeos.get(), tolerance ) );
 
 2481      boundaryGeos = 
asGeos( boundary );
 
 2483    geos.reset( GEOSLargestEmptyCircle_r( geosinit()->ctxt, mGeos.get(), boundaryGeos.get(), tolerance ) );
 
 2499    geos.reset( GEOSMinimumWidth_r( geosinit()->ctxt, mGeos.get() ) );
 
 2509    return std::numeric_limits< double >::quiet_NaN();
 
 2516    if ( GEOSMinimumClearance_r( geosinit()->ctxt, mGeos.get(), &res ) != 0 )
 
 2517      return std::numeric_limits< double >::quiet_NaN();
 
 2533    geos.reset( GEOSMinimumClearanceLine_r( geosinit()->ctxt, mGeos.get() ) );
 
 2549    geos.reset( GEOSNode_r( geosinit()->ctxt, mGeos.get() ) );
 
 2557  if ( !mGeos || !other )
 
 2569    geos.reset( GEOSSharedPaths_r( geosinit()->ctxt, mGeos.get(), otherGeos.get() ) );
 
 2589  geos::unique_ptr reshapeLineGeos = createGeosLinestring( &reshapeWithLine, mPrecision );
 
 2592  int numGeoms = GEOSGetNumGeometries_r( geosinit()->ctxt, mGeos.get() );
 
 2593  if ( numGeoms == -1 )
 
 2602  bool isMultiGeom = 
false;
 
 2603  int geosTypeId = GEOSGeomTypeId_r( geosinit()->ctxt, mGeos.get() );
 
 2604  if ( geosTypeId == GEOS_MULTILINESTRING || geosTypeId == GEOS_MULTIPOLYGON )
 
 2614      reshapedGeometry = reshapeLine( mGeos.get(), reshapeLineGeos.get(), mPrecision );
 
 2618      reshapedGeometry = reshapePolygon( mGeos.get(), reshapeLineGeos.get(), mPrecision );
 
 2623    std::unique_ptr< QgsAbstractGeometry > reshapeResult = 
fromGeos( reshapedGeometry.get() );
 
 2624    return reshapeResult;
 
 2631      bool reshapeTookPlace = 
false;
 
 2634      GEOSGeometry **newGeoms = 
new GEOSGeometry*[numGeoms];
 
 2636      for ( 
int i = 0; i < numGeoms; ++i )
 
 2639          currentReshapeGeometry = reshapeLine( GEOSGetGeometryN_r( geosinit()->ctxt, mGeos.get(), i ), reshapeLineGeos.get(), mPrecision );
 
 2641          currentReshapeGeometry = reshapePolygon( GEOSGetGeometryN_r( geosinit()->ctxt, mGeos.get(), i ), reshapeLineGeos.get(), mPrecision );
 
 2643        if ( currentReshapeGeometry )
 
 2645          newGeoms[i] = currentReshapeGeometry.release();
 
 2646          reshapeTookPlace = 
true;
 
 2650          newGeoms[i] = GEOSGeom_clone_r( geosinit()->ctxt, GEOSGetGeometryN_r( geosinit()->ctxt, mGeos.get(), i ) );
 
 2657        newMultiGeom.reset( GEOSGeom_createCollection_r( geosinit()->ctxt, GEOS_MULTILINESTRING, newGeoms, numGeoms ) );
 
 2661        newMultiGeom.reset( GEOSGeom_createCollection_r( geosinit()->ctxt, GEOS_MULTIPOLYGON, newGeoms, numGeoms ) );
 
 2665      if ( !newMultiGeom )
 
 2671      if ( reshapeTookPlace )
 
 2675        std::unique_ptr< QgsAbstractGeometry > reshapedMultiGeom = 
fromGeos( newMultiGeom.get() );
 
 2676        return reshapedMultiGeom;
 
 2698  if ( GEOSGeomTypeId_r( geosinit()->ctxt, mGeos.get() ) != GEOS_MULTILINESTRING )
 
 2704    geos.reset( GEOSLineMerge_r( geosinit()->ctxt, mGeos.get() ) );
 
 2728    if ( mGeosPrepared ) 
 
 2730      nearestCoord.reset( GEOSPreparedNearestPoints_r( geosinit()->ctxt, mGeosPrepared.get(), otherGeom.get() ) );
 
 2734      nearestCoord.reset( GEOSNearestPoints_r( geosinit()->ctxt, mGeos.get(), otherGeom.get() ) );
 
 2737    ( void )GEOSCoordSeq_getX_r( geosinit()->ctxt, nearestCoord.get(), 0, &nx );
 
 2738    ( void )GEOSCoordSeq_getY_r( geosinit()->ctxt, nearestCoord.get(), 0, &ny );
 
 2740  catch ( GEOSException &e )
 
 2742    logError( QStringLiteral( 
"GEOS" ), e.what() );
 
 2745      *errorMsg = e.what();
 
 2755  if ( !mGeos || other.
isEmpty() )
 
 2765  if ( !other || other->
isEmpty() )
 
 2782    if ( !nearestCoord )
 
 2785        *errorMsg = QStringLiteral( 
"GEOS returned no nearest points" );
 
 2789    ( void )GEOSCoordSeq_getX_r( geosinit()->ctxt, nearestCoord.get(), 0, &nx1 );
 
 2790    ( void )GEOSCoordSeq_getY_r( geosinit()->ctxt, nearestCoord.get(), 0, &ny1 );
 
 2791    ( void )GEOSCoordSeq_getX_r( geosinit()->ctxt, nearestCoord.get(), 1, &nx2 );
 
 2792    ( void )GEOSCoordSeq_getY_r( geosinit()->ctxt, nearestCoord.get(), 1, &ny2 );
 
 2794  catch ( GEOSException &e )
 
 2796    logError( QStringLiteral( 
"GEOS" ), e.what() );
 
 2799      *errorMsg = e.what();
 
 2826    distance = GEOSProject_r( geosinit()->ctxt, mGeos.get(), otherGeom.get() );
 
 2828  catch ( GEOSException &e )
 
 2830    logError( QStringLiteral( 
"GEOS" ), e.what() );
 
 2833      *errorMsg = e.what();
 
 2848  geos::unique_ptr point = createGeosPointXY( x, y, 
false, 0, 
false, 0, 2, 0 );
 
 2855    distance = GEOSProject_r( geosinit()->ctxt, mGeos.get(), point.get() );
 
 2857  catch ( GEOSException &e )
 
 2859    logError( QStringLiteral( 
"GEOS" ), e.what() );
 
 2862      *errorMsg = e.what();
 
 2872  GEOSGeometry **
const lineGeosGeometries = 
new GEOSGeometry*[ geometries.size()];
 
 2879      lineGeosGeometries[validLines] = l.release();
 
 2886    geos::unique_ptr result( GEOSPolygonize_r( geosinit()->ctxt, lineGeosGeometries, validLines ) );
 
 2887    for ( 
int i = 0; i < validLines; ++i )
 
 2889      GEOSGeom_destroy_r( geosinit()->ctxt, lineGeosGeometries[i] );
 
 2891    delete[] lineGeosGeometries;
 
 2894  catch ( GEOSException &e )
 
 2898      *errorMsg = e.what();
 
 2900    for ( 
int i = 0; i < validLines; ++i )
 
 2902      GEOSGeom_destroy_r( geosinit()->ctxt, lineGeosGeometries[i] );
 
 2904    delete[] lineGeosGeometries;
 
 2919    extentGeosGeom = 
asGeos( extent, mPrecision );
 
 2920    if ( !extentGeosGeom )
 
 2929    geos.reset( GEOSVoronoiDiagram_r( geosinit()->ctxt, mGeos.get(), extentGeosGeom.get(), tolerance, edgesOnly ) );
 
 2931    if ( !
geos || GEOSisEmpty_r( geosinit()->ctxt, 
geos.get() ) != 0 )
 
 2951    geos.reset( GEOSDelaunayTriangulation_r( geosinit()->ctxt, mGeos.get(), tolerance, edgesOnly ) );
 
 2953    if ( !
geos || GEOSisEmpty_r( geosinit()->ctxt, 
geos.get() ) != 0 )
 
 2965static bool _linestringEndpoints( 
const GEOSGeometry *linestring, 
double &x1, 
double &y1, 
double &x2, 
double &y2 )
 
 2967  const GEOSCoordSequence *coordSeq = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, linestring );
 
 2971  unsigned int coordSeqSize;
 
 2972  if ( GEOSCoordSeq_getSize_r( geosinit()->ctxt, coordSeq, &coordSeqSize ) == 0 )
 
 2975  if ( coordSeqSize < 2 )
 
 2978  GEOSCoordSeq_getX_r( geosinit()->ctxt, coordSeq, 0, &x1 );
 
 2979  GEOSCoordSeq_getY_r( geosinit()->ctxt, coordSeq, 0, &y1 );
 
 2980  GEOSCoordSeq_getX_r( geosinit()->ctxt, coordSeq, coordSeqSize - 1, &x2 );
 
 2981  GEOSCoordSeq_getY_r( geosinit()->ctxt, coordSeq, coordSeqSize - 1, &y2 );
 
 2987static geos::unique_ptr _mergeLinestrings( 
const GEOSGeometry *line1, 
const GEOSGeometry *line2, 
const QgsPointXY &intersectionPoint )
 
 2989  double x1, y1, x2, y2;
 
 2990  if ( !_linestringEndpoints( line1, x1, y1, x2, y2 ) )
 
 2993  double rx1, ry1, rx2, ry2;
 
 2994  if ( !_linestringEndpoints( line2, rx1, ry1, rx2, ry2 ) )
 
 2997  bool intersectionAtOrigLineEndpoint =
 
 2998    ( intersectionPoint.
x() == x1 && intersectionPoint.
y() == y1 ) !=
 
 2999    ( intersectionPoint.
x() == x2 && intersectionPoint.
y() == y2 );
 
 3000  bool intersectionAtReshapeLineEndpoint =
 
 3001    ( intersectionPoint.
x() == rx1 && intersectionPoint.
y() == ry1 ) ||
 
 3002    ( intersectionPoint.
x() == rx2 && intersectionPoint.
y() == ry2 );
 
 3005  if ( intersectionAtOrigLineEndpoint && intersectionAtReshapeLineEndpoint )
 
 3009    GEOSGeometry *geoms[2] = { g1.release(), g2.release() };
 
 3010    geos::unique_ptr multiGeom( GEOSGeom_createCollection_r( geosinit()->ctxt, GEOS_MULTILINESTRING, geoms, 2 ) );
 
 3011    geos::unique_ptr res( GEOSLineMerge_r( geosinit()->ctxt, multiGeom.get() ) );
 
 3021  if ( !line || !reshapeLineGeos )
 
 3024  bool atLeastTwoIntersections = 
false;
 
 3025  bool oneIntersection = 
false;
 
 3031    geos::unique_ptr intersectGeom( GEOSIntersection_r( geosinit()->ctxt, line, reshapeLineGeos ) );
 
 3032    if ( intersectGeom )
 
 3034      const int geomType = GEOSGeomTypeId_r( geosinit()->ctxt, intersectGeom.get() );
 
 3035      atLeastTwoIntersections = ( geomType == GEOS_MULTIPOINT && GEOSGetNumGeometries_r( geosinit()->ctxt, intersectGeom.get() ) > 1 )
 
 3036                                || ( geomType == GEOS_GEOMETRYCOLLECTION && GEOSGetNumGeometries_r( geosinit()->ctxt, intersectGeom.get() ) > 0 ) 
 
 3037                                || ( geomType == GEOS_MULTILINESTRING && GEOSGetNumGeometries_r( geosinit()->ctxt, intersectGeom.get() ) > 0 );
 
 3039      if ( GEOSGeomTypeId_r( geosinit()->ctxt, intersectGeom.get() ) == GEOS_POINT )
 
 3041        const GEOSCoordSequence *intersectionCoordSeq = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, intersectGeom.get() );
 
 3043        GEOSCoordSeq_getX_r( geosinit()->ctxt, intersectionCoordSeq, 0, &xi );
 
 3044        GEOSCoordSeq_getY_r( geosinit()->ctxt, intersectionCoordSeq, 0, &yi );
 
 3045        oneIntersection = 
true;
 
 3050  catch ( GEOSException & )
 
 3052    atLeastTwoIntersections = 
false;
 
 3056  if ( oneIntersection )
 
 3057    return _mergeLinestrings( line, reshapeLineGeos, oneIntersectionPoint );
 
 3059  if ( !atLeastTwoIntersections )
 
 3063  double x1, y1, x2, y2;
 
 3064  if ( !_linestringEndpoints( line, x1, y1, x2, y2 ) )
 
 3070  bool isRing = 
false;
 
 3071  if ( GEOSGeomTypeId_r( geosinit()->ctxt, line ) == GEOS_LINEARRING
 
 3072       || GEOSEquals_r( geosinit()->ctxt, beginLineVertex.get(), endLineVertex.get() ) == 1 )
 
 3077  if ( !nodedGeometry )
 
 3083  geos::unique_ptr mergedLines( GEOSLineMerge_r( geosinit()->ctxt, nodedGeometry.get() ) );
 
 3089  int numMergedLines = GEOSGetNumGeometries_r( geosinit()->ctxt, mergedLines.get() );
 
 3090  if ( numMergedLines < 2 ) 
 
 3092    if ( numMergedLines == 1 ) 
 
 3094      geos::unique_ptr result( GEOSGeom_clone_r( geosinit()->ctxt, reshapeLineGeos ) );
 
 3101  QVector<GEOSGeometry *> resultLineParts; 
 
 3102  QVector<GEOSGeometry *> probableParts; 
 
 3104  for ( 
int i = 0; i < numMergedLines; ++i )
 
 3106    const GEOSGeometry *currentGeom = GEOSGetGeometryN_r( geosinit()->ctxt, mergedLines.get(), i );
 
 3109    bool alreadyAdded = 
false;
 
 3111    double bufferDistance = std::pow( 10.0L, geomDigits( currentGeom ) - 11 );
 
 3112    for ( 
const GEOSGeometry *other : std::as_const( resultLineParts ) )
 
 3114      GEOSHausdorffDistance_r( geosinit()->ctxt, currentGeom, other, &
distance );
 
 3117        alreadyAdded = 
true;
 
 3124    const GEOSCoordSequence *currentCoordSeq = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, currentGeom );
 
 3125    unsigned int currentCoordSeqSize;
 
 3126    GEOSCoordSeq_getSize_r( geosinit()->ctxt, currentCoordSeq, ¤tCoordSeqSize );
 
 3127    if ( currentCoordSeqSize < 2 )
 
 3131    double xBegin, xEnd, yBegin, yEnd;
 
 3132    GEOSCoordSeq_getX_r( geosinit()->ctxt, currentCoordSeq, 0, &xBegin );
 
 3133    GEOSCoordSeq_getY_r( geosinit()->ctxt, currentCoordSeq, 0, &yBegin );
 
 3134    GEOSCoordSeq_getX_r( geosinit()->ctxt, currentCoordSeq, currentCoordSeqSize - 1, &xEnd );
 
 3135    GEOSCoordSeq_getY_r( geosinit()->ctxt, currentCoordSeq, currentCoordSeqSize - 1, &yEnd );
 
 3140    int nEndpointsOnOriginalLine = 0;
 
 3141    if ( pointContainedInLine( beginCurrentGeomVertex.get(), line ) == 1 )
 
 3142      nEndpointsOnOriginalLine += 1;
 
 3144    if ( pointContainedInLine( endCurrentGeomVertex.get(), line ) == 1 )
 
 3145      nEndpointsOnOriginalLine += 1;
 
 3148    int nEndpointsSameAsOriginalLine = 0;
 
 3149    if ( GEOSEquals_r( geosinit()->ctxt, beginCurrentGeomVertex.get(), beginLineVertex.get() ) == 1
 
 3150         || GEOSEquals_r( geosinit()->ctxt, beginCurrentGeomVertex.get(), endLineVertex.get() ) == 1 )
 
 3151      nEndpointsSameAsOriginalLine += 1;
 
 3153    if ( GEOSEquals_r( geosinit()->ctxt, endCurrentGeomVertex.get(), beginLineVertex.get() ) == 1
 
 3154         || GEOSEquals_r( geosinit()->ctxt, endCurrentGeomVertex.get(), endLineVertex.get() ) == 1 )
 
 3155      nEndpointsSameAsOriginalLine += 1;
 
 3158    bool currentGeomOverlapsOriginalGeom = 
false;
 
 3159    bool currentGeomOverlapsReshapeLine = 
false;
 
 3160    if ( lineContainedInLine( currentGeom, line ) == 1 )
 
 3161      currentGeomOverlapsOriginalGeom = 
true;
 
 3163    if ( lineContainedInLine( currentGeom, reshapeLineGeos ) == 1 )
 
 3164      currentGeomOverlapsReshapeLine = 
true;
 
 3167    if ( !isRing && nEndpointsSameAsOriginalLine == 1 && nEndpointsOnOriginalLine == 2 && currentGeomOverlapsOriginalGeom )
 
 3169      resultLineParts.push_back( GEOSGeom_clone_r( geosinit()->ctxt, currentGeom ) );
 
 3172    else if ( isRing && nEndpointsOnOriginalLine == 2 && currentGeomOverlapsOriginalGeom )
 
 3174      probableParts.push_back( GEOSGeom_clone_r( geosinit()->ctxt, currentGeom ) );
 
 3176    else if ( nEndpointsOnOriginalLine == 2 && !currentGeomOverlapsOriginalGeom )
 
 3178      resultLineParts.push_back( GEOSGeom_clone_r( geosinit()->ctxt, currentGeom ) );
 
 3180    else if ( nEndpointsSameAsOriginalLine == 2 && !currentGeomOverlapsOriginalGeom )
 
 3182      resultLineParts.push_back( GEOSGeom_clone_r( geosinit()->ctxt, currentGeom ) );
 
 3184    else if ( currentGeomOverlapsOriginalGeom && currentGeomOverlapsReshapeLine )
 
 3186      resultLineParts.push_back( GEOSGeom_clone_r( geosinit()->ctxt, currentGeom ) );
 
 3191  if ( isRing && !probableParts.isEmpty() )
 
 3194    GEOSGeometry *currentGeom = 
nullptr;
 
 3195    double maxLength = -std::numeric_limits<double>::max();
 
 3196    double currentLength = 0;
 
 3197    for ( 
int i = 0; i < probableParts.size(); ++i )
 
 3199      currentGeom = probableParts.at( i );
 
 3200      GEOSLength_r( geosinit()->ctxt, currentGeom, ¤tLength );
 
 3201      if ( currentLength > maxLength )
 
 3203        maxLength = currentLength;
 
 3204        maxGeom.reset( currentGeom );
 
 3208        GEOSGeom_destroy_r( geosinit()->ctxt, currentGeom );
 
 3211    resultLineParts.push_back( maxGeom.release() );
 
 3215  if ( resultLineParts.empty() )
 
 3218  if ( resultLineParts.size() == 1 ) 
 
 3220    result.reset( resultLineParts[0] );
 
 3224    GEOSGeometry **lineArray = 
new GEOSGeometry*[resultLineParts.size()];
 
 3225    for ( 
int i = 0; i < resultLineParts.size(); ++i )
 
 3227      lineArray[i] = resultLineParts[i];
 
 3231    geos::unique_ptr multiLineGeom( GEOSGeom_createCollection_r( geosinit()->ctxt, GEOS_MULTILINESTRING, lineArray, resultLineParts.size() ) );
 
 3232    delete [] lineArray;
 
 3235    result.reset( GEOSLineMerge_r( geosinit()->ctxt, multiLineGeom.get() ) );
 
 3239  if ( GEOSGeomTypeId_r( geosinit()->ctxt, result.get() ) != GEOS_LINESTRING )
 
 3247geos::unique_ptr QgsGeos::reshapePolygon( 
const GEOSGeometry *polygon, 
const GEOSGeometry *reshapeLineGeos, 
double precision )
 
 3250  int nIntersections = 0;
 
 3251  int lastIntersectingRing = -2;
 
 3252  const GEOSGeometry *lastIntersectingGeom = 
nullptr;
 
 3254  int nRings = GEOSGetNumInteriorRings_r( geosinit()->ctxt, polygon );
 
 3259  const GEOSGeometry *outerRing = GEOSGetExteriorRing_r( geosinit()->ctxt, polygon );
 
 3260  if ( GEOSIntersects_r( geosinit()->ctxt, outerRing, reshapeLineGeos ) == 1 )
 
 3263    lastIntersectingRing = -1;
 
 3264    lastIntersectingGeom = outerRing;
 
 3268  const GEOSGeometry **innerRings = 
new const GEOSGeometry*[nRings];
 
 3272    for ( 
int i = 0; i < nRings; ++i )
 
 3274      innerRings[i] = GEOSGetInteriorRingN_r( geosinit()->ctxt, polygon, i );
 
 3275      if ( GEOSIntersects_r( geosinit()->ctxt, innerRings[i], reshapeLineGeos ) == 1 )
 
 3278        lastIntersectingRing = i;
 
 3279        lastIntersectingGeom = innerRings[i];
 
 3283  catch ( GEOSException & )
 
 3288  if ( nIntersections != 1 ) 
 
 3290    delete [] innerRings;
 
 3296  if ( !reshapeResult )
 
 3298    delete [] innerRings;
 
 3303  GEOSGeometry *newRing = 
nullptr;
 
 3304  const GEOSCoordSequence *reshapeSequence = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, reshapeResult.get() );
 
 3305  GEOSCoordSequence *newCoordSequence = GEOSCoordSeq_clone_r( geosinit()->ctxt, reshapeSequence );
 
 3307  reshapeResult.reset();
 
 3309  newRing = GEOSGeom_createLinearRing_r( geosinit()->ctxt, newCoordSequence );
 
 3312    delete [] innerRings;
 
 3316  GEOSGeometry *newOuterRing = 
nullptr;
 
 3317  if ( lastIntersectingRing == -1 )
 
 3318    newOuterRing = newRing;
 
 3320    newOuterRing = GEOSGeom_clone_r( geosinit()->ctxt, outerRing );
 
 3323  QVector<GEOSGeometry *> ringList;
 
 3326    GEOSGeometry *outerRingPoly = GEOSGeom_createPolygon_r( geosinit()->ctxt, GEOSGeom_clone_r( geosinit()->ctxt, newOuterRing ), 
nullptr, 0 );
 
 3327    if ( outerRingPoly )
 
 3329      ringList.reserve( nRings );
 
 3330      GEOSGeometry *currentRing = 
nullptr;
 
 3331      for ( 
int i = 0; i < nRings; ++i )
 
 3333        if ( lastIntersectingRing == i )
 
 3334          currentRing = newRing;
 
 3336          currentRing = GEOSGeom_clone_r( geosinit()->ctxt, innerRings[i] );
 
 3339        if ( GEOSContains_r( geosinit()->ctxt, outerRingPoly, currentRing ) == 1 )
 
 3340          ringList.push_back( currentRing );
 
 3342          GEOSGeom_destroy_r( geosinit()->ctxt, currentRing );
 
 3345    GEOSGeom_destroy_r( geosinit()->ctxt, outerRingPoly );
 
 3348  GEOSGeometry **newInnerRings = 
new GEOSGeometry*[ringList.size()];
 
 3349  for ( 
int i = 0; i < ringList.size(); ++i )
 
 3350    newInnerRings[i] = ringList.at( i );
 
 3352  delete [] innerRings;
 
 3354  geos::unique_ptr reshapedPolygon( GEOSGeom_createPolygon_r( geosinit()->ctxt, newOuterRing, newInnerRings, ringList.size() ) );
 
 3355  delete[] newInnerRings;
 
 3357  return reshapedPolygon;
 
 3360int QgsGeos::lineContainedInLine( 
const GEOSGeometry *line1, 
const GEOSGeometry *line2 )
 
 3362  if ( !line1 || !line2 )
 
 3367  double bufferDistance = std::pow( 10.0L, geomDigits( line2 ) - 11 );
 
 3373  geos::unique_ptr intersectionGeom( GEOSIntersection_r( geosinit()->ctxt, bufferGeom.get(), line1 ) );
 
 3376  double intersectGeomLength;
 
 3379  GEOSLength_r( geosinit()->ctxt, intersectionGeom.get(), &intersectGeomLength );
 
 3380  GEOSLength_r( geosinit()->ctxt, line1, &line1Length );
 
 3382  double intersectRatio = line1Length / intersectGeomLength;
 
 3383  if ( intersectRatio > 0.9 && intersectRatio < 1.1 )
 
 3389int QgsGeos::pointContainedInLine( 
const GEOSGeometry *point, 
const GEOSGeometry *line )
 
 3391  if ( !point || !line )
 
 3394  double bufferDistance = std::pow( 10.0L, geomDigits( line ) - 11 );
 
 3396  geos::unique_ptr lineBuffer( GEOSBuffer_r( geosinit()->ctxt, line, bufferDistance, 8 ) );
 
 3400  bool contained = 
false;
 
 3401  if ( GEOSContains_r( geosinit()->ctxt, lineBuffer.get(), point ) == 1 )
 
 3407int QgsGeos::geomDigits( 
const GEOSGeometry *geom )
 
 3413  const GEOSGeometry *bBoxRing = GEOSGetExteriorRing_r( geosinit()->ctxt, bbox.get() );
 
 3417  const GEOSCoordSequence *bBoxCoordSeq = GEOSGeom_getCoordSeq_r( geosinit()->ctxt, bBoxRing );
 
 3419  if ( !bBoxCoordSeq )
 
 3422  unsigned int nCoords = 0;
 
 3423  if ( !GEOSCoordSeq_getSize_r( geosinit()->ctxt, bBoxCoordSeq, &nCoords ) )
 
 3427  for ( 
unsigned int i = 0; i < nCoords - 1; ++i )
 
 3430    GEOSCoordSeq_getX_r( geosinit()->ctxt, bBoxCoordSeq, i, &t );
 
 3433    digits = std::ceil( std::log10( std::fabs( t ) ) );
 
 3434    if ( digits > maxDigits )
 
 3437    GEOSCoordSeq_getY_r( geosinit()->ctxt, bBoxCoordSeq, i, &t );
 
 3438    digits = std::ceil( std::log10( std::fabs( t ) ) );
 
 3439    if ( digits > maxDigits )
 
 3448  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...
 
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.
 
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.
 
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(QgsWkbTypes::Type 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 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)
 
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.