Skip to content

Commit

Permalink
[FEATURE][processing] Snap Geometries algorithm can now snap
Browse files Browse the repository at this point in the history
within the same layer

Allows closure of gaps within a layer
  • Loading branch information
nyalldawson committed Mar 30, 2017
1 parent ece3991 commit 92249c1
Show file tree
Hide file tree
Showing 7 changed files with 148 additions and 14 deletions.
10 changes: 8 additions & 2 deletions python/plugins/processing/algs/help/qgis.yaml
Expand Up @@ -520,8 +520,14 @@ qgis:smoothgeometry: >

The maximum angle parameter can be used to prevent smoothing of nodes with large angles. Any node where the angle of the segments to either side is larger then this will not be smoothed. For example, setting the maximum angle to 90 degrees or lower would preserve right angles in the geometry.

qgis:snapgeometriestolayer: >
This algorithm snaps the geometries in a layer to the geometries in another layer. A tolerance is specified in layer units to control how close vertices need to be to the reference layer geometries before they are snapped. Snapping occurs to both vertices and edges, but snapping to a vertex is preferred. Vertices will be inserted or removed as required to make the geometries match the reference geometries.
qgis:snapgeometries: >
This algorithm snaps the geometries in a layer. Snapping can be done either to the geometries from another layer, or to geometries within the same layer.

A tolerance is specified in layer units to control how close vertices need to be to the reference layer geometries before they are snapped.

Snapping occurs to both nodes and edges. Depending on the snapping behavior, either nodes or edges will be preferred.

Vertices will be inserted or removed as required to make the geometries match the reference geometries.

qgis:snappointstogrid: >
This algorithm modifies the position of points in a vector layer, so they fall in the coordinates of a grid.
Expand Down
26 changes: 19 additions & 7 deletions python/plugins/processing/algs/qgis/SnapGeometries.py
Expand Up @@ -25,7 +25,8 @@

__revision__ = '$Format:%H$'

from qgis.analysis import QgsGeometrySnapper
from qgis.analysis import (QgsGeometrySnapper,
QgsInternalGeometrySnapper)
from qgis.core import QgsFeature

from processing.core.GeoAlgorithm import GeoAlgorithm
Expand All @@ -43,7 +44,7 @@ class SnapGeometriesToLayer(GeoAlgorithm):
BEHAVIOR = 'BEHAVIOR'

def defineCharacteristics(self):
self.name, self.i18n_name = self.trAlgorithm('Snap geometries to layer')
self.name, self.i18n_name = self.trAlgorithm('Snap geometries')
self.group, self.i18n_group = self.trAlgorithm('Vector geometry tools')

self.addParameter(ParameterVector(self.INPUT, self.tr('Input layer')))
Expand Down Expand Up @@ -73,11 +74,22 @@ def processAlgorithm(self, feedback):
self.feedback = feedback
self.total = 100.0 / len(features)

snapper = QgsGeometrySnapper(reference_layer)
snapper.featureSnapped.connect(self.featureSnapped)
snapped_features = snapper.snapFeatures(features, tolerance, mode)
for f in snapped_features:
writer.addFeature(QgsFeature(f))
if self.getParameterValue(self.INPUT) != self.getParameterValue(self.REFERENCE_LAYER):
snapper = QgsGeometrySnapper(reference_layer)
snapper.featureSnapped.connect(self.featureSnapped)
snapped_features = snapper.snapFeatures(features, tolerance, mode)
for f in snapped_features:
writer.addFeature(QgsFeature(f))
else:
# snapping internally
snapper = QgsInternalGeometrySnapper(tolerance, mode)
processed = 0
for f in features:
out_feature = f
out_feature.setGeometry(snapper.snapFeature(f))
writer.addFeature(out_feature)
processed += 1
feedback.setProgress(processed * self.total)

del writer

Expand Down
16 changes: 16 additions & 0 deletions python/plugins/processing/tests/testdata/custom/snap_internal.gfs
@@ -0,0 +1,16 @@
<GMLFeatureClassList>
<GMLFeatureClass>
<Name>snap_internal</Name>
<ElementPath>snap_internal</ElementPath>
<!--LINESTRING-->
<GeometryType>2</GeometryType>
<SRSName>EPSG:4326</SRSName>
<DatasetSpecificInfo>
<FeatureCount>4</FeatureCount>
<ExtentXMin>-1.00000</ExtentXMin>
<ExtentXMax>8.50000</ExtentXMax>
<ExtentYMin>-1.00000</ExtentYMin>
<ExtentYMax>4.50000</ExtentYMax>
</DatasetSpecificInfo>
</GMLFeatureClass>
</GMLFeatureClassList>
34 changes: 34 additions & 0 deletions python/plugins/processing/tests/testdata/custom/snap_internal.gml
@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8" ?>
<ogr:FeatureCollection
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=""
xmlns:ogr="http://ogr.maptools.org/"
xmlns:gml="http://www.opengis.net/gml">
<gml:boundedBy>
<gml:Box>
<gml:coord><gml:X>-1</gml:X><gml:Y>-1</gml:Y></gml:coord>
<gml:coord><gml:X>8.5</gml:X><gml:Y>4.5</gml:Y></gml:coord>
</gml:Box>
</gml:boundedBy>

<gml:featureMember>
<ogr:snap_internal fid="snap_internal.0">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>-1,-1 -1,3 3,3 4.1,4.5 7.9,4.5</gml:coordinates></gml:LineString></ogr:geometryProperty>
</ogr:snap_internal>
</gml:featureMember>
<gml:featureMember>
<ogr:snap_internal fid="snap_internal.1">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>-0.5,-1.0 3.3,-1.0 3.3,2.8</gml:coordinates></gml:LineString></ogr:geometryProperty>
</ogr:snap_internal>
</gml:featureMember>
<gml:featureMember>
<ogr:snap_internal fid="snap_internal.2">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>8.4,1.5 8.5,-0.9 5.8,-0.9</gml:coordinates></gml:LineString></ogr:geometryProperty>
</ogr:snap_internal>
</gml:featureMember>
<gml:featureMember>
<ogr:snap_internal fid="snap_internal.3">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>3.5,3.0 8.4,3.0 8.4,1.6</gml:coordinates></gml:LineString></ogr:geometryProperty>
</ogr:snap_internal>
</gml:featureMember>
</ogr:FeatureCollection>
@@ -0,0 +1,16 @@
<GMLFeatureClassList>
<GMLFeatureClass>
<Name>snap_internal</Name>
<ElementPath>snap_internal</ElementPath>
<!--LINESTRING-->
<GeometryType>2</GeometryType>
<SRSName>EPSG:4326</SRSName>
<DatasetSpecificInfo>
<FeatureCount>4</FeatureCount>
<ExtentXMin>-1.00000</ExtentXMin>
<ExtentXMax>8.50000</ExtentXMax>
<ExtentYMin>-1.00000</ExtentYMin>
<ExtentYMax>4.50000</ExtentYMax>
</DatasetSpecificInfo>
</GMLFeatureClass>
</GMLFeatureClassList>
@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8" ?>
<ogr:FeatureCollection
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=""
xmlns:ogr="http://ogr.maptools.org/"
xmlns:gml="http://www.opengis.net/gml">
<gml:boundedBy>
<gml:Box>
<gml:coord><gml:X>-1</gml:X><gml:Y>-1</gml:Y></gml:coord>
<gml:coord><gml:X>8.5</gml:X><gml:Y>4.5</gml:Y></gml:coord>
</gml:Box>
</gml:boundedBy>

<gml:featureMember>
<ogr:snap_internal fid="snap_internal.0">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>-1,-1 -1,3 3,3 4.1,4.5 7.9,4.5</gml:coordinates></gml:LineString></ogr:geometryProperty>
</ogr:snap_internal>
</gml:featureMember>
<gml:featureMember>
<ogr:snap_internal fid="snap_internal.1">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>-1,-1 3.3,-1.0 3,3</gml:coordinates></gml:LineString></ogr:geometryProperty>
</ogr:snap_internal>
</gml:featureMember>
<gml:featureMember>
<ogr:snap_internal fid="snap_internal.2">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>8.4,1.5 8.5,-0.9 5.8,-0.9</gml:coordinates></gml:LineString></ogr:geometryProperty>
</ogr:snap_internal>
</gml:featureMember>
<gml:featureMember>
<ogr:snap_internal fid="snap_internal.3">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>3,3 8.4,3.0 8.4,1.5</gml:coordinates></gml:LineString></ogr:geometryProperty>
</ogr:snap_internal>
</gml:featureMember>
</ogr:FeatureCollection>
26 changes: 21 additions & 5 deletions python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml
Expand Up @@ -1377,7 +1377,7 @@ tests:
name: expected/geometry_by_expression_line.gml
type: vector

- algorithm: qgis:snapgeometriestolayer
- algorithm: qgis:snapgeometries
name: Snap lines to lines
params:
INPUT:
Expand All @@ -1392,7 +1392,7 @@ tests:
name: expected/snap_lines_to_lines.gml
type: vector

- algorithm: qgis:snapgeometriestolayer
- algorithm: qgis:snapgeometries
name: Snap polygons to polygons
params:
INPUT:
Expand All @@ -1407,7 +1407,7 @@ tests:
name: expected/snap_polys_to_polys.gml
type: vector

- algorithm: qgis:snapgeometriestolayer
- algorithm: qgis:snapgeometries
name: Snap points to points
params:
INPUT:
Expand All @@ -1422,7 +1422,7 @@ tests:
name: expected/snap_points_to_points.gml
type: vector

- algorithm: qgis:snapgeometriestolayer
- algorithm: qgis:snapgeometries
name: Snap points to lines (prefer nodes)
params:
BEHAVIOR: '0'
Expand All @@ -1438,7 +1438,7 @@ tests:
name: expected/snap_point_to_lines_prefer_nodes.gml
type: vector

- algorithm: qgis:snapgeometriestolayer
- algorithm: qgis:snapgeometries
name: Snap points to lines (prefer closest)
params:
BEHAVIOR: '1'
Expand All @@ -1454,6 +1454,22 @@ tests:
name: expected/snap_point_to_lines_prefer_closest.gml
type: vector

- algorithm: qgis:snapgeometries
name: Snap internal
params:
BEHAVIOR: '0'
INPUT:
name: custom/snap_internal.gml
type: vector
REFERENCE_LAYER:
name: custom/snap_internal.gml
type: vector
TOLERANCE: 1.0
results:
OUTPUT:
name: expected/snap_internal.gml
type: vector

- algorithm: qgis:poleofinaccessibility
name: Pole of inaccessibility (polygons)
params:
Expand Down

0 comments on commit 92249c1

Please sign in to comment.