Skip to content

Commit 3706d88

Browse files
committed
[processing] c++ framework for parameters and running algorithms (WIP)
This commit adds the virtual method for running processing algs to the base c++ class, and adds the initial framework for c++ algorithm parameters. When running an algorithm, a QVariantMap is passed as the algorithm parameters. The high level API provided by QgsProcessingParameters should be used to retrieve strings/layers/doubles/etc from this QVariantMap. This allows advanced use cases, such as passing QgsProperty with the QVariantMap for "dynamic" parameters, where the value should be evaluated for every feature processed. E.g. if the buffer algorithm uses a dynamic property for distance, then the distance could be bound to either a field value or to a custom expression. This gets evaluated before buffering each feature to allow for advanced variable buffering. Support for dynamic parameters will be "opt in", and non default. So algorithms will need to specifically add support for dynamic properties as required.
1 parent 8423aaf commit 3706d88

12 files changed

+572
-3
lines changed

python/core/core.sip

+1
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,7 @@
282282
%Include processing/qgsprocessingalgorithm.sip
283283
%Include processing/qgsprocessingcontext.sip
284284
%Include processing/qgsprocessingfeedback.sip
285+
%Include processing/qgsprocessingparameters.sip
285286
%Include processing/qgsprocessingprovider.sip
286287
%Include processing/qgsprocessingregistry.sip
287288
%Include processing/qgsprocessingutils.sip

python/core/processing/qgsprocessingalgorithm.sip

+17
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,23 @@ class QgsProcessingAlgorithm
112112

113113
void setProvider( QgsProcessingProvider *provider );
114114

115+
virtual bool run( const QVariantMap &parameters,
116+
QgsProcessingContext &context, QgsProcessingFeedback *feedback, QVariantMap &outputs /Out/ ) const = 0;
117+
%Docstring
118+
Runs the algorithm using the specified ``parameters``. Algorithms should implement
119+
their custom processing logic here.
120+
121+
The ``context`` argument specifies the context in which the algorithm is being run.
122+
The ``outputs`` map will be amended to include any outputs generated by this algorithm.
123+
124+
Algorithm progress should be reported using the supplied ``feedback`` object. Additionally,
125+
well-behaved algorithms should periodically check ``feedback`` to determine whether the
126+
algorithm should be canceled and exited early.
127+
128+
:return: true if algorithm run was successful, or false if run was unsuccessful.
129+
:rtype: bool
130+
%End
131+
115132
private:
116133
QgsProcessingAlgorithm( const QgsProcessingAlgorithm &other );
117134
};

python/core/processing/qgsprocessingcontext.sip

+1-1
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ class QgsProcessingContext
6464
.. seealso:: project()
6565
%End
6666

67-
QgsExpressionContext expressionContext() const;
67+
QgsExpressionContext &expressionContext();
6868
%Docstring
6969
Returns the expression context.
7070
:rtype: QgsExpressionContext
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/************************************************************************
2+
* This file has been generated automatically from *
3+
* *
4+
* src/core/processing/qgsprocessingparameters.h *
5+
* *
6+
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
7+
************************************************************************/
8+
9+
10+
11+
12+
13+
14+
class QgsProcessingParameters
15+
{
16+
%Docstring
17+
18+
A collection of utilities for working with parameters when running a processing algorithm.
19+
20+
Parameters are stored in a QVariantMap and referenced by a unique string key.
21+
The QVariants in parameters are not usually accessed
22+
directly, and instead the high level API provided through QgsProcessingParameters
23+
parameterAsString(), parameterAsDouble() are used instead.
24+
25+
Parameters are evaluated using a provided QgsProcessingContext, allowing
26+
the evaluation to understand available map layers and expression contexts
27+
(for expression based parameters).
28+
29+
.. versionadded:: 3.0
30+
%End
31+
32+
%TypeHeaderCode
33+
#include "qgsprocessingparameters.h"
34+
%End
35+
public:
36+
37+
static bool isDynamic( const QVariantMap &parameters, const QString &name );
38+
%Docstring
39+
Returns true if the parameter with matching ``name`` is a dynamic parameter, and must
40+
be evaluated once for every input feature processed.
41+
:rtype: bool
42+
%End
43+
44+
static QString parameterAsString( const QVariantMap &parameters, const QString &name, const QgsProcessingContext &context );
45+
%Docstring
46+
Evaluates the parameter with matching ``name`` to a static string value.
47+
:rtype: str
48+
%End
49+
50+
static double parameterAsDouble( const QVariantMap &parameters, const QString &name, const QgsProcessingContext &context );
51+
%Docstring
52+
Evaluates the parameter with matching ``name`` to a static double value.
53+
:rtype: float
54+
%End
55+
56+
static int parameterAsInt( const QVariantMap &parameters, const QString &name, const QgsProcessingContext &context );
57+
%Docstring
58+
Evaluates the parameter with matching ``name`` to a static integer value.
59+
:rtype: int
60+
%End
61+
62+
static bool parameterAsBool( const QVariantMap &parameters, const QString &name, const QgsProcessingContext &context );
63+
%Docstring
64+
Evaluates the parameter with matching ``name`` to a static boolean value.
65+
:rtype: bool
66+
%End
67+
68+
static QgsMapLayer *parameterAsLayer( const QVariantMap &parameters, const QString &name, QgsProcessingContext &context );
69+
%Docstring
70+
Evaluates the parameter with matching ``name`` to a map layer.
71+
72+
Layers will either be taken from ``context``'s active project, or loaded from external
73+
sources and stored temporarily in the ``context``. In either case, callers do not
74+
need to handle deletion of the returned layer.
75+
:rtype: QgsMapLayer
76+
%End
77+
78+
};
79+
80+
81+
82+
83+
/************************************************************************
84+
* This file has been generated automatically from *
85+
* *
86+
* src/core/processing/qgsprocessingparameters.h *
87+
* *
88+
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
89+
************************************************************************/

src/core/CMakeLists.txt

+4
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,9 @@ SET(QGIS_CORE_SRCS
8787
annotations/qgssvgannotation.cpp
8888
annotations/qgstextannotation.cpp
8989

90+
processing/qgsnativealgorithms.cpp
9091
processing/qgsprocessingalgorithm.cpp
92+
processing/qgsprocessingparameters.cpp
9193
processing/qgsprocessingprovider.cpp
9294
processing/qgsprocessingregistry.cpp
9395
processing/qgsprocessingutils.cpp
@@ -867,8 +869,10 @@ SET(QGIS_CORE_HDRS
867869
metadata/qgslayermetadata.h
868870
metadata/qgslayermetadatavalidator.h
869871

872+
processing/qgsnativealgorithms.h
870873
processing/qgsprocessingalgorithm.h
871874
processing/qgsprocessingcontext.h
875+
processing/qgsprocessingparameters.h
872876
processing/qgsprocessingutils.h
873877

874878
providers/memory/qgsmemoryfeatureiterator.h
+123
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
/***************************************************************************
2+
qgsnativealgorithms.cpp
3+
---------------------
4+
begin : April 2017
5+
copyright : (C) 2017 by Nyall Dawson
6+
email : nyall dot dawson at gmail dot com
7+
***************************************************************************/
8+
9+
/***************************************************************************
10+
* *
11+
* This program is free software; you can redistribute it and/or modify *
12+
* it under the terms of the GNU General Public License as published by *
13+
* the Free Software Foundation; either version 2 of the License, or *
14+
* (at your option) any later version. *
15+
* *
16+
***************************************************************************/
17+
18+
#include "qgsnativealgorithms.h"
19+
#include "qgsfeatureiterator.h"
20+
#include "qgsprocessingcontext.h"
21+
#include "qgsprocessingfeedback.h"
22+
#include "qgsprocessingutils.h"
23+
#include "qgsvectorlayer.h"
24+
#include "qgsgeometry.h"
25+
#include "qgswkbtypes.h"
26+
27+
bool QgsCentroidAlgorithm::run( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback, QVariantMap &outputs ) const
28+
{
29+
Q_UNUSED( outputs );
30+
QgsVectorLayer *layer = qobject_cast< QgsVectorLayer *>( QgsProcessingParameters::parameterAsLayer( parameters, QStringLiteral( "INPUT_LAYER" ), context ) );
31+
if ( !layer )
32+
return false;
33+
34+
QString dest;
35+
QgsVectorLayer *outputLayer = nullptr;
36+
std::unique_ptr< QgsFeatureSink > writer( QgsProcessingUtils::createFeatureSink( dest, QString(), layer->fields(), QgsWkbTypes::Point, layer->crs(), context, outputLayer ) );
37+
38+
QgsFeature f;
39+
QgsFeatureIterator it = QgsProcessingUtils::getFeatures( layer, context );
40+
41+
double step = 100.0 / QgsProcessingUtils::featureCount( layer, context );
42+
int current = 0;
43+
while ( it.nextFeature( f ) )
44+
{
45+
if ( feedback->isCanceled() )
46+
{
47+
break;
48+
}
49+
50+
QgsFeature out = f;
51+
if ( out.hasGeometry() )
52+
{
53+
out.setGeometry( f.geometry().centroid() );
54+
if ( !out.geometry() )
55+
{
56+
QgsMessageLog::logMessage( QObject::tr( "Error calculating centroid for feature %1" ).arg( f.id() ), QObject::tr( "Processing" ), QgsMessageLog::WARNING );
57+
}
58+
}
59+
writer->addFeature( out );
60+
61+
feedback->setProgress( current * step );
62+
current++;
63+
}
64+
65+
return true;
66+
}
67+
68+
bool QgsBufferAlgorithm::run( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback, QVariantMap &outputs ) const
69+
{
70+
Q_UNUSED( outputs );
71+
72+
QgsVectorLayer *layer = qobject_cast< QgsVectorLayer *>( QgsProcessingParameters::parameterAsLayer( parameters, QStringLiteral( "INPUT" ), context ) );
73+
if ( !layer )
74+
return false;
75+
76+
QString dest;
77+
QgsVectorLayer *outputLayer = nullptr;
78+
std::unique_ptr< QgsFeatureSink > writer( QgsProcessingUtils::createFeatureSink( dest, QString(), layer->fields(), QgsWkbTypes::Point, layer->crs(), context, outputLayer ) );
79+
80+
// fixed parameters
81+
bool dissolve = QgsProcessingParameters::parameterAsBool( parameters, QStringLiteral( "DISSOLVE" ), context );
82+
int segments = QgsProcessingParameters::parameterAsInt( parameters, QStringLiteral( "DISSOLVE" ), context );
83+
QgsGeometry::EndCapStyle endCapStyle = static_cast< QgsGeometry::EndCapStyle >( QgsProcessingParameters::parameterAsInt( parameters, QStringLiteral( "END_CAP_STYLE" ), context ) );
84+
QgsGeometry::JoinStyle joinStyle = static_cast< QgsGeometry::JoinStyle>( QgsProcessingParameters::parameterAsInt( parameters, QStringLiteral( "JOIN_STYLE" ), context ) );
85+
double miterLimit = QgsProcessingParameters::parameterAsDouble( parameters, QStringLiteral( "MITRE_LIMIT" ), context );
86+
double bufferDistance = QgsProcessingParameters::parameterAsDouble( parameters, QStringLiteral( "DISTANCE" ), context );
87+
bool dynamicBuffer = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "DISTANCE" ) );
88+
89+
QgsFeature f;
90+
QgsFeatureIterator it = QgsProcessingUtils::getFeatures( layer, context );
91+
92+
double step = 100.0 / QgsProcessingUtils::featureCount( layer, context );
93+
int current = 0;
94+
while ( it.nextFeature( f ) )
95+
{
96+
if ( feedback->isCanceled() )
97+
{
98+
break;
99+
}
100+
101+
QgsFeature out = f;
102+
if ( out.hasGeometry() )
103+
{
104+
if ( dynamicBuffer )
105+
{
106+
context.expressionContext().setFeature( f );
107+
bufferDistance = QgsProcessingParameters::parameterAsDouble( parameters, QStringLiteral( "DISTANCE" ), context );
108+
}
109+
110+
out.setGeometry( f.geometry().buffer( bufferDistance, segments, endCapStyle, joinStyle, miterLimit ) );
111+
if ( !out.geometry() )
112+
{
113+
QgsMessageLog::logMessage( QObject::tr( "Error calculating buffer for feature %1" ).arg( f.id() ), QObject::tr( "Processing" ), QgsMessageLog::WARNING );
114+
}
115+
}
116+
writer->addFeature( out );
117+
118+
feedback->setProgress( current * step );
119+
current++;
120+
}
121+
122+
return true;
123+
}
+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/***************************************************************************
2+
qgsnativealgorithms.h
3+
---------------------
4+
begin : April 2017
5+
copyright : (C) 2017 by Nyall Dawson
6+
email : nyall dot dawson at gmail dot com
7+
***************************************************************************/
8+
9+
/***************************************************************************
10+
* *
11+
* This program is free software; you can redistribute it and/or modify *
12+
* it under the terms of the GNU General Public License as published by *
13+
* the Free Software Foundation; either version 2 of the License, or *
14+
* (at your option) any later version. *
15+
* *
16+
***************************************************************************/
17+
18+
#ifndef QGSNATIVEALGORITHMS_H
19+
#define QGSNATIVEALGORITHMS_H
20+
21+
#include "qgis_core.h"
22+
#include "qgis.h"
23+
#include "qgsprocessingalgorithm.h"
24+
25+
///@cond PRIVATE
26+
27+
/**
28+
* Native centroid algorithm.
29+
*/
30+
class QgsCentroidAlgorithm : public QgsProcessingAlgorithm
31+
{
32+
33+
public:
34+
35+
QgsCentroidAlgorithm() = default;
36+
37+
QString name() const override { return QStringLiteral( "centroids" ); }
38+
QString displayName() const override { return QObject::tr( "Centroids" ); }
39+
virtual QStringList tags() const override { return QObject::tr( "centroid,center,average,point,middle" ).split( ',' ); }
40+
QString group() const override { return QObject::tr( "Vector geometry tools" ); }
41+
42+
virtual bool run( const QVariantMap &parameters,
43+
QgsProcessingContext &context, QgsProcessingFeedback *feedback, QVariantMap &outputs ) const override;
44+
45+
};
46+
47+
/**
48+
* Native buffer algorithm.
49+
*/
50+
class QgsBufferAlgorithm : public QgsProcessingAlgorithm
51+
{
52+
53+
public:
54+
55+
QgsBufferAlgorithm() = default;
56+
57+
QString name() const override { return QStringLiteral( "fixeddistancebuffer" ); }
58+
QString displayName() const override { return QObject::tr( "Buffer" ); }
59+
virtual QStringList tags() const override { return QObject::tr( "buffer,grow" ).split( ',' ); }
60+
QString group() const override { return QObject::tr( "Vector geometry tools" ); }
61+
62+
virtual bool run( const QVariantMap &parameters,
63+
QgsProcessingContext &context, QgsProcessingFeedback *feedback, QVariantMap &outputs ) const override;
64+
65+
};
66+
67+
///@endcond PRIVATE
68+
69+
#endif // QGSNATIVEALGORITHMS_H
70+
71+

src/core/processing/qgsprocessingalgorithm.h

+20
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,15 @@
1919
#define QGSPROCESSINGALGORITHM_H
2020

2121
#include "qgis_core.h"
22+
#include "qgis.h"
23+
#include "qgsprocessingparameters.h"
2224
#include <QString>
2325
#include <QVariant>
2426
#include <QIcon>
2527

2628
class QgsProcessingProvider;
29+
class QgsProcessingContext;
30+
class QgsProcessingFeedback;
2731

2832
/**
2933
* \class QgsProcessingAlgorithm
@@ -124,6 +128,22 @@ class CORE_EXPORT QgsProcessingAlgorithm
124128
//TEMPORARY - remove when algorithms are no longer copied in python code
125129
void setProvider( QgsProcessingProvider *provider );
126130

131+
/**
132+
* Runs the algorithm using the specified \a parameters. Algorithms should implement
133+
* their custom processing logic here.
134+
*
135+
* The \a context argument specifies the context in which the algorithm is being run.
136+
* The \a outputs map will be amended to include any outputs generated by this algorithm.
137+
*
138+
* Algorithm progress should be reported using the supplied \a feedback object. Additionally,
139+
* well-behaved algorithms should periodically check \a feedback to determine whether the
140+
* algorithm should be canceled and exited early.
141+
*
142+
* \returns true if algorithm run was successful, or false if run was unsuccessful.
143+
*/
144+
virtual bool run( const QVariantMap &parameters,
145+
QgsProcessingContext &context, QgsProcessingFeedback *feedback, QVariantMap &outputs SIP_OUT ) const = 0;
146+
127147
private:
128148

129149
QgsProcessingProvider *mProvider = nullptr;

0 commit comments

Comments
 (0)