Algorithms don't have to be split to prepare/process/postProcess

Since it's safe to evaluate parameters in background threads
now, it's usually going to be ok to evaluate everything in
the processAlgorithm step.

This keeps the algorithm code as simple as possible, and will
make porting faster.

Note that the prepare/postProcess virtual methods still exist
and can be used when an algorithm MUST do setup/cleanup work
in the main thread.
This commit is contained in:
Nyall Dawson 2017-07-01 12:21:11 +10:00
parent f39b7a0c4c
commit 8a84e134cc
46 changed files with 803 additions and 1339 deletions

View File

@ -259,7 +259,7 @@ class QgsProcessingAlgorithm
:rtype: bool :rtype: bool
%End %End
bool runPrepared( QgsProcessingContext &context, QgsProcessingFeedback *feedback ); QVariantMap runPrepared( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback );
%Docstring %Docstring
Runs the algorithm, which has been prepared by an earlier call to prepare(). Runs the algorithm, which has been prepared by an earlier call to prepare().
This method is safe to call from any thread. Returns true if the algorithm was successfully executed. This method is safe to call from any thread. Returns true if the algorithm was successfully executed.
@ -272,7 +272,7 @@ class QgsProcessingAlgorithm
This method modifies the algorithm instance, so it is not safe to call This method modifies the algorithm instance, so it is not safe to call
on algorithms directly retrieved from QgsProcessingRegistry and QgsProcessingProvider. Instead, a copy on algorithms directly retrieved from QgsProcessingRegistry and QgsProcessingProvider. Instead, a copy
of the algorithm should be created with clone() and prepare()/runPrepared() called on the copy. of the algorithm should be created with clone() and prepare()/runPrepared() called on the copy.
:rtype: bool :rtype: QVariantMap
%End %End
QVariantMap postProcess( QgsProcessingContext &context, QgsProcessingFeedback *feedback ); QVariantMap postProcess( QgsProcessingContext &context, QgsProcessingFeedback *feedback );
@ -374,7 +374,7 @@ class QgsProcessingAlgorithm
:rtype: bool :rtype: bool
%End %End
virtual bool processAlgorithm( QgsProcessingContext &context, QgsProcessingFeedback *feedback ) = 0 /VirtualErrorHandler=processing_exception_handler/; virtual QVariantMap processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) = 0 /VirtualErrorHandler=processing_exception_handler/;
%Docstring %Docstring
Runs the algorithm using the specified ``parameters``. Algorithms should implement Runs the algorithm using the specified ``parameters``. Algorithms should implement
their custom processing logic here. their custom processing logic here.
@ -389,10 +389,10 @@ class QgsProcessingAlgorithm
values such as statistical calculations. values such as statistical calculations.
.. seealso:: prepareAlgorithm() .. seealso:: prepareAlgorithm()
.. seealso:: postProcessAlgorithm() .. seealso:: postProcessAlgorithm()
:rtype: bool :rtype: QVariantMap
%End %End
virtual QVariantMap postProcessAlgorithm( QgsProcessingContext &context, QgsProcessingFeedback *feedback ) = 0 /VirtualErrorHandler=processing_exception_handler/; virtual QVariantMap postProcessAlgorithm( QgsProcessingContext &context, QgsProcessingFeedback *feedback ) /VirtualErrorHandler=processing_exception_handler/;
%Docstring %Docstring
Allows the algorithm to perform any required cleanup tasks. The returned variant map Allows the algorithm to perform any required cleanup tasks. The returned variant map
includes the results evaluated by the algorithm. These may be output layer references, or calculated includes the results evaluated by the algorithm. These may be output layer references, or calculated

View File

@ -835,11 +835,7 @@ Copies are protected to avoid slicing
protected: protected:
virtual bool prepareAlgorithm( const QVariantMap &parameters, virtual QVariantMap processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback );
QgsProcessingContext &context, QgsProcessingFeedback *feedback );
virtual bool processAlgorithm( QgsProcessingContext &context, QgsProcessingFeedback *feedback );
virtual QVariantMap postProcessAlgorithm( QgsProcessingContext &context, QgsProcessingFeedback *feedback );
}; };

View File

@ -74,38 +74,28 @@ class AddTableField(QgisAlgorithm):
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT_LAYER, self.tr('Added'))) self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT_LAYER, self.tr('Added')))
self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT_LAYER, self.tr('Added'))) self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT_LAYER, self.tr('Added')))
self.source = None
self.fieldType = None
self.fieldLength = None
self.fieldName = None
self.fieldPrecision = None
self.sink = None
self.dest_id = None
def name(self): def name(self):
return 'addfieldtoattributestable' return 'addfieldtoattributestable'
def displayName(self): def displayName(self):
return self.tr('Add field to attributes table') return self.tr('Add field to attributes table')
def prepareAlgorithm(self, parameters, context, feedback): def processAlgorithm(self, parameters, context, feedback):
self.source = self.parameterAsSource(parameters, self.INPUT_LAYER, context) source = self.parameterAsSource(parameters, self.INPUT_LAYER, context)
self.fieldType = self.parameterAsEnum(parameters, self.FIELD_TYPE, context) fieldType = self.parameterAsEnum(parameters, self.FIELD_TYPE, context)
self.fieldName = self.parameterAsString(parameters, self.FIELD_NAME, context) fieldName = self.parameterAsString(parameters, self.FIELD_NAME, context)
self.fieldLength = self.parameterAsInt(parameters, self.FIELD_LENGTH, context) fieldLength = self.parameterAsInt(parameters, self.FIELD_LENGTH, context)
self.fieldPrecision = self.parameterAsInt(parameters, self.FIELD_PRECISION, context) fieldPrecision = self.parameterAsInt(parameters, self.FIELD_PRECISION, context)
fields = self.source.fields() fields = source.fields()
fields.append(QgsField(self.fieldName, self.TYPES[self.fieldType], '', fields.append(QgsField(fieldName, self.TYPES[fieldType], '',
self.fieldLength, self.fieldPrecision)) fieldLength, fieldPrecision))
(self.sink, self.dest_id) = self.parameterAsSink(parameters, self.OUTPUT_LAYER, context, (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT_LAYER, context,
fields, self.source.wkbType(), self.source.sourceCrs()) fields, source.wkbType(), source.sourceCrs())
return True
def processAlgorithm(self, context, feedback): features = source.getFeatures()
features = self.source.getFeatures() total = 100.0 / source.featureCount() if source.featureCount() else 0
total = 100.0 / self.source.featureCount() if self.source.featureCount() else 0
for current, input_feature in enumerate(features): for current, input_feature in enumerate(features):
if feedback.isCanceled(): if feedback.isCanceled():
@ -116,10 +106,7 @@ class AddTableField(QgisAlgorithm):
attributes.append(None) attributes.append(None)
output_feature.setAttributes(attributes) output_feature.setAttributes(attributes)
self.sink.addFeature(output_feature, QgsFeatureSink.FastInsert) sink.addFeature(output_feature, QgsFeatureSink.FastInsert)
feedback.setProgress(int(current * total)) feedback.setProgress(int(current * total))
return True return {self.OUTPUT_LAYER: dest_id}
def postProcessAlgorithm(self, context, feedback):
return {self.OUTPUT_LAYER: self.dest_id}

View File

@ -68,30 +68,22 @@ class Aspect(QgisAlgorithm):
self.addParameter(QgsProcessingParameterRasterOutput(self.OUTPUT, self.tr('Aspect'))) self.addParameter(QgsProcessingParameterRasterOutput(self.OUTPUT, self.tr('Aspect')))
self.addOutput(QgsProcessingOutputRasterLayer(self.OUTPUT, self.tr('Aspect'))) self.addOutput(QgsProcessingOutputRasterLayer(self.OUTPUT, self.tr('Aspect')))
self.inputFile = None
self.outputFile = None
self.outputFormat = None
self.zFactor = None
def name(self): def name(self):
return 'aspect' return 'aspect'
def displayName(self): def displayName(self):
return self.tr('Aspect') return self.tr('Aspect')
def prepareAlgorithm(self, parameters, context, feedback): def processAlgorithm(self, parameters, context, feedback):
self.inputFile = exportRasterLayer(self.parameterAsRasterLayer(parameters, self.INPUT, context)) inputFile = exportRasterLayer(self.parameterAsRasterLayer(parameters, self.INPUT, context))
self.zFactor = self.parameterAsDouble(parameters, self.Z_FACTOR, context) zFactor = self.parameterAsDouble(parameters, self.Z_FACTOR, context)
self.outputFile = self.parameterAsRasterOutputLayer(parameters, self.OUTPUT, context) outputFile = self.parameterAsRasterOutputLayer(parameters, self.OUTPUT, context)
self.outputFormat = raster.formatShortNameFromFileName(self.outputFile) outputFormat = raster.formatShortNameFromFileName(outputFile)
return True
def processAlgorithm(self, context, feedback): aspect = QgsAspectFilter(inputFile, outputFile, outputFormat)
aspect = QgsAspectFilter(self.inputFile, self.outputFile, self.outputFormat) aspect.setZFactor(zFactor)
aspect.setZFactor(self.zFactor) aspect.processRaster(feedback)
return aspect.processRaster(feedback) == 0
def postProcessAlgorithm(self, context, feedback): return {self.OUTPUT: outputFile}
return {self.OUTPUT: self.outputFile}

View File

@ -51,10 +51,6 @@ class AutoincrementalField(QgisAlgorithm):
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Incremented'))) self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Incremented')))
self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr('Incremented'))) self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr('Incremented')))
self.source = None
self.sink = None
self.dest_id = None
def group(self): def group(self):
return self.tr('Vector table tools') return self.tr('Vector table tools')
@ -64,18 +60,16 @@ class AutoincrementalField(QgisAlgorithm):
def displayName(self): def displayName(self):
return self.tr('Add autoincremental field') return self.tr('Add autoincremental field')
def prepareAlgorithm(self, parameters, context, feedback): def processAlgorithm(self, parameters, context, feedback):
self.source = self.parameterAsSource(parameters, self.INPUT, context) source = self.parameterAsSource(parameters, self.INPUT, context)
fields = self.source.fields() fields = source.fields()
fields.append(QgsField('AUTO', QVariant.Int)) fields.append(QgsField('AUTO', QVariant.Int))
(self.sink, self.dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
fields, self.source.wkbType(), self.source.sourceCrs()) fields, source.wkbType(), source.sourceCrs())
return True
def processAlgorithm(self, context, feedback): features = source.getFeatures()
features = self.source.getFeatures() total = 100.0 / source.featureCount() if source.featureCount() else 0
total = 100.0 / self.source.featureCount() if self.source.featureCount() else 0
for current, input_feature in enumerate(features): for current, input_feature in enumerate(features):
if feedback.isCanceled(): if feedback.isCanceled():
break break
@ -85,9 +79,7 @@ class AutoincrementalField(QgisAlgorithm):
attributes.append(current) attributes.append(current)
output_feature.setAttributes(attributes) output_feature.setAttributes(attributes)
self.sink.addFeature(output_feature, QgsFeatureSink.FastInsert) sink.addFeature(output_feature, QgsFeatureSink.FastInsert)
feedback.setProgress(int(current * total)) feedback.setProgress(int(current * total))
return True
def postProcessAlgorithm(self, context, feedback): return {self.OUTPUT: dest_id}
return {self.OUTPUT: self.dest_id}

View File

@ -119,52 +119,42 @@ class BasicStatisticsForField(QgisAlgorithm):
self.addOutput(QgsProcessingOutputNumber(self.THIRDQUARTILE, self.tr('Third quartile'))) self.addOutput(QgsProcessingOutputNumber(self.THIRDQUARTILE, self.tr('Third quartile')))
self.addOutput(QgsProcessingOutputNumber(self.IQR, self.tr('Interquartile Range (IQR)'))) self.addOutput(QgsProcessingOutputNumber(self.IQR, self.tr('Interquartile Range (IQR)')))
self.source = None
self.field = None
self.field_name = None
self.output_file = None
self.results = {}
def name(self): def name(self):
return 'basicstatisticsforfields' return 'basicstatisticsforfields'
def displayName(self): def displayName(self):
return self.tr('Basic statistics for fields') return self.tr('Basic statistics for fields')
def prepareAlgorithm(self, parameters, context, feedback): def processAlgorithm(self, parameters, context, feedback):
self.source = self.parameterAsSource(parameters, self.INPUT_LAYER, context) source = self.parameterAsSource(parameters, self.INPUT_LAYER, context)
self.field_name = self.parameterAsString(parameters, self.FIELD_NAME, context) field_name = self.parameterAsString(parameters, self.FIELD_NAME, context)
self.field = self.source.fields().at(self.source.fields().lookupField(self.field_name)) field = source.fields().at(source.fields().lookupField(field_name))
self.output_file = self.parameterAsFileOutput(parameters, self.OUTPUT_HTML_FILE, context) output_file = self.parameterAsFileOutput(parameters, self.OUTPUT_HTML_FILE, context)
return True
def processAlgorithm(self, context, feedback): request = QgsFeatureRequest().setFlags(QgsFeatureRequest.NoGeometry).setSubsetOfAttributes([field_name], source.fields())
request = QgsFeatureRequest().setFlags(QgsFeatureRequest.NoGeometry).setSubsetOfAttributes([self.field_name], self.source.fields()) features = source.getFeatures(request)
features = self.source.getFeatures(request) count = source.featureCount()
count = self.source.featureCount()
data = [] data = []
data.append(self.tr('Analyzed field: {}').format(self.field_name)) data.append(self.tr('Analyzed field: {}').format(field_name))
results = {}
if self.field.isNumeric(): if field.isNumeric():
d, self.results = self.calcNumericStats(features, feedback, self.field, count) d, results = self.calcNumericStats(features, feedback, field, count)
data.extend(d) data.extend(d)
elif self.field.type() in (QVariant.Date, QVariant.Time, QVariant.DateTime): elif field.type() in (QVariant.Date, QVariant.Time, QVariant.DateTime):
d, self.results = self.calcDateTimeStats(features, feedback, self.field, count) d, results = self.calcDateTimeStats(features, feedback, field, count)
data.extend(d) data.extend(d)
else: else:
d, self.results = self.calcStringStats(features, feedback, self.field, count) d, results = self.calcStringStats(features, feedback, field, count)
data.extend(d) data.extend(d)
if self.output_file: if output_file:
self.createHTML(self.output_file, data) self.createHTML(output_file, data)
self.results[self.OUTPUT_HTML_FILE] = self.output_file results[self.OUTPUT_HTML_FILE] = output_file
return True return results
def postProcessAlgorithm(self, context, feedback):
return self.results
def calcNumericStats(self, features, feedback, field, count): def calcNumericStats(self, features, feedback, field, count):
total = 100.0 / count if count else 0 total = 100.0 / count if count else 0

View File

@ -58,10 +58,6 @@ class Boundary(QgisAlgorithm):
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT_LAYER, self.tr('Boundary'))) self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT_LAYER, self.tr('Boundary')))
self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT_LAYER, self.tr("Boundaries"))) self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT_LAYER, self.tr("Boundaries")))
self.source = None
self.sink = None
self.dest_id = None
def icon(self): def icon(self):
return QIcon(os.path.join(pluginPath, 'images', 'ftools', 'convex_hull.png')) return QIcon(os.path.join(pluginPath, 'images', 'ftools', 'convex_hull.png'))
@ -74,11 +70,10 @@ class Boundary(QgisAlgorithm):
def displayName(self): def displayName(self):
return self.tr('Boundary') return self.tr('Boundary')
def prepareAlgorithm(self, parameters, context, feedback): def processAlgorithm(self, parameters, context, feedback):
self.source = self.parameterAsSource(parameters, self.INPUT_LAYER, context) source = self.parameterAsSource(parameters, self.INPUT_LAYER, context)
input_wkb = self.source.wkbType() input_wkb = source.wkbType()
output_wkb = None
if QgsWkbTypes.geometryType(input_wkb) == QgsWkbTypes.LineGeometry: if QgsWkbTypes.geometryType(input_wkb) == QgsWkbTypes.LineGeometry:
output_wkb = QgsWkbTypes.MultiPoint output_wkb = QgsWkbTypes.MultiPoint
elif QgsWkbTypes.geometryType(input_wkb) == QgsWkbTypes.PolygonGeometry: elif QgsWkbTypes.geometryType(input_wkb) == QgsWkbTypes.PolygonGeometry:
@ -88,13 +83,11 @@ class Boundary(QgisAlgorithm):
if QgsWkbTypes.hasM(input_wkb): if QgsWkbTypes.hasM(input_wkb):
output_wkb = QgsWkbTypes.addM(output_wkb) output_wkb = QgsWkbTypes.addM(output_wkb)
(self.sink, self.dest_id) = self.parameterAsSink(parameters, self.OUTPUT_LAYER, context, (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT_LAYER, context,
self.source.fields(), output_wkb, self.source.sourceCrs()) source.fields(), output_wkb, source.sourceCrs())
return True
def processAlgorithm(self, context, feedback): features = source.getFeatures()
features = self.source.getFeatures() total = 100.0 / source.featureCount() if source.featureCount() else 0
total = 100.0 / self.source.featureCount() if self.source.featureCount() else 0
for current, input_feature in enumerate(features): for current, input_feature in enumerate(features):
if feedback.isCanceled(): if feedback.isCanceled():
@ -109,9 +102,7 @@ class Boundary(QgisAlgorithm):
output_feature.setGeometry(output_geometry) output_feature.setGeometry(output_geometry)
self.sink.addFeature(output_feature, QgsFeatureSink.FastInsert) sink.addFeature(output_feature, QgsFeatureSink.FastInsert)
feedback.setProgress(int(current * total)) feedback.setProgress(int(current * total))
return True
def postProcessAlgorithm(self, context, feedback): return {self.OUTPUT_LAYER: dest_id}
return {self.OUTPUT_LAYER: self.dest_id}

View File

@ -66,26 +66,20 @@ class BoundingBox(QgisAlgorithm):
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT_LAYER, self.tr('Bounds'), QgsProcessingParameterDefinition.TypeVectorPolygon)) self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT_LAYER, self.tr('Bounds'), QgsProcessingParameterDefinition.TypeVectorPolygon))
self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT_LAYER, self.tr("Bounds"))) self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT_LAYER, self.tr("Bounds")))
self.source = None
self.sink = None
self.dest_id = None
def name(self): def name(self):
return 'boundingboxes' return 'boundingboxes'
def displayName(self): def displayName(self):
return self.tr('Bounding boxes') return self.tr('Bounding boxes')
def prepareAlgorithm(self, parameters, context, feedback): def processAlgorithm(self, parameters, context, feedback):
self.source = self.parameterAsSource(parameters, self.INPUT_LAYER, context) source = self.parameterAsSource(parameters, self.INPUT_LAYER, context)
(self.sink, self.dest_id) = self.parameterAsSink(parameters, self.OUTPUT_LAYER, context, (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT_LAYER, context,
self.source.fields(), QgsWkbTypes.Polygon, self.source.sourceCrs()) source.fields(), QgsWkbTypes.Polygon, source.sourceCrs())
return True
def processAlgorithm(self, context, feedback): features = source.getFeatures()
features = self.source.getFeatures() total = 100.0 / source.featureCount() if source.featureCount() else 0
total = 100.0 / self.source.featureCount() if self.source.featureCount() else 0
for current, input_feature in enumerate(features): for current, input_feature in enumerate(features):
if feedback.isCanceled(): if feedback.isCanceled():
@ -100,9 +94,7 @@ class BoundingBox(QgisAlgorithm):
output_feature.setGeometry(output_geometry) output_feature.setGeometry(output_geometry)
self.sink.addFeature(output_feature, QgsFeatureSink.FastInsert) sink.addFeature(output_feature, QgsFeatureSink.FastInsert)
feedback.setProgress(int(current * total)) feedback.setProgress(int(current * total))
return True
def postProcessAlgorithm(self, context, feedback): return {self.OUTPUT_LAYER: dest_id}
return {self.OUTPUT_LAYER: self.dest_id}

View File

@ -93,60 +93,46 @@ class CheckValidity(QgisAlgorithm):
self.addOutput(QgsProcessingOutputVectorLayer(self.ERROR_OUTPUT, self.tr('Error output'))) self.addOutput(QgsProcessingOutputVectorLayer(self.ERROR_OUTPUT, self.tr('Error output')))
self.addOutput(QgsProcessingOutputNumber(self.ERROR_COUNT, self.tr('Count of errors'))) self.addOutput(QgsProcessingOutputNumber(self.ERROR_COUNT, self.tr('Count of errors')))
self.method = None
self.source = None
self.valid_output_sink = None
self.valid_output_dest_id = None
self.valid_count = 0
self.invalid_output_sink = None
self.invalid_output_dest_id = None
self.invalid_count = 0
self.error_output_sink = None
self.error_output_dest_id = None
self.error_count = 0
def name(self): def name(self):
return 'checkvalidity' return 'checkvalidity'
def displayName(self): def displayName(self):
return self.tr('Check validity') return self.tr('Check validity')
def prepareAlgorithm(self, parameters, context, feedback): def processAlgorithm(self, parameters, context, feedback):
method_param = self.parameterAsEnum(parameters, self.METHOD, context) method_param = self.parameterAsEnum(parameters, self.METHOD, context)
if method_param == 0: if method_param == 0:
settings = QgsSettings() settings = QgsSettings()
self.method = int(settings.value(settings_method_key, 0)) - 1 method = int(settings.value(settings_method_key, 0)) - 1
if self.method < 0: if method < 0:
self.method = 0 method = 0
else: else:
self.method = method_param - 1 method = method_param - 1
self.source = self.parameterAsSource(parameters, self.INPUT_LAYER, context) results = self.doCheck(method, parameters, context, feedback)
return results
(self.valid_output_sink, self.valid_output_dest_id) = self.parameterAsSink(parameters, self.VALID_OUTPUT, def doCheck(self, method, parameters, context, feedback):
context, source = self.parameterAsSource(parameters, self.INPUT_LAYER, context)
self.source.fields(),
self.source.wkbType(),
self.source.sourceCrs())
invalid_fields = self.source.fields() (valid_output_sink, valid_output_dest_id) = self.parameterAsSink(parameters, self.VALID_OUTPUT, context,
source.fields(), source.wkbType(), source.sourceCrs())
valid_count = 0
invalid_fields = source.fields()
invalid_fields.append(QgsField('_errors', QVariant.String, 'string', 255)) invalid_fields.append(QgsField('_errors', QVariant.String, 'string', 255))
(self.invalid_output_sink, self.invalid_output_dest_id) = self.parameterAsSink(parameters, self.INVALID_OUTPUT, (invalid_output_sink, invalid_output_dest_id) = self.parameterAsSink(parameters, self.INVALID_OUTPUT, context,
context, invalid_fields, source.wkbType(), source.sourceCrs())
invalid_fields, invalid_count = 0
self.source.wkbType(),
self.source.sourceCrs())
error_fields = QgsFields() error_fields = QgsFields()
error_fields.append(QgsField('message', QVariant.String, 'string', 255)) error_fields.append(QgsField('message', QVariant.String, 'string', 255))
(self.error_output_sink, self.error_output_dest_id) = self.parameterAsSink(parameters, self.ERROR_OUTPUT, context, (error_output_sink, error_output_dest_id) = self.parameterAsSink(parameters, self.ERROR_OUTPUT, context,
error_fields, QgsWkbTypes.Point, error_fields, QgsWkbTypes.Point, source.sourceCrs())
self.source.sourceCrs()) error_count = 0
return True
def processAlgorithm(self, context, feedback): features = source.getFeatures(QgsFeatureRequest(), QgsProcessingFeatureSource.FlagSkipGeometryValidityChecks)
features = self.source.getFeatures(QgsFeatureRequest(), QgsProcessingFeatureSource.FlagSkipGeometryValidityChecks) total = 100.0 / source.featureCount() if source.featureCount() else 0
total = 100.0 / self.source.featureCount() if self.source.featureCount() else 0
for current, inFeat in enumerate(features): for current, inFeat in enumerate(features):
if feedback.isCanceled(): if feedback.isCanceled():
break break
@ -155,10 +141,10 @@ class CheckValidity(QgisAlgorithm):
valid = True valid = True
if not geom.isNull() and not geom.isEmpty(): if not geom.isNull() and not geom.isEmpty():
errors = list(geom.validateGeometry(self.method)) errors = list(geom.validateGeometry(method))
if errors: if errors:
# QGIS method return a summary at the end # QGIS method return a summary at the end
if self.method == 1: if method == 1:
errors.pop() errors.pop()
valid = False valid = False
reasons = [] reasons = []
@ -167,9 +153,9 @@ class CheckValidity(QgisAlgorithm):
error_geom = QgsGeometry.fromPoint(error.where()) error_geom = QgsGeometry.fromPoint(error.where())
errFeat.setGeometry(error_geom) errFeat.setGeometry(error_geom)
errFeat.setAttributes([error.what()]) errFeat.setAttributes([error.what()])
if self.error_output_sink: if error_output_sink:
self.error_output_sink.addFeature(errFeat, QgsFeatureSink.FastInsert) error_output_sink.addFeature(errFeat, QgsFeatureSink.FastInsert)
self.error_count += 1 error_count += 1
reasons.append(error.what()) reasons.append(error.what())
@ -183,28 +169,26 @@ class CheckValidity(QgisAlgorithm):
outFeat.setAttributes(attrs) outFeat.setAttributes(attrs)
if valid: if valid:
if self.valid_output_sink: if valid_output_sink:
self.valid_output_sink.addFeature(outFeat, QgsFeatureSink.FastInsert) valid_output_sink.addFeature(outFeat, QgsFeatureSink.FastInsert)
self.valid_count += 1 valid_count += 1
else: else:
if self.invalid_output_sink: if invalid_output_sink:
self.invalid_output_sink.addFeature(outFeat, QgsFeatureSink.FastInsert) invalid_output_sink.addFeature(outFeat, QgsFeatureSink.FastInsert)
self.invalid_count += 1 invalid_count += 1
feedback.setProgress(int(current * total)) feedback.setProgress(int(current * total))
return True
def postProcessAlgorithm(self, context, feedback):
results = { results = {
self.VALID_COUNT: self.valid_count, self.VALID_COUNT: valid_count,
self.INVALID_COUNT: self.invalid_count, self.INVALID_COUNT: invalid_count,
self.ERROR_COUNT: self.error_count self.ERROR_COUNT: error_count
} }
if self.valid_output_sink: if valid_output_sink:
results[self.VALID_OUTPUT] = self.valid_output_dest_id results[self.VALID_OUTPUT] = valid_output_dest_id
if self.invalid_output_sink: if invalid_output_sink:
results[self.INVALID_OUTPUT] = self.invalid_output_dest_id results[self.INVALID_OUTPUT] = invalid_output_dest_id
if self.error_output_sink: if error_output_sink:
results[self.ERROR_OUTPUT] = self.error_output_dest_id results[self.ERROR_OUTPUT] = error_output_dest_id
return results return results

View File

@ -53,35 +53,27 @@ class CreateAttributeIndex(QgisAlgorithm):
self.tr('Attribute to index'), None, self.INPUT)) self.tr('Attribute to index'), None, self.INPUT))
self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr('Indexed layer'))) self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr('Indexed layer')))
self.layer = None
self.field = None
def name(self): def name(self):
return 'createattributeindex' return 'createattributeindex'
def displayName(self): def displayName(self):
return self.tr('Create attribute index') return self.tr('Create attribute index')
def prepareAlgorithm(self, parameters, context, feedback): def processAlgorithm(self, parameters, context, feedback):
self.layer = self.parameterAsVectorLayer(parameters, self.INPUT, context) layer = self.parameterAsVectorLayer(parameters, self.INPUT, context)
self.field = self.parameterAsString(parameters, self.FIELD, context) field = self.parameterAsString(parameters, self.FIELD, context)
return True provider = layer.dataProvider()
def processAlgorithm(self, context, feedback): field_index = layer.fields().lookupField(field)
provider = self.layer.dataProvider() if field_index < 0 or layer.fields().fieldOrigin(field_index) != QgsFields.OriginProvider:
feedback.pushInfo(self.tr('Can not create attribute index on "{}"').format(field))
field_index = self.layer.fields().lookupField(self.field)
if field_index < 0 or self.layer.fields().fieldOrigin(field_index) != QgsFields.OriginProvider:
feedback.pushInfo(self.tr('Can not create attribute index on "{}"').format(self.field))
else: else:
provider_index = self.layer.fields().fieldOriginIndex(field_index) provider_index = layer.fields().fieldOriginIndex(field_index)
if provider.capabilities() & QgsVectorDataProvider.CreateAttributeIndex: if provider.capabilities() & QgsVectorDataProvider.CreateAttributeIndex:
if not provider.createAttributeIndex(provider_index): if not provider.createAttributeIndex(provider_index):
feedback.pushInfo(self.tr('Could not create attribute index')) feedback.pushInfo(self.tr('Could not create attribute index'))
else: else:
feedback.pushInfo(self.tr("Layer's data provider does not support " feedback.pushInfo(self.tr("Layer's data provider does not support "
"creating attribute indexes")) "creating attribute indexes"))
return True
def postProcessAlgorithm(self, context, feedback): return {self.OUTPUT: layer.id()}
return {self.OUTPUT: self.layer.id()}

View File

@ -58,56 +58,46 @@ class DeleteColumn(QgisAlgorithm):
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Output layer'))) self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Output layer')))
self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr("Output layer"))) self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr("Output layer")))
self.source = None
self.fields_to_delete = None
self.sink = None
self.dest_id = None
self.field_indices = []
def name(self): def name(self):
return 'deletecolumn' return 'deletecolumn'
def displayName(self): def displayName(self):
return self.tr('Drop field(s)') return self.tr('Drop field(s)')
def prepareAlgorithm(self, parameters, context, feedback): def processAlgorithm(self, parameters, context, feedback):
self.source = self.parameterAsSource(parameters, self.INPUT, context) source = self.parameterAsSource(parameters, self.INPUT, context)
self.fields_to_delete = self.parameterAsFields(parameters, self.COLUMNS, context) fields_to_delete = self.parameterAsFields(parameters, self.COLUMNS, context)
fields = self.source.fields() fields = source.fields()
field_indices = []
# loop through twice - first we need to build up a list of original attribute indices # loop through twice - first we need to build up a list of original attribute indices
for f in self.fields_to_delete: for f in fields_to_delete:
index = fields.lookupField(f) index = fields.lookupField(f)
self.field_indices.append(index) field_indices.append(index)
# important - make sure we remove from the end so we aren't changing used indices as we go # important - make sure we remove from the end so we aren't changing used indices as we go
self.field_indices.sort(reverse=True) field_indices.sort(reverse=True)
# this second time we make a cleaned version of the fields # this second time we make a cleaned version of the fields
for index in self.field_indices: for index in field_indices:
fields.remove(index) fields.remove(index)
(self.sink, self.dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
fields, self.source.wkbType(), self.source.sourceCrs()) fields, source.wkbType(), source.sourceCrs())
return True
def processAlgorithm(self, context, feedback): features = source.getFeatures()
features = self.source.getFeatures() total = 100.0 / source.featureCount() if source.featureCount() else 0
total = 100.0 / self.source.featureCount() if self.source.featureCount() else 0
for current, f in enumerate(features): for current, f in enumerate(features):
if feedback.isCanceled(): if feedback.isCanceled():
break break
attributes = f.attributes() attributes = f.attributes()
for index in self.field_indices: for index in field_indices:
del attributes[index] del attributes[index]
f.setAttributes(attributes) f.setAttributes(attributes)
self.sink.addFeature(f, QgsFeatureSink.FastInsert) sink.addFeature(f, QgsFeatureSink.FastInsert)
feedback.setProgress(int(current * total)) feedback.setProgress(int(current * total))
return True return {self.OUTPUT: dest_id}
def postProcessAlgorithm(self, context, feedback):
return {self.OUTPUT: self.dest_id}

View File

@ -58,40 +58,31 @@ class DeleteHoles(QgisAlgorithm):
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Cleaned'), QgsProcessingParameterDefinition.TypeVectorPolygon)) self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Cleaned'), QgsProcessingParameterDefinition.TypeVectorPolygon))
self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr('Cleaned'), QgsProcessingParameterDefinition.TypeVectorPolygon)) self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr('Cleaned'), QgsProcessingParameterDefinition.TypeVectorPolygon))
self.source = None
self.min_area = None
self.sink = None
self.dest_id = None
def name(self): def name(self):
return 'deleteholes' return 'deleteholes'
def displayName(self): def displayName(self):
return self.tr('Delete holes') return self.tr('Delete holes')
def prepareAlgorithm(self, parameters, context, feedback): def processAlgorithm(self, parameters, context, feedback):
self.source = self.parameterAsSource(parameters, self.INPUT, context) source = self.parameterAsSource(parameters, self.INPUT, context)
self.min_area = self.parameterAsDouble(parameters, self.MIN_AREA, context) min_area = self.parameterAsDouble(parameters, self.MIN_AREA, context)
if self.min_area == 0.0: if min_area == 0.0:
self.min_area = -1.0 min_area = -1.0
(self.sink, self.dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
self.source.fields(), self.source.wkbType(), self.source.sourceCrs()) source.fields(), source.wkbType(), source.sourceCrs())
return True
def processAlgorithm(self, context, feedback): features = source.getFeatures()
features = self.source.getFeatures() total = 100.0 / source.featureCount() if source.featureCount() else 0
total = 100.0 / self.source.featureCount() if self.source.featureCount() else 0
for current, f in enumerate(features): for current, f in enumerate(features):
if feedback.isCanceled(): if feedback.isCanceled():
break break
if f.hasGeometry(): if f.hasGeometry():
f.setGeometry(f.geometry().removeInteriorRings(self.min_area)) f.setGeometry(f.geometry().removeInteriorRings(min_area))
self.sink.addFeature(f, QgsFeatureSink.FastInsert) sink.addFeature(f, QgsFeatureSink.FastInsert)
feedback.setProgress(int(current * total)) feedback.setProgress(int(current * total))
return True
def postProcessAlgorithm(self, context, feedback): return {self.OUTPUT: dest_id}
return {self.OUTPUT: self.dest_id}

View File

@ -63,28 +63,21 @@ class DensifyGeometries(QgisAlgorithm):
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Densified'))) self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Densified')))
self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr('Densified'))) self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr('Densified')))
self.source = None
self.sink = None
self.vertices = None
self.dest_id = None
def name(self): def name(self):
return 'densifygeometries' return 'densifygeometries'
def displayName(self): def displayName(self):
return self.tr('Densify geometries') return self.tr('Densify geometries')
def prepareAlgorithm(self, parameters, context, feedback): def processAlgorithm(self, parameters, context, feedback):
self.source = self.parameterAsSource(parameters, self.INPUT, context) source = self.parameterAsSource(parameters, self.INPUT, context)
self.vertices = self.parameterAsInt(parameters, self.VERTICES, context) vertices = self.parameterAsInt(parameters, self.VERTICES, context)
(self.sink, self.dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
self.source.fields(), self.source.wkbType(), self.source.sourceCrs()) source.fields(), source.wkbType(), source.sourceCrs())
return True
def processAlgorithm(self, context, feedback): features = source.getFeatures()
features = self.source.getFeatures() total = 100.0 / source.featureCount() if source.featureCount() else 0
total = 100.0 / self.source.featureCount() if self.source.featureCount() else 0
for current, f in enumerate(features): for current, f in enumerate(features):
if feedback.isCanceled(): if feedback.isCanceled():
@ -92,11 +85,9 @@ class DensifyGeometries(QgisAlgorithm):
feature = f feature = f
if feature.hasGeometry(): if feature.hasGeometry():
new_geometry = feature.geometry().densifyByCount(self.vertices) new_geometry = feature.geometry().densifyByCount(vertices)
feature.setGeometry(new_geometry) feature.setGeometry(new_geometry)
self.sink.addFeature(feature, QgsFeatureSink.FastInsert) sink.addFeature(feature, QgsFeatureSink.FastInsert)
feedback.setProgress(int(current * total)) feedback.setProgress(int(current * total))
return True
def postProcessAlgorithm(self, context, feedback): return {self.OUTPUT: dest_id}
return {self.OUTPUT: self.dest_id}

View File

@ -61,40 +61,31 @@ class DensifyGeometriesInterval(QgisAlgorithm):
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Densified'))) self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Densified')))
self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr('Densified'))) self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr('Densified')))
self.source = None
self.interval = None
self.sink = None
self.dest_id = None
def name(self): def name(self):
return 'densifygeometriesgivenaninterval' return 'densifygeometriesgivenaninterval'
def displayName(self): def displayName(self):
return self.tr('Densify geometries given an interval') return self.tr('Densify geometries given an interval')
def prepareAlgorithm(self, parameters, context, feedback): def processAlgorithm(self, parameters, context, feedback):
self.source = self.parameterAsSource(parameters, self.INPUT, context) source = self.parameterAsSource(parameters, self.INPUT, context)
self.interval = self.parameterAsDouble(parameters, self.INTERVAL, context) interval = self.parameterAsDouble(parameters, self.INTERVAL, context)
(self.sink, self.dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
self.source.fields(), self.source.wkbType(), self.source.sourceCrs()) source.fields(), source.wkbType(), source.sourceCrs())
return True
def processAlgorithm(self, context, feedback): features = source.getFeatures()
features = self.source.getFeatures() total = 100.0 / source.featureCount() if source.featureCount() else 0
total = 100.0 / self.source.featureCount() if self.source.featureCount() else 0
for current, f in enumerate(features): for current, f in enumerate(features):
if feedback.isCanceled(): if feedback.isCanceled():
break break
feature = f feature = f
if feature.hasGeometry(): if feature.hasGeometry():
new_geometry = feature.geometry().densifyByDistance(float(self.interval)) new_geometry = feature.geometry().densifyByDistance(float(interval))
feature.setGeometry(new_geometry) feature.setGeometry(new_geometry)
self.sink.addFeature(feature, QgsFeatureSink.FastInsert) sink.addFeature(feature, QgsFeatureSink.FastInsert)
feedback.setProgress(int(current * total)) feedback.setProgress(int(current * total))
return True
def postProcessAlgorithm(self, context, feedback): return {self.OUTPUT: dest_id}
return {self.OUTPUT: self.dest_id}

View File

@ -55,36 +55,27 @@ class DropGeometry(QgisAlgorithm):
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Dropped geometry'))) self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Dropped geometry')))
self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr("Dropped geometry"))) self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr("Dropped geometry")))
self.source = None
self.sink = None
self.dest_id = None
def name(self): def name(self):
return 'dropgeometries' return 'dropgeometries'
def displayName(self): def displayName(self):
return self.tr('Drop geometries') return self.tr('Drop geometries')
def prepareAlgorithm(self, parameters, context, feedback): def processAlgorithm(self, parameters, context, feedback):
self.source = self.parameterAsSource(parameters, self.INPUT, context) source = self.parameterAsSource(parameters, self.INPUT, context)
(self.sink, self.dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
self.source.fields(), QgsWkbTypes.NoGeometry, QgsCoordinateReferenceSystem()) source.fields(), QgsWkbTypes.NoGeometry, QgsCoordinateReferenceSystem())
return True
def processAlgorithm(self, context, feedback):
request = QgsFeatureRequest().setFlags(QgsFeatureRequest.NoGeometry) request = QgsFeatureRequest().setFlags(QgsFeatureRequest.NoGeometry)
features = self.source.getFeatures(request) features = source.getFeatures(request)
total = 100.0 / self.source.featureCount() if self.source.featureCount() else 0 total = 100.0 / source.featureCount() if source.featureCount() else 0
for current, input_feature in enumerate(features): for current, input_feature in enumerate(features):
if feedback.isCanceled(): if feedback.isCanceled():
break break
input_feature.clearGeometry() input_feature.clearGeometry()
self.sink.addFeature(input_feature, QgsFeatureSink.FastInsert) sink.addFeature(input_feature, QgsFeatureSink.FastInsert)
feedback.setProgress(int(current * total)) feedback.setProgress(int(current * total))
return True return {self.OUTPUT: dest_id}
def postProcessAlgorithm(self, context, feedback):
return {self.OUTPUT: self.dest_id}

View File

@ -79,20 +79,15 @@ class ExtentFromLayer(QgisAlgorithm):
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Extent'))) self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Extent')))
self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr("Extent"), QgsProcessingParameterDefinition.TypeVectorPolygon)) self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr("Extent"), QgsProcessingParameterDefinition.TypeVectorPolygon))
self.source = None
self.byFeature = None
self.sink = None
self.dest_id = None
def name(self): def name(self):
return 'polygonfromlayerextent' return 'polygonfromlayerextent'
def displayName(self): def displayName(self):
return self.tr('Polygon from layer extent') return self.tr('Polygon from layer extent')
def prepareAlgorithm(self, parameters, context, feedback): def processAlgorithm(self, parameters, context, feedback):
self.source = self.parameterAsSource(parameters, self.INPUT_LAYER, context) source = self.parameterAsSource(parameters, self.INPUT_LAYER, context)
self.byFeature = self.parameterAsBool(parameters, self.BY_FEATURE, context) byFeature = self.parameterAsBool(parameters, self.BY_FEATURE, context)
fields = QgsFields() fields = QgsFields()
fields.append(QgsField('MINX', QVariant.Double)) fields.append(QgsField('MINX', QVariant.Double))
@ -106,19 +101,15 @@ class ExtentFromLayer(QgisAlgorithm):
fields.append(QgsField('HEIGHT', QVariant.Double)) fields.append(QgsField('HEIGHT', QVariant.Double))
fields.append(QgsField('WIDTH', QVariant.Double)) fields.append(QgsField('WIDTH', QVariant.Double))
(self.sink, self.dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
fields, QgsWkbTypes.Polygon, self.source.sourceCrs()) fields, QgsWkbTypes.Polygon, source.sourceCrs())
return True
def processAlgorithm(self, context, feedback): if byFeature:
if self.byFeature: self.featureExtent(source, context, sink, feedback)
self.featureExtent(self.source, context, self.sink, feedback)
else: else:
self.layerExtent(self.source, self.sink, feedback) self.layerExtent(source, sink, feedback)
return True
def postProcessAlgorithm(self, context, feedback): return {self.OUTPUT: dest_id}
return {self.OUTPUT: self.dest_id}
def layerExtent(self, source, sink, feedback): def layerExtent(self, source, sink, feedback):
rect = source.sourceExtent() rect = source.sourceExtent()

View File

@ -55,26 +55,20 @@ class FixGeometry(QgisAlgorithm):
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Fixed geometries'))) self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Fixed geometries')))
self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr("Fixed geometries"))) self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr("Fixed geometries")))
self.source = None
self.sink = None
self.dest_id = None
def name(self): def name(self):
return 'fixgeometries' return 'fixgeometries'
def displayName(self): def displayName(self):
return self.tr('Fix geometries') return self.tr('Fix geometries')
def prepareAlgorithm(self, parameters, context, feedback): def processAlgorithm(self, parameters, context, feedback):
self.source = self.parameterAsSource(parameters, self.INPUT, context) source = self.parameterAsSource(parameters, self.INPUT, context)
(self.sink, self.dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
self.source.fields(), QgsWkbTypes.multiType(self.source.wkbType()), self.source.sourceCrs()) source.fields(), QgsWkbTypes.multiType(source.wkbType()), source.sourceCrs())
return True
def processAlgorithm(self, context, feedback): features = source.getFeatures(QgsFeatureRequest(), QgsProcessingFeatureSource.FlagSkipGeometryValidityChecks)
features = self.source.getFeatures(QgsFeatureRequest(), QgsProcessingFeatureSource.FlagSkipGeometryValidityChecks) total = 100.0 / source.featureCount() if source.featureCount() else 0
total = 100.0 / self.source.featureCount() if self.source.featureCount() else 0
for current, inputFeature in enumerate(features): for current, inputFeature in enumerate(features):
if feedback.isCanceled(): if feedback.isCanceled():
break break
@ -92,7 +86,7 @@ class FixGeometry(QgisAlgorithm):
try: try:
g.convertToMultiType() g.convertToMultiType()
outputFeature.setGeometry(QgsGeometry(g)) outputFeature.setGeometry(QgsGeometry(g))
self.sink.addFeature(outputFeature, QgsFeatureSink.FastInsert) sink.addFeature(outputFeature, QgsFeatureSink.FastInsert)
except: except:
pass pass
feedback.setProgress(int(current * total)) feedback.setProgress(int(current * total))
@ -101,9 +95,7 @@ class FixGeometry(QgisAlgorithm):
outputGeometry.convertToMultiType() outputGeometry.convertToMultiType()
outputFeature.setGeometry(outputGeometry) outputFeature.setGeometry(outputGeometry)
self.sink.addFeature(outputFeature, QgsFeatureSink.FastInsert) sink.addFeature(outputFeature, QgsFeatureSink.FastInsert)
feedback.setProgress(int(current * total)) feedback.setProgress(int(current * total))
return True
def postProcessAlgorithm(self, context, feedback): return {self.OUTPUT: dest_id}
return {self.OUTPUT: self.dest_id}

View File

@ -102,52 +102,41 @@ class GridPolygon(QgisAlgorithm):
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Grid'))) self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Grid')))
self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr('Grid'), QgsProcessingParameterDefinition.TypeVectorPolygon)) self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr('Grid'), QgsProcessingParameterDefinition.TypeVectorPolygon))
self.idx = None
self.hSpacing = None
self.vSpacing = None
self.hOverlay = None
self.vOverlay = None
self.width = None
self.height = None
self.originX = None
self.originY = None
self.sink = None
self.dest_id = None
def name(self): def name(self):
return 'creategridpolygon' return 'creategridpolygon'
def displayName(self): def displayName(self):
return self.tr('Create grid (polygon)') return self.tr('Create grid (polygon)')
def prepareAlgorithm(self, parameters, context, feedback): def processAlgorithm(self, parameters, context, feedback):
self.idx = self.parameterAsEnum(parameters, self.TYPE, context) idx = self.parameterAsEnum(parameters, self.TYPE, context)
self.hSpacing = self.parameterAsDouble(parameters, self.HSPACING, context) hSpacing = self.parameterAsDouble(parameters, self.HSPACING, context)
self.vSpacing = self.parameterAsDouble(parameters, self.VSPACING, context) vSpacing = self.parameterAsDouble(parameters, self.VSPACING, context)
self.hOverlay = self.parameterAsDouble(parameters, self.HOVERLAY, context) hOverlay = self.parameterAsDouble(parameters, self.HOVERLAY, context)
self.vOverlay = self.parameterAsDouble(parameters, self.VOVERLAY, context) vOverlay = self.parameterAsDouble(parameters, self.VOVERLAY, context)
bbox = self.parameterAsExtent(parameters, self.EXTENT, context) bbox = self.parameterAsExtent(parameters, self.EXTENT, context)
crs = self.parameterAsCrs(parameters, self.CRS, context) crs = self.parameterAsCrs(parameters, self.CRS, context)
self.width = bbox.width()
self.height = bbox.height()
self.originX = bbox.xMinimum()
self.originY = bbox.yMaximum()
if self.hSpacing <= 0 or self.vSpacing <= 0: width = bbox.width()
height = bbox.height()
originX = bbox.xMinimum()
originY = bbox.yMaximum()
if hSpacing <= 0 or vSpacing <= 0:
raise GeoAlgorithmExecutionException( raise GeoAlgorithmExecutionException(
self.tr('Invalid grid spacing: {0}/{1}').format(self.hSpacing, self.vSpacing)) self.tr('Invalid grid spacing: {0}/{1}').format(hSpacing, vSpacing))
if self.width < self.hSpacing: if width < hSpacing:
raise GeoAlgorithmExecutionException( raise GeoAlgorithmExecutionException(
self.tr('Horizontal spacing is too small for the covered area')) self.tr('Horizontal spacing is too small for the covered area'))
if self.hSpacing <= self.hOverlay or self.vSpacing <= self.vOverlay: if hSpacing <= hOverlay or vSpacing <= vOverlay:
raise GeoAlgorithmExecutionException( raise GeoAlgorithmExecutionException(
self.tr('Invalid overlay: {0}/{1}').format(self.hOverlay, self.vOverlay)) self.tr('Invalid overlay: {0}/{1}').format(hOverlay, vOverlay))
if self.height < self.vSpacing: if height < vSpacing:
raise GeoAlgorithmExecutionException( raise GeoAlgorithmExecutionException(
self.tr('Vertical spacing is too small for the covered area')) self.tr('Vertical spacing is too small for the covered area'))
@ -158,24 +147,20 @@ class GridPolygon(QgisAlgorithm):
fields.append(QgsField('bottom', QVariant.Double, '', 24, 16)) fields.append(QgsField('bottom', QVariant.Double, '', 24, 16))
fields.append(QgsField('id', QVariant.Int, '', 10, 0)) fields.append(QgsField('id', QVariant.Int, '', 10, 0))
(self.sink, self.dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
fields, QgsWkbTypes.Polygon, crs) fields, QgsWkbTypes.Polygon, crs)
return True
def processAlgorithm(self, context, feedback): if idx == 0:
if self.idx == 0:
self._rectangleGrid( self._rectangleGrid(
self.sink, self.width, self.height, self.originX, self.originY, self.hSpacing, self.vSpacing, self.hOverlay, self.vOverlay, feedback) sink, width, height, originX, originY, hSpacing, vSpacing, hOverlay, vOverlay, feedback)
elif self.idx == 1: elif idx == 1:
self._diamondGrid( self._diamondGrid(
self.sink, self.width, self.height, self.originX, self.originY, self.hSpacing, self.vSpacing, self.hOverlay, self.vOverlay, feedback) sink, width, height, originX, originY, hSpacing, vSpacing, hOverlay, vOverlay, feedback)
elif self.idx == 2: elif idx == 2:
self._hexagonGrid( self._hexagonGrid(
self.sink, self.width, self.height, self.originX, self.originY, self.hSpacing, self.vSpacing, self.hOverlay, self.vOverlay, feedback) sink, width, height, originX, originY, hSpacing, vSpacing, hOverlay, vOverlay, feedback)
return True
def postProcessAlgorithm(self, context, feedback): return {self.OUTPUT: dest_id}
return {self.OUTPUT: self.dest_id}
def _rectangleGrid(self, sink, width, height, originX, originY, def _rectangleGrid(self, sink, width, height, originX, originY,
hSpacing, vSpacing, hOverlay, vOverlay, feedback): hSpacing, vSpacing, hOverlay, vOverlay, feedback):

View File

@ -27,7 +27,9 @@ __revision__ = '$Format:%H$'
from qgis.core import (QgsVectorLayerExporter, from qgis.core import (QgsVectorLayerExporter,
QgsSettings, QgsSettings,
QgsApplication,
QgsFeatureSink, QgsFeatureSink,
QgsProcessingUtils,
QgsProcessingParameterFeatureSource, QgsProcessingParameterFeatureSource,
QgsProcessingParameterString, QgsProcessingParameterString,
QgsProcessingParameterField, QgsProcessingParameterField,
@ -106,86 +108,70 @@ class ImportIntoPostGIS(QgisAlgorithm):
self.addParameter(QgsProcessingParameterBoolean(self.FORCE_SINGLEPART, self.addParameter(QgsProcessingParameterBoolean(self.FORCE_SINGLEPART,
self.tr('Create single-part geometries instead of multi-part'), False)) self.tr('Create single-part geometries instead of multi-part'), False))
self.db = None
self.schema = None
self.overwrite = None
self.createIndex = None
self.convertLowerCase = None
self.dropStringLength = None
self.forceSinglePart = None
self.primaryKeyField = None
self.encoding = None
self.source = None
self.table = None
self.providerName = None
self.geomColumn = None
def name(self): def name(self):
return 'importintopostgis' return 'importintopostgis'
def displayName(self): def displayName(self):
return self.tr('Import into PostGIS') return self.tr('Import into PostGIS')
def prepareAlgorithm(self, parameters, context, feedback): def processAlgorithm(self, parameters, context, feedback):
connection = self.parameterAsString(parameters, self.DATABASE, context) connection = self.parameterAsString(parameters, self.DATABASE, context)
self.db = postgis.GeoDB.from_name(connection) db = postgis.GeoDB.from_name(connection)
self.schema = self.parameterAsString(parameters, self.SCHEMA, context) schema = self.parameterAsString(parameters, self.SCHEMA, context)
self.overwrite = self.parameterAsBool(parameters, self.OVERWRITE, context) overwrite = self.parameterAsBool(parameters, self.OVERWRITE, context)
self.createIndex = self.parameterAsBool(parameters, self.CREATEINDEX, context) createIndex = self.parameterAsBool(parameters, self.CREATEINDEX, context)
self.convertLowerCase = self.parameterAsBool(parameters, self.LOWERCASE_NAMES, context) convertLowerCase = self.parameterAsBool(parameters, self.LOWERCASE_NAMES, context)
self.dropStringLength = self.parameterAsBool(parameters, self.DROP_STRING_LENGTH, context) dropStringLength = self.parameterAsBool(parameters, self.DROP_STRING_LENGTH, context)
self.forceSinglePart = self.parameterAsBool(parameters, self.FORCE_SINGLEPART, context) forceSinglePart = self.parameterAsBool(parameters, self.FORCE_SINGLEPART, context)
self.primaryKeyField = self.parameterAsString(parameters, self.PRIMARY_KEY, context) or 'id' primaryKeyField = self.parameterAsString(parameters, self.PRIMARY_KEY, context) or 'id'
self.encoding = self.parameterAsString(parameters, self.ENCODING, context) encoding = self.parameterAsString(parameters, self.ENCODING, context)
self.source = self.parameterAsSource(parameters, self.INPUT, context) source = self.parameterAsSource(parameters, self.INPUT, context)
self.table = self.parameterAsString(parameters, self.TABLENAME, context) table = self.parameterAsString(parameters, self.TABLENAME, context)
if self.table: if table:
self.table.strip() table.strip()
if not self.table or self.table == '': if not table or table == '':
self.table = self.source.sourceName() table = source.sourceName()
self.table = self.table.replace('.', '_') table = table.replace('.', '_')
self.table = self.table.replace(' ', '').lower()[0:62] table = table.replace(' ', '').lower()[0:62]
self.providerName = 'postgres' providerName = 'postgres'
self.geomColumn = self.parameterAsString(parameters, self.GEOMETRY_COLUMN, context) geomColumn = self.parameterAsString(parameters, self.GEOMETRY_COLUMN, context)
if not self.geomColumn: if not geomColumn:
self.geomColumn = 'geom' geomColumn = 'geom'
return True
def processAlgorithm(self, context, feedback):
options = {} options = {}
if self.overwrite: if overwrite:
options['overwrite'] = True options['overwrite'] = True
if self.convertLowerCase: if convertLowerCase:
options['lowercaseFieldNames'] = True options['lowercaseFieldNames'] = True
self.geomColumn = self.geomColumn.lower() geomColumn = geomColumn.lower()
if self.dropStringLength: if dropStringLength:
options['dropStringConstraints'] = True options['dropStringConstraints'] = True
if self.forceSinglePart: if forceSinglePart:
options['forceSinglePartGeometryType'] = True options['forceSinglePartGeometryType'] = True
# Clear geometry column for non-geometry tables # Clear geometry column for non-geometry tables
if self.source.wkbType() == QgsWkbTypes.NoGeometry: if source.wkbType() == QgsWkbTypes.NoGeometry:
self.geomColumn = None geomColumn = None
uri = self.db.uri uri = db.uri
uri.setDataSource(self.schema, self.table, self.geomColumn, '', self.primaryKeyField) uri.setDataSource(schema, table, geomColumn, '', primaryKeyField)
if self.encoding: if encoding:
options['fileEncoding'] = self.encoding options['fileEncoding'] = encoding
exporter = QgsVectorLayerExporter(uri.uri(), self.providerName, self.source.fields(), exporter = QgsVectorLayerExporter(uri.uri(), providerName, source.fields(),
self.source.wkbType(), self.source.sourceCrs(), self.overwrite, options) source.wkbType(), source.sourceCrs(), overwrite, options)
if exporter.errorCode() != QgsVectorLayerExporter.NoError: if exporter.errorCode() != QgsVectorLayerExporter.NoError:
raise GeoAlgorithmExecutionException( raise GeoAlgorithmExecutionException(
self.tr('Error importing to PostGIS\n{0}').format(exporter.errorMessage())) self.tr('Error importing to PostGIS\n{0}').format(exporter.errorMessage()))
features = self.source.getFeatures() features = source.getFeatures()
total = 100.0 / self.source.featureCount() if self.source.featureCount() else 0 total = 100.0 / source.featureCount() if source.featureCount() else 0
for current, f in enumerate(features): for current, f in enumerate(features):
if feedback.isCanceled(): if feedback.isCanceled():
break break
@ -200,13 +186,11 @@ class ImportIntoPostGIS(QgisAlgorithm):
raise GeoAlgorithmExecutionException( raise GeoAlgorithmExecutionException(
self.tr('Error importing to PostGIS\n{0}').format(exporter.errorMessage())) self.tr('Error importing to PostGIS\n{0}').format(exporter.errorMessage()))
if self.geomColumn and self.createIndex: if geomColumn and createIndex:
self.db.create_spatial_index(self.table, self.schema, self.geomColumn) db.create_spatial_index(table, schema, geomColumn)
self.db.vacuum_analyze(self.table, self.schema) db.vacuum_analyze(table, schema)
return True
def postProcessAlgorithm(self, context, feedback):
return {} return {}
def dbConnectionNames(self): def dbConnectionNames(self):

View File

@ -71,26 +71,13 @@ class ImportIntoSpatialite(QgisAlgorithm):
self.addParameter(QgsProcessingParameterBoolean(self.DROP_STRING_LENGTH, self.tr('Drop length constraints on character fields'), False)) self.addParameter(QgsProcessingParameterBoolean(self.DROP_STRING_LENGTH, self.tr('Drop length constraints on character fields'), False))
self.addParameter(QgsProcessingParameterBoolean(self.FORCE_SINGLEPART, self.tr('Create single-part geometries instead of multi-part'), False)) self.addParameter(QgsProcessingParameterBoolean(self.FORCE_SINGLEPART, self.tr('Create single-part geometries instead of multi-part'), False))
self.db = None
self.overwrite = None
self.createIndex = None
self.dropStringLength = None
self.convertLowerCase = None
self.forceSinglePart = None
self.primaryKeyField = None
self.encoding = None
self.source = None
self.table = None
self.providerName = None
self.geomColumn = None
def name(self): def name(self):
return 'importintospatialite' return 'importintospatialite'
def displayName(self): def displayName(self):
return self.tr('Import into Spatialite') return self.tr('Import into Spatialite')
def prepareAlgorithm(self, parameters, context, feedback): def processAlgorithm(self, parameters, context, feedback):
database = self.parameterAsVectorLayer(parameters, self.DATABASE, context) database = self.parameterAsVectorLayer(parameters, self.DATABASE, context)
databaseuri = database.dataProvider().dataSourceUri() databaseuri = database.dataProvider().dataSourceUri()
uri = QgsDataSourceUri(databaseuri) uri = QgsDataSourceUri(databaseuri)
@ -98,64 +85,61 @@ class ImportIntoSpatialite(QgisAlgorithm):
if '|layerid' in databaseuri: if '|layerid' in databaseuri:
databaseuri = databaseuri[:databaseuri.find('|layerid')] databaseuri = databaseuri[:databaseuri.find('|layerid')]
uri = QgsDataSourceUri('dbname=\'%s\'' % (databaseuri)) uri = QgsDataSourceUri('dbname=\'%s\'' % (databaseuri))
self.db = spatialite.GeoDB(uri) db = spatialite.GeoDB(uri)
self.overwrite = self.parameterAsBool(parameters, self.OVERWRITE, context) overwrite = self.parameterAsBool(parameters, self.OVERWRITE, context)
self.createIndex = self.parameterAsBool(parameters, self.CREATEINDEX, context) createIndex = self.parameterAsBool(parameters, self.CREATEINDEX, context)
self.convertLowerCase = self.parameterAsBool(parameters, self.LOWERCASE_NAMES, context) convertLowerCase = self.parameterAsBool(parameters, self.LOWERCASE_NAMES, context)
self.dropStringLength = self.parameterAsBool(parameters, self.DROP_STRING_LENGTH, context) dropStringLength = self.parameterAsBool(parameters, self.DROP_STRING_LENGTH, context)
self.forceSinglePart = self.parameterAsBool(parameters, self.FORCE_SINGLEPART, context) forceSinglePart = self.parameterAsBool(parameters, self.FORCE_SINGLEPART, context)
self.primaryKeyField = self.parameterAsString(parameters, self.PRIMARY_KEY, context) or 'id' primaryKeyField = self.parameterAsString(parameters, self.PRIMARY_KEY, context) or 'id'
self.encoding = self.parameterAsString(parameters, self.ENCODING, context) encoding = self.parameterAsString(parameters, self.ENCODING, context)
self.source = self.parameterAsSource(parameters, self.INPUT, context) source = self.parameterAsSource(parameters, self.INPUT, context)
self.table = self.parameterAsString(parameters, self.TABLENAME, context) table = self.parameterAsString(parameters, self.TABLENAME, context)
if self.table: if table:
self.table.strip() table.strip()
if not self.table or self.table == '': if not table or table == '':
self.table = self.source.sourceName() table = source.sourceName()
self.table = self.table.replace('.', '_') table = table.replace('.', '_')
self.table = self.table.replace(' ', '').lower() table = table.replace(' ', '').lower()
self.providerName = 'spatialite' providerName = 'spatialite'
self.geomColumn = self.parameterAsString(parameters, self.GEOMETRY_COLUMN, context) geomColumn = self.parameterAsString(parameters, self.GEOMETRY_COLUMN, context)
if not self.geomColumn: if not geomColumn:
self.geomColumn = 'geom' geomColumn = 'geom'
return True
def processAlgorithm(self, context, feedback):
options = {} options = {}
if self.overwrite: if overwrite:
options['overwrite'] = True options['overwrite'] = True
if self.convertLowerCase: if convertLowerCase:
options['lowercaseFieldNames'] = True options['lowercaseFieldNames'] = True
self.geomColumn = self.geomColumn.lower() geomColumn = geomColumn.lower()
if self.dropStringLength: if dropStringLength:
options['dropStringConstraints'] = True options['dropStringConstraints'] = True
if self.forceSinglePart: if forceSinglePart:
options['forceSinglePartGeometryType'] = True options['forceSinglePartGeometryType'] = True
# Clear geometry column for non-geometry tables # Clear geometry column for non-geometry tables
if self.source.wkbType() == QgsWkbTypes.NoGeometry: if source.wkbType() == QgsWkbTypes.NoGeometry:
self.geomColumn = None geomColumn = None
uri = self.db.uri uri = db.uri
uri.setDataSource('', self.table, self.geomColumn, '', self.primaryKeyField) uri.setDataSource('', table, geomColumn, '', primaryKeyField)
if self.encoding: if encoding:
options['fileEncoding'] = self.encoding options['fileEncoding'] = encoding
exporter = QgsVectorLayerExporter(uri.uri(), self.providerName, self.source.fields(), exporter = QgsVectorLayerExporter(uri.uri(), providerName, source.fields(),
self.source.wkbType(), self.source.sourceCrs(), self.overwrite, options) source.wkbType(), source.sourceCrs(), overwrite, options)
if exporter.errorCode() != QgsVectorLayerExporter.NoError: if exporter.errorCode() != QgsVectorLayerExporter.NoError:
raise GeoAlgorithmExecutionException( raise GeoAlgorithmExecutionException(
self.tr('Error importing to Spatialite\n{0}').format(exporter.errorMessage())) self.tr('Error importing to Spatialite\n{0}').format(exporter.errorMessage()))
features = self.source.getFeatures() features = source.getFeatures()
total = 100.0 / self.source.featureCount() if self.source.featureCount() else 0 total = 100.0 / source.featureCount() if source.featureCount() else 0
for current, f in enumerate(features): for current, f in enumerate(features):
if feedback.isCanceled(): if feedback.isCanceled():
break break
@ -170,9 +154,7 @@ class ImportIntoSpatialite(QgisAlgorithm):
raise GeoAlgorithmExecutionException( raise GeoAlgorithmExecutionException(
self.tr('Error importing to Spatialite\n{0}').format(exporter.errorMessage())) self.tr('Error importing to Spatialite\n{0}').format(exporter.errorMessage()))
if self.geomColumn and self.createIndex: if geomColumn and createIndex:
self.db.create_spatial_index(self.table, self.geomColumn) db.create_spatial_index(table, geomColumn)
return True
def postProcessAlgorithm(self, context, feedback):
return {} return {}

View File

@ -68,26 +68,19 @@ class Merge(QgisAlgorithm):
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Merged'))) self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Merged')))
self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr('Merged'))) self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr('Merged')))
self.input_layers = []
self.fields = None
self.add_layer_field = None
self.add_path_field = None
self.sink = None
self.dest_id = None
self.dest_crs = None
def name(self): def name(self):
return 'mergevectorlayers' return 'mergevectorlayers'
def displayName(self): def displayName(self):
return self.tr('Merge vector layers') return self.tr('Merge vector layers')
def prepareAlgorithm(self, parameters, context, feedback): def processAlgorithm(self, parameters, context, feedback):
self.input_layers = self.parameterAsLayerList(parameters, self.LAYERS, context) input_layers = self.parameterAsLayerList(parameters, self.LAYERS, context)
layers = [] layers = []
self.fields = QgsFields() fields = QgsFields()
totalFeatureCount = 0 totalFeatureCount = 0
for layer in self.input_layers: for layer in input_layers:
if layer.type() != QgsMapLayer.VectorLayer: if layer.type() != QgsMapLayer.VectorLayer:
raise GeoAlgorithmExecutionException( raise GeoAlgorithmExecutionException(
self.tr('All layers must be vector layers!')) self.tr('All layers must be vector layers!'))
@ -102,7 +95,7 @@ class Merge(QgisAlgorithm):
for sindex, sfield in enumerate(layer.fields()): for sindex, sfield in enumerate(layer.fields()):
found = None found = None
for dfield in self.fields: for dfield in fields:
if (dfield.name().upper() == sfield.name().upper()): if (dfield.name().upper() == sfield.name().upper()):
found = dfield found = dfield
if (dfield.type() != sfield.type()): if (dfield.type() != sfield.type()):
@ -111,38 +104,35 @@ class Merge(QgisAlgorithm):
'data type than in other layers.'.format(sfield.name(), layerSource))) 'data type than in other layers.'.format(sfield.name(), layerSource)))
if not found: if not found:
self.fields.append(sfield) fields.append(sfield)
self.add_layer_field = False add_layer_field = False
if self.fields.lookupField('layer') < 0: if fields.lookupField('layer') < 0:
self.fields.append(QgsField('layer', QVariant.String, '', 100)) fields.append(QgsField('layer', QVariant.String, '', 100))
self.add_layer_field = True add_layer_field = True
self.add_path_field = False add_path_field = False
if self.fields.lookupField('path') < 0: if fields.lookupField('path') < 0:
self.fields.append(QgsField('path', QVariant.String, '', 200)) fields.append(QgsField('path', QVariant.String, '', 200))
self.add_path_field = True add_path_field = True
total = 100.0 / totalFeatureCount if totalFeatureCount else 1 total = 100.0 / totalFeatureCount if totalFeatureCount else 1
self.dest_crs = layers[0].crs() dest_crs = layers[0].crs()
(self.sink, self.dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
self.fields, layers[0].wkbType(), self.dest_crs) fields, layers[0].wkbType(), dest_crs)
return True
def processAlgorithm(self, context, feedback):
featureCount = 0 featureCount = 0
for layer in self.layers: for layer in layers:
for feature in layer.getFeatures(QgsFeatureRequest().setDestinationCrs(self.dest_crs)): for feature in layer.getFeatures(QgsFeatureRequest().setDestinationCrs(dest_crs)):
if feedback.isCanceled(): if feedback.isCanceled():
break break
sattributes = feature.attributes() sattributes = feature.attributes()
dattributes = [] dattributes = []
for dindex, dfield in enumerate(self.fields): for dindex, dfield in enumerate(fields):
if self.add_layer_field and dfield.name() == 'layer': if add_layer_field and dfield.name() == 'layer':
dattributes.append(layer.name()) dattributes.append(layer.name())
continue continue
if self.add_path_field and dfield.name() == 'path': if add_path_field and dfield.name() == 'path':
dattributes.append(layer.publicSource()) dattributes.append(layer.publicSource())
continue continue
@ -164,10 +154,8 @@ class Merge(QgisAlgorithm):
dattributes.append(dattribute) dattributes.append(dattribute)
feature.setAttributes(dattributes) feature.setAttributes(dattributes)
self.sink.addFeature(feature, QgsFeatureSink.FastInsert) sink.addFeature(feature, QgsFeatureSink.FastInsert)
featureCount += 1 featureCount += 1
feedback.setProgress(int(featureCount * self.total)) feedback.setProgress(int(featureCount * total))
return True
def postProcessAlgorithm(self, context, feedback): return {self.OUTPUT: dest_id}
return {self.OUTPUT: self.dest_id}

View File

@ -80,49 +80,39 @@ class PointsLayerFromTable(QgisAlgorithm):
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Points from table'), type=QgsProcessingParameterDefinition.TypeVectorPoint)) self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Points from table'), type=QgsProcessingParameterDefinition.TypeVectorPoint))
self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr('Points from table'), type=QgsProcessingParameterDefinition.TypeVectorPoint)) self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr('Points from table'), type=QgsProcessingParameterDefinition.TypeVectorPoint))
self.source = None
self.x_field_index = None
self.y_field_index = None
self.z_field_index = None
self.m_field_index = None
self.sink = None
self.dest_id = None
def name(self): def name(self):
return 'createpointslayerfromtable' return 'createpointslayerfromtable'
def displayName(self): def displayName(self):
return self.tr('Create points layer from table') return self.tr('Create points layer from table')
def prepareAlgorithm(self, parameters, context, feedback): def processAlgorithm(self, parameters, context, feedback):
self.source = self.parameterAsSource(parameters, self.INPUT, context) source = self.parameterAsSource(parameters, self.INPUT, context)
fields = self.source.fields() fields = source.fields()
self.x_field_index = fields.lookupField(self.parameterAsString(parameters, self.XFIELD, context)) x_field_index = fields.lookupField(self.parameterAsString(parameters, self.XFIELD, context))
self.y_field_index = fields.lookupField(self.parameterAsString(parameters, self.YFIELD, context)) y_field_index = fields.lookupField(self.parameterAsString(parameters, self.YFIELD, context))
self.z_field_index = -1 z_field_index = -1
if self.parameterAsString(parameters, self.ZFIELD, context): if self.parameterAsString(parameters, self.ZFIELD, context):
self.z_field_index = fields.lookupField(self.parameterAsString(parameters, self.ZFIELD, context)) z_field_index = fields.lookupField(self.parameterAsString(parameters, self.ZFIELD, context))
self.m_field_index = -1 m_field_index = -1
if self.parameterAsString(parameters, self.MFIELD, context): if self.parameterAsString(parameters, self.MFIELD, context):
self.m_field_index = fields.lookupField(self.parameterAsString(parameters, self.MFIELD, context)) m_field_index = fields.lookupField(self.parameterAsString(parameters, self.MFIELD, context))
wkb_type = QgsWkbTypes.Point wkb_type = QgsWkbTypes.Point
if self.z_field_index >= 0: if z_field_index >= 0:
wkb_type = QgsWkbTypes.addZ(wkb_type) wkb_type = QgsWkbTypes.addZ(wkb_type)
if self.m_field_index >= 0: if m_field_index >= 0:
wkb_type = QgsWkbTypes.addM(wkb_type) wkb_type = QgsWkbTypes.addM(wkb_type)
target_crs = self.parameterAsCrs(parameters, self.TARGET_CRS, context) target_crs = self.parameterAsCrs(parameters, self.TARGET_CRS, context)
(self.sink, self.dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
fields, wkb_type, target_crs) fields, wkb_type, target_crs)
return True
def processAlgorithm(self, context, feedback):
request = QgsFeatureRequest().setFlags(QgsFeatureRequest.NoGeometry) request = QgsFeatureRequest().setFlags(QgsFeatureRequest.NoGeometry)
features = self.source.getFeatures(request) features = source.getFeatures()
total = 100.0 / self.source.featureCount() if self.source.featureCount() else 0 total = 100.0 / source.featureCount() if source.featureCount() else 0
for current, feature in enumerate(features): for current, feature in enumerate(features):
if feedback.isCanceled(): if feedback.isCanceled():
@ -132,20 +122,20 @@ class PointsLayerFromTable(QgisAlgorithm):
attrs = feature.attributes() attrs = feature.attributes()
try: try:
x = float(attrs[self.x_field_index]) x = float(attrs[x_field_index])
y = float(attrs[self.y_field_index]) y = float(attrs[y_field_index])
point = QgsPoint(x, y) point = QgsPoint(x, y)
if self.z_field_index >= 0: if z_field_index >= 0:
try: try:
point.addZValue(float(attrs[self.z_field_index])) point.addZValue(float(attrs[z_field_index]))
except: except:
point.addZValue(0.0) point.addZValue(0.0)
if self.m_field_index >= 0: if m_field_index >= 0:
try: try:
point.addMValue(float(attrs[self.m_field_index])) point.addMValue(float(attrs[m_field_index]))
except: except:
point.addMValue(0.0) point.addMValue(0.0)
@ -153,8 +143,6 @@ class PointsLayerFromTable(QgisAlgorithm):
except: except:
pass # no geometry pass # no geometry
self.sink.addFeature(feature) sink.addFeature(feature)
return True
def postProcessAlgorithm(self, context, feedback): return {self.OUTPUT: dest_id}
return {self.OUTPUT: self.dest_id}

View File

@ -53,28 +53,20 @@ class PostGISExecuteSQL(QgisAlgorithm):
self.addParameter(db_param) self.addParameter(db_param)
self.addParameter(QgsProcessingParameterString(self.SQL, self.tr('SQL query'))) self.addParameter(QgsProcessingParameterString(self.SQL, self.tr('SQL query')))
self.connection = None
self.sql = None
def name(self): def name(self):
return 'postgisexecutesql' return 'postgisexecutesql'
def displayName(self): def displayName(self):
return self.tr('PostGIS execute SQL') return self.tr('PostGIS execute SQL')
def prepareAlgorithm(self, parameters, context, feedback): def processAlgorithm(self, parameters, context, feedback):
self.connection = self.parameterAsString(parameters, self.DATABASE, context) connection = self.parameterAsString(parameters, self.DATABASE, context)
self.sql = self.parameterAsString(parameters, self.SQL, context).replace('\n', ' ') db = postgis.GeoDB.from_name(connection)
return True
def processAlgorithm(self, context, feedback): sql = self.parameterAsString(parameters, self.SQL, context).replace('\n', ' ')
db = postgis.GeoDB.from_name(self.connection)
try: try:
db._exec_sql_and_commit(str(self.sql)) db._exec_sql_and_commit(str(sql))
except postgis.DbError as e: except postgis.DbError as e:
raise GeoAlgorithmExecutionException( raise GeoAlgorithmExecutionException(
self.tr('Error executing SQL:\n{0}').format(str(e))) self.tr('Error executing SQL:\n{0}').format(str(e)))
return True
def postProcessAlgorithm(self, context, feedback):
return {} return {}

View File

@ -66,54 +66,42 @@ class RandomExtract(QgisAlgorithm):
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Extracted (random)'))) self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Extracted (random)')))
self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr('Extracted (random)'))) self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr('Extracted (random)')))
self.source = None
self.method = None
self.value = None
self.featureCount = None
self.sink = None
self.dest_id = None
def name(self): def name(self):
return 'randomextract' return 'randomextract'
def displayName(self): def displayName(self):
return self.tr('Random extract') return self.tr('Random extract')
def prepareAlgorithm(self, parameters, context, feedback): def processAlgorithm(self, parameters, context, feedback):
self.source = self.parameterAsSource(parameters, self.INPUT, context) source = self.parameterAsSource(parameters, self.INPUT, context)
self.method = self.parameterAsEnum(parameters, self.METHOD, context) method = self.parameterAsEnum(parameters, self.METHOD, context)
self.value = self.parameterAsInt(parameters, self.NUMBER, context)
self.featureCount = self.source.featureCount()
if self.method == 0: features = source.getFeatures()
if self.value > self.featureCount: featureCount = source.featureCount()
value = self.parameterAsInt(parameters, self.NUMBER, context)
if method == 0:
if value > featureCount:
raise GeoAlgorithmExecutionException( raise GeoAlgorithmExecutionException(
self.tr('Selected number is greater than feature count. ' self.tr('Selected number is greater than feature count. '
'Choose a lower value and try again.')) 'Choose a lower value and try again.'))
else: else:
if self.value > 100: if value > 100:
raise GeoAlgorithmExecutionException( raise GeoAlgorithmExecutionException(
self.tr("Percentage can't be greater than 100. Set a " self.tr("Percentage can't be greater than 100. Set a "
"different value and try again.")) "different value and try again."))
self.value = int(round(self.value / 100.0000, 4) * self.featureCount) value = int(round(value / 100.0000, 4) * featureCount)
(self.sink, self.dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, selran = random.sample(list(range(featureCount)), value)
self.source.fields(), self.source.wkbType(), self.source.sourceCrs())
return True (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
source.fields(), source.wkbType(), source.sourceCrs())
def processAlgorithm(self, context, feedback): total = 100.0 / featureCount if featureCount else 1
selran = random.sample(list(range(self.featureCount)), self.value)
features = self.source.getFeatures()
total = 100.0 / self.featureCount if self.featureCount else 1
for i, feat in enumerate(features): for i, feat in enumerate(features):
if feedback.isCanceled(): if feedback.isCanceled():
break break
if i in selran: if i in selran:
self.sink.addFeature(feat, QgsFeatureSink.FastInsert) sink.addFeature(feat, QgsFeatureSink.FastInsert)
feedback.setProgress(int(i * total)) feedback.setProgress(int(i * total))
return True return {self.OUTPUT: dest_id}
def postProcessAlgorithm(self, context, feedback):
return {self.OUTPUT: self.dest_id}

View File

@ -74,46 +74,38 @@ class RandomExtractWithinSubsets(QgisAlgorithm):
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Extracted (random stratified)'))) self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Extracted (random stratified)')))
self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr('Extracted (random stratified)'))) self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr('Extracted (random stratified)')))
self.source = None
self.method = None
self.field = None
self.value = None
self.sink = None
self.dest_id = None
def name(self): def name(self):
return 'randomextractwithinsubsets' return 'randomextractwithinsubsets'
def displayName(self): def displayName(self):
return self.tr('Random extract within subsets') return self.tr('Random extract within subsets')
def prepareAlgorithm(self, parameters, context, feedback): def processAlgorithm(self, parameters, context, feedback):
self.source = self.parameterAsSource(parameters, self.INPUT, context) source = self.parameterAsSource(parameters, self.INPUT, context)
self.method = self.parameterAsEnum(parameters, self.METHOD, context) method = self.parameterAsEnum(parameters, self.METHOD, context)
self.field = self.parameterAsString(parameters, self.FIELD, context) field = self.parameterAsString(parameters, self.FIELD, context)
self.value = self.parameterAsInt(parameters, self.NUMBER, context)
(self.sink, self.dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
self.source.fields(), self.source.wkbType(), self.source.sourceCrs())
return True
def processAlgorithm(self, context, feedback): index = source.fields().lookupField(field)
index = self.source.fields().lookupField(self.field)
features = self.source.getFeatures() features = source.getFeatures()
featureCount = self.source.featureCount() featureCount = source.featureCount()
unique = self.source.uniqueValues(index) unique = source.uniqueValues(index)
if self.method == 0: value = self.parameterAsInt(parameters, self.NUMBER, context)
if self.value > featureCount: if method == 0:
if value > featureCount:
raise GeoAlgorithmExecutionException( raise GeoAlgorithmExecutionException(
self.tr('Selected number is greater that feature count. ' self.tr('Selected number is greater that feature count. '
'Choose lesser value and try again.')) 'Choose lesser value and try again.'))
else: else:
if self.value > 100: if value > 100:
raise GeoAlgorithmExecutionException( raise GeoAlgorithmExecutionException(
self.tr("Percentage can't be greater than 100. Set " self.tr("Percentage can't be greater than 100. Set "
"correct value and try again.")) "correct value and try again."))
self.value = self.value / 100.0 value = value / 100.0
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
source.fields(), source.wkbType(), source.sourceCrs())
selran = [] selran = []
total = 100.0 / (featureCount * len(unique)) if featureCount else 1 total = 100.0 / (featureCount * len(unique)) if featureCount else 1
@ -127,17 +119,13 @@ class RandomExtractWithinSubsets(QgisAlgorithm):
feedback.setProgress(int(i * total)) feedback.setProgress(int(i * total))
for subset in classes.values(): for subset in classes.values():
selValue = self.value if self.method != 1 else int(round(self.value * len(subset), 0)) selValue = value if method != 1 else int(round(value * len(subset), 0))
selran.extend(random.sample(subset, selValue)) selran.extend(random.sample(subset, selValue))
total = 100.0 / featureCount if featureCount else 1 total = 100.0 / featureCount if featureCount else 1
for (i, feat) in enumerate(selran): for (i, feat) in enumerate(selran):
if feedback.isCanceled(): if feedback.isCanceled():
break break
self.sink.addFeature(feat, QgsFeatureSink.FastInsert) sink.addFeature(feat, QgsFeatureSink.FastInsert)
feedback.setProgress(int(i * total)) feedback.setProgress(int(i * total))
return {self.OUTPUT: dest_id}
return True
def postProcessAlgorithm(self, context, feedback):
return {self.OUTPUT: self.dest_id}

View File

@ -81,66 +81,55 @@ class RegularPoints(QgisAlgorithm):
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Regular points'), QgsProcessingParameterDefinition.TypeVectorPoint)) self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Regular points'), QgsProcessingParameterDefinition.TypeVectorPoint))
self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr('Regular points'), QgsProcessingParameterDefinition.TypeVectorPoint)) self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr('Regular points'), QgsProcessingParameterDefinition.TypeVectorPoint))
self.extent = None
self.spacing = None
self.inset = None
self.randomize = None
self.isSpacing = None
self.fields = None
self.sink = None
self.dest_id = None
def name(self): def name(self):
return 'regularpoints' return 'regularpoints'
def displayName(self): def displayName(self):
return self.tr('Regular points') return self.tr('Regular points')
def prepareAlgorithm(self, parameters, context, feedback): def processAlgorithm(self, parameters, context, feedback):
self.extent = self.parameterAsExtent(parameters, self.EXTENT, context) extent = self.parameterAsExtent(parameters, self.EXTENT, context)
self.spacing = self.parameterAsDouble(parameters, self.SPACING, context) spacing = self.parameterAsDouble(parameters, self.SPACING, context)
self.inset = self.parameterAsDouble(parameters, self.INSET, context) inset = self.parameterAsDouble(parameters, self.INSET, context)
self.randomize = self.parameterAsBool(parameters, self.RANDOMIZE, context) randomize = self.parameterAsBool(parameters, self.RANDOMIZE, context)
self.isSpacing = self.parameterAsBool(parameters, self.IS_SPACING, context) isSpacing = self.parameterAsBool(parameters, self.IS_SPACING, context)
crs = self.parameterAsCrs(parameters, self.CRS, context) crs = self.parameterAsCrs(parameters, self.CRS, context)
self.fields = QgsFields() fields = QgsFields()
self.fields.append(QgsField('id', QVariant.Int, '', 10, 0)) fields.append(QgsField('id', QVariant.Int, '', 10, 0))
(self.sink, self.dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
self.fields, QgsWkbTypes.Point, crs) fields, QgsWkbTypes.Point, crs)
return True
def processAlgorithm(self, context, feedback): if randomize:
if self.randomize:
seed() seed()
area = self.extent.width() * self.extent.height() area = extent.width() * extent.height()
if self.isSpacing: if isSpacing:
pSpacing = self.spacing pSpacing = spacing
else: else:
pSpacing = sqrt(area / self.spacing) pSpacing = sqrt(area / spacing)
f = QgsFeature() f = QgsFeature()
f.initAttributes(1) f.initAttributes(1)
f.setFields(self.fields) f.setFields(fields)
count = 0 count = 0
total = 100.0 / (area / pSpacing) total = 100.0 / (area / pSpacing)
y = self.extent.yMaximum() - self.inset y = extent.yMaximum() - inset
extent_geom = QgsGeometry.fromRect(self.extent) extent_geom = QgsGeometry.fromRect(extent)
extent_engine = QgsGeometry.createGeometryEngine(extent_geom.geometry()) extent_engine = QgsGeometry.createGeometryEngine(extent_geom.geometry())
extent_engine.prepareGeometry() extent_engine.prepareGeometry()
while y >= self.extent.yMinimum(): while y >= extent.yMinimum():
x = self.extent.xMinimum() + self.inset x = extent.xMinimum() + inset
while x <= self.extent.xMaximum(): while x <= extent.xMaximum():
if feedback.isCanceled(): if feedback.isCanceled():
break break
if self.randomize: if randomize:
geom = QgsGeometry().fromPoint(QgsPointXY( geom = QgsGeometry().fromPoint(QgsPointXY(
uniform(x - (pSpacing / 2.0), x + (pSpacing / 2.0)), uniform(x - (pSpacing / 2.0), x + (pSpacing / 2.0)),
uniform(y - (pSpacing / 2.0), y + (pSpacing / 2.0)))) uniform(y - (pSpacing / 2.0), y + (pSpacing / 2.0))))
@ -150,13 +139,10 @@ class RegularPoints(QgisAlgorithm):
if extent_engine.intersects(geom.geometry()): if extent_engine.intersects(geom.geometry()):
f.setAttribute('id', count) f.setAttribute('id', count)
f.setGeometry(geom) f.setGeometry(geom)
self.sink.addFeature(f, QgsFeatureSink.FastInsert) sink.addFeature(f, QgsFeatureSink.FastInsert)
x += pSpacing x += pSpacing
count += 1 count += 1
feedback.setProgress(int(count * total)) feedback.setProgress(int(count * total))
y = y - pSpacing y = y - pSpacing
return True return {self.OUTPUT: dest_id}
def postProcessAlgorithm(self, context, feedback):
return {self.OUTPUT: self.dest_id}

View File

@ -47,35 +47,27 @@ class SaveSelectedFeatures(QgisAlgorithm):
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Selection'))) self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Selection')))
self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr("Selection"))) self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr("Selection")))
self.vectorLayer = None
self.sink = None
self.dest_id = None
def name(self): def name(self):
return 'saveselectedfeatures' return 'saveselectedfeatures'
def displayName(self): def displayName(self):
return self.tr('Save selected features') return self.tr('Save selected features')
def prepareAlgorithm(self, parameters, context, feedback): def processAlgorithm(self, parameters, context, feedback):
self.vectorLayer = self.parameterAsVectorLayer(parameters, self.INPUT, context) vectorLayer = self.parameterAsVectorLayer(parameters, self.INPUT, context)
(self.sink, self.dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
self.vectorLayer.fields(), self.vectorLayer.wkbType(), self.vectorLayer.sourceCrs()) vectorLayer.fields(), vectorLayer.wkbType(), vectorLayer.sourceCrs())
return True
def processAlgorithm(self, context, feedback): features = vectorLayer.getSelectedFeatures()
features = self.vectorLayer.getSelectedFeatures() count = int(vectorLayer.selectedFeatureCount())
count = int(self.vectorLayer.selectedFeatureCount())
total = 100.0 / count if count else 1 total = 100.0 / count if count else 1
for current, feat in enumerate(features): for current, feat in enumerate(features):
if feedback.isCanceled(): if feedback.isCanceled():
break break
self.sink.addFeature(feat, QgsFeatureSink.FastInsert) sink.addFeature(feat, QgsFeatureSink.FastInsert)
feedback.setProgress(int(current * total)) feedback.setProgress(int(current * total))
return True
def postProcessAlgorithm(self, context, feedback): return {self.OUTPUT: dest_id}
return {self.OUTPUT: self.dest_id}

View File

@ -92,60 +92,47 @@ class SelectByAttribute(QgisAlgorithm):
self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr('Selected (attribute)'))) self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr('Selected (attribute)')))
self.layer = None
self.fieldName = None
self.operator = None
self.value = None
self.input = None
def name(self): def name(self):
return 'selectbyattribute' return 'selectbyattribute'
def displayName(self): def displayName(self):
return self.tr('Select by attribute') return self.tr('Select by attribute')
def prepareAlgorithm(self, parameters, context, feedback): def processAlgorithm(self, parameters, context, feedback):
self.layer = self.parameterAsVectorLayer(parameters, self.INPUT, context) layer = self.parameterAsVectorLayer(parameters, self.INPUT, context)
self.fieldName = self.parameterAsString(parameters, self.FIELD, context) fieldName = self.parameterAsString(parameters, self.FIELD, context)
self.operator = self.OPERATORS[self.parameterAsEnum(parameters, self.OPERATOR, context)] operator = self.OPERATORS[self.parameterAsEnum(parameters, self.OPERATOR, context)]
self.value = self.parameterAsString(parameters, self.VALUE, context) value = self.parameterAsString(parameters, self.VALUE, context)
self.input = parameters[self.INPUT] fields = layer.fields()
return True
def processAlgorithm(self, context, feedback): idx = layer.fields().lookupField(fieldName)
fields = self.layer.fields()
idx = self.layer.fields().lookupField(self.fieldName)
fieldType = fields[idx].type() fieldType = fields[idx].type()
if fieldType != QVariant.String and self.operator in self.STRING_OPERATORS: if fieldType != QVariant.String and operator in self.STRING_OPERATORS:
op = ''.join(['"%s", ' % o for o in self.STRING_OPERATORS]) op = ''.join(['"%s", ' % o for o in self.STRING_OPERATORS])
raise GeoAlgorithmExecutionException( raise GeoAlgorithmExecutionException(
self.tr('Operators {0} can be used only with string fields.').format(op)) self.tr('Operators {0} can be used only with string fields.').format(op))
field_ref = QgsExpression.quotedColumnRef(self.fieldName) field_ref = QgsExpression.quotedColumnRef(fieldName)
quoted_val = QgsExpression.quotedValue(self.value) quoted_val = QgsExpression.quotedValue(value)
if self.operator == 'is null': if operator == 'is null':
expression_string = '{} IS NULL'.format(field_ref) expression_string = '{} IS NULL'.format(field_ref)
elif self.operator == 'is not null': elif operator == 'is not null':
expression_string = '{} IS NOT NULL'.format(field_ref) expression_string = '{} IS NOT NULL'.format(field_ref)
elif self.operator == 'begins with': elif operator == 'begins with':
expression_string = """%s LIKE '%s%%'""" % (field_ref, self.value) expression_string = """%s LIKE '%s%%'""" % (field_ref, value)
elif self.operator == 'contains': elif operator == 'contains':
expression_string = """%s LIKE '%%%s%%'""" % (field_ref, self.value) expression_string = """%s LIKE '%%%s%%'""" % (field_ref, value)
elif self.operator == 'does not contain': elif operator == 'does not contain':
expression_string = """%s NOT LIKE '%%%s%%'""" % (field_ref, self.value) expression_string = """%s NOT LIKE '%%%s%%'""" % (field_ref, value)
else: else:
expression_string = '{} {} {}'.format(field_ref, self.operator, quoted_val) expression_string = '{} {} {}'.format(field_ref, operator, quoted_val)
expression = QgsExpression(expression_string) expression = QgsExpression(expression_string)
if expression.hasParserError(): if expression.hasParserError():
raise GeoAlgorithmExecutionException(expression.parserErrorString()) raise GeoAlgorithmExecutionException(expression.parserErrorString())
self.layer.selectByExpression(expression_string) layer.selectByExpression(expression_string)
return True return {self.OUTPUT: parameters[self.INPUT]}
def postProcessAlgorithm(self, context, feedback):
return {self.OUTPUT: self.input}

View File

@ -60,42 +60,30 @@ class SelectByExpression(QgisAlgorithm):
self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr('Selected (attribute)'))) self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr('Selected (attribute)')))
self.layer = None
self.behavior = None
self.input = None
self.expression = None
def name(self): def name(self):
return 'selectbyexpression' return 'selectbyexpression'
def displayName(self): def displayName(self):
return self.tr('Select by expression') return self.tr('Select by expression')
def prepareAlgorithm(self, parameters, context, feedback): def processAlgorithm(self, parameters, context, feedback):
self.layer = self.parameterAsVectorLayer(parameters, self.INPUT, context) layer = self.parameterAsVectorLayer(parameters, self.INPUT, context)
method = self.parameterAsEnum(parameters, self.METHOD, context) method = self.parameterAsEnum(parameters, self.METHOD, context)
if method == 0: if method == 0:
self.behavior = QgsVectorLayer.SetSelection behavior = QgsVectorLayer.SetSelection
elif method == 1: elif method == 1:
self.behavior = QgsVectorLayer.AddToSelection behavior = QgsVectorLayer.AddToSelection
elif method == 2: elif method == 2:
self.behavior = QgsVectorLayer.RemoveFromSelection behavior = QgsVectorLayer.RemoveFromSelection
elif method == 3: elif method == 3:
self.behavior = QgsVectorLayer.IntersectSelection behavior = QgsVectorLayer.IntersectSelection
self.expression = self.parameterAsString(parameters, self.EXPRESSION, context) expression = self.parameterAsString(parameters, self.EXPRESSION, context)
qExp = QgsExpression(self.expression) qExp = QgsExpression(expression)
if qExp.hasParserError(): if qExp.hasParserError():
raise GeoAlgorithmExecutionException(qExp.parserErrorString()) raise GeoAlgorithmExecutionException(qExp.parserErrorString())
self.input = parameters[self.INPUT] layer.selectByExpression(expression, behavior)
return True return {self.OUTPUT: parameters[self.INPUT]}
def processAlgorithm(self, context, feedback):
self.layer.selectByExpression(self.expression, self.behavior)
return True
def postProcessAlgorithm(self, context, feedback):
return {self.OUTPUT: self.input}

View File

@ -76,37 +76,28 @@ class SimplifyGeometries(QgisAlgorithm):
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Simplified'))) self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Simplified')))
self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr('Simplified'))) self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr('Simplified')))
self.source = None
self.tolerance = None
self.method = None
self.sink = None
self.dest_id = None
def name(self): def name(self):
return 'simplifygeometries' return 'simplifygeometries'
def displayName(self): def displayName(self):
return self.tr('Simplify geometries') return self.tr('Simplify geometries')
def prepareAlgorithm(self, parameters, context, feedback): def processAlgorithm(self, parameters, context, feedback):
self.source = self.parameterAsSource(parameters, self.INPUT, context) source = self.parameterAsSource(parameters, self.INPUT, context)
self.tolerance = self.parameterAsDouble(parameters, self.TOLERANCE, context) tolerance = self.parameterAsDouble(parameters, self.TOLERANCE, context)
self.method = self.parameterAsEnum(parameters, self.METHOD, context) method = self.parameterAsEnum(parameters, self.METHOD, context)
(self.sink, self.dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
self.source.fields(), self.source.wkbType(), self.source.sourceCrs())
return True
def processAlgorithm(self, context, feedback):
pointsBefore = 0 pointsBefore = 0
pointsAfter = 0 pointsAfter = 0
features = self.source.getFeatures() (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
total = 100.0 / self.source.featureCount() if self.source.featureCount() else 0 source.fields(), source.wkbType(), source.sourceCrs())
simplifier = None features = source.getFeatures()
if self.method != 0: total = 100.0 / source.featureCount() if source.featureCount() else 0
simplifier = QgsMapToPixelSimplifier(QgsMapToPixelSimplifier.SimplifyGeometry, self.tolerance, self.method)
if method != 0:
simplifier = QgsMapToPixelSimplifier(QgsMapToPixelSimplifier.SimplifyGeometry, tolerance, method)
for current, input_feature in enumerate(features): for current, input_feature in enumerate(features):
if feedback.isCanceled(): if feedback.isCanceled():
@ -116,20 +107,18 @@ class SimplifyGeometries(QgisAlgorithm):
input_geometry = input_feature.geometry() input_geometry = input_feature.geometry()
pointsBefore += input_geometry.geometry().nCoordinates() pointsBefore += input_geometry.geometry().nCoordinates()
if self.method == 0: # distance if method == 0: # distance
output_geometry = input_geometry.simplify(self.tolerance) output_geometry = input_geometry.simplify(tolerance)
else: else:
output_geometry = simplifier.simplify(input_geometry) output_geometry = simplifier.simplify(input_geometry)
pointsAfter += output_geometry.geometry().nCoordinates() pointsAfter += output_geometry.geometry().nCoordinates()
out_feature.setGeometry(output_geometry) out_feature.setGeometry(output_geometry)
self.sink.addFeature(out_feature, QgsFeatureSink.FastInsert) sink.addFeature(out_feature, QgsFeatureSink.FastInsert)
feedback.setProgress(int(current * total)) feedback.setProgress(int(current * total))
QgsMessageLog.logMessage(self.tr('Simplify: Input geometries have been simplified from {0} to {1} points').format(pointsBefore, pointsAfter), QgsMessageLog.logMessage(self.tr('Simplify: Input geometries have been simplified from {0} to {1} points').format(pointsBefore, pointsAfter),
self.tr('Processing'), QgsMessageLog.INFO) self.tr('Processing'), QgsMessageLog.INFO)
return True
def postProcessAlgorithm(self, context, feedback): return {self.OUTPUT: dest_id}
return {self.OUTPUT: self.dest_id}

View File

@ -66,48 +66,37 @@ class Smooth(QgisAlgorithm):
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Smoothed'))) self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Smoothed')))
self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr('Smoothed'))) self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr('Smoothed')))
self.source = None
self.iterations = None
self.offset = None
self.max_angle = None
self.sink = None
self.dest_id = None
def name(self): def name(self):
return 'smoothgeometry' return 'smoothgeometry'
def displayName(self): def displayName(self):
return self.tr('Smooth geometry') return self.tr('Smooth geometry')
def prepareAlgorithm(self, parameters, context, feedback): def processAlgorithm(self, parameters, context, feedback):
self.source = self.parameterAsSource(parameters, self.INPUT, context) source = self.parameterAsSource(parameters, self.INPUT, context)
self.iterations = self.parameterAsInt(parameters, self.ITERATIONS, context) iterations = self.parameterAsInt(parameters, self.ITERATIONS, context)
self.offset = self.parameterAsDouble(parameters, self.OFFSET, context) offset = self.parameterAsDouble(parameters, self.OFFSET, context)
self.max_angle = self.parameterAsDouble(parameters, self.MAX_ANGLE, context) max_angle = self.parameterAsDouble(parameters, self.MAX_ANGLE, context)
(self.sink, self.dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
self.source.fields(), self.source.wkbType(), self.source.sourceCrs()) source.fields(), source.wkbType(), source.sourceCrs())
return True
def processAlgorithm(self, context, feedback): features = source.getFeatures()
features = self.source.getFeatures() total = 100.0 / source.featureCount() if source.featureCount() else 0
total = 100.0 / self.source.featureCount() if self.source.featureCount() else 0
for current, input_feature in enumerate(features): for current, input_feature in enumerate(features):
if feedback.isCanceled(): if feedback.isCanceled():
break break
output_feature = input_feature output_feature = input_feature
if input_feature.geometry(): if input_feature.geometry():
output_geometry = input_feature.geometry().smooth(self.iterations, self.offset, -1, self.max_angle) output_geometry = input_feature.geometry().smooth(iterations, offset, -1, max_angle)
if not output_geometry: if not output_geometry:
raise GeoAlgorithmExecutionException( raise GeoAlgorithmExecutionException(
self.tr('Error smoothing geometry')) self.tr('Error smoothing geometry'))
output_feature.setGeometry(output_geometry) output_feature.setGeometry(output_geometry)
self.sink.addFeature(output_feature, QgsFeatureSink.FastInsert) sink.addFeature(output_feature, QgsFeatureSink.FastInsert)
feedback.setProgress(int(current * total)) feedback.setProgress(int(current * total))
return True
def postProcessAlgorithm(self, context, feedback): return {self.OUTPUT: dest_id}
return {self.OUTPUT: self.dest_id}

View File

@ -49,34 +49,26 @@ class SpatialiteExecuteSQL(QgisAlgorithm):
self.addParameter(QgsProcessingParameterVectorLayer(self.DATABASE, self.tr('File Database'), False, False)) self.addParameter(QgsProcessingParameterVectorLayer(self.DATABASE, self.tr('File Database'), False, False))
self.addParameter(QgsProcessingParameterString(self.SQL, self.tr('SQL query'), '', True)) self.addParameter(QgsProcessingParameterString(self.SQL, self.tr('SQL query'), '', True))
self.database = None
self.sql = None
def name(self): def name(self):
return 'spatialiteexecutesql' return 'spatialiteexecutesql'
def displayName(self): def displayName(self):
return self.tr('Spatialite execute SQL') return self.tr('Spatialite execute SQL')
def prepareAlgorithm(self, parameters, context, feedback): def processAlgorithm(self, parameters, context, feedback):
self.database = self.parameterAsVectorLayer(parameters, self.DATABASE, context) database = self.parameterAsVectorLayer(parameters, self.DATABASE, context)
self.sql = self.parameterAsString(parameters, self.SQL, context).replace('\n', ' ') databaseuri = database.dataProvider().dataSourceUri()
return True
def processAlgorithm(self, context, feedback):
databaseuri = self.database.dataProvider().dataSourceUri()
uri = QgsDataSourceUri(databaseuri) uri = QgsDataSourceUri(databaseuri)
if uri.database() is '': if uri.database() is '':
if '|layerid' in databaseuri: if '|layerid' in databaseuri:
databaseuri = databaseuri[:databaseuri.find('|layerid')] databaseuri = databaseuri[:databaseuri.find('|layerid')]
uri = QgsDataSourceUri('dbname=\'%s\'' % (databaseuri)) uri = QgsDataSourceUri('dbname=\'%s\'' % (databaseuri))
db = spatialite.GeoDB(uri) db = spatialite.GeoDB(uri)
sql = self.parameterAsString(parameters, self.SQL, context).replace('\n', ' ')
try: try:
db._exec_sql_and_commit(str(self.sql)) db._exec_sql_and_commit(str(sql))
except spatialite.DbError as e: except spatialite.DbError as e:
raise GeoAlgorithmExecutionException( raise GeoAlgorithmExecutionException(
self.tr('Error executing SQL:\n{0}').format(str(e))) self.tr('Error executing SQL:\n{0}').format(str(e)))
return True
def postProcessAlgorithm(self, context, feedback):
return {} return {}

View File

@ -70,39 +70,32 @@ class SymmetricalDifference(QgisAlgorithm):
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Symmetrical difference'))) self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Symmetrical difference')))
self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr('Symmetrical difference'))) self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr('Symmetrical difference')))
self.sourceA = None
self.sourceB = None
self.sink = None
self.dest_id = None
def name(self): def name(self):
return 'symmetricaldifference' return 'symmetricaldifference'
def displayName(self): def displayName(self):
return self.tr('Symmetrical difference') return self.tr('Symmetrical difference')
def prepareAlgorithm(self, parameters, context, feedback): def processAlgorithm(self, parameters, context, feedback):
self.sourceA = self.parameterAsSource(parameters, self.INPUT, context) sourceA = self.parameterAsSource(parameters, self.INPUT, context)
self.sourceB = self.parameterAsSource(parameters, self.OVERLAY, context) sourceB = self.parameterAsSource(parameters, self.OVERLAY, context)
geomType = QgsWkbTypes.multiType(self.sourceA.wkbType()) geomType = QgsWkbTypes.multiType(sourceA.wkbType())
fields = vector.combineFields(self.sourceA.fields(), self.sourceB.fields()) fields = vector.combineFields(sourceA.fields(), sourceB.fields())
(self.sink, self.dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
fields, geomType, self.sourceA.sourceCrs()) fields, geomType, sourceA.sourceCrs())
return True
def processAlgorithm(self, context, feedback):
featB = QgsFeature() featB = QgsFeature()
outFeat = QgsFeature() outFeat = QgsFeature()
indexA = QgsSpatialIndex(self.sourceA) indexA = QgsSpatialIndex(sourceA)
indexB = QgsSpatialIndex(self.sourceB.getFeatures(QgsFeatureRequest().setSubsetOfAttributes([]).setDestinationCrs(self.sourceA.sourceCrs()))) indexB = QgsSpatialIndex(sourceB.getFeatures(QgsFeatureRequest().setSubsetOfAttributes([]).setDestinationCrs(sourceA.sourceCrs())))
total = 100.0 / (self.sourceA.featureCount() * self.sourceB.featureCount()) if self.sourceA.featureCount() and self.sourceB.featureCount() else 1 total = 100.0 / (sourceA.featureCount() * sourceB.featureCount()) if sourceA.featureCount() and sourceB.featureCount() else 1
count = 0 count = 0
for featA in self.sourceA.getFeatures(): for featA in sourceA.getFeatures():
if feedback.isCanceled(): if feedback.isCanceled():
break break
@ -111,8 +104,8 @@ class SymmetricalDifference(QgisAlgorithm):
attrs = featA.attributes() attrs = featA.attributes()
intersects = indexB.intersects(geom.boundingBox()) intersects = indexB.intersects(geom.boundingBox())
request = QgsFeatureRequest().setFilterFids(intersects).setSubsetOfAttributes([]) request = QgsFeatureRequest().setFilterFids(intersects).setSubsetOfAttributes([])
request.setDestinationCrs(self.sourceA.sourceCrs()) request.setDestinationCrs(sourceA.sourceCrs())
for featB in self.sourceB.getFeatures(request): for featB in sourceB.getFeatures(request):
if feedback.isCanceled(): if feedback.isCanceled():
break break
tmpGeom = featB.geometry() tmpGeom = featB.geometry()
@ -122,7 +115,7 @@ class SymmetricalDifference(QgisAlgorithm):
try: try:
outFeat.setGeometry(diffGeom) outFeat.setGeometry(diffGeom)
outFeat.setAttributes(attrs) outFeat.setAttributes(attrs)
self.sink.addFeature(outFeat, QgsFeatureSink.FastInsert) sink.addFeature(outFeat, QgsFeatureSink.FastInsert)
except: except:
QgsMessageLog.logMessage(self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.'), QgsMessageLog.logMessage(self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.'),
self.tr('Processing'), QgsMessageLog.WARNING) self.tr('Processing'), QgsMessageLog.WARNING)
@ -131,9 +124,9 @@ class SymmetricalDifference(QgisAlgorithm):
count += 1 count += 1
feedback.setProgress(int(count * total)) feedback.setProgress(int(count * total))
length = len(self.sourceA.fields()) length = len(sourceA.fields())
for featA in self.sourceB.getFeatures(QgsFeatureRequest().setDestinationCrs(self.sourceA.sourceCrs())): for featA in sourceB.getFeatures(QgsFeatureRequest().setDestinationCrs(sourceA.sourceCrs())):
if feedback.isCanceled(): if feedback.isCanceled():
break break
@ -143,7 +136,7 @@ class SymmetricalDifference(QgisAlgorithm):
attrs = [NULL] * length + attrs attrs = [NULL] * length + attrs
intersects = indexA.intersects(geom.boundingBox()) intersects = indexA.intersects(geom.boundingBox())
request = QgsFeatureRequest().setFilterFids(intersects).setSubsetOfAttributes([]) request = QgsFeatureRequest().setFilterFids(intersects).setSubsetOfAttributes([])
for featB in self.sourceA.getFeatures(request): for featB in sourceA.getFeatures(request):
if feedback.isCanceled(): if feedback.isCanceled():
break break
@ -154,7 +147,7 @@ class SymmetricalDifference(QgisAlgorithm):
try: try:
outFeat.setGeometry(diffGeom) outFeat.setGeometry(diffGeom)
outFeat.setAttributes(attrs) outFeat.setAttributes(attrs)
self.sink.addFeature(outFeat, QgsFeatureSink.FastInsert) sink.addFeature(outFeat, QgsFeatureSink.FastInsert)
except: except:
QgsMessageLog.logMessage(self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.'), QgsMessageLog.logMessage(self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.'),
self.tr('Processing'), QgsMessageLog.WARNING) self.tr('Processing'), QgsMessageLog.WARNING)
@ -162,7 +155,5 @@ class SymmetricalDifference(QgisAlgorithm):
count += 1 count += 1
feedback.setProgress(int(count * total)) feedback.setProgress(int(count * total))
return True
def postProcessAlgorithm(self, context, feedback): return {self.OUTPUT: dest_id}
return {self.OUTPUT: self.dest_id}

View File

@ -66,51 +66,42 @@ class VectorSplit(QgisAlgorithm):
self.addOutput(QgsProcessingOutputFolder(self.OUTPUT, self.tr('Output directory'))) self.addOutput(QgsProcessingOutputFolder(self.OUTPUT, self.tr('Output directory')))
self.source = None
self.fieldName = None
self.directory = None
self.uniqueValues = None
self.sinks = {}
def name(self): def name(self):
return 'splitvectorlayer' return 'splitvectorlayer'
def displayName(self): def displayName(self):
return self.tr('Split vector layer') return self.tr('Split vector layer')
def prepareAlgorithm(self, parameters, context, feedback): def processAlgorithm(self, parameters, context, feedback):
self.source = self.parameterAsSource(parameters, self.INPUT, context) source = self.parameterAsSource(parameters, self.INPUT, context)
self.fieldName = self.parameterAsString(parameters, self.FIELD, context) fieldName = self.parameterAsString(parameters, self.FIELD, context)
self.directory = self.parameterAsString(parameters, self.OUTPUT, context) directory = self.parameterAsString(parameters, self.OUTPUT, context)
mkdir(self.directory)
fieldIndex = self.source.fields().lookupField(self.fieldName) mkdir(directory)
self.uniqueValues = self.source.uniqueValues(fieldIndex)
baseName = os.path.join(self.directory, '{0}'.format(self.fieldName)) fieldIndex = source.fields().lookupField(fieldName)
self.sinks = {} uniqueValues = source.uniqueValues(fieldIndex)
for current, i in enumerate(self.uniqueValues): baseName = os.path.join(directory, '{0}'.format(fieldName))
fields = source.fields()
crs = source.sourceCrs()
geomType = source.wkbType()
total = 100.0 / len(uniqueValues) if uniqueValues else 1
for current, i in enumerate(uniqueValues):
if feedback.isCanceled(): if feedback.isCanceled():
break break
fName = u'{0}_{1}.shp'.format(baseName, str(i).strip()) fName = u'{0}_{1}.shp'.format(baseName, str(i).strip())
feedback.pushInfo(self.tr('Creating layer: {}').format(fName)) feedback.pushInfo(self.tr('Creating layer: {}').format(fName))
sink, dest = QgsProcessingUtils.createFeatureSink(fName, context, self.source.fields, self.source.wkbType(), self.source.sourceCrs())
self.sinks[i] = sink
return True
def processAlgorithm(self, context, feedback): sink, dest = QgsProcessingUtils.createFeatureSink(fName, context, fields, geomType, crs)
total = 100.0 / len(self.uniqueValues) if self.uniqueValues else 1
for current, i in enumerate(self.uniqueValues):
if feedback.isCanceled():
break
sink = self.sinks[i] filter = '{} = {}'.format(QgsExpression.quotedColumnRef(fieldName), QgsExpression.quotedValue(i))
filter = '{} = {}'.format(QgsExpression.quotedColumnRef(self.fieldName), QgsExpression.quotedValue(i))
req = QgsFeatureRequest().setFilterExpression(filter) req = QgsFeatureRequest().setFilterExpression(filter)
count = 0 count = 0
for f in self.source.getFeatures(req): for f in source.getFeatures(req):
if feedback.isCanceled(): if feedback.isCanceled():
break break
sink.addFeature(f, QgsFeatureSink.FastInsert) sink.addFeature(f, QgsFeatureSink.FastInsert)
@ -119,7 +110,5 @@ class VectorSplit(QgisAlgorithm):
del sink del sink
feedback.setProgress(int(current * total)) feedback.setProgress(int(current * total))
return True
def postProcessAlgorithm(self, context, feedback): return {self.OUTPUT: directory}
return {self.OUTPUT: self.directory}

View File

@ -121,14 +121,11 @@ class ZonalStatistics(QgisAlgorithm):
self.rasterLayer = self.parameterAsRasterLayer(parameters, self.INPUT_RASTER, context) self.rasterLayer = self.parameterAsRasterLayer(parameters, self.INPUT_RASTER, context)
return True return True
def processAlgorithm(self, context, feedback): def processAlgorithm(self, parameters, context, feedback):
zs = QgsZonalStatistics(self.vectorLayer, zs = QgsZonalStatistics(self.vectorLayer,
self.rasterLayer, self.rasterLayer,
self.columnPrefix, self.columnPrefix,
self.bandNumber, self.bandNumber,
QgsZonalStatistics.Statistics(self.selectedStats)) QgsZonalStatistics.Statistics(self.selectedStats))
zs.calculateStatistics(feedback) zs.calculateStatistics(feedback)
return True
def postProcessAlgorithm(self, context, feedback):
return {self.INPUT_VECTOR: self.vectorLayer} return {self.INPUT_VECTOR: self.vectorLayer}

View File

@ -248,7 +248,7 @@ class ScriptAlgorithm(QgsProcessingAlgorithm):
return True return True
def processAlgorithm(self, context, feedback): def processAlgorithm(self, parameters, context, feedback):
self.ns['feedback'] = feedback self.ns['feedback'] = feedback
self.ns['context'] = context self.ns['context'] = context
@ -257,9 +257,6 @@ class ScriptAlgorithm(QgsProcessingAlgorithm):
for out in self.outputDefinitions(): for out in self.outputDefinitions():
self.results[out.name()] = self.ns[out.name()] self.results[out.name()] = self.ns[out.name()]
del self.ns del self.ns
return True
def postProcessAlgorithm(self, context, feedback):
return self.results return self.results
def helpUrl(self): def helpUrl(self):

View File

@ -138,7 +138,7 @@ class AlgorithmsTest(object):
pass pass
else: else:
results, ok = alg.run(parameters, context, feedback) results, ok = alg.run(parameters, context, feedback)
self.assertTrue(ok, parameters) self.assertTrue(ok, 'params: {}, results: {}'.format(parameters, results))
self.check_results(results, context, defs['params'], defs['results']) self.check_results(results, context, defs['params'], defs['results'])
def load_params(self, params): def load_params(self, params):

View File

@ -89,27 +89,23 @@ QgsCentroidAlgorithm *QgsCentroidAlgorithm::create() const
return new QgsCentroidAlgorithm(); return new QgsCentroidAlgorithm();
} }
bool QgsCentroidAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback * ) QVariantMap QgsCentroidAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
{ {
mSource.reset( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) ); std::unique_ptr< QgsFeatureSource > source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
if ( !mSource ) if ( !source )
return false; return QVariantMap();
mSink.reset( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, mSinkId, mSource->fields(), QgsWkbTypes::Point, mSource->sourceCrs() ) ); QString dest;
if ( !mSink ) std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, source->fields(), QgsWkbTypes::Point, source->sourceCrs() ) );
return false; if ( !sink )
return QVariantMap();
return true; long count = source->featureCount();
} if ( count <= 0 )
return QVariantMap();
bool QgsCentroidAlgorithm::processAlgorithm( QgsProcessingContext &, QgsProcessingFeedback *feedback )
{
long count = mSource->featureCount();
if ( count == 0 )
return true;
QgsFeature f; QgsFeature f;
QgsFeatureIterator it = mSource->getFeatures(); QgsFeatureIterator it = source->getFeatures();
double step = 100.0 / count; double step = 100.0 / count;
int current = 0; int current = 0;
@ -129,19 +125,14 @@ bool QgsCentroidAlgorithm::processAlgorithm( QgsProcessingContext &, QgsProcessi
QgsMessageLog::logMessage( QObject::tr( "Error calculating centroid for feature %1" ).arg( f.id() ), QObject::tr( "Processing" ), QgsMessageLog::WARNING ); QgsMessageLog::logMessage( QObject::tr( "Error calculating centroid for feature %1" ).arg( f.id() ), QObject::tr( "Processing" ), QgsMessageLog::WARNING );
} }
} }
mSink->addFeature( out, QgsFeatureSink::FastInsert ); sink->addFeature( out, QgsFeatureSink::FastInsert );
feedback->setProgress( current * step ); feedback->setProgress( current * step );
current++; current++;
} }
mSink->flushBuffer();
return true;
}
QVariantMap QgsCentroidAlgorithm::postProcessAlgorithm( QgsProcessingContext &, QgsProcessingFeedback * )
{
QVariantMap outputs; QVariantMap outputs;
outputs.insert( QStringLiteral( "OUTPUT" ), mSinkId ); outputs.insert( QStringLiteral( "OUTPUT" ), dest );
return outputs; return outputs;
} }
@ -178,47 +169,37 @@ QgsBufferAlgorithm *QgsBufferAlgorithm::create() const
return new QgsBufferAlgorithm(); return new QgsBufferAlgorithm();
} }
bool QgsBufferAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback * ) QVariantMap QgsBufferAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
{ {
mSource.reset( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) ); std::unique_ptr< QgsFeatureSource > source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
if ( !mSource ) if ( !source )
return false; return QVariantMap();
mSink.reset( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, mSinkId, mSource->fields(), QgsWkbTypes::Polygon, mSource->sourceCrs() ) ); QString dest;
if ( !mSink ) std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, source->fields(), QgsWkbTypes::Polygon, source->sourceCrs() ) );
return false; if ( !sink )
return QVariantMap();
// fixed parameters // fixed parameters
mDissolve = parameterAsBool( parameters, QStringLiteral( "DISSOLVE" ), context ); bool dissolve = parameterAsBool( parameters, QStringLiteral( "DISSOLVE" ), context );
mSegments = parameterAsInt( parameters, QStringLiteral( "SEGMENTS" ), context ); int segments = parameterAsInt( parameters, QStringLiteral( "SEGMENTS" ), context );
mEndCapStyle = static_cast< QgsGeometry::EndCapStyle >( 1 + parameterAsInt( parameters, QStringLiteral( "END_CAP_STYLE" ), context ) ); QgsGeometry::EndCapStyle endCapStyle = static_cast< QgsGeometry::EndCapStyle >( 1 + parameterAsInt( parameters, QStringLiteral( "END_CAP_STYLE" ), context ) );
mJoinStyle = static_cast< QgsGeometry::JoinStyle>( 1 + parameterAsInt( parameters, QStringLiteral( "JOIN_STYLE" ), context ) ); QgsGeometry::JoinStyle joinStyle = static_cast< QgsGeometry::JoinStyle>( 1 + parameterAsInt( parameters, QStringLiteral( "JOIN_STYLE" ), context ) );
mMiterLimit = parameterAsDouble( parameters, QStringLiteral( "MITRE_LIMIT" ), context ); double miterLimit = parameterAsDouble( parameters, QStringLiteral( "MITRE_LIMIT" ), context );
mBufferDistance = parameterAsDouble( parameters, QStringLiteral( "DISTANCE" ), context ); double bufferDistance = parameterAsDouble( parameters, QStringLiteral( "DISTANCE" ), context );
mDynamicBuffer = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "DISTANCE" ) ); bool dynamicBuffer = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "DISTANCE" ) );
if ( mDynamicBuffer ) const QgsProcessingParameterDefinition *distanceParamDef = parameterDefinition( QStringLiteral( "DISTANCE" ) );
{
mDynamicBufferProperty = parameters.value( QStringLiteral( "DISTANCE" ) ).value< QgsProperty >();
mExpContext = context.expressionContext();
mDefaultBuffer = parameterDefinition( QStringLiteral( "DISTANCE" ) )->defaultValue().toDouble();
}
return true;
}
bool QgsBufferAlgorithm::processAlgorithm( QgsProcessingContext &, QgsProcessingFeedback *feedback ) long count = source->featureCount();
{ if ( count <= 0 )
long count = mSource->featureCount(); return QVariantMap();
if ( count == 0 )
return false;
QgsFeature f; QgsFeature f;
QgsFeatureIterator it = mSource->getFeatures(); QgsFeatureIterator it = source->getFeatures();
double step = 100.0 / count; double step = 100.0 / count;
int current = 0; int current = 0;
double bufferDistance = mBufferDistance;
QList< QgsGeometry > bufferedGeometriesForDissolve; QList< QgsGeometry > bufferedGeometriesForDissolve;
QgsAttributes dissolveAttrs; QgsAttributes dissolveAttrs;
@ -234,50 +215,45 @@ bool QgsBufferAlgorithm::processAlgorithm( QgsProcessingContext &, QgsProcessing
QgsFeature out = f; QgsFeature out = f;
if ( out.hasGeometry() ) if ( out.hasGeometry() )
{ {
if ( mDynamicBuffer ) if ( dynamicBuffer )
{ {
mExpContext.setFeature( f ); context.expressionContext().setFeature( f );
bufferDistance = mDynamicBufferProperty.valueAsDouble( mExpContext, mDefaultBuffer ); bufferDistance = QgsProcessingParameters::parameterAsDouble( distanceParamDef, parameters, context );
} }
QgsGeometry outputGeometry = f.geometry().buffer( bufferDistance, mSegments, mEndCapStyle, mJoinStyle, mMiterLimit ); QgsGeometry outputGeometry = f.geometry().buffer( bufferDistance, segments, endCapStyle, joinStyle, miterLimit );
if ( !outputGeometry ) if ( !outputGeometry )
{ {
QgsMessageLog::logMessage( QObject::tr( "Error calculating buffer for feature %1" ).arg( f.id() ), QObject::tr( "Processing" ), QgsMessageLog::WARNING ); QgsMessageLog::logMessage( QObject::tr( "Error calculating buffer for feature %1" ).arg( f.id() ), QObject::tr( "Processing" ), QgsMessageLog::WARNING );
} }
if ( mDissolve ) if ( dissolve )
bufferedGeometriesForDissolve << outputGeometry; bufferedGeometriesForDissolve << outputGeometry;
else else
out.setGeometry( outputGeometry ); out.setGeometry( outputGeometry );
} }
if ( !mDissolve ) if ( !dissolve )
mSink->addFeature( out, QgsFeatureSink::FastInsert ); sink->addFeature( out, QgsFeatureSink::FastInsert );
feedback->setProgress( current * step ); feedback->setProgress( current * step );
current++; current++;
} }
if ( mDissolve ) if ( dissolve )
{ {
QgsGeometry finalGeometry = QgsGeometry::unaryUnion( bufferedGeometriesForDissolve ); QgsGeometry finalGeometry = QgsGeometry::unaryUnion( bufferedGeometriesForDissolve );
QgsFeature f; QgsFeature f;
f.setGeometry( finalGeometry ); f.setGeometry( finalGeometry );
f.setAttributes( dissolveAttrs ); f.setAttributes( dissolveAttrs );
mSink->addFeature( f, QgsFeatureSink::FastInsert ); sink->addFeature( f, QgsFeatureSink::FastInsert );
} }
mSink->flushBuffer();
return true;
}
QVariantMap QgsBufferAlgorithm::postProcessAlgorithm( QgsProcessingContext &, QgsProcessingFeedback * )
{
QVariantMap outputs; QVariantMap outputs;
outputs.insert( QStringLiteral( "OUTPUT" ), mSinkId ); outputs.insert( QStringLiteral( "OUTPUT" ), dest );
return outputs; return outputs;
} }
QgsDissolveAlgorithm::QgsDissolveAlgorithm() QgsDissolveAlgorithm::QgsDissolveAlgorithm()
{ {
addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ), QObject::tr( "Input layer" ) ) ); addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ), QObject::tr( "Input layer" ) ) );
@ -302,34 +278,31 @@ QgsDissolveAlgorithm *QgsDissolveAlgorithm::create() const
return new QgsDissolveAlgorithm(); return new QgsDissolveAlgorithm();
} }
bool QgsDissolveAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback * ) QVariantMap QgsDissolveAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
{ {
mSource.reset( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) ); std::unique_ptr< QgsFeatureSource > source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
if ( !mSource ) if ( !source )
return false; return QVariantMap();
mSink.reset( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, mSinkId, mSource->fields(), QgsWkbTypes::multiType( mSource->wkbType() ), mSource->sourceCrs() ) ); QString dest;
std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, source->fields(), QgsWkbTypes::multiType( source->wkbType() ), source->sourceCrs() ) );
if ( !mSink ) if ( !sink )
return false; return QVariantMap();
mFields = parameterAsFields( parameters, QStringLiteral( "FIELD" ), context ); QStringList fields = parameterAsFields( parameters, QStringLiteral( "FIELD" ), context );
return true;
}
bool QgsDissolveAlgorithm::processAlgorithm( QgsProcessingContext &, QgsProcessingFeedback *feedback ) long count = source->featureCount();
{ if ( count <= 0 )
long count = mSource->featureCount(); return QVariantMap();
if ( count == 0 )
return true;
QgsFeature f; QgsFeature f;
QgsFeatureIterator it = mSource->getFeatures(); QgsFeatureIterator it = source->getFeatures();
double step = 100.0 / count; double step = 100.0 / count;
int current = 0; int current = 0;
if ( mFields.isEmpty() ) if ( fields.isEmpty() )
{ {
// dissolve all - not using fields // dissolve all - not using fields
bool firstFeature = true; bool firstFeature = true;
@ -367,14 +340,14 @@ bool QgsDissolveAlgorithm::processAlgorithm( QgsProcessingContext &, QgsProcessi
} }
outputFeature.setGeometry( QgsGeometry::unaryUnion( geomQueue ) ); outputFeature.setGeometry( QgsGeometry::unaryUnion( geomQueue ) );
mSink->addFeature( outputFeature, QgsFeatureSink::FastInsert ); sink->addFeature( outputFeature, QgsFeatureSink::FastInsert );
} }
else else
{ {
QList< int > fieldIndexes; QList< int > fieldIndexes;
Q_FOREACH ( const QString &field, mFields ) Q_FOREACH ( const QString &field, fields )
{ {
int index = mSource->fields().lookupField( field ); int index = source->fields().lookupField( field );
if ( index >= 0 ) if ( index >= 0 )
fieldIndexes << index; fieldIndexes << index;
} }
@ -418,21 +391,15 @@ bool QgsDissolveAlgorithm::processAlgorithm( QgsProcessingContext &, QgsProcessi
QgsFeature outputFeature; QgsFeature outputFeature;
outputFeature.setGeometry( QgsGeometry::unaryUnion( geomIt.value() ) ); outputFeature.setGeometry( QgsGeometry::unaryUnion( geomIt.value() ) );
outputFeature.setAttributes( attributeHash.value( geomIt.key() ) ); outputFeature.setAttributes( attributeHash.value( geomIt.key() ) );
mSink->addFeature( outputFeature, QgsFeatureSink::FastInsert ); sink->addFeature( outputFeature, QgsFeatureSink::FastInsert );
feedback->setProgress( current * 100.0 / numberFeatures ); feedback->setProgress( current * 100.0 / numberFeatures );
current++; current++;
} }
} }
mSink->flushBuffer();
return true;
}
QVariantMap QgsDissolveAlgorithm::postProcessAlgorithm( QgsProcessingContext &, QgsProcessingFeedback * )
{
QVariantMap outputs; QVariantMap outputs;
outputs.insert( QStringLiteral( "OUTPUT" ), mSinkId ); outputs.insert( QStringLiteral( "OUTPUT" ), dest );
return outputs; return outputs;
} }
@ -459,29 +426,25 @@ QgsClipAlgorithm *QgsClipAlgorithm::create() const
return new QgsClipAlgorithm(); return new QgsClipAlgorithm();
} }
bool QgsClipAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback * ) QVariantMap QgsClipAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
{ {
mFeatureSource.reset( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) ); std::unique_ptr< QgsFeatureSource > featureSource( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
if ( !mFeatureSource ) if ( !featureSource )
return false; return QVariantMap();
mMaskSource.reset( parameterAsSource( parameters, QStringLiteral( "OVERLAY" ), context ) ); std::unique_ptr< QgsFeatureSource > maskSource( parameterAsSource( parameters, QStringLiteral( "OVERLAY" ), context ) );
if ( !mMaskSource ) if ( !maskSource )
return false; return QVariantMap();
mSink.reset( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, mSinkId, mFeatureSource->fields(), QgsWkbTypes::multiType( mFeatureSource->wkbType() ), mFeatureSource->sourceCrs() ) ); QString dest;
std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, featureSource->fields(), QgsWkbTypes::multiType( featureSource->wkbType() ), featureSource->sourceCrs() ) );
if ( !mSink ) if ( !sink )
return false; return QVariantMap();
return true;
}
bool QgsClipAlgorithm::processAlgorithm( QgsProcessingContext &, QgsProcessingFeedback *feedback )
{
// first build up a list of clip geometries // first build up a list of clip geometries
QList< QgsGeometry > clipGeoms; QList< QgsGeometry > clipGeoms;
QgsFeatureIterator it = mMaskSource->getFeatures( QgsFeatureRequest().setSubsetOfAttributes( QList< int >() ).setDestinationCrs( mFeatureSource->sourceCrs() ) ); QgsFeatureIterator it = maskSource->getFeatures( QgsFeatureRequest().setSubsetOfAttributes( QList< int >() ).setDestinationCrs( featureSource->sourceCrs() ) );
QgsFeature f; QgsFeature f;
while ( it.nextFeature( f ) ) while ( it.nextFeature( f ) )
{ {
@ -490,7 +453,7 @@ bool QgsClipAlgorithm::processAlgorithm( QgsProcessingContext &, QgsProcessingFe
} }
if ( clipGeoms.isEmpty() ) if ( clipGeoms.isEmpty() )
return true; return QVariantMap();
// are we clipping against a single feature? if so, we can show finer progress reports // are we clipping against a single feature? if so, we can show finer progress reports
bool singleClipFeature = false; bool singleClipFeature = false;
@ -521,7 +484,7 @@ bool QgsClipAlgorithm::processAlgorithm( QgsProcessingContext &, QgsProcessingFe
break; break;
} }
QgsFeatureIterator inputIt = mFeatureSource->getFeatures( QgsFeatureRequest().setFilterRect( clipGeom.boundingBox() ) ); QgsFeatureIterator inputIt = featureSource->getFeatures( QgsFeatureRequest().setFilterRect( clipGeom.boundingBox() ) );
QgsFeatureList inputFeatures; QgsFeatureList inputFeatures;
QgsFeature f; QgsFeature f;
while ( inputIt.nextFeature( f ) ) while ( inputIt.nextFeature( f ) )
@ -576,7 +539,8 @@ bool QgsClipAlgorithm::processAlgorithm( QgsProcessingContext &, QgsProcessingFe
QgsFeature outputFeature; QgsFeature outputFeature;
outputFeature.setGeometry( newGeometry ); outputFeature.setGeometry( newGeometry );
outputFeature.setAttributes( inputFeature.attributes() ); outputFeature.setAttributes( inputFeature.attributes() );
mSink->addFeature( outputFeature, QgsFeatureSink::FastInsert ); sink->addFeature( outputFeature, QgsFeatureSink::FastInsert );
if ( singleClipFeature ) if ( singleClipFeature )
feedback->setProgress( current * step ); feedback->setProgress( current * step );
@ -588,17 +552,13 @@ bool QgsClipAlgorithm::processAlgorithm( QgsProcessingContext &, QgsProcessingFe
feedback->setProgress( 100.0 * static_cast< double >( i ) / clipGeoms.length() ); feedback->setProgress( 100.0 * static_cast< double >( i ) / clipGeoms.length() );
} }
} }
mSink->flushBuffer();
return true;
}
QVariantMap QgsClipAlgorithm::postProcessAlgorithm( QgsProcessingContext &, QgsProcessingFeedback * )
{
QVariantMap outputs; QVariantMap outputs;
outputs.insert( QStringLiteral( "OUTPUT" ), mSinkId ); outputs.insert( QStringLiteral( "OUTPUT" ), dest );
return outputs; return outputs;
} }
QgsTransformAlgorithm::QgsTransformAlgorithm() QgsTransformAlgorithm::QgsTransformAlgorithm()
{ {
addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ), QObject::tr( "Input layer" ) ) ); addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ), QObject::tr( "Input layer" ) ) );
@ -619,41 +579,29 @@ QgsTransformAlgorithm *QgsTransformAlgorithm::create() const
return new QgsTransformAlgorithm(); return new QgsTransformAlgorithm();
} }
bool QgsTransformAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback * ) QVariantMap QgsTransformAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
{ {
mSource.reset( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) ); std::unique_ptr< QgsFeatureSource > source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
if ( !mSource ) if ( !source )
return false; return QVariantMap();
mCrs = parameterAsCrs( parameters, QStringLiteral( "TARGET_CRS" ), context ); QgsCoordinateReferenceSystem targetCrs = parameterAsCrs( parameters, QStringLiteral( "TARGET_CRS" ), context );
mSink.reset( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, mSinkId, mSource->fields(), mSource->wkbType(), mCrs ) ); QString dest;
if ( !mSink ) std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, source->fields(), source->wkbType(), targetCrs ) );
return false; if ( !sink )
return QVariantMap();
return true; long count = source->featureCount();
} if ( count <= 0 )
return QVariantMap();
QVariantMap QgsTransformAlgorithm::postProcessAlgorithm( QgsProcessingContext &, QgsProcessingFeedback * )
{
QVariantMap outputs;
outputs.insert( QStringLiteral( "OUTPUT" ), mSinkId );
return outputs;
}
bool QgsTransformAlgorithm::processAlgorithm( QgsProcessingContext &, QgsProcessingFeedback *feedback )
{
long count = mSource->featureCount();
if ( count == 0 )
return true;
QgsFeature f; QgsFeature f;
QgsFeatureRequest req; QgsFeatureRequest req;
// perform reprojection in the iterators... // perform reprojection in the iterators...
req.setDestinationCrs( mCrs ); req.setDestinationCrs( targetCrs );
QgsFeatureIterator it = mSource->getFeatures( req ); QgsFeatureIterator it = source->getFeatures( req );
double step = 100.0 / count; double step = 100.0 / count;
int current = 0; int current = 0;
@ -664,12 +612,14 @@ bool QgsTransformAlgorithm::processAlgorithm( QgsProcessingContext &, QgsProcess
break; break;
} }
mSink->addFeature( f, QgsFeatureSink::FastInsert ); sink->addFeature( f, QgsFeatureSink::FastInsert );
feedback->setProgress( current * step ); feedback->setProgress( current * step );
current++; current++;
} }
return true; QVariantMap outputs;
outputs.insert( QStringLiteral( "OUTPUT" ), dest );
return outputs;
} }
@ -698,29 +648,25 @@ QgsSubdivideAlgorithm *QgsSubdivideAlgorithm::create() const
return new QgsSubdivideAlgorithm(); return new QgsSubdivideAlgorithm();
} }
bool QgsSubdivideAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback * ) QVariantMap QgsSubdivideAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
{ {
mSource.reset( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) ); std::unique_ptr< QgsFeatureSource > source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
if ( !mSource ) if ( !source )
return false; return QVariantMap();
mMaxNodes = parameterAsInt( parameters, QStringLiteral( "MAX_NODES" ), context ); int maxNodes = parameterAsInt( parameters, QStringLiteral( "MAX_NODES" ), context );
mSink.reset( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, mSinkId, mSource->fields(), QString dest;
QgsWkbTypes::multiType( mSource->wkbType() ), mSource->sourceCrs() ) ); std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, source->fields(),
if ( !mSink ) QgsWkbTypes::multiType( source->wkbType() ), source->sourceCrs() ) );
return false; if ( !sink )
return QVariantMap();
return true; long count = source->featureCount();
} if ( count <= 0 )
return QVariantMap();
bool QgsSubdivideAlgorithm::processAlgorithm( QgsProcessingContext &, QgsProcessingFeedback *feedback )
{
long count = mSource->featureCount();
if ( count == 0 )
return true;
QgsFeature f; QgsFeature f;
QgsFeatureIterator it = mSource->getFeatures(); QgsFeatureIterator it = source->getFeatures();
double step = 100.0 / count; double step = 100.0 / count;
int current = 0; int current = 0;
@ -734,29 +680,25 @@ bool QgsSubdivideAlgorithm::processAlgorithm( QgsProcessingContext &, QgsProcess
QgsFeature out = f; QgsFeature out = f;
if ( out.hasGeometry() ) if ( out.hasGeometry() )
{ {
out.setGeometry( f.geometry().subdivide( mMaxNodes ) ); out.setGeometry( f.geometry().subdivide( maxNodes ) );
if ( !out.geometry() ) if ( !out.geometry() )
{ {
QgsMessageLog::logMessage( QObject::tr( "Error calculating subdivision for feature %1" ).arg( f.id() ), QObject::tr( "Processing" ), QgsMessageLog::WARNING ); QgsMessageLog::logMessage( QObject::tr( "Error calculating subdivision for feature %1" ).arg( f.id() ), QObject::tr( "Processing" ), QgsMessageLog::WARNING );
} }
} }
mSink->addFeature( out, QgsFeatureSink::FastInsert ); sink->addFeature( out, QgsFeatureSink::FastInsert );
feedback->setProgress( current * step ); feedback->setProgress( current * step );
current++; current++;
} }
mSink->flushBuffer();
return true;
}
QVariantMap QgsSubdivideAlgorithm::postProcessAlgorithm( QgsProcessingContext &, QgsProcessingFeedback * )
{
QVariantMap outputs; QVariantMap outputs;
outputs.insert( QStringLiteral( "OUTPUT" ), mSinkId ); outputs.insert( QStringLiteral( "OUTPUT" ), dest );
return outputs; return outputs;
} }
QgsMultipartToSinglepartAlgorithm::QgsMultipartToSinglepartAlgorithm() QgsMultipartToSinglepartAlgorithm::QgsMultipartToSinglepartAlgorithm()
{ {
addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ), QObject::tr( "Input layer" ) ) ); addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ), QObject::tr( "Input layer" ) ) );
@ -777,30 +719,26 @@ QgsMultipartToSinglepartAlgorithm *QgsMultipartToSinglepartAlgorithm::create() c
return new QgsMultipartToSinglepartAlgorithm(); return new QgsMultipartToSinglepartAlgorithm();
} }
bool QgsMultipartToSinglepartAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback * ) QVariantMap QgsMultipartToSinglepartAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
{ {
mSource.reset( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) ); std::unique_ptr< QgsFeatureSource > source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
if ( !mSource ) if ( !source )
return false; return QVariantMap();
QgsWkbTypes::Type sinkType = QgsWkbTypes::singleType( mSource->wkbType() ); QgsWkbTypes::Type sinkType = QgsWkbTypes::singleType( source->wkbType() );
mSink.reset( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, mSinkId, mSource->fields(), QString dest;
sinkType, mSource->sourceCrs() ) ); std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, source->fields(),
if ( !mSink ) sinkType, source->sourceCrs() ) );
return false; if ( !sink )
return QVariantMap();
return true; long count = source->featureCount();
} if ( count <= 0 )
return QVariantMap();
bool QgsMultipartToSinglepartAlgorithm::processAlgorithm( QgsProcessingContext &, QgsProcessingFeedback *feedback )
{
long count = mSource->featureCount();
if ( count == 0 )
return true;
QgsFeature f; QgsFeature f;
QgsFeatureIterator it = mSource->getFeatures(); QgsFeatureIterator it = source->getFeatures();
double step = 100.0 / count; double step = 100.0 / count;
int current = 0; int current = 0;
@ -820,34 +758,30 @@ bool QgsMultipartToSinglepartAlgorithm::processAlgorithm( QgsProcessingContext &
Q_FOREACH ( const QgsGeometry &g, inputGeometry.asGeometryCollection() ) Q_FOREACH ( const QgsGeometry &g, inputGeometry.asGeometryCollection() )
{ {
out.setGeometry( g ); out.setGeometry( g );
mSink->addFeature( out, QgsFeatureSink::FastInsert ); sink->addFeature( out, QgsFeatureSink::FastInsert );
} }
} }
else else
{ {
mSink->addFeature( out, QgsFeatureSink::FastInsert ); sink->addFeature( out, QgsFeatureSink::FastInsert );
} }
} }
else else
{ {
// feature with null geometry // feature with null geometry
mSink->addFeature( out, QgsFeatureSink::FastInsert ); sink->addFeature( out, QgsFeatureSink::FastInsert );
} }
feedback->setProgress( current * step ); feedback->setProgress( current * step );
current++; current++;
} }
mSink->flushBuffer();
return true;
}
QVariantMap QgsMultipartToSinglepartAlgorithm::postProcessAlgorithm( QgsProcessingContext &, QgsProcessingFeedback * )
{
QVariantMap outputs; QVariantMap outputs;
outputs.insert( QStringLiteral( "OUTPUT" ), mSinkId ); outputs.insert( QStringLiteral( "OUTPUT" ), dest );
return outputs; return outputs;
} }
QgsExtractByExpressionAlgorithm::QgsExtractByExpressionAlgorithm() QgsExtractByExpressionAlgorithm::QgsExtractByExpressionAlgorithm()
{ {
addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ), QObject::tr( "Input layer" ) ) ); addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ), QObject::tr( "Input layer" ) ) );
@ -872,50 +806,47 @@ QgsExtractByExpressionAlgorithm *QgsExtractByExpressionAlgorithm::create() const
return new QgsExtractByExpressionAlgorithm(); return new QgsExtractByExpressionAlgorithm();
} }
bool QgsExtractByExpressionAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback * ) QVariantMap QgsExtractByExpressionAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
{ {
mSource.reset( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) ); std::unique_ptr< QgsFeatureSource > source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
if ( !mSource ) if ( !source )
return false; return QVariantMap();
mExpressionString = parameterAsExpression( parameters, QStringLiteral( "EXPRESSION" ), context ); QString expressionString = parameterAsExpression( parameters, QStringLiteral( "EXPRESSION" ), context );
mMatchingSink.reset( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, mMatchingSinkId, mSource->fields(), QString matchingSinkId;
mSource->wkbType(), mSource->sourceCrs() ) ); std::unique_ptr< QgsFeatureSink > matchingSink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, matchingSinkId, source->fields(),
if ( !mMatchingSink ) source->wkbType(), source->sourceCrs() ) );
return false; if ( !matchingSink )
return QVariantMap();
mNonMatchingSink.reset( parameterAsSink( parameters, QStringLiteral( "FAIL_OUTPUT" ), context, mNonMatchingSinkId, mSource->fields(), QString nonMatchingSinkId;
mSource->wkbType(), mSource->sourceCrs() ) ); std::unique_ptr< QgsFeatureSink > nonMatchingSink( parameterAsSink( parameters, QStringLiteral( "FAIL_OUTPUT" ), context, nonMatchingSinkId, source->fields(),
source->wkbType(), source->sourceCrs() ) );
mExpressionContext = createExpressionContext( parameters, context ); QgsExpression expression( expressionString );
return true;
}
bool QgsExtractByExpressionAlgorithm::processAlgorithm( QgsProcessingContext &, QgsProcessingFeedback *feedback )
{
QgsExpression expression( mExpressionString );
if ( expression.hasParserError() ) if ( expression.hasParserError() )
{ {
throw QgsProcessingException( expression.parserErrorString() ); throw QgsProcessingException( expression.parserErrorString() );
} }
QgsExpressionContext expressionContext = createExpressionContext( parameters, context );
long count = mSource->featureCount(); long count = source->featureCount();
if ( count == 0 ) if ( count <= 0 )
return true; return QVariantMap();
double step = 100.0 / count; double step = 100.0 / count;
int current = 0; int current = 0;
if ( !mNonMatchingSink ) if ( !nonMatchingSink )
{ {
// not saving failing features - so only fetch good features // not saving failing features - so only fetch good features
QgsFeatureRequest req; QgsFeatureRequest req;
req.setFilterExpression( mExpressionString ); req.setFilterExpression( expressionString );
req.setExpressionContext( mExpressionContext ); req.setExpressionContext( expressionContext );
QgsFeatureIterator it = mSource->getFeatures( req ); QgsFeatureIterator it = source->getFeatures( req );
QgsFeature f; QgsFeature f;
while ( it.nextFeature( f ) ) while ( it.nextFeature( f ) )
{ {
@ -924,7 +855,7 @@ bool QgsExtractByExpressionAlgorithm::processAlgorithm( QgsProcessingContext &,
break; break;
} }
mMatchingSink->addFeature( f, QgsFeatureSink::FastInsert ); matchingSink->addFeature( f, QgsFeatureSink::FastInsert );
feedback->setProgress( current * step ); feedback->setProgress( current * step );
current++; current++;
@ -933,10 +864,10 @@ bool QgsExtractByExpressionAlgorithm::processAlgorithm( QgsProcessingContext &,
else else
{ {
// saving non-matching features, so we need EVERYTHING // saving non-matching features, so we need EVERYTHING
mExpressionContext.setFields( mSource->fields() ); expressionContext.setFields( source->fields() );
expression.prepare( &mExpressionContext ); expression.prepare( &expressionContext );
QgsFeatureIterator it = mSource->getFeatures(); QgsFeatureIterator it = source->getFeatures();
QgsFeature f; QgsFeature f;
while ( it.nextFeature( f ) ) while ( it.nextFeature( f ) )
{ {
@ -945,37 +876,30 @@ bool QgsExtractByExpressionAlgorithm::processAlgorithm( QgsProcessingContext &,
break; break;
} }
mExpressionContext.setFeature( f ); expressionContext.setFeature( f );
if ( expression.evaluate( &mExpressionContext ).toBool() ) if ( expression.evaluate( &expressionContext ).toBool() )
{ {
mMatchingSink->addFeature( f, QgsFeatureSink::FastInsert ); matchingSink->addFeature( f, QgsFeatureSink::FastInsert );
} }
else else
{ {
mNonMatchingSink->addFeature( f, QgsFeatureSink::FastInsert ); nonMatchingSink->addFeature( f, QgsFeatureSink::FastInsert );
} }
feedback->setProgress( current * step ); feedback->setProgress( current * step );
current++; current++;
} }
} }
if ( mMatchingSink )
mMatchingSink->flushBuffer();
if ( mNonMatchingSink )
mNonMatchingSink->flushBuffer();
return true;
}
QVariantMap QgsExtractByExpressionAlgorithm::postProcessAlgorithm( QgsProcessingContext &, QgsProcessingFeedback * )
{
QVariantMap outputs; QVariantMap outputs;
outputs.insert( QStringLiteral( "OUTPUT" ), mMatchingSinkId ); outputs.insert( QStringLiteral( "OUTPUT" ), matchingSinkId );
if ( !mNonMatchingSinkId.isEmpty() ) if ( nonMatchingSink )
outputs.insert( QStringLiteral( "FAIL_OUTPUT" ), mNonMatchingSinkId ); outputs.insert( QStringLiteral( "FAIL_OUTPUT" ), nonMatchingSinkId );
return outputs; return outputs;
} }
QgsExtractByAttributeAlgorithm::QgsExtractByAttributeAlgorithm() QgsExtractByAttributeAlgorithm::QgsExtractByAttributeAlgorithm()
{ {
addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ), QObject::tr( "Input layer" ) ) ); addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ), QObject::tr( "Input layer" ) ) );
@ -1013,38 +937,34 @@ QgsExtractByAttributeAlgorithm *QgsExtractByAttributeAlgorithm::create() const
return new QgsExtractByAttributeAlgorithm(); return new QgsExtractByAttributeAlgorithm();
} }
bool QgsExtractByAttributeAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback * ) QVariantMap QgsExtractByAttributeAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
{ {
mSource.reset( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) ); std::unique_ptr< QgsFeatureSource > source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
if ( !mSource ) if ( !source )
return false; return QVariantMap();
mFieldName = parameterAsString( parameters, QStringLiteral( "FIELD" ), context ); QString fieldName = parameterAsString( parameters, QStringLiteral( "FIELD" ), context );
mOp = static_cast< Operation >( parameterAsEnum( parameters, QStringLiteral( "OPERATOR" ), context ) ); Operation op = static_cast< Operation >( parameterAsEnum( parameters, QStringLiteral( "OPERATOR" ), context ) );
mValue = parameterAsString( parameters, QStringLiteral( "VALUE" ), context ); QString value = parameterAsString( parameters, QStringLiteral( "VALUE" ), context );
mMatchingSink.reset( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, mMatchingSinkId, mSource->fields(), QString matchingSinkId;
mSource->wkbType(), mSource->sourceCrs() ) ); std::unique_ptr< QgsFeatureSink > matchingSink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, matchingSinkId, source->fields(),
if ( !mMatchingSink ) source->wkbType(), source->sourceCrs() ) );
return false; if ( !matchingSink )
return QVariantMap();
mNonMatchingSink.reset( parameterAsSink( parameters, QStringLiteral( "FAIL_OUTPUT" ), context, mNonMatchingSinkId, mSource->fields(), QString nonMatchingSinkId;
mSource->wkbType(), mSource->sourceCrs() ) ); std::unique_ptr< QgsFeatureSink > nonMatchingSink( parameterAsSink( parameters, QStringLiteral( "FAIL_OUTPUT" ), context, nonMatchingSinkId, source->fields(),
source->wkbType(), source->sourceCrs() ) );
mExpressionContext = createExpressionContext( parameters, context ); int idx = source->fields().lookupField( fieldName );
return true; QVariant::Type fieldType = source->fields().at( idx ).type();
}
bool QgsExtractByAttributeAlgorithm::processAlgorithm( QgsProcessingContext &, QgsProcessingFeedback *feedback ) if ( fieldType != QVariant::String && ( op == BeginsWith || op == Contains || op == DoesNotContain ) )
{
int idx = mSource->fields().lookupField( mFieldName );
QVariant::Type fieldType = mSource->fields().at( idx ).type();
if ( fieldType != QVariant::String && ( mOp == BeginsWith || mOp == Contains || mOp == DoesNotContain ) )
{ {
QString method; QString method;
switch ( mOp ) switch ( op )
{ {
case BeginsWith: case BeginsWith:
method = QObject::tr( "begins with" ); method = QObject::tr( "begins with" );
@ -1063,10 +983,10 @@ bool QgsExtractByAttributeAlgorithm::processAlgorithm( QgsProcessingContext &, Q
throw QgsProcessingException( QObject::tr( "Operator '%1' can be used only with string fields." ).arg( method ) ); throw QgsProcessingException( QObject::tr( "Operator '%1' can be used only with string fields." ).arg( method ) );
} }
QString fieldRef = QgsExpression::quotedColumnRef( mFieldName ); QString fieldRef = QgsExpression::quotedColumnRef( fieldName );
QString quotedVal = QgsExpression::quotedValue( mValue ); QString quotedVal = QgsExpression::quotedValue( value );
QString expr; QString expr;
switch ( mOp ) switch ( op )
{ {
case Equals: case Equals:
expr = QStringLiteral( "%1 = %3" ).arg( fieldRef, quotedVal ); expr = QStringLiteral( "%1 = %3" ).arg( fieldRef, quotedVal );
@ -1087,10 +1007,10 @@ bool QgsExtractByAttributeAlgorithm::processAlgorithm( QgsProcessingContext &, Q
expr = QStringLiteral( "%1 <= %3" ).arg( fieldRef, quotedVal ); expr = QStringLiteral( "%1 <= %3" ).arg( fieldRef, quotedVal );
break; break;
case BeginsWith: case BeginsWith:
expr = QStringLiteral( "%1 LIKE '%2%'" ).arg( fieldRef, mValue ); expr = QStringLiteral( "%1 LIKE '%2%'" ).arg( fieldRef, value );
break; break;
case Contains: case Contains:
expr = QStringLiteral( "%1 LIKE '%%2%'" ).arg( fieldRef, mValue ); expr = QStringLiteral( "%1 LIKE '%%2%'" ).arg( fieldRef, value );
break; break;
case IsNull: case IsNull:
expr = QStringLiteral( "%1 IS NULL" ).arg( fieldRef ); expr = QStringLiteral( "%1 IS NULL" ).arg( fieldRef );
@ -1099,31 +1019,34 @@ bool QgsExtractByAttributeAlgorithm::processAlgorithm( QgsProcessingContext &, Q
expr = QStringLiteral( "%1 IS NOT NULL" ).arg( fieldRef ); expr = QStringLiteral( "%1 IS NOT NULL" ).arg( fieldRef );
break; break;
case DoesNotContain: case DoesNotContain:
expr = QStringLiteral( "%1 NOT LIKE '%%2%'" ).arg( fieldRef, mValue ); expr = QStringLiteral( "%1 NOT LIKE '%%2%'" ).arg( fieldRef, value );
break; break;
} }
QgsExpression expression( expr ); QgsExpression expression( expr );
if ( expression.hasParserError() ) if ( expression.hasParserError() )
{ {
throw QgsProcessingException( expression.parserErrorString() ); // raise GeoAlgorithmExecutionException(expression.parserErrorString())
return QVariantMap();
} }
long count = mSource->featureCount(); QgsExpressionContext expressionContext = createExpressionContext( parameters, context );
if ( count == 0 )
return true; long count = source->featureCount();
if ( count <= 0 )
return QVariantMap();
double step = 100.0 / count; double step = 100.0 / count;
int current = 0; int current = 0;
if ( !mNonMatchingSink ) if ( !nonMatchingSink )
{ {
// not saving failing features - so only fetch good features // not saving failing features - so only fetch good features
QgsFeatureRequest req; QgsFeatureRequest req;
req.setFilterExpression( expr ); req.setFilterExpression( expr );
req.setExpressionContext( mExpressionContext ); req.setExpressionContext( expressionContext );
QgsFeatureIterator it = mSource->getFeatures( req ); QgsFeatureIterator it = source->getFeatures( req );
QgsFeature f; QgsFeature f;
while ( it.nextFeature( f ) ) while ( it.nextFeature( f ) )
{ {
@ -1132,7 +1055,7 @@ bool QgsExtractByAttributeAlgorithm::processAlgorithm( QgsProcessingContext &, Q
break; break;
} }
mMatchingSink->addFeature( f, QgsFeatureSink::FastInsert ); matchingSink->addFeature( f, QgsFeatureSink::FastInsert );
feedback->setProgress( current * step ); feedback->setProgress( current * step );
current++; current++;
@ -1141,10 +1064,10 @@ bool QgsExtractByAttributeAlgorithm::processAlgorithm( QgsProcessingContext &, Q
else else
{ {
// saving non-matching features, so we need EVERYTHING // saving non-matching features, so we need EVERYTHING
mExpressionContext.setFields( mSource->fields() ); expressionContext.setFields( source->fields() );
expression.prepare( &mExpressionContext ); expression.prepare( &expressionContext );
QgsFeatureIterator it = mSource->getFeatures(); QgsFeatureIterator it = source->getFeatures();
QgsFeature f; QgsFeature f;
while ( it.nextFeature( f ) ) while ( it.nextFeature( f ) )
{ {
@ -1153,14 +1076,14 @@ bool QgsExtractByAttributeAlgorithm::processAlgorithm( QgsProcessingContext &, Q
break; break;
} }
mExpressionContext.setFeature( f ); expressionContext.setFeature( f );
if ( expression.evaluate( &mExpressionContext ).toBool() ) if ( expression.evaluate( &expressionContext ).toBool() )
{ {
mMatchingSink->addFeature( f, QgsFeatureSink::FastInsert ); matchingSink->addFeature( f, QgsFeatureSink::FastInsert );
} }
else else
{ {
mNonMatchingSink->addFeature( f, QgsFeatureSink::FastInsert ); nonMatchingSink->addFeature( f, QgsFeatureSink::FastInsert );
} }
feedback->setProgress( current * step ); feedback->setProgress( current * step );
@ -1168,21 +1091,12 @@ bool QgsExtractByAttributeAlgorithm::processAlgorithm( QgsProcessingContext &, Q
} }
} }
if ( mMatchingSink )
mMatchingSink->flushBuffer();
if ( mNonMatchingSink )
mNonMatchingSink->flushBuffer();
return true;
}
QVariantMap QgsExtractByAttributeAlgorithm::postProcessAlgorithm( QgsProcessingContext &, QgsProcessingFeedback * )
{
QVariantMap outputs; QVariantMap outputs;
outputs.insert( QStringLiteral( "OUTPUT" ), mMatchingSinkId ); outputs.insert( QStringLiteral( "OUTPUT" ), matchingSinkId );
if ( !mNonMatchingSinkId.isEmpty() ) if ( nonMatchingSink )
outputs.insert( QStringLiteral( "FAIL_OUTPUT" ), mNonMatchingSinkId ); outputs.insert( QStringLiteral( "FAIL_OUTPUT" ), nonMatchingSinkId );
return outputs; return outputs;
} }
///@endcond ///@endcond

View File

@ -64,16 +64,9 @@ class QgsCentroidAlgorithm : public QgsProcessingAlgorithm
protected: protected:
bool prepareAlgorithm( const QVariantMap &parameters, virtual QVariantMap processAlgorithm( const QVariantMap &parameters,
QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override; QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
bool processAlgorithm( QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
QVariantMap postProcessAlgorithm( QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
private:
std::unique_ptr< QgsFeatureSource > mSource;
std::unique_ptr< QgsFeatureSink > mSink;
QString mSinkId;
}; };
/** /**
@ -95,17 +88,9 @@ class QgsTransformAlgorithm : public QgsProcessingAlgorithm
protected: protected:
bool prepareAlgorithm( const QVariantMap &parameters, virtual QVariantMap processAlgorithm( const QVariantMap &parameters,
QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override; QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
bool processAlgorithm( QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
QVariantMap postProcessAlgorithm( QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
private:
std::unique_ptr< QgsFeatureSource > mSource;
std::unique_ptr< QgsFeatureSink > mSink;
QString mSinkId;
QgsCoordinateReferenceSystem mCrs;
}; };
/** /**
@ -127,27 +112,9 @@ class QgsBufferAlgorithm : public QgsProcessingAlgorithm
protected: protected:
bool prepareAlgorithm( const QVariantMap &parameters, virtual QVariantMap processAlgorithm( const QVariantMap &parameters,
QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override; QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
bool processAlgorithm( QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
QVariantMap postProcessAlgorithm( QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
private:
std::unique_ptr< QgsFeatureSource > mSource;
std::unique_ptr< QgsFeatureSink > mSink;
QString mSinkId;
bool mDissolve = false;
int mSegments = 8;
QgsGeometry::EndCapStyle mEndCapStyle = QgsGeometry::CapRound;
QgsGeometry::JoinStyle mJoinStyle = QgsGeometry::JoinStyleRound;
double mMiterLimit = 1;
double mBufferDistance = 1;
bool mDynamicBuffer = false;
QgsProperty mDynamicBufferProperty;
QVariantMap mDynamicParams;
double mDefaultBuffer;
QgsExpressionContext mExpContext;
}; };
/** /**
@ -169,17 +136,8 @@ class QgsDissolveAlgorithm : public QgsProcessingAlgorithm
protected: protected:
bool prepareAlgorithm( const QVariantMap &parameters, virtual QVariantMap processAlgorithm( const QVariantMap &parameters,
QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override; QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
bool processAlgorithm( QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
QVariantMap postProcessAlgorithm( QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
private:
std::unique_ptr< QgsFeatureSource > mSource;
std::unique_ptr< QgsFeatureSink > mSink;
QString mSinkId;
QStringList mFields;
}; };
@ -217,22 +175,9 @@ class QgsExtractByAttributeAlgorithm : public QgsProcessingAlgorithm
protected: protected:
bool prepareAlgorithm( const QVariantMap &parameters, virtual QVariantMap processAlgorithm( const QVariantMap &parameters,
QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override; QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
bool processAlgorithm( QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
QVariantMap postProcessAlgorithm( QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
private:
std::unique_ptr< QgsFeatureSource > mSource;
std::unique_ptr< QgsFeatureSink > mMatchingSink;
QString mMatchingSinkId;
std::unique_ptr< QgsFeatureSink > mNonMatchingSink;
QString mNonMatchingSinkId;
QString mFieldName;
Operation mOp;
QString mValue;
QgsExpressionContext mExpressionContext;
}; };
/** /**
@ -254,20 +199,9 @@ class QgsExtractByExpressionAlgorithm : public QgsProcessingAlgorithm
protected: protected:
bool prepareAlgorithm( const QVariantMap &parameters, virtual QVariantMap processAlgorithm( const QVariantMap &parameters,
QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override; QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
bool processAlgorithm( QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
QVariantMap postProcessAlgorithm( QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
private:
std::unique_ptr< QgsFeatureSource > mSource;
std::unique_ptr< QgsFeatureSink > mMatchingSink;
QString mMatchingSinkId;
std::unique_ptr< QgsFeatureSink > mNonMatchingSink;
QString mNonMatchingSinkId;
QString mExpressionString;
QgsExpressionContext mExpressionContext;
}; };
/** /**
@ -289,18 +223,8 @@ class QgsClipAlgorithm : public QgsProcessingAlgorithm
protected: protected:
bool prepareAlgorithm( const QVariantMap &parameters, virtual QVariantMap processAlgorithm( const QVariantMap &parameters,
QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override; QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
bool processAlgorithm( QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
QVariantMap postProcessAlgorithm( QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
private:
std::unique_ptr< QgsFeatureSource > mFeatureSource;
std::unique_ptr< QgsFeatureSource > mMaskSource;
std::unique_ptr< QgsFeatureSink > mSink;
QString mSinkId;
}; };
@ -324,17 +248,8 @@ class QgsSubdivideAlgorithm : public QgsProcessingAlgorithm
protected: protected:
bool prepareAlgorithm( const QVariantMap &parameters, virtual QVariantMap processAlgorithm( const QVariantMap &parameters,
QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override; QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
bool processAlgorithm( QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
QVariantMap postProcessAlgorithm( QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
private:
std::unique_ptr< QgsFeatureSource > mSource;
std::unique_ptr< QgsFeatureSink > mSink;
QString mSinkId;
int mMaxNodes = 64;
}; };
@ -357,16 +272,9 @@ class QgsMultipartToSinglepartAlgorithm : public QgsProcessingAlgorithm
protected: protected:
bool prepareAlgorithm( const QVariantMap &parameters, virtual QVariantMap processAlgorithm( const QVariantMap &parameters,
QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override; QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
bool processAlgorithm( QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
QVariantMap postProcessAlgorithm( QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
private:
std::unique_ptr< QgsFeatureSource > mSource;
std::unique_ptr< QgsFeatureSink > mSink;
QString mSinkId;
}; };
///@endcond PRIVATE ///@endcond PRIVATE

View File

@ -265,6 +265,11 @@ bool QgsProcessingAlgorithm::prepareAlgorithm( const QVariantMap &, QgsProcessin
return true; return true;
} }
QVariantMap QgsProcessingAlgorithm::postProcessAlgorithm( QgsProcessingContext &, QgsProcessingFeedback * )
{
return QVariantMap();
}
const QgsProcessingParameterDefinition *QgsProcessingAlgorithm::parameterDefinition( const QString &name ) const const QgsProcessingParameterDefinition *QgsProcessingAlgorithm::parameterDefinition( const QString &name ) const
{ {
Q_FOREACH ( const QgsProcessingParameterDefinition *def, mParameters ) Q_FOREACH ( const QgsProcessingParameterDefinition *def, mParameters )
@ -329,14 +334,19 @@ QVariantMap QgsProcessingAlgorithm::run( const QVariantMap &parameters, QgsProce
if ( !res ) if ( !res )
return QVariantMap(); return QVariantMap();
res = alg->runPrepared( context, feedback ); QVariantMap runRes = alg->runPrepared( parameters, context, feedback );
if ( !res )
if ( !alg->mHasExecuted )
return QVariantMap(); return QVariantMap();
if ( ok ) if ( ok )
*ok = true; *ok = true;
return alg->postProcess( context, feedback ); QVariantMap ppRes = alg->postProcess( context, feedback );
if ( !ppRes.isEmpty() )
return ppRes;
else
return runRes;
} }
bool QgsProcessingAlgorithm::prepare( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) bool QgsProcessingAlgorithm::prepare( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
@ -356,9 +366,9 @@ bool QgsProcessingAlgorithm::prepare( const QVariantMap &parameters, QgsProcessi
} }
} }
bool QgsProcessingAlgorithm::runPrepared( QgsProcessingContext &context, QgsProcessingFeedback *feedback ) QVariantMap QgsProcessingAlgorithm::runPrepared( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
{ {
Q_ASSERT_X( mHasPrepared, "QgsProcessingAlgorithm::runPrepared", "prepare() was not called for the algorithm instance" ); Q_ASSERT_X( mHasPrepared, "QgsProcessingAlgorithm::runPrepared", QString( "prepare() was not called for the algorithm instance %1" ).arg( name() ).toLatin1() );
Q_ASSERT_X( !mHasExecuted, "QgsProcessingAlgorithm::runPrepared", "runPrepared() was already called for this algorithm instance" ); Q_ASSERT_X( !mHasExecuted, "QgsProcessingAlgorithm::runPrepared", "runPrepared() was already called for this algorithm instance" );
// Hey kids, let's all be thread safe! It's the fun thing to do! // Hey kids, let's all be thread safe! It's the fun thing to do!
@ -388,8 +398,9 @@ bool QgsProcessingAlgorithm::runPrepared( QgsProcessingContext &context, QgsProc
try try
{ {
mHasExecuted = processAlgorithm( *runContext, feedback ); QVariantMap runResults = processAlgorithm( parameters, *runContext, feedback );
mHasExecuted = true;
if ( mLocalContext ) if ( mLocalContext )
{ {
// ok, time to clean things up. We need to push the temporary context back into // ok, time to clean things up. We need to push the temporary context back into
@ -397,7 +408,7 @@ bool QgsProcessingAlgorithm::runPrepared( QgsProcessingContext &context, QgsProc
// current thread, so we HAVE to do this here) // current thread, so we HAVE to do this here)
mLocalContext->pushToThread( context.thread() ); mLocalContext->pushToThread( context.thread() );
} }
return mHasExecuted; return runResults;
} }
catch ( QgsProcessingException &e ) catch ( QgsProcessingException &e )
{ {
@ -409,14 +420,14 @@ bool QgsProcessingAlgorithm::runPrepared( QgsProcessingContext &context, QgsProc
// see above! // see above!
mLocalContext->pushToThread( context.thread() ); mLocalContext->pushToThread( context.thread() );
} }
return false; return QVariantMap();
} }
} }
QVariantMap QgsProcessingAlgorithm::postProcess( QgsProcessingContext &context, QgsProcessingFeedback *feedback ) QVariantMap QgsProcessingAlgorithm::postProcess( QgsProcessingContext &context, QgsProcessingFeedback *feedback )
{ {
Q_ASSERT_X( QThread::currentThread() == context.temporaryLayerStore()->thread(), "QgsProcessingAlgorithm::postProcess", "postProcess() must be called from the same thread the context was created in" ); Q_ASSERT_X( QThread::currentThread() == context.temporaryLayerStore()->thread(), "QgsProcessingAlgorithm::postProcess", "postProcess() must be called from the same thread the context was created in" );
Q_ASSERT_X( mHasExecuted, "QgsProcessingAlgorithm::postProcess", "runPrepared() was not called for the algorithm instance" ); Q_ASSERT_X( mHasExecuted, "QgsProcessingAlgorithm::postProcess", QString( "algorithm instance %1 was not executed" ).arg( name() ).toLatin1() );
Q_ASSERT_X( !mHasPostProcessed, "QgsProcessingAlgorithm::postProcess", "postProcess() was already called for this algorithm instance" ); Q_ASSERT_X( !mHasPostProcessed, "QgsProcessingAlgorithm::postProcess", "postProcess() was already called for this algorithm instance" );
if ( mLocalContext ) if ( mLocalContext )

View File

@ -265,7 +265,7 @@ class CORE_EXPORT QgsProcessingAlgorithm
* on algorithms directly retrieved from QgsProcessingRegistry and QgsProcessingProvider. Instead, a copy * on algorithms directly retrieved from QgsProcessingRegistry and QgsProcessingProvider. Instead, a copy
* of the algorithm should be created with clone() and prepare()/runPrepared() called on the copy. * of the algorithm should be created with clone() and prepare()/runPrepared() called on the copy.
*/ */
bool runPrepared( QgsProcessingContext &context, QgsProcessingFeedback *feedback ); QVariantMap runPrepared( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback );
/** /**
* Should be called in the main thread following the completion of runPrepared(). This method * Should be called in the main thread following the completion of runPrepared(). This method
@ -371,7 +371,7 @@ class CORE_EXPORT QgsProcessingAlgorithm
* \see prepareAlgorithm() * \see prepareAlgorithm()
* \see postProcessAlgorithm() * \see postProcessAlgorithm()
*/ */
virtual bool processAlgorithm( QgsProcessingContext &context, QgsProcessingFeedback *feedback ) = 0 SIP_VIRTUALERRORHANDLER( processing_exception_handler ); virtual QVariantMap processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) = 0 SIP_VIRTUALERRORHANDLER( processing_exception_handler );
/** /**
* Allows the algorithm to perform any required cleanup tasks. The returned variant map * Allows the algorithm to perform any required cleanup tasks. The returned variant map
@ -389,7 +389,7 @@ class CORE_EXPORT QgsProcessingAlgorithm
* \see prepareAlgorithm() * \see prepareAlgorithm()
* \see processAlgorithm() * \see processAlgorithm()
*/ */
virtual QVariantMap postProcessAlgorithm( QgsProcessingContext &context, QgsProcessingFeedback *feedback ) = 0 SIP_VIRTUALERRORHANDLER( processing_exception_handler ); virtual QVariantMap postProcessAlgorithm( QgsProcessingContext &context, QgsProcessingFeedback *feedback ) SIP_VIRTUALERRORHANDLER( processing_exception_handler );
/** /**
* Evaluates the parameter with matching \a name to a static string value. * Evaluates the parameter with matching \a name to a static string value.

View File

@ -24,6 +24,7 @@
QgsProcessingAlgRunnerTask::QgsProcessingAlgRunnerTask( const QgsProcessingAlgorithm *algorithm, const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) QgsProcessingAlgRunnerTask::QgsProcessingAlgRunnerTask( const QgsProcessingAlgorithm *algorithm, const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
: QgsTask( tr( "Running %1" ).arg( algorithm->name() ), QgsTask::CanCancel ) : QgsTask( tr( "Running %1" ).arg( algorithm->name() ), QgsTask::CanCancel )
, mParameters( parameters )
, mContext( context ) , mContext( context )
, mFeedback( feedback ) , mFeedback( feedback )
, mAlgorithm( algorithm->create() ) , mAlgorithm( algorithm->create() )
@ -33,7 +34,7 @@ QgsProcessingAlgRunnerTask::QgsProcessingAlgRunnerTask( const QgsProcessingAlgor
mOwnedFeedback.reset( new QgsProcessingFeedback() ); mOwnedFeedback.reset( new QgsProcessingFeedback() );
mFeedback = mOwnedFeedback.get(); mFeedback = mOwnedFeedback.get();
} }
if ( !mAlgorithm->prepare( parameters, context, mFeedback ) ) if ( !mAlgorithm->prepare( mParameters, context, mFeedback ) )
cancel(); cancel();
} }
@ -48,7 +49,8 @@ bool QgsProcessingAlgRunnerTask::run()
bool ok = false; bool ok = false;
try try
{ {
ok = mAlgorithm->runPrepared( mContext, mFeedback ); mResults = mAlgorithm->runPrepared( mParameters, mContext, mFeedback );
ok = true;
} }
catch ( QgsProcessingException & ) catch ( QgsProcessingException & )
{ {
@ -60,9 +62,10 @@ bool QgsProcessingAlgRunnerTask::run()
void QgsProcessingAlgRunnerTask::finished( bool result ) void QgsProcessingAlgRunnerTask::finished( bool result )
{ {
Q_UNUSED( result ); Q_UNUSED( result );
QVariantMap ppResults;
if ( result ) if ( result )
{ {
mResults = mAlgorithm->postProcess( mContext, mFeedback ); ppResults = mAlgorithm->postProcess( mContext, mFeedback );
} }
emit executed( result, mResults ); emit executed( result, !ppResults.isEmpty() ? ppResults : mResults );
} }

View File

@ -65,6 +65,7 @@ class CORE_EXPORT QgsProcessingAlgRunnerTask : public QgsTask
private: private:
QVariantMap mParameters;
QVariantMap mResults; QVariantMap mResults;
QgsProcessingContext &mContext; QgsProcessingContext &mContext;
QgsProcessingFeedback *mFeedback = nullptr; QgsProcessingFeedback *mFeedback = nullptr;

View File

@ -472,7 +472,7 @@ bool QgsProcessingModelAlgorithm::childOutputIsRequired( const QString &childId,
return false; return false;
} }
bool QgsProcessingModelAlgorithm::processAlgorithm( QgsProcessingContext &context, QgsProcessingFeedback *feedback ) QVariantMap QgsProcessingModelAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
{ {
QSet< QString > toExecute; QSet< QString > toExecute;
QMap< QString, ChildAlgorithm >::const_iterator childIt = mChildAlgorithms.constBegin(); QMap< QString, ChildAlgorithm >::const_iterator childIt = mChildAlgorithms.constBegin();
@ -515,7 +515,7 @@ bool QgsProcessingModelAlgorithm::processAlgorithm( QgsProcessingContext &contex
const ChildAlgorithm &child = mChildAlgorithms[ childId ]; const ChildAlgorithm &child = mChildAlgorithms[ childId ];
QVariantMap childParams = parametersForChildAlgorithm( child, mInputParameters, childResults ); QVariantMap childParams = parametersForChildAlgorithm( child, parameters, childResults );
feedback->setProgressText( QObject::tr( "Running %1 [%2/%3]" ).arg( child.description() ).arg( executed.count() + 1 ).arg( toExecute.count() ) ); feedback->setProgressText( QObject::tr( "Running %1 [%2/%3]" ).arg( child.description() ).arg( executed.count() + 1 ).arg( toExecute.count() ) );
//feedback->pushDebugInfo( "Parameters: " + ', '.join( [str( p ).strip() + //feedback->pushDebugInfo( "Parameters: " + ', '.join( [str( p ).strip() +
// '=' + str( p.value ) for p in alg.algorithm.parameters] ) ) // '=' + str( p.value ) for p in alg.algorithm.parameters] ) )
@ -551,11 +551,6 @@ bool QgsProcessingModelAlgorithm::processAlgorithm( QgsProcessingContext &contex
feedback->pushDebugInfo( QObject::tr( "Model processed OK. Executed %1 algorithms total in %2 s." ).arg( executed.count() ).arg( totalTime.elapsed() / 1000.0 ) ); feedback->pushDebugInfo( QObject::tr( "Model processed OK. Executed %1 algorithms total in %2 s." ).arg( executed.count() ).arg( totalTime.elapsed() / 1000.0 ) );
mResults = finalResults; mResults = finalResults;
return true;
}
QVariantMap QgsProcessingModelAlgorithm::postProcessAlgorithm( QgsProcessingContext &, QgsProcessingFeedback * )
{
return mResults; return mResults;
} }
@ -655,12 +650,6 @@ QString QgsProcessingModelAlgorithm::asPythonCode() const
return lines.join( '\n' ); return lines.join( '\n' );
} }
bool QgsProcessingModelAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &, QgsProcessingFeedback * )
{
mInputParameters = parameters;
return true;
}
QVariantMap QgsProcessingModelAlgorithm::helpContent() const QVariantMap QgsProcessingModelAlgorithm::helpContent() const
{ {
return mHelpContent; return mHelpContent;

View File

@ -826,10 +826,7 @@ class CORE_EXPORT QgsProcessingModelAlgorithm : public QgsProcessingAlgorithm
protected: protected:
bool prepareAlgorithm( const QVariantMap &parameters, QVariantMap processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
bool processAlgorithm( QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
QVariantMap postProcessAlgorithm( QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
private: private:
@ -846,8 +843,6 @@ class CORE_EXPORT QgsProcessingModelAlgorithm : public QgsProcessingAlgorithm
//! Model source file //! Model source file
QString mSourceFile; QString mSourceFile;
QVariantMap mInputParameters;
QVariantMap mResults; QVariantMap mResults;
void dependsOnChildAlgorithmsRecursive( const QString &childId, QSet<QString> &depends ) const; void dependsOnChildAlgorithmsRecursive( const QString &childId, QSet<QString> &depends ) const;

View File

@ -42,9 +42,7 @@ class DummyAlgorithm : public QgsProcessingAlgorithm
QString name() const override { return mName; } QString name() const override { return mName; }
QString displayName() const override { return mName; } QString displayName() const override { return mName; }
bool processAlgorithm( QgsProcessingContext &, QgsProcessingFeedback * ) override { return true; } QVariantMap processAlgorithm( const QVariantMap &, QgsProcessingContext &, QgsProcessingFeedback * ) override { return QVariantMap(); }
bool prepareAlgorithm( const QVariantMap &, QgsProcessingContext &, QgsProcessingFeedback * ) override { return true; }
QVariantMap postProcessAlgorithm( QgsProcessingContext &, QgsProcessingFeedback * ) override { return QVariantMap(); }
virtual Flags flags() const override { return mFlags; } virtual Flags flags() const override { return mFlags; }
DummyAlgorithm *create() const override { return new DummyAlgorithm( name() ); } DummyAlgorithm *create() const override { return new DummyAlgorithm( name() ); }