Skip to content
21 changes: 19 additions & 2 deletions python/PyQt6/analysis/auto_additions/qgsgeometrycheck.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,23 @@
QgsGeometryCheck.FeatureNodeCheck = QgsGeometryCheck.CheckType.FeatureNodeCheck
QgsGeometryCheck.FeatureCheck = QgsGeometryCheck.CheckType.FeatureCheck
QgsGeometryCheck.LayerCheck = QgsGeometryCheck.CheckType.LayerCheck
# monkey patching scoped based enum
QgsGeometryCheck.Result.Success.__doc__ = "Operation completed successfully"
QgsGeometryCheck.Result.Canceled.__doc__ = "User canceled calculation"
QgsGeometryCheck.Result.DuplicatedUniqueId.__doc__ = "Found duplicated unique ID value"
QgsGeometryCheck.Result.InvalidReferenceLayer.__doc__ = "Missed or invalid reference layer"
QgsGeometryCheck.Result.GeometryOverlayError.__doc__ = "Error performing geometry overlay operation"
QgsGeometryCheck.Result.__doc__ = """
.. versionadded:: 4.0

* ``Success``: Operation completed successfully
* ``Canceled``: User canceled calculation
* ``DuplicatedUniqueId``: Found duplicated unique ID value
* ``InvalidReferenceLayer``: Missed or invalid reference layer
* ``GeometryOverlayError``: Error performing geometry overlay operation

"""
# --
QgsGeometryCheck.AvailableInValidation = QgsGeometryCheck.Flag.AvailableInValidation
QgsGeometryCheck.Flags = lambda flags=0: QgsGeometryCheck.Flag(flags)
QgsGeometryCheck.Flags.baseClass = QgsGeometryCheck
Expand All @@ -23,8 +40,8 @@
except (NameError, AttributeError):
pass
try:
QgsGeometryCheck.__virtual_methods__ = ['prepare', 'isCompatible', 'flags', 'availableResolutionMethods', 'resolutionMethods']
QgsGeometryCheck.__abstract_methods__ = ['compatibleGeometryTypes', 'collectErrors', 'description', 'id', 'checkType']
QgsGeometryCheck.__virtual_methods__ = ['prepare', 'isCompatible', 'flags', 'collectErrors', 'availableResolutionMethods', 'resolutionMethods']
QgsGeometryCheck.__abstract_methods__ = ['compatibleGeometryTypes', 'description', 'id', 'checkType']
QgsGeometryCheck.__group__ = ['vector', 'geometry_checker']
except (NameError, AttributeError):
pass
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,15 @@ the system is aware of the available geometry checks.
LayerCheck
};

enum class Result /BaseType=IntEnum/
{
Success,
Canceled,
DuplicatedUniqueId,
InvalidReferenceLayer,
GeometryOverlayError
};

enum Flag /BaseType=IntEnum/
{
AvailableInValidation
Expand Down Expand Up @@ -193,14 +202,17 @@ A list of geometry types for which this check can be performed.
Flags for this geometry check.
%End

virtual void collectErrors( const QMap<QString, QgsFeaturePool *> &featurePools, QList<QgsGeometryCheckError *> &errors /In,Out/, QStringList &messages /In,Out/, QgsFeedback *feedback, const LayerFeatureIds &ids = QgsGeometryCheck::LayerFeatureIds() ) const = 0;
virtual Result collectErrors( const QMap<QString, QgsFeaturePool *> &featurePools, QList<QgsGeometryCheckError *> &errors /In,Out/, QStringList &messages /In,Out/, QgsFeedback *feedback, const LayerFeatureIds &ids = QgsGeometryCheck::LayerFeatureIds() ) const;
%Docstring
The main worker method. Check all features available from
``featurePools`` and write errors found to ``errors``. Other status
messages can be written to ``messages``. Progress should be reported to
``feedback``. Only features and layers listed in ``ids`` should be
checked.

:return: QgsGeometryCheck.Result.Success in case of success or error
value on failure.

.. versionadded:: 3.4
%End

Expand Down Expand Up @@ -257,6 +269,7 @@ Returns the context




};

/************************************************************************
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,20 @@ Base configuration for geometry checks.
#include "qgsgeometrycheckcontext.h"
%End
public:
QgsGeometryCheckContext( int precision, const QgsCoordinateReferenceSystem &mapCrs, const QgsCoordinateTransformContext &transformContext, const QgsProject *mProject );
QgsGeometryCheckContext( int precision, const QgsCoordinateReferenceSystem &mapCrs, const QgsCoordinateTransformContext &transformContext, const QgsProject *mProject = 0, const int uniqueIdFieldIndex = -1 );
%Docstring
Creates a new QgsGeometryCheckContext.

:param precision: The precision used to define gemetry check tolerance.
Tolerance is calculated as pow(10, -precision)
:param mapCrs: The coordinate system in which calculations should be
done
:param transformContext: The coordinate transform context
:param mProject: The project used to resolve additional layers
:param uniqueIdFieldIndex: The index of the unique ID field used to
identify features. If set to valid field
index, geometry checker will fail if this
field is not unique (since QGIS 4.0)
%End

const double tolerance;
Expand All @@ -37,6 +48,8 @@ Creates a new QgsGeometryCheckContext.

const QgsCoordinateTransformContext transformContext;

const int uniqueIdFieldIndex;

const QgsProject *project() const;
%Docstring
The project can be used to resolve additional layers.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ Subclasses need to implement the processGeometry method.
Creates a new single geometry check.
%End

virtual void collectErrors( const QMap<QString, QgsFeaturePool *> &featurePools, QList<QgsGeometryCheckError *> &errors, QStringList &messages, QgsFeedback *feedback = 0, const QgsGeometryCheck::LayerFeatureIds &ids = QgsGeometryCheck::LayerFeatureIds() ) const ${SIP_FINAL};
virtual QgsGeometryCheck::Result collectErrors( const QMap<QString, QgsFeaturePool *> &featurePools, QList<QgsGeometryCheckError *> &errors, QStringList &messages, QgsFeedback *feedback = 0, const QgsGeometryCheck::LayerFeatureIds &ids = QgsGeometryCheck::LayerFeatureIds() ) const ${SIP_FINAL};


virtual QList<QgsSingleGeometryCheckError *> processGeometry( const QgsGeometry &geometry ) const = 0;
Expand Down
21 changes: 19 additions & 2 deletions python/analysis/auto_additions/qgsgeometrycheck.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,21 @@
# The following has been generated automatically from src/analysis/vector/geometry_checker/qgsgeometrycheck.h
# monkey patching scoped based enum
QgsGeometryCheck.Result.Success.__doc__ = "Operation completed successfully"
QgsGeometryCheck.Result.Canceled.__doc__ = "User canceled calculation"
QgsGeometryCheck.Result.DuplicatedUniqueId.__doc__ = "Found duplicated unique ID value"
QgsGeometryCheck.Result.InvalidReferenceLayer.__doc__ = "Missed or invalid reference layer"
QgsGeometryCheck.Result.GeometryOverlayError.__doc__ = "Error performing geometry overlay operation"
QgsGeometryCheck.Result.__doc__ = """
.. versionadded:: 4.0

* ``Success``: Operation completed successfully
* ``Canceled``: User canceled calculation
* ``DuplicatedUniqueId``: Found duplicated unique ID value
* ``InvalidReferenceLayer``: Missed or invalid reference layer
* ``GeometryOverlayError``: Error performing geometry overlay operation

"""
# --
QgsGeometryCheck.Flags.baseClass = QgsGeometryCheck
Flags = QgsGeometryCheck # dirty hack since SIP seems to introduce the flags in module
try:
Expand All @@ -11,8 +28,8 @@
except (NameError, AttributeError):
pass
try:
QgsGeometryCheck.__virtual_methods__ = ['prepare', 'isCompatible', 'flags', 'availableResolutionMethods', 'resolutionMethods']
QgsGeometryCheck.__abstract_methods__ = ['compatibleGeometryTypes', 'collectErrors', 'description', 'id', 'checkType']
QgsGeometryCheck.__virtual_methods__ = ['prepare', 'isCompatible', 'flags', 'collectErrors', 'availableResolutionMethods', 'resolutionMethods']
QgsGeometryCheck.__abstract_methods__ = ['compatibleGeometryTypes', 'description', 'id', 'checkType']
QgsGeometryCheck.__group__ = ['vector', 'geometry_checker']
except (NameError, AttributeError):
pass
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,15 @@ the system is aware of the available geometry checks.
LayerCheck
};

enum class Result
{
Success,
Canceled,
DuplicatedUniqueId,
InvalidReferenceLayer,
GeometryOverlayError
};

enum Flag
{
AvailableInValidation
Expand Down Expand Up @@ -193,14 +202,17 @@ A list of geometry types for which this check can be performed.
Flags for this geometry check.
%End

virtual void collectErrors( const QMap<QString, QgsFeaturePool *> &featurePools, QList<QgsGeometryCheckError *> &errors /In,Out/, QStringList &messages /In,Out/, QgsFeedback *feedback, const LayerFeatureIds &ids = QgsGeometryCheck::LayerFeatureIds() ) const = 0;
virtual Result collectErrors( const QMap<QString, QgsFeaturePool *> &featurePools, QList<QgsGeometryCheckError *> &errors /In,Out/, QStringList &messages /In,Out/, QgsFeedback *feedback, const LayerFeatureIds &ids = QgsGeometryCheck::LayerFeatureIds() ) const;
%Docstring
The main worker method. Check all features available from
``featurePools`` and write errors found to ``errors``. Other status
messages can be written to ``messages``. Progress should be reported to
``feedback``. Only features and layers listed in ``ids`` should be
checked.

:return: QgsGeometryCheck.Result.Success in case of success or error
value on failure.

.. versionadded:: 3.4
%End

Expand Down Expand Up @@ -257,6 +269,7 @@ Returns the context




};

/************************************************************************
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,20 @@ Base configuration for geometry checks.
#include "qgsgeometrycheckcontext.h"
%End
public:
QgsGeometryCheckContext( int precision, const QgsCoordinateReferenceSystem &mapCrs, const QgsCoordinateTransformContext &transformContext, const QgsProject *mProject );
QgsGeometryCheckContext( int precision, const QgsCoordinateReferenceSystem &mapCrs, const QgsCoordinateTransformContext &transformContext, const QgsProject *mProject = 0, const int uniqueIdFieldIndex = -1 );
%Docstring
Creates a new QgsGeometryCheckContext.

:param precision: The precision used to define gemetry check tolerance.
Tolerance is calculated as pow(10, -precision)
:param mapCrs: The coordinate system in which calculations should be
done
:param transformContext: The coordinate transform context
:param mProject: The project used to resolve additional layers
:param uniqueIdFieldIndex: The index of the unique ID field used to
identify features. If set to valid field
index, geometry checker will fail if this
field is not unique (since QGIS 4.0)
%End

const double tolerance;
Expand All @@ -37,6 +48,8 @@ Creates a new QgsGeometryCheckContext.

const QgsCoordinateTransformContext transformContext;

const int uniqueIdFieldIndex;

const QgsProject *project() const;
%Docstring
The project can be used to resolve additional layers.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ Subclasses need to implement the processGeometry method.
Creates a new single geometry check.
%End

virtual void collectErrors( const QMap<QString, QgsFeaturePool *> &featurePools, QList<QgsGeometryCheckError *> &errors, QStringList &messages, QgsFeedback *feedback = 0, const QgsGeometryCheck::LayerFeatureIds &ids = QgsGeometryCheck::LayerFeatureIds() ) const ${SIP_FINAL};
virtual QgsGeometryCheck::Result collectErrors( const QMap<QString, QgsFeaturePool *> &featurePools, QList<QgsGeometryCheckError *> &errors, QStringList &messages, QgsFeedback *feedback = 0, const QgsGeometryCheck::LayerFeatureIds &ids = QgsGeometryCheck::LayerFeatureIds() ) const ${SIP_FINAL};


virtual QList<QgsSingleGeometryCheckError *> processGeometry( const QgsGeometry &geometry ) const = 0;
Expand Down
26 changes: 17 additions & 9 deletions src/analysis/processing/qgsalgorithmcheckgeometryangle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ QString QgsGeometryCheckAngleAlgorithm::shortHelpString() const

Qgis::ProcessingAlgorithmFlags QgsGeometryCheckAngleAlgorithm::flags() const
{
return QgsProcessingAlgorithm::flags() | Qgis::ProcessingAlgorithmFlag::NoThreading;
return QgsProcessingAlgorithm::flags() | Qgis::ProcessingAlgorithmFlag::NoThreading | Qgis::ProcessingAlgorithmFlag::RequiresProject;
}

QgsGeometryCheckAngleAlgorithm *QgsGeometryCheckAngleAlgorithm::createInstance() const
Expand All @@ -75,7 +75,6 @@ void QgsGeometryCheckAngleAlgorithm::initAlgorithm( const QVariantMap &configura
{
Q_UNUSED( configuration )

// inputs
addParameter(
new QgsProcessingParameterFeatureSource(
QStringLiteral( "INPUT" ), QObject::tr( "Input layer" ),
Expand All @@ -89,7 +88,6 @@ void QgsGeometryCheckAngleAlgorithm::initAlgorithm( const QVariantMap &configura
QStringLiteral( "MIN_ANGLE" ), QObject::tr( "Minimum angle (in degrees)" ), Qgis::ProcessingNumberParameterType::Double, 0, false, 0.0, 180.0
) );

// outputs
addParameter( new QgsProcessingParameterFeatureSink(
QStringLiteral( "ERRORS" ), QObject::tr( "Small angle errors" ), Qgis::ProcessingSourceType::VectorPoint
) );
Expand Down Expand Up @@ -131,8 +129,8 @@ QVariantMap QgsGeometryCheckAngleAlgorithm::processAlgorithm( const QVariantMap
if ( !input )
throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "INPUT" ) ) );

QString uniqueIdFieldName( parameterAsString( parameters, QStringLiteral( "UNIQUE_ID" ), context ) );
int uniqueIdFieldIdx = input->fields().indexFromName( uniqueIdFieldName );
const QString uniqueIdFieldName( parameterAsString( parameters, QStringLiteral( "UNIQUE_ID" ), context ) );
const int uniqueIdFieldIdx = input->fields().indexFromName( uniqueIdFieldName );
if ( uniqueIdFieldIdx == -1 )
throw QgsProcessingException( QObject::tr( "Missing field %1 in input layer" ).arg( uniqueIdFieldName ) );

Expand All @@ -149,9 +147,7 @@ QVariantMap QgsGeometryCheckAngleAlgorithm::processAlgorithm( const QVariantMap

QgsProcessingMultiStepFeedback multiStepFeedback( 3, feedback );

const QgsProject *project = QgsProject::instance();

QgsGeometryCheckContext checkContext = QgsGeometryCheckContext( mTolerance, input->sourceCrs(), project->transformContext(), project );
QgsGeometryCheckContext checkContext = QgsGeometryCheckContext( mTolerance, input->sourceCrs(), context.transformContext(), context.project(), uniqueIdFieldIdx );

// Test detection
QList<QgsGeometryCheckError *> checkErrors;
Expand All @@ -173,7 +169,19 @@ QVariantMap QgsGeometryCheckAngleAlgorithm::processAlgorithm( const QVariantMap

multiStepFeedback.setCurrentStep( 2 );
feedback->setProgressText( QObject::tr( "Collecting errors…" ) );
check.collectErrors( featurePools, checkErrors, messages, feedback );
QgsGeometryCheck::Result res = check.collectErrors( featurePools, checkErrors, messages, feedback );
if ( res == QgsGeometryCheck::Result::Success )
{
feedback->pushInfo( QObject::tr( "Errors collected successfully." ) );
}
else if ( res == QgsGeometryCheck::Result::Canceled )
{
throw QgsProcessingException( QObject::tr( "Operation was canceled." ) );
}
else if ( res == QgsGeometryCheck::Result::DuplicatedUniqueId )
{
throw QgsProcessingException( QObject::tr( "Field '%1' contains non-unique values and can not be used as unique ID." ).arg( uniqueIdFieldName ) );
}

multiStepFeedback.setCurrentStep( 3 );
feedback->setProgressText( QObject::tr( "Exporting errors…" ) );
Expand Down
26 changes: 17 additions & 9 deletions src/analysis/processing/qgsalgorithmcheckgeometryarea.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ QString QgsGeometryCheckAreaAlgorithm::shortHelpString() const

Qgis::ProcessingAlgorithmFlags QgsGeometryCheckAreaAlgorithm::flags() const
{
return QgsProcessingAlgorithm::flags() | Qgis::ProcessingAlgorithmFlag::NoThreading;
return QgsProcessingAlgorithm::flags() | Qgis::ProcessingAlgorithmFlag::NoThreading | Qgis::ProcessingAlgorithmFlag::RequiresProject;
}

QgsGeometryCheckAreaAlgorithm *QgsGeometryCheckAreaAlgorithm::createInstance() const
Expand All @@ -75,7 +75,6 @@ void QgsGeometryCheckAreaAlgorithm::initAlgorithm( const QVariantMap &configurat
{
Q_UNUSED( configuration )

// inputs
addParameter(
new QgsProcessingParameterFeatureSource(
QStringLiteral( "INPUT" ), QObject::tr( "Input layer" ),
Expand All @@ -89,7 +88,6 @@ void QgsGeometryCheckAreaAlgorithm::initAlgorithm( const QVariantMap &configurat
QStringLiteral( "AREATHRESHOLD" ), QObject::tr( "Area threshold" ), 0, QStringLiteral( "INPUT" )
) );

// outputs
addParameter( new QgsProcessingParameterFeatureSink(
QStringLiteral( "ERRORS" ), QObject::tr( "Small polygons errors" ), Qgis::ProcessingSourceType::VectorPoint
) );
Expand Down Expand Up @@ -134,8 +132,8 @@ QVariantMap QgsGeometryCheckAreaAlgorithm::processAlgorithm( const QVariantMap &
if ( !input )
throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "INPUT" ) ) );

QString uniqueIdFieldName( parameterAsString( parameters, QStringLiteral( "UNIQUE_ID" ), context ) );
int uniqueIdFieldIdx = input->fields().indexFromName( uniqueIdFieldName );
const QString uniqueIdFieldName( parameterAsString( parameters, QStringLiteral( "UNIQUE_ID" ), context ) );
const int uniqueIdFieldIdx = input->fields().indexFromName( uniqueIdFieldName );
if ( uniqueIdFieldIdx == -1 )
throw QgsProcessingException( QObject::tr( "Missing field %1 in input layer" ).arg( uniqueIdFieldName ) );

Expand All @@ -156,9 +154,7 @@ QVariantMap QgsGeometryCheckAreaAlgorithm::processAlgorithm( const QVariantMap &

QgsProcessingMultiStepFeedback multiStepFeedback( 3, feedback );

QgsProject *project = QgsProject::instance();

QgsGeometryCheckContext checkContext = QgsGeometryCheckContext( mTolerance, input->sourceCrs(), project->transformContext(), project );
QgsGeometryCheckContext checkContext = QgsGeometryCheckContext( mTolerance, input->sourceCrs(), context.transformContext(), context.project(), uniqueIdFieldIdx );

// Test detection
QList<QgsGeometryCheckError *> checkErrors;
Expand All @@ -180,7 +176,19 @@ QVariantMap QgsGeometryCheckAreaAlgorithm::processAlgorithm( const QVariantMap &

multiStepFeedback.setCurrentStep( 2 );
feedback->setProgressText( QObject::tr( "Collecting errors…" ) );
check.collectErrors( featurePools, checkErrors, messages, feedback );
QgsGeometryCheck::Result res = check.collectErrors( featurePools, checkErrors, messages, feedback );
if ( res == QgsGeometryCheck::Result::Success )
{
feedback->pushInfo( QObject::tr( "Errors collected successfully." ) );
}
else if ( res == QgsGeometryCheck::Result::Canceled )
{
throw QgsProcessingException( QObject::tr( "Operation was canceled." ) );
}
else if ( res == QgsGeometryCheck::Result::DuplicatedUniqueId )
{
throw QgsProcessingException( QObject::tr( "Field '%1' contains non-unique values and can not be used as unique ID." ).arg( uniqueIdFieldName ) );
}

multiStepFeedback.setCurrentStep( 3 );
feedback->setProgressText( QObject::tr( "Exporting errors…" ) );
Expand Down
Loading
Loading