QGIS API Documentation 3.99.0-Master (2fe06baccd8)
Loading...
Searching...
No Matches
qgsgeometrycheckerutils.cpp
Go to the documentation of this file.
1/***************************************************************************
2 * qgsgeometrycheckerutils.cpp *
3 * ------------------- *
4 * copyright : (C) 2014 by Sandro Mani / Sourcepole AG *
5 * email : [email protected] *
6 ***************************************************************************/
7
8/***************************************************************************
9 * *
10 * This program is free software; you can redistribute it and/or modify *
11 * it under the terms of the GNU General Public License as published by *
12 * the Free Software Foundation; either version 2 of the License, or *
13 * (at your option) any later version. *
14 * *
15 ***************************************************************************/
16
18
19#include "qgsfeaturepool.h"
20#include "qgsfeedback.h"
21#include "qgsgeometry.h"
22#include "qgsgeometrycheck.h"
25#include "qgsgeometryutils.h"
26#include "qgsgeos.h"
27#include "qgspolygon.h"
28#include "qgssurface.h"
29#include "qgsvectorlayer.h"
30
31#include <qmath.h>
32
34 : mFeaturePool( pool )
35 , mFeature( feature )
36 , mGeometry( feature.geometry() )
37 , mMapCrs( useMapCrs )
38{
39 const QgsCoordinateTransform transform( pool->crs(), context->mapCrs, context->transformContext );
40 if ( useMapCrs && context->mapCrs.isValid() && !transform.isShortCircuited() )
41 {
42 try
43 {
44 mGeometry.transform( transform );
45 }
46 catch ( const QgsCsException & )
47 {
48 QgsDebugError( QStringLiteral( "Shrug. What shall we do with a geometry that cannot be converted?" ) );
49 }
50 }
51}
52
57
62
63QPointer<QgsVectorLayer> QgsGeometryCheckerUtils::LayerFeature::layer() const
64{
65 return mFeaturePool->layerPtr();
66}
67
69{
70 return mFeaturePool->layerId();
71}
72
77
79{
80 return QStringLiteral( "%1:%2" ).arg( mFeaturePool->layerName() ).arg( mFeature.id() );
81}
82
84{
85 return layerId() == other.layerId() && mFeature.id() == other.mFeature.id();
86}
87
89{
90 return layerId() != other.layerId() || mFeature.id() != other.mFeature.id();
91}
92
94
95QgsGeometryCheckerUtils::LayerFeatures::iterator::iterator( const QStringList::const_iterator &layerIt, const LayerFeatures *parent )
96 : mLayerIt( layerIt )
97 , mFeatureIt( QgsFeatureIds::const_iterator() )
98 , mParent( parent )
99{
100 nextLayerFeature( true );
101}
102
104 : mLayerIt( rh.mLayerIt )
105 , mFeatureIt( rh.mFeatureIt )
106 , mParent( rh.mParent )
107 , mCurrentFeature( std::make_unique<LayerFeature>( *rh.mCurrentFeature.get() ) )
108{
109}
110
112{
113 return mMapCrs;
114}
118
125
127{
128 Q_ASSERT( mCurrentFeature );
129 return *mCurrentFeature;
130}
131
133{
134 return mLayerIt != other.mLayerIt || mFeatureIt != other.mFeatureIt;
135}
136
142bool QgsGeometryCheckerUtils::LayerFeatures::iterator::nextLayerFeature( bool begin )
143{
144 if ( !begin && nextFeature( false ) )
145 {
146 return true;
147 }
148 while ( nextLayer( begin ) )
149 {
150 begin = false;
151 if ( nextFeature( true ) )
152 {
153 return true;
154 }
155 }
156 // End
157 mFeatureIt = QgsFeatureIds::const_iterator();
158 mCurrentFeature.reset();
159 return false;
160}
161
162bool QgsGeometryCheckerUtils::LayerFeatures::iterator::nextLayer( bool begin )
163{
164 if ( !begin )
165 {
166 ++mLayerIt;
167 }
168 while ( true )
169 {
170 if ( mLayerIt == mParent->mLayerIds.end() )
171 {
172 break;
173 }
174 if ( mParent->mGeometryTypes.contains( mParent->mFeaturePools[*mLayerIt]->geometryType() ) )
175 {
176 mFeatureIt = mParent->mFeatureIds[*mLayerIt].constBegin();
177 return true;
178 }
179 ++mLayerIt;
180 }
181 return false;
182}
183
184bool QgsGeometryCheckerUtils::LayerFeatures::iterator::nextFeature( bool begin )
185{
186 QgsFeaturePool *featurePool = mParent->mFeaturePools[*mLayerIt];
187 const QgsFeatureIds &featureIds = mParent->mFeatureIds[*mLayerIt];
188 if ( !begin )
189 {
190 ++mFeatureIt;
191 }
192 while ( true )
193 {
194 if ( mFeatureIt == featureIds.end() )
195 {
196 break;
197 }
198 if ( mParent->mFeedback )
199 mParent->mFeedback->setProgress( mParent->mFeedback->progress() + 1.0 );
200 QgsFeature feature;
201 if ( featurePool->getFeature( *mFeatureIt, feature ) && !feature.geometry().isNull() )
202 {
203 mCurrentFeature = std::make_unique<LayerFeature>( featurePool, feature, mParent->mContext, mParent->mUseMapCrs );
204 return true;
205 }
206 ++mFeatureIt;
207 }
208 return false;
209}
210
212
213QgsGeometryCheckerUtils::LayerFeatures::LayerFeatures( const QMap<QString, QgsFeaturePool *> &featurePools, const QMap<QString, QgsFeatureIds> &featureIds, const QList<Qgis::GeometryType> &geometryTypes, QgsFeedback *feedback, const QgsGeometryCheckContext *context, bool useMapCrs )
214 : mFeaturePools( featurePools )
215 , mFeatureIds( featureIds )
216 , mLayerIds( featurePools.keys() )
217 , mGeometryTypes( geometryTypes )
218 , mFeedback( feedback )
219 , mContext( context )
220 , mUseMapCrs( useMapCrs )
221{}
222
223QgsGeometryCheckerUtils::LayerFeatures::LayerFeatures( const QMap<QString, QgsFeaturePool *> &featurePools, const QList<QString> &layerIds, const QgsRectangle &extent, const QList<Qgis::GeometryType> &geometryTypes, const QgsGeometryCheckContext *context )
224 : mFeaturePools( featurePools )
225 , mLayerIds( layerIds )
226 , mExtent( extent )
227 , mGeometryTypes( geometryTypes )
228 , mContext( context )
229{
230 for ( const QString &layerId : layerIds )
231 {
232 const QgsFeaturePool *featurePool = featurePools[layerId];
233 if ( geometryTypes.contains( featurePool->geometryType() ) )
234 {
235 const QgsCoordinateTransform ct( featurePool->crs(), context->mapCrs, context->transformContext );
236 mFeatureIds.insert( layerId, featurePool->getIntersects( ct.transform( extent, Qgis::TransformDirection::Reverse ) ) );
237 }
238 else
239 {
240 mFeatureIds.insert( layerId, QgsFeatureIds() );
241 }
242 }
243}
244
249
254
256
258{
260 {
261 return collection->geometryN( partIdx );
262 }
263 return geom;
264}
265
267{
269 {
270 return collection->geometryN( partIdx );
271 }
272 return geom;
273}
274
275QList<const QgsLineString *> QgsGeometryCheckerUtils::polygonRings( const QgsPolygon *polygon )
276{
277 QList<const QgsLineString *> rings;
278 if ( const QgsLineString *exterior = qgsgeometry_cast<const QgsLineString *>( polygon->exteriorRing() ) )
279 {
280 rings.append( exterior );
281 }
282 for ( int iInt = 0, nInt = polygon->numInteriorRings(); iInt < nInt; ++iInt )
283 {
284 if ( const QgsLineString *interior = qgsgeometry_cast<const QgsLineString *>( polygon->interiorRing( iInt ) ) )
285 {
286 rings.append( interior );
287 }
288 }
289 return rings;
290}
291
293{
295 {
296 for ( int nParts = geom->partCount(), iPart = nParts - 1; iPart >= 0; --iPart )
297 {
298 if ( !qgsgeometry_cast<QgsSurface *>( geomCollection->geometryN( iPart ) ) )
299 {
300 geomCollection->removeGeometry( iPart );
301 }
302 }
303 }
304}
305
306double pointLineDist( const QgsPoint &p1, const QgsPoint &p2, const QgsPoint &q )
307{
308 const double nom = std::fabs( ( p2.y() - p1.y() ) * q.x() - ( p2.x() - p1.x() ) * q.y() + p2.x() * p1.y() - p2.y() * p1.x() );
309 const double dx = p2.x() - p1.x();
310 const double dy = p2.y() - p1.y();
311 return nom / std::sqrt( dx * dx + dy * dy );
312}
313
314bool QgsGeometryCheckerUtils::pointOnLine( const QgsPoint &p, const QgsLineString *line, double tol, bool excludeExtremities )
315{
316 const int nVerts = line->vertexCount();
317 for ( int i = 0 + excludeExtremities; i < nVerts - 1 - excludeExtremities; ++i )
318 {
319 const QgsPoint p1 = line->vertexAt( QgsVertexId( 0, 0, i ) );
320 const QgsPoint p2 = line->vertexAt( QgsVertexId( 0, 0, i + 1 ) );
321 const double dist = pointLineDist( p1, p2, p );
322 if ( dist < tol )
323 {
324 return true;
325 }
326 }
327 return false;
328}
329
330QList<QgsPoint> QgsGeometryCheckerUtils::lineIntersections( const QgsLineString *line1, const QgsLineString *line2, double tol )
331{
332 QList<QgsPoint> intersections;
333 QgsPoint inter;
334 bool intersection = false;
335 for ( int i = 0, n = line1->vertexCount() - 1; i < n; ++i )
336 {
337 for ( int j = 0, m = line2->vertexCount() - 1; j < m; ++j )
338 {
339 const QgsPoint p1 = line1->vertexAt( QgsVertexId( 0, 0, i ) );
340 const QgsPoint p2 = line1->vertexAt( QgsVertexId( 0, 0, i + 1 ) );
341 const QgsPoint q1 = line2->vertexAt( QgsVertexId( 0, 0, j ) );
342 const QgsPoint q2 = line2->vertexAt( QgsVertexId( 0, 0, j + 1 ) );
343 if ( QgsGeometryUtils::segmentIntersection( p1, p2, q1, q2, inter, intersection, tol ) )
344 {
345 intersections.append( inter );
346 }
347 }
348 }
349 return intersections;
350}
351
353{
354 double len = 0;
355
356 // Test every pair of segments for shared edges
357 for ( int iPart1 = 0, nParts1 = geom1->partCount(); iPart1 < nParts1; ++iPart1 )
358 {
359 for ( int iRing1 = 0, nRings1 = geom1->ringCount( iPart1 ); iRing1 < nRings1; ++iRing1 )
360 {
361 for ( int iVert1 = 0, jVert1 = 1, nVerts1 = geom1->vertexCount( iPart1, iRing1 ); jVert1 < nVerts1; iVert1 = jVert1++ )
362 {
363 const QgsPoint p1 = geom1->vertexAt( QgsVertexId( iPart1, iRing1, iVert1 ) );
364 const QgsPoint p2 = geom1->vertexAt( QgsVertexId( iPart1, iRing1, jVert1 ) );
365 const double lambdap1 = 0.;
366 const double lambdap2 = std::sqrt( QgsGeometryUtils::sqrDistance2D( p1, p2 ) );
367 QgsVector d;
368 try
369 {
370 d = QgsVector( p2.x() - p1.x(), p2.y() - p1.y() ).normalized();
371 }
372 catch ( const QgsException & )
373 {
374 // Edge has zero length, skip
375 continue;
376 }
377
378 for ( int iPart2 = 0, nParts2 = geom2->partCount(); iPart2 < nParts2; ++iPart2 )
379 {
380 for ( int iRing2 = 0, nRings2 = geom2->ringCount( iPart2 ); iRing2 < nRings2; ++iRing2 )
381 {
382 for ( int iVert2 = 0, jVert2 = 1, nVerts2 = geom2->vertexCount( iPart2, iRing2 ); jVert2 < nVerts2; iVert2 = jVert2++ )
383 {
384 const QgsPoint q1 = geom2->vertexAt( QgsVertexId( iPart2, iRing2, iVert2 ) );
385 const QgsPoint q2 = geom2->vertexAt( QgsVertexId( iPart2, iRing2, jVert2 ) );
386
387 // Check whether q1 and q2 are on the line p1, p
388 if ( pointLineDist( p1, p2, q1 ) <= tol && pointLineDist( p1, p2, q2 ) <= tol )
389 {
390 // Get length common edge
391 double lambdaq1 = QgsVector( q1.x() - p1.x(), q1.y() - p1.y() ) * d;
392 double lambdaq2 = QgsVector( q2.x() - p1.x(), q2.y() - p1.y() ) * d;
393 if ( lambdaq1 > lambdaq2 )
394 {
395 std::swap( lambdaq1, lambdaq2 );
396 }
397 const double lambda1 = std::max( lambdaq1, lambdap1 );
398 const double lambda2 = std::min( lambdaq2, lambdap2 );
399 len += std::max( 0., lambda2 - lambda1 );
400 }
401 }
402 }
403 }
404 }
405 }
406 }
407 return len;
408}
@ Reverse
Reverse/inverse transform (from destination to source).
Definition qgis.h:2673
Abstract base class for all geometries.
virtual int ringCount(int part=0) const =0
Returns the number of rings of which this geometry is built.
virtual int vertexCount(int part=0, int ring=0) const =0
Returns the number of vertices of which this geometry is built.
virtual QgsPoint vertexAt(QgsVertexId id) const =0
Returns the point corresponding to a specified vertex id.
virtual int partCount() const =0
Returns count of parts contained in the geometry.
Represents a coordinate reference system (CRS).
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
Handles coordinate transforms between two coordinate systems.
QgsPointXY transform(const QgsPointXY &point, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward) const
Transform the point from the source CRS to the destination CRS.
bool isShortCircuited() const
Returns true if the transform short circuits because the source and destination are equivalent.
Custom exception class for Coordinate Reference System related exceptions.
int numInteriorRings() const
Returns the number of interior rings contained with the curve polygon.
const QgsCurve * exteriorRing() const
Returns the curve polygon's exterior ring.
const QgsCurve * interiorRing(int i) const
Retrieves an interior ring from the curve polygon.
int vertexCount(int part=0, int ring=0) const override
Returns the number of vertices of which this geometry is built.
Definition qgscurve.cpp:181
QgsPoint vertexAt(QgsVertexId id) const override
Returns the point corresponding to a specified vertex id.
Definition qgscurve.cpp:199
Defines a QGIS exception class.
A feature pool is based on a vector layer and caches features.
Qgis::GeometryType geometryType() const
The geometry type of this layer.
QgsCoordinateReferenceSystem crs() const
The coordinate reference system of this layer.
QgsFeatureIds getIntersects(const QgsRectangle &rect) const
Gets all feature ids in the bounding box rect.
bool getFeature(QgsFeatureId id, QgsFeature &feature)
Retrieves the feature with the specified id into feature.
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
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.
const QgsCoordinateTransformContext transformContext
The coordinate transform context with which transformations will be done.
const QgsCoordinateReferenceSystem mapCrs
The coordinate system in which calculations should be done.
A layer feature combination to uniquely identify and access a feature in a set of layers.
LayerFeature(const QgsFeaturePool *pool, const QgsFeature &feature, const QgsGeometryCheckContext *context, bool useMapCrs)
Create a new layer/feature combination.
QgsGeometry geometry() const
Returns the geometry of this feature.
QString id() const
Returns a combination of the layerId and the feature id.
bool operator==(const QgsGeometryCheckerUtils::LayerFeature &other) const
QgsFeature feature() const
Returns the feature.
QPointer< QgsVectorLayer > layer() const
The layer.
bool operator!=(const QgsGeometryCheckerUtils::LayerFeature &other) const
bool useMapCrs() const
Returns if the geometry is reprojected to the map CRS or not.
QgsCoordinateReferenceSystem layerCrs() const
The layer CRS.
An iterator over all features in a QgsGeometryCheckerUtils::LayerFeatures.
const iterator & operator++()
Increments the item the iterator currently points to by one and returns the new iterator.
const QgsGeometryCheckerUtils::LayerFeature & operator*() const
Dereferences the item at the current iterator location.
iterator(const QStringList::const_iterator &layerIt, const LayerFeatures *parent)
Creates a new iterator.
iterator end() const
One after the last feature to stop iterating.
LayerFeatures(const QMap< QString, QgsFeaturePool * > &featurePools, const QMap< QString, QgsFeatureIds > &featureIds, const QList< Qgis::GeometryType > &geometryTypes, QgsFeedback *feedback, const QgsGeometryCheckContext *context, bool useMapCrs=false)
Creates a new set of layer and features.
iterator begin() const
The first feature to start iterating.
static void filter1DTypes(QgsAbstractGeometry *geom)
static QList< const QgsLineString * > polygonRings(const QgsPolygon *polygon)
static QgsAbstractGeometry * getGeomPart(QgsAbstractGeometry *geom, int partIdx)
static double sharedEdgeLength(const QgsAbstractGeometry *geom1, const QgsAbstractGeometry *geom2, double tol)
static QList< QgsPoint > lineIntersections(const QgsLineString *line1, const QgsLineString *line2, double tol)
static bool pointOnLine(const QgsPoint &p, const QgsLineString *line, double tol, bool excludeExtremities=false)
static bool segmentIntersection(const QgsPoint &p1, const QgsPoint &p2, const QgsPoint &q1, const QgsPoint &q2, QgsPoint &intersectionPoint, bool &isIntersection, double tolerance=1e-8, bool acceptImproperIntersection=false)
Compute the intersection between two segments.
static Q_DECL_DEPRECATED double sqrDistance2D(double x1, double y1, double x2, double y2)
Returns the squared 2D distance between (x1, y1) and (x2, y2).
A geometry is the spatial representation of a feature.
Line string geometry type, with support for z-dimension and m-values.
Point geometry type, with support for z-dimension and m-values.
Definition qgspoint.h:49
double x
Definition qgspoint.h:52
double y
Definition qgspoint.h:53
Polygon geometry type.
Definition qgspolygon.h:33
A rectangle specified with double values.
Represent a 2-dimensional vector.
Definition qgsvector.h:31
QgsVector normalized() const
Returns the vector's normalized (or "unit") vector (ie same angle but length of 1....
Definition qgsvector.cpp:29
T qgsgeometry_cast(QgsAbstractGeometry *geom)
QSet< QgsFeatureId > QgsFeatureIds
double pointLineDist(const QgsPoint &p1, const QgsPoint &p2, const QgsPoint &q)
#define QgsDebugError(str)
Definition qgslogger.h:57
Utility class for identifying a unique vertex within a geometry.
Definition qgsvertexid.h:30