QGIS API Documentation  3.27.0-Master (e113457133)
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 
19 class QgsPointXY;
20 class QgsFeatureRenderer;
21 class QgsRenderContext;
22 class QgsRectangle;
24 
25 #include "qgis_core.h"
26 #include "qgspointxy.h"
28 #include "qgscoordinatetransform.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 
101 class 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 
255  void edgePoints( QgsPointXY &pt1 SIP_OUT, QgsPointXY &pt2 SIP_OUT ) const
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 
349  struct MatchFilter
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:125
QgsPoint vertexAt(int atVertex) const
Returns coordinates of a vertex.
Q_GADGET bool isNull
Definition: qgsgeometry.h:127
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:
const QgsRectangle * extent() const
Gets extent of the area point locator covers - if nullptr then it caches the whole layer.
int cachedGeometryCount() const
Returns how many geometries are cached in the index.
class QList< QgsPointLocator::Match > MatchList
QgsVectorLayer * layer() const
Gets associated layer.
bool isIndexing() const
Returns true if the point locator is currently indexing the data.
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
QgsVectorLayer * layer() const
The vector layer where the snap occurred.
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.
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