21 #if ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR<8 ) 
   40   const GEOSGeometry *geom = 
nullptr;
 
   41   GEOSGeometry *env = 
nullptr;
 
   43   struct Face_t *parent; 
 
   46 static Face *newFace( 
const GEOSGeometry *g );
 
   47 static void delFace( Face *f );
 
   48 static unsigned int countParens( 
const Face *f );
 
   49 static void findFaceHoles( Face **faces, 
int nfaces );
 
   51 static Face *newFace( 
const GEOSGeometry *g )
 
   57   f->env = GEOSEnvelope_r( handle, f->geom );
 
   58   GEOSArea_r( handle, f->env, &f->envarea );
 
   63 static unsigned int countParens( 
const Face *f )
 
   65   unsigned int pcount = 0;
 
   75 static void delFace( Face *f )
 
   78   GEOSGeom_destroy_r( handle, f->env );
 
   83 static int compare_by_envarea( 
const void *g1, 
const void *g2 )
 
   85   Face *f1 = *( Face ** )g1;
 
   86   Face *f2 = *( Face ** )g2;
 
   87   double n1 = f1->envarea;
 
   88   double n2 = f2->envarea;
 
   90   if ( n1 < n2 ) 
return 1;
 
   91   if ( n1 > n2 ) 
return -1;
 
   96 static void findFaceHoles( Face **faces, 
int nfaces )
 
  102   qsort( faces, nfaces, 
sizeof( Face * ), compare_by_envarea );
 
  103   for ( 
int i = 0; i < nfaces; ++i )
 
  106     int nholes = GEOSGetNumInteriorRings_r( handle, f->geom );
 
  107     for ( 
int h = 0; h < nholes; ++h )
 
  109       const GEOSGeometry *hole = GEOSGetInteriorRingN_r( handle, f->geom, h );
 
  110       for ( 
int j = i + 1; j < nfaces; ++j )
 
  120         if ( GEOSEquals_r( handle, GEOSGetExteriorRing_r( handle, f2->geom ), hole ) )
 
  130 static GEOSGeometry *collectFacesWithEvenAncestors( Face **faces, 
int nfaces )
 
  134   unsigned int ngeoms = 0;
 
  135   GEOSGeometry **geoms = 
new GEOSGeometry*[nfaces];
 
  136   for ( 
int i = 0; i < nfaces; ++i )
 
  139     if ( countParens( f ) % 2 )
 
  141     geoms[ngeoms++] = GEOSGeom_clone_r( handle, f->geom );
 
  144   GEOSGeometry *ret = GEOSGeom_createCollection_r( handle, GEOS_MULTIPOLYGON, geoms, ngeoms );
 
  150 static GEOSGeometry *LWGEOM_GEOS_buildArea( 
const GEOSGeometry *geom_in, QString &errorMessage )
 
  154   GEOSGeometry *tmp = 
nullptr;
 
  155   GEOSGeometry *shp = 
nullptr;
 
  156   GEOSGeometry *geos_result = 
nullptr;
 
  157   int srid = GEOSGetSRID_r( handle, geom_in );
 
  159   GEOSGeometry 
const *vgeoms[1];
 
  163     geos_result = GEOSPolygonize_r( handle, vgeoms, 1 );
 
  165   catch ( GEOSException &e )
 
  167     errorMessage = QStringLiteral( 
"GEOSPolygonize(): %1" ).arg( e.what() );
 
  172 #if PARANOIA_LEVEL > 0 
  173   if ( GEOSGeometryTypeId_r( handle, geos_result ) != COLLECTIONTYPE )
 
  175     GEOSGeom_destroy_r( handle, geos_result );
 
  176     errorMessage = 
"Unexpected return from GEOSpolygonize";
 
  181   int ngeoms = GEOSGetNumGeometries_r( handle, geos_result );
 
  186     GEOSSetSRID_r( handle, geos_result, srid );
 
  194     tmp = ( GEOSGeometry * )GEOSGetGeometryN_r( handle, geos_result, 0 );
 
  197       GEOSGeom_destroy_r( handle, geos_result );
 
  200     shp = GEOSGeom_clone_r( handle, tmp );
 
  201     GEOSGeom_destroy_r( handle, geos_result ); 
 
  202     GEOSSetSRID_r( handle, shp, srid );
 
  235   Face **geoms = 
new Face*[ngeoms];
 
  236   for ( 
int i = 0; i < ngeoms; ++i )
 
  237     geoms[i] = newFace( GEOSGetGeometryN_r( handle, geos_result, i ) );
 
  240   findFaceHoles( geoms, ngeoms );
 
  244   tmp = collectFacesWithEvenAncestors( geoms, ngeoms );
 
  247   for ( 
int i = 0; i < ngeoms; ++i )
 
  253   GEOSGeom_destroy_r( handle, geos_result );
 
  256   shp = GEOSUnionCascaded_r( handle, tmp );
 
  259     GEOSGeom_destroy_r( handle, tmp );
 
  263   GEOSGeom_destroy_r( handle, tmp );
 
  265   GEOSSetSRID_r( handle, shp, srid );
 
  273 static GEOSGeometry *LWGEOM_GEOS_getPointN( 
const GEOSGeometry *g_in, uint32_t n )
 
  278   const GEOSCoordSequence *seq_in = 
nullptr;
 
  279   GEOSCoordSeq seq_out;
 
  283   GEOSGeometry *ret = 
nullptr;
 
  285   switch ( GEOSGeomTypeId_r( handle, g_in ) )
 
  287     case GEOS_MULTIPOINT:
 
  288     case GEOS_MULTILINESTRING:
 
  289     case GEOS_MULTIPOLYGON:
 
  290     case GEOS_GEOMETRYCOLLECTION:
 
  292       for ( gn = 0; gn < GEOSGetNumGeometries_r( handle, g_in ); ++gn )
 
  294         const GEOSGeometry *g = GEOSGetGeometryN_r( handle, g_in, gn );
 
  295         ret = LWGEOM_GEOS_getPointN( g, n );
 
  296         if ( ret ) 
return ret;
 
  303       ret = LWGEOM_GEOS_getPointN( GEOSGetExteriorRing_r( handle, g_in ), n );
 
  304       if ( ret ) 
return ret;
 
  305       for ( gn = 0; gn < GEOSGetNumInteriorRings_r( handle, g_in ); ++gn )
 
  307         const GEOSGeometry *g = GEOSGetInteriorRingN_r( handle, g_in, gn );
 
  308         ret = LWGEOM_GEOS_getPointN( g, n );
 
  309         if ( ret ) 
return ret;
 
  315     case GEOS_LINESTRING:
 
  316     case GEOS_LINEARRING:
 
  321   seq_in = GEOSGeom_getCoordSeq_r( handle, g_in );
 
  322   if ( ! seq_in ) 
return nullptr;
 
  323   if ( ! GEOSCoordSeq_getSize_r( handle, seq_in, &sz ) ) 
return nullptr;
 
  324   if ( ! sz ) 
return nullptr;
 
  326   if ( ! GEOSCoordSeq_getDimensions_r( handle, seq_in, &dims ) ) 
return nullptr;
 
  328   seq_out = GEOSCoordSeq_create_r( handle, 1, dims );
 
  329   if ( ! seq_out ) 
return nullptr;
 
  331   if ( ! GEOSCoordSeq_getX_r( handle, seq_in, n, &val ) ) 
return nullptr;
 
  332   if ( ! GEOSCoordSeq_setX_r( handle, seq_out, n, val ) ) 
return nullptr;
 
  333   if ( ! GEOSCoordSeq_getY_r( handle, seq_in, n, &val ) ) 
return nullptr;
 
  334   if ( ! GEOSCoordSeq_setY_r( handle, seq_out, n, val ) ) 
return nullptr;
 
  337     if ( ! GEOSCoordSeq_getZ_r( handle, seq_in, n, &val ) ) 
return nullptr;
 
  338     if ( ! GEOSCoordSeq_setZ_r( handle, seq_out, n, val ) ) 
return nullptr;
 
  341   return GEOSGeom_createPoint_r( handle, seq_out );
 
  345 static bool lwline_make_geos_friendly( 
QgsLineString *line );
 
  346 static bool lwpoly_make_geos_friendly( 
QgsPolygon *poly );
 
  364       return lwline_make_geos_friendly( qgsgeometry_cast<QgsLineString *>( geom ) );
 
  369       return lwpoly_make_geos_friendly( qgsgeometry_cast<QgsPolygon *>( geom ) );
 
  375       return lwcollection_make_geos_friendly( qgsgeometry_cast<QgsGeometryCollection *>( geom ) );
 
  379       QgsDebugMsg( QStringLiteral( 
"lwgeom_make_geos_friendly: unsupported input geometry type: %1" ).arg( geom->
wkbType() ) );
 
  386 static bool ring_make_geos_friendly( 
QgsCurve *ring )
 
  392   QgsLineString *linestring = qgsgeometry_cast<QgsLineString *>( ring );
 
  393   Q_ASSERT_X( linestring, 
"ring_make_geos_friendly", 
"ring was not a linestring" );
 
  398   if ( p1.
x() != p2.x() || p1.
y() != p2.y() )
 
  410 static bool lwpoly_make_geos_friendly( 
QgsPolygon *poly )
 
  419     if ( !ring_make_geos_friendly( qgsgeometry_cast<QgsCurve *>( poly->
interiorRing( i ) ) ) )
 
  440     if ( !lwgeom_make_geos_friendly( g->
geometryN( i ) ) )
 
  449 static GEOSGeometry *LWGEOM_GEOS_nodeLines( 
const GEOSGeometry *lines )
 
  458   GEOSGeometry *point = LWGEOM_GEOS_getPointN( lines, 0 );
 
  462   GEOSGeometry *noded = 
nullptr;
 
  465     noded = GEOSUnion_r( handle, lines, point );
 
  467   catch ( GEOSException & )
 
  471   GEOSGeom_destroy_r( handle, point );
 
  477 static GEOSGeometry *LWGEOM_GEOS_makeValidPolygon( 
const GEOSGeometry *gin, QString &errorMessage )
 
  483   GEOSGeom geos_cut_edges, geos_area, collapse_points;
 
  484   GEOSGeometry *vgeoms[3]; 
 
  485   unsigned int nvgeoms = 0;
 
  487   Q_ASSERT( GEOSGeomTypeId_r( handle, gin ) == GEOS_POLYGON ||
 
  488             GEOSGeomTypeId_r( handle, gin ) == GEOS_MULTIPOLYGON );
 
  490   geos_bound = GEOSBoundary_r( handle, gin );
 
  496   geos_cut_edges = LWGEOM_GEOS_nodeLines( geos_bound );
 
  497   if ( !geos_cut_edges )
 
  499     GEOSGeom_destroy_r( handle, geos_bound );
 
  500     errorMessage = QStringLiteral( 
"LWGEOM_GEOS_nodeLines() failed" );
 
  507     GEOSGeometry *pi = 
nullptr;
 
  508     GEOSGeometry *po = 
nullptr;
 
  512       pi = GEOSGeom_extractUniquePoints_r( handle, geos_bound );
 
  514     catch ( GEOSException &e )
 
  516       GEOSGeom_destroy_r( handle, geos_bound );
 
  517       errorMessage = QStringLiteral( 
"GEOSGeom_extractUniquePoints(): %1" ).arg( e.what() );
 
  523       po = GEOSGeom_extractUniquePoints_r( handle, geos_cut_edges );
 
  525     catch ( GEOSException &e )
 
  527       GEOSGeom_destroy_r( handle, geos_bound );
 
  528       GEOSGeom_destroy_r( handle, pi );
 
  529       errorMessage = QStringLiteral( 
"GEOSGeom_extractUniquePoints(): %1" ).arg( e.what() );
 
  535       collapse_points = GEOSDifference_r( handle, pi, po );
 
  537     catch ( GEOSException &e )
 
  539       GEOSGeom_destroy_r( handle, geos_bound );
 
  540       GEOSGeom_destroy_r( handle, pi );
 
  541       GEOSGeom_destroy_r( handle, po );
 
  542       errorMessage = QStringLiteral( 
"GEOSDifference(): %1" ).arg( e.what() );
 
  546     GEOSGeom_destroy_r( handle, pi );
 
  547     GEOSGeom_destroy_r( handle, po );
 
  549   GEOSGeom_destroy_r( handle, geos_bound );
 
  554     geos_area = GEOSGeom_createEmptyPolygon_r( handle );
 
  556   catch ( GEOSException &e )
 
  558     errorMessage = QStringLiteral( 
"GEOSGeom_createEmptyPolygon(): %1" ).arg( e.what() );
 
  559     GEOSGeom_destroy_r( handle, geos_cut_edges );
 
  567   while ( GEOSGetNumGeometries_r( handle, geos_cut_edges ) )
 
  569     GEOSGeometry *new_area = 
nullptr;
 
  570     GEOSGeometry *new_area_bound = 
nullptr;
 
  571     GEOSGeometry *symdif = 
nullptr;
 
  572     GEOSGeometry *new_cut_edges = 
nullptr;
 
  578       new_area = LWGEOM_GEOS_buildArea( geos_cut_edges, errorMessage );
 
  580     catch ( GEOSException &e )
 
  582       GEOSGeom_destroy_r( handle, geos_cut_edges );
 
  583       GEOSGeom_destroy_r( handle, geos_area );
 
  584       errorMessage = QStringLiteral( 
"LWGEOM_GEOS_buildArea() threw an error: %1" ).arg( e.what() );
 
  588     if ( GEOSisEmpty_r( handle, new_area ) )
 
  591       GEOSGeom_destroy_r( handle, new_area );
 
  601       new_area_bound = GEOSBoundary_r( handle, new_area );
 
  603     catch ( GEOSException &e )
 
  607       errorMessage = QStringLiteral( 
"GEOSBoundary() threw an error: %1" ).arg( e.what() );
 
  608       GEOSGeom_destroy_r( handle, new_area );
 
  609       GEOSGeom_destroy_r( handle, geos_area );
 
  616       symdif = GEOSSymDifference_r( handle, geos_area, new_area );
 
  618     catch ( GEOSException &e )
 
  620       GEOSGeom_destroy_r( handle, geos_cut_edges );
 
  621       GEOSGeom_destroy_r( handle, new_area );
 
  622       GEOSGeom_destroy_r( handle, new_area_bound );
 
  623       GEOSGeom_destroy_r( handle, geos_area );
 
  624       errorMessage = QStringLiteral( 
"GEOSSymDifference() threw an error: %1" ).arg( e.what() );
 
  628     GEOSGeom_destroy_r( handle, geos_area );
 
  629     GEOSGeom_destroy_r( handle, new_area );
 
  643       new_cut_edges = GEOSDifference_r( handle, geos_cut_edges, new_area_bound );
 
  645     catch ( GEOSException &e )
 
  647       GEOSGeom_destroy_r( handle, geos_cut_edges );
 
  648       GEOSGeom_destroy_r( handle, new_area_bound );
 
  649       GEOSGeom_destroy_r( handle, geos_area );
 
  650       errorMessage = QStringLiteral( 
"GEOSDifference() threw an error: %1" ).arg( e.what() );
 
  653     GEOSGeom_destroy_r( handle, geos_cut_edges );
 
  654     GEOSGeom_destroy_r( handle, new_area_bound );
 
  655     geos_cut_edges = new_cut_edges;
 
  658   if ( !GEOSisEmpty_r( handle, geos_area ) )
 
  660     vgeoms[nvgeoms++] = geos_area;
 
  664     GEOSGeom_destroy_r( handle, geos_area );
 
  667   if ( !GEOSisEmpty_r( handle, geos_cut_edges ) )
 
  669     vgeoms[nvgeoms++] = geos_cut_edges;
 
  673     GEOSGeom_destroy_r( handle, geos_cut_edges );
 
  676   if ( !GEOSisEmpty_r( handle, collapse_points ) )
 
  678     vgeoms[nvgeoms++] = collapse_points;
 
  682     GEOSGeom_destroy_r( handle, collapse_points );
 
  695       gout = GEOSGeom_createCollection_r( handle, GEOS_GEOMETRYCOLLECTION, vgeoms, nvgeoms );
 
  697     catch ( GEOSException &e )
 
  699       errorMessage = QStringLiteral( 
"GEOSGeom_createCollection() threw an error: %1" ).arg( e.what() );
 
  710 static GEOSGeometry *LWGEOM_GEOS_makeValidLine( 
const GEOSGeometry *gin, QString &errorMessage )
 
  712   Q_UNUSED( errorMessage )
 
  713   return LWGEOM_GEOS_nodeLines( gin );
 
  716 static GEOSGeometry *LWGEOM_GEOS_makeValidMultiLine( 
const GEOSGeometry *gin, QString &errorMessage )
 
  720   int ngeoms = GEOSGetNumGeometries_r( handle, gin );
 
  721   uint32_t nlines_alloc = ngeoms;
 
  722   QVector<GEOSGeometry *> lines;
 
  723   QVector<GEOSGeometry *> points;
 
  724   lines.reserve( nlines_alloc );
 
  725   points.reserve( ngeoms );
 
  727   for ( 
int i = 0; i < ngeoms; ++i )
 
  729     const GEOSGeometry *g = GEOSGetGeometryN_r( handle, gin, i );
 
  730     GEOSGeometry *vg = LWGEOM_GEOS_makeValidLine( g, errorMessage );
 
  731     if ( GEOSisEmpty_r( handle, vg ) )
 
  734       GEOSGeom_destroy_r( handle, vg );
 
  736     if ( GEOSGeomTypeId_r( handle, vg ) == GEOS_POINT )
 
  740     else if ( GEOSGeomTypeId_r( handle, vg ) == GEOS_LINESTRING )
 
  744     else if ( GEOSGeomTypeId_r( handle, vg ) == GEOS_MULTILINESTRING )
 
  746       int nsubgeoms = GEOSGetNumGeometries_r( handle, vg );
 
  747       nlines_alloc += nsubgeoms;
 
  748       lines.reserve( nlines_alloc );
 
  749       for ( 
int j = 0; j < nsubgeoms; ++j )
 
  752         lines.append( GEOSGeom_clone_r( handle, GEOSGetGeometryN_r( handle, vg, j ) ) );
 
  758       errorMessage = QStringLiteral( 
"unexpected geom type returned by LWGEOM_GEOS_makeValid: %1" ).arg( GEOSGeomTypeId_r( handle, vg ) );
 
  762   GEOSGeometry *mpoint_out = 
nullptr;
 
  763   if ( !points.isEmpty() )
 
  765     if ( points.count() > 1 )
 
  767       mpoint_out = GEOSGeom_createCollection_r( handle, GEOS_MULTIPOINT, points.data(), points.count() );
 
  771       mpoint_out = points[0];
 
  775   GEOSGeometry *mline_out = 
nullptr;
 
  776   if ( !lines.isEmpty() )
 
  778     if ( lines.count() > 1 )
 
  780       mline_out = GEOSGeom_createCollection_r( handle, GEOS_MULTILINESTRING, lines.data(), lines.count() );
 
  784       mline_out = lines[0];
 
  788   if ( mline_out && mpoint_out )
 
  790     GEOSGeometry *collection[2];
 
  791     collection[0] = mline_out;
 
  792     collection[1] = mpoint_out;
 
  793     return GEOSGeom_createCollection_r( handle, GEOS_GEOMETRYCOLLECTION, collection, 2 );
 
  795   else if ( mline_out )
 
  799   else if ( mpoint_out )
 
  810 static GEOSGeometry *LWGEOM_GEOS_makeValid( 
const GEOSGeometry *gin, QString &errorMessage );
 
  813 static GEOSGeometry *LWGEOM_GEOS_makeValidCollection( 
const GEOSGeometry *gin, QString &errorMessage )
 
  817   int nvgeoms = GEOSGetNumGeometries_r( handle, gin );
 
  820     errorMessage = QStringLiteral( 
"GEOSGetNumGeometries: %1" ).arg( QLatin1String( 
"?" ) );
 
  824   QVector<GEOSGeometry *> vgeoms( nvgeoms );
 
  825   for ( 
int i = 0; i < nvgeoms; ++i )
 
  827     vgeoms[i] = LWGEOM_GEOS_makeValid( GEOSGetGeometryN_r( handle, gin, i ), errorMessage );
 
  831         GEOSGeom_destroy_r( handle, vgeoms[i] );
 
  840     return GEOSGeom_createCollection_r( handle, GEOS_GEOMETRYCOLLECTION, vgeoms.data(), nvgeoms );
 
  842   catch ( GEOSException &e )
 
  845     for ( 
int i = 0; i < nvgeoms; ++i )
 
  846       GEOSGeom_destroy_r( handle, vgeoms[i] );
 
  847     errorMessage = QStringLiteral( 
"GEOSGeom_createCollection() threw an error: %1" ).arg( e.what() );
 
  853 static GEOSGeometry *LWGEOM_GEOS_makeValid( 
const GEOSGeometry *gin, QString &errorMessage )
 
  861     if ( GEOSisValid_r( handle, gin ) )
 
  864       return GEOSGeom_clone_r( handle, gin );
 
  867   catch ( GEOSException &e )
 
  870     errorMessage = QStringLiteral( 
"GEOSisValid(): %1" ).arg( e.what() );
 
  877   switch ( GEOSGeomTypeId_r( handle, gin ) )
 
  879     case GEOS_MULTIPOINT:
 
  882       QgsDebugMsg( QStringLiteral( 
"PUNTUAL geometry resulted invalid to GEOS -- dunno how to clean that up" ) );
 
  885     case GEOS_LINESTRING:
 
  886       return LWGEOM_GEOS_makeValidLine( gin, errorMessage );
 
  888     case GEOS_MULTILINESTRING:
 
  889       return LWGEOM_GEOS_makeValidMultiLine( gin, errorMessage );
 
  892     case GEOS_MULTIPOLYGON:
 
  893       return LWGEOM_GEOS_makeValidPolygon( gin, errorMessage );
 
  895     case GEOS_GEOMETRYCOLLECTION:
 
  896       return LWGEOM_GEOS_makeValidCollection( gin, errorMessage );
 
  899       errorMessage = QStringLiteral( 
"ST_MakeValid: doesn't support geometry type: %1" ).arg( GEOSGeomTypeId_r( handle, gin ) );
 
  905 std::unique_ptr< QgsAbstractGeometry > _qgis_lwgeom_make_valid( 
const QgsAbstractGeometry *lwgeom_in, QString &errorMessage )
 
  916     QgsDebugMsgLevel( QStringLiteral( 
"Original geom can't be converted to GEOS - will try cleaning that up first" ), 3 );
 
  918     std::unique_ptr<QgsAbstractGeometry> lwgeom_in_clone( lwgeom_in->
clone() );
 
  919     if ( !lwgeom_make_geos_friendly( lwgeom_in_clone.get() ) )
 
  921       QgsDebugMsg( QStringLiteral( 
"Could not make a valid geometry out of input" ) );
 
  930       errorMessage = QStringLiteral( 
"Could not convert QGIS geom to GEOS" );
 
  939   GEOSGeometry *geosout = LWGEOM_GEOS_makeValid( geosgeom.get(), errorMessage );
 
  943   std::unique_ptr< QgsAbstractGeometry > lwgeom_out = 
QgsGeos::fromGeos( geosout );
 
  944   GEOSGeom_destroy_r( handle, geosout );
 
  968     lwgeom_out.reset( collection );
 
Abstract base class for all geometries.
virtual int nCoordinates() const
Returns the number of nodes contained in the geometry.
virtual QgsAbstractGeometry * clone() const =0
Clones the geometry by performing a deep copy.
QgsWkbTypes::Type wkbType() const SIP_HOLDGIL
Returns the WKB type of the geometry.
const QgsCurve * interiorRing(int i) const SIP_HOLDGIL
Retrieves an interior ring from the curve polygon.
int numInteriorRings() const SIP_HOLDGIL
Returns the number of interior rings contained with the curve polygon.
Abstract base class for curved geometry type.
int numGeometries() const SIP_HOLDGIL
Returns the number of geometries within the collection.
const QgsAbstractGeometry * geometryN(int n) const
Returns a const reference to a geometry from within the collection.
virtual bool addGeometry(QgsAbstractGeometry *g)
Adds a geometry and takes ownership. Returns true in case of success.
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...
static std::unique_ptr< QgsAbstractGeometry > fromGeos(const GEOSGeometry *geos)
Create a geometry from a GEOSGeometry.
static GEOSContextHandle_t getGEOSHandler()
Line string geometry type, with support for z-dimension and m-values.
QgsPoint startPoint() const override SIP_HOLDGIL
Returns the starting point of the curve.
QgsPoint endPoint() const override SIP_HOLDGIL
Returns the end point of the curve.
int numPoints() const override SIP_HOLDGIL
Returns the number of points in the curve.
int nCoordinates() const override SIP_HOLDGIL
Returns the number of nodes contained in the geometry.
void addVertex(const QgsPoint &pt)
Adds a new vertex to the end of the line string.
Multi line string geometry collection.
Multi point geometry collection.
Multi polygon geometry collection.
Point geometry type, with support for z-dimension and m-values.
static bool isMultiType(Type type) SIP_HOLDGIL
Returns true if the WKB type is a multi type.
static Type flatType(Type type) SIP_HOLDGIL
Returns the flat type for a WKB type.
static Type multiType(Type type) SIP_HOLDGIL
Returns the multi type for a WKB type.
std::unique_ptr< GEOSGeometry, GeosDeleter > unique_ptr
Scoped GEOS pointer.
#define Q_NOWARN_UNREACHABLE_PUSH
#define Q_NOWARN_UNREACHABLE_POP
#define QgsDebugMsgLevel(str, level)