Skip to content

Commit 90f10ae

Browse files
committed
Port snap geometries algorithm to new API
1 parent 05364aa commit 90f10ae

File tree

3 files changed

+150
-135
lines changed

3 files changed

+150
-135
lines changed

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

+3-2
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@
6969
from .SelectByExpression import SelectByExpression
7070
from .SimplifyGeometries import SimplifyGeometries
7171
from .Smooth import Smooth
72+
from .SnapGeometries import SnapGeometriesToLayer
7273
from .SpatialiteExecuteSQL import SpatialiteExecuteSQL
7374
from .SymmetricalDifference import SymmetricalDifference
7475
from .VectorSplit import VectorSplit
@@ -156,7 +157,6 @@
156157
# from .ExtendLines import ExtendLines
157158
# from .ExtractSpecificNodes import ExtractSpecificNodes
158159
# from .GeometryByExpression import GeometryByExpression
159-
# from .SnapGeometries import SnapGeometriesToLayer
160160
# from .PoleOfInaccessibility import PoleOfInaccessibility
161161
# from .RasterCalculator import RasterCalculator
162162
# from .Heatmap import Heatmap
@@ -230,7 +230,7 @@ def getAlgs(self):
230230
# IdwInterpolation(), TinInterpolation(),
231231
# RemoveNullGeometry(),
232232
# ExtendLines(), ExtractSpecificNodes(),
233-
# GeometryByExpression(), SnapGeometriesToLayer(),
233+
# GeometryByExpression(),
234234
# PoleOfInaccessibility(),
235235
#
236236
# RasterCalculator(), Heatmap(), Orthogonalize(),
@@ -269,6 +269,7 @@ def getAlgs(self):
269269
SelectByExpression(),
270270
SimplifyGeometries(),
271271
Smooth(),
272+
SnapGeometriesToLayer(),
272273
SpatialiteExecuteSQL(),
273274
SymmetricalDifference(),
274275
VectorSplit(),

python/plugins/processing/algs/qgis/SnapGeometries.py

+53-39
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,15 @@
2727

2828
from qgis.analysis import (QgsGeometrySnapper,
2929
QgsInternalGeometrySnapper)
30-
from qgis.core import (QgsApplication,
31-
QgsFeature,
32-
QgsFeatureSink,
33-
QgsProcessingUtils)
30+
from qgis.core import (QgsFeatureSink,
31+
QgsProcessingParameterDefinition,
32+
QgsProcessingParameterFeatureSource,
33+
QgsProcessingParameterFeatureSink,
34+
QgsProcessingParameterNumber,
35+
QgsProcessingParameterEnum,
36+
QgsProcessingOutputVectorLayer)
3437

3538
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
36-
from processing.core.parameters import ParameterVector, ParameterNumber, ParameterSelection
37-
from processing.core.outputs import OutputVector
3839

3940

4041
class SnapGeometriesToLayer(QgisAlgorithm):
@@ -50,20 +51,28 @@ def group(self):
5051

5152
def __init__(self):
5253
super().__init__()
53-
self.addParameter(ParameterVector(self.INPUT, self.tr('Input layer')))
54-
self.addParameter(ParameterVector(self.REFERENCE_LAYER, self.tr('Reference layer')))
55-
self.addParameter(ParameterNumber(self.TOLERANCE, self.tr('Tolerance (layer units)'), 0.00000001, 9999999999, default=10.0))
54+
55+
self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, self.tr('Input layer'), [QgsProcessingParameterDefinition.TypeVectorPoint, QgsProcessingParameterDefinition.TypeVectorLine, QgsProcessingParameterDefinition.TypeVectorPolygon]))
56+
self.addParameter(QgsProcessingParameterFeatureSource(self.REFERENCE_LAYER, self.tr('Reference layer'),
57+
[QgsProcessingParameterDefinition.TypeVectorPoint,
58+
QgsProcessingParameterDefinition.TypeVectorLine,
59+
QgsProcessingParameterDefinition.TypeVectorPolygon]))
60+
61+
self.addParameter(QgsProcessingParameterNumber(self.TOLERANCE, self.tr('Tolerance (layer units)'), type=QgsProcessingParameterNumber.Double,
62+
minValue=0.00000001, maxValue=9999999999, defaultValue=10.0))
5663

5764
self.modes = [self.tr('Prefer aligning nodes'),
5865
self.tr('Prefer closest point'),
5966
self.tr('Move end points only, prefer aligning nodes'),
6067
self.tr('Move end points only, prefer closest point'),
6168
self.tr('Snap end points to end points only')]
62-
self.addParameter(ParameterSelection(
69+
self.addParameter(QgsProcessingParameterEnum(
6370
self.BEHAVIOR,
6471
self.tr('Behavior'),
65-
self.modes, default=0))
66-
self.addOutput(OutputVector(self.OUTPUT, self.tr('Snapped geometries')))
72+
options=self.modes, defaultValue=0))
73+
74+
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Snapped geometry')))
75+
self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr("Snapped geometry")))
6776

6877
def name(self):
6978
return 'snapgeometries'
@@ -72,39 +81,44 @@ def displayName(self):
7281
return self.tr('Snap geometries to layer')
7382

7483
def processAlgorithm(self, parameters, context, feedback):
75-
layer = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.INPUT), context)
76-
reference_layer = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.REFERENCE_LAYER), context)
77-
tolerance = self.getParameterValue(self.TOLERANCE)
78-
mode = self.getParameterValue(self.BEHAVIOR)
79-
80-
writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(layer.fields(), layer.wkbType(), layer.crs(),
81-
context)
82-
83-
features = QgsProcessingUtils.getFeatures(layer, context)
84-
85-
self.processed = 0
86-
self.feedback = feedback
87-
self.total = 100.0 / layer.featureCount() if layer.featureCount() else 0
88-
89-
if self.getParameterValue(self.INPUT) != self.getParameterValue(self.REFERENCE_LAYER):
90-
snapper = QgsGeometrySnapper(reference_layer)
91-
snapper.featureSnapped.connect(self.featureSnapped)
92-
snapped_features = snapper.snapFeatures(features, tolerance, mode)
93-
for f in snapped_features:
94-
writer.addFeature(f, QgsFeatureSink.FastInsert)
84+
source = self.parameterAsSource(parameters, self.INPUT, context)
85+
86+
reference_source = self.parameterAsSource(parameters, self.REFERENCE_LAYER, context)
87+
tolerance = self.parameterAsDouble(parameters, self.TOLERANCE, context)
88+
mode = self.parameterAsEnum(parameters, self.BEHAVIOR, context)
89+
90+
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
91+
source.fields(), source.wkbType(), source.sourceCrs())
92+
93+
features = source.getFeatures()
94+
total = 100.0 / source.featureCount() if source.featureCount() else 0
95+
96+
if parameters[self.INPUT] != parameters[self.REFERENCE_LAYER]:
97+
snapper = QgsGeometrySnapper(reference_source)
98+
processed = 0
99+
for f in features:
100+
if feedback.isCanceled():
101+
break
102+
if f.hasGeometry():
103+
out_feature = f
104+
out_feature.setGeometry(snapper.snapGeometry(f.geometry(), tolerance, mode))
105+
sink.addFeature(out_feature, QgsFeatureSink.FastInsert)
106+
else:
107+
sink.addFeature(f)
108+
processed += 1
109+
feedback.setProgress(processed * total)
95110
else:
96111
# snapping internally
97112
snapper = QgsInternalGeometrySnapper(tolerance, mode)
98113
processed = 0
99114
for f in features:
115+
if feedback.isCanceled():
116+
break
117+
100118
out_feature = f
101119
out_feature.setGeometry(snapper.snapFeature(f))
102-
writer.addFeature(out_feature, QgsFeatureSink.FastInsert)
120+
sink.addFeature(out_feature, QgsFeatureSink.FastInsert)
103121
processed += 1
104-
feedback.setProgress(processed * self.total)
105-
106-
del writer
122+
feedback.setProgress(processed * total)
107123

108-
def featureSnapped(self):
109-
self.processed += 1
110-
self.feedback.setProgress(int(self.processed * self.total))
124+
return {self.OUTPUT: dest_id}

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

+94-94
Original file line numberDiff line numberDiff line change
@@ -1376,100 +1376,100 @@ tests:
13761376
# OUTPUT_LAYER:
13771377
# name: expected/geometry_by_expression_line.gml
13781378
# type: vector
1379-
#
1380-
# - algorithm: qgis:snapgeometries
1381-
# name: Snap lines to lines
1382-
# params:
1383-
# INPUT:
1384-
# name: snap_lines.gml
1385-
# type: vector
1386-
# REFERENCE_LAYER:
1387-
# name: lines.gml
1388-
# type: vector
1389-
# TOLERANCE: 1.0
1390-
# results:
1391-
# OUTPUT:
1392-
# name: expected/snap_lines_to_lines.gml
1393-
# type: vector
1394-
#
1395-
# - algorithm: qgis:snapgeometries
1396-
# name: Snap polygons to polygons
1397-
# params:
1398-
# INPUT:
1399-
# name: snap_polys.gml
1400-
# type: vector
1401-
# REFERENCE_LAYER:
1402-
# name: polys.gml
1403-
# type: vector
1404-
# TOLERANCE: 1.0
1405-
# results:
1406-
# OUTPUT:
1407-
# name: expected/snap_polys_to_polys.gml
1408-
# type: vector
1409-
#
1410-
# - algorithm: qgis:snapgeometries
1411-
# name: Snap points to points
1412-
# params:
1413-
# INPUT:
1414-
# name: snap_points.gml
1415-
# type: vector
1416-
# REFERENCE_LAYER:
1417-
# name: points.gml
1418-
# type: vector
1419-
# TOLERANCE: 1.0
1420-
# results:
1421-
# OUTPUT:
1422-
# name: expected/snap_points_to_points.gml
1423-
# type: vector
1424-
#
1425-
# - algorithm: qgis:snapgeometries
1426-
# name: Snap points to lines (prefer nodes)
1427-
# params:
1428-
# BEHAVIOR: '0'
1429-
# INPUT:
1430-
# name: snap_points.gml
1431-
# type: vector
1432-
# REFERENCE_LAYER:
1433-
# name: lines.gml
1434-
# type: vector
1435-
# TOLERANCE: 1.0
1436-
# results:
1437-
# OUTPUT:
1438-
# name: expected/snap_point_to_lines_prefer_nodes.gml
1439-
# type: vector
1440-
#
1441-
# - algorithm: qgis:snapgeometries
1442-
# name: Snap points to lines (prefer closest)
1443-
# params:
1444-
# BEHAVIOR: '1'
1445-
# INPUT:
1446-
# name: snap_points.gml
1447-
# type: vector
1448-
# REFERENCE_LAYER:
1449-
# name: lines.gml
1450-
# type: vector
1451-
# TOLERANCE: 1.0
1452-
# results:
1453-
# OUTPUT:
1454-
# name: expected/snap_point_to_lines_prefer_closest.gml
1455-
# type: vector
1456-
#
1457-
# - algorithm: qgis:snapgeometries
1458-
# name: Snap internal
1459-
# params:
1460-
# BEHAVIOR: '0'
1461-
# INPUT:
1462-
# name: custom/snap_internal.gml
1463-
# type: vector
1464-
# REFERENCE_LAYER:
1465-
# name: custom/snap_internal.gml
1466-
# type: vector
1467-
# TOLERANCE: 1.0
1468-
# results:
1469-
# OUTPUT:
1470-
# name: expected/snap_internal.gml
1471-
# type: vector
1472-
#
1379+
1380+
- algorithm: qgis:snapgeometries
1381+
name: Snap lines to lines
1382+
params:
1383+
INPUT:
1384+
name: snap_lines.gml
1385+
type: vector
1386+
REFERENCE_LAYER:
1387+
name: lines.gml
1388+
type: vector
1389+
TOLERANCE: 1.0
1390+
results:
1391+
OUTPUT:
1392+
name: expected/snap_lines_to_lines.gml
1393+
type: vector
1394+
1395+
- algorithm: qgis:snapgeometries
1396+
name: Snap polygons to polygons
1397+
params:
1398+
INPUT:
1399+
name: snap_polys.gml
1400+
type: vector
1401+
REFERENCE_LAYER:
1402+
name: polys.gml
1403+
type: vector
1404+
TOLERANCE: 1.0
1405+
results:
1406+
OUTPUT:
1407+
name: expected/snap_polys_to_polys.gml
1408+
type: vector
1409+
1410+
- algorithm: qgis:snapgeometries
1411+
name: Snap points to points
1412+
params:
1413+
INPUT:
1414+
name: snap_points.gml
1415+
type: vector
1416+
REFERENCE_LAYER:
1417+
name: points.gml
1418+
type: vector
1419+
TOLERANCE: 1.0
1420+
results:
1421+
OUTPUT:
1422+
name: expected/snap_points_to_points.gml
1423+
type: vector
1424+
1425+
- algorithm: qgis:snapgeometries
1426+
name: Snap points to lines (prefer nodes)
1427+
params:
1428+
BEHAVIOR: '0'
1429+
INPUT:
1430+
name: snap_points.gml
1431+
type: vector
1432+
REFERENCE_LAYER:
1433+
name: lines.gml
1434+
type: vector
1435+
TOLERANCE: 1.0
1436+
results:
1437+
OUTPUT:
1438+
name: expected/snap_point_to_lines_prefer_nodes.gml
1439+
type: vector
1440+
1441+
- algorithm: qgis:snapgeometries
1442+
name: Snap points to lines (prefer closest)
1443+
params:
1444+
BEHAVIOR: '1'
1445+
INPUT:
1446+
name: snap_points.gml
1447+
type: vector
1448+
REFERENCE_LAYER:
1449+
name: lines.gml
1450+
type: vector
1451+
TOLERANCE: 1.0
1452+
results:
1453+
OUTPUT:
1454+
name: expected/snap_point_to_lines_prefer_closest.gml
1455+
type: vector
1456+
1457+
- algorithm: qgis:snapgeometries
1458+
name: Snap internal
1459+
params:
1460+
BEHAVIOR: '0'
1461+
INPUT:
1462+
name: custom/snap_internal.gml
1463+
type: vector
1464+
REFERENCE_LAYER:
1465+
name: custom/snap_internal.gml
1466+
type: vector
1467+
TOLERANCE: 1.0
1468+
results:
1469+
OUTPUT:
1470+
name: expected/snap_internal.gml
1471+
type: vector
1472+
14731473
# - algorithm: qgis:poleofinaccessibility
14741474
# name: Pole of inaccessibility (polygons)
14751475
# params:

0 commit comments

Comments
 (0)