QGIS API Documentation 3.34.0-Prizren (ffbdd678812)
Loading...
Searching...
No Matches
qgspointlocator.h
Go to the documentation of this file.
1/***************************************************************************
2 qgspointlocator.h
3 --------------------------------------
4 Date : November 2014
5 Copyright : (C) 2014 by Martin Dobias
6 Email : wonder dot sk at gmail dot com
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 QGSPOINTLOCATOR_H
17#define QGSPOINTLOCATOR_H
18
19class QgsPointXY;
22class QgsRectangle;
24
25#include "qgis_core.h"
26#include "qgspointxy.h"
29#include "qgsfeatureid.h"
30#include "qgsgeometry.h"
31#include "qgsgeometryutils.h"
32#include "qgsvectorlayer.h"
33#include "qgslinestring.h"
35#include <memory>
36
37#include <QPointer>
38
45
53
61
68
75
82
84{
85 class IStorageManager;
86 class ISpatialIndex;
87}
88
101class CORE_EXPORT QgsPointLocator : public QObject
102{
103 Q_OBJECT
104 public:
105
118 const QgsRectangle *extent = nullptr );
119
120 ~QgsPointLocator() override;
121
126 QgsVectorLayer *layer() const { return mLayer; }
127
132 QgsCoordinateReferenceSystem destinationCrs() const;
133
138 const QgsRectangle *extent() const { return mExtent.get(); }
139
144 void setExtent( const QgsRectangle *extent );
145
150 void setRenderContext( const QgsRenderContext *context );
151
155 enum Type
156 {
157 Invalid = 0,
158 Vertex = 1 << 0,
159 Edge = 1 << 1,
160 Area = 1 << 2,
161 Centroid = 1 << 3,
162 MiddleOfSegment = 1 << 4,
163 LineEndpoint = 1 << 5,
164 All = Vertex | Edge | Area | Centroid | MiddleOfSegment
165 };
166
167 Q_DECLARE_FLAGS( Types, Type )
168
169
182 bool init( int maxFeaturesToIndex = -1, bool relaxed = false );
183
185 bool hasIndex() const;
186
187 struct Match
188 {
190 Match() = default;
191
192 Match( QgsPointLocator::Type t, QgsVectorLayer *vl, QgsFeatureId fid, double dist, const QgsPointXY &pt, int vertexIndex = 0, QgsPointXY *edgePoints = nullptr )
193 : mType( t )
194 , mDist( dist )
195 , mPoint( pt )
196 , mLayer( vl )
197 , mFid( fid )
198 , mVertexIndex( vertexIndex )
199 {
200 if ( edgePoints )
201 {
202 mEdgePoints[0] = edgePoints[0];
203 mEdgePoints[1] = edgePoints[1];
204 }
205 }
206
207 QgsPointLocator::Type type() const { return mType; }
208
209 bool isValid() const { return mType != Invalid; }
211 bool hasVertex() const { return mType == Vertex; }
213 bool hasEdge() const { return mType == Edge; }
215 bool hasCentroid() const { return mType == Centroid; }
217 bool hasArea() const { return mType == Area; }
219 bool hasMiddleSegment() const { return mType == MiddleOfSegment; }
220
226 bool hasLineEndpoint() const { return mType == LineEndpoint; }
227
232 double distance() const { return mDist; }
233
238 QgsPointXY point() const { return mPoint; }
239
241 int vertexIndex() const { return mVertexIndex; }
242
247 QgsVectorLayer *layer() const { return mLayer; }
248
252 QgsFeatureId featureId() const { return mFid; }
253
256 {
257 pt1 = mEdgePoints[0];
258 pt2 = mEdgePoints[1];
259 }
260
268 {
269 QgsPoint point;
270
271 if ( mLayer )
272 {
273 QgsPointXY snappedPoint( mPoint );
274 const QgsGeometry geom = mLayer->getGeometry( mFid );
275 QgsCoordinateTransform transform( destinationCrs, mLayer->crs(), mLayer->transformContext() );
276 if ( transform.isValid() )
277 {
278 try
279 {
280 snappedPoint = transform.transform( snappedPoint );
281 }
282 catch ( QgsCsException & )
283 {
284 QgsDebugError( QStringLiteral( "transformation to layer coordinate failed" ) );
285 }
286 }
287
288 if ( !( geom.isNull() || geom.isEmpty() ) )
289 {
290 // when snapping to a curve we need to use real geometry in order to have correct location
291 // of the snapped point, see https://github.com/qgis/QGIS/issues/53197.
292 // In other cases it is ok to use only a segment to speedup calculations.
293 if ( QgsWkbTypes::isCurvedType( geom.wkbType() ) )
294 {
295 point = QgsGeometryUtils::closestPoint( *geom.constGet(), QgsPoint( snappedPoint ) );
296 }
297 else
298 {
299 const QgsLineString line( geom.vertexAt( mVertexIndex ), geom.vertexAt( mVertexIndex + 1 ) );
300 point = QgsGeometryUtils::closestPoint( line, QgsPoint( snappedPoint ) );
301 }
302 }
303
304 if ( transform.isValid() )
305 {
306 try
307 {
309 }
310 catch ( QgsCsException & )
311 {
312 QgsDebugError( QStringLiteral( "transformation to destination coordinate failed" ) );
313 }
314 }
315 }
316
317 return point;
318 }
319
320 // TODO c++20 - replace with = default
321 bool operator==( const QgsPointLocator::Match &other ) const
322 {
323 return mType == other.mType &&
324 mDist == other.mDist &&
325 mPoint == other.mPoint &&
326 mLayer == other.mLayer &&
327 mFid == other.mFid &&
328 mVertexIndex == other.mVertexIndex &&
329 mEdgePoints[0] == other.mEdgePoints[0] &&
330 mEdgePoints[1] == other.mEdgePoints[1] &&
331 mCentroid == other.mCentroid &&
332 mMiddleOfSegment == other.mMiddleOfSegment;
333 }
334
335 protected:
336 Type mType = Invalid;
337 double mDist = 0;
339 QgsVectorLayer *mLayer = nullptr;
340 QgsFeatureId mFid = 0;
341 int mVertexIndex = 0; // e.g. vertex index
342 QgsPointXY mEdgePoints[2];
345 };
346
347#ifndef SIP_RUN
348 typedef class QList<QgsPointLocator::Match> MatchList;
349#else
350 typedef QList<QgsPointLocator::Match> MatchList;
351#endif
352
359 {
360 virtual ~MatchFilter() = default;
361 virtual bool acceptMatch( const QgsPointLocator::Match &match ) = 0;
362 };
363
364 // intersection queries
365
371 Match nearestVertex( const QgsPointXY &point, double tolerance, QgsPointLocator::MatchFilter *filter = nullptr, bool relaxed = false );
372
379 Match nearestCentroid( const QgsPointXY &point, double tolerance, QgsPointLocator::MatchFilter *filter = nullptr, bool relaxed = false );
380
387 Match nearestMiddleOfSegment( const QgsPointXY &point, double tolerance, QgsPointLocator::MatchFilter *filter = nullptr, bool relaxed = false );
388
395 Match nearestLineEndpoints( const QgsPointXY &point, double tolerance, QgsPointLocator::MatchFilter *filter = nullptr, bool relaxed = false );
396
402 Match nearestEdge( const QgsPointXY &point, double tolerance, QgsPointLocator::MatchFilter *filter = nullptr, bool relaxed = false );
403
412 Match nearestArea( const QgsPointXY &point, double tolerance, QgsPointLocator::MatchFilter *filter = nullptr, bool relaxed = false );
413
419 MatchList edgesInRect( const QgsRectangle &rect, QgsPointLocator::MatchFilter *filter = nullptr, bool relaxed = false );
420
425 MatchList edgesInRect( const QgsPointXY &point, double tolerance, QgsPointLocator::MatchFilter *filter = nullptr, bool relaxed = false );
426
433 MatchList verticesInRect( const QgsRectangle &rect, QgsPointLocator::MatchFilter *filter = nullptr, bool relaxed = false );
434
440 MatchList verticesInRect( const QgsPointXY &point, double tolerance, QgsPointLocator::MatchFilter *filter = nullptr, bool relaxed = false );
441
442 // point-in-polygon query
443
444 // TODO: function to return just the first match?
445
451 MatchList pointInPolygon( const QgsPointXY &point, bool relaxed = false );
452
457 int cachedGeometryCount() const { return mGeoms.count(); }
458
465 bool isIndexing() const { return mIsIndexing; }
466
471 void waitForIndexingFinished();
472
473 signals:
474
480 void initFinished( bool ok );
481
482 protected:
483 bool rebuildIndex( int maxFeaturesToIndex = -1 );
484
485 protected slots:
486 void destroyIndex();
487 private slots:
488 void onInitTaskFinished();
489 void onFeatureAdded( QgsFeatureId fid );
490 void onFeatureDeleted( QgsFeatureId fid );
491 void onGeometryChanged( QgsFeatureId fid, const QgsGeometry &geom );
492 void onAttributeValueChanged( QgsFeatureId fid, int idx, const QVariant &value );
493
494 private:
495
500 bool prepare( bool relaxed );
501
503 std::unique_ptr< SpatialIndex::IStorageManager > mStorage;
504
505 QHash<QgsFeatureId, QgsGeometry *> mGeoms;
506 std::unique_ptr< SpatialIndex::ISpatialIndex > mRTree;
507
509 bool mIsEmptyLayer = false;
510
511
513 QgsCoordinateTransform mTransform;
514 QgsVectorLayer *mLayer = nullptr;
515 std::unique_ptr< QgsRectangle > mExtent;
516
517 std::unique_ptr<QgsRenderContext> mContext;
518 std::unique_ptr<QgsFeatureRenderer> mRenderer;
519 std::unique_ptr<QgsVectorLayerFeatureSource> mSource;
520 int mMaxFeaturesToIndex = -1;
521 bool mIsIndexing = false;
522 bool mIsDestroying = false;
523 QgsFeatureIds mAddedFeatures;
524 QgsFeatureIds mDeletedFeatures;
525 QPointer<QgsPointLocatorInitTask> mInitTask;
526
534 friend class QgsPointLocatorInitTask;
535 friend class TestQgsPointLocator;
539};
540
541
542#endif // QGSPOINTLOCATOR_H
@ Reverse
Reverse/inverse transform (from destination to source)
This class represents a coordinate reference system (CRS).
Contains information about the context in which a coordinate transform is executed.
Class for doing transforms between two map 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 isValid() const
Returns true if the coordinate transform is valid, ie both the source and destination CRS have been s...
Custom exception class for Coordinate Reference System related exceptions.
static QgsPoint closestPoint(const QgsAbstractGeometry &geometry, const QgsPoint &point)
Returns the nearest point on a segment of a geometry for the specified point.
A geometry is the spatial representation of a feature.
QgsPoint vertexAt(int atVertex) const
Returns coordinates of a vertex.
const QgsAbstractGeometry * constGet() const
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
bool isEmpty() const
Returns true if the geometry is empty (eg a linestring with no vertices, or a collection with no geom...
Qgis::WkbType wkbType() const
Returns type of the geometry as a WKB type (point / linestring / polygon etc.)
Line string geometry type, with support for z-dimension and m-values.
Helper class used when traversing the index with areas - builds a list of matches.
Helper class used when traversing the index looking for centroid - builds a list of matches.
Helper class used when traversing the index looking for edges - builds a list of matches.
Helper class used when traversing the index looking for middle segment - builds a list of matches.
Helper class used when traversing the index looking for centroid - builds a list of matches.
Helper class used when traversing the index looking for edges - builds a list of matches.
Helper class used when traversing the index looking for line endpoints (start or end vertex) - builds...
Helper class used when traversing the index looking for middle segment - builds a list of matches.
Helper class used when traversing the index looking for vertices - builds a list of matches.
Helper class used when traversing the index looking for vertices - builds a list of matches.
The class defines interface for querying point location:
int cachedGeometryCount() const
Returns how many geometries are cached in the index.
QgsVectorLayer * layer() const
Gets associated layer.
class QList< QgsPointLocator::Match > MatchList
bool isIndexing() const
Returns true if the point locator is currently indexing the data.
const QgsRectangle * extent() const
Gets extent of the area point locator covers - if nullptr then it caches the whole layer.
void initFinished(bool ok)
Emitted whenever index has been built and initialization is finished.
Type
The type of a snap result or the filter type for a snap request.
A class to represent a 2D point.
Definition qgspointxy.h:59
Point geometry type, with support for z-dimension and m-values.
Definition qgspoint.h:49
void transform(const QgsCoordinateTransform &ct, Qgis::TransformDirection d=Qgis::TransformDirection::Forward, bool transformZ=false) override
Transforms the geometry using a coordinate transform.
Definition qgspoint.cpp:383
A rectangle specified with double values.
Contains information about the context of a rendering operation.
Partial snapshot of vector layer's state (only the members necessary for access to features)
Represents a vector layer which manages a vector based data sets.
static bool isCurvedType(Qgis::WkbType type)
Returns true if the WKB type is a curved type or can contain curved geometries.
#define SIP_SKIP
Definition qgis_sip.h:126
#define SIP_OUT
Definition qgis_sip.h:58
QSet< QgsFeatureId > QgsFeatureIds
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features
#define QgsDebugError(str)
Definition qgslogger.h:38
Interface that allows rejection of some matches in intersection queries (e.g.
virtual bool acceptMatch(const QgsPointLocator::Match &match)=0
virtual ~MatchFilter()=default
QgsFeatureId featureId() const
The id of the feature to which the snapped geometry belongs.
bool hasCentroid() const
Returns true if the Match is a centroid.
QgsVectorLayer * layer() const
The vector layer where the snap occurred.
QgsPoint interpolatedPoint(const QgsCoordinateReferenceSystem &destinationCrs=QgsCoordinateReferenceSystem()) const
Convenient method to return a point on an edge with linear interpolation of the Z value.
double distance() const
for vertex / edge match units depending on what class returns it (geom.cache: layer units,...
QgsPointXY point() const
for vertex / edge match coords depending on what class returns it (geom.cache: layer coords,...
bool hasEdge() const
Returns true if the Match is an edge.
void edgePoints(QgsPointXY &pt1, QgsPointXY &pt2) const
Only for a valid edge match - obtain endpoints of the edge.
bool hasArea() const
Returns true if the Match is an area.
QgsVectorLayer * mLayer
Match()=default
construct invalid match
Match(QgsPointLocator::Type t, QgsVectorLayer *vl, QgsFeatureId fid, double dist, const QgsPointXY &pt, int vertexIndex=0, QgsPointXY *edgePoints=nullptr)
QgsPointLocator::Type type() const
bool hasLineEndpoint() const
Returns true if the Match is a line endpoint (start or end vertex).
bool hasMiddleSegment() const
Returns true if the Match is the middle of a segment.
int vertexIndex() const
for vertex / edge match (first vertex of the edge)
bool hasVertex() const
Returns true if the Match is a vertex.
bool operator==(const QgsPointLocator::Match &other) const