QGIS API Documentation  3.22.4-Białowieża (ce8e65e95e)
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 == other.mEdgePoints &&
321  mCentroid == other.mCentroid &&
322  mMiddleOfSegment == other.mMiddleOfSegment;
323  }
324 
325  protected:
326  Type mType = Invalid;
327  double mDist = 0;
329  QgsVectorLayer *mLayer = nullptr;
330  QgsFeatureId mFid = 0;
331  int mVertexIndex = 0; // e.g. vertex index
332  QgsPointXY mEdgePoints[2];
335  };
336 
337 #ifndef SIP_RUN
338  typedef class QList<QgsPointLocator::Match> MatchList;
339 #else
340  typedef QList<QgsPointLocator::Match> MatchList;
341 #endif
342 
348  struct MatchFilter
349  {
350  virtual ~MatchFilter() = default;
351  virtual bool acceptMatch( const QgsPointLocator::Match &match ) = 0;
352  };
353 
354  // intersection queries
355 
361  Match nearestVertex( const QgsPointXY &point, double tolerance, QgsPointLocator::MatchFilter *filter = nullptr, bool relaxed = false );
362 
369  Match nearestCentroid( const QgsPointXY &point, double tolerance, QgsPointLocator::MatchFilter *filter = nullptr, bool relaxed = false );
370 
377  Match nearestMiddleOfSegment( const QgsPointXY &point, double tolerance, QgsPointLocator::MatchFilter *filter = nullptr, bool relaxed = false );
378 
385  Match nearestLineEndpoints( const QgsPointXY &point, double tolerance, QgsPointLocator::MatchFilter *filter = nullptr, bool relaxed = false );
386 
392  Match nearestEdge( const QgsPointXY &point, double tolerance, QgsPointLocator::MatchFilter *filter = nullptr, bool relaxed = false );
393 
402  Match nearestArea( const QgsPointXY &point, double tolerance, QgsPointLocator::MatchFilter *filter = nullptr, bool relaxed = false );
403 
409  MatchList edgesInRect( const QgsRectangle &rect, QgsPointLocator::MatchFilter *filter = nullptr, bool relaxed = false );
410 
415  MatchList edgesInRect( const QgsPointXY &point, double tolerance, QgsPointLocator::MatchFilter *filter = nullptr, bool relaxed = false );
416 
423  MatchList verticesInRect( const QgsRectangle &rect, QgsPointLocator::MatchFilter *filter = nullptr, bool relaxed = false );
424 
430  MatchList verticesInRect( const QgsPointXY &point, double tolerance, QgsPointLocator::MatchFilter *filter = nullptr, bool relaxed = false );
431 
432  // point-in-polygon query
433 
434  // TODO: function to return just the first match?
435 
441  MatchList pointInPolygon( const QgsPointXY &point, bool relaxed = false );
442 
447  int cachedGeometryCount() const { return mGeoms.count(); }
448 
455  bool isIndexing() const { return mIsIndexing; }
456 
461  void waitForIndexingFinished();
462 
463  signals:
464 
470  void initFinished( bool ok );
471 
472  protected:
473  bool rebuildIndex( int maxFeaturesToIndex = -1 );
474 
475  protected slots:
476  void destroyIndex();
477  private slots:
478  void onInitTaskFinished();
479  void onFeatureAdded( QgsFeatureId fid );
480  void onFeatureDeleted( QgsFeatureId fid );
481  void onGeometryChanged( QgsFeatureId fid, const QgsGeometry &geom );
482  void onAttributeValueChanged( QgsFeatureId fid, int idx, const QVariant &value );
483 
484  private:
485 
490  bool prepare( bool relaxed );
491 
493  std::unique_ptr< SpatialIndex::IStorageManager > mStorage;
494 
495  QHash<QgsFeatureId, QgsGeometry *> mGeoms;
496  std::unique_ptr< SpatialIndex::ISpatialIndex > mRTree;
497 
499  bool mIsEmptyLayer = false;
500 
501 
503  QgsCoordinateTransform mTransform;
504  QgsVectorLayer *mLayer = nullptr;
505  std::unique_ptr< QgsRectangle > mExtent;
506 
507  std::unique_ptr<QgsRenderContext> mContext;
508  std::unique_ptr<QgsFeatureRenderer> mRenderer;
509  std::unique_ptr<QgsVectorLayerFeatureSource> mSource;
510  int mMaxFeaturesToIndex = -1;
511  bool mIsIndexing = false;
512  bool mIsDestroying = false;
513  QgsFeatureIds mAddedFeatures;
514  QgsFeatureIds mDeletedFeatures;
515  QPointer<QgsPointLocatorInitTask> mInitTask;
516 
524  friend class QgsPointLocatorInitTask;
525  friend class TestQgsPointLocator;
529 };
530 
531 
532 #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:44
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