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" ); }

0 commit comments

Comments
 (0)
Please sign in to comment.