Skip to content

Commit d129c2c

Browse files
authoredSep 19, 2018
Merge pull request #7932 from m-kuhn/single_geometry_check
Add QgsSingleGeometryCheck
2 parents 3cb82a5 + a0283eb commit d129c2c

14 files changed

+497
-194
lines changed
 

‎src/analysis/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ SET(QGIS_ANALYSIS_SRCS
139139
vector/geometry_checker/qgsgeometryanglecheck.cpp
140140
vector/geometry_checker/qgsgeometryareacheck.cpp
141141
vector/geometry_checker/qgsgeometrycheck.cpp
142+
vector/geometry_checker/qgssinglegeometrycheck.cpp
142143
vector/geometry_checker/qgsgeometrychecker.cpp
143144
vector/geometry_checker/qgsgeometrycheckerutils.cpp
144145
vector/geometry_checker/qgsgeometrycontainedcheck.cpp
@@ -268,6 +269,7 @@ SET(QGIS_ANALYSIS_HDRS
268269
vector/geometry_checker/qgsgeometryareacheck.h
269270
vector/geometry_checker/qgsgeometrychecker.h
270271
vector/geometry_checker/qgsgeometrycheck.h
272+
vector/geometry_checker/qgssinglegeometrycheck.h
271273
vector/geometry_checker/qgsgeometrycontainedcheck.h
272274
vector/geometry_checker/qgsgeometrydanglecheck.h
273275
vector/geometry_checker/qgsgeometrydegeneratepolygoncheck.h

‎src/analysis/vector/geometry_checker/qgsgeometrycheck.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,32 @@ QgsRectangle QgsGeometryCheckError::affectedAreaBBox() const
127127
return mGeometry.boundingBox();
128128
}
129129

130+
void QgsGeometryCheckError::setFixed( int method )
131+
{
132+
mStatus = StatusFixed;
133+
const QStringList methods = mCheck->resolutionMethods();
134+
mResolutionMessage = methods[method];
135+
}
136+
137+
void QgsGeometryCheckError::setFixFailed( const QString &reason )
138+
{
139+
mStatus = StatusFixFailed;
140+
mResolutionMessage = reason;
141+
}
142+
143+
bool QgsGeometryCheckError::isEqual( QgsGeometryCheckError *other ) const
144+
{
145+
return other->check() == check() &&
146+
other->layerId() == layerId() &&
147+
other->featureId() == featureId() &&
148+
other->vidx() == vidx();
149+
}
150+
151+
bool QgsGeometryCheckError::closeMatch( QgsGeometryCheckError * ) const
152+
{
153+
return false;
154+
}
155+
130156
bool QgsGeometryCheckError::handleChanges( const QgsGeometryCheck::Changes &changes )
131157
{
132158
if ( status() == StatusObsolete )
@@ -277,3 +303,14 @@ void QgsGeometryCheck::deleteFeatureGeometryRing( const QString &layerId, QgsFea
277303
deleteFeatureGeometryPart( layerId, feature, partIdx, changes );
278304
}
279305
}
306+
307+
void QgsGeometryCheckError::update( const QgsGeometryCheckError *other )
308+
{
309+
Q_ASSERT( mCheck == other->mCheck );
310+
Q_ASSERT( mLayerId == other->mLayerId );
311+
Q_ASSERT( mFeatureId == other->mFeatureId );
312+
mErrorLocation = other->mErrorLocation;
313+
mVidx = other->mVidx;
314+
mValue = other->mValue;
315+
mGeometry = other->mGeometry;
316+
}

‎src/analysis/vector/geometry_checker/qgsgeometrycheck.h

Lines changed: 24 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -157,40 +157,32 @@ class ANALYSIS_EXPORT QgsGeometryCheckError
157157
const QgsVertexId &vidx() const { return mVidx; }
158158
Status status() const { return mStatus; }
159159
QString resolutionMessage() const { return mResolutionMessage; }
160-
void setFixed( int method )
161-
{
162-
mStatus = StatusFixed;
163-
const QStringList methods = mCheck->resolutionMethods();
164-
mResolutionMessage = methods[method];
165-
}
166-
void setFixFailed( const QString &reason )
167-
{
168-
mStatus = StatusFixFailed;
169-
mResolutionMessage = reason;
170-
}
160+
void setFixed( int method );
161+
void setFixFailed( const QString &reason );
171162
void setObsolete() { mStatus = StatusObsolete; }
172-
virtual bool isEqual( QgsGeometryCheckError *other ) const
173-
{
174-
return other->check() == check() &&
175-
other->layerId() == layerId() &&
176-
other->featureId() == featureId() &&
177-
other->vidx() == vidx();
178-
}
179-
virtual bool closeMatch( QgsGeometryCheckError * /*other*/ ) const
180-
{
181-
return false;
182-
}
183-
virtual void update( const QgsGeometryCheckError *other )
184-
{
185-
Q_ASSERT( mCheck == other->mCheck );
186-
Q_ASSERT( mLayerId == other->mLayerId );
187-
Q_ASSERT( mFeatureId == other->mFeatureId );
188-
mErrorLocation = other->mErrorLocation;
189-
mVidx = other->mVidx;
190-
mValue = other->mValue;
191-
mGeometry = other->mGeometry;
192-
}
193163

164+
/**
165+
* Check if this error is equal to \a other.
166+
* Is reimplemented by subclasses with additional information, comparison
167+
* of base information is done in parent class.
168+
*/
169+
virtual bool isEqual( QgsGeometryCheckError *other ) const;
170+
171+
/**
172+
* Check if this error is almost equal to \a other.
173+
* If this returns true, it can be used to update existing errors after re-checking.
174+
*/
175+
virtual bool closeMatch( QgsGeometryCheckError * /*other*/ ) const;
176+
177+
/**
178+
* Update this error with the information from \other.
179+
* Will be used to update existing errors whenever they are re-checked.
180+
*/
181+
virtual void update( const QgsGeometryCheckError *other );
182+
183+
/**
184+
* Apply a list of \a changes.
185+
*/
194186
virtual bool handleChanges( const QgsGeometryCheck::Changes &changes );
195187

196188
protected:

‎src/analysis/vector/geometry_checker/qgsgeometrymultipartcheck.cpp

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,18 @@
1616
#include "qgsgeometrymultipartcheck.h"
1717
#include "qgsfeaturepool.h"
1818

19-
void QgsGeometryMultipartCheck::collectErrors( QList<QgsGeometryCheckError *> &errors, QStringList &/*messages*/, QAtomicInt *progressCounter, const QMap<QString, QgsFeatureIds> &ids ) const
19+
QList<QgsSingleGeometryCheckError *> QgsGeometryMultipartCheck::processGeometry( const QgsGeometry &geometry, const QVariantMap &configuration ) const
2020
{
21-
QMap<QString, QgsFeatureIds> featureIds = ids.isEmpty() ? allLayerFeatureIds() : ids;
22-
QgsGeometryCheckerUtils::LayerFeatures layerFeatures( mContext->featurePools, featureIds, mCompatibleGeometryTypes, progressCounter, mContext );
23-
for ( const QgsGeometryCheckerUtils::LayerFeature &layerFeature : layerFeatures )
21+
Q_UNUSED( configuration )
22+
QList<QgsSingleGeometryCheckError *> errors;
23+
24+
const QgsAbstractGeometry *geom = geometry.constGet();
25+
QgsWkbTypes::Type type = geom->wkbType();
26+
if ( geom->partCount() == 1 && QgsWkbTypes::isMultiType( type ) )
2427
{
25-
const QgsAbstractGeometry *geom = layerFeature.geometry().constGet();
26-
QgsWkbTypes::Type type = geom->wkbType();
27-
if ( geom->partCount() == 1 && QgsWkbTypes::isMultiType( type ) )
28-
{
29-
errors.append( new QgsGeometryCheckError( this, layerFeature, geom->centroid() ) );
30-
}
28+
errors.append( new QgsSingleGeometryCheckError( this, geometry, geometry ) );
3129
}
30+
return errors;
3231
}
3332

3433
void QgsGeometryMultipartCheck::fixError( QgsGeometryCheckError *error, int method, const QMap<QString, int> & /*mergeAttributeIndices*/, Changes &changes ) const

‎src/analysis/vector/geometry_checker/qgsgeometrymultipartcheck.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,14 @@
1818
#ifndef QGS_GEOMETRY_MULTIPART_CHECK_H
1919
#define QGS_GEOMETRY_MULTIPART_CHECK_H
2020

21-
#include "qgsgeometrycheck.h"
21+
#include "qgssinglegeometrycheck.h"
2222

23-
class ANALYSIS_EXPORT QgsGeometryMultipartCheck : public QgsGeometryCheck
23+
class ANALYSIS_EXPORT QgsGeometryMultipartCheck : public QgsSingleGeometryCheck
2424
{
2525
public:
2626
explicit QgsGeometryMultipartCheck( QgsGeometryCheckerContext *context )
27-
: QgsGeometryCheck( FeatureCheck, {QgsWkbTypes::PointGeometry, QgsWkbTypes::LineGeometry, QgsWkbTypes::PolygonGeometry}, context ) {}
28-
void collectErrors( QList<QgsGeometryCheckError *> &errors, QStringList &messages, QAtomicInt *progressCounter = nullptr, const QMap<QString, QgsFeatureIds> &ids = QMap<QString, QgsFeatureIds>() ) const override;
27+
: QgsSingleGeometryCheck( FeatureCheck, {QgsWkbTypes::PointGeometry, QgsWkbTypes::LineGeometry, QgsWkbTypes::PolygonGeometry}, context ) {}
28+
QList<QgsSingleGeometryCheckError *> processGeometry( const QgsGeometry &geometry, const QVariantMap &configuration ) const override;
2929
void fixError( QgsGeometryCheckError *error, int method, const QMap<QString, int> &mergeAttributeIndices, Changes &changes ) const override;
3030
QStringList resolutionMethods() const override;
3131
QString errorDescription() const override { return tr( "Multipart object with only one feature" ); }

‎src/analysis/vector/geometry_checker/qgsgeometryselfcontactcheck.cpp

Lines changed: 48 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -17,70 +17,68 @@
1717
#include "qgsgeometryutils.h"
1818
#include "qgsfeaturepool.h"
1919

20-
void QgsGeometrySelfContactCheck::collectErrors( QList<QgsGeometryCheckError *> &errors, QStringList &/*messages*/, QAtomicInt *progressCounter, const QMap<QString, QgsFeatureIds> &ids ) const
20+
QList<QgsSingleGeometryCheckError *> QgsGeometrySelfContactCheck::processGeometry( const QgsGeometry &geometry, const QVariantMap &configuration ) const
2121
{
22-
QMap<QString, QgsFeatureIds> featureIds = ids.isEmpty() ? allLayerFeatureIds() : ids;
23-
QgsGeometryCheckerUtils::LayerFeatures layerFeatures( mContext->featurePools, featureIds, mCompatibleGeometryTypes, progressCounter, mContext );
24-
for ( const QgsGeometryCheckerUtils::LayerFeature &layerFeature : layerFeatures )
22+
Q_UNUSED( configuration )
23+
QList<QgsSingleGeometryCheckError *> errors;
24+
const QgsAbstractGeometry *geom = geometry.constGet();
25+
for ( int iPart = 0, nParts = geom->partCount(); iPart < nParts; ++iPart )
2526
{
26-
const QgsAbstractGeometry *geom = layerFeature.geometry().constGet();
27-
for ( int iPart = 0, nParts = geom->partCount(); iPart < nParts; ++iPart )
27+
for ( int iRing = 0, nRings = geom->ringCount( iPart ); iRing < nRings; ++iRing )
2828
{
29-
for ( int iRing = 0, nRings = geom->ringCount( iPart ); iRing < nRings; ++iRing )
30-
{
31-
// Test for self-contacts
32-
int n = geom->vertexCount( iPart, iRing );
33-
bool isClosed = geom->vertexAt( QgsVertexId( iPart, iRing, 0 ) ) == geom->vertexAt( QgsVertexId( iPart, iRing, n - 1 ) );
29+
// Test for self-contacts
30+
int n = geom->vertexCount( iPart, iRing );
31+
bool isClosed = geom->vertexAt( QgsVertexId( iPart, iRing, 0 ) ) == geom->vertexAt( QgsVertexId( iPart, iRing, n - 1 ) );
3432

35-
// Geometry ring without duplicate nodes
36-
QVector<int> vtxMap;
37-
QVector<QgsPoint> ring;
38-
vtxMap.append( 0 );
39-
ring.append( geom->vertexAt( QgsVertexId( iPart, iRing, 0 ) ) );
40-
for ( int i = 1; i < n; ++i )
41-
{
42-
QgsPoint p = geom->vertexAt( QgsVertexId( iPart, iRing, i ) );
43-
if ( QgsGeometryUtils::sqrDistance2D( p, ring.last() ) > mContext->tolerance * mContext->tolerance )
44-
{
45-
vtxMap.append( i );
46-
ring.append( p );
47-
}
48-
}
49-
while ( QgsGeometryUtils::sqrDistance2D( ring.front(), ring.back() ) < mContext->tolerance * mContext->tolerance )
50-
{
51-
vtxMap.pop_back();
52-
ring.pop_back();
53-
}
54-
if ( isClosed )
33+
// Geometry ring without duplicate nodes
34+
QVector<int> vtxMap;
35+
QVector<QgsPoint> ring;
36+
vtxMap.append( 0 );
37+
ring.append( geom->vertexAt( QgsVertexId( iPart, iRing, 0 ) ) );
38+
for ( int i = 1; i < n; ++i )
39+
{
40+
QgsPoint p = geom->vertexAt( QgsVertexId( iPart, iRing, i ) );
41+
if ( QgsGeometryUtils::sqrDistance2D( p, ring.last() ) > mContext->tolerance * mContext->tolerance )
5542
{
56-
vtxMap.append( n - 1 );
57-
ring.append( ring.front() );
43+
vtxMap.append( i );
44+
ring.append( p );
5845
}
59-
n = ring.size();
46+
}
47+
while ( QgsGeometryUtils::sqrDistance2D( ring.front(), ring.back() ) < mContext->tolerance * mContext->tolerance )
48+
{
49+
vtxMap.pop_back();
50+
ring.pop_back();
51+
}
52+
if ( isClosed )
53+
{
54+
vtxMap.append( n - 1 );
55+
ring.append( ring.front() );
56+
}
57+
n = ring.size();
6058

61-
// For each vertex, check whether it lies on a segment
62-
for ( int iVert = 0, nVerts = n - isClosed; iVert < nVerts; ++iVert )
59+
// For each vertex, check whether it lies on a segment
60+
for ( int iVert = 0, nVerts = n - isClosed; iVert < nVerts; ++iVert )
61+
{
62+
const QgsPoint &p = ring[iVert];
63+
for ( int i = 0, j = 1; j < n; i = j++ )
6364
{
64-
const QgsPoint &p = ring[iVert];
65-
for ( int i = 0, j = 1; j < n; i = j++ )
65+
if ( iVert == i || iVert == j || ( isClosed && iVert == 0 && j == n - 1 ) )
66+
{
67+
continue;
68+
}
69+
const QgsPoint &si = ring[i];
70+
const QgsPoint &sj = ring[j];
71+
QgsPoint q = QgsGeometryUtils::projectPointOnSegment( p, si, sj );
72+
if ( QgsGeometryUtils::sqrDistance2D( p, q ) < mContext->tolerance * mContext->tolerance )
6673
{
67-
if ( iVert == i || iVert == j || ( isClosed && iVert == 0 && j == n - 1 ) )
68-
{
69-
continue;
70-
}
71-
const QgsPoint &si = ring[i];
72-
const QgsPoint &sj = ring[j];
73-
QgsPoint q = QgsGeometryUtils::projectPointOnSegment( p, si, sj );
74-
if ( QgsGeometryUtils::sqrDistance2D( p, q ) < mContext->tolerance * mContext->tolerance )
75-
{
76-
errors.append( new QgsGeometryCheckError( this, layerFeature, p, QgsVertexId( iPart, iRing, vtxMap[iVert] ) ) );
77-
break; // No need to report same contact on different segments multiple times
78-
}
74+
errors.append( new QgsSingleGeometryCheckError( this, geometry, QgsGeometry( p.clone() ), QgsVertexId( iPart, iRing, vtxMap[iVert] ) ) );
75+
break; // No need to report same contact on different segments multiple times
7976
}
8077
}
8178
}
8279
}
8380
}
81+
return errors;
8482
}
8583

8684
void QgsGeometrySelfContactCheck::fixError( QgsGeometryCheckError *error, int method, const QMap<QString, int> & /*mergeAttributeIndices*/, Changes & /*changes*/ ) const

‎src/analysis/vector/geometry_checker/qgsgeometryselfcontactcheck.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,14 @@
1818
#ifndef QGS_GEOMETRY_SELFCONTACT_CHECK_H
1919
#define QGS_GEOMETRY_SELFCONTACT_CHECK_H
2020

21-
#include "qgsgeometrycheck.h"
21+
#include "qgssinglegeometrycheck.h"
2222

23-
class ANALYSIS_EXPORT QgsGeometrySelfContactCheck : public QgsGeometryCheck
23+
class ANALYSIS_EXPORT QgsGeometrySelfContactCheck : public QgsSingleGeometryCheck
2424
{
2525
public:
2626
QgsGeometrySelfContactCheck( QgsGeometryCheckerContext *context )
27-
: QgsGeometryCheck( FeatureNodeCheck, {QgsWkbTypes::LineGeometry, QgsWkbTypes::PolygonGeometry}, context ) {}
28-
void collectErrors( QList<QgsGeometryCheckError *> &errors, QStringList &messages, QAtomicInt *progressCounter = nullptr, const QMap<QString, QgsFeatureIds> &ids = QMap<QString, QgsFeatureIds>() ) const override;
27+
: QgsSingleGeometryCheck( FeatureNodeCheck, {QgsWkbTypes::LineGeometry, QgsWkbTypes::PolygonGeometry}, context ) {}
28+
QList<QgsSingleGeometryCheckError *> processGeometry( const QgsGeometry &geometry, const QVariantMap &configuration ) const override;
2929
void fixError( QgsGeometryCheckError *error, int method, const QMap<QString, int> &mergeAttributeIndices, Changes & ) const override;
3030
QStringList resolutionMethods() const override;
3131
QString errorDescription() const override { return tr( "Self contact" ); }

‎src/analysis/vector/geometry_checker/qgsgeometryselfintersectioncheck.cpp

Lines changed: 45 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -22,62 +22,48 @@
2222
#include "qgsgeometryutils.h"
2323
#include "qgsfeaturepool.h"
2424

25-
bool QgsGeometrySelfIntersectionCheckError::isEqual( QgsGeometryCheckError *other ) const
25+
bool QgsGeometrySelfIntersectionCheckError::isEqual( const QgsSingleGeometryCheckError *other ) const
2626
{
27-
return QgsGeometryCheckError::isEqual( other ) &&
28-
static_cast<QgsGeometrySelfIntersectionCheckError *>( other )->intersection().segment1 == intersection().segment1 &&
29-
static_cast<QgsGeometrySelfIntersectionCheckError *>( other )->intersection().segment2 == intersection().segment2;
27+
return QgsSingleGeometryCheckError::isEqual( other ) &&
28+
static_cast<const QgsGeometrySelfIntersectionCheckError *>( other )->intersection().segment1 == intersection().segment1 &&
29+
static_cast<const QgsGeometrySelfIntersectionCheckError *>( other )->intersection().segment2 == intersection().segment2;
3030
}
3131

32-
bool QgsGeometrySelfIntersectionCheckError::handleChanges( const QgsGeometryCheck::Changes &changes )
32+
bool QgsGeometrySelfIntersectionCheckError::handleChanges( const QList<QgsGeometryCheck::Change> &changes )
3333
{
34-
if ( !QgsGeometryCheckError::handleChanges( changes ) )
35-
{
34+
if ( !QgsSingleGeometryCheckError::handleChanges( changes ) )
3635
return false;
37-
}
38-
for ( const QgsGeometryCheck::Change &change : changes[layerId()].value( featureId() ) )
36+
37+
for ( const QgsGeometryCheck::Change &change : changes )
3938
{
40-
if ( change.vidx.vertex == mInter.segment1 ||
41-
change.vidx.vertex == mInter.segment1 + 1 ||
42-
change.vidx.vertex == mInter.segment2 ||
43-
change.vidx.vertex == mInter.segment2 + 1 )
39+
if ( change.vidx.vertex == mIntersection.segment1 ||
40+
change.vidx.vertex == mIntersection.segment1 + 1 ||
41+
change.vidx.vertex == mIntersection.segment2 ||
42+
change.vidx.vertex == mIntersection.segment2 + 1 )
4443
{
4544
return false;
4645
}
4746
else if ( change.vidx.vertex >= 0 )
4847
{
49-
if ( change.vidx.vertex < mInter.segment1 )
48+
if ( change.vidx.vertex < mIntersection.segment1 )
5049
{
51-
mInter.segment1 += change.type == QgsGeometryCheck::ChangeAdded ? 1 : -1;
50+
mIntersection.segment1 += change.type == QgsGeometryCheck::ChangeAdded ? 1 : -1;
5251
}
53-
if ( change.vidx.vertex < mInter.segment2 )
52+
if ( change.vidx.vertex < mIntersection.segment2 )
5453
{
55-
mInter.segment2 += change.type == QgsGeometryCheck::ChangeAdded ? 1 : -1;
54+
mIntersection.segment2 += change.type == QgsGeometryCheck::ChangeAdded ? 1 : -1;
5655
}
5756
}
5857
}
5958
return true;
6059
}
6160

62-
63-
void QgsGeometrySelfIntersectionCheck::collectErrors( QList<QgsGeometryCheckError *> &errors, QStringList &/*messages*/, QAtomicInt *progressCounter, const QMap<QString, QgsFeatureIds> &ids ) const
61+
void QgsGeometrySelfIntersectionCheckError::update( const QgsSingleGeometryCheckError *other )
6462
{
65-
QMap<QString, QgsFeatureIds> featureIds = ids.isEmpty() ? allLayerFeatureIds() : ids;
66-
QgsGeometryCheckerUtils::LayerFeatures layerFeatures( mContext->featurePools, featureIds, mCompatibleGeometryTypes, progressCounter, mContext );
67-
for ( const QgsGeometryCheckerUtils::LayerFeature &layerFeature : layerFeatures )
68-
{
69-
const QgsAbstractGeometry *geom = layerFeature.geometry().constGet();
70-
for ( int iPart = 0, nParts = geom->partCount(); iPart < nParts; ++iPart )
71-
{
72-
for ( int iRing = 0, nRings = geom->ringCount( iPart ); iRing < nRings; ++iRing )
73-
{
74-
for ( const QgsGeometryUtils::SelfIntersection &inter : QgsGeometryUtils::selfIntersections( geom, iPart, iRing, mContext->tolerance ) )
75-
{
76-
errors.append( new QgsGeometrySelfIntersectionCheckError( this, layerFeature, inter.point, QgsVertexId( iPart, iRing ), inter ) );
77-
}
78-
}
79-
}
80-
}
63+
QgsSingleGeometryCheckError::update( other );
64+
// Static cast since this should only get called if isEqual == true
65+
const QgsGeometrySelfIntersectionCheckError *err = static_cast<const QgsGeometrySelfIntersectionCheckError *>( other );
66+
mIntersection.point = err->mIntersection.point;
8167
}
8268

8369
void QgsGeometrySelfIntersectionCheck::fixError( QgsGeometryCheckError *error, int method, const QMap<QString, int> & /*mergeAttributeIndices*/, Changes &changes ) const
@@ -89,9 +75,11 @@ void QgsGeometrySelfIntersectionCheck::fixError( QgsGeometryCheckError *error, i
8975
error->setObsolete();
9076
return;
9177
}
78+
9279
QgsGeometry featureGeom = feature.geometry();
9380
QgsAbstractGeometry *geom = featureGeom.get();
94-
QgsVertexId vidx = error->vidx();
81+
82+
const QgsVertexId vidx = error->vidx();
9583

9684
// Check if ring still exists
9785
if ( !vidx.isValid( geom ) )
@@ -100,7 +88,8 @@ void QgsGeometrySelfIntersectionCheck::fixError( QgsGeometryCheckError *error, i
10088
return;
10189
}
10290

103-
const QgsGeometryUtils::SelfIntersection &inter = static_cast<QgsGeometrySelfIntersectionCheckError *>( error )->intersection();
91+
const QgsGeometryCheckErrorSingle *singleError = static_cast<const QgsGeometryCheckErrorSingle *>( error );
92+
const QgsGeometryUtils::SelfIntersection &inter = static_cast<const QgsGeometrySelfIntersectionCheckError *>( singleError->singleError() )->intersection();
10493
// Check if error still applies
10594
bool ringIsClosed = false;
10695
int nVerts = QgsGeometryCheckerUtils::polyLineSize( geom, vidx.part, vidx.ring, &ringIsClosed );
@@ -325,3 +314,22 @@ QStringList QgsGeometrySelfIntersectionCheck::resolutionMethods() const
325314
<< tr( "No action" );
326315
return methods;
327316
}
317+
318+
QList<QgsSingleGeometryCheckError *> QgsGeometrySelfIntersectionCheck::processGeometry( const QgsGeometry &geometry, const QVariantMap &configuration ) const
319+
{
320+
Q_UNUSED( configuration )
321+
322+
QList<QgsSingleGeometryCheckError *> errors;
323+
const QgsAbstractGeometry *geom = geometry.constGet();
324+
for ( int iPart = 0, nParts = geom->partCount(); iPart < nParts; ++iPart )
325+
{
326+
for ( int iRing = 0, nRings = geom->ringCount( iPart ); iRing < nRings; ++iRing )
327+
{
328+
for ( const QgsGeometryUtils::SelfIntersection &inter : QgsGeometryUtils::selfIntersections( geom, iPart, iRing, mContext->tolerance ) )
329+
{
330+
errors.append( new QgsGeometrySelfIntersectionCheckError( this, geometry, QgsGeometry( inter.point.clone() ), QgsVertexId( iPart, iRing ), inter ) );
331+
}
332+
}
333+
}
334+
return errors;
335+
}

‎src/analysis/vector/geometry_checker/qgsgeometryselfintersectioncheck.h

Lines changed: 19 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -19,44 +19,39 @@
1919
#define QGS_GEOMETRY_SELFINTERSECTION_CHECK_H
2020

2121
#include "qgsgeometryutils.h"
22-
#include "qgsgeometrycheck.h"
22+
#include "qgssinglegeometrycheck.h"
2323

24-
class ANALYSIS_EXPORT QgsGeometrySelfIntersectionCheckError : public QgsGeometryCheckError
24+
class ANALYSIS_EXPORT QgsGeometrySelfIntersectionCheckError : public QgsSingleGeometryCheckError
2525
{
2626
public:
27-
QgsGeometrySelfIntersectionCheckError( const QgsGeometryCheck *check,
28-
const QgsGeometryCheckerUtils::LayerFeature &layerFeature,
29-
const QgsPointXY &errorLocation,
30-
QgsVertexId vidx,
31-
const QgsGeometryUtils::SelfIntersection &inter )
32-
: QgsGeometryCheckError( check, layerFeature, errorLocation, vidx )
33-
, mInter( inter )
34-
{ }
35-
const QgsGeometryUtils::SelfIntersection &intersection() const { return mInter; }
36-
bool isEqual( QgsGeometryCheckError *other ) const override;
37-
bool handleChanges( const QgsGeometryCheck::Changes &changes ) override;
38-
void update( const QgsGeometrySelfIntersectionCheckError *other )
39-
{
40-
QgsGeometryCheckError::update( other );
41-
// Static cast since this should only get called if isEqual == true
42-
const QgsGeometrySelfIntersectionCheckError *err = static_cast<const QgsGeometrySelfIntersectionCheckError *>( other );
43-
mInter.point = err->mInter.point;
44-
}
27+
QgsGeometrySelfIntersectionCheckError( const QgsSingleGeometryCheck *check,
28+
const QgsGeometry &geometry,
29+
const QgsGeometry &errorLocation,
30+
QgsVertexId vertexId,
31+
const QgsGeometryUtils::SelfIntersection &intersection )
32+
: QgsSingleGeometryCheckError( check, geometry, errorLocation, vertexId )
33+
, mIntersection( intersection )
34+
{}
35+
36+
const QgsGeometryUtils::SelfIntersection &intersection() const { return mIntersection; }
37+
bool isEqual( const QgsSingleGeometryCheckError *other ) const override;
38+
bool handleChanges( const QList<QgsGeometryCheck::Change> &changes ) override;
39+
void update( const QgsSingleGeometryCheckError *other ) override;
4540

4641
private:
47-
QgsGeometryUtils::SelfIntersection mInter;
42+
QgsGeometryUtils::SelfIntersection mIntersection;
4843
};
4944

50-
class ANALYSIS_EXPORT QgsGeometrySelfIntersectionCheck : public QgsGeometryCheck
45+
class ANALYSIS_EXPORT QgsGeometrySelfIntersectionCheck : public QgsSingleGeometryCheck
5146
{
5247
public:
5348
explicit QgsGeometrySelfIntersectionCheck( QgsGeometryCheckerContext *context )
54-
: QgsGeometryCheck( FeatureNodeCheck, {QgsWkbTypes::LineGeometry, QgsWkbTypes::PolygonGeometry}, context ) {}
55-
void collectErrors( QList<QgsGeometryCheckError *> &errors, QStringList &messages, QAtomicInt *progressCounter = nullptr, const QMap<QString, QgsFeatureIds> &ids = QMap<QString, QgsFeatureIds>() ) const override;
49+
: QgsSingleGeometryCheck( FeatureNodeCheck, {QgsWkbTypes::LineGeometry, QgsWkbTypes::PolygonGeometry}, context ) {}
5650
void fixError( QgsGeometryCheckError *error, int method, const QMap<QString, int> &mergeAttributeIndices, Changes &changes ) const override;
5751
QStringList resolutionMethods() const override;
5852
QString errorDescription() const override { return tr( "Self intersection" ); }
5953
QString errorName() const override { return QStringLiteral( "QgsGeometrySelfIntersectionCheck" ); }
54+
QList<QgsSingleGeometryCheckError *> processGeometry( const QgsGeometry &geometry, const QVariantMap &configuration ) const override;
6055

6156
enum ResolutionMethod { ToMultiObject, ToSingleObjects, NoChange };
6257
};

‎src/analysis/vector/geometry_checker/qgsgeometrytypecheck.cpp

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,19 +23,17 @@
2323
#include "qgsfeaturepool.h"
2424

2525

26-
void QgsGeometryTypeCheck::collectErrors( QList<QgsGeometryCheckError *> &errors, QStringList &/*messages*/, QAtomicInt *progressCounter, const QMap<QString, QgsFeatureIds> &ids ) const
26+
QList<QgsSingleGeometryCheckError *> QgsGeometryTypeCheck::processGeometry( const QgsGeometry &geometry, const QVariantMap &configuration ) const
2727
{
28-
QMap<QString, QgsFeatureIds> featureIds = ids.isEmpty() ? allLayerFeatureIds() : ids;
29-
QgsGeometryCheckerUtils::LayerFeatures layerFeatures( mContext->featurePools, featureIds, mCompatibleGeometryTypes, progressCounter, mContext );
30-
for ( const QgsGeometryCheckerUtils::LayerFeature &layerFeature : layerFeatures )
28+
Q_UNUSED( configuration )
29+
QList<QgsSingleGeometryCheckError *> errors;
30+
const QgsAbstractGeometry *geom = geometry.constGet();
31+
QgsWkbTypes::Type type = QgsWkbTypes::flatType( geom->wkbType() );
32+
if ( ( mAllowedTypes & ( 1 << type ) ) == 0 )
3133
{
32-
const QgsAbstractGeometry *geom = layerFeature.geometry().constGet();
33-
QgsWkbTypes::Type type = QgsWkbTypes::flatType( geom->wkbType() );
34-
if ( ( mAllowedTypes & ( 1 << type ) ) == 0 )
35-
{
36-
errors.append( new QgsGeometryTypeCheckError( this, layerFeature, geom->centroid(), type ) );
37-
}
34+
errors.append( new QgsGeometryTypeCheckError( this, geometry, geometry, type ) );
3835
}
36+
return errors;
3937
}
4038

4139
void QgsGeometryTypeCheck::fixError( QgsGeometryCheckError *error, int method, const QMap<QString, int> & /*mergeAttributeIndices*/, Changes &changes ) const
@@ -157,3 +155,14 @@ QStringList QgsGeometryTypeCheck::resolutionMethods() const
157155
<< tr( "No action" );
158156
return methods;
159157
}
158+
159+
bool QgsGeometryTypeCheckError::isEqual( const QgsSingleGeometryCheckError *other ) const
160+
{
161+
return QgsSingleGeometryCheckError::isEqual( other ) &&
162+
mFlatType == static_cast<const QgsGeometryTypeCheckError *>( other )->mFlatType;
163+
}
164+
165+
QString QgsGeometryTypeCheckError::description() const
166+
{
167+
return QStringLiteral( "%1 (%2)" ).arg( mCheck->errorDescription(), QgsWkbTypes::displayString( mFlatType ) );
168+
}

‎src/analysis/vector/geometry_checker/qgsgeometrytypecheck.h

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,40 +18,36 @@
1818
#ifndef QGS_GEOMETRY_TYPE_CHECK_H
1919
#define QGS_GEOMETRY_TYPE_CHECK_H
2020

21-
#include "qgsgeometrycheck.h"
21+
#include "qgssinglegeometrycheck.h"
2222

23-
class ANALYSIS_EXPORT QgsGeometryTypeCheckError : public QgsGeometryCheckError
23+
class ANALYSIS_EXPORT QgsGeometryTypeCheckError : public QgsSingleGeometryCheckError
2424
{
2525
public:
26-
QgsGeometryTypeCheckError( const QgsGeometryCheck *check,
27-
const QgsGeometryCheckerUtils::LayerFeature &layerFeature,
28-
const QgsPointXY &errorLocation,
26+
QgsGeometryTypeCheckError( const QgsSingleGeometryCheck *check,
27+
const QgsGeometry &geometry,
28+
const QgsGeometry &errorLocation,
2929
QgsWkbTypes::Type flatType )
30-
: QgsGeometryCheckError( check, layerFeature, errorLocation )
30+
: QgsSingleGeometryCheckError( check, geometry, errorLocation )
31+
, mFlatType( flatType )
3132
{
32-
mTypeName = QgsWkbTypes::displayString( flatType );
3333
}
3434

35-
bool isEqual( QgsGeometryCheckError *other ) const override
36-
{
37-
return QgsGeometryCheckError::isEqual( other ) &&
38-
mTypeName == static_cast<QgsGeometryTypeCheckError *>( other )->mTypeName;
39-
}
35+
bool isEqual( const QgsSingleGeometryCheckError *other ) const override;
4036

41-
QString description() const override { return QStringLiteral( "%1 (%2)" ).arg( mCheck->errorDescription(), mTypeName ); }
37+
QString description() const override;
4238

4339
private:
44-
QString mTypeName;
40+
QgsWkbTypes::Type mFlatType;
4541
};
4642

47-
class ANALYSIS_EXPORT QgsGeometryTypeCheck : public QgsGeometryCheck
43+
class ANALYSIS_EXPORT QgsGeometryTypeCheck : public QgsSingleGeometryCheck
4844
{
4945
public:
5046
QgsGeometryTypeCheck( QgsGeometryCheckerContext *context, int allowedTypes )
51-
: QgsGeometryCheck( FeatureCheck, {QgsWkbTypes::PointGeometry, QgsWkbTypes::LineGeometry, QgsWkbTypes::PolygonGeometry}, context )
47+
: QgsSingleGeometryCheck( FeatureCheck, {QgsWkbTypes::PointGeometry, QgsWkbTypes::LineGeometry, QgsWkbTypes::PolygonGeometry}, context )
5248
, mAllowedTypes( allowedTypes )
5349
{}
54-
void collectErrors( QList<QgsGeometryCheckError *> &errors, QStringList &messages, QAtomicInt *progressCounter = nullptr, const QMap<QString, QgsFeatureIds> &ids = QMap<QString, QgsFeatureIds>() ) const override;
50+
QList<QgsSingleGeometryCheckError *> processGeometry( const QgsGeometry &geometry, const QVariantMap &configuration ) const override;
5551
void fixError( QgsGeometryCheckError *error, int method, const QMap<QString, int> &mergeAttributeIndices, Changes &changes ) const override;
5652
QStringList resolutionMethods() const override;
5753
QString errorDescription() const override { return tr( "Geometry type" ); }
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
/***************************************************************************
2+
qgssinglegeometrycheck.cpp
3+
--------------------------------------
4+
Date : 6.9.2018
5+
Copyright : (C) 2018 by Matthias Kuhn
6+
email : matthias@opengis.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 "qgssinglegeometrycheck.h"
17+
#include "qgspoint.h"
18+
19+
QgsSingleGeometryCheck::QgsSingleGeometryCheck( CheckType checkType, const QList<QgsWkbTypes::GeometryType> &compatibleGeometryTypes, QgsGeometryCheckerContext *context )
20+
: QgsGeometryCheck( checkType, compatibleGeometryTypes, context )
21+
{
22+
23+
}
24+
25+
void QgsSingleGeometryCheck::collectErrors( QList<QgsGeometryCheckError *> &errors, QStringList &messages, QAtomicInt *progressCounter, const QMap<QString, QgsFeatureIds> &ids ) const
26+
{
27+
Q_UNUSED( messages )
28+
QMap<QString, QgsFeatureIds> featureIds = ids.isEmpty() ? allLayerFeatureIds() : ids;
29+
QgsGeometryCheckerUtils::LayerFeatures layerFeatures( mContext->featurePools, featureIds, mCompatibleGeometryTypes, progressCounter, mContext );
30+
for ( const QgsGeometryCheckerUtils::LayerFeature &layerFeature : layerFeatures )
31+
{
32+
const auto singleErrors = processGeometry( layerFeature.geometry(), QVariantMap() );
33+
for ( const auto error : singleErrors )
34+
errors.append( convertToGeometryCheckError( error, layerFeature ) );
35+
}
36+
}
37+
38+
QgsGeometryCheckErrorSingle *QgsSingleGeometryCheck::convertToGeometryCheckError( QgsSingleGeometryCheckError *singleGeometryCheckError, const QgsGeometryCheckerUtils::LayerFeature &layerFeature ) const
39+
{
40+
return new QgsGeometryCheckErrorSingle( singleGeometryCheckError, layerFeature );
41+
}
42+
43+
void QgsSingleGeometryCheckError::update( const QgsSingleGeometryCheckError *other )
44+
{
45+
Q_ASSERT( mCheck == other->mCheck );
46+
mErrorLocation = other->mErrorLocation;
47+
mVertexId = other->mVertexId;
48+
mGeometry = other->mGeometry;
49+
}
50+
51+
bool QgsSingleGeometryCheckError::isEqual( const QgsSingleGeometryCheckError *other ) const
52+
{
53+
return mGeometry == other->mGeometry
54+
&& mCheck == other->mCheck
55+
&& mErrorLocation == other->mErrorLocation
56+
&& mVertexId == other->mVertexId;
57+
}
58+
59+
bool QgsSingleGeometryCheckError::handleChanges( const QList<QgsGeometryCheck::Change> &changes )
60+
{
61+
Q_UNUSED( changes )
62+
return true;
63+
}
64+
65+
QString QgsSingleGeometryCheckError::description() const
66+
{
67+
return mCheck->errorDescription();
68+
}
69+
70+
const QgsSingleGeometryCheck *QgsSingleGeometryCheckError::check() const
71+
{
72+
return mCheck;
73+
}
74+
75+
QgsGeometry QgsSingleGeometryCheckError::errorLocation() const
76+
{
77+
return mErrorLocation;
78+
}
79+
80+
QgsVertexId QgsSingleGeometryCheckError::vertexId() const
81+
{
82+
return mVertexId;
83+
}
84+
85+
QgsGeometryCheckErrorSingle::QgsGeometryCheckErrorSingle( QgsSingleGeometryCheckError *error, const QgsGeometryCheckerUtils::LayerFeature &layerFeature )
86+
: QgsGeometryCheckError( error->check(), layerFeature, QgsPointXY( error->errorLocation().constGet()->centroid() ), error->vertexId() ) // TODO: should send geometry to QgsGeometryCheckError
87+
, mError( error )
88+
{
89+
90+
}
91+
92+
QgsSingleGeometryCheckError *QgsGeometryCheckErrorSingle::singleError() const
93+
{
94+
return mError;
95+
}
96+
97+
bool QgsGeometryCheckErrorSingle::handleChanges( const QgsGeometryCheck::Changes &changes )
98+
{
99+
if ( !QgsGeometryCheckError::handleChanges( changes ) )
100+
return false;
101+
102+
return mError->handleChanges( changes.value( layerId() ).value( featureId() ) );
103+
}
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
/***************************************************************************
2+
qgssinglegeometrycheck.h
3+
--------------------------------------
4+
Date : 6.9.2018
5+
Copyright : (C) 2018 by Matthias Kuhn
6+
email : matthias@opengis.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+
#ifndef QGSSINGLEGEOMETRYCHECK_H
17+
#define QGSSINGLEGEOMETRYCHECK_H
18+
19+
#define SIP_NO_FILE
20+
21+
#include <QList>
22+
#include <QCoreApplication>
23+
24+
#include "qgsgeometry.h"
25+
#include "qgsgeometrycheck.h"
26+
27+
#include "qgis_analysis.h"
28+
29+
class QgsFeature;
30+
class QgsSingleGeometryCheck;
31+
32+
/**
33+
* \ingroup analysis
34+
*
35+
* An error from a QgsSingleGeometryCheck.
36+
*
37+
* \since QGIS 3.4
38+
*/
39+
class ANALYSIS_EXPORT QgsSingleGeometryCheckError
40+
{
41+
public:
42+
QgsSingleGeometryCheckError( const QgsSingleGeometryCheck *check, const QgsGeometry &geometry, const QgsGeometry &errorLocation, const QgsVertexId &vertexId = QgsVertexId() )
43+
: mCheck( check )
44+
, mGeometry( geometry )
45+
, mErrorLocation( errorLocation )
46+
, mVertexId( vertexId )
47+
{}
48+
49+
virtual ~QgsSingleGeometryCheckError() = default;
50+
51+
/**
52+
* Update this error with the information from \other.
53+
* Will be used to update existing errors whenever they are re-checked.
54+
*/
55+
virtual void update( const QgsSingleGeometryCheckError *other );
56+
57+
/**
58+
* Check if this error is equal to \a other.
59+
* Is reimplemented by subclasses with additional information, comparison
60+
* of base information is done in parent class.
61+
*/
62+
virtual bool isEqual( const QgsSingleGeometryCheckError *other ) const;
63+
64+
/**
65+
* Apply a list of \a changes.
66+
*/
67+
virtual bool handleChanges( const QList<QgsGeometryCheck::Change> &changes );
68+
69+
/**
70+
* A human readable description of this error.
71+
*/
72+
virtual QString description() const;
73+
74+
/**
75+
* The check that created this error.
76+
*
77+
* \since QGIS 3.4
78+
*/
79+
const QgsSingleGeometryCheck *check() const;
80+
81+
/**
82+
* The exact location of the error.
83+
*
84+
* \since QGIS 3.4
85+
*/
86+
QgsGeometry errorLocation() const;
87+
88+
/**
89+
* The vertex id of the error. May be invalid depending on the check.
90+
*
91+
* \since QGIS 3.4
92+
*/
93+
QgsVertexId vertexId() const;
94+
95+
protected:
96+
const QgsSingleGeometryCheck *mCheck = nullptr;
97+
QgsGeometry mGeometry;
98+
QgsGeometry mErrorLocation;
99+
QgsVertexId mVertexId;
100+
};
101+
102+
/**
103+
* \ingroup analysis
104+
*
105+
* Wraps a QgsSingleGeometryError into a standard QgsGeometryCheckError.
106+
* The single error can be obtained via singleError.
107+
*
108+
* \since QGIS 3.4
109+
*/
110+
class ANALYSIS_EXPORT QgsGeometryCheckErrorSingle : public QgsGeometryCheckError
111+
{
112+
public:
113+
QgsGeometryCheckErrorSingle( QgsSingleGeometryCheckError *singleError, const QgsGeometryCheckerUtils::LayerFeature &layerFeature );
114+
115+
/**
116+
* The underlying single error.
117+
*/
118+
QgsSingleGeometryCheckError *singleError() const;
119+
120+
bool handleChanges( const QgsGeometryCheck::Changes &changes ) override;
121+
122+
private:
123+
QgsSingleGeometryCheckError *mError = nullptr;
124+
};
125+
126+
/**
127+
* \ingroup analysis
128+
*
129+
* Base class for geometry checks for a single geometry without any context of the layer or other layers in the project.
130+
* Classic examples are validity checks like self-intersection.
131+
*
132+
* Subclasses need to implement the processGeometry method.
133+
*
134+
* \since QGIS 3.4
135+
*/
136+
class ANALYSIS_EXPORT QgsSingleGeometryCheck : public QgsGeometryCheck
137+
{
138+
public:
139+
QgsSingleGeometryCheck( CheckType checkType, const QList<QgsWkbTypes::GeometryType> &compatibleGeometryTypes, QgsGeometryCheckerContext *context );
140+
141+
void collectErrors( QList<QgsGeometryCheckError *> &errors, QStringList &messages, QAtomicInt *progressCounter = nullptr, const QMap<QString, QgsFeatureIds> &ids = QMap<QString, QgsFeatureIds>() ) const final;
142+
143+
/**
144+
* Check the \a geometry for errors. It may make use of \a configuration options.
145+
*
146+
* Returns a list of QgsSingleGeometryCheckErrors, ownership is transferred to the caller.
147+
* An empty list is returned for geometries without errors.
148+
*
149+
* \since QGIS 3.4
150+
*/
151+
virtual QList<QgsSingleGeometryCheckError *> processGeometry( const QgsGeometry &geometry, const QVariantMap &configuration ) const = 0;
152+
153+
private:
154+
155+
/**
156+
* Converts a QgsSingleGeometryCheckError to a QgsGeometryCheckErrorSingle.
157+
*
158+
* \since QGIS 3.4
159+
*/
160+
QgsGeometryCheckErrorSingle *convertToGeometryCheckError( QgsSingleGeometryCheckError *singleGeometryCheckError, const QgsGeometryCheckerUtils::LayerFeature &layerFeature ) const;
161+
162+
};
163+
164+
#endif // QGSSINGLEGEOMETRYCHECK_H

‎tests/src/geometry_checker/testqgsgeometrychecks.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -916,14 +916,14 @@ void TestQgsGeometryChecks::testSelfIntersectionCheck()
916916
QCOMPARE( f.geometry().constGet()->vertexCount( 1, 1 ), 5 );
917917

918918
// Test change tracking
919-
QgsGeometrySelfIntersectionCheckError *err = static_cast<QgsGeometrySelfIntersectionCheckError *>( errs4[0] );
920-
QgsGeometryUtils::SelfIntersection oldInter = err->intersection();
921-
QVERIFY( err->handleChanges( change2changes( {err->layerId(), err->featureId(), QgsGeometryCheck::ChangeNode, QgsGeometryCheck::ChangeRemoved, QgsVertexId( errs4[0]->vidx().part, errs4[0]->vidx().ring, 0 )} ) ) );
922-
QgsGeometryUtils::SelfIntersection newInter = err->intersection();
919+
QgsGeometryCheckErrorSingle *err = static_cast<QgsGeometryCheckErrorSingle *>( errs4[0] );
920+
QgsGeometryUtils::SelfIntersection oldInter = static_cast<QgsGeometrySelfIntersectionCheckError *>( err->singleError() )->intersection();
921+
QVERIFY( err->handleChanges( change2changes( {err->layerId(), err->featureId(), QgsGeometryCheck::ChangeNode, QgsGeometryCheck::ChangeRemoved, QgsVertexId( err->vidx().part, errs4[0]->vidx().ring, 0 )} ) ) );
922+
QgsGeometryUtils::SelfIntersection newInter = static_cast<QgsGeometrySelfIntersectionCheckError *>( err->singleError() )->intersection();
923923
QVERIFY( oldInter.segment1 == newInter.segment1 + 1 );
924924
QVERIFY( oldInter.segment2 == newInter.segment2 + 1 );
925-
QVERIFY( err->handleChanges( change2changes( {err->layerId(), err->featureId(), QgsGeometryCheck::ChangeNode, QgsGeometryCheck::ChangeAdded, QgsVertexId( errs4[0]->vidx().part, errs4[0]->vidx().ring, 0 )} ) ) );
926-
newInter = err->intersection();
925+
QVERIFY( err->handleChanges( change2changes( {err->layerId(), errs4[0]->featureId(), QgsGeometryCheck::ChangeNode, QgsGeometryCheck::ChangeAdded, QgsVertexId( err->vidx().part, errs4[0]->vidx().ring, 0 )} ) ) );
926+
newInter = static_cast<QgsGeometrySelfIntersectionCheckError *>( err->singleError() )->intersection();
927927
QVERIFY( oldInter.segment1 == newInter.segment1 );
928928
QVERIFY( oldInter.segment2 == newInter.segment2 );
929929

0 commit comments

Comments
 (0)
Please sign in to comment.