Branch data Line data Source code
1 : : /***************************************************************************
2 : : qgsgeometrydanglecheck.cpp
3 : : ---------------------
4 : : begin : June 2017
5 : : copyright : (C) 2017 by Sandro Mani / Sourcepole AG
6 : : email : smani at sourcepole dot ch
7 : : ***************************************************************************
8 : : * *
9 : : * This program is free software; you can redistribute it and/or modify *
10 : : * it under the terms of the GNU General Public License as published by *
11 : : * the Free Software Foundation; either version 2 of the License, or *
12 : : * (at your option) any later version. *
13 : : * *
14 : : ***************************************************************************/
15 : :
16 : : #include "qgsgeometrycheckcontext.h"
17 : : #include "qgsgeometrydanglecheck.h"
18 : : #include "qgslinestring.h"
19 : : #include "qgsvectorlayer.h"
20 : : #include "qgsgeometrycheckerror.h"
21 : :
22 : 1 : void QgsGeometryDangleCheck::collectErrors( const QMap<QString, QgsFeaturePool *> &featurePools, QList<QgsGeometryCheckError *> &errors, QStringList &messages, QgsFeedback *feedback, const LayerFeatureIds &ids ) const
23 : : {
24 : 1 : Q_UNUSED( messages )
25 : 1 : QMap<QString, QgsFeatureIds> featureIds = ids.isEmpty() ? allLayerFeatureIds( featurePools ) : ids.toMap();
26 : 1 : QgsGeometryCheckerUtils::LayerFeatures layerFeatures( featurePools, featureIds, compatibleGeometryTypes(), feedback, mContext );
27 : 10 : for ( const QgsGeometryCheckerUtils::LayerFeature &layerFeature : layerFeatures )
28 : : {
29 : 9 : const QgsAbstractGeometry *geom = layerFeature.geometry().constGet();
30 : 19 : for ( int iPart = 0, nParts = geom->partCount(); iPart < nParts; ++iPart )
31 : : {
32 : 10 : const QgsLineString *line = dynamic_cast<const QgsLineString *>( QgsGeometryCheckerUtils::getGeomPart( geom, iPart ) );
33 : 10 : if ( !line )
34 : : {
35 : : // Should not happen
36 : 0 : continue;
37 : : }
38 : : // Check that start and end node lie on a line
39 : 10 : int nVerts = geom->vertexCount( iPart, 0 );
40 : 10 : const QgsPoint &p1 = geom->vertexAt( QgsVertexId( iPart, 0, 0 ) );
41 : 10 : const QgsPoint &p2 = geom->vertexAt( QgsVertexId( iPart, 0, nVerts - 1 ) );
42 : :
43 : 10 : bool p1touches = QgsGeometryCheckerUtils::pointOnLine( p1, line, mContext->tolerance, true );
44 : 10 : bool p2touches = QgsGeometryCheckerUtils::pointOnLine( p2, line, mContext->tolerance, true );
45 : :
46 : 10 : if ( p1touches && p2touches )
47 : : {
48 : : // Both endpoints lie on line itself
49 : 2 : continue;
50 : : }
51 : :
52 : : // Check whether endpoints line on another line in the layer
53 : 8 : QgsGeometryCheckerUtils::LayerFeatures checkFeatures( featurePools, QList<QString>() << layerFeature.layer()->id(), line->boundingBox(), {QgsWkbTypes::LineGeometry}, mContext );
54 : 23 : for ( const QgsGeometryCheckerUtils::LayerFeature &checkFeature : checkFeatures )
55 : : {
56 : 15 : const QgsAbstractGeometry *testGeom = checkFeature.geometry().constGet();
57 : 31 : for ( int jPart = 0, mParts = testGeom->partCount(); jPart < mParts; ++jPart )
58 : : {
59 : 20 : if ( checkFeature.feature().id() == layerFeature.feature().id() && iPart == jPart )
60 : : {
61 : : // Skip current feature part, it was already checked above
62 : 7 : continue;
63 : : }
64 : 13 : const QgsLineString *testLine = dynamic_cast<const QgsLineString *>( QgsGeometryCheckerUtils::getGeomPart( testGeom, jPart ) );
65 : 13 : if ( !testLine )
66 : : {
67 : 0 : continue;
68 : : }
69 : 13 : p1touches = p1touches || QgsGeometryCheckerUtils::pointOnLine( p1, testLine, mContext->tolerance );
70 : 13 : p2touches = p2touches || QgsGeometryCheckerUtils::pointOnLine( p2, testLine, mContext->tolerance );
71 : 13 : if ( p1touches && p2touches )
72 : : {
73 : 4 : break;
74 : : }
75 : 9 : }
76 : 15 : if ( p1touches && p2touches )
77 : : {
78 : 4 : break;
79 : : }
80 : : }
81 : 8 : if ( p1touches && p2touches )
82 : : {
83 : 4 : continue;
84 : : }
85 : 4 : if ( !p1touches )
86 : : {
87 : 4 : errors.append( new QgsGeometryCheckError( this, layerFeature, p1, QgsVertexId( iPart, 0, 0 ) ) );
88 : 4 : }
89 : 4 : if ( !p2touches )
90 : : {
91 : 2 : errors.append( new QgsGeometryCheckError( this, layerFeature, p2, QgsVertexId( iPart, 0, nVerts - 1 ) ) );
92 : 2 : }
93 : 10 : }
94 : : }
95 : 1 : }
96 : :
97 : 0 : void QgsGeometryDangleCheck::fixError( const QMap<QString, QgsFeaturePool *> &featurePools, QgsGeometryCheckError *error, int method, const QMap<QString, int> & /*mergeAttributeIndices*/, Changes & /*changes*/ ) const
98 : : {
99 : 0 : Q_UNUSED( featurePools )
100 : :
101 : 0 : if ( method == NoChange )
102 : : {
103 : 0 : error->setFixed( method );
104 : 0 : }
105 : : else
106 : : {
107 : 0 : error->setFixFailed( tr( "Unknown method" ) );
108 : : }
109 : 0 : }
110 : :
111 : 0 : QStringList QgsGeometryDangleCheck::resolutionMethods() const
112 : : {
113 : 0 : static QStringList methods = QStringList() << tr( "No action" );
114 : 0 : return methods;
115 : 0 : }
116 : :
117 : 0 : QgsGeometryCheck::CheckType QgsGeometryDangleCheck::factoryCheckType()
118 : : {
119 : 0 : return QgsGeometryCheck::FeatureNodeCheck;
120 : : }
|