QGIS API Documentation 3.99.0-Master (21b3aa880ba)
Loading...
Searching...
No Matches
qgsgeometrycheck.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsgeometrycheck.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 "qgsgeometrycheck.h"
17
18#include "qgscurvepolygon.h"
19#include "qgsfeaturepool.h"
23#include "qgsreadwritelocker.h"
24#include "qgsthreadingutils.h"
25#include "qgsvectorlayer.h"
26
27#include "moc_qgsgeometrycheck.cpp"
28
29QgsGeometryCheck::QgsGeometryCheck( const QgsGeometryCheckContext *context, const QVariantMap &configuration )
30 : mContext( context )
31 , mConfiguration( configuration )
32{}
33
34void QgsGeometryCheck::prepare( const QgsGeometryCheckContext *context, const QVariantMap &configuration )
35{
36 Q_UNUSED( context )
37 Q_UNUSED( configuration )
38}
39
41{
42 return compatibleGeometryTypes().contains( layer->geometryType() );
43}
44
49
50QgsGeometryCheck::Result QgsGeometryCheck::collectErrors( const QMap<QString, QgsFeaturePool *> &featurePools, QList<QgsGeometryCheckError *> &errors SIP_INOUT, QStringList &messages SIP_INOUT, QgsFeedback *feedback, const LayerFeatureIds &ids ) const
51{
52 Q_UNUSED( featurePools )
53 Q_UNUSED( errors )
54 Q_UNUSED( messages )
55 Q_UNUSED( feedback )
56 Q_UNUSED( ids )
57
59}
60
61
62void QgsGeometryCheck::fixError( const QMap<QString, QgsFeaturePool *> &featurePools, QgsGeometryCheckError *error, int method, const QMap<QString, int> &mergeAttributeIndices, QgsGeometryCheck::Changes &changes ) const
63{
64 Q_UNUSED( featurePools )
65 Q_UNUSED( error )
66 Q_UNUSED( method )
67 Q_UNUSED( mergeAttributeIndices )
68 Q_UNUSED( changes )
69}
70
71QList<QgsGeometryCheckResolutionMethod> QgsGeometryCheck::availableResolutionMethods() const
72{
73 QList<QgsGeometryCheckResolutionMethod> fixes;
74 // Once the deprecated `resolutionMethods()` function is gone, this default implementation
75 // should be removed and each check will need to implement this method instead of resolutionMethods().
77 const QStringList methods = resolutionMethods();
79
80 int i = 0;
81 for ( const QString &method : methods )
82 {
83 fixes.append( QgsGeometryCheckResolutionMethod( i++, method, QString(), false ) );
84 }
85
86 return fixes;
87}
88
90{
91 return QStringList();
92}
93
94QMap<QString, QgsFeatureIds> QgsGeometryCheck::allLayerFeatureIds( const QMap<QString, QgsFeaturePool *> &featurePools ) const
95{
96 QMap<QString, QgsFeatureIds> featureIds;
97 for ( QgsFeaturePool *pool : featurePools )
98 {
99 featureIds.insert( pool->layerId(), pool->allFeatureIds() );
100 }
101 return featureIds;
102}
103
104void QgsGeometryCheck::replaceFeatureGeometryPart( const QMap<QString, QgsFeaturePool *> &featurePools, const QString &layerId, QgsFeature &feature, int partIdx, QgsAbstractGeometry *newPartGeom, Changes &changes ) const
105{
106 QgsFeaturePool *featurePool = featurePools[layerId];
107 QgsGeometry featureGeom = feature.geometry();
108 QgsAbstractGeometry *geom = featureGeom.get();
109 if ( QgsGeometryCollection *geomCollection = dynamic_cast<QgsGeometryCollection *>( geom ) )
110 {
111 geomCollection->removeGeometry( partIdx );
112 geomCollection->addGeometry( newPartGeom );
113 changes[layerId][feature.id()].append( Change( ChangePart, ChangeRemoved, QgsVertexId( partIdx ) ) );
114 changes[layerId][feature.id()].append( Change( ChangePart, ChangeAdded, QgsVertexId( geomCollection->partCount() - 1 ) ) );
115 feature.setGeometry( featureGeom );
116 }
117 else
118 {
119 feature.setGeometry( QgsGeometry( newPartGeom ) );
120 changes[layerId][feature.id()].append( Change( ChangeFeature, ChangeChanged ) );
121 }
122 featurePool->updateFeature( feature );
123}
124
125void QgsGeometryCheck::deleteFeatureGeometryPart( const QMap<QString, QgsFeaturePool *> &featurePools, const QString &layerId, QgsFeature &feature, int partIdx, Changes &changes ) const
126{
127 QgsFeaturePool *featurePool = featurePools[layerId];
128 QgsGeometry featureGeom = feature.geometry();
129 QgsAbstractGeometry *geom = featureGeom.get();
130 if ( dynamic_cast<QgsGeometryCollection *>( geom ) )
131 {
132 static_cast<QgsGeometryCollection *>( geom )->removeGeometry( partIdx );
133 if ( static_cast<QgsGeometryCollection *>( geom )->numGeometries() == 0 )
134 {
135 featurePool->deleteFeature( feature.id() );
136 changes[layerId][feature.id()].append( Change( ChangeFeature, ChangeRemoved ) );
137 }
138 else
139 {
140 feature.setGeometry( featureGeom );
141 featurePool->updateFeature( feature );
142 changes[layerId][feature.id()].append( Change( ChangePart, ChangeRemoved, QgsVertexId( partIdx ) ) );
143 }
144 }
145 else
146 {
147 featurePool->deleteFeature( feature.id() );
148 changes[layerId][feature.id()].append( Change( ChangeFeature, ChangeRemoved ) );
149 }
150}
151
152void QgsGeometryCheck::deleteFeatureGeometryRing( const QMap<QString, QgsFeaturePool *> &featurePools, const QString &layerId, QgsFeature &feature, int partIdx, int ringIdx, Changes &changes ) const
153{
154 QgsFeaturePool *featurePool = featurePools[layerId];
155 QgsGeometry featureGeom = feature.geometry();
156 QgsAbstractGeometry *partGeom = QgsGeometryCheckerUtils::getGeomPart( featureGeom.get(), partIdx );
157 if ( dynamic_cast<QgsCurvePolygon *>( partGeom ) )
158 {
159 // If we delete the exterior ring of a polygon, it makes no sense to keep the interiors
160 if ( ringIdx == 0 )
161 {
162 deleteFeatureGeometryPart( featurePools, layerId, feature, partIdx, changes );
163 }
164 else
165 {
166 static_cast<QgsCurvePolygon *>( partGeom )->removeInteriorRing( ringIdx - 1 );
167 feature.setGeometry( featureGeom );
168 featurePool->updateFeature( feature );
169 changes[layerId][feature.id()].append( Change( ChangeRing, ChangeRemoved, QgsVertexId( partIdx, ringIdx ) ) );
170 }
171 }
172 // Other geometry types do not have rings, remove the entire part
173 else
174 {
175 deleteFeatureGeometryPart( featurePools, layerId, feature, partIdx, changes );
176 }
177}
178
179double QgsGeometryCheck::scaleFactor( const QPointer<QgsVectorLayer> &layer ) const
180{
181 double scaleFactor = 1.0;
182
183 QgsVectorLayer *lyr = layer.data();
184 if ( lyr )
185 {
186 const QgsCoordinateTransform ct( lyr->crs(), mContext->mapCrs, mContext->transformContext );
187 scaleFactor = ct.scaleFactor( lyr->extent() );
188 }
189 return scaleFactor;
190}
191
192QgsGeometryCheck::Result QgsGeometryCheck::checkUniqueId( const QgsGeometryCheckerUtils::LayerFeature layerFeature, QMap< QString, QSet<QVariant> > &uniqueIds ) const
193{
194 const int uniqueIdFieldIndex = mContext->uniqueIdFieldIndex;
195 if ( uniqueIdFieldIndex == -1 )
196 {
198 }
199
200 auto uniqueIdIt = uniqueIds.find( layerFeature.layerId() );
201 if ( uniqueIdIt == uniqueIds.end() )
202 {
203 uniqueIdIt = uniqueIds.insert( layerFeature.layerId(), QSet<QVariant>() );
204 }
205 const QVariant uniqueIdValue = layerFeature.feature().attribute( uniqueIdFieldIndex );
206 if ( uniqueIdIt.value().contains( uniqueIdValue ) )
207 {
209 }
210 uniqueIdIt.value().insert( uniqueIdValue );
211
213}
Abstract base class for all geometries.
Handles coordinate transforms between two coordinate systems.
double scaleFactor(const QgsRectangle &referenceExtent) const
Computes an estimated conversion factor between source and destination units:
Curve polygon geometry type.
A feature pool is based on a vector layer and caches features.
virtual void updateFeature(QgsFeature &feature)=0
Updates a feature in this pool.
virtual void deleteFeature(QgsFeatureId fid)=0
Removes a feature from this pool.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition qgsfeature.h:58
QgsFeatureId id
Definition qgsfeature.h:66
QgsGeometry geometry
Definition qgsfeature.h:69
Q_INVOKABLE QVariant attribute(const QString &name) const
Lookup attribute value by attribute name.
void setGeometry(const QgsGeometry &geometry)
Set the feature's geometry.
Base class for feedback objects to be used for cancellation of something running in a worker thread.
Definition qgsfeedback.h:44
Base configuration for geometry checks.
This represents an error reported by a geometry check.
Implements a resolution for problems detected in geometry checks.
QMap< QString, QMap< QgsFeatureId, QList< QgsGeometryCheck::Change > > > Changes
A collection of changes.
QFlags< Flag > Flags
void deleteFeatureGeometryPart(const QMap< QString, QgsFeaturePool * > &featurePools, const QString &layerId, QgsFeature &feature, int partIdx, Changes &changes) const
Deletes a part of a feature geometry.
virtual QList< QgsGeometryCheckResolutionMethod > availableResolutionMethods() const
Returns a list of available resolution methods.
void deleteFeatureGeometryRing(const QMap< QString, QgsFeaturePool * > &featurePools, const QString &layerId, QgsFeature &feature, int partIdx, int ringIdx, Changes &changes) const
Deletes a ring in a feature geometry.
void replaceFeatureGeometryPart(const QMap< QString, QgsFeaturePool * > &featurePools, const QString &layerId, QgsFeature &feature, int partIdx, QgsAbstractGeometry *newPartGeom, Changes &changes) const
Replaces a part in a feature geometry.
virtual Q_DECL_DEPRECATED QStringList resolutionMethods() const
Returns a list of descriptions for available resolutions for errors.
const QgsGeometryCheckContext * mContext
@ ChangeRing
This change happens on ring level.
@ ChangeFeature
This change happens on feature level.
@ ChangePart
This change happens on part level.
QMap< QString, QgsFeatureIds > allLayerFeatureIds(const QMap< QString, QgsFeaturePool * > &featurePools) const
Returns all layers and feature ids.
Result checkUniqueId(const QgsGeometryCheckerUtils::LayerFeature layerFeature, QMap< QString, QSet< QVariant > > &uniqueIds) const
Checks that there are no duplicated unique IDs.
Result
Result of the geometry checker operation.
@ DuplicatedUniqueId
Found duplicated unique ID value.
@ Success
Operation completed successfully.
QVariantMap mConfiguration
@ ChangeChanged
Something has been updated.
@ ChangeAdded
Something has been added.
@ ChangeRemoved
Something has been removed.
double scaleFactor(const QPointer< QgsVectorLayer > &layer) const
Determines the scale factor of a layer to the map coordinate reference system.
virtual QgsGeometryCheck::Flags flags() const
Flags for this geometry check.
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 QList< Qgis::GeometryType > compatibleGeometryTypes() const =0
A list of geometry types for which this check can be performed.
QgsGeometryCheck(const QgsGeometryCheckContext *context, const QVariantMap &configuration)
Create a new geometry check.
const QgsGeometryCheckContext * context() const
Returns the context.
virtual bool isCompatible(QgsVectorLayer *layer) const
Returns if this geometry check is compatible with layer.
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.
virtual void prepare(const QgsGeometryCheckContext *context, const QVariantMap &configuration)
Will be run in the main thread before collectErrors() is called (which may be run from a background t...
A layer feature combination to uniquely identify and access a feature in a set of layers.
QgsFeature feature() const
Returns the feature.
static QgsAbstractGeometry * getGeomPart(QgsAbstractGeometry *geom, int partIdx)
A geometry is the spatial representation of a feature.
QgsAbstractGeometry * get()
Returns a modifiable (non-const) reference to the underlying abstract geometry primitive.
QgsCoordinateReferenceSystem crs
Definition qgsmaplayer.h:87
Represents a vector layer which manages a vector based dataset.
QgsRectangle extent() const final
Returns the extent of the layer.
Q_INVOKABLE Qgis::GeometryType geometryType() const
Returns point, line or polygon.
#define Q_NOWARN_DEPRECATED_POP
Definition qgis.h:7170
#define Q_NOWARN_DEPRECATED_PUSH
Definition qgis.h:7169
#define SIP_INOUT
Definition qgis_sip.h:79
Descripts a change to fix a geometry.
A list of layers and feature ids for each of these layers.
Utility class for identifying a unique vertex within a geometry.
Definition qgsvertexid.h:30