QGIS API Documentation 3.28.0-Firenze (ed3ad0430f)
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 QgsDebugMsg( QStringLiteral( "transformation to layer coordinate failed" ) );
285 }
286 }
287
288 if ( !( geom.isNull() || geom.isEmpty() ) )
289 {
290 const QgsLineString line( geom.vertexAt( mVertexIndex ), geom.vertexAt( mVertexIndex + 1 ) );
291 point = QgsGeometryUtils::closestPoint( line, QgsPoint( snappedPoint ) );
292 }
293
294
295 if ( transform.isValid() )
296 {
297 try
298 {
299 point.transform( transform, Qgis::TransformDirection::Reverse );
300 }
301 catch ( QgsCsException & )
302 {
303 QgsDebugMsg( QStringLiteral( "transformation to destination coordinate failed" ) );
304 }
305 }
306 }
307
308 return point;
309 }
310
311 // TODO c++20 - replace with = default
312 bool operator==( const QgsPointLocator::Match &other ) const
313 {
314 return mType == other.mType &&
315 mDist == other.mDist &&
316 mPoint == other.mPoint &&
317 mLayer == other.mLayer &&
318 mFid == other.mFid &&
319 mVertexIndex == other.mVertexIndex &&
320 mEdgePoints[0] == other.mEdgePoints[0] &&
321 mEdgePoints[1] == other.mEdgePoints[1] &&
322 mCentroid == other.mCentroid &&
323 mMiddleOfSegment == other.mMiddleOfSegment;
324 }
325
326 protected:
327 Type mType = Invalid;
328 double mDist = 0;
330 QgsVectorLayer *mLayer = nullptr;
331 QgsFeatureId mFid = 0;
332 int mVertexIndex = 0; // e.g. vertex index
333 QgsPointXY mEdgePoints[2];
336 };
337
338#ifndef SIP_RUN
339 typedef class QList<QgsPointLocator::Match> MatchList;
340#else
341 typedef QList<QgsPointLocator::Match> MatchList;
342#endif
343
350 {
351 virtual ~MatchFilter() = default;
352 virtual bool acceptMatch( const QgsPointLocator::Match &match ) = 0;
353 };
354
355 // intersection queries
356
362 Match nearestVertex( const QgsPointXY &point, double tolerance, QgsPointLocator::MatchFilter *filter = nullptr, bool relaxed = false );
363
370 Match nearestCentroid( const QgsPointXY &point, double tolerance, QgsPointLocator::MatchFilter *filter = nullptr, bool relaxed = false );
371
378 Match nearestMiddleOfSegment( const QgsPointXY &point, double tolerance, QgsPointLocator::MatchFilter *filter = nullptr, bool relaxed = false );
379
386 Match nearestLineEndpoints( const QgsPointXY &point, double tolerance, QgsPointLocator::MatchFilter *filter = nullptr, bool relaxed = false );
387
393 Match nearestEdge( const QgsPointXY &point, double tolerance, QgsPointLocator::MatchFilter *filter = nullptr, bool relaxed = false );
394
403 Match nearestArea( const QgsPointXY &point, double tolerance, QgsPointLocator::MatchFilter *filter = nullptr, bool relaxed = false );
404
410 MatchList edgesInRect( const QgsRectangle &rect, QgsPointLocator::MatchFilter *filter = nullptr, bool relaxed = false );
411
416 MatchList edgesInRect( const QgsPointXY &point, double tolerance, QgsPointLocator::MatchFilter *filter = nullptr, bool relaxed = false );
417
424 MatchList verticesInRect( const QgsRectangle &rect, QgsPointLocator::MatchFilter *filter = nullptr, bool relaxed = false );
425
431 MatchList verticesInRect( const QgsPointXY &point, double tolerance, QgsPointLocator::MatchFilter *filter = nullptr, bool relaxed = false );
432
433 // point-in-polygon query
434
435 // TODO: function to return just the first match?
436
442 MatchList pointInPolygon( const QgsPointXY &point, bool relaxed = false );
443
448 int cachedGeometryCount() const { return mGeoms.count(); }
449
456 bool isIndexing() const { return mIsIndexing; }
457
462 void waitForIndexingFinished();
463
464 signals:
465
471 void initFinished( bool ok );
472
473 protected:
474 bool rebuildIndex( int maxFeaturesToIndex = -1 );
475
476 protected slots:
477 void destroyIndex();
478 private slots:
479 void onInitTaskFinished();
480 void onFeatureAdded( QgsFeatureId fid );
481 void onFeatureDeleted( QgsFeatureId fid );
482 void onGeometryChanged( QgsFeatureId fid, const QgsGeometry &geom );
483 void onAttributeValueChanged( QgsFeatureId fid, int idx, const QVariant &value );
484
485 private:
486
491 bool prepare( bool relaxed );
492
494 std::unique_ptr< SpatialIndex::IStorageManager > mStorage;
495
496 QHash<QgsFeatureId, QgsGeometry *> mGeoms;
497 std::unique_ptr< SpatialIndex::ISpatialIndex > mRTree;
498
500 bool mIsEmptyLayer = false;
501
502
504 QgsCoordinateTransform mTransform;
505 QgsVectorLayer *mLayer = nullptr;
506 std::unique_ptr< QgsRectangle > mExtent;
507
508 std::unique_ptr<QgsRenderContext> mContext;
509 std::unique_ptr<QgsFeatureRenderer> mRenderer;
510 std::unique_ptr<QgsVectorLayerFeatureSource> mSource;
511 int mMaxFeaturesToIndex = -1;
512 bool mIsIndexing = false;
513 bool mIsDestroying = false;
514 QgsFeatureIds mAddedFeatures;
515 QgsFeatureIds mDeletedFeatures;
516 QPointer<QgsPointLocatorInitTask> mInitTask;
517
525 friend class QgsPointLocatorInitTask;
526 friend class TestQgsPointLocator;
530};
531
532
533#endif // QGSPOINTLOCATOR_H
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.
bool isValid() const
Returns true if the coordinate transform is valid, ie both the source and destination CRS have been s...
QgsPointXY transform(const QgsPointXY &point, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward) const SIP_THROW(QgsCsException)
Transform the point from the source CRS to the destination CRS.
Custom exception class for Coordinate Reference System related exceptions.
Definition: qgsexception.h:66
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.
Definition: qgsgeometry.h:164
QgsPoint vertexAt(int atVertex) const
Returns coordinates of a vertex.
Q_GADGET bool isNull
Definition: qgsgeometry.h:166
bool isEmpty() const
Returns true if the geometry is empty (eg a linestring with no vertices, or a collection with no geom...
Line string geometry type, with support for z-dimension and m-values.
Definition: qgslinestring.h:45
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 SIP_THROW(QgsCsException)
Transforms the geometry using a coordinate transform.
Definition: qgspoint.cpp:382
A rectangle specified with double values.
Definition: qgsrectangle.h:42
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.
#define SIP_SKIP
Definition: qgis_sip.h:126
#define SIP_OUT
Definition: qgis_sip.h:58
QSet< QgsFeatureId > QgsFeatureIds
Definition: qgsfeatureid.h:37
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features
Definition: qgsfeatureid.h:28
#define QgsDebugMsg(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