QGIS API Documentation 4.0.0-Norrköping (1ddcee3d0e4)
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 <memory>
26
27#include "qgis_core.h"
30#include "qgsfeatureid.h"
31#include "qgsgeometry.h"
32#include "qgsgeometryutils.h"
33#include "qgslinestring.h"
35#include "qgspointxy.h"
36#include "qgsvectorlayer.h"
37
38#include <QPointer>
39#include <QString>
40
41using namespace Qt::StringLiterals;
42
49
57
65
72
79
86
88{
89 class IStorageManager;
90 class ISpatialIndex;
91} //namespace SpatialIndex
92
106class CORE_EXPORT QgsPointLocator : public QObject
107{
108 Q_OBJECT
109 public:
120 explicit QgsPointLocator(
124 const QgsRectangle *extent = nullptr
125 );
126
127 ~QgsPointLocator() override;
128
132 QgsVectorLayer *layer() const { return mLayer; }
133
137 QgsCoordinateReferenceSystem destinationCrs() const;
138
142 const QgsRectangle *extent() const { return mExtent.get(); }
143
147 void setExtent( const QgsRectangle *extent );
148
153 void setRenderContext( const QgsRenderContext *context );
154
158 enum Type SIP_ENUM_BASETYPE( IntFlag )
159 {
161 Vertex = 1 << 0,
162 Edge = 1 << 1,
163 Area = 1 << 2,
164 Centroid = 1 << 3,
166 LineEndpoint = 1 << 5,
168 };
169
170 Q_DECLARE_FLAGS( Types, Type )
171
172
185 bool init( int maxFeaturesToIndex = -1, bool relaxed = false );
186
188 bool hasIndex() const;
189
190 struct Match
191 {
193 Match() = default;
194
195 Match( QgsPointLocator::Type t, QgsVectorLayer *vl, QgsFeatureId fid, double dist, const QgsPointXY &pt, int vertexIndex = 0, QgsPointXY *edgePoints = nullptr )
196 : mType( t )
197 , mDist( dist )
198 , mPoint( pt )
199 , mLayer( vl )
200 , mFid( fid )
202 {
203 if ( edgePoints )
204 {
205 mEdgePoints[0] = edgePoints[0];
206 mEdgePoints[1] = edgePoints[1];
207 }
208 }
209
210 QgsPointLocator::Type type() const { return mType; }
211
212 bool isValid() const { return mType != Invalid; }
214 bool hasVertex() const { return mType == Vertex; }
216 bool hasEdge() const { return mType == Edge; }
218 bool hasCentroid() const { return mType == Centroid; }
220 bool hasArea() const { return mType == Area; }
222 bool hasMiddleSegment() const { return mType == MiddleOfSegment; }
223
229 bool hasLineEndpoint() const { return mType == LineEndpoint; }
230
235 double distance() const { return mDist; }
236
241 QgsPointXY point() const { return mPoint; }
242
244 int vertexIndex() const { return mVertexIndex; }
245
250 QgsVectorLayer *layer() const { return mLayer; }
251
255 QgsFeatureId featureId() const { return mFid; }
256
259 {
260 pt1 = mEdgePoints[0];
261 pt2 = mEdgePoints[1];
262 }
263
271 {
273
274 if ( mLayer )
275 {
276 QgsPointXY snappedPoint( mPoint );
277 const QgsGeometry geom = mLayer->getGeometry( mFid );
278 QgsCoordinateTransform transform( destinationCrs, mLayer->crs(), mLayer->transformContext() );
279 if ( transform.isValid() )
280 {
281 try
282 {
283 snappedPoint = transform.transform( snappedPoint );
284 }
285 catch ( QgsCsException & )
286 {
287 QgsDebugError( u"transformation to layer coordinate failed"_s );
288 }
289 }
290
291 if ( !( geom.isNull() || geom.isEmpty() ) )
292 {
293 // when snapping to a curve we need to use real geometry in order to have correct location
294 // of the snapped point, see https://github.com/qgis/QGIS/issues/53197.
295 // In other cases it is ok to use only a segment to speedup calculations.
296 if ( QgsWkbTypes::isCurvedType( geom.wkbType() ) )
297 {
298 point = QgsGeometryUtils::closestPoint( *geom.constGet(), QgsPoint( snappedPoint ) );
299 }
300 else
301 {
302 const QgsLineString line( geom.vertexAt( mVertexIndex ), geom.vertexAt( mVertexIndex + 1 ) );
303 point = QgsGeometryUtils::closestPoint( line, QgsPoint( snappedPoint ) );
304 }
305 }
306
307 if ( transform.isValid() )
308 {
309 try
310 {
311 point.transform( transform, Qgis::TransformDirection::Reverse );
312 }
313 catch ( QgsCsException & )
314 {
315 QgsDebugError( u"transformation to destination coordinate failed"_s );
316 }
317 }
318 }
319
320 return point;
321 }
322
323 // TODO c++20 - replace with = default
324 bool operator==( const QgsPointLocator::Match &other ) const
325 {
326 return mType == other.mType
327 && mDist == other.mDist
328 && mPoint == other.mPoint
329 && mLayer == other.mLayer
330 && mFid == other.mFid
331 && mVertexIndex == other.mVertexIndex
332 && mEdgePoints[0] == other.mEdgePoints[0]
333 && mEdgePoints[1] == other.mEdgePoints[1]
334 && mCentroid == other.mCentroid
336 }
337
338 protected:
340 double mDist = 0;
344 int mVertexIndex = 0; // e.g. vertex index
348 };
349
350#ifndef SIP_RUN
351 typedef class QList<QgsPointLocator::Match> MatchList;
352#else
353 typedef QList<QgsPointLocator::Match> MatchList;
354#endif
355
362 {
363 virtual ~MatchFilter() = default;
364 virtual bool acceptMatch( const QgsPointLocator::Match &match ) = 0;
365 };
366
367 // intersection queries
368
374 Match nearestVertex( const QgsPointXY &point, double tolerance, QgsPointLocator::MatchFilter *filter = nullptr, bool relaxed = false );
375
382 Match nearestCentroid( const QgsPointXY &point, double tolerance, QgsPointLocator::MatchFilter *filter = nullptr, bool relaxed = false );
383
390 Match nearestMiddleOfSegment( const QgsPointXY &point, double tolerance, QgsPointLocator::MatchFilter *filter = nullptr, bool relaxed = false );
391
398 Match nearestLineEndpoints( const QgsPointXY &point, double tolerance, QgsPointLocator::MatchFilter *filter = nullptr, bool relaxed = false );
399
405 Match nearestEdge( const QgsPointXY &point, double tolerance, QgsPointLocator::MatchFilter *filter = nullptr, bool relaxed = false );
406
414 Match nearestArea( const QgsPointXY &point, double tolerance, QgsPointLocator::MatchFilter *filter = nullptr, bool relaxed = false );
415
421 MatchList edgesInRect( const QgsRectangle &rect, QgsPointLocator::MatchFilter *filter = nullptr, bool relaxed = false );
422
427 MatchList edgesInRect( const QgsPointXY &point, double tolerance, QgsPointLocator::MatchFilter *filter = nullptr, bool relaxed = false );
428
435 MatchList verticesInRect( const QgsRectangle &rect, QgsPointLocator::MatchFilter *filter = nullptr, bool relaxed = false );
436
442 MatchList verticesInRect( const QgsPointXY &point, double tolerance, QgsPointLocator::MatchFilter *filter = nullptr, bool relaxed = false );
443
444 // point-in-polygon query
445
446 // TODO: function to return just the first match?
447
455 MatchList pointInPolygon( const QgsPointXY &point, bool relaxed = false, QgsPointLocator::MatchFilter *filter = nullptr );
456
460 int cachedGeometryCount() const { return mGeoms.count(); }
461
468 bool isIndexing() const { return mIsIndexing; }
469
474 void waitForIndexingFinished();
475
476 signals:
477
483 void initFinished( bool ok );
484
485 protected:
486 bool rebuildIndex( int maxFeaturesToIndex = -1 );
487
488 protected slots:
489 void destroyIndex();
490 private slots:
491 void onInitTaskFinished();
492 void onFeatureAdded( QgsFeatureId fid );
493 void onFeatureDeleted( QgsFeatureId fid );
494 void onGeometryChanged( QgsFeatureId fid, const QgsGeometry &geom );
495 void onAttributeValueChanged( QgsFeatureId fid, int idx, const QVariant &value );
496
497 private:
502 bool prepare( bool relaxed );
503
505 std::unique_ptr< SpatialIndex::IStorageManager > mStorage;
506
507 QHash<QgsFeatureId, QgsGeometry *> mGeoms;
508 std::unique_ptr< SpatialIndex::ISpatialIndex > mRTree;
509
511 bool mIsEmptyLayer = false;
512
513
515 QgsCoordinateTransform mTransform;
516 QgsVectorLayer *mLayer = nullptr;
517 std::unique_ptr< QgsRectangle > mExtent;
518
519 std::unique_ptr<QgsRenderContext> mContext;
520 std::unique_ptr<QgsFeatureRenderer> mRenderer;
521 std::unique_ptr<QgsVectorLayerFeatureSource> mSource;
522 int mMaxFeaturesToIndex = -1;
523 bool mIsIndexing = false;
524 bool mIsDestroying = false;
525 QgsFeatureIds mAddedFeatures;
526 QgsFeatureIds mDeletedFeatures;
527 QPointer<QgsPointLocatorInitTask> mInitTask;
528
541};
542
543
544#endif // QGSPOINTLOCATOR_H
@ Reverse
Reverse/inverse transform (from destination to source).
Definition qgis.h:2766
Represents a coordinate reference system (CRS).
Contains information about the context in which a coordinate transform is executed.
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 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.
Abstract base class for all 2D vector feature renderers.
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 edges - 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 vertices - builds a list of matches.
friend class QgsPointLocator_VisitorMiddlesInRect
friend class QgsPointLocator_VisitorNearestLineEndpoint
friend class QgsPointLocatorInitTask
friend class QgsPointLocator_VisitorEdgesInRect
Match nearestEdge(const QgsPointXY &point, double tolerance, QgsPointLocator::MatchFilter *filter=nullptr, bool relaxed=false)
Find nearest edge to the specified point - up to distance specified by tolerance Optional filter may ...
friend class TestQgsPointLocator
friend class QgsPointLocator_VisitorNearestVertex
QgsCoordinateReferenceSystem destinationCrs() const
Gets destination CRS - may be an invalid QgsCoordinateReferenceSystem if not doing OTF reprojection.
friend class QgsPointLocator_VisitorNearestCentroid
int cachedGeometryCount() const
Returns how many geometries are cached in the index.
MatchList pointInPolygon(const QgsPointXY &point, bool relaxed=false, QgsPointLocator::MatchFilter *filter=nullptr)
Find out if the point is in any polygons.
bool init(int maxFeaturesToIndex=-1, bool relaxed=false)
Prepare the index for queries.
QFlags< Type > Types
QgsVectorLayer * layer() const
Gets associated layer.
friend class QgsPointLocator_VisitorNearestMiddleOfSegment
MatchList verticesInRect(const QgsRectangle &rect, QgsPointLocator::MatchFilter *filter=nullptr, bool relaxed=false)
Find vertices within a specified rectangle This method is either blocking or non blocking according t...
class QList< QgsPointLocator::Match > MatchList
Match nearestVertex(const QgsPointXY &point, double tolerance, QgsPointLocator::MatchFilter *filter=nullptr, bool relaxed=false)
Find nearest vertex to the specified point - up to distance specified by tolerance Optional filter ma...
bool isIndexing() const
Returns true if the point locator is currently indexing the data.
friend class QgsPointLocator_VisitorNearestEdge
const QgsRectangle * extent() const
Gets extent of the area point locator covers - if nullptr then it caches the whole layer.
MatchList edgesInRect(const QgsRectangle &rect, QgsPointLocator::MatchFilter *filter=nullptr, bool relaxed=false)
Find edges within a specified rectangle Optional filter may discard unwanted matches.
bool hasIndex() const
Indicate whether the data have been already indexed.
friend class QgsPointLocator_VisitorVerticesInRect
Match nearestMiddleOfSegment(const QgsPointXY &point, double tolerance, QgsPointLocator::MatchFilter *filter=nullptr, bool relaxed=false)
Find nearest middle of segment to the specified point - up to distance specified by tolerance Optiona...
Match nearestCentroid(const QgsPointXY &point, double tolerance, QgsPointLocator::MatchFilter *filter=nullptr, bool relaxed=false)
Find nearest centroid to the specified point - up to distance specified by tolerance Optional filter ...
void initFinished(bool ok)
Emitted whenever index has been built and initialization is finished.
bool rebuildIndex(int maxFeaturesToIndex=-1)
friend class QgsPointLocator_VisitorCentroidsInRect
Match nearestArea(const QgsPointXY &point, double tolerance, QgsPointLocator::MatchFilter *filter=nullptr, bool relaxed=false)
Find nearest area to the specified point - up to distance specified by tolerance Optional filter may ...
Type
The type of a snap result or the filter type for a snap request.
@ Area
Snapped to an area.
@ MiddleOfSegment
Snapped to the middle of a segment.
@ Vertex
Snapped to a vertex. Can be a vertex of the geometry or an intersection.
@ All
Combination of all types. Note LineEndpoint is not included as endpoints made redundant by the presen...
@ Centroid
Snapped to a centroid.
@ Edge
Snapped to an edge.
@ LineEndpoint
Start or end points of lines only.
QgsPointLocator(QgsVectorLayer *layer, const QgsCoordinateReferenceSystem &destinationCrs=QgsCoordinateReferenceSystem(), const QgsCoordinateTransformContext &transformContext=QgsCoordinateTransformContext(), const QgsRectangle *extent=nullptr)
Construct point locator for a layer.
friend class QgsPointLocator_VisitorArea
Match nearestLineEndpoints(const QgsPointXY &point, double tolerance, QgsPointLocator::MatchFilter *filter=nullptr, bool relaxed=false)
Find nearest line endpoint (start or end vertex) to the specified point - up to distance specified by...
Represents a 2D point.
Definition qgspointxy.h:62
Point geometry type, with support for z-dimension and m-values.
Definition qgspoint.h:53
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 dataset.
static Q_INVOKABLE bool isCurvedType(Qgis::WkbType type)
Returns true if the WKB type is a curved type or can contain curved geometries.
#define SIP_ENUM_BASETYPE(type)
Definition qgis_sip.h:274
#define SIP_SKIP
Definition qgis_sip.h:133
#define SIP_OUT
Definition qgis_sip.h:57
QSet< QgsFeatureId > QgsFeatureIds
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features
#define QgsDebugError(str)
Definition qgslogger.h:59
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