Branch data Line data Source code
1 : : /*************************************************************************** 2 : : qgsgeometryselfcontactcheck.cpp 3 : : --------------------- 4 : : begin : September 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 "qgsgeometryselfcontactcheck.h" 18 : : #include "qgsgeometryutils.h" 19 : : #include "qgsfeaturepool.h" 20 : : 21 : 36 : QList<QgsSingleGeometryCheckError *> QgsGeometrySelfContactCheck::processGeometry( const QgsGeometry &geometry ) const 22 : : { 23 : 36 : QList<QgsSingleGeometryCheckError *> errors; 24 : 36 : const QgsAbstractGeometry *geom = geometry.constGet(); 25 : 77 : for ( int iPart = 0, nParts = geom->partCount(); iPart < nParts; ++iPart ) 26 : : { 27 : 82 : for ( int iRing = 0, nRings = geom->ringCount( iPart ); iRing < nRings; ++iRing ) 28 : : { 29 : : // Test for self-contacts 30 : 41 : int n = geom->vertexCount( iPart, iRing ); 31 : 41 : bool isClosed = geom->vertexAt( QgsVertexId( iPart, iRing, 0 ) ) == geom->vertexAt( QgsVertexId( iPart, iRing, n - 1 ) ); 32 : : 33 : : // Geometry ring without duplicate nodes 34 : 41 : QVector<int> vtxMap; 35 : 41 : QVector<QgsPoint> ring; 36 : 41 : vtxMap.append( 0 ); 37 : 41 : ring.append( geom->vertexAt( QgsVertexId( iPart, iRing, 0 ) ) ); 38 : 226 : for ( int i = 1; i < n; ++i ) 39 : : { 40 : 185 : QgsPoint p = geom->vertexAt( QgsVertexId( iPart, iRing, i ) ); 41 : 185 : if ( QgsGeometryUtils::sqrDistance2D( p, ring.last() ) > mContext->tolerance * mContext->tolerance ) 42 : : { 43 : 181 : vtxMap.append( i ); 44 : 181 : ring.append( p ); 45 : 181 : } 46 : 185 : } 47 : 70 : while ( !ring.empty() && QgsGeometryUtils::sqrDistance2D( ring.front(), ring.back() ) < mContext->tolerance * mContext->tolerance ) 48 : : { 49 : 29 : vtxMap.pop_back(); 50 : 29 : ring.pop_back(); 51 : : } 52 : 41 : if ( !ring.empty() && isClosed ) 53 : : { 54 : 27 : vtxMap.append( n - 1 ); 55 : 27 : ring.append( ring.front() ); 56 : 27 : } 57 : 41 : n = ring.size(); 58 : : 59 : : // For each vertex, check whether it lies on a segment 60 : 234 : for ( int iVert = 0, nVerts = n - isClosed; iVert < nVerts; ++iVert ) 61 : : { 62 : 193 : const QgsPoint &p = ring[iVert]; 63 : 1202 : for ( int i = 0, j = 1; j < n; i = j++ ) 64 : : { 65 : 1012 : if ( iVert == i || iVert == j || ( isClosed && iVert == 0 && j == n - 1 ) ) 66 : : { 67 : 361 : continue; 68 : : } 69 : 651 : const QgsPoint &si = ring[i]; 70 : 651 : const QgsPoint &sj = ring[j]; 71 : 651 : QgsPoint q = QgsGeometryUtils::projectPointOnSegment( p, si, sj ); 72 : 651 : if ( QgsGeometryUtils::sqrDistance2D( p, q ) < mContext->tolerance * mContext->tolerance ) 73 : : { 74 : 3 : errors.append( new QgsSingleGeometryCheckError( this, geometry, QgsGeometry( p.clone() ), QgsVertexId( iPart, iRing, vtxMap[iVert] ) ) ); 75 : 3 : break; // No need to report same contact on different segments multiple times 76 : : } 77 : 651 : } 78 : 193 : } 79 : 41 : } 80 : 41 : } 81 : 36 : return errors; 82 : 36 : } 83 : : 84 : 0 : void QgsGeometrySelfContactCheck::fixError( const QMap<QString, QgsFeaturePool *> &featurePools, QgsGeometryCheckError *error, int method, const QMap<QString, int> & /*mergeAttributeIndices*/, Changes & /*changes*/ ) const 85 : : { 86 : 0 : Q_UNUSED( featurePools ) 87 : 0 : if ( method == NoChange ) 88 : : { 89 : 0 : error->setFixed( method ); 90 : 0 : } 91 : : else 92 : : { 93 : 0 : error->setFixFailed( tr( "Unknown method" ) ); 94 : : } 95 : 0 : } 96 : : 97 : 0 : QStringList QgsGeometrySelfContactCheck::resolutionMethods() const 98 : : { 99 : 0 : static QStringList methods = QStringList() << tr( "No action" ); 100 : 0 : return methods; 101 : 0 : } 102 : : 103 : 0 : QgsGeometryCheck::CheckType QgsGeometrySelfContactCheck::factoryCheckType() 104 : : { 105 : 0 : return QgsGeometryCheck::FeatureNodeCheck; 106 : : }