QGIS API Documentation  3.16.0-Hannover (43b64b13f3)
qgspointlocator.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgspointlocator.cpp
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 #include "qgspointlocator.h"
17 
18 #include "qgsfeatureiterator.h"
19 #include "qgsgeometry.h"
20 #include "qgsvectorlayer.h"
21 #include "qgswkbptr.h"
22 #include "qgis.h"
23 #include "qgslogger.h"
24 #include "qgsrenderer.h"
25 #include "qgsapplication.h"
28 #include "qgslinestring.h"
30 #include <spatialindex/SpatialIndex.h>
31 
32 #include <QLinkedListIterator>
33 #include <QtConcurrent>
34 
35 using namespace SpatialIndex;
36 
37 
38 
39 static SpatialIndex::Point point2point( const QgsPointXY &point )
40 {
41  double plow[2] = { point.x(), point.y() };
42  return Point( plow, 2 );
43 }
44 
45 
46 static SpatialIndex::Region rect2region( const QgsRectangle &rect )
47 {
48  double pLow[2] = { rect.xMinimum(), rect.yMinimum() };
49  double pHigh[2] = { rect.xMaximum(), rect.yMaximum() };
50  return SpatialIndex::Region( pLow, pHigh, 2 );
51 }
52 
53 
54 // Ahh.... another magic number. Taken from QgsVectorLayer::snapToGeometry() call to closestSegmentWithContext().
55 // The default epsilon used for sqrDistToSegment (1e-8) is too high when working with lat/lon coordinates
56 // I still do not fully understand why the sqrDistToSegment() code uses epsilon and if the square distance
57 // is lower than epsilon it will have a special logic...
58 static const double POINT_LOC_EPSILON = 1e-12;
59 
61 
62 
68 class QgsPointLocator_Stream : public IDataStream
69 {
70  public:
71  explicit QgsPointLocator_Stream( const QLinkedList<RTree::Data *> &dataList )
72  : mDataList( dataList )
73  , mIt( mDataList )
74  { }
75 
76  IData *getNext() override { return mIt.next(); }
77  bool hasNext() override { return mIt.hasNext(); }
78 
79  uint32_t size() override { Q_ASSERT( false && "not available" ); return 0; }
80  void rewind() override { Q_ASSERT( false && "not available" ); }
81 
82  private:
83  QLinkedList<RTree::Data *> mDataList;
84  QLinkedListIterator<RTree::Data *> mIt;
85 };
86 
87 
89 
90 
96 class QgsPointLocator_VisitorNearestVertex : public IVisitor
97 {
98  public:
100  : mLocator( pl )
101  , mBest( m )
102  , mSrcPoint( srcPoint )
103  , mFilter( filter )
104  {}
105 
106  void visitNode( const INode &n ) override { Q_UNUSED( n ) }
107  void visitData( std::vector<const IData *> &v ) override { Q_UNUSED( v ) }
108 
109  void visitData( const IData &d ) override
110  {
111  QgsFeatureId id = d.getIdentifier();
112  QgsGeometry *geom = mLocator->mGeoms.value( id );
113  int vertexIndex, beforeVertex, afterVertex;
114  double sqrDist;
115 
116  QgsPointXY pt = geom->closestVertex( mSrcPoint, vertexIndex, beforeVertex, afterVertex, sqrDist );
117  if ( sqrDist < 0 )
118  return; // probably empty geometry
119 
120  QgsPointLocator::Match m( QgsPointLocator::Vertex, mLocator->mLayer, id, std::sqrt( sqrDist ), pt, vertexIndex );
121  // in range queries the filter may reject some matches
122  if ( mFilter && !mFilter->acceptMatch( m ) )
123  return;
124 
125  if ( !mBest.isValid() || m.distance() < mBest.distance() )
126  mBest = m;
127  }
128 
129  private:
130  QgsPointLocator *mLocator = nullptr;
131  QgsPointLocator::Match &mBest;
132  QgsPointXY mSrcPoint;
133  QgsPointLocator::MatchFilter *mFilter = nullptr;
134 };
135 
136 
137 
145 {
146  public:
147 
155  : mLocator( pl )
156  , mBest( m )
157  , mSrcPoint( srcPoint )
158  , mFilter( filter )
159  {}
160 
161  void visitNode( const INode &n ) override { Q_UNUSED( n ); }
162  void visitData( std::vector<const IData *> &v ) override { Q_UNUSED( v ); }
163 
164  void visitData( const IData &d ) override
165  {
166  QgsFeatureId id = d.getIdentifier();
167  QgsGeometry *geom = mLocator->mGeoms.value( id );
168 
169  QgsPointXY pt = geom->centroid().asPoint();
170 
171  QgsPointLocator::Match m( QgsPointLocator::Centroid, mLocator->mLayer, id, std::sqrt( mSrcPoint.sqrDist( pt ) ), pt, -1 );
172  // in range queries the filter may reject some matches
173  if ( mFilter && !mFilter->acceptMatch( m ) )
174  return;
175 
176  if ( !mBest.isValid() || m.distance() < mBest.distance() )
177  mBest = m;
178 
179  }
180 
181  private:
182  QgsPointLocator *mLocator = nullptr;
183  QgsPointLocator::Match &mBest;
184  QgsPointXY mSrcPoint;
185  QgsPointLocator::MatchFilter *mFilter = nullptr;
186 };
187 
189 
197 {
198  public:
199 
207  : mLocator( pl )
208  , mBest( m )
209  , mSrcPoint( srcPoint )
210  , mFilter( filter )
211  {}
212 
213  void visitNode( const INode &n ) override { Q_UNUSED( n ); }
214  void visitData( std::vector<const IData *> &v ) override { Q_UNUSED( v ); }
215 
216  void visitData( const IData &d ) override
217  {
218  QgsFeatureId id = d.getIdentifier();
219  QgsGeometry *geom = mLocator->mGeoms.value( id );
220  QgsPointXY pt;
221  int afterVertex;
222  double sqrDist = geom->closestSegmentWithContext( mSrcPoint, pt, afterVertex, nullptr, POINT_LOC_EPSILON );
223  if ( sqrDist < 0 )
224  return;
225 
226  QgsPointXY edgePoints[2];
227  edgePoints[0] = geom->vertexAt( afterVertex - 1 );
228  edgePoints[1] = geom->vertexAt( afterVertex );
229  pt = QgsPointXY( ( edgePoints[0].x() + edgePoints[1].x() ) / 2.0, ( edgePoints[0].y() + edgePoints[1].y() ) / 2.0 );
230 
231  QgsPointLocator::Match m( QgsPointLocator::MiddleOfSegment, mLocator->mLayer, id, std::sqrt( mSrcPoint.sqrDist( pt ) ), pt, afterVertex - 1 );
232  // in range queries the filter may reject some matches
233  if ( mFilter && !mFilter->acceptMatch( m ) )
234  return;
235 
236  if ( !mBest.isValid() || m.distance() < mBest.distance() )
237  mBest = m;
238 
239  }
240 
241  private:
242  QgsPointLocator *mLocator = nullptr;
243  QgsPointLocator::Match &mBest;
244  QgsPointXY mSrcPoint;
245  QgsPointLocator::MatchFilter *mFilter = nullptr;
246 };
247 
249 
250 
256 class QgsPointLocator_VisitorNearestEdge : public IVisitor
257 {
258  public:
260  : mLocator( pl )
261  , mBest( m )
262  , mSrcPoint( srcPoint )
263  , mFilter( filter )
264  {}
265 
266  void visitNode( const INode &n ) override { Q_UNUSED( n ) }
267  void visitData( std::vector<const IData *> &v ) override { Q_UNUSED( v ) }
268 
269  void visitData( const IData &d ) override
270  {
271  QgsFeatureId id = d.getIdentifier();
272  QgsGeometry *geom = mLocator->mGeoms.value( id );
273  QgsPointXY pt;
274  int afterVertex;
275  double sqrDist = geom->closestSegmentWithContext( mSrcPoint, pt, afterVertex, nullptr, POINT_LOC_EPSILON );
276  if ( sqrDist < 0 )
277  return;
278 
279  QgsPointXY edgePoints[2];
280  edgePoints[0] = geom->vertexAt( afterVertex - 1 );
281  edgePoints[1] = geom->vertexAt( afterVertex );
282  QgsPointLocator::Match m( QgsPointLocator::Edge, mLocator->mLayer, id, std::sqrt( sqrDist ), pt, afterVertex - 1, edgePoints );
283  // in range queries the filter may reject some matches
284  if ( mFilter && !mFilter->acceptMatch( m ) )
285  return;
286 
287  if ( !mBest.isValid() || m.distance() < mBest.distance() )
288  mBest = m;
289  }
290 
291  private:
292  QgsPointLocator *mLocator = nullptr;
293  QgsPointLocator::Match &mBest;
294  QgsPointXY mSrcPoint;
295  QgsPointLocator::MatchFilter *mFilter = nullptr;
296 };
297 
298 
300 
306 class QgsPointLocator_VisitorArea : public IVisitor
307 {
308  public:
311  : mLocator( pl )
312  , mList( list )
313  , mGeomPt( QgsGeometry::fromPointXY( origPt ) )
314  {}
315 
316  void visitNode( const INode &n ) override { Q_UNUSED( n ) }
317  void visitData( std::vector<const IData *> &v ) override { Q_UNUSED( v ) }
318 
319  void visitData( const IData &d ) override
320  {
321  QgsFeatureId id = d.getIdentifier();
322  QgsGeometry *g = mLocator->mGeoms.value( id );
323  if ( g->intersects( mGeomPt ) )
324  mList << QgsPointLocator::Match( QgsPointLocator::Area, mLocator->mLayer, id, 0, mGeomPt.asPoint() );
325  }
326  private:
327  QgsPointLocator *mLocator = nullptr;
329  QgsGeometry mGeomPt;
330 };
331 
332 
334 
335 // code adapted from
336 // http://en.wikipedia.org/wiki/Cohen%E2%80%93Sutherland_algorithm
338 {
339  explicit _CohenSutherland( const QgsRectangle &rect ) : mRect( rect ) {}
340 
341  typedef int OutCode;
342 
343  static const int INSIDE = 0; // 0000
344  static const int LEFT = 1; // 0001
345  static const int RIGHT = 2; // 0010
346  static const int BOTTOM = 4; // 0100
347  static const int TOP = 8; // 1000
348 
350 
351  OutCode computeOutCode( double x, double y )
352  {
353  OutCode code = INSIDE; // initialized as being inside of clip window
354  if ( x < mRect.xMinimum() ) // to the left of clip window
355  code |= LEFT;
356  else if ( x > mRect.xMaximum() ) // to the right of clip window
357  code |= RIGHT;
358  if ( y < mRect.yMinimum() ) // below the clip window
359  code |= BOTTOM;
360  else if ( y > mRect.yMaximum() ) // above the clip window
361  code |= TOP;
362  return code;
363  }
364 
365  bool isSegmentInRect( double x0, double y0, double x1, double y1 )
366  {
367  // compute outcodes for P0, P1, and whatever point lies outside the clip rectangle
368  OutCode outcode0 = computeOutCode( x0, y0 );
369  OutCode outcode1 = computeOutCode( x1, y1 );
370  bool accept = false;
371 
372  while ( true )
373  {
374  if ( !( outcode0 | outcode1 ) )
375  {
376  // Bitwise OR is 0. Trivially accept and get out of loop
377  accept = true;
378  break;
379  }
380  else if ( outcode0 & outcode1 )
381  {
382  // Bitwise AND is not 0. Trivially reject and get out of loop
383  break;
384  }
385  else
386  {
387  // failed both tests, so calculate the line segment to clip
388  // from an outside point to an intersection with clip edge
389  double x, y;
390 
391  // At least one endpoint is outside the clip rectangle; pick it.
392  OutCode outcodeOut = outcode0 ? outcode0 : outcode1;
393 
394  // Now find the intersection point;
395  // use formulas y = y0 + slope * (x - x0), x = x0 + (1 / slope) * (y - y0)
396  if ( outcodeOut & TOP )
397  {
398  // point is above the clip rectangle
399  x = x0 + ( x1 - x0 ) * ( mRect.yMaximum() - y0 ) / ( y1 - y0 );
400  y = mRect.yMaximum();
401  }
402  else if ( outcodeOut & BOTTOM )
403  {
404  // point is below the clip rectangle
405  x = x0 + ( x1 - x0 ) * ( mRect.yMinimum() - y0 ) / ( y1 - y0 );
406  y = mRect.yMinimum();
407  }
408  else if ( outcodeOut & RIGHT )
409  {
410  // point is to the right of clip rectangle
411  y = y0 + ( y1 - y0 ) * ( mRect.xMaximum() - x0 ) / ( x1 - x0 );
412  x = mRect.xMaximum();
413  }
414  else if ( outcodeOut & LEFT )
415  {
416  // point is to the left of clip rectangle
417  y = y0 + ( y1 - y0 ) * ( mRect.xMinimum() - x0 ) / ( x1 - x0 );
418  x = mRect.xMinimum();
419  }
420  else
421  break;
422 
423  // Now we move outside point to intersection point to clip
424  // and get ready for next pass.
425  if ( outcodeOut == outcode0 )
426  {
427  x0 = x;
428  y0 = y;
429  outcode0 = computeOutCode( x0, y0 );
430  }
431  else
432  {
433  x1 = x;
434  y1 = y;
435  outcode1 = computeOutCode( x1, y1 );
436  }
437  }
438  }
439  return accept;
440  }
441 };
442 
443 
444 static QgsPointLocator::MatchList _geometrySegmentsInRect( QgsGeometry *geom, const QgsRectangle &rect, QgsVectorLayer *vl, QgsFeatureId fid )
445 {
446  // this code is stupidly based on QgsGeometry::closestSegmentWithContext
447  // we need iterator for segments...
448 
450 
451  // geom is converted to a MultiCurve
452  QgsGeometry straightGeom = geom->convertToType( QgsWkbTypes::LineGeometry, true );
453  // and convert to straight segemnt / converts curve to linestring
454  straightGeom.convertToStraightSegment();
455 
456  // so, you must have multilinestring
457  //
458  // Special case: Intersections cannot be done on an empty linestring like
459  // QgsGeometry(QgsLineString()) or QgsGeometry::fromWkt("LINESTRING EMPTY")
460  if ( straightGeom.isEmpty() || ( ( straightGeom.type() != QgsWkbTypes::LineGeometry ) && ( !straightGeom.isMultipart() ) ) )
461  return lst;
462 
463  _CohenSutherland cs( rect );
464 
465  int pointIndex = 0;
466  for ( auto part = straightGeom.const_parts_begin(); part != straightGeom.const_parts_end(); ++part )
467  {
468  // Checking for invalid linestrings
469  // A linestring should/(must?) have at least two points.
470  QgsCurve *curve = qgsgeometry_cast<QgsCurve *>( *part );
471  Q_ASSERT( !curve->hasCurvedSegments() );
472  if ( curve->numPoints() < 2 )
473  continue;
474 
475  QgsAbstractGeometry::vertex_iterator it = ( *part )->vertices_begin();
476  QgsPointXY prevPoint( *it );
477  it++;
478  while ( it != ( *part )->vertices_end() )
479  {
480  QgsPointXY thisPoint( *it );
481  if ( cs.isSegmentInRect( prevPoint.x(), prevPoint.y(), thisPoint.x(), thisPoint.y() ) )
482  {
483  QgsPointXY edgePoints[2];
484  edgePoints[0] = prevPoint;
485  edgePoints[1] = thisPoint;
486  lst << QgsPointLocator::Match( QgsPointLocator::Edge, vl, fid, 0, QgsPointXY(), pointIndex - 1, edgePoints );
487  }
488  prevPoint = QgsPointXY( *it );
489  it++;
490  pointIndex += 1;
491 
492  }
493  }
494  return lst;
495 }
496 
502 class QgsPointLocator_VisitorEdgesInRect : public IVisitor
503 {
504  public:
506  : mLocator( pl )
507  , mList( lst )
508  , mSrcRect( srcRect )
509  , mFilter( filter )
510  {}
511 
512  void visitNode( const INode &n ) override { Q_UNUSED( n ) }
513  void visitData( std::vector<const IData *> &v ) override { Q_UNUSED( v ) }
514 
515  void visitData( const IData &d ) override
516  {
517  QgsFeatureId id = d.getIdentifier();
518  QgsGeometry *geom = mLocator->mGeoms.value( id );
519 
520  const auto segmentsInRect {_geometrySegmentsInRect( geom, mSrcRect, mLocator->mLayer, id )};
521  for ( const QgsPointLocator::Match &m : segmentsInRect )
522  {
523  // in range queries the filter may reject some matches
524  if ( mFilter && !mFilter->acceptMatch( m ) )
525  continue;
526 
527  mList << m;
528  }
529  }
530 
531  private:
532  QgsPointLocator *mLocator = nullptr;
534  QgsRectangle mSrcRect;
535  QgsPointLocator::MatchFilter *mFilter = nullptr;
536 };
537 
539 
547 {
548  public:
551  : mLocator( pl )
552  , mList( lst )
553  , mSrcRect( srcRect )
554  , mFilter( filter )
555  {}
556 
557  void visitNode( const INode &n ) override { Q_UNUSED( n ) }
558  void visitData( std::vector<const IData *> &v ) override { Q_UNUSED( v ) }
559 
560  void visitData( const IData &d ) override
561  {
562  QgsFeatureId id = d.getIdentifier();
563  const QgsGeometry *geom = mLocator->mGeoms.value( id );
564 
565  for ( QgsAbstractGeometry::vertex_iterator it = geom->vertices_begin(); it != geom->vertices_end(); ++it )
566  {
567  if ( mSrcRect.contains( *it ) )
568  {
569  QgsPointLocator::Match m( QgsPointLocator::Vertex, mLocator->mLayer, id, 0, *it, geom->vertexNrFromVertexId( it.vertexId() ) );
570 
571  // in range queries the filter may reject some matches
572  if ( mFilter && !mFilter->acceptMatch( m ) )
573  continue;
574 
575  mList << m;
576  }
577  }
578  }
579 
580  private:
581  QgsPointLocator *mLocator = nullptr;
583  QgsRectangle mSrcRect;
584  QgsPointLocator::MatchFilter *mFilter = nullptr;
585 };
586 
594 {
595  public:
598  : mLocator( pl )
599  , mList( lst )
600  , mSrcRect( srcRect )
601  , mFilter( filter )
602  {}
603 
604  void visitNode( const INode &n ) override { Q_UNUSED( n ); }
605  void visitData( std::vector<const IData *> &v ) override { Q_UNUSED( v ); }
606 
607  void visitData( const IData &d ) override
608  {
609  QgsFeatureId id = d.getIdentifier();
610  const QgsGeometry *geom = mLocator->mGeoms.value( id );
611  const QgsPointXY centroid = geom->centroid().asPoint();
612  if ( mSrcRect.contains( centroid ) )
613  {
614  QgsPointLocator::Match m( QgsPointLocator::Centroid, mLocator->mLayer, id, 0, centroid, -1 );
615 
616  // in range queries the filter may reject some matches
617  if ( !( mFilter && !mFilter->acceptMatch( m ) ) )
618  mList << m;
619  }
620  }
621 
622  private:
623  QgsPointLocator *mLocator = nullptr;
625  QgsRectangle mSrcRect;
626  QgsPointLocator::MatchFilter *mFilter = nullptr;
627 };
628 
636 {
637  public:
640  : mLocator( pl )
641  , mList( lst )
642  , mSrcRect( srcRect )
643  , mFilter( filter )
644  {}
645 
646  void visitNode( const INode &n ) override { Q_UNUSED( n ); }
647  void visitData( std::vector<const IData *> &v ) override { Q_UNUSED( v ); }
648 
649  void visitData( const IData &d ) override
650  {
651  QgsFeatureId id = d.getIdentifier();
652  const QgsGeometry *geom = mLocator->mGeoms.value( id );
653 
654  for ( QgsAbstractGeometry::const_part_iterator itPart = geom->const_parts_begin() ; itPart != geom->const_parts_end() ; ++itPart )
655  {
656  QgsAbstractGeometry::vertex_iterator it = ( *itPart )->vertices_begin();
657  QgsAbstractGeometry::vertex_iterator itPrevious = ( *itPart )->vertices_begin();
658  it++;
659  for ( ; it != geom->vertices_end(); ++it, ++itPrevious )
660  {
661  QgsPointXY pt( ( ( *itPrevious ).x() + ( *it ).x() ) / 2.0, ( ( *itPrevious ).y() + ( *it ).y() ) / 2.0 );
662  if ( mSrcRect.contains( pt ) )
663  {
664  QgsPointLocator::Match m( QgsPointLocator::MiddleOfSegment, mLocator->mLayer, id, 0, pt, geom->vertexNrFromVertexId( it.vertexId() ) );
665 
666  // in range queries the filter may reject some matches
667  if ( mFilter && !mFilter->acceptMatch( m ) )
668  continue;
669 
670  mList << m;
671  }
672  }
673  }
674  }
675 
676  private:
677  QgsPointLocator *mLocator = nullptr;
679  QgsRectangle mSrcRect;
680  QgsPointLocator::MatchFilter *mFilter = nullptr;
681 };
682 
684 #include <QStack>
685 
691 class QgsPointLocator_DumpTree : public SpatialIndex::IQueryStrategy
692 {
693  private:
694  QStack<id_type> ids;
695 
696  public:
697 
698  void getNextEntry( const IEntry &entry, id_type &nextEntry, bool &hasNext ) override
699  {
700  const INode *n = dynamic_cast<const INode *>( &entry );
701  if ( !n )
702  return;
703 
704  QgsDebugMsgLevel( QStringLiteral( "NODE: %1" ).arg( n->getIdentifier() ), 4 );
705  if ( n->getLevel() > 0 )
706  {
707  // inner nodes
708  for ( uint32_t cChild = 0; cChild < n->getChildrenCount(); cChild++ )
709  {
710  QgsDebugMsgLevel( QStringLiteral( "- CH: %1" ).arg( n->getChildIdentifier( cChild ) ), 4 );
711  ids.push( n->getChildIdentifier( cChild ) );
712  }
713  }
714  else
715  {
716  // leaves
717  for ( uint32_t cChild = 0; cChild < n->getChildrenCount(); cChild++ )
718  {
719  QgsDebugMsgLevel( QStringLiteral( "- L: %1" ).arg( n->getChildIdentifier( cChild ) ), 4 );
720  }
721  }
722 
723  if ( ! ids.empty() )
724  {
725  nextEntry = ids.back();
726  ids.pop();
727  hasNext = true;
728  }
729  else
730  hasNext = false;
731  }
732 };
733 
735 
736 
738  : mLayer( layer )
739 {
740  if ( destCRS.isValid() )
741  {
742  mTransform = QgsCoordinateTransform( layer->crs(), destCRS, transformContext );
743  }
744 
745  setExtent( extent );
746 
747  mStorage.reset( StorageManager::createNewMemoryStorageManager() );
748 
749  connect( mLayer, &QgsVectorLayer::featureAdded, this, &QgsPointLocator::onFeatureAdded );
750  connect( mLayer, &QgsVectorLayer::featureDeleted, this, &QgsPointLocator::onFeatureDeleted );
751  connect( mLayer, &QgsVectorLayer::geometryChanged, this, &QgsPointLocator::onGeometryChanged );
752  connect( mLayer, &QgsVectorLayer::attributeValueChanged, this, &QgsPointLocator::onAttributeValueChanged );
754 }
755 
756 
758 {
759  // don't delete a locator if there is an indexing task running on it
760  mIsDestroying = true;
761  if ( mIsIndexing )
763 
764  destroyIndex();
765 }
766 
768 {
769  return mTransform.isValid() ? mTransform.destinationCrs() : QgsCoordinateReferenceSystem();
770 }
771 
773 {
774  if ( mIsIndexing )
775  // already indexing, return!
776  return;
777 
778  mExtent.reset( extent ? new QgsRectangle( *extent ) : nullptr );
779 
780  destroyIndex();
781 }
782 
784 {
785  if ( mIsIndexing )
786  // already indexing, return!
787  return;
788 
789  disconnect( mLayer, &QgsVectorLayer::styleChanged, this, &QgsPointLocator::destroyIndex );
790 
791  destroyIndex();
792  mContext.reset( nullptr );
793 
794  if ( context )
795  {
796  mContext = std::unique_ptr<QgsRenderContext>( new QgsRenderContext( *context ) );
798  }
799 
800 }
801 
802 void QgsPointLocator::onInitTaskFinished()
803 {
804  // Check that we don't call this method twice, when calling waitForFinished
805  // for instance (because of taskCompleted signal)
806  if ( !mIsIndexing )
807  return;
808 
809  if ( mIsDestroying )
810  return;
811 
812  mIsIndexing = false;
813  mRenderer.reset();
814  mSource.reset();
815 
816  // treat added and deleted feature while indexing
817  for ( QgsFeatureId fid : mAddedFeatures )
818  onFeatureAdded( fid );
819  mAddedFeatures.clear();
820 
821  for ( QgsFeatureId fid : mDeletedFeatures )
822  onFeatureDeleted( fid );
823  mDeletedFeatures.clear();
824 
825  emit initFinished( mInitTask->isBuildOK() );
826 }
827 
828 bool QgsPointLocator::init( int maxFeaturesToIndex, bool relaxed )
829 {
830  const QgsWkbTypes::GeometryType geomType = mLayer->geometryType();
831  if ( geomType == QgsWkbTypes::NullGeometry // nothing to index
832  || hasIndex()
833  || mIsIndexing ) // already indexing, return!
834  return true;
835 
836  if ( !mLayer->dataProvider()
837  || !mLayer->dataProvider()->isValid() )
838  return false;
839 
840  mRenderer.reset( mLayer->renderer() ? mLayer->renderer()->clone() : nullptr );
841  mSource.reset( new QgsVectorLayerFeatureSource( mLayer ) );
842 
843  if ( mContext )
844  {
845  mContext->expressionContext() << QgsExpressionContextUtils::layerScope( mLayer );
846  }
847 
848  mIsIndexing = true;
849 
850  if ( relaxed )
851  {
852  mInitTask = new QgsPointLocatorInitTask( this );
853  connect( mInitTask, &QgsPointLocatorInitTask::taskTerminated, this, &QgsPointLocator::onInitTaskFinished );
854  connect( mInitTask, &QgsPointLocatorInitTask::taskCompleted, this, &QgsPointLocator::onInitTaskFinished );
855  QgsApplication::taskManager()->addTask( mInitTask );
856  return true;
857  }
858  else
859  {
860  const bool ok = rebuildIndex( maxFeaturesToIndex );
861  mIsIndexing = false;
862  emit initFinished( ok );
863  return ok;
864  }
865 }
866 
868 {
869  mInitTask->waitForFinished();
870 
871  if ( !mIsDestroying )
872  onInitTaskFinished();
873 }
874 
876 {
877  return mIsIndexing || mRTree || mIsEmptyLayer;
878 }
879 
880 bool QgsPointLocator::prepare( bool relaxed )
881 {
882  if ( mIsIndexing )
883  {
884  if ( relaxed )
885  return false;
886  else
888  }
889 
890  if ( !mRTree )
891  {
892  init( -1, relaxed );
893  if ( ( relaxed && mIsIndexing ) || !mRTree ) // relaxed mode and currently indexing or still invalid?
894  return false;
895  }
896 
897  return true;
898 }
899 
900 bool QgsPointLocator::rebuildIndex( int maxFeaturesToIndex )
901 {
902  QElapsedTimer t;
903  t.start();
904 
905  QgsDebugMsgLevel( QStringLiteral( "RebuildIndex start : %1" ).arg( mSource->id() ), 2 );
906 
907  destroyIndex();
908 
909  QLinkedList<RTree::Data *> dataList;
910  QgsFeature f;
911 
912  QgsFeatureRequest request;
913  request.setNoAttributes();
914 
915  if ( mExtent )
916  {
917  QgsRectangle rect = *mExtent;
918  if ( mTransform.isValid() )
919  {
920  try
921  {
923  }
924  catch ( const QgsException &e )
925  {
926  Q_UNUSED( e )
927  // See https://github.com/qgis/QGIS/issues/20749
928  QgsDebugMsg( QStringLiteral( "could not transform bounding box to map, skipping the snap filter (%1)" ).arg( e.what() ) );
929  }
930  }
931  request.setFilterRect( rect );
932  }
933 
934  bool filter = false;
935  QgsRenderContext *ctx = nullptr;
936  if ( mContext )
937  {
938  ctx = mContext.get();
939  if ( mRenderer )
940  {
941  // setup scale for scale dependent visibility (rule based)
942  mRenderer->startRender( *ctx, mSource->fields() );
943  filter = mRenderer->capabilities() & QgsFeatureRenderer::Filter;
944  request.setSubsetOfAttributes( mRenderer->usedAttributes( *ctx ), mSource->fields() );
945  }
946  }
947 
948  QgsFeatureIterator fi = mSource->getFeatures( request );
949  int indexedCount = 0;
950 
951  while ( fi.nextFeature( f ) )
952  {
953  if ( !f.hasGeometry() )
954  continue;
955 
956  if ( filter && ctx && mRenderer )
957  {
958  ctx->expressionContext().setFeature( f );
959  if ( !mRenderer->willRenderFeature( f, *ctx ) )
960  {
961  continue;
962  }
963  }
964 
965  if ( mTransform.isValid() )
966  {
967  try
968  {
969  QgsGeometry transformedGeometry = f.geometry();
970  transformedGeometry.transform( mTransform );
971  f.setGeometry( transformedGeometry );
972  }
973  catch ( const QgsException &e )
974  {
975  Q_UNUSED( e )
976  // See https://github.com/qgis/QGIS/issues/20749
977  QgsDebugMsg( QStringLiteral( "could not transform geometry to map, skipping the snap for it (%1)" ).arg( e.what() ) );
978  continue;
979  }
980  }
981 
982  const QgsRectangle bbox = f.geometry().boundingBox();
983  if ( bbox.isFinite() )
984  {
985  SpatialIndex::Region r( rect2region( bbox ) );
986  dataList << new RTree::Data( 0, nullptr, r, f.id() );
987 
988  if ( mGeoms.contains( f.id() ) )
989  delete mGeoms.take( f.id() );
990  mGeoms[f.id()] = new QgsGeometry( f.geometry() );
991  ++indexedCount;
992  }
993 
994  if ( maxFeaturesToIndex != -1 && indexedCount > maxFeaturesToIndex )
995  {
996  qDeleteAll( dataList );
997  destroyIndex();
998  return false;
999  }
1000  }
1001 
1002  // R-Tree parameters
1003  double fillFactor = 0.7;
1004  unsigned long indexCapacity = 10;
1005  unsigned long leafCapacity = 10;
1006  unsigned long dimension = 2;
1007  RTree::RTreeVariant variant = RTree::RV_RSTAR;
1008  SpatialIndex::id_type indexId;
1009 
1010  if ( dataList.isEmpty() )
1011  {
1012  mIsEmptyLayer = true;
1013  return true; // no features
1014  }
1015 
1016  QgsPointLocator_Stream stream( dataList );
1017  mRTree.reset( RTree::createAndBulkLoadNewRTree( RTree::BLM_STR, stream, *mStorage, fillFactor, indexCapacity,
1018  leafCapacity, dimension, variant, indexId ) );
1019 
1020  if ( ctx && mRenderer )
1021  {
1022  mRenderer->stopRender( *ctx );
1023  }
1024 
1025  QgsDebugMsgLevel( QStringLiteral( "RebuildIndex end : %1 ms (%2)" ).arg( t.elapsed() ).arg( mSource->id() ), 2 );
1026 
1027  return true;
1028 }
1029 
1030 
1032 {
1033  mRTree.reset();
1034 
1035  mIsEmptyLayer = false;
1036 
1037  qDeleteAll( mGeoms );
1038 
1039  mGeoms.clear();
1040 }
1041 
1042 void QgsPointLocator::onFeatureAdded( QgsFeatureId fid )
1043 {
1044  if ( mIsIndexing )
1045  {
1046  // will modify index once current indexing is finished
1047  mAddedFeatures << fid;
1048  return;
1049  }
1050 
1051  if ( !mRTree )
1052  {
1053  if ( mIsEmptyLayer )
1054  {
1055  // layer is not empty any more, let's build the index
1056  mIsEmptyLayer = false;
1057  init();
1058  }
1059  return; // nothing to do if we are not initialized yet
1060  }
1061 
1062  QgsFeature f;
1063  if ( mLayer->getFeatures( QgsFeatureRequest( fid ) ).nextFeature( f ) )
1064  {
1065  if ( !f.hasGeometry() )
1066  return;
1067 
1068  if ( mContext )
1069  {
1070  std::unique_ptr< QgsFeatureRenderer > renderer( mLayer->renderer() ? mLayer->renderer()->clone() : nullptr );
1071  QgsRenderContext *ctx = nullptr;
1072 
1073  mContext->expressionContext() << QgsExpressionContextUtils::layerScope( mLayer );
1074  ctx = mContext.get();
1075  if ( renderer && ctx )
1076  {
1077  bool pass = false;
1078  renderer->startRender( *ctx, mLayer->fields() );
1079 
1080  ctx->expressionContext().setFeature( f );
1081  if ( !renderer->willRenderFeature( f, *ctx ) )
1082  {
1083  pass = true;
1084  }
1085 
1086  renderer->stopRender( *ctx );
1087  if ( pass )
1088  return;
1089  }
1090  }
1091 
1092  if ( mTransform.isValid() )
1093  {
1094  try
1095  {
1096  QgsGeometry transformedGeom = f.geometry();
1097  transformedGeom.transform( mTransform );
1098  f.setGeometry( transformedGeom );
1099  }
1100  catch ( const QgsException &e )
1101  {
1102  Q_UNUSED( e )
1103  // See https://github.com/qgis/QGIS/issues/20749
1104  QgsDebugMsg( QStringLiteral( "could not transform geometry to map, skipping the snap for it (%1)" ).arg( e.what() ) );
1105  return;
1106  }
1107  }
1108 
1109  const QgsRectangle bbox = f.geometry().boundingBox();
1110  if ( bbox.isFinite() )
1111  {
1112  SpatialIndex::Region r( rect2region( bbox ) );
1113  mRTree->insertData( 0, nullptr, r, f.id() );
1114 
1115  if ( mGeoms.contains( f.id() ) )
1116  delete mGeoms.take( f.id() );
1117  mGeoms[fid] = new QgsGeometry( f.geometry() );
1118  }
1119  }
1120 }
1121 
1122 void QgsPointLocator::onFeatureDeleted( QgsFeatureId fid )
1123 {
1124  if ( mIsIndexing )
1125  {
1126  if ( mAddedFeatures.contains( fid ) )
1127  {
1128  mAddedFeatures.remove( fid );
1129  }
1130  else
1131  {
1132  // will modify index once current indexing is finished
1133  mDeletedFeatures << fid;
1134  }
1135  return;
1136  }
1137 
1138  if ( !mRTree )
1139  return; // nothing to do if we are not initialized yet
1140 
1141  if ( mGeoms.contains( fid ) )
1142  {
1143  mRTree->deleteData( rect2region( mGeoms[fid]->boundingBox() ), fid );
1144  delete mGeoms.take( fid );
1145  }
1146 
1147 }
1148 
1149 void QgsPointLocator::onGeometryChanged( QgsFeatureId fid, const QgsGeometry &geom )
1150 {
1151  Q_UNUSED( geom )
1152  onFeatureDeleted( fid );
1153  onFeatureAdded( fid );
1154 }
1155 
1156 void QgsPointLocator::onAttributeValueChanged( QgsFeatureId fid, int idx, const QVariant &value )
1157 {
1158  Q_UNUSED( idx )
1159  Q_UNUSED( value )
1160  if ( mContext )
1161  {
1162  onFeatureDeleted( fid );
1163  onFeatureAdded( fid );
1164  }
1165 }
1166 
1167 
1168 QgsPointLocator::Match QgsPointLocator::nearestVertex( const QgsPointXY &point, double tolerance, MatchFilter *filter, bool relaxed )
1169 {
1170  if ( !prepare( relaxed ) )
1171  return Match();
1172 
1173  Match m;
1174  QgsPointLocator_VisitorNearestVertex visitor( this, m, point, filter );
1175  QgsRectangle rect( point.x() - tolerance, point.y() - tolerance, point.x() + tolerance, point.y() + tolerance );
1176  mRTree->intersectsWithQuery( rect2region( rect ), visitor );
1177  if ( m.isValid() && m.distance() > tolerance )
1178  return Match(); // make sure that only match strictly within the tolerance is returned
1179  return m;
1180 }
1181 
1182 QgsPointLocator::Match QgsPointLocator::nearestCentroid( const QgsPointXY &point, double tolerance, MatchFilter *filter, bool relaxed )
1183 {
1184  if ( !prepare( relaxed ) )
1185  return Match();
1186 
1187  Match m;
1188  QgsPointLocator_VisitorNearestCentroid visitor( this, m, point, filter );
1189 
1190  QgsRectangle rect( point.x() - tolerance, point.y() - tolerance, point.x() + tolerance, point.y() + tolerance );
1191  mRTree->intersectsWithQuery( rect2region( rect ), visitor );
1192  if ( m.isValid() && m.distance() > tolerance )
1193  return Match(); // make sure that only match strictly within the tolerance is returned
1194  return m;
1195 }
1196 
1197 QgsPointLocator::Match QgsPointLocator::nearestMiddleOfSegment( const QgsPointXY &point, double tolerance, MatchFilter *filter, bool relaxed )
1198 {
1199  if ( !prepare( relaxed ) )
1200  return Match();
1201 
1202  Match m;
1203  QgsPointLocator_VisitorNearestMiddleOfSegment visitor( this, m, point, filter );
1204 
1205  QgsRectangle rect( point.x() - tolerance, point.y() - tolerance, point.x() + tolerance, point.y() + tolerance );
1206  mRTree->intersectsWithQuery( rect2region( rect ), visitor );
1207  if ( m.isValid() && m.distance() > tolerance )
1208  return Match(); // make sure that only match strictly within the tolerance is returned
1209  return m;
1210 }
1211 
1212 QgsPointLocator::Match QgsPointLocator::nearestEdge( const QgsPointXY &point, double tolerance, MatchFilter *filter, bool relaxed )
1213 {
1214  if ( !prepare( relaxed ) )
1215  return Match();
1216 
1217  QgsWkbTypes::GeometryType geomType = mLayer->geometryType();
1218  if ( geomType == QgsWkbTypes::PointGeometry )
1219  return Match();
1220 
1221  Match m;
1222  QgsPointLocator_VisitorNearestEdge visitor( this, m, point, filter );
1223  QgsRectangle rect( point.x() - tolerance, point.y() - tolerance, point.x() + tolerance, point.y() + tolerance );
1224  mRTree->intersectsWithQuery( rect2region( rect ), visitor );
1225  if ( m.isValid() && m.distance() > tolerance )
1226  return Match(); // make sure that only match strictly within the tolerance is returned
1227  return m;
1228 }
1229 
1230 QgsPointLocator::Match QgsPointLocator::nearestArea( const QgsPointXY &point, double tolerance, MatchFilter *filter, bool relaxed )
1231 {
1232  if ( !prepare( relaxed ) )
1233  return Match();
1234 
1235  MatchList mlist = pointInPolygon( point );
1236  if ( !mlist.isEmpty() && mlist.at( 0 ).isValid() )
1237  {
1238  return mlist.at( 0 );
1239  }
1240 
1241  if ( tolerance == 0 )
1242  {
1243  return Match();
1244  }
1245 
1246  // discard point and line layers to keep only polygons
1247  QgsWkbTypes::GeometryType geomType = mLayer->geometryType();
1248  if ( geomType == QgsWkbTypes::PointGeometry || geomType == QgsWkbTypes::LineGeometry )
1249  return Match();
1250 
1251  // use edges for adding tolerance
1252  Match m = nearestEdge( point, tolerance, filter );
1253  if ( m.isValid() )
1254  return Match( Area, m.layer(), m.featureId(), m.distance(), m.point() );
1255  else
1256  return Match();
1257 }
1258 
1259 
1261 {
1262  if ( !prepare( relaxed ) )
1263  return MatchList();
1264 
1265  QgsWkbTypes::GeometryType geomType = mLayer->geometryType();
1266  if ( geomType == QgsWkbTypes::PointGeometry )
1267  return MatchList();
1268 
1269  MatchList lst;
1270  QgsPointLocator_VisitorEdgesInRect visitor( this, lst, rect, filter );
1271  mRTree->intersectsWithQuery( rect2region( rect ), visitor );
1272 
1273  return lst;
1274 }
1275 
1277 {
1278  QgsRectangle rect( point.x() - tolerance, point.y() - tolerance, point.x() + tolerance, point.y() + tolerance );
1279  return edgesInRect( rect, filter, relaxed );
1280 }
1281 
1283 {
1284  if ( !prepare( relaxed ) )
1285  return MatchList();
1286 
1287  MatchList lst;
1288  QgsPointLocator_VisitorVerticesInRect visitor( this, lst, rect, filter );
1289  mRTree->intersectsWithQuery( rect2region( rect ), visitor );
1290 
1291  return lst;
1292 }
1293 
1295 {
1296  QgsRectangle rect( point.x() - tolerance, point.y() - tolerance, point.x() + tolerance, point.y() + tolerance );
1297  return verticesInRect( rect, filter, relaxed );
1298 }
1299 
1301 {
1302  if ( !prepare( relaxed ) )
1303  return MatchList();
1304 
1305  QgsWkbTypes::GeometryType geomType = mLayer->geometryType();
1306  if ( geomType == QgsWkbTypes::PointGeometry || geomType == QgsWkbTypes::LineGeometry )
1307  return MatchList();
1308 
1309  MatchList lst;
1310  QgsPointLocator_VisitorArea visitor( this, point, lst );
1311  mRTree->intersectsWithQuery( point2point( point ), visitor );
1312  return lst;
1313 }
QgsCurve
Abstract base class for curved geometry type.
Definition: qgscurve.h:36
QgsPointLocator_VisitorNearestEdge::visitData
void visitData(std::vector< const IData * > &v) override
Definition: qgspointlocator.cpp:267
QgsVectorLayer::getFeatures
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Queries the layer for features specified in request.
Definition: qgsvectorlayer.cpp:993
SpatialIndex
Definition: qgspointlocator.h:82
QgsMapLayer::crs
QgsCoordinateReferenceSystem crs
Definition: qgsmaplayer.h:89
QgsPointLocator_VisitorArea
Helper class used when traversing the index with areas - builds a list of matches.
Definition: qgspointlocator.cpp:307
qgsexpressioncontextutils.h
QgsFeatureRenderer::Filter
@ Filter
Features may be filtered, i.e. some features may not be rendered (categorized, rule based ....
Definition: qgsrenderer.h:256
QgsRectangle::isFinite
bool isFinite() const
Returns true if the rectangle has finite boundaries.
Definition: qgsrectangle.h:527
QgsPointLocator_VisitorArea::visitData
void visitData(std::vector< const IData * > &v) override
Definition: qgspointlocator.cpp:317
QgsFeature::id
Q_GADGET QgsFeatureId id
Definition: qgsfeature.h:64
QgsPointXY::y
double y
Definition: qgspointxy.h:48
QgsException
Defines a QGIS exception class.
Definition: qgsexception.h:35
QgsGeometry::transform
OperationResult transform(const QgsCoordinateTransform &ct, QgsCoordinateTransform::TransformDirection direction=QgsCoordinateTransform::ForwardTransform, bool transformZ=false) SIP_THROW(QgsCsException)
Transforms this geometry as described by the coordinate transform ct.
Definition: qgsgeometry.cpp:2813
QgsCoordinateTransformContext
Contains information about the context in which a coordinate transform is executed.
Definition: qgscoordinatetransformcontext.h:58
QgsPointLocator_VisitorEdgesInRect::visitData
void visitData(std::vector< const IData * > &v) override
Definition: qgspointlocator.cpp:513
QgsRenderContext::expressionContext
QgsExpressionContext & expressionContext()
Gets the expression context.
Definition: qgsrendercontext.h:596
qgslinestring.h
QgsWkbTypes::NullGeometry
@ NullGeometry
Definition: qgswkbtypes.h:146
QgsPointLocator_Stream::rewind
void rewind() override
Definition: qgspointlocator.cpp:80
QgsGeometry::const_parts_end
QgsAbstractGeometry::const_part_iterator const_parts_end() const
Returns STL-style iterator pointing to the imaginary part after the last part of the geometry.
Definition: qgsgeometry.cpp:1880
qgswkbptr.h
QgsDebugMsgLevel
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
QgsPointLocator::setRenderContext
void setRenderContext(const QgsRenderContext *context)
Configure render context - if not nullptr, it will use to index only visible feature.
Definition: qgspointlocator.cpp:783
LEFT
#define LEFT(x)
Definition: priorityqueue.h:38
QgsPointXY::x
Q_GADGET double x
Definition: qgspointxy.h:47
QgsPointLocator::nearestArea
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 ...
Definition: qgspointlocator.cpp:1230
qgsfeatureiterator.h
QgsRectangle::yMinimum
double yMinimum() const SIP_HOLDGIL
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:177
QgsExpressionContextUtils::layerScope
static QgsExpressionContextScope * layerScope(const QgsMapLayer *layer)
Creates a new scope which contains variables and functions relating to a QgsMapLayer.
Definition: qgsexpressioncontextutils.cpp:265
QgsGeometry::centroid
QgsGeometry centroid() const
Returns the center of mass of a geometry.
Definition: qgsgeometry.cpp:2138
QgsFeature::geometry
QgsGeometry geometry
Definition: qgsfeature.h:67
qgis.h
QgsRenderContext
Contains information about the context of a rendering operation.
Definition: qgsrendercontext.h:58
QgsPointLocator_VisitorNearestMiddleOfSegment::visitData
void visitData(std::vector< const IData * > &v) override
Definition: qgspointlocator.cpp:214
QgsPointLocator_VisitorCentroidsInRect::QgsPointLocator_VisitorCentroidsInRect
QgsPointLocator_VisitorCentroidsInRect(QgsPointLocator *pl, QgsPointLocator::MatchList &lst, const QgsRectangle &srcRect, QgsPointLocator::MatchFilter *filter=nullptr)
Constructs the visitor.
Definition: qgspointlocator.cpp:597
QgsPointLocator_VisitorNearestCentroid::visitData
void visitData(std::vector< const IData * > &v) override
Definition: qgspointlocator.cpp:162
QgsGeometry::const_parts_begin
QgsAbstractGeometry::const_part_iterator const_parts_begin() const
Returns STL-style const iterator pointing to the first part of the geometry.
Definition: qgsgeometry.cpp:1873
QgsPointLocator::~QgsPointLocator
~QgsPointLocator() override
Definition: qgspointlocator.cpp:757
QgsVectorLayer::featureDeleted
void featureDeleted(QgsFeatureId fid)
Emitted when a feature has been deleted.
QgsFeatureRequest::setSubsetOfAttributes
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
Definition: qgsfeaturerequest.cpp:185
QgsPointLocator::Match::point
QgsPointXY point() const
for vertex / edge match coords depending on what class returns it (geom.cache: layer coords,...
Definition: qgspointlocator.h:228
QgsDebugMsg
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
QgsPointLocator_DumpTree::getNextEntry
void getNextEntry(const IEntry &entry, id_type &nextEntry, bool &hasNext) override
Definition: qgspointlocator.cpp:698
QgsPointLocator_VisitorNearestVertex
Helper class used when traversing the index looking for vertices - builds a list of matches.
Definition: qgspointlocator.cpp:97
QgsPointLocator_VisitorNearestCentroid::visitData
void visitData(const IData &d) override
Definition: qgspointlocator.cpp:164
QgsCoordinateTransform::isValid
bool isValid() const
Returns true if the coordinate transform is valid, ie both the source and destination CRS have been s...
Definition: qgscoordinatetransform.cpp:892
QgsPointLocator_VisitorMiddlesInRect::visitData
void visitData(const IData &d) override
Definition: qgspointlocator.cpp:649
QgsPointLocator::edgesInRect
MatchList edgesInRect(const QgsRectangle &rect, QgsPointLocator::MatchFilter *filter=nullptr, bool relaxed=false)
Find edges within a specified rectangle Optional filter may discard unwanted matches.
Definition: qgspointlocator.cpp:1260
QgsPointLocator_VisitorCentroidsInRect
Helper class used when traversing the index looking for centroid - builds a list of matches.
Definition: qgspointlocator.cpp:594
QgsGeometry::closestVertex
QgsPointXY closestVertex(const QgsPointXY &point, int &atVertex, int &beforeVertex, int &afterVertex, double &sqrDist) const
Returns the vertex closest to the given point, the corresponding vertex index, squared distance snap ...
Definition: qgsgeometry.cpp:386
QgsRectangle
A rectangle specified with double values.
Definition: qgsrectangle.h:42
QgsCoordinateTransform::ReverseTransform
@ ReverseTransform
Transform from destination to source CRS.
Definition: qgscoordinatetransform.h:61
QgsCoordinateTransform::transformBoundingBox
QgsRectangle transformBoundingBox(const QgsRectangle &rectangle, TransformDirection direction=ForwardTransform, bool handle180Crossover=false) const SIP_THROW(QgsCsException)
Transforms a rectangle from the source CRS to the destination CRS.
Definition: qgscoordinatetransform.cpp:511
QgsPointLocator_VisitorNearestMiddleOfSegment::visitNode
void visitNode(const INode &n) override
Definition: qgspointlocator.cpp:213
QgsPointLocator_VisitorNearestMiddleOfSegment
Helper class used when traversing the index looking for middle segment - builds a list of matches.
Definition: qgspointlocator.cpp:197
QgsPointLocator::init
bool init(int maxFeaturesToIndex=-1, bool relaxed=false)
Prepare the index for queries.
Definition: qgspointlocator.cpp:828
QgsTaskManager::addTask
long addTask(QgsTask *task, int priority=0)
Adds a task to the manager.
Definition: qgstaskmanager.cpp:416
QgsPointLocator_VisitorNearestCentroid
Helper class used when traversing the index looking for centroid - builds a list of matches.
Definition: qgspointlocator.cpp:145
QgsGeometry::isMultipart
bool isMultipart() const SIP_HOLDGIL
Returns true if WKB of the geometry is of WKBMulti* type.
Definition: qgsgeometry.cpp:377
QgsPointLocator::nearestVertex
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...
Definition: qgspointlocator.cpp:1168
QgsPointLocator_VisitorNearestVertex::visitNode
void visitNode(const INode &n) override
Definition: qgspointlocator.cpp:106
qgsapplication.h
QgsCoordinateTransform::destinationCrs
QgsCoordinateReferenceSystem destinationCrs() const
Returns the destination coordinate reference system, which the transform will transform coordinates t...
Definition: qgscoordinatetransform.cpp:234
QgsGeometry::convertToStraightSegment
void convertToStraightSegment(double tolerance=M_PI/180., QgsAbstractGeometry::SegmentationToleranceType toleranceType=QgsAbstractGeometry::MaximumAngle)
Converts the geometry to straight line segments, if it is a curved geometry type.
Definition: qgsgeometry.cpp:2792
QgsFeatureRequest::setFilterRect
QgsFeatureRequest & setFilterRect(const QgsRectangle &rectangle)
Sets the rectangle from which features will be taken.
Definition: qgsfeaturerequest.cpp:92
QgsVectorLayer::fields
QgsFields fields() const FINAL
Returns the list of fields of this layer.
Definition: qgsvectorlayer.cpp:3283
QgsPointLocator::rebuildIndex
bool rebuildIndex(int maxFeaturesToIndex=-1)
Definition: qgspointlocator.cpp:900
QgsRectangle::xMaximum
double xMaximum() const SIP_HOLDGIL
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:162
QgsPointLocator_VisitorCentroidsInRect::visitData
void visitData(std::vector< const IData * > &v) override
Definition: qgspointlocator.cpp:605
QgsFeatureRequest
This class wraps a request for features to a vector layer (or directly its vector data provider).
Definition: qgsfeaturerequest.h:76
QgsPointLocator_VisitorMiddlesInRect::visitNode
void visitNode(const INode &n) override
Definition: qgspointlocator.cpp:646
QgsGeometry::intersects
bool intersects(const QgsRectangle &rectangle) const
Returns true if this geometry exactly intersects with a rectangle.
Definition: qgsgeometry.cpp:1129
_CohenSutherland::isSegmentInRect
bool isSegmentInRect(double x0, double y0, double x1, double y1)
Definition: qgspointlocator.cpp:365
QgsPointLocator_VisitorNearestVertex::visitData
void visitData(const IData &d) override
Definition: qgspointlocator.cpp:109
QgsFeature::setGeometry
void setGeometry(const QgsGeometry &geometry)
Set the feature's geometry.
Definition: qgsfeature.cpp:139
QgsPointLocator::verticesInRect
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...
Definition: qgspointlocator.cpp:1282
_CohenSutherland::computeOutCode
OutCode computeOutCode(double x, double y)
Definition: qgspointlocator.cpp:351
QgsPointLocator_VisitorEdgesInRect::visitNode
void visitNode(const INode &n) override
Definition: qgspointlocator.cpp:512
QgsPointLocator::MatchList
class QList< QgsPointLocator::Match > MatchList
Definition: qgspointlocator.h:295
QgsAbstractGeometry::const_part_iterator
The part_iterator class provides STL-style iterator for const references to geometry parts.
Definition: qgsabstractgeometry.h:796
QgsPointLocator_DumpTree
Helper class to dump the R-index nodes and their content.
Definition: qgspointlocator.cpp:692
QgsMapLayer::styleChanged
void styleChanged()
Signal emitted whenever a change affects the layer's style.
QgsFeatureRenderer::clone
virtual QgsFeatureRenderer * clone() const =0
Create a deep copy of this renderer.
_CohenSutherland::OutCode
int OutCode
Definition: qgspointlocator.cpp:341
QgsPointLocator_VisitorNearestEdge::visitNode
void visitNode(const INode &n) override
Definition: qgspointlocator.cpp:266
QgsPointLocator::nearestMiddleOfSegment
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...
Definition: qgspointlocator.cpp:1197
QgsException::what
QString what() const
Definition: qgsexception.h:48
QgsVectorLayer::attributeValueChanged
void attributeValueChanged(QgsFeatureId fid, int idx, const QVariant &value)
Emitted whenever an attribute value change is done in the edit buffer.
QgsPointLocator::hasIndex
bool hasIndex() const
Indicate whether the data have been already indexed.
Definition: qgspointlocator.cpp:875
QgsPointLocator_VisitorVerticesInRect::QgsPointLocator_VisitorVerticesInRect
QgsPointLocator_VisitorVerticesInRect(QgsPointLocator *pl, QgsPointLocator::MatchList &lst, const QgsRectangle &srcRect, QgsPointLocator::MatchFilter *filter=nullptr)
Constructs the visitor.
Definition: qgspointlocator.cpp:550
QgsPointLocator_VisitorNearestEdge
Helper class used when traversing the index looking for edges - builds a list of matches.
Definition: qgspointlocator.cpp:257
QgsApplication::taskManager
static QgsTaskManager * taskManager()
Returns the application's task manager, used for managing application wide background task handling.
Definition: qgsapplication.cpp:2133
QgsPointLocator::Match::isValid
bool isValid() const
Definition: qgspointlocator.h:206
QgsCoordinateReferenceSystem::isValid
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
Definition: qgscoordinatereferencesystem.cpp:924
QgsPointLocator::setExtent
void setExtent(const QgsRectangle *extent)
Configure extent - if not nullptr, it will index only that area.
Definition: qgspointlocator.cpp:772
QgsPointLocator::Centroid
@ Centroid
Snapped to a centroid.
Definition: qgspointlocator.h:159
QgsPointLocator_VisitorNearestMiddleOfSegment::visitData
void visitData(const IData &d) override
Definition: qgspointlocator.cpp:216
QgsPointLocator_VisitorMiddlesInRect::visitData
void visitData(std::vector< const IData * > &v) override
Definition: qgspointlocator.cpp:647
QgsGeometry::isEmpty
bool isEmpty() const
Returns true if the geometry is empty (eg a linestring with no vertices, or a collection with no geom...
Definition: qgsgeometry.cpp:367
qgsvectorlayerfeatureiterator.h
QgsPointLocator_VisitorVerticesInRect
Helper class used when traversing the index looking for vertices - builds a list of matches.
Definition: qgspointlocator.cpp:547
QgsPointLocator_VisitorNearestEdge::visitData
void visitData(const IData &d) override
Definition: qgspointlocator.cpp:269
QgsPointLocator::Match::layer
QgsVectorLayer * layer() const
The vector layer where the snap occurred.
Definition: qgspointlocator.h:237
QgsPointLocator_VisitorVerticesInRect::visitData
void visitData(const IData &d) override
Definition: qgspointlocator.cpp:560
QgsPointLocator::extent
const QgsRectangle * extent() const
Gets extent of the area point locator covers - if nullptr then it caches the whole layer.
Definition: qgspointlocator.h:136
QgsPointLocator_VisitorMiddlesInRect
Helper class used when traversing the index looking for middle segment - builds a list of matches.
Definition: qgspointlocator.cpp:636
QgsAbstractGeometry::hasCurvedSegments
virtual bool hasCurvedSegments() const
Returns true if the geometry contains curved segments.
Definition: qgsabstractgeometry.cpp:305
QgsPointLocator_Stream::hasNext
bool hasNext() override
Definition: qgspointlocator.cpp:77
QgsAbstractGeometry::vertex_iterator::vertexId
QgsVertexId vertexId() const
Returns vertex ID of the current item.
Definition: qgsabstractgeometry.cpp:362
QgsRectangle::xMinimum
double xMinimum() const SIP_HOLDGIL
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:167
qgsrenderer.h
_CohenSutherland::mRect
QgsRectangle mRect
Definition: qgspointlocator.cpp:349
QgsFeatureRequest::setNoAttributes
QgsFeatureRequest & setNoAttributes()
Set that no attributes will be fetched.
Definition: qgsfeaturerequest.cpp:192
QgsCoordinateReferenceSystem
This class represents a coordinate reference system (CRS).
Definition: qgscoordinatereferencesystem.h:206
QgsPointLocator::Vertex
@ Vertex
Snapped to a vertex. Can be a vertex of the geometry or an intersection.
Definition: qgspointlocator.h:156
QgsPointLocator_VisitorNearestEdge::QgsPointLocator_VisitorNearestEdge
QgsPointLocator_VisitorNearestEdge(QgsPointLocator *pl, QgsPointLocator::Match &m, const QgsPointXY &srcPoint, QgsPointLocator::MatchFilter *filter=nullptr)
Definition: qgspointlocator.cpp:259
QgsGeometry::vertexAt
QgsPoint vertexAt(int atVertex) const
Returns coordinates of a vertex.
Definition: qgsgeometry.cpp:588
QgsPointLocator::Match
Definition: qgspointlocator.h:185
qgsvectorlayer.h
QgsPointXY
A class to represent a 2D point.
Definition: qgspointxy.h:44
QgsPointLocator::destinationCrs
QgsCoordinateReferenceSystem destinationCrs() const
Gets destination CRS - may be an invalid QgsCoordinateReferenceSystem if not doing OTF reprojection.
Definition: qgspointlocator.cpp:767
QgsPointLocator_VisitorEdgesInRect
Helper class used when traversing the index looking for edges - builds a list of matches.
Definition: qgspointlocator.cpp:503
QgsMapLayer::dataChanged
void dataChanged()
Data of layer changed.
QgsGeometry::asPoint
QgsPointXY asPoint() const
Returns the contents of the geometry as a 2-dimensional point.
Definition: qgsgeometry.cpp:1544
QgsPointLocator_VisitorVerticesInRect::visitData
void visitData(std::vector< const IData * > &v) override
Definition: qgspointlocator.cpp:558
_CohenSutherland::_CohenSutherland
_CohenSutherland(const QgsRectangle &rect)
Definition: qgspointlocator.cpp:339
QgsPointLocator_VisitorNearestCentroid::visitNode
void visitNode(const INode &n) override
Definition: qgspointlocator.cpp:161
QgsPointLocator::Match::featureId
QgsFeatureId featureId() const
The id of the feature to which the snapped geometry belongs.
Definition: qgspointlocator.h:242
QgsWkbTypes::LineGeometry
@ LineGeometry
Definition: qgswkbtypes.h:143
QgsPointLocator_VisitorNearestCentroid::QgsPointLocator_VisitorNearestCentroid
QgsPointLocator_VisitorNearestCentroid(QgsPointLocator *pl, QgsPointLocator::Match &m, const QgsPointXY &srcPoint, QgsPointLocator::MatchFilter *filter=nullptr)
Helper class used when traversing the index looking for centroid - builds a list of matches.
Definition: qgspointlocator.cpp:154
QgsWkbTypes::PointGeometry
@ PointGeometry
Definition: qgswkbtypes.h:142
QgsRectangle::yMaximum
double yMaximum() const SIP_HOLDGIL
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:172
qgsgeometry.h
QgsWkbTypes::GeometryType
GeometryType
The geometry types are used to group QgsWkbTypes::Type in a coarse way.
Definition: qgswkbtypes.h:141
QgsAbstractGeometry::vertex_iterator
The vertex_iterator class provides STL-style iterator for vertices.
Definition: qgsabstractgeometry.h:856
QgsFeatureIterator::nextFeature
bool nextFeature(QgsFeature &f)
Definition: qgsfeatureiterator.h:374
QgsGeometry
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:124
QgsPointLocator::Edge
@ Edge
Snapped to an edge.
Definition: qgspointlocator.h:157
QgsPointLocator_Stream::QgsPointLocator_Stream
QgsPointLocator_Stream(const QLinkedList< RTree::Data * > &dataList)
Definition: qgspointlocator.cpp:71
QgsVectorLayer
Represents a vector layer which manages a vector based data sets.
Definition: qgsvectorlayer.h:387
QgsFeature::hasGeometry
bool hasGeometry() const
Returns true if the feature has an associated geometry.
Definition: qgsfeature.cpp:199
_CohenSutherland
Definition: qgspointlocator.cpp:338
QgsVectorLayer::geometryChanged
void geometryChanged(QgsFeatureId fid, const QgsGeometry &geometry)
Emitted whenever a geometry change is done in the edit buffer.
RIGHT
#define RIGHT(x)
Definition: priorityqueue.h:39
QgsVectorLayerFeatureSource
Partial snapshot of vector layer's state (only the members necessary for access to features)
Definition: qgsvectorlayerfeatureiterator.h:52
QgsPointLocator::pointInPolygon
MatchList pointInPolygon(const QgsPointXY &point, bool relaxed=false)
find out if the point is in any polygons This method is either blocking or non blocking according to ...
Definition: qgspointlocator.cpp:1300
QgsPointLocator
The class defines interface for querying point location:
Definition: qgspointlocator.h:100
QgsPointLocator::QgsPointLocator
QgsPointLocator(QgsVectorLayer *layer, const QgsCoordinateReferenceSystem &destinationCrs=QgsCoordinateReferenceSystem(), const QgsCoordinateTransformContext &transformContext=QgsCoordinateTransformContext(), const QgsRectangle *extent=nullptr)
Construct point locator for a layer.
Definition: qgspointlocator.cpp:737
QgsGeometry::convertToType
QgsGeometry convertToType(QgsWkbTypes::GeometryType destType, bool destMultipart=false) const
Try to convert the geometry to the requested type.
Definition: qgsgeometry.cpp:1435
QgsPointLocator_VisitorArea::visitData
void visitData(const IData &d) override
Definition: qgspointlocator.cpp:319
QgsGeometry::vertexNrFromVertexId
int vertexNrFromVertexId(QgsVertexId id) const
Returns the vertex number corresponding to a vertex id.
Definition: qgsgeometry.cpp:2986
QgsPointLocator_VisitorNearestVertex::visitData
void visitData(std::vector< const IData * > &v) override
Definition: qgspointlocator.cpp:107
QgsVectorLayer::dataProvider
QgsVectorDataProvider * dataProvider() FINAL
Returns the layer's data provider, it may be nullptr.
Definition: qgsvectorlayer.cpp:627
QgsPointLocator_VisitorArea::visitNode
void visitNode(const INode &n) override
Definition: qgspointlocator.cpp:316
QgsPointLocator::layer
QgsVectorLayer * layer() const
Gets associated layer.
Definition: qgspointlocator.h:124
QgsPointLocator::QgsPointLocatorInitTask
friend class QgsPointLocatorInitTask
Definition: qgspointlocator.h:473
QgsPointLocator::nearestCentroid
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 ...
Definition: qgspointlocator.cpp:1182
QgsPointLocator::destroyIndex
void destroyIndex()
Definition: qgspointlocator.cpp:1031
QgsPointLocator::MatchFilter
Interface that allows rejection of some matches in intersection queries (e.g.
Definition: qgspointlocator.h:306
QgsPointLocator_Stream
Helper class for bulk loading of R-trees.
Definition: qgspointlocator.cpp:69
QgsGeometry::boundingBox
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
Definition: qgsgeometry.cpp:996
qgspointlocatorinittask.h
qgspointlocator.h
QgsPointLocator_VisitorNearestMiddleOfSegment::QgsPointLocator_VisitorNearestMiddleOfSegment
QgsPointLocator_VisitorNearestMiddleOfSegment(QgsPointLocator *pl, QgsPointLocator::Match &m, const QgsPointXY &srcPoint, QgsPointLocator::MatchFilter *filter=nullptr)
Helper class used when traversing the index looking for middle segment - builds a list of matches.
Definition: qgspointlocator.cpp:206
QgsPointLocator::nearestEdge
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 ...
Definition: qgspointlocator.cpp:1212
QgsFeature
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:56
QgsPointLocator_VisitorMiddlesInRect::QgsPointLocator_VisitorMiddlesInRect
QgsPointLocator_VisitorMiddlesInRect(QgsPointLocator *pl, QgsPointLocator::MatchList &lst, const QgsRectangle &srcRect, QgsPointLocator::MatchFilter *filter=nullptr)
Constructs the visitor.
Definition: qgspointlocator.cpp:639
QgsCurve::numPoints
virtual int numPoints() const =0
Returns the number of points in the curve.
QgsGeometry::vertices_end
QgsAbstractGeometry::vertex_iterator vertices_end() const
Returns STL-style iterator pointing to the imaginary vertex after the last vertex of the geometry.
Definition: qgsgeometry.cpp:1843
QgsPointLocator::MiddleOfSegment
@ MiddleOfSegment
Snapped to the middle of a segment.
Definition: qgspointlocator.h:160
QgsPointLocator_VisitorVerticesInRect::visitNode
void visitNode(const INode &n) override
Definition: qgspointlocator.cpp:557
qgslogger.h
QgsGeometry::vertices_begin
QgsAbstractGeometry::vertex_iterator vertices_begin() const
Returns STL-style iterator pointing to the first vertex of the geometry.
Definition: qgsgeometry.cpp:1836
QgsPointLocator_VisitorArea::QgsPointLocator_VisitorArea
QgsPointLocator_VisitorArea(QgsPointLocator *pl, const QgsPointXY &origPt, QgsPointLocator::MatchList &list)
constructor
Definition: qgspointlocator.cpp:310
QgsCoordinateTransform
Class for doing transforms between two map coordinate systems.
Definition: qgscoordinatetransform.h:53
QgsPointLocator::initFinished
void initFinished(bool ok)
Emitted whenever index has been built and initialization is finished.
QgsPointLocator_Stream::size
uint32_t size() override
Definition: qgspointlocator.cpp:79
QgsGeometry::type
QgsWkbTypes::GeometryType type
Definition: qgsgeometry.h:127
QgsFeatureIterator
Wrapper for iterator of features from vector data provider or vector layer.
Definition: qgsfeatureiterator.h:265
QgsVectorLayer::geometryType
Q_INVOKABLE QgsWkbTypes::GeometryType geometryType() const
Returns point, line or polygon.
Definition: qgsvectorlayer.cpp:659
QgsPointLocator_Stream::getNext
IData * getNext() override
Definition: qgspointlocator.cpp:76
QgsPointLocator_VisitorCentroidsInRect::visitData
void visitData(const IData &d) override
Definition: qgspointlocator.cpp:607
QgsPointLocator_VisitorCentroidsInRect::visitNode
void visitNode(const INode &n) override
Definition: qgspointlocator.cpp:604
QgsPointLocator_VisitorNearestVertex::QgsPointLocator_VisitorNearestVertex
QgsPointLocator_VisitorNearestVertex(QgsPointLocator *pl, QgsPointLocator::Match &m, const QgsPointXY &srcPoint, QgsPointLocator::MatchFilter *filter=nullptr)
Definition: qgspointlocator.cpp:99
QgsPointLocator::waitForIndexingFinished
void waitForIndexingFinished()
If the point locator has been initialized relaxedly and is currently indexing, this methods waits for...
Definition: qgspointlocator.cpp:867
QgsDataProvider::isValid
virtual bool isValid() const =0
Returns true if this is a valid layer.
QgsGeometry::closestSegmentWithContext
double closestSegmentWithContext(const QgsPointXY &point, QgsPointXY &minDistPoint, int &afterVertex, int *leftOf=nullptr, double epsilon=DEFAULT_SEGMENT_EPSILON) const
Searches for the closest segment of geometry to the given point.
Definition: qgsgeometry.cpp:656
QgsPointLocator_VisitorEdgesInRect::visitData
void visitData(const IData &d) override
Definition: qgspointlocator.cpp:515
QgsFeatureId
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features
Definition: qgsfeatureid.h:28
QgsPointLocator::Area
@ Area
Snapped to an area.
Definition: qgspointlocator.h:158
QgsPointLocator_VisitorEdgesInRect::QgsPointLocator_VisitorEdgesInRect
QgsPointLocator_VisitorEdgesInRect(QgsPointLocator *pl, QgsPointLocator::MatchList &lst, const QgsRectangle &srcRect, QgsPointLocator::MatchFilter *filter=nullptr)
Definition: qgspointlocator.cpp:505
QgsExpressionContext::setFeature
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
Definition: qgsexpressioncontext.cpp:521
QgsPointLocator::Match::distance
double distance() const
for vertex / edge match units depending on what class returns it (geom.cache: layer units,...
Definition: qgspointlocator.h:222
QgsVectorLayer::renderer
QgsFeatureRenderer * renderer()
Returns renderer.
Definition: qgsvectorlayer.h:892
QgsVectorLayer::featureAdded
void featureAdded(QgsFeatureId fid)
Emitted when a new feature has been added to the layer.