Skip to content
Permalink
Browse files
Add validation of changed geometries
Whenever geometries are modified, validation will be run while node tool
is active and validation errors are displayed in status bar and with markers on canvas
  • Loading branch information
wonder-sk committed Apr 6, 2017
1 parent f004468 commit 0b41425105c9239380592a6cf2334a16056bd738
Showing with 137 additions and 1 deletion.
  1. +108 −1 src/app/nodetool/qgsnodetool2.cpp
  2. +29 −0 src/app/nodetool/qgsnodetool2.h
@@ -19,12 +19,14 @@
#include "qgscurve.h"
#include "qgscurvepolygon.h"
#include "qgsgeometryutils.h"
#include "qgsgeometryvalidator.h"
#include "qgslogger.h"
#include "qgsmapcanvas.h"
#include "qgsmulticurve.h"
#include "qgspointlocator.h"
#include "qgsproject.h"
#include "qgsrubberband.h"
#include "qgssettings.h"
#include "qgssnappingutils.h"
#include "qgsvectorlayer.h"
#include "qgsvertexmarker.h"
@@ -845,6 +847,9 @@ void QgsNodeTool2::onCachedGeometryChanged( QgsFeatureId fid, const QgsGeometry

// refresh highlighted nodes - their position may have changed
setHighlightedNodes( mSelectedNodes );

// re-run validation for the feature
validateGeometry( layer, fid );
}

void QgsNodeTool2::onCachedGeometryDeleted( QgsFeatureId fid )
@@ -1521,7 +1526,6 @@ void QgsNodeTool2::deleteVertex()
setHighlightedNodes( nodes_new );
}
}

}

void QgsNodeTool2::setHighlightedNodes( QList<Vertex> listNodes )
@@ -1635,3 +1639,106 @@ void QgsNodeTool2::CircularBand::updateRubberBand( const QgsPoint &mapPoint )
Q_FOREACH ( const QgsPointV2 &p, points )
band->addPoint( p );
}


void QgsNodeTool2::validationErrorFound( QgsGeometry::Error e )
{
QgsGeometryValidator *validator = qobject_cast<QgsGeometryValidator *>( sender() );
if ( !validator )
return;

QHash< QPair<QgsVectorLayer *, QgsFeatureId>, GeometryValidation>::iterator it = mValidations.begin();
for ( ; it != mValidations.end(); ++it )
{
GeometryValidation &validation = *it;
if ( validation.validator == validator )
{
validation.addError( e );
break;
}
}
}

void QgsNodeTool2::validationFinished()
{
QgsGeometryValidator *validator = qobject_cast<QgsGeometryValidator *>( sender() );
if ( !validator )
return;

QHash< QPair<QgsVectorLayer *, QgsFeatureId>, GeometryValidation>::iterator it = mValidations.begin();
for ( ; it != mValidations.end(); ++it )
{
GeometryValidation &validation = *it;
if ( validation.validator == validator )
{
QStatusBar *sb = QgisApp::instance()->statusBar();
sb->showMessage( tr( "Validation finished (%n error(s) found).", "number of geometry errors", validation.errorMarkers.size() ) );
}
}
}

void QgsNodeTool2::GeometryValidation::start( QgsGeometry &geom, QgsNodeTool2 *t, QgsVectorLayer *l )
{
tool = t;
layer = l;
validator = new QgsGeometryValidator( &geom );
connect( validator, &QgsGeometryValidator::errorFound, tool, &QgsNodeTool2::validationErrorFound );
connect( validator, &QThread::finished, tool, &QgsNodeTool2::validationFinished );
validator->start();
}

void QgsNodeTool2::GeometryValidation::addError( QgsGeometry::Error e )
{
if ( !errors.isEmpty() )
errors += '\n';
errors += e.what();

if ( e.hasWhere() )
{
QgsVertexMarker *marker = new QgsVertexMarker( tool->canvas() );
marker->setCenter( tool->canvas()->mapSettings().layerToMapCoordinates( layer, e.where() ) );
marker->setIconType( QgsVertexMarker::ICON_X );
marker->setColor( Qt::green );
marker->setZValue( marker->zValue() + 1 );
marker->setPenWidth( 2 );
marker->setToolTip( e.what() );
errorMarkers << marker;
}

QStatusBar *sb = QgisApp::instance()->statusBar();
sb->showMessage( e.what() );
sb->setToolTip( errors );
}

void QgsNodeTool2::GeometryValidation::cleanup()
{
if ( validator )
{
validator->stop();
validator->wait();
validator->deleteLater();
validator = nullptr;
}

qDeleteAll( errorMarkers );
errorMarkers.clear();
}

void QgsNodeTool2::validateGeometry( QgsVectorLayer *layer, QgsFeatureId featureId )
{
QgsSettings settings;
if ( settings.value( QStringLiteral( "qgis/digitizing/validate_geometries" ), 1 ).toInt() == 0 )
return;

QPair<QgsVectorLayer *, QgsFeatureId> id( layer, featureId );
if ( mValidations.contains( id ) )
{
mValidations[id].cleanup();
mValidations.remove( id );
}

GeometryValidation validation;
QgsGeometry geom = cachedGeometry( layer, featureId );
validation.start( geom, this, layer );
mValidations.insert( id, validation );
}
@@ -20,9 +20,11 @@

#include "qgis_app.h"
#include "qgsmaptooladvanceddigitizing.h"
#include "qgsgeometry.h"

class QRubberBand;

class QgsGeometryValidator;
class QgsNodeEditor;
class QgsSelectedFeature;
class QgsVertexMarker;
@@ -88,6 +90,10 @@ class APP_EXPORT QgsNodeTool2 : public QgsMapToolAdvancedDigitizing

void deleteNodeEditorSelection();

void validationErrorFound( QgsGeometry::Error e );

void validationFinished();

private:

void buildDragBandsForVertices( const QSet<Vertex> &movingVertices, const QgsPoint &dragVertexMapPoint );
@@ -178,6 +184,9 @@ class APP_EXPORT QgsNodeTool2 : public QgsMapToolAdvancedDigitizing

void cleanupNodeEditor();

//! Run validation on a geometry (in a background thread)
void validateGeometry( QgsVectorLayer *layer, QgsFeatureId featureId );

private:

// members used for temporary highlight of stuff
@@ -305,6 +314,26 @@ class APP_EXPORT QgsNodeTool2 : public QgsMapToolAdvancedDigitizing
std::unique_ptr<QgsSelectedFeature> mSelectedFeature;
//! Dock widget which allows editing vertices
std::unique_ptr<QgsNodeEditor> mNodeEditor;

// suport for validation of geometries

//! data structure for validation of one geometry of a vector layer
struct GeometryValidation
{
QgsNodeTool2 *tool = nullptr; //!< Pointer to the parent node tool (for connections / canvas)
QgsVectorLayer *layer = nullptr; //!< Pointer to the layer of the validated geometry (for reporojection)
QgsGeometryValidator *validator = nullptr; //!< Object that does validation. Non-null if active
QList<QgsVertexMarker *> errorMarkers; //!< Markers created by validation
QString errors; //!< Full error text from validation

void start( QgsGeometry &geom, QgsNodeTool2 *tool, QgsVectorLayer *l ); //!< Start validation
void addError( QgsGeometry::Error e ); //!< Add another error to the validation
void cleanup(); //!< Delete everything
};

//! data structure to keep validation details
QHash< QPair<QgsVectorLayer *, QgsFeatureId>, GeometryValidation> mValidations;

};


0 comments on commit 0b41425

Please sign in to comment.