Branch data Line data Source code
1 : : /*************************************************************************** 2 : : qgsgeometryfollowboundariescheck.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 "qgsgeometryfollowboundariescheck.h" 18 : : #include "qgsgeometryengine.h" 19 : : #include "qgsproject.h" 20 : : #include "qgsspatialindex.h" 21 : : #include "qgsvectorlayer.h" 22 : : #include "qgsgeometrycheckerror.h" 23 : : 24 : 1 : QgsGeometryFollowBoundariesCheck::QgsGeometryFollowBoundariesCheck( QgsGeometryCheckContext *context, const QVariantMap &configuration, QgsVectorLayer *checkLayer ) 25 : 1 : : QgsGeometryCheck( context, configuration ) 26 : 2 : { 27 : 1 : mCheckLayer = checkLayer; 28 : 1 : if ( mCheckLayer ) 29 : : { 30 : 1 : mIndex = new QgsSpatialIndex( *mCheckLayer->dataProvider() ); 31 : 1 : } 32 : 1 : } 33 : : 34 : 1 : QgsGeometryFollowBoundariesCheck::~QgsGeometryFollowBoundariesCheck() 35 : 1 : { 36 : 1 : delete mIndex; 37 : 1 : } 38 : : 39 : 1 : void QgsGeometryFollowBoundariesCheck::collectErrors( const QMap<QString, QgsFeaturePool *> &featurePools, QList<QgsGeometryCheckError *> &errors, QStringList &messages, QgsFeedback *feedback, const LayerFeatureIds &ids ) const 40 : : { 41 : 1 : Q_UNUSED( messages ) 42 : : 43 : 1 : if ( !mIndex || !mCheckLayer ) 44 : : { 45 : 0 : return; 46 : : } 47 : : 48 : 1 : QMap<QString, QgsFeatureIds> featureIds = ids.isEmpty() ? allLayerFeatureIds( featurePools ) : ids.toMap(); 49 : 1 : featureIds.remove( mCheckLayer->id() ); // Don't check layer against itself 50 : 1 : QgsGeometryCheckerUtils::LayerFeatures layerFeatures( featurePools, featureIds, compatibleGeometryTypes(), feedback, mContext ); 51 : 6 : for ( const QgsGeometryCheckerUtils::LayerFeature &layerFeature : layerFeatures ) 52 : : { 53 : 4 : const QgsAbstractGeometry *geom = layerFeature.geometry().constGet(); 54 : : 55 : : // The geometry to crs of the check layer 56 : 4 : QgsCoordinateTransform crst( layerFeature.layer()->crs(), mCheckLayer->crs(), QgsProject::instance() ); 57 : 4 : QgsGeometry geomt( geom->clone() ); 58 : 4 : geomt.transform( crst ); 59 : : 60 : 4 : std::unique_ptr< QgsGeometryEngine > geomEngine = QgsGeometryCheckerUtils::createGeomEngine( geomt.constGet(), mContext->tolerance ); 61 : : 62 : : // Get potential reference features 63 : 4 : QgsRectangle searchBounds = geomt.constGet()->boundingBox(); 64 : 4 : searchBounds.grow( mContext->tolerance ); 65 : 4 : QgsFeatureIds refFeatureIds = qgis::listToSet( mIndex->intersects( searchBounds ) ); 66 : : 67 : 4 : QgsFeatureRequest refFeatureRequest = QgsFeatureRequest().setFilterFids( refFeatureIds ).setNoAttributes(); 68 : 4 : QgsFeatureIterator refFeatureIt = mCheckLayer->getFeatures( refFeatureRequest ); 69 : : 70 : 4 : if ( refFeatureIds.isEmpty() ) 71 : : { 72 : : // If no potential reference features are found, the geometry is definitely not following boundaries of reference layer features 73 : 0 : errors.append( new QgsGeometryCheckError( this, layerFeature, QgsPointXY( geom->centroid() ) ) ); 74 : 0 : } 75 : : else 76 : : { 77 : : // All reference features must be either contained or disjoint from tested geometry 78 : 4 : QgsFeature refFeature; 79 : 17 : while ( refFeatureIt.nextFeature( refFeature ) ) 80 : : { 81 : 15 : const QgsAbstractGeometry *refGeom = refFeature.geometry().constGet(); 82 : 15 : std::unique_ptr<QgsGeometryEngine> refgeomEngine( QgsGeometryCheckerUtils::createGeomEngine( refGeom, mContext->tolerance ) ); 83 : 15 : QgsGeometry reducedRefGeom( refgeomEngine->buffer( -mContext->tolerance, 0 ) ); 84 : 15 : if ( !( geomEngine->contains( reducedRefGeom.constGet() ) || geomEngine->disjoint( reducedRefGeom.constGet() ) ) ) 85 : : { 86 : 2 : errors.append( new QgsGeometryCheckError( this, layerFeature, QgsPointXY( geom->centroid() ) ) ); 87 : 2 : break; 88 : : } 89 : 15 : } 90 : 4 : } 91 : 4 : } 92 : 1 : } 93 : : 94 : 0 : void QgsGeometryFollowBoundariesCheck::fixError( const QMap<QString, QgsFeaturePool *> &featurePools, QgsGeometryCheckError *error, int method, const QMap<QString, int> & /*mergeAttributeIndices*/, Changes & /*changes*/ ) const 95 : : { 96 : 0 : Q_UNUSED( featurePools ) 97 : : 98 : 0 : if ( method == NoChange ) 99 : : { 100 : 0 : error->setFixed( method ); 101 : 0 : } 102 : : else 103 : : { 104 : 0 : error->setFixFailed( tr( "Unknown method" ) ); 105 : : } 106 : 0 : } 107 : : 108 : 0 : QStringList QgsGeometryFollowBoundariesCheck::resolutionMethods() const 109 : : { 110 : 0 : static QStringList methods = QStringList() << tr( "No action" ); 111 : 0 : return methods; 112 : 0 : } 113 : : 114 : 0 : QgsGeometryCheck::CheckType QgsGeometryFollowBoundariesCheck::factoryCheckType() 115 : : { 116 : 0 : return QgsGeometryCheck::FeatureNodeCheck; 117 : : }