QGIS API Documentation 3.37.0-Master (fdefdf9c27f)
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
100class CORE_EXPORT QgsPointLocator : public QObject
101{
102 Q_OBJECT
103 public:
104
117 const QgsRectangle *extent = nullptr );
118
119 ~QgsPointLocator() override;
120
124 QgsVectorLayer *layer() const { return mLayer; }
125
129 QgsCoordinateReferenceSystem destinationCrs() const;
130
134 const QgsRectangle *extent() const { return mExtent.get(); }
135
139 void setExtent( const QgsRectangle *extent );
140
145 void setRenderContext( const QgsRenderContext *context );
146
150 enum Type SIP_ENUM_BASETYPE( IntFlag )
151 {
152 Invalid = 0,
153 Vertex = 1 << 0,
154 Edge = 1 << 1,
155 Area = 1 << 2,
156 Centroid = 1 << 3,
157 MiddleOfSegment = 1 << 4,
158 LineEndpoint = 1 << 5,
159 All = Vertex | Edge | Area | Centroid | MiddleOfSegment
160 };
161
162 Q_DECLARE_FLAGS( Types, Type )
163
164
177 bool init( int maxFeaturesToIndex = -1, bool relaxed = false );
178
180 bool hasIndex() const;
181
182 struct Match
183 {
185 Match() = default;
186
187 Match( QgsPointLocator::Type t, QgsVectorLayer *vl, QgsFeatureId fid, double dist, const QgsPointXY &pt, int vertexIndex = 0, QgsPointXY *edgePoints = nullptr )
188 : mType( t )
189 , mDist( dist )
190 , mPoint( pt )
191 , mLayer( vl )
192 , mFid( fid )
193 , mVertexIndex( vertexIndex )
194 {
195 if ( edgePoints )
196 {
197 mEdgePoints[0] = edgePoints[0];
198 mEdgePoints[1] = edgePoints[1];
199 }
200 }
201
202 QgsPointLocator::Type type() const { return mType; }
203
204 bool isValid() const { return mType != Invalid; }
206 bool hasVertex() const { return mType == Vertex; }
208 bool hasEdge() const { return mType == Edge; }
210 bool hasCentroid() const { return mType == Centroid; }
212 bool hasArea() const { return mType == Area; }
214 bool hasMiddleSegment() const { return mType == MiddleOfSegment; }
215
221 bool hasLineEndpoint() const { return mType == LineEndpoint; }
222
227 double distance() const { return mDist; }
228
233 QgsPointXY point() const { return mPoint; }
234
236 int vertexIndex() const { return mVertexIndex; }
237
242 QgsVectorLayer *layer() const { return mLayer; }
243
247 QgsFeatureId featureId() const { return mFid; }
248
251 {
252 pt1 = mEdgePoints[0];
253 pt2 = mEdgePoints[1];
254 }
255
263 {
264 QgsPoint point;
265
266 if ( mLayer )
267 {
268 QgsPointXY snappedPoint( mPoint );
269 const QgsGeometry geom = mLayer->getGeometry( mFid );
270 QgsCoordinateTransform transform( destinationCrs, mLayer->crs(), mLayer->transformContext() );
271 if ( transform.isValid() )
272 {
273 try
274 {
275 snappedPoint = transform.transform( snappedPoint );
276 }
277 catch ( QgsCsException & )
278 {
279 QgsDebugError( QStringLiteral( "transformation to layer coordinate failed" ) );
280 }
281 }
282
283 if ( !( geom.isNull() || geom.isEmpty() ) )
284 {
285 // when snapping to a curve we need to use real geometry in order to have correct location
286 // of the snapped point, see https://github.com/qgis/QGIS/issues/53197.
287 // In other cases it is ok to use only a segment to speedup calculations.
288 if ( QgsWkbTypes::isCurvedType( geom.wkbType() ) )
289 {
290 point = QgsGeometryUtils::closestPoint( *geom.constGet(), QgsPoint( snappedPoint ) );
291 }
292 else
293 {
294 const QgsLineString line( geom.vertexAt( mVertexIndex ), geom.vertexAt( mVertexIndex + 1 ) );
295 point = QgsGeometryUtils::closestPoint( line, QgsPoint( snappedPoint ) );
296 }
297 }
298
299 if ( transform.isValid() )
300 {
301 try
302 {
304 }
305 catch ( QgsCsException & )
306 {
307 QgsDebugError( QStringLiteral( "transformation to destination coordinate failed" ) );
308 }
309 }
310 }
311
312 return point;
313 }
314
315 // TODO c++20 - replace with = default
316 bool operator==( const QgsPointLocator::Match &other ) const
317 {
318 return mType == other.mType &&
319 mDist == other.mDist &&
320 mPoint == other.mPoint &&
321 mLayer == other.mLayer &&
322 mFid == other.mFid &&
323 mVertexIndex == other.mVertexIndex &&
324 mEdgePoints[0] == other.mEdgePoints[0] &&
325 mEdgePoints[1] == other.mEdgePoints[1] &&
326 mCentroid == other.mCentroid &&
327 mMiddleOfSegment == other.mMiddleOfSegment;
328 }
329
330 protected:
331 Type mType = Invalid;
332 double mDist = 0;
334 QgsVectorLayer *mLayer = nullptr;
335 QgsFeatureId mFid = 0;
336 int mVertexIndex = 0; // e.g. vertex index
337 QgsPointXY mEdgePoints[2];
340 };
341
342#ifndef SIP_RUN
343 typedef class QList<QgsPointLocator::Match> MatchList;
344#else
345 typedef QList<QgsPointLocator::Match> MatchList;
346#endif
347
354 {
355 virtual ~MatchFilter() = default;
356 virtual bool acceptMatch( const QgsPointLocator::Match &match ) = 0;
357 };
358
359 // intersection queries
360
366 Match nearestVertex( const QgsPointXY &point, double tolerance, QgsPointLocator::MatchFilter *filter = nullptr, bool relaxed = false );
367
374 Match nearestCentroid( const QgsPointXY &point, double tolerance, QgsPointLocator::MatchFilter *filter = nullptr, bool relaxed = false );
375
382 Match nearestMiddleOfSegment( const QgsPointXY &point, double tolerance, QgsPointLocator::MatchFilter *filter = nullptr, bool relaxed = false );
383
390 Match nearestLineEndpoints( const QgsPointXY &point, double tolerance, QgsPointLocator::MatchFilter *filter = nullptr, bool relaxed = false );
391
397 Match nearestEdge( const QgsPointXY &point, double tolerance, QgsPointLocator::MatchFilter *filter = nullptr, bool relaxed = false );
398
406 Match nearestArea( const QgsPointXY &point, double tolerance, QgsPointLocator::MatchFilter *filter = nullptr, bool relaxed = false );
407
413 MatchList edgesInRect( const QgsRectangle &rect, QgsPointLocator::MatchFilter *filter = nullptr, bool relaxed = false );
414
419 MatchList edgesInRect( const QgsPointXY &point, double tolerance, QgsPointLocator::MatchFilter *filter = nullptr, bool relaxed = false );
420
427 MatchList verticesInRect( const QgsRectangle &rect, QgsPointLocator::MatchFilter *filter = nullptr, bool relaxed = false );
428
434 MatchList verticesInRect( const QgsPointXY &point, double tolerance, QgsPointLocator::MatchFilter *filter = nullptr, bool relaxed = false );
435
436 // point-in-polygon query
437
438 // TODO: function to return just the first match?
439
447 MatchList pointInPolygon( const QgsPointXY &point, bool relaxed = false, QgsPointLocator::MatchFilter *filter = nullptr );
448
452 int cachedGeometryCount() const { return mGeoms.count(); }
453
460 bool isIndexing() const { return mIsIndexing; }
461
466 void waitForIndexingFinished();
467
468 signals:
469
475 void initFinished( bool ok );
476
477 protected:
478 bool rebuildIndex( int maxFeaturesToIndex = -1 );
479
480 protected slots:
481 void destroyIndex();
482 private slots:
483 void onInitTaskFinished();
484 void onFeatureAdded( QgsFeatureId fid );
485 void onFeatureDeleted( QgsFeatureId fid );
486 void onGeometryChanged( QgsFeatureId fid, const QgsGeometry &geom );
487 void onAttributeValueChanged( QgsFeatureId fid, int idx, const QVariant &value );
488
489 private:
490
495 bool prepare( bool relaxed );
496
498 std::unique_ptr< SpatialIndex::IStorageManager > mStorage;
499
500 QHash<QgsFeatureId, QgsGeometry *> mGeoms;
501 std::unique_ptr< SpatialIndex::ISpatialIndex > mRTree;
502
504 bool mIsEmptyLayer = false;
505
506
508 QgsCoordinateTransform mTransform;
509 QgsVectorLayer *mLayer = nullptr;
510 std::unique_ptr< QgsRectangle > mExtent;
511
512 std::unique_ptr<QgsRenderContext> mContext;
513 std::unique_ptr<QgsFeatureRenderer> mRenderer;
514 std::unique_ptr<QgsVectorLayerFeatureSource> mSource;
515 int mMaxFeaturesToIndex = -1;
516 bool mIsIndexing = false;
517 bool mIsDestroying = false;
518 QgsFeatureIds mAddedFeatures;
519 QgsFeatureIds mDeletedFeatures;
520 QPointer<QgsPointLocatorInitTask> mInitTask;
521
529 friend class QgsPointLocatorInitTask;
530 friend class TestQgsPointLocator;
534};
535
536
537#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.
Definition: qgsexception.h:67
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:162
QgsPoint vertexAt(int atVertex) const
Returns coordinates of a vertex.
Q_GADGET bool isNull
Definition: qgsgeometry.h:164
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.
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.
QFlags< Type > Types
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:60
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:379
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.
static bool isCurvedType(Qgis::WkbType type)
Returns true if the WKB type is a curved type or can contain curved geometries.
Definition: qgswkbtypes.h:806
#define SIP_ENUM_BASETYPE(type)
Definition: qgis_sip.h:278
#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 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