Skip to content

Commit

Permalink
[processing] Hookup backend API allowing features sources to be
Browse files Browse the repository at this point in the history
limited to a specific maximum number of features, and allowing
per-source overriding of the default "invalid geometry" handling behavior
  • Loading branch information
nyalldawson committed Mar 24, 2020
1 parent 24cf1ca commit b0474d7
Show file tree
Hide file tree
Showing 9 changed files with 373 additions and 37 deletions.
Expand Up @@ -25,20 +25,44 @@ Encapsulates settings relating to a feature source input to a processing algorit
%End
public:

QgsProcessingFeatureSourceDefinition( const QString &source = QString(), bool selectedFeaturesOnly = false );
QgsProcessingFeatureSourceDefinition( const QString &source = QString(), bool selectedFeaturesOnly = false, long long featureLimit = -1,
bool overrideDefaultGeometryCheck = false, QgsFeatureRequest::InvalidGeometryCheck geometryCheck = QgsFeatureRequest::GeometryAbortOnInvalid );
%Docstring
Constructor for QgsProcessingFeatureSourceDefinition, accepting a static string source.
Constructor for QgsProcessingFeatureSourceDefinition, accepting a static string ``source``.

If ``selectedFeaturesOnly`` is ``True``, then only selected features from the source will be used.

The optional ``featureLimit`` can be set to a value > 0 to place a hard limit on the maximum number
of features which will be read from the source.

If ``overrideDefaultGeometryCheck`` is ``True``, then the value of ``geometryCheck`` will override
the default geometry check method (as dictated by :py:class:`QgsProcessingContext`) for this source.
%End

QgsProcessingFeatureSourceDefinition( const QgsProperty &source, bool selectedFeaturesOnly = false );
QgsProcessingFeatureSourceDefinition( const QgsProperty &source, bool selectedFeaturesOnly = false, long long featureLimit = -1,
bool overrideDefaultGeometryCheck = false, QgsFeatureRequest::InvalidGeometryCheck geometryCheck = QgsFeatureRequest::GeometryAbortOnInvalid );
%Docstring
Constructor for QgsProcessingFeatureSourceDefinition, accepting a QgsProperty source.

If ``selectedFeaturesOnly`` is ``True``, then only selected features from the source will be used.

The optional ``featureLimit`` can be set to a value > 0 to place a hard limit on the maximum number
of features which will be read from the source.

If ``overrideDefaultGeometryCheck`` is ``True``, then the value of ``geometryCheck`` will override
the default geometry check method (as dictated by :py:class:`QgsProcessingContext`) for this source.
%End

QgsProperty source;

bool selectedFeaturesOnly;

long long featureLimit;

bool overrideDefaultGeometryCheck;

QgsFeatureRequest::InvalidGeometryCheck geometryCheck;

bool operator==( const QgsProcessingFeatureSourceDefinition &other );

bool operator!=( const QgsProcessingFeatureSourceDefinition &other );
Expand Down
13 changes: 12 additions & 1 deletion python/core/auto_generated/processing/qgsprocessingutils.sip.in
Expand Up @@ -379,13 +379,17 @@ results according to the settings in a :py:class:`QgsProcessingContext`.
typedef QFlags<QgsProcessingFeatureSource::Flag> Flags;


QgsProcessingFeatureSource( QgsFeatureSource *originalSource, const QgsProcessingContext &context, bool ownsOriginalSource = false );
QgsProcessingFeatureSource( QgsFeatureSource *originalSource, const QgsProcessingContext &context, bool ownsOriginalSource = false,
long long featureLimit = -1 );
%Docstring
Constructor for QgsProcessingFeatureSource, accepting an original feature source ``originalSource``
and processing ``context``.
Ownership of ``originalSource`` is dictated by ``ownsOriginalSource``. If ``ownsOriginalSource`` is ``False``,
ownership is not transferred, and callers must ensure that ``originalSource`` exists for the lifetime of this object.
If ``ownsOriginalSource`` is ``True``, then this object will take ownership of ``originalSource``.

If ``featureLimit`` is set to a value > 0, then a limit is placed on the maximum number of features which will be
read from the source.
%End

~QgsProcessingFeatureSource();
Expand Down Expand Up @@ -428,6 +432,13 @@ iterator, eg by restricting the returned attributes or geometry.
QgsExpressionContextScope *createExpressionContextScope() const /Factory/;
%Docstring
Returns an expression context scope suitable for this source.
%End

void setInvalidGeometryCheck( QgsFeatureRequest::InvalidGeometryCheck method );
%Docstring
Overrides the default geometry check method for the source.

.. versionadded:: 3.14
%End

};
Expand Down
47 changes: 37 additions & 10 deletions src/core/processing/qgsprocessingparameters.cpp
Expand Up @@ -615,11 +615,13 @@ QString parameterAsCompatibleSourceLayerPathInternal( const QgsProcessingParamet
QVariant val = parameters.value( definition->name() );

bool selectedFeaturesOnly = false;
long long featureLimit = -1;
if ( val.canConvert<QgsProcessingFeatureSourceDefinition>() )
{
// input is a QgsProcessingFeatureSourceDefinition - get extra properties from it
QgsProcessingFeatureSourceDefinition fromVar = qvariant_cast<QgsProcessingFeatureSourceDefinition>( val );
selectedFeaturesOnly = fromVar.selectedFeaturesOnly;
featureLimit = fromVar.featureLimit;
val = fromVar.source;
}
else if ( val.canConvert<QgsProcessingOutputLayerDefinition>() )
Expand Down Expand Up @@ -673,10 +675,10 @@ QString parameterAsCompatibleSourceLayerPathInternal( const QgsProcessingParamet

if ( layerName )
return QgsProcessingUtils::convertToCompatibleFormatAndLayerName( vl, selectedFeaturesOnly, definition->name(),
compatibleFormats, preferredFormat, context, feedback, *layerName );
compatibleFormats, preferredFormat, context, feedback, *layerName, featureLimit );
else
return QgsProcessingUtils::convertToCompatibleFormat( vl, selectedFeaturesOnly, definition->name(),
compatibleFormats, preferredFormat, context, feedback );
compatibleFormats, preferredFormat, context, feedback, featureLimit );
}

QString QgsProcessingParameters::parameterAsCompatibleSourceLayerPath( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context, const QStringList &compatibleFormats, const QString &preferredFormat, QgsProcessingFeedback *feedback )
Expand Down Expand Up @@ -4624,26 +4626,51 @@ QString QgsProcessingParameterFeatureSource::valueAsPythonString( const QVariant
if ( value.canConvert<QgsProcessingFeatureSourceDefinition>() )
{
QgsProcessingFeatureSourceDefinition fromVar = qvariant_cast<QgsProcessingFeatureSourceDefinition>( value );
QString geometryCheckString;
switch ( fromVar.geometryCheck )
{
case QgsFeatureRequest::GeometryNoCheck:
geometryCheckString = QStringLiteral( "QgsFeatureRequest.GeometryNoCheck" );
break;

case QgsFeatureRequest::GeometrySkipInvalid:
geometryCheckString = QStringLiteral( "QgsFeatureRequest.GeometrySkipInvalid" );
break;

case QgsFeatureRequest::GeometryAbortOnInvalid:
geometryCheckString = QStringLiteral( "QgsFeatureRequest.GeometryAbortOnInvalid" );
break;
}
if ( fromVar.source.propertyType() == QgsProperty::StaticProperty )
{
if ( fromVar.selectedFeaturesOnly )
QString layerString = fromVar.source.staticValue().toString();
// prefer to use layer source instead of id if possible (since it's persistent)
if ( QgsVectorLayer *layer = qobject_cast< QgsVectorLayer * >( QgsProcessingUtils::mapLayerFromString( layerString, context, true, QgsProcessingUtils::LayerHint::Vector ) ) )
layerString = layer->source();

if ( fromVar.selectedFeaturesOnly || fromVar.featureLimit != -1 || fromVar.overrideDefaultGeometryCheck )
{
return QStringLiteral( "QgsProcessingFeatureSourceDefinition('%1', True)" ).arg( fromVar.source.staticValue().toString() );
return QStringLiteral( "QgsProcessingFeatureSourceDefinition('%1', selectedFeaturesOnly=%2, featureLimit=%3, overrideDefaultGeometryCheck=%4, geometryCheck=%5)" ).arg( layerString,
fromVar.selectedFeaturesOnly ? QStringLiteral( "True" ) : QStringLiteral( "False" ),
QString::number( fromVar.featureLimit ),
fromVar.overrideDefaultGeometryCheck ? QStringLiteral( "True" ) : QStringLiteral( "False" ),
geometryCheckString );
}
else
{
QString layerString = fromVar.source.staticValue().toString();
// prefer to use layer source instead of id if possible (since it's persistent)
if ( QgsVectorLayer *layer = qobject_cast< QgsVectorLayer * >( QgsProcessingUtils::mapLayerFromString( layerString, context, true, QgsProcessingUtils::LayerHint::Vector ) ) )
layerString = layer->source();
return QgsProcessingUtils::stringToPythonLiteral( layerString );
}
}
else
{
if ( fromVar.selectedFeaturesOnly )
if ( fromVar.selectedFeaturesOnly || fromVar.featureLimit != -1 || fromVar.overrideDefaultGeometryCheck )
{
return QStringLiteral( "QgsProcessingFeatureSourceDefinition(QgsProperty.fromExpression('%1'), True)" ).arg( fromVar.source.asExpression() );
return QStringLiteral( "QgsProcessingFeatureSourceDefinition(QgsProperty.fromExpression('%1'), selectedFeaturesOnly=%2, featureLimit=%3, overrideDefaultGeometryCheck=%4, geometryCheck=%5)" )
.arg( fromVar.source.asExpression(),
fromVar.selectedFeaturesOnly ? QStringLiteral( "True" ) : QStringLiteral( "False" ),
QString::number( fromVar.featureLimit ),
fromVar.overrideDefaultGeometryCheck ? QStringLiteral( "True" ) : QStringLiteral( "False" ),
geometryCheckString );
}
else
{
Expand Down
62 changes: 58 additions & 4 deletions src/core/processing/qgsprocessingparameters.h
Expand Up @@ -56,19 +56,43 @@ class CORE_EXPORT QgsProcessingFeatureSourceDefinition
public:

/**
* Constructor for QgsProcessingFeatureSourceDefinition, accepting a static string source.
* Constructor for QgsProcessingFeatureSourceDefinition, accepting a static string \a source.
*
* If \a selectedFeaturesOnly is TRUE, then only selected features from the source will be used.
*
* The optional \a featureLimit can be set to a value > 0 to place a hard limit on the maximum number
* of features which will be read from the source.
*
* If \a overrideDefaultGeometryCheck is TRUE, then the value of \a geometryCheck will override
* the default geometry check method (as dictated by QgsProcessingContext) for this source.
*/
QgsProcessingFeatureSourceDefinition( const QString &source = QString(), bool selectedFeaturesOnly = false )
QgsProcessingFeatureSourceDefinition( const QString &source = QString(), bool selectedFeaturesOnly = false, long long featureLimit = -1,
bool overrideDefaultGeometryCheck = false, QgsFeatureRequest::InvalidGeometryCheck geometryCheck = QgsFeatureRequest::GeometryAbortOnInvalid )
: source( QgsProperty::fromValue( source ) )
, selectedFeaturesOnly( selectedFeaturesOnly )
, featureLimit( featureLimit )
, overrideDefaultGeometryCheck( overrideDefaultGeometryCheck )
, geometryCheck( geometryCheck )
{}

/**
* Constructor for QgsProcessingFeatureSourceDefinition, accepting a QgsProperty source.
*
* If \a selectedFeaturesOnly is TRUE, then only selected features from the source will be used.
*
* The optional \a featureLimit can be set to a value > 0 to place a hard limit on the maximum number
* of features which will be read from the source.
*
* If \a overrideDefaultGeometryCheck is TRUE, then the value of \a geometryCheck will override
* the default geometry check method (as dictated by QgsProcessingContext) for this source.
*/
QgsProcessingFeatureSourceDefinition( const QgsProperty &source, bool selectedFeaturesOnly = false )
QgsProcessingFeatureSourceDefinition( const QgsProperty &source, bool selectedFeaturesOnly = false, long long featureLimit = -1,
bool overrideDefaultGeometryCheck = false, QgsFeatureRequest::InvalidGeometryCheck geometryCheck = QgsFeatureRequest::GeometryAbortOnInvalid )
: source( source )
, selectedFeaturesOnly( selectedFeaturesOnly )
, featureLimit( featureLimit )
, overrideDefaultGeometryCheck( overrideDefaultGeometryCheck )
, geometryCheck( geometryCheck )
{}

/**
Expand All @@ -81,9 +105,39 @@ class CORE_EXPORT QgsProcessingFeatureSourceDefinition
*/
bool selectedFeaturesOnly;

/**
* If set to a value > 0, places a limit on the maximum number of features which will be
* read from the source.
*
* \since QGIS 3.14
*/
long long featureLimit = -1;

/**
* TRUE if the default geometry check method (as dictated by QgsProcessingContext)
* should be overridden for this source.
*
* \see geometryCheck
* \since QGIS 3.14
*/
bool overrideDefaultGeometryCheck = false;

/**
* Geometry check method to apply to this source. This setting is only
* utilised if QgsProcessingFeatureSourceDefinition::overrideDefaultGeometryCheck is TRUE.
*
* \see overrideDefaultGeometryCheck
* \since QGIS 3.14
*/
QgsFeatureRequest::InvalidGeometryCheck geometryCheck = QgsFeatureRequest::GeometryAbortOnInvalid;

bool operator==( const QgsProcessingFeatureSourceDefinition &other )
{
return source == other.source && selectedFeaturesOnly == other.selectedFeaturesOnly;
return source == other.source
&& selectedFeaturesOnly == other.selectedFeaturesOnly
&& featureLimit == other.featureLimit
&& overrideDefaultGeometryCheck == other.overrideDefaultGeometryCheck
&& geometryCheck == other.geometryCheck;
}

bool operator!=( const QgsProcessingFeatureSourceDefinition &other )
Expand Down

0 comments on commit b0474d7

Please sign in to comment.