13
13
* *
14
14
***************************************************************************/
15
15
16
+ #include " qgscrscache.h"
16
17
#include " qgsgeometryengine.h"
17
18
#include " qgsgeometryoverlapcheck.h"
18
19
#include " ../utils/qgsfeaturepool.h"
19
20
20
21
void QgsGeometryOverlapCheck::collectErrors ( QList<QgsGeometryCheckError *> &errors, QStringList &messages, QAtomicInt *progressCounter, const QMap<QString, QgsFeatureIds> &ids ) const
21
22
{
23
+ double overlapThreshold = mThresholdMapUnits ;
22
24
QMap<QString, QgsFeatureIds> featureIds = ids.isEmpty () ? allLayerFeatureIds () : ids;
23
- for ( const QString &layerId : featureIds.keys () )
25
+ QList<QString> layerIds = featureIds.keys ();
26
+ for ( int i = 0 , n = layerIds.length (); i < n; ++i )
24
27
{
25
- QgsFeaturePool *featurePool = mContext ->featurePools [ layerId ];
26
- if ( !getCompatibility ( featurePool->getLayer ()->geometryType () ) )
28
+ QString layerIdA = layerIds[i];
29
+ QgsFeaturePool *featurePoolA = mContext ->featurePools [ layerIdA ];
30
+ if ( !getCompatibility ( featurePoolA->getLayer ()->geometryType () ) )
27
31
{
28
32
continue ;
29
33
}
30
- double mapToLayerUnits = featurePool-> getMapToLayerUnits ( );
31
- double overlapThreshold = mThresholdMapUnits * mapToLayerUnits * mapToLayerUnits;
32
- for ( QgsFeatureId featureid : featureIds[layerId ] )
34
+ QgsCoordinateTransform crstA = QgsCoordinateTransformCache::instance ()-> transform ( featurePoolA-> getLayer ()-> crs (). authid (), mContext -> mapCrs );
35
+
36
+ for ( QgsFeatureId featureIdA : featureIds[layerIdA ] )
33
37
{
34
38
if ( progressCounter ) progressCounter->fetchAndAddRelaxed ( 1 );
35
- QgsFeature feature ;
36
- if ( !featurePool ->get ( featureid, feature ) )
39
+ QgsFeature featureA ;
40
+ if ( !featurePoolA ->get ( featureIdA, featureA ) )
37
41
{
38
42
continue ;
39
43
}
40
- QgsGeometry featureGeom = feature.geometry ();
41
- QgsAbstractGeometry *geom = featureGeom.geometry ();
42
- QgsGeometryEngine *geomEngine = QgsGeometryCheckerUtils::createGeomEngine ( geom, mContext ->tolerance );
43
44
44
- QgsFeatureIds ids = featurePool->getIntersects ( feature.geometry ().boundingBox () );
45
- for ( QgsFeatureId otherid : ids )
46
- {
47
- // >= : only report overlaps once
48
- if ( otherid >= featureid )
49
- {
50
- continue ;
51
- }
45
+ QgsAbstractGeometry *featureGeomA = featureA.geometry ().geometry ()->clone ();
46
+ featureGeomA->transform ( crstA );
47
+ QgsGeometryEngine *geomEngineA = QgsGeometryCheckerUtils::createGeomEngine ( featureGeomA, mContext ->tolerance );
48
+ QgsRectangle bboxA = featureGeomA->boundingBox ();
52
49
53
- QgsFeature otherFeature;
54
- if ( !featurePool->get ( otherid, otherFeature ) )
50
+ for ( int j = i; j < n; ++j )
51
+ {
52
+ QString layerIdB = layerIds[j];
53
+ QgsFeaturePool *featurePoolB = mContext ->featurePools [ layerIdA ];
54
+ if ( !getCompatibility ( featurePoolB->getLayer ()->geometryType () ) )
55
55
{
56
56
continue ;
57
57
}
58
+ QgsCoordinateTransform crstB = QgsCoordinateTransformCache::instance ()->transform ( featurePoolB->getLayer ()->crs ().authid (), mContext ->mapCrs );
58
59
59
- QString errMsg ;
60
- if ( geomEngine-> overlaps ( *otherFeature. geometry (). geometry (), &errMsg ) )
60
+ QgsFeatureIds idsB = featurePoolB-> getIntersects ( crstB. transform ( bboxA, QgsCoordinateTransform::ReverseTransform ) ) ;
61
+ for ( QgsFeatureId featureIdB : idsB )
61
62
{
62
- QgsAbstractGeometry *interGeom = geomEngine->intersection ( *otherFeature.geometry ().geometry () );
63
- if ( interGeom && !interGeom->isEmpty () )
63
+ // > : only report overlaps within same layer once
64
+ if ( layerIdA == layerIdB && featureIdB >= featureIdA )
65
+ {
66
+ continue ;
67
+ }
68
+ QgsFeature featureB;
69
+ if ( !featurePoolB->get ( featureIdB, featureB ) )
64
70
{
65
- QgsGeometryCheckerUtils::filter1DTypes ( interGeom );
66
- for ( int iPart = 0 , nParts = interGeom->partCount (); iPart < nParts; ++iPart )
71
+ continue ;
72
+ }
73
+ QgsAbstractGeometry *featureGeomB = featureB.geometry ().geometry ()->clone ();
74
+ featureGeomB->transform ( crstB );
75
+ QString errMsg;
76
+ if ( geomEngineA->overlaps ( *featureGeomB, &errMsg ) )
77
+ {
78
+ QgsAbstractGeometry *interGeom = geomEngineA->intersection ( *featureGeomB );
79
+ if ( interGeom && !interGeom->isEmpty () )
67
80
{
68
- double area = QgsGeometryCheckerUtils::getGeomPart ( interGeom, iPart )-> area ( );
69
- if ( area > mContext -> reducedTolerance && area < overlapThreshold )
81
+ QgsGeometryCheckerUtils::filter1DTypes ( interGeom );
82
+ for ( int iPart = 0 , nParts = interGeom-> partCount (); iPart < nParts; ++iPart )
70
83
{
71
- errors.append ( new QgsGeometryOverlapCheckError ( this , layerId, featureid, QgsGeometryCheckerUtils::getGeomPart ( interGeom, iPart )->centroid (), area, otherid ) );
84
+ double area = QgsGeometryCheckerUtils::getGeomPart ( interGeom, iPart )->area ();
85
+ if ( area > mContext ->reducedTolerance && area < overlapThreshold )
86
+ {
87
+ errors.append ( new QgsGeometryOverlapCheckError ( this , layerIdA, featureIdA, QgsGeometryCheckerUtils::getGeomPart ( interGeom, iPart )->centroid (), area, qMakePair ( layerIdB, featureIdB ) ) );
88
+ }
72
89
}
73
90
}
91
+ else if ( !errMsg.isEmpty () )
92
+ {
93
+ messages.append ( tr ( " Overlap check between features %1:%2 and %3:%4 %5" ).arg ( layerIdA ).arg ( featureIdA ).arg ( layerIdB ).arg ( featureIdB ).arg ( errMsg ) );
94
+ }
95
+ delete interGeom;
74
96
}
75
- else if ( !errMsg.isEmpty () )
76
- {
77
- messages.append ( tr ( " Overlap check between features %1 and %2: %3" ).arg ( feature.id () ).arg ( otherFeature.id () ).arg ( errMsg ) );
78
- }
79
- delete interGeom;
97
+ delete featureGeomB;
80
98
}
81
99
}
82
- delete geomEngine;
100
+ delete geomEngineA;
101
+ delete featureGeomA;
83
102
}
84
103
}
85
104
}
@@ -89,30 +108,41 @@ void QgsGeometryOverlapCheck::fixError( QgsGeometryCheckError *error, int method
89
108
QString errMsg;
90
109
QgsGeometryOverlapCheckError *overlapError = static_cast <QgsGeometryOverlapCheckError *>( error );
91
110
92
- QgsFeaturePool *featurePool = mContext ->featurePools [ error->layerId () ];
93
- QgsFeature feature;
94
- QgsFeature otherFeature;
95
- if ( !featurePool->get ( error->featureId (), feature ) ||
96
- !featurePool->get ( overlapError->otherId (), otherFeature ) )
111
+ QgsFeaturePool *featurePoolA = mContext ->featurePools [ overlapError->layerId () ];
112
+ QgsFeaturePool *featurePoolB = mContext ->featurePools [ overlapError->overlappedFeature ().first ];
113
+ QgsFeature featureA;
114
+ QgsFeature featureB;
115
+ if ( !featurePoolA->get ( overlapError->featureId (), featureA ) ||
116
+ !featurePoolB->get ( overlapError->overlappedFeature ().second , featureB ) )
97
117
{
98
118
error->setObsolete ();
99
119
return ;
100
120
}
101
- QgsGeometry featureGeom = feature.geometry ();
102
- QgsAbstractGeometry *geom = featureGeom.geometry ();
103
- QgsGeometryEngine *geomEngine = QgsGeometryCheckerUtils::createGeomEngine ( geom, mContext ->tolerance );
121
+ QgsCoordinateTransform crstA = QgsCoordinateTransformCache::instance ()->transform ( featurePoolA->getLayer ()->crs ().authid (), mContext ->mapCrs );
122
+ QgsCoordinateTransform crstB = QgsCoordinateTransformCache::instance ()->transform ( featurePoolB->getLayer ()->crs ().authid (), mContext ->mapCrs );
104
123
105
124
// Check if error still applies
106
- if ( !geomEngine->overlaps ( otherFeature.geometry ().geometry () ) )
125
+ QgsAbstractGeometry *featureGeomA = featureA.geometry ().geometry ()->clone ();
126
+ featureGeomA->transform ( crstA );
127
+ QgsGeometryEngine *geomEngineA = QgsGeometryCheckerUtils::createGeomEngine ( featureGeomA, mContext ->reducedTolerance );
128
+
129
+ QgsAbstractGeometry *featureGeomB = featureB.geometry ().geometry ()->clone ();
130
+ featureGeomB->transform ( crstB );
131
+
132
+ if ( !geomEngineA->overlaps ( *featureGeomB ) )
107
133
{
108
- delete geomEngine;
134
+ delete geomEngineA;
135
+ delete featureGeomA;
136
+ delete featureGeomB;
109
137
error->setObsolete ();
110
138
return ;
111
139
}
112
- QgsAbstractGeometry *interGeom = geomEngine->intersection ( otherFeature.geometry ().geometry (), &errMsg );
113
- delete geomEngine;
140
+ QgsAbstractGeometry *interGeom = geomEngineA->intersection ( *featureGeomB, &errMsg );
114
141
if ( !interGeom )
115
142
{
143
+ delete geomEngineA;
144
+ delete featureGeomA;
145
+ delete featureGeomB;
116
146
error->setFixFailed ( tr ( " Failed to compute intersection between overlapping features: %1" ).arg ( errMsg ) );
117
147
return ;
118
148
}
@@ -132,6 +162,9 @@ void QgsGeometryOverlapCheck::fixError( QgsGeometryCheckError *error, int method
132
162
if ( !interPart || interPart->isEmpty () )
133
163
{
134
164
delete interGeom;
165
+ delete geomEngineA;
166
+ delete featureGeomA;
167
+ delete featureGeomB;
135
168
error->setObsolete ();
136
169
return ;
137
170
}
@@ -143,9 +176,7 @@ void QgsGeometryOverlapCheck::fixError( QgsGeometryCheckError *error, int method
143
176
}
144
177
else if ( method == Subtract )
145
178
{
146
- geomEngine = QgsGeometryCheckerUtils::createGeomEngine ( geom, mContext ->reducedTolerance );
147
- QgsAbstractGeometry *diff1 = geomEngine->difference ( *interPart, &errMsg );
148
- delete geomEngine;
179
+ QgsAbstractGeometry *diff1 = geomEngineA->difference ( *interPart, &errMsg );
149
180
if ( !diff1 || diff1->isEmpty () )
150
181
{
151
182
delete diff1;
@@ -155,10 +186,9 @@ void QgsGeometryOverlapCheck::fixError( QgsGeometryCheckError *error, int method
155
186
{
156
187
QgsGeometryCheckerUtils::filter1DTypes ( diff1 );
157
188
}
158
- QgsGeometry otherFeatureGeom = otherFeature.geometry ();
159
- QgsGeometryEngine *otherGeomEngine = QgsGeometryCheckerUtils::createGeomEngine ( otherFeatureGeom.geometry (), mContext ->reducedTolerance );
160
- QgsAbstractGeometry *diff2 = otherGeomEngine->difference ( *interPart, &errMsg );
161
- delete otherGeomEngine;
189
+ QgsGeometryEngine *geomEngineB = QgsGeometryCheckerUtils::createGeomEngine ( featureGeomB, mContext ->reducedTolerance );
190
+ QgsAbstractGeometry *diff2 = geomEngineB->difference ( *interPart, &errMsg );
191
+ delete geomEngineB;
162
192
if ( !diff2 || diff2->isEmpty () )
163
193
{
164
194
delete diff2;
@@ -178,19 +208,19 @@ void QgsGeometryOverlapCheck::fixError( QgsGeometryCheckError *error, int method
178
208
{
179
209
if ( shared1 < shared2 )
180
210
{
181
- feature .setGeometry ( QgsGeometry ( diff1 ) );
211
+ featureA .setGeometry ( QgsGeometry ( diff1 ) );
182
212
183
- changes[error->layerId ()][feature .id ()].append ( Change ( ChangeFeature, ChangeChanged ) );
184
- featurePool ->updateFeature ( feature );
213
+ changes[error->layerId ()][featureA .id ()].append ( Change ( ChangeFeature, ChangeChanged ) );
214
+ featurePoolA ->updateFeature ( featureA );
185
215
186
216
delete diff2;
187
217
}
188
218
else
189
219
{
190
- otherFeature .setGeometry ( QgsGeometry ( diff2 ) );
220
+ featureB .setGeometry ( QgsGeometry ( diff2 ) );
191
221
192
- changes[error-> layerId ()][otherFeature .id ()].append ( Change ( ChangeFeature, ChangeChanged ) );
193
- featurePool ->updateFeature ( otherFeature );
222
+ changes[overlapError-> overlappedFeature (). first ][featureB .id ()].append ( Change ( ChangeFeature, ChangeChanged ) );
223
+ featurePoolB ->updateFeature ( featureB );
194
224
195
225
delete diff1;
196
226
}
@@ -203,6 +233,9 @@ void QgsGeometryOverlapCheck::fixError( QgsGeometryCheckError *error, int method
203
233
error->setFixFailed ( tr ( " Unknown method" ) );
204
234
}
205
235
delete interGeom;
236
+ delete geomEngineA;
237
+ delete featureGeomA;
238
+ delete featureGeomB;
206
239
}
207
240
208
241
QStringList QgsGeometryOverlapCheck::getResolutionMethods () const
0 commit comments