From d4af76150f9db96bf75d13ee10fadbe4076da230 Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Thu, 20 Jul 2017 13:06:18 +1000 Subject: [PATCH] Flip some more algorithms to feature based algorithms --- .../plugins/processing/algs/qgis/Boundary.py | 58 +++++---------- .../processing/algs/qgis/DeleteColumn.py | 72 +++++++----------- .../processing/algs/qgis/DeleteHoles.py | 50 ++++--------- .../processing/algs/qgis/DensifyGeometries.py | 50 ++++--------- .../algs/qgis/DensifyGeometriesInterval.py | 50 ++++--------- .../processing/algs/qgis/DropGeometry.py | 43 ++++------- .../processing/algs/qgis/LinesToPolygons.py | 56 ++++---------- .../processing/algs/qgis/OffsetLine.py | 64 +++++++--------- .../processing/algs/qgis/Orthogonalize.py | 67 ++++++----------- .../processing/algs/qgis/PointOnSurface.py | 56 +++++--------- .../processing/algs/qgis/PolygonsToLines.py | 62 ++++------------ .../algs/qgis/ReverseLineDirection.py | 56 +++++--------- .../algs/qgis/SimplifyGeometries.py | 73 ++++++------------- python/plugins/processing/algs/qgis/Smooth.py | 58 +++++---------- .../tests/testdata/qgis_algorithm_tests.yaml | 28 +++---- 15 files changed, 278 insertions(+), 565 deletions(-) diff --git a/python/plugins/processing/algs/qgis/Boundary.py b/python/plugins/processing/algs/qgis/Boundary.py index b3b0c15ba4db..558d71276e8b 100644 --- a/python/plugins/processing/algs/qgis/Boundary.py +++ b/python/plugins/processing/algs/qgis/Boundary.py @@ -28,31 +28,20 @@ import os from qgis.core import (QgsGeometry, - QgsWkbTypes, - QgsFeatureSink, - QgsProcessing, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterFeatureSink) + QgsWkbTypes) from qgis.PyQt.QtGui import QIcon -from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm +from processing.algs.qgis.QgisAlgorithm import QgisFeatureBasedAlgorithm pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0] -class Boundary(QgisAlgorithm): - - INPUT_LAYER = 'INPUT_LAYER' - OUTPUT_LAYER = 'OUTPUT_LAYER' +class Boundary(QgisFeatureBasedAlgorithm): def __init__(self): super().__init__() - def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT_LAYER, self.tr('Input layer'), [QgsProcessing.TypeVectorLine, QgsProcessing.TypeVectorPolygon])) - self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT_LAYER, self.tr('Boundary'))) - def icon(self): return QIcon(os.path.join(pluginPath, 'images', 'ftools', 'convex_hull.png')) @@ -65,10 +54,10 @@ def name(self): def displayName(self): return self.tr('Boundary') - def processAlgorithm(self, parameters, context, feedback): - source = self.parameterAsSource(parameters, self.INPUT_LAYER, context) + def outputName(self): + return self.tr('Boundary') - input_wkb = source.wkbType() + def outputWkbType(self, input_wkb): if QgsWkbTypes.geometryType(input_wkb) == QgsWkbTypes.LineGeometry: output_wkb = QgsWkbTypes.MultiPoint elif QgsWkbTypes.geometryType(input_wkb) == QgsWkbTypes.PolygonGeometry: @@ -78,26 +67,15 @@ def processAlgorithm(self, parameters, context, feedback): if QgsWkbTypes.hasM(input_wkb): output_wkb = QgsWkbTypes.addM(output_wkb) - (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT_LAYER, context, - source.fields(), output_wkb, source.sourceCrs()) - - features = source.getFeatures() - total = 100.0 / source.featureCount() if source.featureCount() else 0 - - for current, input_feature in enumerate(features): - if feedback.isCanceled(): - break - output_feature = input_feature - input_geometry = input_feature.geometry() - if input_geometry: - output_geometry = QgsGeometry(input_geometry.geometry().boundary()) - if not output_geometry: - feedback.reportError(self.tr('No boundary for feature {} (possibly a closed linestring?)').format(input_feature.id())) - output_feature.clearGeometry() - else: - output_feature.setGeometry(output_geometry) - - sink.addFeature(output_feature, QgsFeatureSink.FastInsert) - feedback.setProgress(int(current * total)) - - return {self.OUTPUT_LAYER: dest_id} + return output_wkb + + def processFeature(self, feature, feedback): + input_geometry = feature.geometry() + if input_geometry: + output_geometry = QgsGeometry(input_geometry.geometry().boundary()) + if not output_geometry: + feedback.reportError(self.tr('No boundary for feature {} (possibly a closed linestring?)').format(feature.id())) + feature.clearGeometry() + else: + feature.setGeometry(output_geometry) + return feature diff --git a/python/plugins/processing/algs/qgis/DeleteColumn.py b/python/plugins/processing/algs/qgis/DeleteColumn.py index 52dbd90eba8f..2a2c8c34247e 100644 --- a/python/plugins/processing/algs/qgis/DeleteColumn.py +++ b/python/plugins/processing/algs/qgis/DeleteColumn.py @@ -25,18 +25,13 @@ __revision__ = '$Format:%H$' -from qgis.core import (QgsFeatureSink, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterFeatureSink, - QgsProcessingParameterField) -from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm +from qgis.core import (QgsProcessingParameterField) +from processing.algs.qgis.QgisAlgorithm import QgisFeatureBasedAlgorithm -class DeleteColumn(QgisAlgorithm): +class DeleteColumn(QgisFeatureBasedAlgorithm): - INPUT = 'INPUT' COLUMNS = 'COLUMN' - OUTPUT = 'OUTPUT' def tags(self): return self.tr('drop,delete,remove,fields,columns,attributes').split(',') @@ -46,14 +41,13 @@ def group(self): def __init__(self): super().__init__() + self.fields_to_delete = [] + self.field_indices = [] - def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, self.tr('Input layer'))) + def initParameters(self, config=None): self.addParameter(QgsProcessingParameterField(self.COLUMNS, self.tr('Fields to drop'), - None, self.INPUT, QgsProcessingParameterField.Any, True)) - - self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Output layer'))) + None, 'INPUT', QgsProcessingParameterField.Any, True)) def name(self): return 'deletecolumn' @@ -61,40 +55,30 @@ def name(self): def displayName(self): return self.tr('Drop field(s)') - def processAlgorithm(self, parameters, context, feedback): - source = self.parameterAsSource(parameters, self.INPUT, context) - fields_to_delete = self.parameterAsFields(parameters, self.COLUMNS, context) + def outputName(self): + return self.tr('Fields dropped') + + def prepareAlgorithm(self, parameters, context, feedback): + self.fields_to_delete = self.parameterAsFields(parameters, self.COLUMNS, context) + return True - fields = source.fields() - field_indices = [] + def outputFields(self, input_fields): # loop through twice - first we need to build up a list of original attribute indices - for f in fields_to_delete: - index = fields.lookupField(f) - field_indices.append(index) + for f in self.fields_to_delete: + index = input_fields.lookupField(f) + self.field_indices.append(index) # important - make sure we remove from the end so we aren't changing used indices as we go - field_indices.sort(reverse=True) + self.field_indices.sort(reverse=True) # this second time we make a cleaned version of the fields - for index in field_indices: - fields.remove(index) - - (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, - fields, source.wkbType(), source.sourceCrs()) - - features = source.getFeatures() - total = 100.0 / source.featureCount() if source.featureCount() else 0 - - for current, f in enumerate(features): - if feedback.isCanceled(): - break - - attributes = f.attributes() - for index in field_indices: - del attributes[index] - f.setAttributes(attributes) - sink.addFeature(f, QgsFeatureSink.FastInsert) - - feedback.setProgress(int(current * total)) - - return {self.OUTPUT: dest_id} + for index in self.field_indices: + input_fields.remove(index) + return input_fields + + def processFeature(self, feature, feedback): + attributes = feature.attributes() + for index in self.field_indices: + del attributes[index] + feature.setAttributes(attributes) + return feature diff --git a/python/plugins/processing/algs/qgis/DeleteHoles.py b/python/plugins/processing/algs/qgis/DeleteHoles.py index 735f79b0db4a..2e52a69d7938 100644 --- a/python/plugins/processing/algs/qgis/DeleteHoles.py +++ b/python/plugins/processing/algs/qgis/DeleteHoles.py @@ -24,32 +24,23 @@ __revision__ = '$Format:%H$' -from qgis.core import (QgsFeatureSink, - QgsProcessing, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterNumber, - QgsProcessingParameterFeatureSink) -from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm +from qgis.core import (QgsProcessingParameterNumber) +from processing.algs.qgis.QgisAlgorithm import QgisFeatureBasedAlgorithm -class DeleteHoles(QgisAlgorithm): +class DeleteHoles(QgisFeatureBasedAlgorithm): - INPUT = 'INPUT' MIN_AREA = 'MIN_AREA' - OUTPUT = 'OUTPUT' def __init__(self): super().__init__() + self.min_area = None - def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, - self.tr('Input layer'), [QgsProcessing.TypeVectorPolygon])) + def initParameters(self, config=None): self.addParameter(QgsProcessingParameterNumber(self.MIN_AREA, self.tr('Remove holes with area less than'), QgsProcessingParameterNumber.Double, 0, True, 0.0, 10000000.0)) - self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Cleaned'), QgsProcessing.TypeVectorPolygon)) - def tags(self): return self.tr('remove,delete,drop,holes,rings,fill').split(',') @@ -62,25 +53,16 @@ def name(self): def displayName(self): return self.tr('Delete holes') - def processAlgorithm(self, parameters, context, feedback): - source = self.parameterAsSource(parameters, self.INPUT, context) - min_area = self.parameterAsDouble(parameters, self.MIN_AREA, context) - if min_area == 0.0: - min_area = -1.0 - - (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, - source.fields(), source.wkbType(), source.sourceCrs()) - - features = source.getFeatures() - total = 100.0 / source.featureCount() if source.featureCount() else 0 - - for current, f in enumerate(features): - if feedback.isCanceled(): - break + def outputName(self): + return self.tr('Cleaned') - if f.hasGeometry(): - f.setGeometry(f.geometry().removeInteriorRings(min_area)) - sink.addFeature(f, QgsFeatureSink.FastInsert) - feedback.setProgress(int(current * total)) + def prepareAlgorithm(self, parameters, context, feedback): + self.min_area = self.parameterAsDouble(parameters, self.MIN_AREA, context) + if self.min_area == 0.0: + self.min_area = -1.0 + return True - return {self.OUTPUT: dest_id} + def processFeature(self, feature, feedback): + if feature.hasGeometry(): + feature.setGeometry(feature.geometry().removeInteriorRings(self.min_area)) + return feature diff --git a/python/plugins/processing/algs/qgis/DensifyGeometries.py b/python/plugins/processing/algs/qgis/DensifyGeometries.py index f5a0a039094c..87885473c592 100644 --- a/python/plugins/processing/algs/qgis/DensifyGeometries.py +++ b/python/plugins/processing/algs/qgis/DensifyGeometries.py @@ -28,19 +28,14 @@ import os -from qgis.core import (QgsFeatureSink, - QgsProcessing, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterNumber, - QgsProcessingParameterFeatureSink) -from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm +from qgis.core import (QgsProcessingParameterNumber) +from processing.algs.qgis.QgisAlgorithm import QgisFeatureBasedAlgorithm -class DensifyGeometries(QgisAlgorithm): - INPUT = 'INPUT' +class DensifyGeometries(QgisFeatureBasedAlgorithm): + VERTICES = 'VERTICES' - OUTPUT = 'OUTPUT' def tags(self): return self.tr('add,vertices,points').split(',') @@ -50,41 +45,28 @@ def group(self): def __init__(self): super().__init__() + self.vertices = None - def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, - self.tr('Input layer'), [QgsProcessing.TypeVectorPolygon, QgsProcessing.TypeVectorLine])) + def initParameters(self, config=None): self.addParameter(QgsProcessingParameterNumber(self.VERTICES, self.tr('Vertices to add'), QgsProcessingParameterNumber.Integer, 1, False, 1, 10000000)) - self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Densified'))) - def name(self): return 'densifygeometries' def displayName(self): return self.tr('Densify geometries') - def processAlgorithm(self, parameters, context, feedback): - source = self.parameterAsSource(parameters, self.INPUT, context) - vertices = self.parameterAsInt(parameters, self.VERTICES, context) - - (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, - source.fields(), source.wkbType(), source.sourceCrs()) - - features = source.getFeatures() - total = 100.0 / source.featureCount() if source.featureCount() else 0 - - for current, f in enumerate(features): - if feedback.isCanceled(): - break + def outputName(self): + return self.tr('Densified') - feature = f - if feature.hasGeometry(): - new_geometry = feature.geometry().densifyByCount(vertices) - feature.setGeometry(new_geometry) - sink.addFeature(feature, QgsFeatureSink.FastInsert) - feedback.setProgress(int(current * total)) + def prepareAlgorithm(self, parameters, context, feedback): + self.vertices = self.parameterAsInt(parameters, self.VERTICES, context) + return True - return {self.OUTPUT: dest_id} + def processFeature(self, feature, feedback): + if feature.hasGeometry(): + new_geometry = feature.geometry().densifyByCount(self.vertices) + feature.setGeometry(new_geometry) + return feature diff --git a/python/plugins/processing/algs/qgis/DensifyGeometriesInterval.py b/python/plugins/processing/algs/qgis/DensifyGeometriesInterval.py index 9ac668e4035f..20b62df4ecb8 100644 --- a/python/plugins/processing/algs/qgis/DensifyGeometriesInterval.py +++ b/python/plugins/processing/algs/qgis/DensifyGeometriesInterval.py @@ -27,60 +27,42 @@ __revision__ = '$Format:%H$' -from qgis.core import (QgsFeatureSink, - QgsProcessing, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterNumber, - QgsProcessingParameterFeatureSink) -from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm +from qgis.core import (QgsProcessingParameterNumber) +from processing.algs.qgis.QgisAlgorithm import QgisFeatureBasedAlgorithm -class DensifyGeometriesInterval(QgisAlgorithm): - INPUT = 'INPUT' +class DensifyGeometriesInterval(QgisFeatureBasedAlgorithm): + INTERVAL = 'INTERVAL' - OUTPUT = 'OUTPUT' def group(self): return self.tr('Vector geometry tools') def __init__(self): super().__init__() + self.interval = None - def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, - self.tr('Input layer'), [QgsProcessing.TypeVectorPolygon, QgsProcessing.TypeVectorLine])) + def initParameters(self, config=None): self.addParameter(QgsProcessingParameterNumber(self.INTERVAL, self.tr('Interval between vertices to add'), QgsProcessingParameterNumber.Double, 1, False, 0, 10000000)) - self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Densified'))) - def name(self): return 'densifygeometriesgivenaninterval' def displayName(self): return self.tr('Densify geometries given an interval') - def processAlgorithm(self, parameters, context, feedback): - source = self.parameterAsSource(parameters, self.INPUT, context) - interval = self.parameterAsDouble(parameters, self.INTERVAL, context) - - (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, - source.fields(), source.wkbType(), source.sourceCrs()) + def outputName(self): + return self.tr('Densified') - features = source.getFeatures() - total = 100.0 / source.featureCount() if source.featureCount() else 0 - for current, f in enumerate(features): - if feedback.isCanceled(): - break - - feature = f - if feature.hasGeometry(): - new_geometry = feature.geometry().densifyByDistance(float(interval)) - feature.setGeometry(new_geometry) - sink.addFeature(feature, QgsFeatureSink.FastInsert) - - feedback.setProgress(int(current * total)) + def prepareAlgorithm(self, parameters, context, feedback): + interval = self.parameterAsDouble(parameters, self.INTERVAL, context) + return True - return {self.OUTPUT: dest_id} + def processFeature(self, feature, feedback): + if feature.hasGeometry(): + new_geometry = feature.geometry().densifyByDistance(float(interval)) + feature.setGeometry(new_geometry) + return feature diff --git a/python/plugins/processing/algs/qgis/DropGeometry.py b/python/plugins/processing/algs/qgis/DropGeometry.py index 11597e3a38de..57f2e9048be9 100644 --- a/python/plugins/processing/algs/qgis/DropGeometry.py +++ b/python/plugins/processing/algs/qgis/DropGeometry.py @@ -25,20 +25,13 @@ __revision__ = '$Format:%H$' -from qgis.core import (QgsFeatureRequest, - QgsWkbTypes, - QgsFeatureSink, - QgsCoordinateReferenceSystem, - QgsProcessing, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterFeatureSink) -from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm +from qgis.core import (QgsWkbTypes, + QgsCoordinateReferenceSystem) +from processing.algs.qgis.QgisAlgorithm import QgisFeatureBasedAlgorithm -class DropGeometry(QgisAlgorithm): - INPUT = 'INPUT' - OUTPUT = 'OUTPUT' +class DropGeometry(QgisFeatureBasedAlgorithm): def tags(self): return self.tr('remove,drop,delete,geometry,objects').split(',') @@ -49,31 +42,21 @@ def group(self): def __init__(self): super().__init__() - def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, self.tr('Input layer'), [QgsProcessing.TypeVectorPoint, QgsProcessing.TypeVectorLine, QgsProcessing.TypeVectorPolygon])) - self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Dropped geometry'))) - def name(self): return 'dropgeometries' def displayName(self): return self.tr('Drop geometries') - def processAlgorithm(self, parameters, context, feedback): - source = self.parameterAsSource(parameters, self.INPUT, context) - (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, - source.fields(), QgsWkbTypes.NoGeometry, QgsCoordinateReferenceSystem()) - - request = QgsFeatureRequest().setFlags(QgsFeatureRequest.NoGeometry) - features = source.getFeatures(request) - total = 100.0 / source.featureCount() if source.featureCount() else 0 + def outputName(self): + return self.tr('Dropped geometries') - for current, input_feature in enumerate(features): - if feedback.isCanceled(): - break + def outputCrs(self, input_crs): + return QgsCoordinateReferenceSystem() - input_feature.clearGeometry() - sink.addFeature(input_feature, QgsFeatureSink.FastInsert) - feedback.setProgress(int(current * total)) + def outputWkbType(self, input_wkb_type): + return QgsWkbTypes.NoGeometry - return {self.OUTPUT: dest_id} + def processFeature(self, feature, feedback): + feature.clearGeometry() + return feature diff --git a/python/plugins/processing/algs/qgis/LinesToPolygons.py b/python/plugins/processing/algs/qgis/LinesToPolygons.py index e6bc8b781a7a..8ac1abf9c399 100644 --- a/python/plugins/processing/algs/qgis/LinesToPolygons.py +++ b/python/plugins/processing/algs/qgis/LinesToPolygons.py @@ -42,16 +42,13 @@ QgsProcessingParameterFeatureSink, QgsProcessingUtils) -from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm +from processing.algs.qgis.QgisAlgorithm import QgisFeatureBasedAlgorithm from processing.tools import dataobjects, vector pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0] -class LinesToPolygons(QgisAlgorithm): - - INPUT = 'INPUT' - OUTPUT = 'OUTPUT' +class LinesToPolygons(QgisFeatureBasedAlgorithm): def icon(self): return QIcon(os.path.join(pluginPath, 'images', 'ftools', 'to_lines.png')) @@ -65,52 +62,27 @@ def group(self): def __init__(self): super().__init__() - def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, - self.tr('Input layer'), - [QgsProcessing.TypeVectorLine])) - - self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, - self.tr('Lines to polygons'), - QgsProcessing.TypeVectorPolygon)) - def name(self): return 'linestopolygons' def displayName(self): return self.tr('Lines to polygons') - def processAlgorithm(self, parameters, context, feedback): - source = self.parameterAsSource(parameters, self.INPUT, context) - - geomType = self.convertWkbToPolygons(source.wkbType()) - - (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, - source.fields(), geomType, source.sourceCrs()) - - outFeat = QgsFeature() - - total = 100.0 / source.featureCount() if source.featureCount() else 0 - count = 0 - - for feat in source.getFeatures(): - if feedback.isCanceled(): - break + def outputName(self): + return self.tr('Polygons') - if feat.hasGeometry(): - outFeat.setGeometry(QgsGeometry(self.convertToPolygons(feat.geometry()))) - attrs = feat.attributes() - outFeat.setAttributes(attrs) - sink.addFeature(outFeat, QgsFeatureSink.FastInsert) - if outFeat.geometry().isEmpty(): - feedback.reportError(self.tr("One or more line ignored due to geometry not having a minimum of three vertices.")) - else: - sink.addFeature(feat, QgsFeatureSink.FastInsert) + def outputType(self): + return QgsProcessing.TypeVectorPolygon - count += 1 - feedback.setProgress(int(count * total)) + def outputWkbType(self, input_wkb_type): + return self.convertWkbToPolygons(input_wkb_type) - return {self.OUTPUT: dest_id} + def processFeature(self, feature, feedback): + if feature.hasGeometry(): + feature.setGeometry(QgsGeometry(self.convertToPolygons(feature.geometry()))) + if feature.geometry().isEmpty(): + feedback.reportError(self.tr("One or more line ignored due to geometry not having a minimum of three vertices.")) + return feature def convertWkbToPolygons(self, wkb): multi_wkb = None diff --git a/python/plugins/processing/algs/qgis/OffsetLine.py b/python/plugins/processing/algs/qgis/OffsetLine.py index 64ed774907b4..66c2c7f4c776 100644 --- a/python/plugins/processing/algs/qgis/OffsetLine.py +++ b/python/plugins/processing/algs/qgis/OffsetLine.py @@ -35,14 +35,13 @@ QgsProcessingParameterEnum, QgsProcessingParameterFeatureSink) -from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm +from processing.algs.qgis.QgisAlgorithm import QgisFeatureBasedAlgorithm pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0] -class OffsetLine(QgisAlgorithm): - INPUT = 'INPUT' - OUTPUT = 'OUTPUT' +class OffsetLine(QgisFeatureBasedAlgorithm): + DISTANCE = 'DISTANCE' SEGMENTS = 'SEGMENTS' JOIN_STYLE = 'JOIN_STYLE' @@ -54,9 +53,12 @@ def group(self): def __init__(self): super().__init__() - def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, self.tr('Input layer'), - [QgsProcessing.TypeVectorLine])) + self.distance = None + self.segments = None + self.join_style = None + self.miter_limit = None + + def initParameters(self, config=None): self.addParameter(QgsProcessingParameterNumber(self.DISTANCE, self.tr('Distance'), type=QgsProcessingParameterNumber.Double, @@ -76,43 +78,33 @@ def initAlgorithm(self, config=None): self.tr('Mitre limit'), type=QgsProcessingParameterNumber.Double, minValue=1, defaultValue=2)) - self.addParameter( - QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Offset'), QgsProcessing.TypeVectorLine)) - def name(self): return 'offsetline' def displayName(self): return self.tr('Offset line') - def processAlgorithm(self, parameters, context, feedback): - source = self.parameterAsSource(parameters, self.INPUT, context) - (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, - source.fields(), source.wkbType(), source.sourceCrs()) - - distance = self.parameterAsDouble(parameters, self.DISTANCE, context) - segments = self.parameterAsInt(parameters, self.SEGMENTS, context) - join_style = self.parameterAsEnum(parameters, self.JOIN_STYLE, context) + 1 - miter_limit = self.parameterAsDouble(parameters, self.MITRE_LIMIT, context) - - features = source.getFeatures() - total = 100.0 / source.featureCount() if source.featureCount() else 0 + def outputName(self): + return self.tr('Offset') - for current, input_feature in enumerate(features): - if feedback.isCanceled(): - break + def outputType(self): + return QgsProcessing.TypeVectorLine - output_feature = input_feature - input_geometry = input_feature.geometry() - if input_geometry: - output_geometry = input_geometry.offsetCurve(distance, segments, join_style, miter_limit) - if not output_geometry: - raise QgsProcessingException( - self.tr('Error calculating line offset')) + def prepareAlgorithm(self, parameters, context, feedback): + self.distance = self.parameterAsDouble(parameters, self.DISTANCE, context) + self.segments = self.parameterAsInt(parameters, self.SEGMENTS, context) + self.join_style = self.parameterAsEnum(parameters, self.JOIN_STYLE, context) + 1 + self.miter_limit = self.parameterAsDouble(parameters, self.MITRE_LIMIT, context) + return True - output_feature.setGeometry(output_geometry) + def processFeature(self, feature, feedback): + input_geometry = feature.geometry() + if input_geometry: + output_geometry = input_geometry.offsetCurve(self.distance, self.segments, self.join_style, self.miter_limit) + if not output_geometry: + raise QgsProcessingException( + self.tr('Error calculating line offset')) - sink.addFeature(output_feature, QgsFeatureSink.FastInsert) - feedback.setProgress(int(current * total)) + feature.setGeometry(output_geometry) - return {self.OUTPUT: dest_id} + return feature diff --git a/python/plugins/processing/algs/qgis/Orthogonalize.py b/python/plugins/processing/algs/qgis/Orthogonalize.py index c5d6759b77cd..00038a520503 100644 --- a/python/plugins/processing/algs/qgis/Orthogonalize.py +++ b/python/plugins/processing/algs/qgis/Orthogonalize.py @@ -25,19 +25,14 @@ __revision__ = '$Format:%H$' -from qgis.core import (QgsFeatureSink, - QgsProcessingException, - QgsProcessing, +from qgis.core import (QgsProcessingException, QgsProcessingParameterDefinition, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterNumber, - QgsProcessingParameterFeatureSink) -from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm + QgsProcessingParameterNumber) +from processing.algs.qgis.QgisAlgorithm import QgisFeatureBasedAlgorithm -class Orthogonalize(QgisAlgorithm): - INPUT = 'INPUT' - OUTPUT = 'OUTPUT' +class Orthogonalize(QgisFeatureBasedAlgorithm): + MAX_ITERATIONS = 'MAX_ITERATIONS' DISTANCE_THRESHOLD = 'DISTANCE_THRESHOLD' ANGLE_TOLERANCE = 'ANGLE_TOLERANCE' @@ -50,12 +45,10 @@ def group(self): def __init__(self): super().__init__() + self.max_iterations = None + self.angle_tolerance = None - def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, self.tr('Input layer'), - [QgsProcessing.TypeVectorLine, - QgsProcessing.TypeVectorPolygon])) - + def initParameters(self, config=None): self.addParameter(QgsProcessingParameterNumber(self.ANGLE_TOLERANCE, self.tr('Maximum angle tolerance (degrees)'), type=QgsProcessingParameterNumber.Double, @@ -68,41 +61,27 @@ def initAlgorithm(self, config=None): max_iterations.setFlags(max_iterations.flags() | QgsProcessingParameterDefinition.FlagAdvanced) self.addParameter(max_iterations) - self.addParameter( - QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Orthogonalized'))) - def name(self): return 'orthogonalize' def displayName(self): return self.tr('Orthogonalize') - def processAlgorithm(self, parameters, context, feedback): - source = self.parameterAsSource(parameters, self.INPUT, context) - max_iterations = self.parameterAsInt(parameters, self.MAX_ITERATIONS, context) - angle_tolerance = self.parameterAsDouble(parameters, self.ANGLE_TOLERANCE, context) - - (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, - source.fields(), source.wkbType(), source.sourceCrs()) - - features = source.getFeatures() - total = 100.0 / source.featureCount() if source.featureCount() else 0 - - for current, input_feature in enumerate(features): - if feedback.isCanceled(): - break - - output_feature = input_feature - input_geometry = input_feature.geometry() - if input_geometry: - output_geometry = input_geometry.orthogonalize(1.0e-8, max_iterations, angle_tolerance) - if not output_geometry: - raise QgsProcessingException( - self.tr('Error orthogonalizing geometry')) + def outputName(self): + return self.tr('Orthogonalized') - output_feature.setGeometry(output_geometry) + def prepareAlgorithm(self, parameters, context, feedback): + self.max_iterations = self.parameterAsInt(parameters, self.MAX_ITERATIONS, context) + self.angle_tolerance = self.parameterAsDouble(parameters, self.ANGLE_TOLERANCE, context) + return True - sink.addFeature(output_feature, QgsFeatureSink.FastInsert) - feedback.setProgress(int(current * total)) + def processFeature(self, feature, feedback): + input_geometry = feature.geometry() + if input_geometry: + output_geometry = input_geometry.orthogonalize(1.0e-8, self.max_iterations, self.angle_tolerance) + if not output_geometry: + raise QgsProcessingException( + self.tr('Error orthogonalizing geometry')) - return {self.OUTPUT: dest_id} + feature.setGeometry(output_geometry) + return feature diff --git a/python/plugins/processing/algs/qgis/PointOnSurface.py b/python/plugins/processing/algs/qgis/PointOnSurface.py index 882d377208e0..ad62d8847748 100644 --- a/python/plugins/processing/algs/qgis/PointOnSurface.py +++ b/python/plugins/processing/algs/qgis/PointOnSurface.py @@ -27,24 +27,18 @@ import os -from qgis.core import (QgsWkbTypes, - QgsFeatureSink, - QgsProcessing, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterFeatureSink) +from qgis.core import (QgsProcessing, + QgsProcessingException, + QgsWkbTypes) from qgis.PyQt.QtGui import QIcon -from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm -from processing.tools import dataobjects +from processing.algs.qgis.QgisAlgorithm import QgisFeatureBasedAlgorithm pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0] -class PointOnSurface(QgisAlgorithm): - - INPUT_LAYER = 'INPUT_LAYER' - OUTPUT_LAYER = 'OUTPUT_LAYER' +class PointOnSurface(QgisFeatureBasedAlgorithm): def icon(self): return QIcon(os.path.join(pluginPath, 'images', 'ftools', 'centroids.png')) @@ -55,39 +49,27 @@ def group(self): def __init__(self): super().__init__() - def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT_LAYER, - self.tr('Input layer'))) - self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT_LAYER, self.tr('Point'), QgsProcessing.TypeVectorPoint)) - def name(self): return 'pointonsurface' def displayName(self): return self.tr('Point on surface') - def processAlgorithm(self, parameters, context, feedback): - source = self.parameterAsSource(parameters, self.INPUT_LAYER, context) - - (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT_LAYER, context, source.fields(), QgsWkbTypes.Point, source.sourceCrs()) - - features = source.getFeatures() - total = 100.0 / source.featureCount() if source.featureCount() else 0 - - for current, input_feature in enumerate(features): - if feedback.isCanceled(): - break + def outputName(self): + return self.tr('Point') - output_feature = input_feature - input_geometry = input_feature.geometry() - if input_geometry: - output_geometry = input_geometry.pointOnSurface() - if not output_geometry: - raise QgsProcessingException(self.tr('Error calculating point on surface: `{error_message}`'.format(error_message=output_geometry.error()))) + def outputType(self): + return QgsProcessing.TypeVectorPoint - output_feature.setGeometry(output_geometry) + def outputWkbType(self, input_wkb_type): + return QgsWkbTypes.Point - sink.addFeature(output_feature, QgsFeatureSink.FastInsert) - feedback.setProgress(int(current * total)) + def processFeature(self, feature, feedback): + input_geometry = feature.geometry() + if input_geometry: + output_geometry = input_geometry.pointOnSurface() + if not output_geometry: + raise QgsProcessingException(self.tr('Error calculating point on surface: `{error_message}`'.format(error_message=output_geometry.error()))) - return {self.OUTPUT_LAYER: dest_id} + feature.setGeometry(output_geometry) + return feature diff --git a/python/plugins/processing/algs/qgis/PolygonsToLines.py b/python/plugins/processing/algs/qgis/PolygonsToLines.py index 7a7e141d19bf..c8e1ef96dfd2 100644 --- a/python/plugins/processing/algs/qgis/PolygonsToLines.py +++ b/python/plugins/processing/algs/qgis/PolygonsToLines.py @@ -29,28 +29,19 @@ from qgis.PyQt.QtGui import QIcon -from qgis.core import (QgsFeature, - QgsGeometry, +from qgis.core import (QgsGeometry, QgsGeometryCollection, QgsMultiLineString, QgsMultiCurve, QgsWkbTypes, - QgsFeatureSink, - QgsProcessing, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterFeatureSink, - QgsProcessingUtils) + QgsProcessing) -from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm -from processing.tools import dataobjects +from processing.algs.qgis.QgisAlgorithm import QgisFeatureBasedAlgorithm pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0] -class PolygonsToLines(QgisAlgorithm): - - INPUT = 'INPUT' - OUTPUT = 'OUTPUT' +class PolygonsToLines(QgisFeatureBasedAlgorithm): def icon(self): return QIcon(os.path.join(pluginPath, 'images', 'ftools', 'to_lines.png')) @@ -64,50 +55,25 @@ def group(self): def __init__(self): super().__init__() - def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, - self.tr('Input layer'), - [QgsProcessing.TypeVectorPolygon])) - - self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, - self.tr('Polygons to lines'), - QgsProcessing.TypeVectorLine)) - def name(self): return 'polygonstolines' def displayName(self): return self.tr('Polygons to lines') - def processAlgorithm(self, parameters, context, feedback): - source = self.parameterAsSource(parameters, self.INPUT, context) - - geomType = self.convertWkbToLines(source.wkbType()) - - (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, - source.fields(), geomType, source.sourceCrs()) - - outFeat = QgsFeature() - - total = 100.0 / source.featureCount() if source.featureCount() else 0 - count = 0 - - for feat in source.getFeatures(): - if feedback.isCanceled(): - break + def outputName(self): + return self.tr('Lines') - if feat.hasGeometry(): - outFeat.setGeometry(QgsGeometry(self.convertToLines(feat.geometry()))) - attrs = feat.attributes() - outFeat.setAttributes(attrs) - sink.addFeature(outFeat, QgsFeatureSink.FastInsert) - else: - sink.addFeature(feat, QgsFeatureSink.FastInsert) + def outputType(self): + return QgsProcessing.TypeVectorLine - count += 1 - feedback.setProgress(int(count * total)) + def outputWkbType(self, input_wkb_type): + return self.convertWkbToLines(input_wkb_type) - return {self.OUTPUT: dest_id} + def processFeature(self, feature, feedback): + if feature.hasGeometry(): + feature.setGeometry(QgsGeometry(self.convertToLines(feature.geometry()))) + return feature def convertWkbToLines(self, wkb): multi_wkb = None diff --git a/python/plugins/processing/algs/qgis/ReverseLineDirection.py b/python/plugins/processing/algs/qgis/ReverseLineDirection.py index b8ed34524c00..9a6e901ce1db 100644 --- a/python/plugins/processing/algs/qgis/ReverseLineDirection.py +++ b/python/plugins/processing/algs/qgis/ReverseLineDirection.py @@ -26,19 +26,12 @@ __revision__ = '$Format:%H$' from qgis.core import (QgsGeometry, - QgsFeature, - QgsFeatureSink, QgsProcessingException, - QgsProcessing, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterFeatureSink) -from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm + QgsProcessing) +from processing.algs.qgis.QgisAlgorithm import QgisFeatureBasedAlgorithm -class ReverseLineDirection(QgisAlgorithm): - - INPUT = 'INPUT' - OUTPUT = 'OUTPUT' +class ReverseLineDirection(QgisFeatureBasedAlgorithm): def group(self): return self.tr('Vector geometry tools') @@ -46,41 +39,26 @@ def group(self): def __init__(self): super().__init__() - def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, self.tr('Input layer'), - [QgsProcessing.TypeVectorLine])) - self.addParameter( - QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Reversed'), QgsProcessing.TypeVectorLine)) - def name(self): return 'reverselinedirection' def displayName(self): return self.tr('Reverse line direction') - def processAlgorithm(self, parameters, context, feedback): - source = self.parameterAsSource(parameters, self.INPUT, context) - - (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, - source.fields(), source.wkbType(), source.sourceCrs()) - - features = source.getFeatures() - total = 100.0 / source.featureCount() if source.featureCount() else 0 - for current, inFeat in enumerate(features): - if feedback.isCanceled(): - break + def outputName(self): + return self.tr('Reversed') - outFeat = inFeat - if inFeat.geometry(): - inGeom = inFeat.geometry() - reversedLine = inGeom.geometry().reversed() - if not reversedLine: - raise QgsProcessingException( - self.tr('Error reversing line')) - outGeom = QgsGeometry(reversedLine) + def outputType(self): + return QgsProcessing.TypeVectorLine - outFeat.setGeometry(outGeom) - sink.addFeature(outFeat, QgsFeatureSink.FastInsert) - feedback.setProgress(int(current * total)) + def processFeature(self, feature, feedback): + if feature.geometry(): + inGeom = feature.geometry() + reversedLine = inGeom.geometry().reversed() + if not reversedLine: + raise QgsProcessingException( + self.tr('Error reversing line')) + outGeom = QgsGeometry(reversedLine) - return {self.OUTPUT: dest_id} + feature.setGeometry(outGeom) + return feature diff --git a/python/plugins/processing/algs/qgis/SimplifyGeometries.py b/python/plugins/processing/algs/qgis/SimplifyGeometries.py index 1507bfbbf87c..8dec58724984 100644 --- a/python/plugins/processing/algs/qgis/SimplifyGeometries.py +++ b/python/plugins/processing/algs/qgis/SimplifyGeometries.py @@ -30,24 +30,17 @@ from qgis.PyQt.QtGui import QIcon from qgis.core import (QgsMapToPixelSimplifier, - QgsMessageLog, - QgsFeatureSink, - QgsProcessing, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterFeatureSink, QgsProcessingParameterEnum, QgsProcessingParameterNumber) -from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm +from processing.algs.qgis.QgisAlgorithm import QgisFeatureBasedAlgorithm pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0] -class SimplifyGeometries(QgisAlgorithm): +class SimplifyGeometries(QgisFeatureBasedAlgorithm): - INPUT = 'INPUT' TOLERANCE = 'TOLERANCE' - OUTPUT = 'OUTPUT' METHOD = 'METHOD' def icon(self): @@ -58,11 +51,11 @@ def group(self): def __init__(self): super().__init__() + self.tolerance = None + self.method = None + self.simplifier = None - def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, - self.tr('Input layer'), - [QgsProcessing.TypeVectorPolygon, QgsProcessing.TypeVectorLine])) + def initParameters(self, config=None): self.methods = [self.tr('Distance (Douglas-Peucker)'), 'Snap to grid', 'Area (Visvalingam)'] @@ -73,51 +66,31 @@ def initAlgorithm(self, config=None): self.addParameter(QgsProcessingParameterNumber(self.TOLERANCE, self.tr('Tolerance'), minValue=0.0, maxValue=10000000.0, defaultValue=1.0)) - self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Simplified'))) - def name(self): return 'simplifygeometries' def displayName(self): return self.tr('Simplify geometries') - def processAlgorithm(self, parameters, context, feedback): - source = self.parameterAsSource(parameters, self.INPUT, context) - tolerance = self.parameterAsDouble(parameters, self.TOLERANCE, context) - method = self.parameterAsEnum(parameters, self.METHOD, context) - - pointsBefore = 0 - pointsAfter = 0 - - (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, - source.fields(), source.wkbType(), source.sourceCrs()) - - features = source.getFeatures() - total = 100.0 / source.featureCount() if source.featureCount() else 0 - - if method != 0: - simplifier = QgsMapToPixelSimplifier(QgsMapToPixelSimplifier.SimplifyGeometry, tolerance, method) - - for current, input_feature in enumerate(features): - if feedback.isCanceled(): - break - out_feature = input_feature - if input_feature.geometry(): - input_geometry = input_feature.geometry() - pointsBefore += input_geometry.geometry().nCoordinates() + def outputName(self): + return self.tr('Simplified') - if method == 0: # distance - output_geometry = input_geometry.simplify(tolerance) - else: - output_geometry = simplifier.simplify(input_geometry) + def prepareAlgorithm(self, parameters, context, feedback): + self.tolerance = self.parameterAsDouble(parameters, self.TOLERANCE, context) + self.method = self.parameterAsEnum(parameters, self.METHOD, context) + if self.method != 0: + self.simplifier = QgsMapToPixelSimplifier(QgsMapToPixelSimplifier.SimplifyGeometry, self.tolerance, self.method) - pointsAfter += output_geometry.geometry().nCoordinates() - out_feature.setGeometry(output_geometry) + return True - sink.addFeature(out_feature, QgsFeatureSink.FastInsert) - feedback.setProgress(int(current * total)) + def processFeature(self, feature, feedback): + if feature.hasGeometry(): + input_geometry = feature.geometry() - QgsMessageLog.logMessage(self.tr('Simplify: Input geometries have been simplified from {0} to {1} points').format(pointsBefore, pointsAfter), - self.tr('Processing'), QgsMessageLog.INFO) + if self.method == 0: # distance + output_geometry = input_geometry.simplify(self.tolerance) + else: + output_geometry = self.simplifier.simplify(input_geometry) - return {self.OUTPUT: dest_id} + feature.setGeometry(output_geometry) + return feature diff --git a/python/plugins/processing/algs/qgis/Smooth.py b/python/plugins/processing/algs/qgis/Smooth.py index 2267702c69b5..7abcb46f4530 100644 --- a/python/plugins/processing/algs/qgis/Smooth.py +++ b/python/plugins/processing/algs/qgis/Smooth.py @@ -25,20 +25,14 @@ __revision__ = '$Format:%H$' -from qgis.core import (QgsFeatureSink, - QgsProcessing, - QgsProcessingException, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterFeatureSink, +from qgis.core import (QgsProcessingException, QgsProcessingParameterNumber) -from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm +from processing.algs.qgis.QgisAlgorithm import QgisFeatureBasedAlgorithm -class Smooth(QgisAlgorithm): +class Smooth(QgisFeatureBasedAlgorithm): - INPUT = 'INPUT' - OUTPUT = 'OUTPUT' ITERATIONS = 'ITERATIONS' MAX_ANGLE = 'MAX_ANGLE' OFFSET = 'OFFSET' @@ -49,9 +43,7 @@ def group(self): def __init__(self): super().__init__() - def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, - self.tr('Input layer'), [QgsProcessing.TypeVectorPolygon, QgsProcessing.TypeVectorLine])) + def initParameters(self, config=None): self.addParameter(QgsProcessingParameterNumber(self.ITERATIONS, self.tr('Iterations'), defaultValue=1, minValue=1, maxValue=10)) @@ -62,39 +54,27 @@ def initAlgorithm(self, config=None): self.tr('Maximum node angle to smooth'), QgsProcessingParameterNumber.Double, defaultValue=180.0, minValue=0.0, maxValue=180.0)) - self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Smoothed'))) - def name(self): return 'smoothgeometry' def displayName(self): return self.tr('Smooth geometry') - def processAlgorithm(self, parameters, context, feedback): - source = self.parameterAsSource(parameters, self.INPUT, context) - iterations = self.parameterAsInt(parameters, self.ITERATIONS, context) - offset = self.parameterAsDouble(parameters, self.OFFSET, context) - max_angle = self.parameterAsDouble(parameters, self.MAX_ANGLE, context) - - (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, - source.fields(), source.wkbType(), source.sourceCrs()) - - features = source.getFeatures() - total = 100.0 / source.featureCount() if source.featureCount() else 0 - - for current, input_feature in enumerate(features): - if feedback.isCanceled(): - break - output_feature = input_feature - if input_feature.geometry(): - output_geometry = input_feature.geometry().smooth(iterations, offset, -1, max_angle) - if not output_geometry: - raise QgsProcessingException( - self.tr('Error smoothing geometry')) + def outputName(self): + return self.tr('Smoothed') - output_feature.setGeometry(output_geometry) + def prepareAlgorithm(self, parameters, context, feedback): + self.iterations = self.parameterAsInt(parameters, self.ITERATIONS, context) + self.offset = self.parameterAsDouble(parameters, self.OFFSET, context) + self.max_angle = self.parameterAsDouble(parameters, self.MAX_ANGLE, context) + return True - sink.addFeature(output_feature, QgsFeatureSink.FastInsert) - feedback.setProgress(int(current * total)) + def processFeature(self, feature, feedback): + if feature.hasGeometry(): + output_geometry = feature.geometry().smooth(self.iterations, self.offset, -1, self.max_angle) + if not output_geometry: + raise QgsProcessingException( + self.tr('Error smoothing geometry')) - return {self.OUTPUT: dest_id} + feature.setGeometry(output_geometry) + return feature diff --git a/python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml b/python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml index 09e562f193c4..269d8538520c 100644 --- a/python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml +++ b/python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml @@ -481,44 +481,44 @@ tests: - algorithm: qgis:boundary name: Polygon boundary params: - INPUT_LAYER: + INPUT: name: polys.gml type: vector results: - OUTPUT_LAYER: + OUTPUT: name: expected/poly_boundary.gml type: vector - algorithm: qgis:boundary name: Multipoly boundary params: - INPUT_LAYER: + INPUT: name: multipolys.gml type: vector results: - OUTPUT_LAYER: + OUTPUT: name: expected/multipoly_boundary.gml type: vector - algorithm: qgis:boundary name: Line boundary params: - INPUT_LAYER: + INPUT: name: lines.gml type: vector results: - OUTPUT_LAYER: + OUTPUT: name: expected/lines_boundary.gml type: vector - algorithm: qgis:boundary name: Multiline boundary params: - INPUT_LAYER: + INPUT: name: multilines.gml type: vector results: - OUTPUT_LAYER: + OUTPUT: name: expected/multiline_boundary.gml type: vector @@ -588,33 +588,33 @@ tests: - algorithm: qgis:pointonsurface name: Point on polygon surface params: - INPUT_LAYER: + INPUT: name: polys.gml type: vector results: - OUTPUT_LAYER: + OUTPUT: name: expected/point_on_poly.gml type: vector - algorithm: qgis:pointonsurface name: Point on multipoint surface params: - INPUT_LAYER: + INPUT: name: multipoints.gml type: vector results: - OUTPUT_LAYER: + OUTPUT: name: expected/point_on_multipoint.gml type: vector - algorithm: qgis:pointonsurface name: Point on line surface params: - INPUT_LAYER: + INPUT: name: lines.gml type: vector results: - OUTPUT_LAYER: + OUTPUT: name: expected/point_on_line.gml type: vector