mirror of
https://github.com/qgis/QGIS.git
synced 2025-06-19 00:02:48 -04:00
Add QgsProcessingFeatureBasedAlgorithm subclass
An abstract QgsProcessingAlgorithm base class for processing algorithms which operate "feature-by-feature". Feature based algorithms are algorithms which operate on individual features in isolation. These are algorithms where one feature is output for each input feature, and the output feature result for each input feature is not dependent on any other features present in the source. For instance, algorithms like "centroids" and "buffers" are feature based algorithms since the centroid or buffer of a feature is calculated for each feature in isolation. An algorithm like "dissolve" is NOT suitable for a feature based algorithm as the dissolved output depends on multiple input features and these features cannot be processed in isolation. Using QgsProcessingFeatureBasedAlgorithm as the base class for feature based algorithms allows shortcutting much of the common algorithm code for handling iterating over sources and pushing features to output sinks. It also allows the algorithm execution to be optimised in future (for instance allowing automatic multi-thread processing of the algorithm, or use of the algorithm in "chains", avoiding the need for temporary outputs in multi-step models).
This commit is contained in:
parent
71b9ce25c6
commit
1a41624370
@ -30,6 +30,8 @@ class QgsProcessingAlgorithm
|
||||
%ConvertToSubClassCode
|
||||
if ( dynamic_cast< QgsProcessingModelAlgorithm * >( sipCpp ) != NULL )
|
||||
sipType = sipType_QgsProcessingModelAlgorithm;
|
||||
else if ( dynamic_cast< QgsProcessingFeatureBasedAlgorithm * >( sipCpp ) != NULL )
|
||||
sipType = sipType_QgsProcessingFeatureBasedAlgorithm;
|
||||
else
|
||||
sipType = sipType_QgsProcessingAlgorithm;
|
||||
%End
|
||||
@ -717,6 +719,107 @@ QFlags<QgsProcessingAlgorithm::Flag> operator|(QgsProcessingAlgorithm::Flag f1,
|
||||
|
||||
|
||||
|
||||
class QgsProcessingFeatureBasedAlgorithm : QgsProcessingAlgorithm
|
||||
{
|
||||
%Docstring
|
||||
An abstract QgsProcessingAlgorithm base class for processing algorithms which operate "feature-by-feature".
|
||||
|
||||
Feature based algorithms are algorithms which operate on individual features in isolation. These
|
||||
are algorithms where one feature is output for each input feature, and the output feature result
|
||||
for each input feature is not dependent on any other features present in the source.
|
||||
|
||||
For instance, algorithms like "centroids" and "buffers" are feature based algorithms since the centroid
|
||||
or buffer of a feature is calculated for each feature in isolation. An algorithm like "dissolve"
|
||||
is NOT suitable for a feature based algorithm as the dissolved output depends on multiple input features
|
||||
and these features cannot be processed in isolation.
|
||||
|
||||
Using QgsProcessingFeatureBasedAlgorithm as the base class for feature based algorithms allows
|
||||
shortcutting much of the common algorithm code for handling iterating over sources and pushing
|
||||
features to output sinks. It also allows the algorithm execution to be optimised in future
|
||||
(for instance allowing automatic multi-thread processing of the algorithm, or use of the
|
||||
algorithm in "chains", avoiding the need for temporary outputs in multi-step models).
|
||||
|
||||
.. versionadded:: 3.0
|
||||
%End
|
||||
|
||||
%TypeHeaderCode
|
||||
#include "qgsprocessingalgorithm.h"
|
||||
%End
|
||||
public:
|
||||
|
||||
QgsProcessingFeatureBasedAlgorithm();
|
||||
%Docstring
|
||||
Constructor for QgsProcessingFeatureBasedAlgorithm.
|
||||
%End
|
||||
|
||||
protected:
|
||||
|
||||
virtual void initAlgorithm( const QVariantMap &configuration = QVariantMap() );
|
||||
|
||||
|
||||
virtual QString outputName() const = 0;
|
||||
%Docstring
|
||||
Returns the translated, user visible name for any layers created by this algorithm.
|
||||
This name will be used as the default name when loading the resultant layer into a
|
||||
QGIS project.
|
||||
:rtype: str
|
||||
%End
|
||||
|
||||
virtual QgsProcessing::LayerType outputLayerType() const;
|
||||
%Docstring
|
||||
Returns the layer type for layers generated by this algorithm, if
|
||||
this is possible to determine in advance.
|
||||
:rtype: QgsProcessing.LayerType
|
||||
%End
|
||||
|
||||
virtual QgsWkbTypes::Type outputWkbType( QgsWkbTypes::Type inputWkbType ) const;
|
||||
%Docstring
|
||||
Maps the input WKB geometry type (``inputWkbType``) to the corresponding
|
||||
output WKB type generated by the algorithm. The default behavior is that the algorithm maintains
|
||||
the same WKB type.
|
||||
:rtype: QgsWkbTypes.Type
|
||||
%End
|
||||
|
||||
virtual QgsFields outputFields( const QgsFields &inputFields ) const;
|
||||
%Docstring
|
||||
Maps the input source fields (``inputFields``) to corresponding
|
||||
output fields generated by the algorithm. The default behavior is that the algorithm maintains
|
||||
the same fields as are input.
|
||||
Algorithms which add, remove or modify existing fields should override this method and
|
||||
implement logic here to indicate which fields are output by the algorithm.
|
||||
:rtype: QgsFields
|
||||
%End
|
||||
|
||||
virtual QgsCoordinateReferenceSystem outputCrs( const QgsCoordinateReferenceSystem &inputCrs ) const;
|
||||
%Docstring
|
||||
Maps the input source coordinate reference system (``inputCrs``) to a corresponding
|
||||
output CRS generated by the algorithm. The default behavior is that the algorithm maintains
|
||||
the same CRS as the input source.
|
||||
:rtype: QgsCoordinateReferenceSystem
|
||||
%End
|
||||
|
||||
virtual bool processFeature( QgsFeature &feature, QgsProcessingFeedback *feedback ) = 0;
|
||||
%Docstring
|
||||
Processes an individual input ``feature`` from the source. Algorithms should implement their
|
||||
logic in this method for performing the algorithm's operation (e.g. replacing the feature's
|
||||
geometry with the centroid of the original feature geometry for a 'centroid' type
|
||||
algorithm).
|
||||
|
||||
Implementations should return true if the feature should be kept and added to the algorithm's
|
||||
output sink, or false if the feature should be skipped and omitted from the output.
|
||||
|
||||
The provided ``feedback`` object can be used to push messages to the log and for giving feedback
|
||||
to users. Note that handling of progress reports and algorithm cancelation is handled by
|
||||
the base class and subclasses do not need to reimplement this logic.
|
||||
:rtype: bool
|
||||
%End
|
||||
|
||||
virtual QVariantMap processAlgorithm( const QVariantMap ¶meters,
|
||||
QgsProcessingContext &context, QgsProcessingFeedback *feedback );
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
/************************************************************************
|
||||
* This file has been generated automatically from *
|
||||
|
@ -87,53 +87,18 @@ QgsCentroidAlgorithm *QgsCentroidAlgorithm::createInstance() const
|
||||
return new QgsCentroidAlgorithm();
|
||||
}
|
||||
|
||||
QVariantMap QgsCentroidAlgorithm::processAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
|
||||
bool QgsCentroidAlgorithm::processFeature( QgsFeature &feature, QgsProcessingFeedback *feedback )
|
||||
{
|
||||
std::unique_ptr< QgsFeatureSource > source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
|
||||
if ( !source )
|
||||
return QVariantMap();
|
||||
|
||||
QString dest;
|
||||
std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, source->fields(), QgsWkbTypes::Point, source->sourceCrs() ) );
|
||||
if ( !sink )
|
||||
return QVariantMap();
|
||||
|
||||
long count = source->featureCount();
|
||||
if ( count <= 0 )
|
||||
return QVariantMap();
|
||||
|
||||
QgsFeature f;
|
||||
QgsFeatureIterator it = source->getFeatures();
|
||||
|
||||
double step = 100.0 / count;
|
||||
int current = 0;
|
||||
while ( it.nextFeature( f ) )
|
||||
if ( feature.hasGeometry() )
|
||||
{
|
||||
if ( feedback->isCanceled() )
|
||||
feature.setGeometry( feature.geometry().centroid() );
|
||||
if ( !feature.geometry() )
|
||||
{
|
||||
break;
|
||||
feedback->pushInfo( QObject::tr( "Error calculating centroid for feature %1" ).arg( feature.id() ) );
|
||||
}
|
||||
|
||||
QgsFeature out = f;
|
||||
if ( out.hasGeometry() )
|
||||
{
|
||||
out.setGeometry( f.geometry().centroid() );
|
||||
if ( !out.geometry() )
|
||||
{
|
||||
QgsMessageLog::logMessage( QObject::tr( "Error calculating centroid for feature %1" ).arg( f.id() ), QObject::tr( "Processing" ), QgsMessageLog::WARNING );
|
||||
}
|
||||
}
|
||||
sink->addFeature( out, QgsFeatureSink::FastInsert );
|
||||
|
||||
feedback->setProgress( current * step );
|
||||
current++;
|
||||
}
|
||||
|
||||
QVariantMap outputs;
|
||||
outputs.insert( QStringLiteral( "OUTPUT" ), dest );
|
||||
return outputs;
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// QgsBufferAlgorithm
|
||||
//
|
||||
|
@ -48,7 +48,7 @@ class QgsNativeAlgorithms: public QgsProcessingProvider
|
||||
/**
|
||||
* Native centroid algorithm.
|
||||
*/
|
||||
class QgsCentroidAlgorithm : public QgsProcessingAlgorithm
|
||||
class QgsCentroidAlgorithm : public QgsProcessingFeatureBasedAlgorithm
|
||||
{
|
||||
|
||||
public:
|
||||
@ -57,16 +57,18 @@ class QgsCentroidAlgorithm : public QgsProcessingAlgorithm
|
||||
void initAlgorithm( const QVariantMap &configuration = QVariantMap() ) override;
|
||||
QString name() const override { return QStringLiteral( "centroids" ); }
|
||||
QString displayName() const override { return QObject::tr( "Centroids" ); }
|
||||
virtual QStringList tags() const override { return QObject::tr( "centroid,center,average,point,middle" ).split( ',' ); }
|
||||
QStringList tags() const override { return QObject::tr( "centroid,center,average,point,middle" ).split( ',' ); }
|
||||
QString group() const override { return QObject::tr( "Vector geometry tools" ); }
|
||||
QString shortHelpString() const override;
|
||||
QgsCentroidAlgorithm *createInstance() const override SIP_FACTORY;
|
||||
|
||||
protected:
|
||||
|
||||
virtual QVariantMap processAlgorithm( const QVariantMap ¶meters,
|
||||
QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
|
||||
QString outputName() const override { return QObject::tr( "Centroids" ); }
|
||||
QgsProcessing::LayerType outputLayerType() const override { return QgsProcessing::TypeVectorPoint; }
|
||||
QgsWkbTypes::Type outputWkbType( QgsWkbTypes::Type inputWkbType ) const override { Q_UNUSED( inputWkbType ); return QgsWkbTypes::Point; }
|
||||
|
||||
bool processFeature( QgsFeature &feature, QgsProcessingFeedback *feedback ) override;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -608,3 +608,57 @@ bool QgsProcessingAlgorithm::createAutoOutputForParameter( QgsProcessingParamete
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// QgsProcessingFeatureBasedAlgorithm
|
||||
//
|
||||
|
||||
void QgsProcessingFeatureBasedAlgorithm::initAlgorithm( const QVariantMap & )
|
||||
{
|
||||
addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ), QObject::tr( "Input layer" ) ) );
|
||||
addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "OUTPUT" ), outputName(), outputLayerType() ) );
|
||||
addOutput( new QgsProcessingOutputVectorLayer( QStringLiteral( "OUTPUT" ), outputName(), outputLayerType() ) );
|
||||
}
|
||||
|
||||
QVariantMap QgsProcessingFeatureBasedAlgorithm::processAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
|
||||
{
|
||||
std::unique_ptr< QgsFeatureSource > source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
|
||||
if ( !source )
|
||||
return QVariantMap();
|
||||
|
||||
QString dest;
|
||||
std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest,
|
||||
outputFields( source->fields() ),
|
||||
outputWkbType( source->wkbType() ),
|
||||
outputCrs( source->sourceCrs() ) ) );
|
||||
if ( !sink )
|
||||
return QVariantMap();
|
||||
|
||||
long count = source->featureCount();
|
||||
if ( count <= 0 )
|
||||
return QVariantMap();
|
||||
|
||||
QgsFeature f;
|
||||
QgsFeatureIterator it = source->getFeatures();
|
||||
|
||||
double step = 100.0 / count;
|
||||
int current = 0;
|
||||
while ( it.nextFeature( f ) )
|
||||
{
|
||||
if ( feedback->isCanceled() )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if ( processFeature( f, feedback ) )
|
||||
{
|
||||
sink->addFeature( f, QgsFeatureSink::FastInsert );
|
||||
}
|
||||
|
||||
feedback->setProgress( current * step );
|
||||
current++;
|
||||
}
|
||||
|
||||
QVariantMap outputs;
|
||||
outputs.insert( QStringLiteral( "OUTPUT" ), dest );
|
||||
return outputs;
|
||||
}
|
||||
|
@ -53,6 +53,8 @@ class CORE_EXPORT QgsProcessingAlgorithm
|
||||
SIP_CONVERT_TO_SUBCLASS_CODE
|
||||
if ( dynamic_cast< QgsProcessingModelAlgorithm * >( sipCpp ) != NULL )
|
||||
sipType = sipType_QgsProcessingModelAlgorithm;
|
||||
else if ( dynamic_cast< QgsProcessingFeatureBasedAlgorithm * >( sipCpp ) != NULL )
|
||||
sipType = sipType_QgsProcessingFeatureBasedAlgorithm;
|
||||
else
|
||||
sipType = sipType_QgsProcessingAlgorithm;
|
||||
SIP_END
|
||||
@ -697,6 +699,98 @@ Q_DECLARE_OPERATORS_FOR_FLAGS( QgsProcessingAlgorithm::Flags )
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* \class QgsProcessingFeatureBasedAlgorithm
|
||||
* \ingroup core
|
||||
* An abstract QgsProcessingAlgorithm base class for processing algorithms which operate "feature-by-feature".
|
||||
*
|
||||
* Feature based algorithms are algorithms which operate on individual features in isolation. These
|
||||
* are algorithms where one feature is output for each input feature, and the output feature result
|
||||
* for each input feature is not dependent on any other features present in the source.
|
||||
*
|
||||
* For instance, algorithms like "centroids" and "buffers" are feature based algorithms since the centroid
|
||||
* or buffer of a feature is calculated for each feature in isolation. An algorithm like "dissolve"
|
||||
* is NOT suitable for a feature based algorithm as the dissolved output depends on multiple input features
|
||||
* and these features cannot be processed in isolation.
|
||||
*
|
||||
* Using QgsProcessingFeatureBasedAlgorithm as the base class for feature based algorithms allows
|
||||
* shortcutting much of the common algorithm code for handling iterating over sources and pushing
|
||||
* features to output sinks. It also allows the algorithm execution to be optimised in future
|
||||
* (for instance allowing automatic multi-thread processing of the algorithm, or use of the
|
||||
* algorithm in "chains", avoiding the need for temporary outputs in multi-step models).
|
||||
*
|
||||
* \since QGIS 3.0
|
||||
*/
|
||||
|
||||
class CORE_EXPORT QgsProcessingFeatureBasedAlgorithm : public QgsProcessingAlgorithm
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor for QgsProcessingFeatureBasedAlgorithm.
|
||||
*/
|
||||
QgsProcessingFeatureBasedAlgorithm() = default;
|
||||
|
||||
protected:
|
||||
|
||||
void initAlgorithm( const QVariantMap &configuration = QVariantMap() ) override;
|
||||
|
||||
/**
|
||||
* Returns the translated, user visible name for any layers created by this algorithm.
|
||||
* This name will be used as the default name when loading the resultant layer into a
|
||||
* QGIS project.
|
||||
*/
|
||||
virtual QString outputName() const = 0;
|
||||
|
||||
/**
|
||||
* Returns the layer type for layers generated by this algorithm, if
|
||||
* this is possible to determine in advance.
|
||||
*/
|
||||
virtual QgsProcessing::LayerType outputLayerType() const { return QgsProcessing::TypeVectorAny; }
|
||||
|
||||
/**
|
||||
* Maps the input WKB geometry type (\a inputWkbType) to the corresponding
|
||||
* output WKB type generated by the algorithm. The default behavior is that the algorithm maintains
|
||||
* the same WKB type.
|
||||
*/
|
||||
virtual QgsWkbTypes::Type outputWkbType( QgsWkbTypes::Type inputWkbType ) const { return inputWkbType; }
|
||||
|
||||
/**
|
||||
* Maps the input source fields (\a inputFields) to corresponding
|
||||
* output fields generated by the algorithm. The default behavior is that the algorithm maintains
|
||||
* the same fields as are input.
|
||||
* Algorithms which add, remove or modify existing fields should override this method and
|
||||
* implement logic here to indicate which fields are output by the algorithm.
|
||||
*/
|
||||
virtual QgsFields outputFields( const QgsFields &inputFields ) const { return inputFields; }
|
||||
|
||||
/**
|
||||
* Maps the input source coordinate reference system (\a inputCrs) to a corresponding
|
||||
* output CRS generated by the algorithm. The default behavior is that the algorithm maintains
|
||||
* the same CRS as the input source.
|
||||
*/
|
||||
virtual QgsCoordinateReferenceSystem outputCrs( const QgsCoordinateReferenceSystem &inputCrs ) const { return inputCrs; }
|
||||
|
||||
/**
|
||||
* Processes an individual input \a feature from the source. Algorithms should implement their
|
||||
* logic in this method for performing the algorithm's operation (e.g. replacing the feature's
|
||||
* geometry with the centroid of the original feature geometry for a 'centroid' type
|
||||
* algorithm).
|
||||
*
|
||||
* Implementations should return true if the feature should be kept and added to the algorithm's
|
||||
* output sink, or false if the feature should be skipped and omitted from the output.
|
||||
*
|
||||
* The provided \a feedback object can be used to push messages to the log and for giving feedback
|
||||
* to users. Note that handling of progress reports and algorithm cancelation is handled by
|
||||
* the base class and subclasses do not need to reimplement this logic.
|
||||
*/
|
||||
virtual bool processFeature( QgsFeature &feature, QgsProcessingFeedback *feedback ) = 0;
|
||||
|
||||
virtual QVariantMap processAlgorithm( const QVariantMap ¶meters,
|
||||
QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
|
||||
|
||||
};
|
||||
|
||||
#endif // QGSPROCESSINGALGORITHM_H
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user