Skip to content

Commit 32ba5bf

Browse files
authored
Merge pull request #5791 from nyalldawson/geom_snapper_vertices
Fix geometry snapper sometimes creates unwanted overlapping segments when snapping line layers
2 parents f180ea4 + 5a81870 commit 32ba5bf

45 files changed

Lines changed: 866 additions & 20 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

python/analysis/vector/qgsgeometrysnapper.sip

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ class QgsGeometrySnapper : QObject
2828
{
2929
PreferNodes,
3030
PreferClosest,
31+
PreferNodesNoExtraVertices,
32+
PreferClosestNoExtraVertices,
3133
EndPointPreferNodes,
3234
EndPointPreferClosest,
3335
EndPointToEndPoint,

python/core/geometry/qgsabstractgeometry.sip

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,29 @@ Returns the centroid of the geometry
436436
:rtype: QgsAbstractGeometry
437437
%End
438438

439+
virtual bool removeDuplicateNodes( double epsilon = 4 * DBL_EPSILON, bool useZValues = false ) = 0;
440+
%Docstring
441+
Removes duplicate nodes from the geometry, wherever removing the nodes does not result in a
442+
degenerate geometry.
443+
444+
The ``epsilon`` parameter specifies the tolerance for coordinates when determining that
445+
vertices are identical.
446+
447+
By default, z values are not considered when detecting duplicate nodes. E.g. two nodes
448+
with the same x and y coordinate but different z values will still be considered
449+
duplicate and one will be removed. If ``useZValues`` is true, then the z values are
450+
also tested and nodes with the same x and y but different z will be maintained.
451+
452+
Note that duplicate nodes are not tested between different parts of a multipart geometry. E.g.
453+
a multipoint geometry with overlapping points will not be changed by this method.
454+
455+
The function will return true if nodes were removed, or false if no duplicate nodes
456+
were found.
457+
458+
.. versionadded:: 3.0
459+
:rtype: bool
460+
%End
461+
439462
virtual double vertexAngle( QgsVertexId vertex ) const = 0;
440463
%Docstring
441464
Returns approximate angle at a vertex. This is usually the average angle between adjacent

python/core/geometry/qgscircularstring.sip

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,9 @@ class QgsCircularString: QgsCurve
8383

8484
virtual QgsCircularString *snappedToGrid( double hSpacing, double vSpacing, double dSpacing = 0, double mSpacing = 0 ) const /Factory/;
8585

86+
virtual bool removeDuplicateNodes( double epsilon = 4 * DBL_EPSILON, bool useZValues = false );
87+
88+
8689
virtual void draw( QPainter &p ) const;
8790

8891
virtual void transform( const QgsCoordinateTransform &ct, QgsCoordinateTransform::TransformDirection d = QgsCoordinateTransform::ForwardTransform,

python/core/geometry/qgscompoundcurve.sip

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ class QgsCompoundCurve: QgsCurve
7979

8080
virtual QgsCompoundCurve *snappedToGrid( double hSpacing, double vSpacing, double dSpacing = 0, double mSpacing = 0 ) const /Factory/;
8181

82+
virtual bool removeDuplicateNodes( double epsilon = 4 * DBL_EPSILON, bool useZValues = false );
83+
8284

8385
int nCurves() const;
8486
%Docstring

python/core/geometry/qgscurvepolygon.sip

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@ class QgsCurvePolygon: QgsSurface
6767

6868
virtual QgsCurvePolygon *snappedToGrid( double hSpacing, double vSpacing, double dSpacing = 0, double mSpacing = 0 ) const /Factory/;
6969

70+
virtual bool removeDuplicateNodes( double epsilon = 4 * DBL_EPSILON, bool useZValues = false );
71+
7072

7173
int numInteriorRings() const;
7274
%Docstring

python/core/geometry/qgsgeometry.sip

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -501,7 +501,7 @@ Returns true if WKB of the geometry is of WKBMulti* type
501501
\param afterVertex Receives index of the vertex after the closest segment. The vertex
502502
before the closest segment is always afterVertex - 1
503503
\param leftOf Out: Returns if the point lies on the left of left side of the geometry ( < 0 means left, > 0 means right, 0 indicates
504-
that the test was unsuccesful, e.g. for a point exactly on the line)
504+
that the test was unsuccessful, e.g. for a point exactly on the line)
505505
\param epsilon epsilon for segment snapping
506506
:return: The squared Cartesian distance is also returned in sqrDist, negative number on error
507507
:rtype: float
@@ -688,6 +688,29 @@ Returns true if WKB of the geometry is of WKBMulti* type
688688
:rtype: QgsGeometry
689689
%End
690690

691+
bool removeDuplicateNodes( double epsilon = 4 * DBL_EPSILON, bool useZValues = false );
692+
%Docstring
693+
Removes duplicate nodes from the geometry, wherever removing the nodes does not result in a
694+
degenerate geometry.
695+
696+
The ``epsilon`` parameter specifies the tolerance for coordinates when determining that
697+
vertices are identical.
698+
699+
By default, z values are not considered when detecting duplicate nodes. E.g. two nodes
700+
with the same x and y coordinate but different z values will still be considered
701+
duplicate and one will be removed. If ``useZValues`` is true, then the z values are
702+
also tested and nodes with the same x and y but different z will be maintained.
703+
704+
Note that duplicate nodes are not tested between different parts of a multipart geometry. E.g.
705+
a multipoint geometry with overlapping points will not be changed by this method.
706+
707+
The function will return true if nodes were removed, or false if no duplicate nodes
708+
were found.
709+
710+
.. versionadded:: 3.0
711+
:rtype: bool
712+
%End
713+
691714
bool intersects( const QgsRectangle &r ) const;
692715
%Docstring
693716
Tests for intersection with a rectangle (uses GEOS)

python/core/geometry/qgsgeometrycollection.sip

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ class QgsGeometryCollection: QgsAbstractGeometry
5252
virtual void clear();
5353

5454
virtual QgsGeometryCollection *snappedToGrid( double hSpacing, double vSpacing, double dSpacing = 0, double mSpacing = 0 ) const /Factory/;
55+
56+
virtual bool removeDuplicateNodes( double epsilon = 4 * DBL_EPSILON, bool useZValues = false );
57+
5558
virtual QgsAbstractGeometry *boundary() const /Factory/;
5659

5760
virtual void adjacentVertices( QgsVertexId vertex, QgsVertexId &previousVertex /Out/, QgsVertexId &nextVertex /Out/ ) const;

python/core/geometry/qgslinestring.sip

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,8 @@ Closes the line string by appending the first point to the end of the line, if i
179179

180180
virtual QgsLineString *snappedToGrid( double hSpacing, double vSpacing, double dSpacing = 0, double mSpacing = 0 ) const /Factory/;
181181

182+
virtual bool removeDuplicateNodes( double epsilon = 4 * DBL_EPSILON, bool useZValues = false );
183+
182184

183185
virtual bool fromWkb( QgsConstWkbPtr &wkb );
184186

python/core/geometry/qgspoint.sip

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,9 @@ class QgsPoint: QgsAbstractGeometry
339339
virtual QgsPoint *clone() const /Factory/;
340340

341341
virtual QgsPoint *snappedToGrid( double hSpacing, double vSpacing, double dSpacing = 0, double mSpacing = 0 ) const /Factory/;
342+
343+
virtual bool removeDuplicateNodes( double epsilon = 4 * DBL_EPSILON, bool useZValues = false );
344+
342345
virtual void clear();
343346

344347
virtual bool fromWkb( QgsConstWkbPtr &wkb );

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,9 @@ def icon(self):
6868
def group(self):
6969
return self.tr('Vector geometry')
7070

71+
def tags(self):
72+
return self.tr('valid,invalid,detect').split(',')
73+
7174
def __init__(self):
7275
super().__init__()
7376

@@ -79,7 +82,7 @@ def initAlgorithm(self, config=None):
7982
self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT_LAYER,
8083
self.tr('Input layer')))
8184
self.addParameter(QgsProcessingParameterEnum(self.METHOD,
82-
self.tr('Method'), self.methods))
85+
self.tr('Method'), self.methods, defaultValue=2))
8386
self.parameterDefinition(self.METHOD).setMetadata({
8487
'widget_wrapper': {
8588
'class': 'processing.gui.wrappers.EnumWidgetWrapper',

0 commit comments

Comments
 (0)