Branch data Line data Source code
1 : : /*************************************************************************** 2 : : qgsgeometryduplicatenodescheck.cpp 3 : : --------------------- 4 : : begin : September 2015 5 : : copyright : (C) 2014 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 "qgsgeometryduplicatenodescheck.h" 18 : : #include "qgsgeometryutils.h" 19 : : #include "qgsfeaturepool.h" 20 : : #include "qgsgeometrycheckerror.h" 21 : : 22 : 1 : void QgsGeometryDuplicateNodesCheck::collectErrors( const QMap<QString, QgsFeaturePool *> &featurePools, QList<QgsGeometryCheckError *> &errors, QStringList &messages, QgsFeedback *feedback, const LayerFeatureIds &ids ) const 23 : : { 24 : 1 : Q_UNUSED( messages ) 25 : : 26 : 1 : QMap<QString, QgsFeatureIds> featureIds = ids.isEmpty() ? allLayerFeatureIds( featurePools ) : ids.toMap(); 27 : 1 : QgsGeometryCheckerUtils::LayerFeatures layerFeatures( featurePools, featureIds, compatibleGeometryTypes(), feedback, mContext ); 28 : 35 : for ( const QgsGeometryCheckerUtils::LayerFeature &layerFeature : layerFeatures ) 29 : : { 30 : 34 : const QgsAbstractGeometry *geom = layerFeature.geometry().constGet(); 31 : 70 : for ( int iPart = 0, nParts = geom->partCount(); iPart < nParts; ++iPart ) 32 : : { 33 : 73 : for ( int iRing = 0, nRings = geom->ringCount( iPart ); iRing < nRings; ++iRing ) 34 : : { 35 : 37 : int nVerts = QgsGeometryCheckerUtils::polyLineSize( geom, iPart, iRing ); 36 : 37 : if ( nVerts < 2 ) 37 : 0 : continue; 38 : 216 : for ( int iVert = nVerts - 1, jVert = 0; jVert < nVerts; iVert = jVert++ ) 39 : : { 40 : 179 : QgsPoint pi = geom->vertexAt( QgsVertexId( iPart, iRing, iVert ) ); 41 : 179 : QgsPoint pj = geom->vertexAt( QgsVertexId( iPart, iRing, jVert ) ); 42 : 179 : if ( QgsGeometryUtils::sqrDistance2D( pi, pj ) < mContext->tolerance ) 43 : : { 44 : 4 : errors.append( new QgsGeometryCheckError( this, layerFeature, pj, QgsVertexId( iPart, iRing, jVert ) ) ); 45 : 4 : } 46 : 179 : } 47 : 37 : } 48 : 36 : } 49 : : } 50 : 1 : } 51 : : 52 : 1 : void QgsGeometryDuplicateNodesCheck::fixError( const QMap<QString, QgsFeaturePool *> &featurePools, QgsGeometryCheckError *error, int method, const QMap<QString, int> & /*mergeAttributeIndices*/, Changes &changes ) const 53 : : { 54 : 1 : QgsFeaturePool *featurePool = featurePools[ error->layerId() ]; 55 : 1 : QgsFeature feature; 56 : 1 : if ( !featurePool->getFeature( error->featureId(), feature ) ) 57 : : { 58 : 0 : error->setObsolete(); 59 : 0 : return; 60 : : } 61 : 1 : QgsGeometry featureGeom = feature.geometry(); 62 : 1 : QgsAbstractGeometry *geom = featureGeom.get(); 63 : 1 : QgsVertexId vidx = error->vidx(); 64 : : 65 : : // Check if point still exists 66 : 1 : if ( !vidx.isValid( geom ) ) 67 : : { 68 : 0 : error->setObsolete(); 69 : 0 : return; 70 : : } 71 : : 72 : : // Check if error still applies 73 : 1 : int nVerts = QgsGeometryCheckerUtils::polyLineSize( geom, vidx.part, vidx.ring ); 74 : 1 : QgsPoint pi = geom->vertexAt( QgsVertexId( vidx.part, vidx.ring, ( vidx.vertex + nVerts - 1 ) % nVerts ) ); 75 : 1 : QgsPoint pj = geom->vertexAt( error->vidx() ); 76 : 1 : if ( QgsGeometryUtils::sqrDistance2D( pi, pj ) >= mContext->tolerance ) 77 : : { 78 : 0 : error->setObsolete(); 79 : 0 : return; 80 : : } 81 : : 82 : : // Fix error 83 : 1 : if ( method == NoChange ) 84 : : { 85 : 0 : error->setFixed( method ); 86 : 0 : } 87 : 1 : else if ( method == RemoveDuplicates ) 88 : : { 89 : 1 : if ( !QgsGeometryCheckerUtils::canDeleteVertex( geom, vidx.part, vidx.ring ) ) 90 : : { 91 : 0 : error->setFixFailed( tr( "Resulting geometry is degenerate" ) ); 92 : 0 : } 93 : 1 : else if ( !geom->deleteVertex( error->vidx() ) ) 94 : : { 95 : 0 : error->setFixFailed( tr( "Failed to delete vertex" ) ); 96 : 0 : } 97 : : else 98 : : { 99 : 1 : feature.setGeometry( featureGeom ); 100 : 1 : featurePool->updateFeature( feature ); 101 : 1 : error->setFixed( method ); 102 : 1 : changes[error->layerId()][error->featureId()].append( Change( ChangeNode, ChangeRemoved, error->vidx() ) ); 103 : : } 104 : 1 : } 105 : : else 106 : : { 107 : 0 : error->setFixFailed( tr( "Unknown method" ) ); 108 : : } 109 : 1 : } 110 : : 111 : 1 : QStringList QgsGeometryDuplicateNodesCheck::resolutionMethods() const 112 : : { 113 : 1 : static QStringList methods = QStringList() << tr( "Delete duplicate node" ) << tr( "No action" ); 114 : 1 : return methods; 115 : 0 : } 116 : : 117 : 0 : QgsGeometryCheck::CheckType QgsGeometryDuplicateNodesCheck::factoryCheckType() 118 : : { 119 : 0 : return QgsGeometryCheck::FeatureNodeCheck; 120 : : }