Skip to content

Commit 96fc3bd

Browse files
authoredJul 20, 2017
Merge pull request #4890 from nyalldawson/algs_next
Resurrect some processing algorithms
2 parents cd39999 + 96cf661 commit 96fc3bd

20 files changed

+607
-954
lines changed
 

‎python/plugins/processing/algs/qgis/Boundary.py

Lines changed: 18 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -28,31 +28,20 @@
2828
import os
2929

3030
from qgis.core import (QgsGeometry,
31-
QgsWkbTypes,
32-
QgsFeatureSink,
33-
QgsProcessing,
34-
QgsProcessingParameterFeatureSource,
35-
QgsProcessingParameterFeatureSink)
31+
QgsWkbTypes)
3632

3733
from qgis.PyQt.QtGui import QIcon
3834

39-
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
35+
from processing.algs.qgis.QgisAlgorithm import QgisFeatureBasedAlgorithm
4036

4137
pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0]
4238

4339

44-
class Boundary(QgisAlgorithm):
45-
46-
INPUT_LAYER = 'INPUT_LAYER'
47-
OUTPUT_LAYER = 'OUTPUT_LAYER'
40+
class Boundary(QgisFeatureBasedAlgorithm):
4841

4942
def __init__(self):
5043
super().__init__()
5144

52-
def initAlgorithm(self, config=None):
53-
self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT_LAYER, self.tr('Input layer'), [QgsProcessing.TypeVectorLine, QgsProcessing.TypeVectorPolygon]))
54-
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT_LAYER, self.tr('Boundary')))
55-
5645
def icon(self):
5746
return QIcon(os.path.join(pluginPath, 'images', 'ftools', 'convex_hull.png'))
5847

@@ -65,10 +54,10 @@ def name(self):
6554
def displayName(self):
6655
return self.tr('Boundary')
6756

68-
def processAlgorithm(self, parameters, context, feedback):
69-
source = self.parameterAsSource(parameters, self.INPUT_LAYER, context)
57+
def outputName(self):
58+
return self.tr('Boundary')
7059

71-
input_wkb = source.wkbType()
60+
def outputWkbType(self, input_wkb):
7261
if QgsWkbTypes.geometryType(input_wkb) == QgsWkbTypes.LineGeometry:
7362
output_wkb = QgsWkbTypes.MultiPoint
7463
elif QgsWkbTypes.geometryType(input_wkb) == QgsWkbTypes.PolygonGeometry:
@@ -78,26 +67,15 @@ def processAlgorithm(self, parameters, context, feedback):
7867
if QgsWkbTypes.hasM(input_wkb):
7968
output_wkb = QgsWkbTypes.addM(output_wkb)
8069

81-
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT_LAYER, context,
82-
source.fields(), output_wkb, source.sourceCrs())
83-
84-
features = source.getFeatures()
85-
total = 100.0 / source.featureCount() if source.featureCount() else 0
86-
87-
for current, input_feature in enumerate(features):
88-
if feedback.isCanceled():
89-
break
90-
output_feature = input_feature
91-
input_geometry = input_feature.geometry()
92-
if input_geometry:
93-
output_geometry = QgsGeometry(input_geometry.geometry().boundary())
94-
if not output_geometry:
95-
feedback.reportError(self.tr('No boundary for feature {} (possibly a closed linestring?)').format(input_feature.id()))
96-
output_feature.clearGeometry()
97-
else:
98-
output_feature.setGeometry(output_geometry)
99-
100-
sink.addFeature(output_feature, QgsFeatureSink.FastInsert)
101-
feedback.setProgress(int(current * total))
102-
103-
return {self.OUTPUT_LAYER: dest_id}
70+
return output_wkb
71+
72+
def processFeature(self, feature, feedback):
73+
input_geometry = feature.geometry()
74+
if input_geometry:
75+
output_geometry = QgsGeometry(input_geometry.geometry().boundary())
76+
if not output_geometry:
77+
feedback.reportError(self.tr('No boundary for feature {} (possibly a closed linestring?)').format(feature.id()))
78+
feature.clearGeometry()
79+
else:
80+
feature.setGeometry(output_geometry)
81+
return feature

‎python/plugins/processing/algs/qgis/DeleteColumn.py

Lines changed: 28 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -25,18 +25,13 @@
2525

2626
__revision__ = '$Format:%H$'
2727

28-
from qgis.core import (QgsFeatureSink,
29-
QgsProcessingParameterFeatureSource,
30-
QgsProcessingParameterFeatureSink,
31-
QgsProcessingParameterField)
32-
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
28+
from qgis.core import (QgsProcessingParameterField)
29+
from processing.algs.qgis.QgisAlgorithm import QgisFeatureBasedAlgorithm
3330

3431

35-
class DeleteColumn(QgisAlgorithm):
32+
class DeleteColumn(QgisFeatureBasedAlgorithm):
3633

37-
INPUT = 'INPUT'
3834
COLUMNS = 'COLUMN'
39-
OUTPUT = 'OUTPUT'
4035

4136
def tags(self):
4237
return self.tr('drop,delete,remove,fields,columns,attributes').split(',')
@@ -46,55 +41,44 @@ def group(self):
4641

4742
def __init__(self):
4843
super().__init__()
44+
self.fields_to_delete = []
45+
self.field_indices = []
4946

50-
def initAlgorithm(self, config=None):
51-
self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, self.tr('Input layer')))
47+
def initParameters(self, config=None):
5248
self.addParameter(QgsProcessingParameterField(self.COLUMNS,
5349
self.tr('Fields to drop'),
54-
None, self.INPUT, QgsProcessingParameterField.Any, True))
55-
56-
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Output layer')))
50+
None, 'INPUT', QgsProcessingParameterField.Any, True))
5751

5852
def name(self):
5953
return 'deletecolumn'
6054

6155
def displayName(self):
6256
return self.tr('Drop field(s)')
6357

64-
def processAlgorithm(self, parameters, context, feedback):
65-
source = self.parameterAsSource(parameters, self.INPUT, context)
66-
fields_to_delete = self.parameterAsFields(parameters, self.COLUMNS, context)
58+
def outputName(self):
59+
return self.tr('Fields dropped')
60+
61+
def prepareAlgorithm(self, parameters, context, feedback):
62+
self.fields_to_delete = self.parameterAsFields(parameters, self.COLUMNS, context)
63+
return True
6764

68-
fields = source.fields()
69-
field_indices = []
65+
def outputFields(self, input_fields):
7066
# loop through twice - first we need to build up a list of original attribute indices
71-
for f in fields_to_delete:
72-
index = fields.lookupField(f)
73-
field_indices.append(index)
67+
for f in self.fields_to_delete:
68+
index = input_fields.lookupField(f)
69+
self.field_indices.append(index)
7470

7571
# important - make sure we remove from the end so we aren't changing used indices as we go
76-
field_indices.sort(reverse=True)
72+
self.field_indices.sort(reverse=True)
7773

7874
# this second time we make a cleaned version of the fields
79-
for index in field_indices:
80-
fields.remove(index)
81-
82-
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
83-
fields, source.wkbType(), source.sourceCrs())
84-
85-
features = source.getFeatures()
86-
total = 100.0 / source.featureCount() if source.featureCount() else 0
87-
88-
for current, f in enumerate(features):
89-
if feedback.isCanceled():
90-
break
91-
92-
attributes = f.attributes()
93-
for index in field_indices:
94-
del attributes[index]
95-
f.setAttributes(attributes)
96-
sink.addFeature(f, QgsFeatureSink.FastInsert)
97-
98-
feedback.setProgress(int(current * total))
99-
100-
return {self.OUTPUT: dest_id}
75+
for index in self.field_indices:
76+
input_fields.remove(index)
77+
return input_fields
78+
79+
def processFeature(self, feature, feedback):
80+
attributes = feature.attributes()
81+
for index in self.field_indices:
82+
del attributes[index]
83+
feature.setAttributes(attributes)
84+
return feature

‎python/plugins/processing/algs/qgis/DeleteHoles.py

Lines changed: 16 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -24,32 +24,23 @@
2424

2525
__revision__ = '$Format:%H$'
2626

27-
from qgis.core import (QgsFeatureSink,
28-
QgsProcessing,
29-
QgsProcessingParameterFeatureSource,
30-
QgsProcessingParameterNumber,
31-
QgsProcessingParameterFeatureSink)
32-
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
27+
from qgis.core import (QgsProcessingParameterNumber)
28+
from processing.algs.qgis.QgisAlgorithm import QgisFeatureBasedAlgorithm
3329

3430

35-
class DeleteHoles(QgisAlgorithm):
31+
class DeleteHoles(QgisFeatureBasedAlgorithm):
3632

37-
INPUT = 'INPUT'
3833
MIN_AREA = 'MIN_AREA'
39-
OUTPUT = 'OUTPUT'
4034

4135
def __init__(self):
4236
super().__init__()
37+
self.min_area = None
4338

44-
def initAlgorithm(self, config=None):
45-
self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
46-
self.tr('Input layer'), [QgsProcessing.TypeVectorPolygon]))
39+
def initParameters(self, config=None):
4740
self.addParameter(QgsProcessingParameterNumber(self.MIN_AREA,
4841
self.tr('Remove holes with area less than'), QgsProcessingParameterNumber.Double,
4942
0, True, 0.0, 10000000.0))
5043

51-
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Cleaned'), QgsProcessing.TypeVectorPolygon))
52-
5344
def tags(self):
5445
return self.tr('remove,delete,drop,holes,rings,fill').split(',')
5546

@@ -62,25 +53,16 @@ def name(self):
6253
def displayName(self):
6354
return self.tr('Delete holes')
6455

65-
def processAlgorithm(self, parameters, context, feedback):
66-
source = self.parameterAsSource(parameters, self.INPUT, context)
67-
min_area = self.parameterAsDouble(parameters, self.MIN_AREA, context)
68-
if min_area == 0.0:
69-
min_area = -1.0
70-
71-
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
72-
source.fields(), source.wkbType(), source.sourceCrs())
73-
74-
features = source.getFeatures()
75-
total = 100.0 / source.featureCount() if source.featureCount() else 0
76-
77-
for current, f in enumerate(features):
78-
if feedback.isCanceled():
79-
break
56+
def outputName(self):
57+
return self.tr('Cleaned')
8058

81-
if f.hasGeometry():
82-
f.setGeometry(f.geometry().removeInteriorRings(min_area))
83-
sink.addFeature(f, QgsFeatureSink.FastInsert)
84-
feedback.setProgress(int(current * total))
59+
def prepareAlgorithm(self, parameters, context, feedback):
60+
self.min_area = self.parameterAsDouble(parameters, self.MIN_AREA, context)
61+
if self.min_area == 0.0:
62+
self.min_area = -1.0
63+
return True
8564

86-
return {self.OUTPUT: dest_id}
65+
def processFeature(self, feature, feedback):
66+
if feature.hasGeometry():
67+
feature.setGeometry(feature.geometry().removeInteriorRings(self.min_area))
68+
return feature

‎python/plugins/processing/algs/qgis/DensifyGeometries.py

Lines changed: 16 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -28,19 +28,14 @@
2828

2929
import os
3030

31-
from qgis.core import (QgsFeatureSink,
32-
QgsProcessing,
33-
QgsProcessingParameterFeatureSource,
34-
QgsProcessingParameterNumber,
35-
QgsProcessingParameterFeatureSink)
36-
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
31+
from qgis.core import (QgsProcessingParameterNumber)
3732

33+
from processing.algs.qgis.QgisAlgorithm import QgisFeatureBasedAlgorithm
3834

39-
class DensifyGeometries(QgisAlgorithm):
4035

41-
INPUT = 'INPUT'
36+
class DensifyGeometries(QgisFeatureBasedAlgorithm):
37+
4238
VERTICES = 'VERTICES'
43-
OUTPUT = 'OUTPUT'
4439

4540
def tags(self):
4641
return self.tr('add,vertices,points').split(',')
@@ -50,41 +45,28 @@ def group(self):
5045

5146
def __init__(self):
5247
super().__init__()
48+
self.vertices = None
5349

54-
def initAlgorithm(self, config=None):
55-
self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
56-
self.tr('Input layer'), [QgsProcessing.TypeVectorPolygon, QgsProcessing.TypeVectorLine]))
50+
def initParameters(self, config=None):
5751
self.addParameter(QgsProcessingParameterNumber(self.VERTICES,
5852
self.tr('Vertices to add'), QgsProcessingParameterNumber.Integer,
5953
1, False, 1, 10000000))
6054

61-
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Densified')))
62-
6355
def name(self):
6456
return 'densifygeometries'
6557

6658
def displayName(self):
6759
return self.tr('Densify geometries')
6860

69-
def processAlgorithm(self, parameters, context, feedback):
70-
source = self.parameterAsSource(parameters, self.INPUT, context)
71-
vertices = self.parameterAsInt(parameters, self.VERTICES, context)
72-
73-
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
74-
source.fields(), source.wkbType(), source.sourceCrs())
75-
76-
features = source.getFeatures()
77-
total = 100.0 / source.featureCount() if source.featureCount() else 0
78-
79-
for current, f in enumerate(features):
80-
if feedback.isCanceled():
81-
break
61+
def outputName(self):
62+
return self.tr('Densified')
8263

83-
feature = f
84-
if feature.hasGeometry():
85-
new_geometry = feature.geometry().densifyByCount(vertices)
86-
feature.setGeometry(new_geometry)
87-
sink.addFeature(feature, QgsFeatureSink.FastInsert)
88-
feedback.setProgress(int(current * total))
64+
def prepareAlgorithm(self, parameters, context, feedback):
65+
self.vertices = self.parameterAsInt(parameters, self.VERTICES, context)
66+
return True
8967

90-
return {self.OUTPUT: dest_id}
68+
def processFeature(self, feature, feedback):
69+
if feature.hasGeometry():
70+
new_geometry = feature.geometry().densifyByCount(self.vertices)
71+
feature.setGeometry(new_geometry)
72+
return feature

‎python/plugins/processing/algs/qgis/DensifyGeometriesInterval.py

Lines changed: 16 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -27,60 +27,42 @@
2727

2828
__revision__ = '$Format:%H$'
2929

30-
from qgis.core import (QgsFeatureSink,
31-
QgsProcessing,
32-
QgsProcessingParameterFeatureSource,
33-
QgsProcessingParameterNumber,
34-
QgsProcessingParameterFeatureSink)
35-
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
30+
from qgis.core import (QgsProcessingParameterNumber)
3631

32+
from processing.algs.qgis.QgisAlgorithm import QgisFeatureBasedAlgorithm
3733

38-
class DensifyGeometriesInterval(QgisAlgorithm):
3934

40-
INPUT = 'INPUT'
35+
class DensifyGeometriesInterval(QgisFeatureBasedAlgorithm):
36+
4137
INTERVAL = 'INTERVAL'
42-
OUTPUT = 'OUTPUT'
4338

4439
def group(self):
4540
return self.tr('Vector geometry tools')
4641

4742
def __init__(self):
4843
super().__init__()
44+
self.interval = None
4945

50-
def initAlgorithm(self, config=None):
51-
self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
52-
self.tr('Input layer'), [QgsProcessing.TypeVectorPolygon, QgsProcessing.TypeVectorLine]))
46+
def initParameters(self, config=None):
5347
self.addParameter(QgsProcessingParameterNumber(self.INTERVAL,
5448
self.tr('Interval between vertices to add'), QgsProcessingParameterNumber.Double,
5549
1, False, 0, 10000000))
5650

57-
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Densified')))
58-
5951
def name(self):
6052
return 'densifygeometriesgivenaninterval'
6153

6254
def displayName(self):
6355
return self.tr('Densify geometries given an interval')
6456

65-
def processAlgorithm(self, parameters, context, feedback):
66-
source = self.parameterAsSource(parameters, self.INPUT, context)
67-
interval = self.parameterAsDouble(parameters, self.INTERVAL, context)
68-
69-
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
70-
source.fields(), source.wkbType(), source.sourceCrs())
57+
def outputName(self):
58+
return self.tr('Densified')
7159

72-
features = source.getFeatures()
73-
total = 100.0 / source.featureCount() if source.featureCount() else 0
74-
for current, f in enumerate(features):
75-
if feedback.isCanceled():
76-
break
77-
78-
feature = f
79-
if feature.hasGeometry():
80-
new_geometry = feature.geometry().densifyByDistance(float(interval))
81-
feature.setGeometry(new_geometry)
82-
sink.addFeature(feature, QgsFeatureSink.FastInsert)
83-
84-
feedback.setProgress(int(current * total))
60+
def prepareAlgorithm(self, parameters, context, feedback):
61+
interval = self.parameterAsDouble(parameters, self.INTERVAL, context)
62+
return True
8563

86-
return {self.OUTPUT: dest_id}
64+
def processFeature(self, feature, feedback):
65+
if feature.hasGeometry():
66+
new_geometry = feature.geometry().densifyByDistance(float(interval))
67+
feature.setGeometry(new_geometry)
68+
return feature

‎python/plugins/processing/algs/qgis/DropGeometry.py

Lines changed: 13 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -25,20 +25,13 @@
2525

2626
__revision__ = '$Format:%H$'
2727

28-
from qgis.core import (QgsFeatureRequest,
29-
QgsWkbTypes,
30-
QgsFeatureSink,
31-
QgsCoordinateReferenceSystem,
32-
QgsProcessing,
33-
QgsProcessingParameterFeatureSource,
34-
QgsProcessingParameterFeatureSink)
35-
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
28+
from qgis.core import (QgsWkbTypes,
29+
QgsCoordinateReferenceSystem)
3630

31+
from processing.algs.qgis.QgisAlgorithm import QgisFeatureBasedAlgorithm
3732

38-
class DropGeometry(QgisAlgorithm):
3933

40-
INPUT = 'INPUT'
41-
OUTPUT = 'OUTPUT'
34+
class DropGeometry(QgisFeatureBasedAlgorithm):
4235

4336
def tags(self):
4437
return self.tr('remove,drop,delete,geometry,objects').split(',')
@@ -49,31 +42,21 @@ def group(self):
4942
def __init__(self):
5043
super().__init__()
5144

52-
def initAlgorithm(self, config=None):
53-
self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, self.tr('Input layer'), [QgsProcessing.TypeVectorPoint, QgsProcessing.TypeVectorLine, QgsProcessing.TypeVectorPolygon]))
54-
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Dropped geometry')))
55-
5645
def name(self):
5746
return 'dropgeometries'
5847

5948
def displayName(self):
6049
return self.tr('Drop geometries')
6150

62-
def processAlgorithm(self, parameters, context, feedback):
63-
source = self.parameterAsSource(parameters, self.INPUT, context)
64-
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
65-
source.fields(), QgsWkbTypes.NoGeometry, QgsCoordinateReferenceSystem())
66-
67-
request = QgsFeatureRequest().setFlags(QgsFeatureRequest.NoGeometry)
68-
features = source.getFeatures(request)
69-
total = 100.0 / source.featureCount() if source.featureCount() else 0
51+
def outputName(self):
52+
return self.tr('Dropped geometries')
7053

71-
for current, input_feature in enumerate(features):
72-
if feedback.isCanceled():
73-
break
54+
def outputCrs(self, input_crs):
55+
return QgsCoordinateReferenceSystem()
7456

75-
input_feature.clearGeometry()
76-
sink.addFeature(input_feature, QgsFeatureSink.FastInsert)
77-
feedback.setProgress(int(current * total))
57+
def outputWkbType(self, input_wkb_type):
58+
return QgsWkbTypes.NoGeometry
7859

79-
return {self.OUTPUT: dest_id}
60+
def processFeature(self, feature, feedback):
61+
feature.clearGeometry()
62+
return feature

‎python/plugins/processing/algs/qgis/ExtendLines.py

Lines changed: 26 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -25,20 +25,13 @@
2525

2626
__revision__ = '$Format:%H$'
2727

28-
from qgis.core import (QgsApplication,
29-
QgsFeatureSink,
30-
QgsProcessingUtils)
31-
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
32-
from processing.core.GeoAlgorithmExecutionException import GeoAlgorithmExecutionException
33-
from processing.core.parameters import ParameterVector, ParameterNumber
34-
from processing.core.outputs import OutputVector
35-
from processing.tools import dataobjects
28+
from qgis.core import (QgsProcessingParameterNumber,
29+
QgsProcessingException)
30+
from processing.algs.qgis.QgisAlgorithm import QgisFeatureBasedAlgorithm
3631

3732

38-
class ExtendLines(QgisAlgorithm):
33+
class ExtendLines(QgisFeatureBasedAlgorithm):
3934

40-
INPUT_LAYER = 'INPUT_LAYER'
41-
OUTPUT_LAYER = 'OUTPUT_LAYER'
4235
START_DISTANCE = 'START_DISTANCE'
4336
END_DISTANCE = 'END_DISTANCE'
4437

@@ -47,47 +40,37 @@ def group(self):
4740

4841
def __init__(self):
4942
super().__init__()
43+
self.start_distance = None
44+
self.end_distance = None
5045

51-
def initAlgorithm(self, config=None):
52-
self.addParameter(ParameterVector(self.INPUT_LAYER,
53-
self.tr('Input layer'), [dataobjects.TYPE_VECTOR_LINE]))
54-
self.addParameter(ParameterNumber(self.START_DISTANCE,
55-
self.tr('Start distance'), default=0.0))
56-
self.addParameter(ParameterNumber(self.END_DISTANCE,
57-
self.tr('End distance'), default=0.0))
58-
59-
self.addOutput(OutputVector(self.OUTPUT_LAYER, self.tr('Extended lines')))
46+
def initParameters(self, config=None):
47+
self.addParameter(QgsProcessingParameterNumber(self.START_DISTANCE,
48+
self.tr('Start distance'), defaultValue=0.0))
49+
self.addParameter(QgsProcessingParameterNumber(self.END_DISTANCE,
50+
self.tr('End distance'), defaultValue=0.0))
6051

6152
def name(self):
6253
return 'extendlines'
6354

6455
def displayName(self):
6556
return self.tr('Extend lines')
6657

67-
def processAlgorithm(self, parameters, context, feedback):
68-
layer = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.INPUT_LAYER), context)
69-
70-
writer = self.getOutputFromName(
71-
self.OUTPUT_LAYER).getVectorWriter(layer.fields(), layer.wkbType(), layer.crs(), context)
72-
73-
start_distance = self.getParameterValue(self.START_DISTANCE)
74-
end_distance = self.getParameterValue(self.END_DISTANCE)
75-
76-
features = QgsProcessingUtils.getFeatures(layer, context)
77-
total = 100.0 / layer.featureCount() if layer.featureCount() else 0
58+
def outputName(self):
59+
return self.tr('Extended')
7860

79-
for current, input_feature in enumerate(features):
80-
output_feature = input_feature
81-
input_geometry = input_feature.geometry()
82-
if input_geometry:
83-
output_geometry = input_geometry.extendLine(start_distance, end_distance)
84-
if not output_geometry:
85-
raise GeoAlgorithmExecutionException(
86-
self.tr('Error calculating extended line'))
61+
def prepareAlgorithm(self, parameters, context, feedback):
62+
self.start_distance = self.parameterAsDouble(parameters, self.START_DISTANCE, context)
63+
self.end_distance = self.parameterAsDouble(parameters, self.END_DISTANCE, context)
64+
return True
8765

88-
output_feature.setGeometry(output_geometry)
66+
def processFeature(self, feature, feedback):
67+
input_geometry = feature.geometry()
68+
if input_geometry:
69+
output_geometry = input_geometry.extendLine(self.start_distance, self.end_distance)
70+
if not output_geometry:
71+
raise QgsProcessingException(
72+
self.tr('Error calculating extended line'))
8973

90-
writer.addFeature(output_feature, QgsFeatureSink.FastInsert)
91-
feedback.setProgress(int(current * total))
74+
feature.setGeometry(output_geometry)
9275

93-
del writer
76+
return feature

‎python/plugins/processing/algs/qgis/GeometryByExpression.py

Lines changed: 63 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -27,23 +27,17 @@
2727

2828
from qgis.core import (QgsWkbTypes,
2929
QgsExpression,
30-
QgsFeatureSink,
31-
QgsExpressionContext,
32-
QgsExpressionContextUtils,
3330
QgsGeometry,
34-
QgsApplication,
35-
QgsProcessingUtils)
31+
QgsProcessingException,
32+
QgsProcessingParameterBoolean,
33+
QgsProcessingParameterEnum,
34+
QgsProcessingParameterExpression)
3635

37-
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
38-
from processing.core.GeoAlgorithmExecutionException import GeoAlgorithmExecutionException
39-
from processing.core.parameters import ParameterVector, ParameterSelection, ParameterBoolean, ParameterExpression
40-
from processing.core.outputs import OutputVector
36+
from processing.algs.qgis.QgisAlgorithm import QgisFeatureBasedAlgorithm
4137

4238

43-
class GeometryByExpression(QgisAlgorithm):
39+
class GeometryByExpression(QgisFeatureBasedAlgorithm):
4440

45-
INPUT_LAYER = 'INPUT_LAYER'
46-
OUTPUT_LAYER = 'OUTPUT_LAYER'
4741
OUTPUT_GEOMETRY = 'OUTPUT_GEOMETRY'
4842
WITH_Z = 'WITH_Z'
4943
WITH_M = 'WITH_M'
@@ -54,83 +48,75 @@ def group(self):
5448

5549
def __init__(self):
5650
super().__init__()
57-
58-
def initAlgorithm(self, config=None):
59-
self.addParameter(ParameterVector(self.INPUT_LAYER,
60-
self.tr('Input layer')))
61-
6251
self.geometry_types = [self.tr('Polygon'),
6352
'Line',
6453
'Point']
65-
self.addParameter(ParameterSelection(
54+
55+
def initParameters(self, config=None):
56+
self.addParameter(QgsProcessingParameterEnum(
6657
self.OUTPUT_GEOMETRY,
6758
self.tr('Output geometry type'),
68-
self.geometry_types, default=0))
69-
self.addParameter(ParameterBoolean(self.WITH_Z,
70-
self.tr('Output geometry has z dimension'), False))
71-
self.addParameter(ParameterBoolean(self.WITH_M,
72-
self.tr('Output geometry has m values'), False))
59+
options=self.geometry_types, defaultValue=0))
60+
self.addParameter(QgsProcessingParameterBoolean(self.WITH_Z,
61+
self.tr('Output geometry has z dimension'), defaultValue=False))
62+
self.addParameter(QgsProcessingParameterBoolean(self.WITH_M,
63+
self.tr('Output geometry has m values'), defaultValue=False))
7364

74-
self.addParameter(ParameterExpression(self.EXPRESSION,
75-
self.tr("Geometry expression"), '$geometry', parent_layer=self.INPUT_LAYER))
76-
77-
self.addOutput(OutputVector(self.OUTPUT_LAYER, self.tr('Modified geometry')))
65+
self.addParameter(QgsProcessingParameterExpression(self.EXPRESSION,
66+
self.tr("Geometry expression"), defaultValue='$geometry', parentLayerParameterName='INPUT'))
7867

7968
def name(self):
8069
return 'geometrybyexpression'
8170

8271
def displayName(self):
8372
return self.tr('Geometry by expression')
8473

85-
def processAlgorithm(self, parameters, context, feedback):
86-
layer = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.INPUT_LAYER), context)
74+
def outputName(self):
75+
return self.tr('Modified geometry')
8776

88-
geometry_type = self.getParameterValue(self.OUTPUT_GEOMETRY)
89-
wkb_type = None
90-
if geometry_type == 0:
91-
wkb_type = QgsWkbTypes.Polygon
92-
elif geometry_type == 1:
93-
wkb_type = QgsWkbTypes.LineString
77+
def prepareAlgorithm(self, parameters, context, feedback):
78+
self.geometry_type = self.parameterAsEnum(parameters, self.OUTPUT_GEOMETRY, context)
79+
self.wkb_type = None
80+
if self.geometry_type == 0:
81+
self.wkb_type = QgsWkbTypes.Polygon
82+
elif self.geometry_type == 1:
83+
self.wkb_type = QgsWkbTypes.LineString
84+
else:
85+
self.wkb_type = QgsWkbTypes.Point
86+
if self.parameterAsBool(parameters, self.WITH_Z, context):
87+
self.wkb_type = QgsWkbTypes.addZ(self.wkb_type)
88+
if self.parameterAsBool(parameters, self.WITH_M, context):
89+
self.wkb_type = QgsWkbTypes.addM(self.wkb_type)
90+
91+
self.expression = QgsExpression(self.parameterAsString(parameters, self.EXPRESSION, context))
92+
if self.expression.hasParserError():
93+
feedback.reportError(self.expression.parserErrorString())
94+
return False
95+
96+
self.expression_context = self.createExpressionContext(parameters, context)
97+
98+
if not self.expression.prepare(self.expression_context):
99+
feedback.reportErro(
100+
self.tr('Evaluation error: {0}').format(self.expression.evalErrorString()))
101+
return False
102+
103+
return True
104+
105+
def outputWkbType(self, input_wkb_type):
106+
return self.wkb_type
107+
108+
def processFeature(self, feature, feedback):
109+
self.expression_context.setFeature(feature)
110+
value = self.expression.evaluate(self.expression_context)
111+
if self.expression.hasEvalError():
112+
raise QgsProcessingException(
113+
self.tr('Evaluation error: {0}').format(self.expression.evalErrorString()))
114+
115+
if not value:
116+
feature.setGeometry(QgsGeometry())
94117
else:
95-
wkb_type = QgsWkbTypes.Point
96-
if self.getParameterValue(self.WITH_Z):
97-
wkb_type = QgsWkbTypes.addZ(wkb_type)
98-
if self.getParameterValue(self.WITH_M):
99-
wkb_type = QgsWkbTypes.addM(wkb_type)
100-
101-
writer = self.getOutputFromName(
102-
self.OUTPUT_LAYER).getVectorWriter(layer.fields(), wkb_type, layer.crs(), context)
103-
104-
expression = QgsExpression(self.getParameterValue(self.EXPRESSION))
105-
if expression.hasParserError():
106-
raise GeoAlgorithmExecutionException(expression.parserErrorString())
107-
108-
exp_context = QgsExpressionContext(QgsExpressionContextUtils.globalProjectLayerScopes(layer))
109-
110-
if not expression.prepare(exp_context):
111-
raise GeoAlgorithmExecutionException(
112-
self.tr('Evaluation error: {0}').format(expression.evalErrorString()))
113-
114-
features = QgsProcessingUtils.getFeatures(layer, context)
115-
total = 100.0 / layer.featureCount() if layer.featureCount() else 0
116-
for current, input_feature in enumerate(features):
117-
output_feature = input_feature
118-
119-
exp_context.setFeature(input_feature)
120-
value = expression.evaluate(exp_context)
121-
if expression.hasEvalError():
122-
raise GeoAlgorithmExecutionException(
123-
self.tr('Evaluation error: {0}').format(expression.evalErrorString()))
124-
125-
if not value:
126-
output_feature.setGeometry(QgsGeometry())
127-
else:
128-
if not isinstance(value, QgsGeometry):
129-
raise GeoAlgorithmExecutionException(
130-
self.tr('{} is not a geometry').format(value))
131-
output_feature.setGeometry(value)
132-
133-
writer.addFeature(output_feature, QgsFeatureSink.FastInsert)
134-
feedback.setProgress(int(current * total))
135-
136-
del writer
118+
if not isinstance(value, QgsGeometry):
119+
raise QgsProcessingException(
120+
self.tr('{} is not a geometry').format(value))
121+
feature.setGeometry(value)
122+
return feature

‎python/plugins/processing/algs/qgis/LinesToPolygons.py

Lines changed: 14 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -42,16 +42,13 @@
4242
QgsProcessingParameterFeatureSink,
4343
QgsProcessingUtils)
4444

45-
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
45+
from processing.algs.qgis.QgisAlgorithm import QgisFeatureBasedAlgorithm
4646
from processing.tools import dataobjects, vector
4747

4848
pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0]
4949

5050

51-
class LinesToPolygons(QgisAlgorithm):
52-
53-
INPUT = 'INPUT'
54-
OUTPUT = 'OUTPUT'
51+
class LinesToPolygons(QgisFeatureBasedAlgorithm):
5552

5653
def icon(self):
5754
return QIcon(os.path.join(pluginPath, 'images', 'ftools', 'to_lines.png'))
@@ -65,52 +62,27 @@ def group(self):
6562
def __init__(self):
6663
super().__init__()
6764

68-
def initAlgorithm(self, config=None):
69-
self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
70-
self.tr('Input layer'),
71-
[QgsProcessing.TypeVectorLine]))
72-
73-
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT,
74-
self.tr('Lines to polygons'),
75-
QgsProcessing.TypeVectorPolygon))
76-
7765
def name(self):
7866
return 'linestopolygons'
7967

8068
def displayName(self):
8169
return self.tr('Lines to polygons')
8270

83-
def processAlgorithm(self, parameters, context, feedback):
84-
source = self.parameterAsSource(parameters, self.INPUT, context)
85-
86-
geomType = self.convertWkbToPolygons(source.wkbType())
87-
88-
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
89-
source.fields(), geomType, source.sourceCrs())
90-
91-
outFeat = QgsFeature()
92-
93-
total = 100.0 / source.featureCount() if source.featureCount() else 0
94-
count = 0
95-
96-
for feat in source.getFeatures():
97-
if feedback.isCanceled():
98-
break
71+
def outputName(self):
72+
return self.tr('Polygons')
9973

100-
if feat.hasGeometry():
101-
outFeat.setGeometry(QgsGeometry(self.convertToPolygons(feat.geometry())))
102-
attrs = feat.attributes()
103-
outFeat.setAttributes(attrs)
104-
sink.addFeature(outFeat, QgsFeatureSink.FastInsert)
105-
if outFeat.geometry().isEmpty():
106-
feedback.reportError(self.tr("One or more line ignored due to geometry not having a minimum of three vertices."))
107-
else:
108-
sink.addFeature(feat, QgsFeatureSink.FastInsert)
74+
def outputType(self):
75+
return QgsProcessing.TypeVectorPolygon
10976

110-
count += 1
111-
feedback.setProgress(int(count * total))
77+
def outputWkbType(self, input_wkb_type):
78+
return self.convertWkbToPolygons(input_wkb_type)
11279

113-
return {self.OUTPUT: dest_id}
80+
def processFeature(self, feature, feedback):
81+
if feature.hasGeometry():
82+
feature.setGeometry(QgsGeometry(self.convertToPolygons(feature.geometry())))
83+
if feature.geometry().isEmpty():
84+
feedback.reportError(self.tr("One or more line ignored due to geometry not having a minimum of three vertices."))
85+
return feature
11486

11587
def convertWkbToPolygons(self, wkb):
11688
multi_wkb = None

‎python/plugins/processing/algs/qgis/OffsetLine.py

Lines changed: 28 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,13 @@
3535
QgsProcessingParameterEnum,
3636
QgsProcessingParameterFeatureSink)
3737

38-
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
38+
from processing.algs.qgis.QgisAlgorithm import QgisFeatureBasedAlgorithm
3939

4040
pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0]
4141

4242

43-
class OffsetLine(QgisAlgorithm):
44-
INPUT = 'INPUT'
45-
OUTPUT = 'OUTPUT'
43+
class OffsetLine(QgisFeatureBasedAlgorithm):
44+
4645
DISTANCE = 'DISTANCE'
4746
SEGMENTS = 'SEGMENTS'
4847
JOIN_STYLE = 'JOIN_STYLE'
@@ -54,9 +53,12 @@ def group(self):
5453
def __init__(self):
5554
super().__init__()
5655

57-
def initAlgorithm(self, config=None):
58-
self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, self.tr('Input layer'),
59-
[QgsProcessing.TypeVectorLine]))
56+
self.distance = None
57+
self.segments = None
58+
self.join_style = None
59+
self.miter_limit = None
60+
61+
def initParameters(self, config=None):
6062
self.addParameter(QgsProcessingParameterNumber(self.DISTANCE,
6163
self.tr('Distance'),
6264
type=QgsProcessingParameterNumber.Double,
@@ -76,43 +78,33 @@ def initAlgorithm(self, config=None):
7678
self.tr('Mitre limit'), type=QgsProcessingParameterNumber.Double,
7779
minValue=1, defaultValue=2))
7880

79-
self.addParameter(
80-
QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Offset'), QgsProcessing.TypeVectorLine))
81-
8281
def name(self):
8382
return 'offsetline'
8483

8584
def displayName(self):
8685
return self.tr('Offset line')
8786

88-
def processAlgorithm(self, parameters, context, feedback):
89-
source = self.parameterAsSource(parameters, self.INPUT, context)
90-
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
91-
source.fields(), source.wkbType(), source.sourceCrs())
92-
93-
distance = self.parameterAsDouble(parameters, self.DISTANCE, context)
94-
segments = self.parameterAsInt(parameters, self.SEGMENTS, context)
95-
join_style = self.parameterAsEnum(parameters, self.JOIN_STYLE, context) + 1
96-
miter_limit = self.parameterAsDouble(parameters, self.MITRE_LIMIT, context)
97-
98-
features = source.getFeatures()
99-
total = 100.0 / source.featureCount() if source.featureCount() else 0
87+
def outputName(self):
88+
return self.tr('Offset')
10089

101-
for current, input_feature in enumerate(features):
102-
if feedback.isCanceled():
103-
break
90+
def outputType(self):
91+
return QgsProcessing.TypeVectorLine
10492

105-
output_feature = input_feature
106-
input_geometry = input_feature.geometry()
107-
if input_geometry:
108-
output_geometry = input_geometry.offsetCurve(distance, segments, join_style, miter_limit)
109-
if not output_geometry:
110-
raise QgsProcessingException(
111-
self.tr('Error calculating line offset'))
93+
def prepareAlgorithm(self, parameters, context, feedback):
94+
self.distance = self.parameterAsDouble(parameters, self.DISTANCE, context)
95+
self.segments = self.parameterAsInt(parameters, self.SEGMENTS, context)
96+
self.join_style = self.parameterAsEnum(parameters, self.JOIN_STYLE, context) + 1
97+
self.miter_limit = self.parameterAsDouble(parameters, self.MITRE_LIMIT, context)
98+
return True
11299

113-
output_feature.setGeometry(output_geometry)
100+
def processFeature(self, feature, feedback):
101+
input_geometry = feature.geometry()
102+
if input_geometry:
103+
output_geometry = input_geometry.offsetCurve(self.distance, self.segments, self.join_style, self.miter_limit)
104+
if not output_geometry:
105+
raise QgsProcessingException(
106+
self.tr('Error calculating line offset'))
114107

115-
sink.addFeature(output_feature, QgsFeatureSink.FastInsert)
116-
feedback.setProgress(int(current * total))
108+
feature.setGeometry(output_geometry)
117109

118-
return {self.OUTPUT: dest_id}
110+
return feature

‎python/plugins/processing/algs/qgis/Orthogonalize.py

Lines changed: 23 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -25,19 +25,14 @@
2525

2626
__revision__ = '$Format:%H$'
2727

28-
from qgis.core import (QgsFeatureSink,
29-
QgsProcessingException,
30-
QgsProcessing,
28+
from qgis.core import (QgsProcessingException,
3129
QgsProcessingParameterDefinition,
32-
QgsProcessingParameterFeatureSource,
33-
QgsProcessingParameterNumber,
34-
QgsProcessingParameterFeatureSink)
35-
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
30+
QgsProcessingParameterNumber)
31+
from processing.algs.qgis.QgisAlgorithm import QgisFeatureBasedAlgorithm
3632

3733

38-
class Orthogonalize(QgisAlgorithm):
39-
INPUT = 'INPUT'
40-
OUTPUT = 'OUTPUT'
34+
class Orthogonalize(QgisFeatureBasedAlgorithm):
35+
4136
MAX_ITERATIONS = 'MAX_ITERATIONS'
4237
DISTANCE_THRESHOLD = 'DISTANCE_THRESHOLD'
4338
ANGLE_TOLERANCE = 'ANGLE_TOLERANCE'
@@ -50,12 +45,10 @@ def group(self):
5045

5146
def __init__(self):
5247
super().__init__()
48+
self.max_iterations = None
49+
self.angle_tolerance = None
5350

54-
def initAlgorithm(self, config=None):
55-
self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, self.tr('Input layer'),
56-
[QgsProcessing.TypeVectorLine,
57-
QgsProcessing.TypeVectorPolygon]))
58-
51+
def initParameters(self, config=None):
5952
self.addParameter(QgsProcessingParameterNumber(self.ANGLE_TOLERANCE,
6053
self.tr('Maximum angle tolerance (degrees)'),
6154
type=QgsProcessingParameterNumber.Double,
@@ -68,41 +61,27 @@ def initAlgorithm(self, config=None):
6861
max_iterations.setFlags(max_iterations.flags() | QgsProcessingParameterDefinition.FlagAdvanced)
6962
self.addParameter(max_iterations)
7063

71-
self.addParameter(
72-
QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Orthogonalized')))
73-
7464
def name(self):
7565
return 'orthogonalize'
7666

7767
def displayName(self):
7868
return self.tr('Orthogonalize')
7969

80-
def processAlgorithm(self, parameters, context, feedback):
81-
source = self.parameterAsSource(parameters, self.INPUT, context)
82-
max_iterations = self.parameterAsInt(parameters, self.MAX_ITERATIONS, context)
83-
angle_tolerance = self.parameterAsDouble(parameters, self.ANGLE_TOLERANCE, context)
84-
85-
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
86-
source.fields(), source.wkbType(), source.sourceCrs())
87-
88-
features = source.getFeatures()
89-
total = 100.0 / source.featureCount() if source.featureCount() else 0
90-
91-
for current, input_feature in enumerate(features):
92-
if feedback.isCanceled():
93-
break
94-
95-
output_feature = input_feature
96-
input_geometry = input_feature.geometry()
97-
if input_geometry:
98-
output_geometry = input_geometry.orthogonalize(1.0e-8, max_iterations, angle_tolerance)
99-
if not output_geometry:
100-
raise QgsProcessingException(
101-
self.tr('Error orthogonalizing geometry'))
70+
def outputName(self):
71+
return self.tr('Orthogonalized')
10272

103-
output_feature.setGeometry(output_geometry)
73+
def prepareAlgorithm(self, parameters, context, feedback):
74+
self.max_iterations = self.parameterAsInt(parameters, self.MAX_ITERATIONS, context)
75+
self.angle_tolerance = self.parameterAsDouble(parameters, self.ANGLE_TOLERANCE, context)
76+
return True
10477

105-
sink.addFeature(output_feature, QgsFeatureSink.FastInsert)
106-
feedback.setProgress(int(current * total))
78+
def processFeature(self, feature, feedback):
79+
input_geometry = feature.geometry()
80+
if input_geometry:
81+
output_geometry = input_geometry.orthogonalize(1.0e-8, self.max_iterations, self.angle_tolerance)
82+
if not output_geometry:
83+
raise QgsProcessingException(
84+
self.tr('Error orthogonalizing geometry'))
10785

108-
return {self.OUTPUT: dest_id}
86+
feature.setGeometry(output_geometry)
87+
return feature

‎python/plugins/processing/algs/qgis/PointOnSurface.py

Lines changed: 19 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -27,24 +27,18 @@
2727

2828
import os
2929

30-
from qgis.core import (QgsWkbTypes,
31-
QgsFeatureSink,
32-
QgsProcessing,
33-
QgsProcessingParameterFeatureSource,
34-
QgsProcessingParameterFeatureSink)
30+
from qgis.core import (QgsProcessing,
31+
QgsProcessingException,
32+
QgsWkbTypes)
3533

3634
from qgis.PyQt.QtGui import QIcon
3735

38-
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
39-
from processing.tools import dataobjects
36+
from processing.algs.qgis.QgisAlgorithm import QgisFeatureBasedAlgorithm
4037

4138
pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0]
4239

4340

44-
class PointOnSurface(QgisAlgorithm):
45-
46-
INPUT_LAYER = 'INPUT_LAYER'
47-
OUTPUT_LAYER = 'OUTPUT_LAYER'
41+
class PointOnSurface(QgisFeatureBasedAlgorithm):
4842

4943
def icon(self):
5044
return QIcon(os.path.join(pluginPath, 'images', 'ftools', 'centroids.png'))
@@ -55,39 +49,27 @@ def group(self):
5549
def __init__(self):
5650
super().__init__()
5751

58-
def initAlgorithm(self, config=None):
59-
self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT_LAYER,
60-
self.tr('Input layer')))
61-
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT_LAYER, self.tr('Point'), QgsProcessing.TypeVectorPoint))
62-
6352
def name(self):
6453
return 'pointonsurface'
6554

6655
def displayName(self):
6756
return self.tr('Point on surface')
6857

69-
def processAlgorithm(self, parameters, context, feedback):
70-
source = self.parameterAsSource(parameters, self.INPUT_LAYER, context)
71-
72-
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT_LAYER, context, source.fields(), QgsWkbTypes.Point, source.sourceCrs())
73-
74-
features = source.getFeatures()
75-
total = 100.0 / source.featureCount() if source.featureCount() else 0
76-
77-
for current, input_feature in enumerate(features):
78-
if feedback.isCanceled():
79-
break
58+
def outputName(self):
59+
return self.tr('Point')
8060

81-
output_feature = input_feature
82-
input_geometry = input_feature.geometry()
83-
if input_geometry:
84-
output_geometry = input_geometry.pointOnSurface()
85-
if not output_geometry:
86-
raise QgsProcessingException(self.tr('Error calculating point on surface: `{error_message}`'.format(error_message=output_geometry.error())))
61+
def outputType(self):
62+
return QgsProcessing.TypeVectorPoint
8763

88-
output_feature.setGeometry(output_geometry)
64+
def outputWkbType(self, input_wkb_type):
65+
return QgsWkbTypes.Point
8966

90-
sink.addFeature(output_feature, QgsFeatureSink.FastInsert)
91-
feedback.setProgress(int(current * total))
67+
def processFeature(self, feature, feedback):
68+
input_geometry = feature.geometry()
69+
if input_geometry:
70+
output_geometry = input_geometry.pointOnSurface()
71+
if not output_geometry:
72+
raise QgsProcessingException(self.tr('Error calculating point on surface: `{error_message}`'.format(error_message=output_geometry.error())))
9273

93-
return {self.OUTPUT_LAYER: dest_id}
74+
feature.setGeometry(output_geometry)
75+
return feature

‎python/plugins/processing/algs/qgis/PolygonsToLines.py

Lines changed: 14 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -29,28 +29,19 @@
2929

3030
from qgis.PyQt.QtGui import QIcon
3131

32-
from qgis.core import (QgsFeature,
33-
QgsGeometry,
32+
from qgis.core import (QgsGeometry,
3433
QgsGeometryCollection,
3534
QgsMultiLineString,
3635
QgsMultiCurve,
3736
QgsWkbTypes,
38-
QgsFeatureSink,
39-
QgsProcessing,
40-
QgsProcessingParameterFeatureSource,
41-
QgsProcessingParameterFeatureSink,
42-
QgsProcessingUtils)
37+
QgsProcessing)
4338

44-
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
45-
from processing.tools import dataobjects
39+
from processing.algs.qgis.QgisAlgorithm import QgisFeatureBasedAlgorithm
4640

4741
pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0]
4842

4943

50-
class PolygonsToLines(QgisAlgorithm):
51-
52-
INPUT = 'INPUT'
53-
OUTPUT = 'OUTPUT'
44+
class PolygonsToLines(QgisFeatureBasedAlgorithm):
5445

5546
def icon(self):
5647
return QIcon(os.path.join(pluginPath, 'images', 'ftools', 'to_lines.png'))
@@ -64,50 +55,25 @@ def group(self):
6455
def __init__(self):
6556
super().__init__()
6657

67-
def initAlgorithm(self, config=None):
68-
self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
69-
self.tr('Input layer'),
70-
[QgsProcessing.TypeVectorPolygon]))
71-
72-
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT,
73-
self.tr('Polygons to lines'),
74-
QgsProcessing.TypeVectorLine))
75-
7658
def name(self):
7759
return 'polygonstolines'
7860

7961
def displayName(self):
8062
return self.tr('Polygons to lines')
8163

82-
def processAlgorithm(self, parameters, context, feedback):
83-
source = self.parameterAsSource(parameters, self.INPUT, context)
84-
85-
geomType = self.convertWkbToLines(source.wkbType())
86-
87-
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
88-
source.fields(), geomType, source.sourceCrs())
89-
90-
outFeat = QgsFeature()
91-
92-
total = 100.0 / source.featureCount() if source.featureCount() else 0
93-
count = 0
94-
95-
for feat in source.getFeatures():
96-
if feedback.isCanceled():
97-
break
64+
def outputName(self):
65+
return self.tr('Lines')
9866

99-
if feat.hasGeometry():
100-
outFeat.setGeometry(QgsGeometry(self.convertToLines(feat.geometry())))
101-
attrs = feat.attributes()
102-
outFeat.setAttributes(attrs)
103-
sink.addFeature(outFeat, QgsFeatureSink.FastInsert)
104-
else:
105-
sink.addFeature(feat, QgsFeatureSink.FastInsert)
67+
def outputType(self):
68+
return QgsProcessing.TypeVectorLine
10669

107-
count += 1
108-
feedback.setProgress(int(count * total))
70+
def outputWkbType(self, input_wkb_type):
71+
return self.convertWkbToLines(input_wkb_type)
10972

110-
return {self.OUTPUT: dest_id}
73+
def processFeature(self, feature, feedback):
74+
if feature.hasGeometry():
75+
feature.setGeometry(QgsGeometry(self.convertToLines(feature.geometry())))
76+
return feature
11177

11278
def convertWkbToLines(self, wkb):
11379
multi_wkb = None

‎python/plugins/processing/algs/qgis/QGISAlgorithmProvider.py

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,11 @@
5757
from .Difference import Difference
5858
from .DropGeometry import DropGeometry
5959
from .DropMZValues import DropMZValues
60+
from .ExtendLines import ExtendLines
6061
from .ExtentFromLayer import ExtentFromLayer
6162
from .ExtractNodes import ExtractNodes
6263
from .FixGeometry import FixGeometry
64+
from .GeometryByExpression import GeometryByExpression
6365
from .GridPolygon import GridPolygon
6466
from .Heatmap import Heatmap
6567
from .Hillshade import Hillshade
@@ -96,12 +98,14 @@
9698
from .ShortestPathPointToLayer import ShortestPathPointToLayer
9799
from .ShortestPathPointToPoint import ShortestPathPointToPoint
98100
from .SimplifyGeometries import SimplifyGeometries
101+
from .SingleSidedBuffer import SingleSidedBuffer
99102
from .Slope import Slope
100103
from .Smooth import Smooth
101104
from .SnapGeometries import SnapGeometriesToLayer
102105
from .SpatialiteExecuteSQL import SpatialiteExecuteSQL
103106
from .SumLines import SumLines
104107
from .SymmetricalDifference import SymmetricalDifference
108+
from .Translate import Translate
105109
from .Union import Union
106110
from .UniqueValues import UniqueValues
107111
from .VectorSplit import VectorSplit
@@ -156,15 +160,11 @@
156160
# from .RectanglesOvalsDiamondsVariable import RectanglesOvalsDiamondsVariable
157161
# from .RectanglesOvalsDiamondsFixed import RectanglesOvalsDiamondsFixed
158162
# from .MergeLines import MergeLines
159-
# from .Translate import Translate
160-
# from .SingleSidedBuffer import SingleSidedBuffer
161163
# from .PointsAlongGeometry import PointsAlongGeometry
162164
# from .Relief import Relief
163165
# from .IdwInterpolation import IdwInterpolation
164166
# from .TinInterpolation import TinInterpolation
165-
# from .ExtendLines import ExtendLines
166167
# from .ExtractSpecificNodes import ExtractSpecificNodes
167-
# from .GeometryByExpression import GeometryByExpression
168168
# from .RasterCalculator import RasterCalculator
169169
# from .TruncateTable import TruncateTable
170170
# from .Polygonize import Polygonize
@@ -217,12 +217,10 @@ def getAlgs(self):
217217
# SpatialIndex(), DefineProjection(),
218218
# RectanglesOvalsDiamondsVariable(),
219219
# RectanglesOvalsDiamondsFixed(), MergeLines(),
220-
# Translate(),
221-
# SingleSidedBuffer(), PointsAlongGeometry(),
220+
# PointsAlongGeometry(),
222221
# Relief(),
223222
# IdwInterpolation(), TinInterpolation(),
224-
# ExtendLines(), ExtractSpecificNodes(),
225-
# GeometryByExpression(),
223+
# ExtractSpecificNodes(),
226224
# RasterCalculator(),
227225
# ShortestPathPointToPoint(), ShortestPathPointToLayer(),
228226
# ShortestPathLayerToPoint(), ServiceAreaFromPoint(),
@@ -247,9 +245,11 @@ def getAlgs(self):
247245
Difference(),
248246
DropGeometry(),
249247
DropMZValues(),
248+
ExtendLines(),
250249
ExtentFromLayer(),
251250
ExtractNodes(),
252251
FixGeometry(),
252+
GeometryByExpression(),
253253
GridPolygon(),
254254
Heatmap(),
255255
Hillshade(),
@@ -286,12 +286,14 @@ def getAlgs(self):
286286
ShortestPathPointToLayer(),
287287
ShortestPathPointToPoint(),
288288
SimplifyGeometries(),
289+
SingleSidedBuffer(),
289290
Slope(),
290291
Smooth(),
291292
SnapGeometriesToLayer(),
292293
SpatialiteExecuteSQL(),
293294
SumLines(),
294295
SymmetricalDifference(),
296+
Translate(),
295297
Union(),
296298
UniqueValues(),
297299
VectorSplit(),

‎python/plugins/processing/algs/qgis/ReverseLineDirection.py

Lines changed: 17 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -26,61 +26,39 @@
2626
__revision__ = '$Format:%H$'
2727

2828
from qgis.core import (QgsGeometry,
29-
QgsFeature,
30-
QgsFeatureSink,
3129
QgsProcessingException,
32-
QgsProcessing,
33-
QgsProcessingParameterFeatureSource,
34-
QgsProcessingParameterFeatureSink)
35-
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
30+
QgsProcessing)
31+
from processing.algs.qgis.QgisAlgorithm import QgisFeatureBasedAlgorithm
3632

3733

38-
class ReverseLineDirection(QgisAlgorithm):
39-
40-
INPUT = 'INPUT'
41-
OUTPUT = 'OUTPUT'
34+
class ReverseLineDirection(QgisFeatureBasedAlgorithm):
4235

4336
def group(self):
4437
return self.tr('Vector geometry tools')
4538

4639
def __init__(self):
4740
super().__init__()
4841

49-
def initAlgorithm(self, config=None):
50-
self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, self.tr('Input layer'),
51-
[QgsProcessing.TypeVectorLine]))
52-
self.addParameter(
53-
QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Reversed'), QgsProcessing.TypeVectorLine))
54-
5542
def name(self):
5643
return 'reverselinedirection'
5744

5845
def displayName(self):
5946
return self.tr('Reverse line direction')
6047

61-
def processAlgorithm(self, parameters, context, feedback):
62-
source = self.parameterAsSource(parameters, self.INPUT, context)
63-
64-
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
65-
source.fields(), source.wkbType(), source.sourceCrs())
66-
67-
features = source.getFeatures()
68-
total = 100.0 / source.featureCount() if source.featureCount() else 0
69-
for current, inFeat in enumerate(features):
70-
if feedback.isCanceled():
71-
break
48+
def outputName(self):
49+
return self.tr('Reversed')
7250

73-
outFeat = inFeat
74-
if inFeat.geometry():
75-
inGeom = inFeat.geometry()
76-
reversedLine = inGeom.geometry().reversed()
77-
if not reversedLine:
78-
raise QgsProcessingException(
79-
self.tr('Error reversing line'))
80-
outGeom = QgsGeometry(reversedLine)
51+
def outputType(self):
52+
return QgsProcessing.TypeVectorLine
8153

82-
outFeat.setGeometry(outGeom)
83-
sink.addFeature(outFeat, QgsFeatureSink.FastInsert)
84-
feedback.setProgress(int(current * total))
54+
def processFeature(self, feature, feedback):
55+
if feature.geometry():
56+
inGeom = feature.geometry()
57+
reversedLine = inGeom.geometry().reversed()
58+
if not reversedLine:
59+
raise QgsProcessingException(
60+
self.tr('Error reversing line'))
61+
outGeom = QgsGeometry(reversedLine)
8562

86-
return {self.OUTPUT: dest_id}
63+
feature.setGeometry(outGeom)
64+
return feature

‎python/plugins/processing/algs/qgis/SimplifyGeometries.py

Lines changed: 23 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -30,24 +30,17 @@
3030
from qgis.PyQt.QtGui import QIcon
3131

3232
from qgis.core import (QgsMapToPixelSimplifier,
33-
QgsMessageLog,
34-
QgsFeatureSink,
35-
QgsProcessing,
36-
QgsProcessingParameterFeatureSource,
37-
QgsProcessingParameterFeatureSink,
3833
QgsProcessingParameterEnum,
3934
QgsProcessingParameterNumber)
4035

41-
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
36+
from processing.algs.qgis.QgisAlgorithm import QgisFeatureBasedAlgorithm
4237

4338
pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0]
4439

4540

46-
class SimplifyGeometries(QgisAlgorithm):
41+
class SimplifyGeometries(QgisFeatureBasedAlgorithm):
4742

48-
INPUT = 'INPUT'
4943
TOLERANCE = 'TOLERANCE'
50-
OUTPUT = 'OUTPUT'
5144
METHOD = 'METHOD'
5245

5346
def icon(self):
@@ -58,11 +51,11 @@ def group(self):
5851

5952
def __init__(self):
6053
super().__init__()
54+
self.tolerance = None
55+
self.method = None
56+
self.simplifier = None
6157

62-
def initAlgorithm(self, config=None):
63-
self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
64-
self.tr('Input layer'),
65-
[QgsProcessing.TypeVectorPolygon, QgsProcessing.TypeVectorLine]))
58+
def initParameters(self, config=None):
6659
self.methods = [self.tr('Distance (Douglas-Peucker)'),
6760
'Snap to grid',
6861
'Area (Visvalingam)']
@@ -73,51 +66,31 @@ def initAlgorithm(self, config=None):
7366
self.addParameter(QgsProcessingParameterNumber(self.TOLERANCE,
7467
self.tr('Tolerance'), minValue=0.0, maxValue=10000000.0, defaultValue=1.0))
7568

76-
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Simplified')))
77-
7869
def name(self):
7970
return 'simplifygeometries'
8071

8172
def displayName(self):
8273
return self.tr('Simplify geometries')
8374

84-
def processAlgorithm(self, parameters, context, feedback):
85-
source = self.parameterAsSource(parameters, self.INPUT, context)
86-
tolerance = self.parameterAsDouble(parameters, self.TOLERANCE, context)
87-
method = self.parameterAsEnum(parameters, self.METHOD, context)
88-
89-
pointsBefore = 0
90-
pointsAfter = 0
91-
92-
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
93-
source.fields(), source.wkbType(), source.sourceCrs())
94-
95-
features = source.getFeatures()
96-
total = 100.0 / source.featureCount() if source.featureCount() else 0
97-
98-
if method != 0:
99-
simplifier = QgsMapToPixelSimplifier(QgsMapToPixelSimplifier.SimplifyGeometry, tolerance, method)
100-
101-
for current, input_feature in enumerate(features):
102-
if feedback.isCanceled():
103-
break
104-
out_feature = input_feature
105-
if input_feature.geometry():
106-
input_geometry = input_feature.geometry()
107-
pointsBefore += input_geometry.geometry().nCoordinates()
75+
def outputName(self):
76+
return self.tr('Simplified')
10877

109-
if method == 0: # distance
110-
output_geometry = input_geometry.simplify(tolerance)
111-
else:
112-
output_geometry = simplifier.simplify(input_geometry)
78+
def prepareAlgorithm(self, parameters, context, feedback):
79+
self.tolerance = self.parameterAsDouble(parameters, self.TOLERANCE, context)
80+
self.method = self.parameterAsEnum(parameters, self.METHOD, context)
81+
if self.method != 0:
82+
self.simplifier = QgsMapToPixelSimplifier(QgsMapToPixelSimplifier.SimplifyGeometry, self.tolerance, self.method)
11383

114-
pointsAfter += output_geometry.geometry().nCoordinates()
115-
out_feature.setGeometry(output_geometry)
84+
return True
11685

117-
sink.addFeature(out_feature, QgsFeatureSink.FastInsert)
118-
feedback.setProgress(int(current * total))
86+
def processFeature(self, feature, feedback):
87+
if feature.hasGeometry():
88+
input_geometry = feature.geometry()
11989

120-
QgsMessageLog.logMessage(self.tr('Simplify: Input geometries have been simplified from {0} to {1} points').format(pointsBefore, pointsAfter),
121-
self.tr('Processing'), QgsMessageLog.INFO)
90+
if self.method == 0: # distance
91+
output_geometry = input_geometry.simplify(self.tolerance)
92+
else:
93+
output_geometry = self.simplifier.simplify(input_geometry)
12294

123-
return {self.OUTPUT: dest_id}
95+
feature.setGeometry(output_geometry)
96+
return feature

‎python/plugins/processing/algs/qgis/SingleSidedBuffer.py

Lines changed: 57 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -25,27 +25,17 @@
2525

2626
__revision__ = '$Format:%H$'
2727

28-
import os
29-
30-
from qgis.core import (QgsApplication,
31-
QgsGeometry,
32-
QgsFeatureSink,
28+
from qgis.core import (QgsGeometry,
3329
QgsWkbTypes,
34-
QgsProcessingUtils)
35-
36-
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
37-
from processing.core.GeoAlgorithmExecutionException import GeoAlgorithmExecutionException
38-
from processing.core.parameters import ParameterVector, ParameterSelection, ParameterNumber
39-
from processing.core.outputs import OutputVector
40-
from processing.tools import dataobjects
41-
42-
pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0]
30+
QgsProcessing,
31+
QgsProcessingParameterNumber,
32+
QgsProcessingParameterEnum,
33+
QgsProcessingException)
4334

35+
from processing.algs.qgis.QgisAlgorithm import QgisFeatureBasedAlgorithm
4436

45-
class SingleSidedBuffer(QgisAlgorithm):
4637

47-
INPUT_LAYER = 'INPUT_LAYER'
48-
OUTPUT_LAYER = 'OUTPUT_LAYER'
38+
class SingleSidedBuffer(QgisFeatureBasedAlgorithm):
4939
DISTANCE = 'DISTANCE'
5040
SIDE = 'SIDE'
5141
SEGMENTS = 'SEGMENTS'
@@ -57,71 +47,71 @@ def group(self):
5747

5848
def __init__(self):
5949
super().__init__()
60-
61-
def initAlgorithm(self, config=None):
62-
self.addParameter(ParameterVector(self.INPUT_LAYER,
63-
self.tr('Input layer'), [dataobjects.TYPE_VECTOR_LINE]))
64-
self.addParameter(ParameterNumber(self.DISTANCE,
65-
self.tr('Distance'), default=10.0))
50+
self.distance = None
51+
self.segments = None
52+
self.join_style = None
53+
self.side = None
54+
self.miter_limit = None
6655
self.sides = [self.tr('Left'),
6756
'Right']
68-
self.addParameter(ParameterSelection(
57+
self.join_styles = [self.tr('Round'),
58+
'Mitre',
59+
'Bevel']
60+
61+
def initParameters(self, config=None):
62+
self.addParameter(QgsProcessingParameterNumber(self.DISTANCE,
63+
self.tr('Distance'), defaultValue=10.0))
64+
self.addParameter(QgsProcessingParameterEnum(
6965
self.SIDE,
7066
self.tr('Side'),
71-
self.sides))
67+
options=self.sides))
7268

73-
self.addParameter(ParameterNumber(self.SEGMENTS,
74-
self.tr('Segments'), 1, default=8))
69+
self.addParameter(QgsProcessingParameterNumber(self.SEGMENTS,
70+
self.tr('Segments'), QgsProcessingParameterNumber.Integer,
71+
minValue=1, defaultValue=8))
7572

76-
self.join_styles = [self.tr('Round'),
77-
'Mitre',
78-
'Bevel']
79-
self.addParameter(ParameterSelection(
73+
self.addParameter(QgsProcessingParameterEnum(
8074
self.JOIN_STYLE,
8175
self.tr('Join style'),
82-
self.join_styles))
83-
self.addParameter(ParameterNumber(self.MITRE_LIMIT,
84-
self.tr('Mitre limit'), 1, default=2))
85-
86-
self.addOutput(OutputVector(self.OUTPUT_LAYER, self.tr('Single sided buffers')))
76+
options=self.join_styles))
77+
self.addParameter(QgsProcessingParameterNumber(self.MITRE_LIMIT,
78+
self.tr('Mitre limit'), minValue=1, defaultValue=2))
8779

8880
def name(self):
8981
return 'singlesidedbuffer'
9082

9183
def displayName(self):
9284
return self.tr('Single sided buffer')
9385

94-
def processAlgorithm(self, parameters, context, feedback):
95-
layer = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.INPUT_LAYER), context)
86+
def outputName(self):
87+
return self.tr('Buffers')
9688

97-
writer = self.getOutputFromName(
98-
self.OUTPUT_LAYER).getVectorWriter(layer.fields(), QgsWkbTypes.Polygon, layer.crs(), context)
99-
100-
distance = self.getParameterValue(self.DISTANCE)
101-
segments = int(self.getParameterValue(self.SEGMENTS))
102-
join_style = self.getParameterValue(self.JOIN_STYLE) + 1
103-
if self.getParameterValue(self.SIDE) == 0:
104-
side = QgsGeometry.SideLeft
105-
else:
106-
side = QgsGeometry.SideRight
107-
miter_limit = self.getParameterValue(self.MITRE_LIMIT)
89+
def outputType(self):
90+
return QgsProcessing.TypeVectorPolygon
10891

109-
features = QgsProcessingUtils.getFeatures(layer, context)
110-
total = 100.0 / layer.featureCount() if layer.featureCount() else 0
92+
def outputWkbType(self, input_wkb_type):
93+
return QgsWkbTypes.Polygon
11194

112-
for current, input_feature in enumerate(features):
113-
output_feature = input_feature
114-
input_geometry = input_feature.geometry()
115-
if input_geometry:
116-
output_geometry = input_geometry.singleSidedBuffer(distance, segments,
117-
side, join_style, miter_limit)
118-
if not output_geometry:
119-
raise GeoAlgorithmExecutionException(
120-
self.tr('Error calculating single sided buffer'))
121-
122-
output_feature.setGeometry(output_geometry)
123-
124-
writer.addFeature(output_feature, QgsFeatureSink.FastInsert)
125-
feedback.setProgress(int(current * total))
126-
127-
del writer
95+
def prepareAlgorithm(self, parameters, context, feedback):
96+
self.distance = self.parameterAsDouble(parameters, self.DISTANCE, context)
97+
self.segments = self.parameterAsInt(parameters, self.SEGMENTS, context)
98+
self.join_style = self.parameterAsEnum(parameters, self.JOIN_STYLE, context) + 1
99+
if self.parameterAsEnum(parameters, self.SIDE, context) == 0:
100+
self.side = QgsGeometry.SideLeft
101+
else:
102+
self.side = QgsGeometry.SideRight
103+
self.miter_limit = self.parameterAsDouble(parameters, self.MITRE_LIMIT, context)
104+
return True
105+
106+
def processFeature(self, feature, feedback):
107+
input_geometry = feature.geometry()
108+
if input_geometry:
109+
output_geometry = input_geometry.singleSidedBuffer(self.distance, self.segments,
110+
self.side, self.join_style, self.miter_limit)
111+
if not output_geometry:
112+
raise QgsProcessingException(
113+
self.tr('Error calculating single sided buffer'))
114+
115+
feature.setGeometry(output_geometry)
116+
117+
return feature

‎python/plugins/processing/algs/qgis/Smooth.py

Lines changed: 19 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -25,20 +25,14 @@
2525

2626
__revision__ = '$Format:%H$'
2727

28-
from qgis.core import (QgsFeatureSink,
29-
QgsProcessing,
30-
QgsProcessingException,
31-
QgsProcessingParameterFeatureSource,
32-
QgsProcessingParameterFeatureSink,
28+
from qgis.core import (QgsProcessingException,
3329
QgsProcessingParameterNumber)
3430

35-
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
31+
from processing.algs.qgis.QgisAlgorithm import QgisFeatureBasedAlgorithm
3632

3733

38-
class Smooth(QgisAlgorithm):
34+
class Smooth(QgisFeatureBasedAlgorithm):
3935

40-
INPUT = 'INPUT'
41-
OUTPUT = 'OUTPUT'
4236
ITERATIONS = 'ITERATIONS'
4337
MAX_ANGLE = 'MAX_ANGLE'
4438
OFFSET = 'OFFSET'
@@ -49,9 +43,7 @@ def group(self):
4943
def __init__(self):
5044
super().__init__()
5145

52-
def initAlgorithm(self, config=None):
53-
self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
54-
self.tr('Input layer'), [QgsProcessing.TypeVectorPolygon, QgsProcessing.TypeVectorLine]))
46+
def initParameters(self, config=None):
5547
self.addParameter(QgsProcessingParameterNumber(self.ITERATIONS,
5648
self.tr('Iterations'),
5749
defaultValue=1, minValue=1, maxValue=10))
@@ -62,39 +54,27 @@ def initAlgorithm(self, config=None):
6254
self.tr('Maximum node angle to smooth'), QgsProcessingParameterNumber.Double,
6355
defaultValue=180.0, minValue=0.0, maxValue=180.0))
6456

65-
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Smoothed')))
66-
6757
def name(self):
6858
return 'smoothgeometry'
6959

7060
def displayName(self):
7161
return self.tr('Smooth geometry')
7262

73-
def processAlgorithm(self, parameters, context, feedback):
74-
source = self.parameterAsSource(parameters, self.INPUT, context)
75-
iterations = self.parameterAsInt(parameters, self.ITERATIONS, context)
76-
offset = self.parameterAsDouble(parameters, self.OFFSET, context)
77-
max_angle = self.parameterAsDouble(parameters, self.MAX_ANGLE, context)
78-
79-
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
80-
source.fields(), source.wkbType(), source.sourceCrs())
81-
82-
features = source.getFeatures()
83-
total = 100.0 / source.featureCount() if source.featureCount() else 0
84-
85-
for current, input_feature in enumerate(features):
86-
if feedback.isCanceled():
87-
break
88-
output_feature = input_feature
89-
if input_feature.geometry():
90-
output_geometry = input_feature.geometry().smooth(iterations, offset, -1, max_angle)
91-
if not output_geometry:
92-
raise QgsProcessingException(
93-
self.tr('Error smoothing geometry'))
63+
def outputName(self):
64+
return self.tr('Smoothed')
9465

95-
output_feature.setGeometry(output_geometry)
66+
def prepareAlgorithm(self, parameters, context, feedback):
67+
self.iterations = self.parameterAsInt(parameters, self.ITERATIONS, context)
68+
self.offset = self.parameterAsDouble(parameters, self.OFFSET, context)
69+
self.max_angle = self.parameterAsDouble(parameters, self.MAX_ANGLE, context)
70+
return True
9671

97-
sink.addFeature(output_feature, QgsFeatureSink.FastInsert)
98-
feedback.setProgress(int(current * total))
72+
def processFeature(self, feature, feedback):
73+
if feature.hasGeometry():
74+
output_geometry = feature.geometry().smooth(self.iterations, self.offset, -1, self.max_angle)
75+
if not output_geometry:
76+
raise QgsProcessingException(
77+
self.tr('Error smoothing geometry'))
9978

100-
return {self.OUTPUT: dest_id}
79+
feature.setGeometry(output_geometry)
80+
return feature

‎python/plugins/processing/algs/qgis/Translate.py

Lines changed: 30 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -25,23 +25,13 @@
2525

2626
__revision__ = '$Format:%H$'
2727

28-
import os
28+
from qgis.core import (QgsProcessingException,
29+
QgsProcessingParameterNumber)
30+
from processing.algs.qgis.QgisAlgorithm import QgisFeatureBasedAlgorithm
2931

30-
from qgis.core import (QgsApplication,
31-
QgsFeatureSink,
32-
QgsProcessingUtils)
33-
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
34-
from processing.core.GeoAlgorithmExecutionException import GeoAlgorithmExecutionException
35-
from processing.core.parameters import ParameterVector, ParameterNumber
36-
from processing.core.outputs import OutputVector
3732

38-
pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0]
33+
class Translate(QgisFeatureBasedAlgorithm):
3934

40-
41-
class Translate(QgisAlgorithm):
42-
43-
INPUT_LAYER = 'INPUT_LAYER'
44-
OUTPUT_LAYER = 'OUTPUT_LAYER'
4535
DELTA_X = 'DELTA_X'
4636
DELTA_Y = 'DELTA_Y'
4737

@@ -50,48 +40,37 @@ def group(self):
5040

5141
def __init__(self):
5242
super().__init__()
43+
self.delta_x = 0
44+
self.delta_y = 0
5345

54-
def initAlgorithm(self, config=None):
55-
self.addParameter(ParameterVector(self.INPUT_LAYER,
56-
self.tr('Input layer')))
57-
self.addParameter(ParameterNumber(self.DELTA_X,
58-
self.tr('Offset distance (x-axis)'), default=1.0))
59-
self.addParameter(ParameterNumber(self.DELTA_Y,
60-
self.tr('Offset distance (y-axis)'), default=0.0))
61-
62-
self.addOutput(OutputVector(self.OUTPUT_LAYER, self.tr('Translated')))
46+
def initParameters(self, config=None):
47+
self.addParameter(QgsProcessingParameterNumber(self.DELTA_X,
48+
self.tr('Offset distance (x-axis)'), QgsProcessingParameterNumber.Double, defaultValue=0.0))
49+
self.addParameter(QgsProcessingParameterNumber(self.DELTA_Y,
50+
self.tr('Offset distance (y-axis)'), QgsProcessingParameterNumber.Double, defaultValue=0.0))
6351

6452
def name(self):
6553
return 'translategeometry'
6654

6755
def displayName(self):
6856
return self.tr('Translate geometry')
6957

70-
def processAlgorithm(self, parameters, context, feedback):
71-
layer = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.INPUT_LAYER), context)
72-
73-
writer = self.getOutputFromName(
74-
self.OUTPUT_LAYER).getVectorWriter(layer.fields(), layer.wkbType(), layer.crs(), context)
75-
76-
delta_x = self.getParameterValue(self.DELTA_X)
77-
delta_y = self.getParameterValue(self.DELTA_Y)
78-
79-
features = QgsProcessingUtils.getFeatures(layer, context)
80-
total = 100.0 / layer.featureCount() if layer.featureCount() else 0
81-
82-
for current, input_feature in enumerate(features):
83-
output_feature = input_feature
84-
input_geometry = input_feature.geometry()
85-
if input_geometry:
86-
output_geometry = input_geometry
87-
output_geometry.translate(delta_x, delta_y)
88-
if not output_geometry:
89-
raise GeoAlgorithmExecutionException(
90-
self.tr('Error translating geometry'))
91-
92-
output_feature.setGeometry(output_geometry)
93-
94-
writer.addFeature(output_feature, QgsFeatureSink.FastInsert)
95-
feedback.setProgress(int(current * total))
96-
97-
del writer
58+
def outputName(self):
59+
return self.tr('Translated')
60+
61+
def prepareAlgorithm(self, parameters, context, feedback):
62+
self.delta_x = self.parameterAsDouble(parameters, self.DELTA_X, context)
63+
self.delta_y = self.parameterAsDouble(parameters, self.DELTA_Y, context)
64+
return True
65+
66+
def processFeature(self, feature, feedback):
67+
input_geometry = feature.geometry()
68+
if input_geometry:
69+
output_geometry = input_geometry
70+
output_geometry.translate(self.delta_x, self.delta_y)
71+
if not output_geometry:
72+
raise QgsProcessingException(
73+
self.tr('Error translating geometry'))
74+
75+
feature.setGeometry(output_geometry)
76+
return feature

‎python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml

Lines changed: 157 additions & 157 deletions
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)
Please sign in to comment.