Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Fix loss of callback when invalid geometry handling method is set thr…
…ough

source definition
  • Loading branch information
nyalldawson committed Mar 24, 2020
1 parent afbe727 commit 488c8c7
Show file tree
Hide file tree
Showing 6 changed files with 52 additions and 7 deletions.
Expand Up @@ -290,6 +290,7 @@ called using the feature with invalid geometry as a parameter.
%End



void setTransformErrorCallback( SIP_PYCALLABLE / AllowNone / );
%Docstring
Sets a callback function to use when encountering a transform error when iterating
Expand Down
17 changes: 10 additions & 7 deletions src/core/processing/qgsprocessingcontext.cpp
Expand Up @@ -61,17 +61,20 @@ void QgsProcessingContext::addLayerToLoadOnCompletion( const QString &layer, con
void QgsProcessingContext::setInvalidGeometryCheck( QgsFeatureRequest::InvalidGeometryCheck check )
{
mInvalidGeometryCheck = check;
mInvalidGeometryCallback = defaultInvalidGeometryCallbackForCheck( check );
}

switch ( mInvalidGeometryCheck )
std::function<void ( const QgsFeature & )> QgsProcessingContext::defaultInvalidGeometryCallbackForCheck( QgsFeatureRequest::InvalidGeometryCheck check ) const
{
switch ( check )
{
case QgsFeatureRequest::GeometryAbortOnInvalid:
{
auto callback = []( const QgsFeature & feature )
{
throw QgsProcessingException( QObject::tr( "Feature (%1) has invalid geometry. Please fix the geometry or change the Processing setting to the \"Ignore invalid input features\" option." ).arg( feature.id() ) );
};
mInvalidGeometryCallback = callback;
break;
return callback;
}

case QgsFeatureRequest::GeometrySkipInvalid:
Expand All @@ -81,13 +84,13 @@ void QgsProcessingContext::setInvalidGeometryCheck( QgsFeatureRequest::InvalidGe
if ( mFeedback )
mFeedback->reportError( QObject::tr( "Feature (%1) has invalid geometry and has been skipped. Please fix the geometry or change the Processing setting to the \"Ignore invalid input features\" option." ).arg( feature.id() ) );
};
mInvalidGeometryCallback = callback;
break;
return callback;
}

default:
break;
case QgsFeatureRequest::GeometryNoCheck:
return nullptr;
}
return nullptr;
}

void QgsProcessingContext::takeResultsFrom( QgsProcessingContext &context )
Expand Down
7 changes: 7 additions & 0 deletions src/core/processing/qgsprocessingcontext.h
Expand Up @@ -337,6 +337,13 @@ class CORE_EXPORT QgsProcessingContext
*/
SIP_SKIP std::function< void( const QgsFeature & ) > invalidGeometryCallback() const { return mInvalidGeometryCallback; }

/**
* Returns the default callback function to use for a particular invalid geometry \a check
* \note not available in Python bindings
* \since QGIS 3.14
*/
SIP_SKIP std::function< void( const QgsFeature & ) > defaultInvalidGeometryCallbackForCheck( QgsFeatureRequest::InvalidGeometryCheck check ) const;

/**
* Sets a callback function to use when encountering a transform error when iterating
* features. This function will be
Expand Down
17 changes: 17 additions & 0 deletions src/core/processing/qgsprocessingutils.cpp
Expand Up @@ -1061,6 +1061,8 @@ QgsProcessingFeatureSource::QgsProcessingFeatureSource( QgsFeatureSource *origin
: context.invalidGeometryCheck() )
, mInvalidGeometryCallback( context.invalidGeometryCallback() )
, mTransformErrorCallback( context.transformErrorCallback() )
, mInvalidGeometryCallbackSkip( context.defaultInvalidGeometryCallbackForCheck( QgsFeatureRequest::GeometrySkipInvalid ) )
, mInvalidGeometryCallbackAbort( context.defaultInvalidGeometryCallbackForCheck( QgsFeatureRequest::GeometryAbortOnInvalid ) )
, mFeatureLimit( featureLimit )
{}

Expand Down Expand Up @@ -1191,6 +1193,21 @@ QgsExpressionContextScope *QgsProcessingFeatureSource::createExpressionContextSc
void QgsProcessingFeatureSource::setInvalidGeometryCheck( QgsFeatureRequest::InvalidGeometryCheck method )
{
mInvalidGeometryCheck = method;
switch ( mInvalidGeometryCheck )
{
case QgsFeatureRequest::GeometryNoCheck:
mInvalidGeometryCallback = nullptr;
break;

case QgsFeatureRequest::GeometrySkipInvalid:
mInvalidGeometryCallback = mInvalidGeometryCallbackSkip;
break;

case QgsFeatureRequest::GeometryAbortOnInvalid:
mInvalidGeometryCallback = mInvalidGeometryCallbackAbort;
break;

}
}


Expand Down
4 changes: 4 additions & 0 deletions src/core/processing/qgsprocessingutils.h
Expand Up @@ -506,6 +506,10 @@ class CORE_EXPORT QgsProcessingFeatureSource : public QgsFeatureSource
QgsFeatureRequest::InvalidGeometryCheck mInvalidGeometryCheck = QgsFeatureRequest::GeometryNoCheck;
std::function< void( const QgsFeature & ) > mInvalidGeometryCallback;
std::function< void( const QgsFeature & ) > mTransformErrorCallback;

std::function< void( const QgsFeature & ) > mInvalidGeometryCallbackSkip;
std::function< void( const QgsFeature & ) > mInvalidGeometryCallbackAbort;

long long mFeatureLimit = -1;

};
Expand Down
13 changes: 13 additions & 0 deletions tests/src/analysis/testqgsprocessing.cpp
Expand Up @@ -1418,6 +1418,19 @@ void TestQgsProcessing::features()
ids = getIds( source->getFeatures() );
QVERIFY( !encountered );

QgsProcessingContext context2;
// context wants to skip, source wants to abort
context2.setInvalidGeometryCheck( QgsFeatureRequest::GeometrySkipInvalid );
params.insert( QStringLiteral( "layer" ), QVariant::fromValue( QgsProcessingFeatureSourceDefinition( polyLayer->id(), false, -1, QgsProcessingFeatureSourceDefinition::Flag::FlagOverrideDefaultGeometryCheck, QgsFeatureRequest::GeometryAbortOnInvalid ) ) );
source.reset( QgsProcessingParameters::parameterAsSource( def.get(), params, context ) );
try
{
ids = getIds( source->getFeatures() );
QVERIFY( false );
}
catch ( QgsProcessingException & )
{}

// equality operator
QVERIFY( QgsProcessingFeatureSourceDefinition( layer->id(), true ) == QgsProcessingFeatureSourceDefinition( layer->id(), true ) );
QVERIFY( QgsProcessingFeatureSourceDefinition( layer->id(), true ) != QgsProcessingFeatureSourceDefinition( "b", true ) );
Expand Down

0 comments on commit 488c8c7

Please sign in to comment.