Branch data Line data Source code
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 "qgsgeometrycheckcontext.h"
17 : : #include "qgsgeometrycollection.h"
18 : : #include "qgscurvepolygon.h"
19 : : #include "qgsgeometrycheck.h"
20 : : #include "qgsgeometrycheckerror.h"
21 : : #include "qgsfeaturepool.h"
22 : : #include "qgsvectorlayer.h"
23 : : #include "qgsreadwritelocker.h"
24 : : #include "qgsthreadingutils.h"
25 : :
26 : :
27 : :
28 : :
29 : 26 : QgsGeometryCheck::QgsGeometryCheck( const QgsGeometryCheckContext *context, const QVariantMap &configuration )
30 : 26 : : mContext( context )
31 : 26 : , mConfiguration( configuration )
32 : 52 : {}
33 : :
34 : 0 : void QgsGeometryCheck::prepare( const QgsGeometryCheckContext *context, const QVariantMap &configuration )
35 : : {
36 : : Q_UNUSED( context )
37 : 0 : Q_UNUSED( configuration )
38 : 0 : }
39 : :
40 : 0 : bool QgsGeometryCheck::isCompatible( QgsVectorLayer *layer ) const
41 : : {
42 : 0 : return compatibleGeometryTypes().contains( layer->geometryType() );
43 : 0 : }
44 : :
45 : 0 : QgsGeometryCheck::Flags QgsGeometryCheck::flags() const
46 : : {
47 : 0 : return QgsGeometryCheck::Flags();
48 : : }
49 : :
50 : 0 : void QgsGeometryCheck::fixError( const QMap<QString, QgsFeaturePool *> &featurePools, QgsGeometryCheckError *error, int method, const QMap<QString, int> &mergeAttributeIndices, QgsGeometryCheck::Changes &changes ) const
51 : : {
52 : 0 : Q_UNUSED( featurePools )
53 : : Q_UNUSED( error )
54 : : Q_UNUSED( method )
55 : 0 : Q_UNUSED( mergeAttributeIndices )
56 : 0 : Q_UNUSED( changes )
57 : 0 : }
58 : :
59 : 18 : QList<QgsGeometryCheckResolutionMethod> QgsGeometryCheck::availableResolutionMethods() const
60 : : {
61 : 18 : QList<QgsGeometryCheckResolutionMethod> fixes;
62 : : // Once the deprecated `resolutionMethods()` function is gone, this default implementation
63 : : // should be removed and each check will need to implement this method instead of resolutionMethods().
64 : : Q_NOWARN_DEPRECATED_PUSH
65 : 18 : const QStringList methods = resolutionMethods();
66 : : Q_NOWARN_DEPRECATED_POP
67 : :
68 : 18 : int i = 0;
69 : 71 : for ( const QString &method : methods )
70 : : {
71 : 53 : fixes.append( QgsGeometryCheckResolutionMethod( i, method, QString(), false ) );
72 : : }
73 : :
74 : 18 : return fixes;
75 : 18 : }
76 : :
77 : 0 : QStringList QgsGeometryCheck::resolutionMethods() const
78 : : {
79 : 0 : return QStringList();
80 : : }
81 : :
82 : 27 : QMap<QString, QgsFeatureIds> QgsGeometryCheck::allLayerFeatureIds( const QMap<QString, QgsFeaturePool *> &featurePools ) const
83 : : {
84 : 27 : QMap<QString, QgsFeatureIds> featureIds;
85 : 93 : for ( QgsFeaturePool *pool : featurePools )
86 : : {
87 : 66 : featureIds.insert( pool->layerId(), pool->allFeatureIds() );
88 : : }
89 : 27 : return featureIds;
90 : 27 : }
91 : :
92 : 5 : void QgsGeometryCheck::replaceFeatureGeometryPart( const QMap<QString, QgsFeaturePool *> &featurePools,
93 : : const QString &layerId, QgsFeature &feature,
94 : : int partIdx, QgsAbstractGeometry *newPartGeom, Changes &changes ) const
95 : : {
96 : 5 : QgsFeaturePool *featurePool = featurePools[layerId];
97 : 5 : QgsGeometry featureGeom = feature.geometry();
98 : 5 : QgsAbstractGeometry *geom = featureGeom.get();
99 : 5 : if ( QgsGeometryCollection *geomCollection = dynamic_cast< QgsGeometryCollection *>( geom ) )
100 : : {
101 : 5 : geomCollection->removeGeometry( partIdx );
102 : 5 : geomCollection->addGeometry( newPartGeom );
103 : 5 : changes[layerId][feature.id()].append( Change( ChangePart, ChangeRemoved, QgsVertexId( partIdx ) ) );
104 : 5 : changes[layerId][feature.id()].append( Change( ChangePart, ChangeAdded, QgsVertexId( geomCollection->partCount() - 1 ) ) );
105 : 5 : feature.setGeometry( featureGeom );
106 : 5 : }
107 : : else
108 : : {
109 : 0 : feature.setGeometry( QgsGeometry( newPartGeom ) );
110 : 0 : changes[layerId][feature.id()].append( Change( ChangeFeature, ChangeChanged ) );
111 : : }
112 : 5 : featurePool->updateFeature( feature );
113 : 5 : }
114 : :
115 : 5 : void QgsGeometryCheck::deleteFeatureGeometryPart( const QMap<QString, QgsFeaturePool *> &featurePools, const QString &layerId, QgsFeature &feature, int partIdx, Changes &changes ) const
116 : : {
117 : 5 : QgsFeaturePool *featurePool = featurePools[layerId];
118 : 5 : QgsGeometry featureGeom = feature.geometry();
119 : 5 : QgsAbstractGeometry *geom = featureGeom.get();
120 : 5 : if ( dynamic_cast<QgsGeometryCollection *>( geom ) )
121 : : {
122 : 5 : static_cast<QgsGeometryCollection *>( geom )->removeGeometry( partIdx );
123 : 5 : if ( static_cast<QgsGeometryCollection *>( geom )->numGeometries() == 0 )
124 : : {
125 : 5 : featurePool->deleteFeature( feature.id() );
126 : 5 : changes[layerId][feature.id()].append( Change( ChangeFeature, ChangeRemoved ) );
127 : 5 : }
128 : : else
129 : : {
130 : 0 : feature.setGeometry( featureGeom );
131 : 0 : featurePool->updateFeature( feature );
132 : 0 : changes[layerId][feature.id()].append( Change( ChangePart, ChangeRemoved, QgsVertexId( partIdx ) ) );
133 : : }
134 : 5 : }
135 : : else
136 : : {
137 : 0 : featurePool->deleteFeature( feature.id() );
138 : 0 : changes[layerId][feature.id()].append( Change( ChangeFeature, ChangeRemoved ) );
139 : : }
140 : 5 : }
141 : :
142 : 2 : void QgsGeometryCheck::deleteFeatureGeometryRing( const QMap<QString, QgsFeaturePool *> &featurePools,
143 : : const QString &layerId, QgsFeature &feature,
144 : : int partIdx, int ringIdx, Changes &changes ) const
145 : : {
146 : 2 : QgsFeaturePool *featurePool = featurePools[layerId];
147 : 2 : QgsGeometry featureGeom = feature.geometry();
148 : 2 : QgsAbstractGeometry *partGeom = QgsGeometryCheckerUtils::getGeomPart( featureGeom.get(), partIdx );
149 : 2 : if ( dynamic_cast<QgsCurvePolygon *>( partGeom ) )
150 : : {
151 : : // If we delete the exterior ring of a polygon, it makes no sense to keep the interiors
152 : 2 : if ( ringIdx == 0 )
153 : : {
154 : 1 : deleteFeatureGeometryPart( featurePools, layerId, feature, partIdx, changes );
155 : 1 : }
156 : : else
157 : : {
158 : 1 : static_cast<QgsCurvePolygon *>( partGeom )->removeInteriorRing( ringIdx - 1 );
159 : 1 : feature.setGeometry( featureGeom );
160 : 1 : featurePool->updateFeature( feature );
161 : 1 : changes[layerId][feature.id()].append( Change( ChangeRing, ChangeRemoved, QgsVertexId( partIdx, ringIdx ) ) );
162 : : }
163 : 2 : }
164 : : // Other geometry types do not have rings, remove the entire part
165 : : else
166 : : {
167 : 0 : deleteFeatureGeometryPart( featurePools, layerId, feature, partIdx, changes );
168 : : }
169 : 2 : }
170 : :
171 : 88 : double QgsGeometryCheck::scaleFactor( const QPointer<QgsVectorLayer> &layer ) const
172 : : {
173 : 88 : double scaleFactor = 1.0;
174 : :
175 : 88 : QgsVectorLayer *lyr = layer.data();
176 : 88 : if ( lyr )
177 : : {
178 : 88 : QgsCoordinateTransform ct( lyr->crs(), mContext->mapCrs, mContext->transformContext );
179 : 88 : scaleFactor = ct.scaleFactor( lyr->extent() );
180 : 88 : }
181 : 88 : return scaleFactor;
182 : 0 : }
183 : :
184 : :
|