diff --git a/python/core/processing/qgsprocessingcontext.sip b/python/core/processing/qgsprocessingcontext.sip index f2ba49a06b4..9c2feb3b655 100644 --- a/python/core/processing/qgsprocessingcontext.sip +++ b/python/core/processing/qgsprocessingcontext.sip @@ -163,6 +163,28 @@ Destination project %End + void setTransformErrorCallback( SIP_PYCALLABLE / AllowNone / ); +%Docstring + Sets a callback function to use when encountering a transform error when iterating + features. This function will be + called using the feature which encountered the transform error as a parameter. +.. versionadded:: 3.0 +.. seealso:: transformErrorCallback() +%End +%MethodCode + Py_BEGIN_ALLOW_THREADS + + sipCpp->setTransformErrorCallback( [a0]( const QgsFeature &arg ) + { + SIP_BLOCK_THREADS + Py_XDECREF( sipCallMethod( NULL, a0, "D", &arg, sipType_QgsFeature, NULL ) ); + SIP_UNBLOCK_THREADS + } ); + + Py_END_ALLOW_THREADS +%End + + QString defaultEncoding() const; %Docstring Returns the default encoding to use for newly created files. diff --git a/python/plugins/processing/tools/dataobjects.py b/python/plugins/processing/tools/dataobjects.py index 28da6d1331a..241bdc318b5 100644 --- a/python/plugins/processing/tools/dataobjects.py +++ b/python/plugins/processing/tools/dataobjects.py @@ -85,6 +85,11 @@ def createContext(): context.setInvalidGeometryCallback(raise_error) + def raise_transform_error(f): + raise GeoAlgorithmExecutionException(QCoreApplication.translate("FeatureIterator", + 'Encountered a transform error when reprojecting feature with id {}.'.format(f.id()))) + context.setTransformErrorCallback(raise_transform_error) + settings = QgsSettings() context.setDefaultEncoding(settings.value("/Processing/encoding", "System")) diff --git a/src/core/processing/qgsprocessingcontext.h b/src/core/processing/qgsprocessingcontext.h index 0b65b314eff..ddcbc365d56 100644 --- a/src/core/processing/qgsprocessingcontext.h +++ b/src/core/processing/qgsprocessingcontext.h @@ -206,6 +206,41 @@ class CORE_EXPORT QgsProcessingContext */ SIP_SKIP std::function< void( const QgsFeature & ) > invalidGeometryCallback() const { return mInvalidGeometryCallback; } + /** + * Sets a callback function to use when encountering a transform error when iterating + * features. This function will be + * called using the feature which encountered the transform error as a parameter. + * \since QGIS 3.0 + * \see transformErrorCallback() + */ +#ifndef SIP_RUN + void setTransformErrorCallback( std::function< void( const QgsFeature & ) > callback ) { mTransformErrorCallback = callback; } +#else + void setTransformErrorCallback( SIP_PYCALLABLE / AllowNone / ); + % MethodCode + Py_BEGIN_ALLOW_THREADS + + sipCpp->setTransformErrorCallback( [a0]( const QgsFeature &arg ) + { + SIP_BLOCK_THREADS + Py_XDECREF( sipCallMethod( NULL, a0, "D", &arg, sipType_QgsFeature, NULL ) ); + SIP_UNBLOCK_THREADS + } ); + + Py_END_ALLOW_THREADS + % End +#endif + + /** + * Returns the callback function to use when encountering a transform error when iterating + * features. + * \since QGIS 3.0 + * \note not available in Python bindings + * \see setTransformErrorCallback() + * \see destinationCrs() + */ + std::function< void( const QgsFeature & ) > transformErrorCallback() const { return mTransformErrorCallback; } SIP_SKIP + /** * Returns the default encoding to use for newly created files. * \see setDefaultEncoding() @@ -228,6 +263,7 @@ class CORE_EXPORT QgsProcessingContext QgsExpressionContext mExpressionContext; QgsFeatureRequest::InvalidGeometryCheck mInvalidGeometryCheck = QgsFeatureRequest::GeometryNoCheck; std::function< void( const QgsFeature & ) > mInvalidGeometryCallback; + std::function< void( const QgsFeature & ) > mTransformErrorCallback; QString mDefaultEncoding; QMap< QString, LayerDetails > mLayersToLoadOnCompletion; diff --git a/src/core/processing/qgsprocessingutils.cpp b/src/core/processing/qgsprocessingutils.cpp index ad4e6d58f4a..93cf956fdad 100644 --- a/src/core/processing/qgsprocessingutils.cpp +++ b/src/core/processing/qgsprocessingutils.cpp @@ -375,6 +375,7 @@ QgsProcessingFeatureSource::QgsProcessingFeatureSource( QgsFeatureSource *origin , mOwnsSource( ownsOriginalSource ) , mInvalidGeometryCheck( context.invalidGeometryCheck() ) , mInvalidGeometryCallback( context.invalidGeometryCallback() ) + , mTransformErrorCallback( context.transformErrorCallback() ) {} QgsProcessingFeatureSource::~QgsProcessingFeatureSource() @@ -388,6 +389,7 @@ QgsFeatureIterator QgsProcessingFeatureSource::getFeatures( const QgsFeatureRequ QgsFeatureRequest req( request ); req.setInvalidGeometryCheck( mInvalidGeometryCheck ); req.setInvalidGeometryCallback( mInvalidGeometryCallback ); + req.setTransformErrorCallback( mTransformErrorCallback ); return mSource->getFeatures( req ); } diff --git a/src/core/processing/qgsprocessingutils.h b/src/core/processing/qgsprocessingutils.h index 3324926aa92..2281fe1f71d 100644 --- a/src/core/processing/qgsprocessingutils.h +++ b/src/core/processing/qgsprocessingutils.h @@ -228,6 +228,7 @@ class QgsProcessingFeatureSource : public QgsFeatureSource bool mOwnsSource = false; QgsFeatureRequest::InvalidGeometryCheck mInvalidGeometryCheck = QgsFeatureRequest::GeometryNoCheck; std::function< void( const QgsFeature & ) > mInvalidGeometryCallback; + std::function< void( const QgsFeature & ) > mTransformErrorCallback; };