[api] Expose GEOS make valid options for geos 3.10+ builds

This commit is contained in:
Nyall Dawson 2022-09-03 09:27:55 +10:00
parent 6b071d3be5
commit 804951ea26
8 changed files with 83 additions and 20 deletions

View File

@ -957,6 +957,12 @@ Qgis.JoinStyle.__doc__ = 'Join styles for buffers.\n\n.. versionadded:: 3.22\n\n
# --
Qgis.JoinStyle.baseClass = Qgis
# monkey patching scoped based enum
Qgis.MakeValidMethod.Linework.__doc__ = "Combines all rings into a set of noded lines and then extracts valid polygons from that linework."
Qgis.MakeValidMethod.Structure.__doc__ = "Structured method, first makes all rings valid and then merges shells and subtracts holes from shells to generate valid result. Assumes that holes and shells are correctly categorized. Requires GEOS 3.10+."
Qgis.MakeValidMethod.__doc__ = 'Algorithms to use when repairing invalid geometries.\n\n.. versionadded:: 3.28\n\n' + '* ``Linework``: ' + Qgis.MakeValidMethod.Linework.__doc__ + '\n' + '* ``Structure``: ' + Qgis.MakeValidMethod.Structure.__doc__
# --
Qgis.MakeValidMethod.baseClass = Qgis
# monkey patching scoped based enum
Qgis.SpatialFilterType.NoFilter.__doc__ = "No spatial filtering of features"
Qgis.SpatialFilterType.BoundingBox.__doc__ = "Filter using a bounding box"
Qgis.SpatialFilterType.DistanceWithin.__doc__ = "Filter by distance to reference geometry"

View File

@ -2293,7 +2293,7 @@ Modifies geometry to avoid intersections with the layers specified in project pr
.. versionadded:: 1.5
%End
QgsGeometry makeValid() const;
QgsGeometry makeValid( Qgis::MakeValidMethod method = Qgis::MakeValidMethod::Linework, bool keepCollapsed = false ) const throw( QgsNotSupportedException );
%Docstring
Attempts to make an invalid geometry valid without losing vertices.
@ -2306,13 +2306,12 @@ It preserves Z values, but M values will be dropped.
If an error was encountered during the process, more information can be retrieved
by calling :py:func:`~QgsGeometry.lastError` on the returned geometry.
The ``method`` and ``keepCollapsed`` arguments are available since QGIS 3.28.
They require builds based on GEOS 3.10 or later.
:return: new valid QgsGeometry or null geometry on error
.. note::
For QGIS builds using GEOS library versions older than 3.8 this method calls
an internal fork of PostGIS' ST_MakeValid() function. For builds based on GEOS 3.8 or
later this method calls the GEOS MakeValid method directly.
:raises QgsNotSupportedException: on QGIS builds based on GEOS 3.9 or earlier when the ``method`` is not Qgis.MakeValidMethod.Linework or the ``keepCollapsed`` option is set.
.. versionadded:: 3.0

View File

@ -617,6 +617,12 @@ The development version
Bevel,
};
enum class MakeValidMethod
{
Linework,
Structure,
};
enum class SpatialFilterType
{
NoFilter,

View File

@ -30,27 +30,21 @@ email : morb at ozemail dot com dot au
#include "qgsgeometryutils.h"
#include "qgsinternalgeometryengine.h"
#include "qgsgeos.h"
#include "qgsapplication.h"
#include "qgslogger.h"
#include "qgsmaptopixel.h"
#include "qgsmessagelog.h"
#include "qgspointxy.h"
#include "qgsrectangle.h"
#include "qgsvectorlayer.h"
#include "qgsgeometryvalidator.h"
#include "qgsmulticurve.h"
#include "qgsmultilinestring.h"
#include "qgsmultipoint.h"
#include "qgsmultipolygon.h"
#include "qgsmultisurface.h"
#include "qgspoint.h"
#include "qgspolygon.h"
#include "qgslinestring.h"
#include "qgscircle.h"
#include "qgscurve.h"
#include "qgsreadwritelocker.h"
struct QgsGeometryPrivate
{
@ -2871,14 +2865,14 @@ int QgsGeometry::avoidIntersections( const QList<QgsVectorLayer *> &avoidInterse
}
QgsGeometry QgsGeometry::makeValid() const
QgsGeometry QgsGeometry::makeValid( Qgis::MakeValidMethod method, bool keepCollapsed ) const
{
if ( !d->geometry )
return QgsGeometry();
mLastError.clear();
QgsGeos geos( d->geometry.get() );
std::unique_ptr< QgsAbstractGeometry > g( geos.makeValid( &mLastError ) );
std::unique_ptr< QgsAbstractGeometry > g( geos.makeValid( method, keepCollapsed, &mLastError ) );
QgsGeometry result = QgsGeometry( std::move( g ) );
result.mLastError = mLastError;

View File

@ -2369,15 +2369,16 @@ class CORE_EXPORT QgsGeometry
* If an error was encountered during the process, more information can be retrieved
* by calling lastError() on the returned geometry.
*
* The \a method and \a keepCollapsed arguments are available since QGIS 3.28.
* They require builds based on GEOS 3.10 or later.
*
* \returns new valid QgsGeometry or null geometry on error
*
* \note For QGIS builds using GEOS library versions older than 3.8 this method calls
* an internal fork of PostGIS' ST_MakeValid() function. For builds based on GEOS 3.8 or
* later this method calls the GEOS MakeValid method directly.
* \throws QgsNotSupportedException on QGIS builds based on GEOS 3.9 or earlier when the \a method is not Qgis::MakeValidMethod::Linework or the \a keepCollapsed option is set.
*
* \since QGIS 3.0
*/
QgsGeometry makeValid() const;
QgsGeometry makeValid( Qgis::MakeValidMethod method = Qgis::MakeValidMethod::Linework, bool keepCollapsed = false ) const SIP_THROW( QgsNotSupportedException );
/**
* Forces geometries to respect the Right-Hand-Rule, in which the area that is bounded by a polygon

View File

@ -160,19 +160,60 @@ QgsGeometry QgsGeos::geometryFromGeos( const geos::unique_ptr &geos )
return g;
}
std::unique_ptr<QgsAbstractGeometry> QgsGeos::makeValid( QString *errorMsg ) const
std::unique_ptr<QgsAbstractGeometry> QgsGeos::makeValid( Qgis::MakeValidMethod method, bool keepCollapsed, QString *errorMsg ) const
{
if ( !mGeos )
{
return nullptr;
}
#if GEOS_VERSION_MAJOR==3 && GEOS_VERSION_MINOR<10
if ( method != Qgis::MakeValidMethod::Linework )
throw QgsNotSupportedException( QStringLiteral( "The structured method to make geometries valid requires a QGIS build based on GEOS 3.10 or later" ) );
if ( keepCollapsed )
throw QgsNotSupportedException( QStringLiteral( "The keep collapsed option for making geometries valid requires a QGIS build based on GEOS 3.10 or later" ) );
geos::unique_ptr geos;
try
{
geos.reset( GEOSMakeValid_r( geosinit()->ctxt, mGeos.get() ) );
}
CATCH_GEOS_WITH_ERRMSG( nullptr )
#else
GEOSMakeValidParams *params = GEOSMakeValidParams_create_r( geosinit()->ctxt );
switch ( method )
{
case Qgis::MakeValidMethod::Linework:
GEOSMakeValidParams_setMethod_r( geosinit()->ctxt, params, GEOS_MAKE_VALID_LINEWORK );
break;
case Qgis::MakeValidMethod::Structure:
GEOSMakeValidParams_setMethod_r( geosinit()->ctxt, params, GEOS_MAKE_VALID_STRUCTURE );
break;
}
GEOSMakeValidParams_setKeepCollapsed_r( geosinit()->ctxt,
params,
keepCollapsed ? 1 : 0 );
geos::unique_ptr geos;
try
{
geos.reset( GEOSMakeValidWithParams_r( geosinit()->ctxt, mGeos.get(), params ) );
GEOSMakeValidParams_destroy_r( geosinit()->ctxt, params );
}
catch ( GEOSException &e )
{
if ( errorMsg )
{
*errorMsg = e.what();
}
GEOSMakeValidParams_destroy_r( geosinit()->ctxt, params );
return nullptr;
}
#endif
return fromGeos( geos.get() );
}

View File

@ -119,9 +119,13 @@ class CORE_EXPORT QgsGeos: public QgsGeometryEngine
/**
* Repairs the geometry using GEOS make valid routine.
*
* The \a method and \a keepCollapsed arguments require builds based on GEOS 3.10 or later.
*
* \throws QgsNotSupportedException on QGIS builds based on GEOS 3.9 or earlier when the \a method is not Qgis::MakeValidMethod::Linework or the \a keepCollapsed option is set.
* \since QGIS 3.20
*/
std::unique_ptr< QgsAbstractGeometry > makeValid( QString *errorMsg = nullptr ) const;
std::unique_ptr< QgsAbstractGeometry > makeValid( Qgis::MakeValidMethod method = Qgis::MakeValidMethod::Linework, bool keepCollapsed = false, QString *errorMsg = nullptr ) const;
/**
* Adds a new island polygon to a multipolygon feature

View File

@ -1017,6 +1017,18 @@ class CORE_EXPORT Qgis
};
Q_ENUM( JoinStyle )
/**
* Algorithms to use when repairing invalid geometries.
*
* \since QGIS 3.28
*/
enum class MakeValidMethod : int
{
Linework = 0, //!< Combines all rings into a set of noded lines and then extracts valid polygons from that linework.
Structure = 1, //!< Structured method, first makes all rings valid and then merges shells and subtracts holes from shells to generate valid result. Assumes that holes and shells are correctly categorized. Requires GEOS 3.10+.
};
Q_ENUM( MakeValidMethod )
/**
* Feature request spatial filter types.
*