Branch data Line data Source code
1 : : /***************************************************************************
2 : : * qgsgeometrycheckerutils.h *
3 : : * ------------------- *
4 : : * copyright : (C) 2014 by Sandro Mani / Sourcepole AG *
5 : : * email : smani@sourcepole.ch *
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 : :
17 : : #ifndef QGS_GEOMETRYCHECKERUTILS_H
18 : : #define QGS_GEOMETRYCHECKERUTILS_H
19 : :
20 : : #include "qgis_analysis.h"
21 : : #include "qgsfeature.h"
22 : : #include "geometry/qgsabstractgeometry.h"
23 : : #include "geometry/qgspoint.h"
24 : : #include "qgsgeometrycheckcontext.h"
25 : : #include <qmath.h>
26 : :
27 : : class QgsGeometryEngine;
28 : : class QgsFeaturePool;
29 : : class QgsFeedback;
30 : :
31 : : /**
32 : : * \ingroup analysis
33 : : *
34 : : * \brief Contains utilities required for geometry checks.
35 : : *
36 : : * \note This class is a technology preview and unstable API.
37 : : * \since QGIS 3.4
38 : : */
39 : : class ANALYSIS_EXPORT QgsGeometryCheckerUtils
40 : : {
41 : : public:
42 : :
43 : : /**
44 : : * \ingroup analysis
45 : : *
46 : : * \brief A layer feature combination to uniquely identify and access a feature in
47 : : * a set of layers.
48 : : *
49 : : * \since QGIS 3.4
50 : : */
51 : 1082 : class ANALYSIS_EXPORT LayerFeature
52 : : {
53 : : public:
54 : :
55 : : /**
56 : : * Create a new layer/feature combination.
57 : : * The layer is defined by \a pool, \a feature needs to be from this layer.
58 : : * If \a useMapCrs is TRUE, geometries will be reprojected to the mapCrs defined
59 : : * in \a context.
60 : : */
61 : : LayerFeature( const QgsFeaturePool *pool, const QgsFeature &feature, const QgsGeometryCheckContext *context, bool useMapCrs );
62 : :
63 : : /**
64 : : * Returns the feature.
65 : : * The geometry will not be reprojected regardless of useMapCrs.
66 : : */
67 : : QgsFeature feature() const;
68 : :
69 : : /**
70 : : * The layer.
71 : : */
72 : : QPointer<QgsVectorLayer> layer() const SIP_SKIP;
73 : :
74 : : /**
75 : : * The layer id.
76 : : */
77 : : QString layerId() const;
78 : :
79 : : /**
80 : : * Returns the geometry of this feature.
81 : : * If useMapCrs was specified, it will already be reprojected into the
82 : : * CRS specified in the context specified in the constructor.
83 : : */
84 : : QgsGeometry geometry() const;
85 : :
86 : : /**
87 : : * Returns a combination of the layerId and the feature id.
88 : : */
89 : : QString id() const;
90 : : bool operator==( const QgsGeometryCheckerUtils::LayerFeature &other ) const;
91 : : bool operator!=( const QgsGeometryCheckerUtils::LayerFeature &other ) const;
92 : :
93 : : /**
94 : : * Returns if the geometry is reprojected to the map CRS or not.
95 : : */
96 : : bool useMapCrs() const;
97 : :
98 : : private:
99 : : const QgsFeaturePool *mFeaturePool;
100 : : QgsFeature mFeature;
101 : : QgsGeometry mGeometry;
102 : : bool mMapCrs;
103 : : };
104 : :
105 : : /**
106 : : * \ingroup analysis
107 : : *
108 : : * \brief Contains a set of layers and feature ids in those layers to pass to a geometry check.
109 : : *
110 : : * \since QGIS 3.4
111 : : */
112 : 216 : class ANALYSIS_EXPORT LayerFeatures
113 : : {
114 : : public:
115 : : #ifndef SIP_RUN
116 : :
117 : : /**
118 : : * Creates a new set of layer and features.
119 : : */
120 : : LayerFeatures( const QMap<QString, QgsFeaturePool *> &featurePools,
121 : : const QMap<QString, QgsFeatureIds> &featureIds,
122 : : const QList<QgsWkbTypes::GeometryType> &geometryTypes,
123 : : QgsFeedback *feedback,
124 : : const QgsGeometryCheckContext *context,
125 : : bool useMapCrs = false );
126 : :
127 : : /**
128 : : * Creates a new set of layer and features.
129 : : */
130 : : LayerFeatures( const QMap<QString, QgsFeaturePool *> &featurePools,
131 : : const QList<QString> &layerIds, const QgsRectangle &extent,
132 : : const QList<QgsWkbTypes::GeometryType> &geometryTypes,
133 : : const QgsGeometryCheckContext *context );
134 : :
135 : : /**
136 : : * \ingroup analysis
137 : : *
138 : : * \brief An iterator over all features in a QgsGeometryCheckerUtils::LayerFeatures.
139 : : *
140 : : * \since QGIS 3.4
141 : : */
142 : : class iterator
143 : : {
144 : : public:
145 : :
146 : : /**
147 : : * Creates a new iterator.
148 : : */
149 : : iterator( const QStringList::const_iterator &layerIt, const LayerFeatures *parent );
150 : :
151 : : /**
152 : : * Copies the iterator \a rh.
153 : : */
154 : : iterator( const iterator &rh );
155 : : ~iterator();
156 : :
157 : : /**
158 : : * Increments the item the iterator currently points to by one and
159 : : * returns the new iterator.
160 : : */
161 : : const iterator &operator++();
162 : :
163 : : /**
164 : : * Increments the item the iterator currently points to by \a n and
165 : : * returns the new iterator.
166 : : */
167 : : iterator operator++( int n );
168 : :
169 : : /**
170 : : * Dereferences the item at the current iterator location.
171 : : */
172 : : const QgsGeometryCheckerUtils::LayerFeature &operator*() const;
173 : : bool operator!=( const iterator &other );
174 : :
175 : : private:
176 : : bool nextLayerFeature( bool begin );
177 : : bool nextLayer( bool begin );
178 : : bool nextFeature( bool begin );
179 : : QList<QString>::const_iterator mLayerIt;
180 : : QgsFeatureIds::const_iterator mFeatureIt;
181 : : const LayerFeatures *mParent = nullptr;
182 : : std::unique_ptr<QgsGeometryCheckerUtils::LayerFeature> mCurrentFeature;
183 : :
184 : : iterator &operator= ( const iterator & ) = delete;
185 : : };
186 : :
187 : : /**
188 : : * The first feature to start iterating.
189 : : */
190 : : iterator begin() const;
191 : :
192 : : /**
193 : : * One after the last feature to stop iterating.
194 : : */
195 : : iterator end() const;
196 : :
197 : : #endif
198 : :
199 : : private:
200 : : #ifdef SIP_RUN
201 : : LayerFeatures();
202 : : #endif
203 : : QMap<QString, QgsFeaturePool *> mFeaturePools;
204 : : QMap<QString, QgsFeatureIds> mFeatureIds;
205 : : QList<QString> mLayerIds;
206 : : QgsRectangle mExtent;
207 : : QList<QgsWkbTypes::GeometryType> mGeometryTypes;
208 : : QgsFeedback *mFeedback = nullptr;
209 : : const QgsGeometryCheckContext *mContext = nullptr;
210 : : bool mUseMapCrs = true;
211 : : };
212 : :
213 : : #ifndef SIP_RUN
214 : :
215 : : static std::unique_ptr<QgsGeometryEngine> createGeomEngine( const QgsAbstractGeometry *geometry, double tolerance );
216 : :
217 : : static QgsAbstractGeometry *getGeomPart( QgsAbstractGeometry *geom, int partIdx );
218 : : static const QgsAbstractGeometry *getGeomPart( const QgsAbstractGeometry *geom, int partIdx );
219 : :
220 : : static QList <const QgsLineString *> polygonRings( const QgsPolygon *polygon );
221 : :
222 : : static void filter1DTypes( QgsAbstractGeometry *geom );
223 : :
224 : : /**
225 : : * Returns the number of points in a polyline, accounting for duplicate start and end point if the polyline is closed
226 : : * \returns The number of distinct points of the polyline
227 : : */
228 : 146 : static inline int polyLineSize( const QgsAbstractGeometry *geom, int iPart, int iRing, bool *isClosed = nullptr )
229 : : {
230 : 146 : if ( !geom->isEmpty() )
231 : : {
232 : 146 : int nVerts = geom->vertexCount( iPart, iRing );
233 : 146 : QgsPoint front = geom->vertexAt( QgsVertexId( iPart, iRing, 0 ) );
234 : 146 : QgsPoint back = geom->vertexAt( QgsVertexId( iPart, iRing, nVerts - 1 ) );
235 : 146 : bool closed = back == front;
236 : 146 : if ( isClosed )
237 : 78 : *isClosed = closed;
238 : 146 : return closed ? nVerts - 1 : nVerts;
239 : 146 : }
240 : : else
241 : : {
242 : 0 : if ( isClosed )
243 : 0 : *isClosed = true;
244 : 0 : return 0;
245 : : }
246 : 146 : }
247 : :
248 : : static bool pointOnLine( const QgsPoint &p, const QgsLineString *line, double tol, bool excludeExtremities = false );
249 : :
250 : : static QList<QgsPoint> lineIntersections( const QgsLineString *line1, const QgsLineString *line2, double tol );
251 : :
252 : : static double sharedEdgeLength( const QgsAbstractGeometry *geom1, const QgsAbstractGeometry *geom2, double tol );
253 : :
254 : : /**
255 : : * \brief Determine whether two points are equal up to the specified tolerance
256 : : * \param p1 The first point
257 : : * \param p2 The second point
258 : : * \param tol The tolerance
259 : : * \returns Whether the points are equal
260 : : */
261 : 2 : static inline bool pointsFuzzyEqual( const QgsPointXY &p1, const QgsPointXY &p2, double tol )
262 : : {
263 : 2 : double dx = p1.x() - p2.x(), dy = p1.y() - p2.y();
264 : 2 : return ( dx * dx + dy * dy ) < tol * tol;
265 : : }
266 : :
267 : 3 : static inline bool canDeleteVertex( const QgsAbstractGeometry *geom, int iPart, int iRing )
268 : : {
269 : 3 : int nVerts = geom->vertexCount( iPart, iRing );
270 : 3 : QgsPoint front = geom->vertexAt( QgsVertexId( iPart, iRing, 0 ) );
271 : 3 : QgsPoint back = geom->vertexAt( QgsVertexId( iPart, iRing, nVerts - 1 ) );
272 : 3 : bool closed = back == front;
273 : 3 : return closed ? nVerts > 4 : nVerts > 2;
274 : 3 : }
275 : :
276 : : #endif
277 : :
278 : : }; // QgsGeometryCheckerUtils
279 : :
280 : : #endif // QGS_GEOMETRYCHECKERUTILS_H
|