17#include <QtConcurrentMap> 
   18#include <QFutureWatcher> 
   36  , mFeaturePools( featurePools )
 
   38  for ( 
auto it = 
featurePools.constBegin(); it != mFeaturePools.constEnd(); ++it )
 
   40    if ( it.value()->layer() )
 
   42      it.value()->layer()->setReadOnly( 
true );
 
   44      it.value()->layer()->dataProvider()->enterUpdateMode();
 
   51  qDeleteAll( mCheckErrors );
 
   52  qDeleteAll( mChecks );
 
   53  for ( 
auto it = mFeaturePools.constBegin(); it != mFeaturePools.constEnd(); ++it )
 
   55    if ( it.value()->layer() )
 
   57      it.value()->layer()->dataProvider()->leaveUpdateMode();
 
   58      it.value()->layer()->setReadOnly( 
false );
 
   72      for ( 
auto it = mFeaturePools.constBegin(); it != mFeaturePools.constEnd(); ++it )
 
   76          *totalSteps += check->isCompatible( it.value()->layer() ) ? it.value()->allFeatureIds().size() : 0;
 
   85  QTimer *timer = 
new QTimer();
 
   86  connect( timer, &QTimer::timeout, 
this, &QgsGeometryChecker::emitProgressValue );
 
   87  QFutureWatcher<void> *watcher = 
new QFutureWatcher<void>();
 
   88  connect( watcher, &QFutureWatcherBase::finished, timer, &QObject::deleteLater );
 
   89  connect( watcher, &QFutureWatcherBase::finished, watcher, &QObject::deleteLater );
 
   91  QFuture<void> future = QtConcurrent::map( mChecks, RunCheckWrapper( 
this ) );
 
   92  watcher->setFuture( future );
 
   98void QgsGeometryChecker::emitProgressValue()
 
  117  error->
check()->
fixError( mFeaturePools, error, method, mMergeAttributeIndices, changes );
 
  120  static QVector<QString> strChangeWhat = { 
"ChangeFeature", 
"ChangePart", 
"ChangeRing", 
"ChangeNode" };
 
  121  static QVector<QString> strChangeType = { 
"ChangeAdded", 
"ChangeRemoved", 
"ChangeChanged" };
 
  122  for ( 
const QString &layerId : changes.keys() )
 
  124    for ( 
const QgsFeatureId &fid : changes[layerId].keys() )
 
  128        QTextStream( stdout ) << 
" * Change: " << layerId << 
":" << fid << 
" :: " << strChangeWhat[change.what] << 
":" << strChangeType[change.type] << 
":(" << change.vidx.part << 
"," << change.vidx.ring << 
"," << change.vidx.vertex << 
")" << endl;
 
  140  if ( changes.isEmpty() )
 
  147  QMap<QString, QSet<QgsFeatureId>> recheckFeatures;
 
  148  for ( 
auto it = changes.constBegin(); it != changes.constEnd(); ++it )
 
  150    const QMap<QgsFeatureId, QList<QgsGeometryCheck::Change>> &layerChanges = it.value();
 
  154    for ( 
auto layerChangeIt = layerChanges.constBegin(); layerChangeIt != layerChanges.constEnd(); ++layerChangeIt )
 
  156      bool removed = 
false;
 
  168        if ( featurePool->
getFeature( layerChangeIt.key(), f ) )
 
  170          recheckFeatures[it.key()].insert( layerChangeIt.key() );
 
  181      if ( err->affectedAreaBBox().intersects( recheckArea ) )
 
  188  QMap<QString, QgsFeatureIds> recheckAreaFeatures;
 
  189  for ( 
auto it = mFeaturePools.constBegin(); it != mFeaturePools.constEnd(); it++ )
 
  197  QList<QgsGeometryCheckError *> recheckErrors;
 
  202      if ( !recheckAreaFeatures.isEmpty() )
 
  204        check->collectErrors( mFeaturePools, recheckErrors, mMessages, 
nullptr, recheckAreaFeatures );
 
  209      if ( !recheckFeatures.isEmpty() )
 
  211        check->collectErrors( mFeaturePools, recheckErrors, mMessages, 
nullptr, recheckFeatures );
 
  226    bool handled = err->handleChanges( changes );
 
  233      if ( recheckErr->isEqual( err ) || recheckErr->closeMatch( err ) )
 
  236        matchErr = recheckErr;
 
  240    if ( nMatch == 1 && matchErr )
 
  244      recheckErrors.removeAll( matchErr );
 
  270    mCheckErrors.append( recheckErr );
 
  273  if ( triggerRepaint )
 
  275    for ( 
auto itChange = changes.constBegin(); itChange != changes.constEnd(); itChange++ )
 
  277      mFeaturePools[itChange.key()]->layer()->triggerRepaint();
 
  284void QgsGeometryChecker::runCheck( 
const QMap<QString, QgsFeaturePool *> &featurePools, 
const QgsGeometryCheck *check )
 
  287  QList<QgsGeometryCheckError *> errors;
 
  288  QStringList messages;
 
  290  mErrorListMutex.lock();
 
  291  mCheckErrors.append( errors );
 
  292  mMessages.append( messages );
 
  293  mErrorListMutex.unlock();
 
  301  : mInstance( instance )
 
  305void QgsGeometryChecker::RunCheckWrapper::operator()( 
const QgsGeometryCheck *check )
 
  307  mInstance->runCheck( mInstance->mFeaturePools, check );
 
A feature pool is based on a vector layer and caches features.
 
QgsFeatureIds getIntersects(const QgsRectangle &rect) const
Gets all feature ids in the bounding box rect.
 
QgsVectorLayer * layer() const
Gets a pointer to the underlying layer.
 
bool getFeature(QgsFeatureId id, QgsFeature &feature)
Retrieves the feature with the specified id into feature.
 
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
 
double progress() const SIP_HOLDGIL
Returns the current progress reported by the feedback object.
 
Base configuration for geometry checks.
 
const QgsCoordinateReferenceSystem mapCrs
The coordinate system in which calculations should be done.
 
const double tolerance
The tolerance to allow for in geometry checks.
 
This represents an error reported by a geometry check.
 
Status
The status of an error.
 
@ StatusFixed
The error is fixed.
 
@ StatusObsolete
The error is obsolete because of other modifications.
 
Status status() const
The status of the error.
 
QString resolutionMessage() const
A message with details, how the error has been resolved.
 
const QgsVertexId & vidx() const
The id of the affected vertex.
 
QgsFeatureId featureId() const
The id of the feature on which this error has been detected.
 
virtual void update(const QgsGeometryCheckError *other)
Update this error with the information from other.
 
virtual QString description() const
The error description.
 
QVariant value() const
An additional value for the error.
 
void setObsolete()
Set the error status to obsolete.
 
const QgsGeometryCheck * check() const
The geometry check that created this error.
 
const QString & layerId() const
The id of the layer on which this error has been detected.
 
virtual QgsRectangle affectedAreaBBox() const
The bounding box of the affected area of the error.
 
const QgsPointXY & location() const
The location of the error in map units.
 
This class implements a geometry check.
 
QMap< QString, QMap< QgsFeatureId, QList< QgsGeometryCheck::Change > > > Changes
A collection of changes.
 
virtual void collectErrors(const QMap< QString, QgsFeaturePool * > &featurePools, QList< QgsGeometryCheckError * > &errors, QStringList &messages, QgsFeedback *feedback, const LayerFeatureIds &ids=QgsGeometryCheck::LayerFeatureIds()) const =0
The main worker method.
 
@ ChangeFeature
This change happens on feature level.
 
@ LayerCheck
The check controls a whole layer (topology checks)
 
@ FeatureCheck
The check controls geometries as a whole.
 
@ ChangeRemoved
Something has been removed.
 
virtual void fixError(const QMap< QString, QgsFeaturePool * > &featurePools, QgsGeometryCheckError *error, int method, const QMap< QString, int > &mergeAttributeIndices, Changes &changes) const
Fixes the error error with the specified method.
 
Manages and runs a set of geometry checks.
 
QFuture< void > execute(int *totalSteps=nullptr)
 
~QgsGeometryChecker() override
 
void progressValue(int value)
 
bool fixError(QgsGeometryCheckError *error, int method, bool triggerRepaint=false)
 
QgsGeometryChecker(const QList< QgsGeometryCheck * > &checks, QgsGeometryCheckContext *context, const QMap< QString, QgsFeaturePool * > &featurePools)
 
void errorAdded(QgsGeometryCheckError *error)
 
void errorUpdated(QgsGeometryCheckError *error, bool statusChanged)
 
const QMap< QString, QgsFeaturePool * > & featurePools() const
 
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
 
QgsCoordinateReferenceSystem crs
 
static QgsProject * instance()
Returns the QgsProject singleton instance.
 
A rectangle specified with double values.
 
void grow(double delta)
Grows the rectangle in place by the specified amount.
 
void combineExtentWith(const QgsRectangle &rect)
Expands the rectangle so that it covers both the original rectangle and the given rectangle.
 
bool contains(const QgsRectangle &rect) const SIP_HOLDGIL
Returns true when rectangle contains other rectangle.
 
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features
 
Descripts a change to fix a geometry.