Skip to content
Permalink
Browse files
Allow setting the invalid geometry callback in processing context
  • Loading branch information
nyalldawson committed Apr 26, 2017
1 parent b32b395 commit e6a33e876c96774d4309ec4f028eb7c2103e2ca7
@@ -85,6 +85,29 @@ class QgsProcessingContext
\see invalidGeometryCheck()
%End


void setInvalidGeometryCallback( SIP_PYCALLABLE / AllowNone / );
%Docstring
Sets a callback function to use when encountering an invalid geometry and
invalidGeometryCheck() is set to GeometryAbortOnInvalid. This function will be
called using the feature with invalid geometry as a parameter.
.. versionadded:: 3.0
\see invalidGeometryCallback()
%End
%MethodCode
Py_BEGIN_ALLOW_THREADS

sipCpp->setInvalidGeometryCallback( [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


};
QFlags<QgsProcessingContext::Flag> operator|(QgsProcessingContext::Flag f1, QFlags<QgsProcessingContext::Flag> f2);

@@ -93,12 +93,48 @@ class CORE_EXPORT QgsProcessingContext
*/
void setInvalidGeometryCheck( const QgsFeatureRequest::InvalidGeometryCheck &check ) { mInvalidGeometryCheck = check; }


/**
* Sets a callback function to use when encountering an invalid geometry and
* invalidGeometryCheck() is set to GeometryAbortOnInvalid. This function will be
* called using the feature with invalid geometry as a parameter.
* \since QGIS 3.0
* \see invalidGeometryCallback()
*/
#ifndef SIP_RUN
void setInvalidGeometryCallback( std::function< void( const QgsFeature & ) > callback ) { mInvalidGeometryCallback = callback; }
#else
void setInvalidGeometryCallback( SIP_PYCALLABLE / AllowNone / );
% MethodCode
Py_BEGIN_ALLOW_THREADS

sipCpp->setInvalidGeometryCallback( [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 an invalid geometry and
* invalidGeometryCheck() is set to GeometryAbortOnInvalid.
* \since QGIS 3.0
* \note not available in Python bindings
* \see setInvalidGeometryCallback()
*/
SIP_SKIP std::function< void( const QgsFeature & ) > invalidGeometryCallback() const { return mInvalidGeometryCallback; }

private:

QgsProcessingContext::Flags mFlags = 0;
QPointer< QgsProject > mProject;
QgsExpressionContext mExpressionContext;
QgsFeatureRequest::InvalidGeometryCheck mInvalidGeometryCheck = QgsFeatureRequest::GeometryNoCheck;
std::function< void( const QgsFeature & ) > mInvalidGeometryCallback;

};
Q_DECLARE_OPERATORS_FOR_FLAGS( QgsProcessingContext::Flags )
@@ -179,6 +179,7 @@ QgsFeatureIterator QgsProcessingUtils::getFeatures( QgsVectorLayer *layer, const

QgsFeatureRequest req( request );
req.setInvalidGeometryCheck( context.invalidGeometryCheck() );
req.setInvalidGeometryCallback( context.invalidGeometryCallback() );
if ( useSelection )
{
return layer->selectedFeaturesIterator( req );
@@ -501,12 +501,31 @@ void TestQgsProcessing::features()
ids = getIds( QgsProcessingUtils::getFeatures( layer, context, QgsFeatureRequest().setFlags( QgsFeatureRequest::NoGeometry ) ) );
QCOMPARE( ids, QgsFeatureIds() << 2 << 4 );

#if 0
// test exception is raised when filtering invalid geoms
context.setInvalidGeometryCheck( QgsFeatureRequest.GeometryAbortOnInvalid )
#endif
// test callback is hit when filtering invalid geoms
bool encountered = false;
std::function< void( const QgsFeature & ) > callback = [ &encountered ]( const QgsFeature & )
{
encountered = true;
};

context.setFlags( QgsProcessingContext::Flags( 0 ) );
context.setInvalidGeometryCheck( QgsFeatureRequest::GeometryAbortOnInvalid );
context.setInvalidGeometryCallback( callback );
QgsVectorLayer *polyLayer = new QgsVectorLayer( "Polygon", "v2", "memory" );
QgsFeature f;
f.setGeometry( QgsGeometry::fromWkt( QStringLiteral( "Polygon((0 0, 1 0, 0 1, 1 1, 0 0))" ) ) );
polyLayer->dataProvider()->addFeatures( QgsFeatureList() << f );

ids = getIds( QgsProcessingUtils::getFeatures( polyLayer, context ) );
QVERIFY( encountered );

encountered = false;
context.setInvalidGeometryCheck( QgsFeatureRequest::GeometryNoCheck );
ids = getIds( QgsProcessingUtils::getFeatures( polyLayer, context ) );
QVERIFY( !encountered );

delete layer;
delete polyLayer;
}

QGSTEST_MAIN( TestQgsProcessing )

0 comments on commit e6a33e8

Please sign in to comment.