26#include <QFutureWatcher>
30#include <QtConcurrentMap>
32#include "moc_qgsgeometrychecker.cpp"
36 , mContext( std::move( context ) )
39 for (
auto it =
featurePools.constBegin(); it != mFeaturePools.constEnd(); ++it )
41 if ( it.value()->layer() )
43 it.value()->layer()->setReadOnly( true );
45 it.value()->layer()->dataProvider()->enterUpdateMode();
52 qDeleteAll( mCheckErrors );
53 qDeleteAll( mChecks );
54 for (
auto it = mFeaturePools.constBegin(); it != mFeaturePools.constEnd(); ++it )
56 if ( it.value()->layer() )
58 it.value()->layer()->dataProvider()->leaveUpdateMode();
59 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 ) )
187 recheckArea.
grow( 10 * mContext->tolerance );
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 )
242 err->update( matchErr );
244 recheckErrors.removeAll( matchErr );
271 mCheckErrors.append( recheckErr );
274 if ( triggerRepaint )
276 for (
auto itChange = changes.constBegin(); itChange != changes.constEnd(); itChange++ )
278 mFeaturePools[itChange.key()]->layer()->triggerRepaint();
285void QgsGeometryChecker::runCheck(
const QMap<QString, QgsFeaturePool *> &featurePools,
const QgsGeometryCheck *check )
288 QList<QgsGeometryCheckError *> errors;
289 QStringList messages;
291 mErrorListMutex.lock();
292 mCheckErrors.append( errors );
293 mMessages.append( messages );
294 mErrorListMutex.unlock();
302 : 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.
QgsCoordinateReferenceSystem crs() const
The coordinate reference system of this layer.
QgsFeatureIds getIntersects(const QgsRectangle &rect) const
Gets all feature ids in the bounding box rect.
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
Returns the current progress reported by the feedback object.
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 QString description() const
The error description.
QVariant value() const
An additional value for the error.
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.
Base class for geometry checks.
QMap< QString, QMap< QgsFeatureId, QList< QgsGeometryCheck::Change > > > Changes
A collection of changes.
@ 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.
virtual Result collectErrors(const QMap< QString, QgsFeaturePool * > &featurePools, QList< QgsGeometryCheckError * > &errors, QStringList &messages, QgsFeedback *feedback, const LayerFeatureIds &ids=QgsGeometryCheck::LayerFeatureIds()) const
The main worker method.
Manages and runs a set of geometry checks.
QFuture< void > execute(int *totalSteps=nullptr)
QgsGeometryChecker(const QList< QgsGeometryCheck * > &checks, std::unique_ptr< QgsGeometryCheckContext > context, const QMap< QString, QgsFeaturePool * > &featurePools)
Constructor.
~QgsGeometryChecker() override
void progressValue(int value)
bool fixError(QgsGeometryCheckError *error, int method, bool triggerRepaint=false)
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.
static QgsProject * instance()
Returns the QgsProject singleton instance.
A rectangle specified with double values.
bool contains(const QgsRectangle &rect) const
Returns true when rectangle contains other rectangle.
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.
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features
Descripts a change to fix a geometry.