Skip to content

Commit dae0a01

Browse files
committedNov 7, 2016
[FEATURE][processing] Snap geometries algorithm allows snapping
to other layer types, supports point/line layers Fix #14791, #15313
1 parent c3a978b commit dae0a01

File tree

9 files changed

+589
-15
lines changed

9 files changed

+589
-15
lines changed
 

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

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@
3131

3232
from processing.core.GeoAlgorithm import GeoAlgorithm
3333
from processing.core.parameters import ParameterVector, ParameterNumber
34-
from processing.core.GeoAlgorithmExecutionException import GeoAlgorithmExecutionException
3534
from processing.core.outputs import OutputVector
3635
from processing.tools import dataobjects, vector
3736

@@ -57,10 +56,6 @@ def processAlgorithm(self, progress):
5756
reference_layer = dataobjects.getObjectFromUri(self.getParameterValue(self.REFERENCE_LAYER))
5857
tolerance = self.getParameterValue(self.TOLERANCE)
5958

60-
if not layer.geometryType() == reference_layer.geometryType():
61-
raise GeoAlgorithmExecutionException(
62-
self.tr('Input layer and reference layer must have the same geometry type (eg both are line layers)'))
63-
6459
writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(
6560
layer.fields(), layer.wkbType(), layer.crs())
6661

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<GMLFeatureClassList>
2+
<GMLFeatureClass>
3+
<Name>snap_points_to_points</Name>
4+
<ElementPath>snap_points_to_points</ElementPath>
5+
<!--POINT-->
6+
<GeometryType>1</GeometryType>
7+
<SRSName>EPSG:4326</SRSName>
8+
<DatasetSpecificInfo>
9+
<FeatureCount>9</FeatureCount>
10+
<ExtentXMin>0.20114</ExtentXMin>
11+
<ExtentXMax>7.97127</ExtentXMax>
12+
<ExtentYMin>-4.82759</ExtentYMin>
13+
<ExtentYMax>2.74139</ExtentYMax>
14+
</DatasetSpecificInfo>
15+
</GMLFeatureClass>
16+
</GMLFeatureClassList>
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<ogr:FeatureCollection
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation=""
5+
xmlns:ogr="http://ogr.maptools.org/"
6+
xmlns:gml="http://www.opengis.net/gml">
7+
<gml:boundedBy>
8+
<gml:Box>
9+
<gml:coord><gml:X>0</gml:X><gml:Y>-5</gml:Y></gml:coord>
10+
<gml:coord><gml:X>7.971265678449257</gml:X><gml:Y>3</gml:Y></gml:coord>
11+
</gml:Box>
12+
</gml:boundedBy>
13+
14+
<gml:featureMember>
15+
<ogr:snap_points_to_points fid="points.0">
16+
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>1,1</gml:coordinates></gml:Point></ogr:geometryProperty>
17+
</ogr:snap_points_to_points>
18+
</gml:featureMember>
19+
<gml:featureMember>
20+
<ogr:snap_points_to_points fid="points.1">
21+
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>3,3</gml:coordinates></gml:Point></ogr:geometryProperty>
22+
</ogr:snap_points_to_points>
23+
</gml:featureMember>
24+
<gml:featureMember>
25+
<ogr:snap_points_to_points fid="points.2">
26+
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>2,2</gml:coordinates></gml:Point></ogr:geometryProperty>
27+
</ogr:snap_points_to_points>
28+
</gml:featureMember>
29+
<gml:featureMember>
30+
<ogr:snap_points_to_points fid="points.3">
31+
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>5,2</gml:coordinates></gml:Point></ogr:geometryProperty>
32+
</ogr:snap_points_to_points>
33+
</gml:featureMember>
34+
<gml:featureMember>
35+
<ogr:snap_points_to_points fid="points.4">
36+
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>4,1</gml:coordinates></gml:Point></ogr:geometryProperty>
37+
</ogr:snap_points_to_points>
38+
</gml:featureMember>
39+
<gml:featureMember>
40+
<ogr:snap_points_to_points fid="points.5">
41+
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>0,-5</gml:coordinates></gml:Point></ogr:geometryProperty>
42+
</ogr:snap_points_to_points>
43+
</gml:featureMember>
44+
<gml:featureMember>
45+
<ogr:snap_points_to_points fid="points.6">
46+
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>7.971265678449257,0.609122006841505</gml:coordinates></gml:Point></ogr:geometryProperty>
47+
</ogr:snap_points_to_points>
48+
</gml:featureMember>
49+
<gml:featureMember>
50+
<ogr:snap_points_to_points fid="points.7">
51+
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>7,-1</gml:coordinates></gml:Point></ogr:geometryProperty>
52+
</ogr:snap_points_to_points>
53+
</gml:featureMember>
54+
<gml:featureMember>
55+
<ogr:snap_points_to_points fid="points.8">
56+
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>0,-1</gml:coordinates></gml:Point></ogr:geometryProperty>
57+
</ogr:snap_points_to_points>
58+
</gml:featureMember>
59+
</ogr:FeatureCollection>

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1417,3 +1417,18 @@ tests:
14171417
OUTPUT:
14181418
name: expected/snap_polys_to_polys.gml
14191419
type: vector
1420+
1421+
- algorithm: qgis:snapgeometriestolayer
1422+
name: Snap points to points
1423+
params:
1424+
INPUT:
1425+
name: snap_points.gml
1426+
type: vector
1427+
REFERENCE_LAYER:
1428+
name: points.gml
1429+
type: vector
1430+
TOLERANCE: 1.0
1431+
results:
1432+
OUTPUT:
1433+
name: expected/snap_points_to_points.gml
1434+
type: vector
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<GMLFeatureClassList>
2+
<GMLFeatureClass>
3+
<Name>snap_points</Name>
4+
<ElementPath>snap_points</ElementPath>
5+
<!--POINT-->
6+
<GeometryType>1</GeometryType>
7+
<SRSName>EPSG:4326</SRSName>
8+
<DatasetSpecificInfo>
9+
<FeatureCount>9</FeatureCount>
10+
<ExtentXMin>0.20114</ExtentXMin>
11+
<ExtentXMax>7.97127</ExtentXMax>
12+
<ExtentYMin>-4.82759</ExtentYMin>
13+
<ExtentYMax>2.74139</ExtentYMax>
14+
</DatasetSpecificInfo>
15+
</GMLFeatureClass>
16+
</GMLFeatureClassList>
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<ogr:FeatureCollection
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation=""
5+
xmlns:ogr="http://ogr.maptools.org/"
6+
xmlns:gml="http://www.opengis.net/gml">
7+
<gml:boundedBy>
8+
<gml:Box>
9+
<gml:coord><gml:X>0.2011402508551881</gml:X><gml:Y>-4.827594070695552</gml:Y></gml:coord>
10+
<gml:coord><gml:X>7.971265678449257</gml:X><gml:Y>2.74139110604333</gml:Y></gml:coord>
11+
</gml:Box>
12+
</gml:boundedBy>
13+
14+
<gml:featureMember>
15+
<ogr:snap_points fid="points.0">
16+
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>1,1</gml:coordinates></gml:Point></ogr:geometryProperty>
17+
</ogr:snap_points>
18+
</gml:featureMember>
19+
<gml:featureMember>
20+
<ogr:snap_points fid="points.1">
21+
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>3.134093500570125,2.74139110604333</gml:coordinates></gml:Point></ogr:geometryProperty>
22+
</ogr:snap_points>
23+
</gml:featureMember>
24+
<gml:featureMember>
25+
<ogr:snap_points fid="points.2">
26+
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>2,2</gml:coordinates></gml:Point></ogr:geometryProperty>
27+
</ogr:snap_points>
28+
</gml:featureMember>
29+
<gml:featureMember>
30+
<ogr:snap_points fid="points.3">
31+
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>5.25860889395667,1.578563283922463</gml:coordinates></gml:Point></ogr:geometryProperty>
32+
</ogr:snap_points>
33+
</gml:featureMember>
34+
<gml:featureMember>
35+
<ogr:snap_points fid="points.4">
36+
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>3.683922462941847,0.961687571265678</gml:coordinates></gml:Point></ogr:geometryProperty>
37+
</ogr:snap_points>
38+
</gml:featureMember>
39+
<gml:featureMember>
40+
<ogr:snap_points fid="points.5">
41+
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>0.201140250855188,-4.827594070695552</gml:coordinates></gml:Point></ogr:geometryProperty>
42+
</ogr:snap_points>
43+
</gml:featureMember>
44+
<gml:featureMember>
45+
<ogr:snap_points fid="points.6">
46+
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>7.971265678449257,0.609122006841505</gml:coordinates></gml:Point></ogr:geometryProperty>
47+
</ogr:snap_points>
48+
</gml:featureMember>
49+
<gml:featureMember>
50+
<ogr:snap_points fid="points.7">
51+
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>7.181984036488029,-1.268187001140251</gml:coordinates></gml:Point></ogr:geometryProperty>
52+
</ogr:snap_points>
53+
</gml:featureMember>
54+
<gml:featureMember>
55+
<ogr:snap_points fid="points.8">
56+
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>0.220296465222349,-1.210718358038768</gml:coordinates></gml:Point></ogr:geometryProperty>
57+
</ogr:snap_points>
58+
</gml:featureMember>
59+
</ogr:FeatureCollection>

‎src/analysis/vector/qgsgeometrysnapper.cpp

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
#include "qgsvectordataprovider.h"
2525
#include "qgsgeometryutils.h"
2626
#include "qgsmapsettings.h"
27+
#include "qgssurface.h"
28+
#include "qgscurve.h"
2729

2830
///@cond PRIVATE
2931

@@ -328,7 +330,17 @@ void QgsSnapIndex::addGeometry( const QgsAbstractGeometry* geom )
328330
{
329331
for ( int iRing = 0, nRings = geom->ringCount( iPart ); iRing < nRings; ++iRing )
330332
{
331-
for ( int iVert = 0, nVerts = geom->vertexCount( iPart, iRing ) - 1; iVert < nVerts; ++iVert )
333+
int nVerts = geom->vertexCount( iPart, iRing );
334+
335+
if ( dynamic_cast< const QgsSurface* >( geom ) )
336+
nVerts--;
337+
else if ( const QgsCurve* curve = dynamic_cast< const QgsCurve* >( geom ) )
338+
{
339+
if ( curve->isClosed() )
340+
nVerts--;
341+
}
342+
343+
for ( int iVert = 0; iVert < nVerts; ++iVert )
332344
{
333345
CoordIdx* idx = new CoordIdx( geom, QgsVertexId( iPart, iRing, iVert ) );
334346
CoordIdx* idx1 = new CoordIdx( geom, QgsVertexId( iPart, iRing, iVert + 1 ) );
@@ -469,16 +481,15 @@ void QgsGeometrySnapper::processFeature( QgsFeature& feature )
469481

470482
QgsGeometry QgsGeometrySnapper::snapGeometry( const QgsGeometry& geometry ) const
471483
{
472-
// can't snap to different geometry types
473-
if ( geometry.type() != mReferenceLayer->geometryType() )
474-
return geometry;
475-
476-
QgsPointV2 center = QgsPointV2( geometry.geometry()->boundingBox().center() );
484+
QgsPointV2 center = dynamic_cast< const QgsPointV2* >( geometry.geometry() ) ? *dynamic_cast< const QgsPointV2* >( geometry.geometry() ) :
485+
QgsPointV2( geometry.geometry()->boundingBox().center() );
477486

478487
// Get potential reference features and construct snap index
479488
QList<QgsGeometry> refGeometries;
480489
mIndexMutex.lock();
481-
QgsFeatureIds refFeatureIds = mIndex.intersects( geometry.boundingBox() ).toSet();
490+
QgsRectangle searchBounds = geometry.boundingBox();
491+
searchBounds.grow( mSnapTolerance );
492+
QgsFeatureIds refFeatureIds = mIndex.intersects( searchBounds ).toSet();
482493
mIndexMutex.unlock();
483494

484495
QgsFeatureRequest refFeatureRequest = QgsFeatureRequest().setFilterFids( refFeatureIds ).setSubsetOfAttributes( QgsAttributeList() );
@@ -541,6 +552,10 @@ QgsGeometry QgsGeometrySnapper::snapGeometry( const QgsGeometry& geometry ) cons
541552
}
542553
}
543554

555+
//nothing more to do for points
556+
if ( dynamic_cast< const QgsPointV2* >( subjGeom ) )
557+
return QgsGeometry( subjGeom );
558+
544559
// SnapIndex for subject feature
545560
QgsSnapIndex* subjSnapIndex = new QgsSnapIndex( center, 10 * mSnapTolerance );
546561
subjSnapIndex->addGeometry( subjGeom );
@@ -642,7 +657,14 @@ QgsGeometry QgsGeometrySnapper::snapGeometry( const QgsGeometry& geometry ) cons
642657
int QgsGeometrySnapper::polyLineSize( const QgsAbstractGeometry* geom, int iPart, int iRing ) const
643658
{
644659
int nVerts = geom->vertexCount( iPart, iRing );
645-
QgsPointV2 front = geom->vertexAt( QgsVertexId( iPart, iRing, 0 ) );
646-
QgsPointV2 back = geom->vertexAt( QgsVertexId( iPart, iRing, nVerts - 1 ) );
647-
return back == front ? nVerts - 1 : nVerts;
660+
661+
if ( dynamic_cast< const QgsSurface* >( geom ) )
662+
{
663+
QgsPointV2 front = geom->vertexAt( QgsVertexId( iPart, iRing, 0 ) );
664+
QgsPointV2 back = geom->vertexAt( QgsVertexId( iPart, iRing, nVerts - 1 ) );
665+
if ( front == back )
666+
return nVerts - 1;
667+
}
668+
669+
return nVerts;
648670
}

‎tests/src/analysis/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ ENDMACRO (ADD_QGIS_TEST)
7777
# Tests:
7878

7979
ADD_QGIS_TEST(analyzertest testqgsvectoranalyzer.cpp)
80+
ADD_QGIS_TEST(geometrysnappertest testqgsgeometrysnapper.cpp)
8081
ADD_QGIS_TEST(openstreetmaptest testopenstreetmap.cpp)
8182
ADD_QGIS_TEST(zonalstatisticstest testqgszonalstatistics.cpp)
8283
ADD_QGIS_TEST(rastercalculatortest testqgsrastercalculator.cpp)

‎tests/src/analysis/testqgsgeometrysnapper.cpp

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

0 commit comments

Comments
 (0)
Please sign in to comment.