QGIS API Documentation  3.14.0-Pi (9f7028fd23)
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, -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  if ( qgsgeometry_cast<QgsLineString *>( *part )->numPoints() < 2 )
471  continue;
472 
473  QgsAbstractGeometry::vertex_iterator it = ( *part )->vertices_begin();
474  QgsPointXY prevPoint( *it );
475  it++;
476  while ( it != ( *part )->vertices_end() )
477  {
478  QgsPointXY thisPoint( *it );
479  if ( cs.isSegmentInRect( prevPoint.x(), prevPoint.y(), thisPoint.x(), thisPoint.y() ) )
480  {
481  QgsPointXY edgePoints[2];
482  edgePoints[0] = prevPoint;
483  edgePoints[1] = thisPoint;
484  lst << QgsPointLocator::Match( QgsPointLocator::Edge, vl, fid, 0, QgsPointXY(), pointIndex - 1, edgePoints );
485  }
486  prevPoint = QgsPointXY( *it );
487  it++;
488  pointIndex += 1;
489 
490  }
491  }
492  return lst;
493 }
494 
500 class QgsPointLocator_VisitorEdgesInRect : public IVisitor
501 {
502  public:
504  : mLocator( pl )
505  , mList( lst )
506  , mSrcRect( srcRect )
507  , mFilter( filter )
508  {}
509 
510  void visitNode( const INode &n ) override { Q_UNUSED( n ) }
511  void visitData( std::vector<const IData *> &v ) override { Q_UNUSED( v ) }
512 
513  void visitData( const IData &d ) override
514  {
515  QgsFeatureId id = d.getIdentifier();
516  QgsGeometry *geom = mLocator->mGeoms.value( id );
517 
518  const auto segmentsInRect {_geometrySegmentsInRect( geom, mSrcRect, mLocator->mLayer, id )};
519  for ( const QgsPointLocator::Match &m : segmentsInRect )
520  {
521  // in range queries the filter may reject some matches
522  if ( mFilter && !mFilter->acceptMatch( m ) )
523  continue;
524 
525  mList << m;
526  }
527  }
528 
529  private:
530  QgsPointLocator *mLocator = nullptr;
532  QgsRectangle mSrcRect;
533  QgsPointLocator::MatchFilter *mFilter = nullptr;
534 };
535 
537 
545 {
546  public:
549  : mLocator( pl )
550  , mList( lst )
551  , mSrcRect( srcRect )
552  , mFilter( filter )
553  {}
554 
555  void visitNode( const INode &n ) override { Q_UNUSED( n ) }
556  void visitData( std::vector<const IData *> &v ) override { Q_UNUSED( v ) }
557 
558  void visitData( const IData &d ) override
559  {
560  QgsFeatureId id = d.getIdentifier();
561  const QgsGeometry *geom = mLocator->mGeoms.value( id );
562 
563  for ( QgsAbstractGeometry::vertex_iterator it = geom->vertices_begin(); it != geom->vertices_end(); ++it )
564  {
565  if ( mSrcRect.contains( *it ) )
566  {
567  QgsPointLocator::Match m( QgsPointLocator::Vertex, mLocator->mLayer, id, 0, *it, geom->vertexNrFromVertexId( it.vertexId() ) );
568 
569  // in range queries the filter may reject some matches
570  if ( mFilter && !mFilter->acceptMatch( m ) )
571  continue;
572 
573  mList << m;
574  }
575  }
576  }
577 
578  private:
579  QgsPointLocator *mLocator = nullptr;
581  QgsRectangle mSrcRect;
582  QgsPointLocator::MatchFilter *mFilter = nullptr;
583 };
584 
592 {
593  public:
596  : mLocator( pl )
597  , mList( lst )
598  , mSrcRect( srcRect )
599  , mFilter( filter )
600  {}
601 
602  void visitNode( const INode &n ) override { Q_UNUSED( n ); }
603  void visitData( std::vector<const IData *> &v ) override { Q_UNUSED( v ); }
604 
605  void visitData( const IData &d ) override
606  {
607  QgsFeatureId id = d.getIdentifier();
608  const QgsGeometry *geom = mLocator->mGeoms.value( id );
609  const QgsPointXY centroid = geom->centroid().asPoint();
610  if ( mSrcRect.contains( centroid ) )
611  {
612  QgsPointLocator::Match m( QgsPointLocator::Centroid, mLocator->mLayer, id, 0, centroid, -1 );
613 
614  // in range queries the filter may reject some matches
615  if ( !( mFilter && !mFilter->acceptMatch( m ) ) )
616  mList << m;
617  }
618  }
619 
620  private:
621  QgsPointLocator *mLocator = nullptr;
623  QgsRectangle mSrcRect;
624  QgsPointLocator::MatchFilter *mFilter = nullptr;
625 };
626 
634 {
635  public:
638  : mLocator( pl )
639  , mList( lst )
640  , mSrcRect( srcRect )
641  , mFilter( filter )
642  {}
643 
644  void visitNode( const INode &n ) override { Q_UNUSED( n ); }
645  void visitData( std::vector<const IData *> &v ) override { Q_UNUSED( v ); }
646 
647  void visitData( const IData &d ) override
648  {
649  QgsFeatureId id = d.getIdentifier();
650  const QgsGeometry *geom = mLocator->mGeoms.value( id );
651 
652  for ( QgsAbstractGeometry::const_part_iterator itPart = geom->const_parts_begin() ; itPart != geom->const_parts_end() ; ++itPart )
653  {
654  QgsAbstractGeometry::vertex_iterator it = ( *itPart )->vertices_begin();
655  QgsAbstractGeometry::vertex_iterator itPrevious = ( *itPart )->vertices_begin();
656  it++;
657  for ( ; it != geom->vertices_end(); ++it, ++itPrevious )
658  {
659  QgsPointXY pt( ( ( *itPrevious ).x() + ( *it ).x() ) / 2.0, ( ( *itPrevious ).y() + ( *it ).y() ) / 2.0 );
660  if ( mSrcRect.contains( pt ) )
661  {
662  QgsPointLocator::Match m( QgsPointLocator::MiddleOfSegment, mLocator->mLayer, id, 0, pt, -1 );
663 
664  // in range queries the filter may reject some matches
665  if ( mFilter && !mFilter->acceptMatch( m ) )
666  continue;
667 
668  mList << m;
669  }
670  }
671  }
672  }
673 
674  private:
675  QgsPointLocator *mLocator = nullptr;
677  QgsRectangle mSrcRect;
678  QgsPointLocator::MatchFilter *mFilter = nullptr;
679 };
680 
682 #include <QStack>
683 
689 class QgsPointLocator_DumpTree : public SpatialIndex::IQueryStrategy
690 {
691  private:
692  QStack<id_type> ids;
693 
694  public:
695 
696  void getNextEntry( const IEntry &entry, id_type &nextEntry, bool &hasNext ) override
697  {
698  const INode *n = dynamic_cast<const INode *>( &entry );
699  if ( !n )
700  return;
701 
702  QgsDebugMsgLevel( QStringLiteral( "NODE: %1" ).arg( n->getIdentifier() ), 4 );
703  if ( n->getLevel() > 0 )
704  {
705  // inner nodes
706  for ( uint32_t cChild = 0; cChild < n->getChildrenCount(); cChild++ )
707  {
708  QgsDebugMsgLevel( QStringLiteral( "- CH: %1" ).arg( n->getChildIdentifier( cChild ) ), 4 );
709  ids.push( n->getChildIdentifier( cChild ) );
710  }
711  }
712  else
713  {
714  // leaves
715  for ( uint32_t cChild = 0; cChild < n->getChildrenCount(); cChild++ )
716  {
717  QgsDebugMsgLevel( QStringLiteral( "- L: %1" ).arg( n->getChildIdentifier( cChild ) ), 4 );
718  }
719  }
720 
721  if ( ! ids.empty() )
722  {
723  nextEntry = ids.back();
724  ids.pop();
725  hasNext = true;
726  }
727  else
728  hasNext = false;
729  }
730 };
731 
733 
734 
736  : mLayer( layer )
737 {
738  if ( destCRS.isValid() )
739  {
740  mTransform = QgsCoordinateTransform( layer->crs(), destCRS, transformContext );
741  }
742 
743  setExtent( extent );
744 
745  mStorage.reset( StorageManager::createNewMemoryStorageManager() );
746 
747  connect( mLayer, &QgsVectorLayer::featureAdded, this, &QgsPointLocator::onFeatureAdded );
748  connect( mLayer, &QgsVectorLayer::featureDeleted, this, &QgsPointLocator::onFeatureDeleted );
749  connect( mLayer, &QgsVectorLayer::geometryChanged, this, &QgsPointLocator::onGeometryChanged );
750  connect( mLayer, &QgsVectorLayer::attributeValueChanged, this, &QgsPointLocator::onAttributeValueChanged );
752 }
753 
754 
756 {
757  // don't delete a locator if there is an indexing task running on it
758  mIsDestroying = true;
759  if ( mIsIndexing )
761 
762  destroyIndex();
763 }
764 
766 {
767  return mTransform.isValid() ? mTransform.destinationCrs() : QgsCoordinateReferenceSystem();
768 }
769 
771 {
772  if ( mIsIndexing )
773  // already indexing, return!
774  return;
775 
776  mExtent.reset( extent ? new QgsRectangle( *extent ) : nullptr );
777 
778  destroyIndex();
779 }
780 
782 {
783  if ( mIsIndexing )
784  // already indexing, return!
785  return;
786 
787  disconnect( mLayer, &QgsVectorLayer::styleChanged, this, &QgsPointLocator::destroyIndex );
788 
789  destroyIndex();
790  mContext.reset( nullptr );
791 
792  if ( context )
793  {
794  mContext = std::unique_ptr<QgsRenderContext>( new QgsRenderContext( *context ) );
796  }
797 
798 }
799 
800 void QgsPointLocator::onInitTaskFinished()
801 {
802  // Check that we don't call this method twice, when calling waitForFinished
803  // for instance (because of taskCompleted signal)
804  if ( !mIsIndexing )
805  return;
806 
807  if ( mIsDestroying )
808  return;
809 
810  mIsIndexing = false;
811  mRenderer.reset();
812  mSource.reset();
813 
814  // treat added and deleted feature while indexing
815  for ( QgsFeatureId fid : mAddedFeatures )
816  onFeatureAdded( fid );
817  mAddedFeatures.clear();
818 
819  for ( QgsFeatureId fid : mDeletedFeatures )
820  onFeatureDeleted( fid );
821  mDeletedFeatures.clear();
822 
823  emit initFinished( mInitTask->isBuildOK() );
824 }
825 
826 bool QgsPointLocator::init( int maxFeaturesToIndex, bool relaxed )
827 {
828  const QgsWkbTypes::GeometryType geomType = mLayer->geometryType();
829  if ( geomType == QgsWkbTypes::NullGeometry // nothing to index
830  || hasIndex()
831  || mIsIndexing ) // already indexing, return!
832  return true;
833 
834  mRenderer.reset( mLayer->renderer() ? mLayer->renderer()->clone() : nullptr );
835  mSource.reset( new QgsVectorLayerFeatureSource( mLayer ) );
836 
837  if ( mContext )
838  {
839  mContext->expressionContext() << QgsExpressionContextUtils::layerScope( mLayer );
840  }
841 
842  mIsIndexing = true;
843 
844  if ( relaxed )
845  {
846  mInitTask = new QgsPointLocatorInitTask( this );
847  connect( mInitTask, &QgsPointLocatorInitTask::taskTerminated, this, &QgsPointLocator::onInitTaskFinished );
848  connect( mInitTask, &QgsPointLocatorInitTask::taskCompleted, this, &QgsPointLocator::onInitTaskFinished );
849  QgsApplication::taskManager()->addTask( mInitTask );
850  return true;
851  }
852  else
853  {
854  const bool ok = rebuildIndex( maxFeaturesToIndex );
855  mIsIndexing = false;
856  emit initFinished( ok );
857  return ok;
858  }
859 }
860 
862 {
863  mInitTask->waitForFinished();
864 
865  if ( !mIsDestroying )
866  onInitTaskFinished();
867 }
868 
870 {
871  return mIsIndexing || mRTree || mIsEmptyLayer;
872 }
873 
874 bool QgsPointLocator::prepare( bool relaxed )
875 {
876  if ( mIsIndexing )
877  {
878  if ( relaxed )
879  return false;
880  else
882  }
883 
884  if ( !mRTree )
885  {
886  init( -1, relaxed );
887  if ( ( relaxed && mIsIndexing ) || !mRTree ) // relaxed mode and currently indexing or still invalid?
888  return false;
889  }
890 
891  return true;
892 }
893 
894 bool QgsPointLocator::rebuildIndex( int maxFeaturesToIndex )
895 {
896  QElapsedTimer t;
897  t.start();
898 
899  QgsDebugMsgLevel( QStringLiteral( "RebuildIndex start : %1" ).arg( mSource->id() ), 2 );
900 
901  destroyIndex();
902 
903  QLinkedList<RTree::Data *> dataList;
904  QgsFeature f;
905 
906  QgsFeatureRequest request;
907  request.setNoAttributes();
908 
909  if ( mExtent )
910  {
911  QgsRectangle rect = *mExtent;
912  if ( mTransform.isValid() )
913  {
914  try
915  {
917  }
918  catch ( const QgsException &e )
919  {
920  Q_UNUSED( e )
921  // See https://github.com/qgis/QGIS/issues/20749
922  QgsDebugMsg( QStringLiteral( "could not transform bounding box to map, skipping the snap filter (%1)" ).arg( e.what() ) );
923  }
924  }
925  request.setFilterRect( rect );
926  }
927 
928  bool filter = false;
929  QgsRenderContext *ctx = nullptr;
930  if ( mContext )
931  {
932  ctx = mContext.get();
933  if ( mRenderer )
934  {
935  // setup scale for scale dependent visibility (rule based)
936  mRenderer->startRender( *ctx, mSource->fields() );
937  filter = mRenderer->capabilities() & QgsFeatureRenderer::Filter;
938  request.setSubsetOfAttributes( mRenderer->usedAttributes( *ctx ), mSource->fields() );
939  }
940  }
941 
942  QgsFeatureIterator fi = mSource->getFeatures( request );
943  int indexedCount = 0;
944 
945  while ( fi.nextFeature( f ) )
946  {
947  if ( !f.hasGeometry() )
948  continue;
949 
950  if ( filter && ctx && mRenderer )
951  {
952  ctx->expressionContext().setFeature( f );
953  if ( !mRenderer->willRenderFeature( f, *ctx ) )
954  {
955  continue;
956  }
957  }
958 
959  if ( mTransform.isValid() )
960  {
961  try
962  {
963  QgsGeometry transformedGeometry = f.geometry();
964  transformedGeometry.transform( mTransform );
965  f.setGeometry( transformedGeometry );
966  }
967  catch ( const QgsException &e )
968  {
969  Q_UNUSED( e )
970  // See https://github.com/qgis/QGIS/issues/20749
971  QgsDebugMsg( QStringLiteral( "could not transform geometry to map, skipping the snap for it (%1)" ).arg( e.what() ) );
972  continue;
973  }
974  }
975 
976  const QgsRectangle bbox = f.geometry().boundingBox();
977  if ( bbox.isFinite() )
978  {
979  SpatialIndex::Region r( rect2region( bbox ) );
980  dataList << new RTree::Data( 0, nullptr, r, f.id() );
981 
982  if ( mGeoms.contains( f.id() ) )
983  delete mGeoms.take( f.id() );
984  mGeoms[f.id()] = new QgsGeometry( f.geometry() );
985  ++indexedCount;
986  }
987 
988  if ( maxFeaturesToIndex != -1 && indexedCount > maxFeaturesToIndex )
989  {
990  qDeleteAll( dataList );
991  destroyIndex();
992  return false;
993  }
994  }
995 
996  // R-Tree parameters
997  double fillFactor = 0.7;
998  unsigned long indexCapacity = 10;
999  unsigned long leafCapacity = 10;
1000  unsigned long dimension = 2;
1001  RTree::RTreeVariant variant = RTree::RV_RSTAR;
1002  SpatialIndex::id_type indexId;
1003 
1004  if ( dataList.isEmpty() )
1005  {
1006  mIsEmptyLayer = true;
1007  return true; // no features
1008  }
1009 
1010  QgsPointLocator_Stream stream( dataList );
1011  mRTree.reset( RTree::createAndBulkLoadNewRTree( RTree::BLM_STR, stream, *mStorage, fillFactor, indexCapacity,
1012  leafCapacity, dimension, variant, indexId ) );
1013 
1014  if ( ctx && mRenderer )
1015  {
1016  mRenderer->stopRender( *ctx );
1017  }
1018 
1019  QgsDebugMsgLevel( QStringLiteral( "RebuildIndex end : %1 ms (%2)" ).arg( t.elapsed() ).arg( mSource->id() ), 2 );
1020 
1021  return true;
1022 }
1023 
1024 
1026 {
1027  mRTree.reset();
1028 
1029  mIsEmptyLayer = false;
1030 
1031  qDeleteAll( mGeoms );
1032 
1033  mGeoms.clear();
1034 }
1035 
1036 void QgsPointLocator::onFeatureAdded( QgsFeatureId fid )
1037 {
1038  if ( mIsIndexing )
1039  {
1040  // will modify index once current indexing is finished
1041  mAddedFeatures << fid;
1042  return;
1043  }
1044 
1045  if ( !mRTree )
1046  {
1047  if ( mIsEmptyLayer )
1048  {
1049  // layer is not empty any more, let's build the index
1050  mIsEmptyLayer = false;
1051  init();
1052  }
1053  return; // nothing to do if we are not initialized yet
1054  }
1055 
1056  QgsFeature f;
1057  if ( mLayer->getFeatures( QgsFeatureRequest( fid ) ).nextFeature( f ) )
1058  {
1059  if ( !f.hasGeometry() )
1060  return;
1061 
1062  if ( mContext )
1063  {
1064  std::unique_ptr< QgsFeatureRenderer > renderer( mLayer->renderer() ? mLayer->renderer()->clone() : nullptr );
1065  QgsRenderContext *ctx = nullptr;
1066 
1067  mContext->expressionContext() << QgsExpressionContextUtils::layerScope( mLayer );
1068  ctx = mContext.get();
1069  if ( renderer && ctx )
1070  {
1071  bool pass = false;
1072  renderer->startRender( *ctx, mLayer->fields() );
1073 
1074  ctx->expressionContext().setFeature( f );
1075  if ( !renderer->willRenderFeature( f, *ctx ) )
1076  {
1077  pass = true;
1078  }
1079 
1080  renderer->stopRender( *ctx );
1081  if ( pass )
1082  return;
1083  }
1084  }
1085 
1086  if ( mTransform.isValid() )
1087  {
1088  try
1089  {
1090  QgsGeometry transformedGeom = f.geometry();
1091  transformedGeom.transform( mTransform );
1092  f.setGeometry( transformedGeom );
1093  }
1094  catch ( const QgsException &e )
1095  {
1096  Q_UNUSED( e )
1097  // See https://github.com/qgis/QGIS/issues/20749
1098  QgsDebugMsg( QStringLiteral( "could not transform geometry to map, skipping the snap for it (%1)" ).arg( e.what() ) );
1099  return;
1100  }
1101  }
1102 
1103  const QgsRectangle bbox = f.geometry().boundingBox();
1104  if ( bbox.isFinite() )
1105  {
1106  SpatialIndex::Region r( rect2region( bbox ) );
1107  mRTree->insertData( 0, nullptr, r, f.id() );
1108 
1109  if ( mGeoms.contains( f.id() ) )
1110  delete mGeoms.take( f.id() );
1111  mGeoms[fid] = new QgsGeometry( f.geometry() );
1112  }
1113  }
1114 }
1115 
1116 void QgsPointLocator::onFeatureDeleted( QgsFeatureId fid )
1117 {
1118  if ( mIsIndexing )
1119  {
1120  if ( mAddedFeatures.contains( fid ) )
1121  {
1122  mAddedFeatures.remove( fid );
1123  }
1124  else
1125  {
1126  // will modify index once current indexing is finished
1127  mDeletedFeatures << fid;
1128  }
1129  return;
1130  }
1131 
1132  if ( !mRTree )
1133  return; // nothing to do if we are not initialized yet
1134 
1135  if ( mGeoms.contains( fid ) )
1136  {
1137  mRTree->deleteData( rect2region( mGeoms[fid]->boundingBox() ), fid );
1138  delete mGeoms.take( fid );
1139  }
1140 
1141 }
1142 
1143 void QgsPointLocator::onGeometryChanged( QgsFeatureId fid, const QgsGeometry &geom )
1144 {
1145  Q_UNUSED( geom )
1146  onFeatureDeleted( fid );
1147  onFeatureAdded( fid );
1148 }
1149 
1150 void QgsPointLocator::onAttributeValueChanged( QgsFeatureId fid, int idx, const QVariant &value )
1151 {
1152  Q_UNUSED( idx )
1153  Q_UNUSED( value )
1154  if ( mContext )
1155  {
1156  onFeatureDeleted( fid );
1157  onFeatureAdded( fid );
1158  }
1159 }
1160 
1161 
1162 QgsPointLocator::Match QgsPointLocator::nearestVertex( const QgsPointXY &point, double tolerance, MatchFilter *filter, bool relaxed )
1163 {
1164  if ( !prepare( relaxed ) )
1165  return Match();
1166 
1167  Match m;
1168  QgsPointLocator_VisitorNearestVertex visitor( this, m, point, filter );
1169  QgsRectangle rect( point.x() - tolerance, point.y() - tolerance, point.x() + tolerance, point.y() + tolerance );
1170  mRTree->intersectsWithQuery( rect2region( rect ), visitor );
1171  if ( m.isValid() && m.distance() > tolerance )
1172  return Match(); // make sure that only match strictly within the tolerance is returned
1173  return m;
1174 }
1175 
1176 QgsPointLocator::Match QgsPointLocator::nearestCentroid( const QgsPointXY &point, double tolerance, MatchFilter *filter, bool relaxed )
1177 {
1178  if ( !prepare( relaxed ) )
1179  return Match();
1180 
1181  Match m;
1182  QgsPointLocator_VisitorNearestCentroid visitor( this, m, point, filter );
1183 
1184  QgsRectangle rect( point.x() - tolerance, point.y() - tolerance, point.x() + tolerance, point.y() + tolerance );
1185  mRTree->intersectsWithQuery( rect2region( rect ), visitor );
1186  if ( m.isValid() && m.distance() > tolerance )
1187  return Match(); // make sure that only match strictly within the tolerance is returned
1188  return m;
1189 }
1190 
1191 QgsPointLocator::Match QgsPointLocator::nearestMiddleOfSegment( const QgsPointXY &point, double tolerance, MatchFilter *filter, bool relaxed )
1192 {
1193  if ( !prepare( relaxed ) )
1194  return Match();
1195 
1196  Match m;
1197  QgsPointLocator_VisitorNearestMiddleOfSegment visitor( this, m, point, filter );
1198 
1199  QgsRectangle rect( point.x() - tolerance, point.y() - tolerance, point.x() + tolerance, point.y() + tolerance );
1200  mRTree->intersectsWithQuery( rect2region( rect ), visitor );
1201  if ( m.isValid() && m.distance() > tolerance )
1202  return Match(); // make sure that only match strictly within the tolerance is returned
1203  return m;
1204 }
1205 
1206 QgsPointLocator::Match QgsPointLocator::nearestEdge( const QgsPointXY &point, double tolerance, MatchFilter *filter, bool relaxed )
1207 {
1208  if ( !prepare( relaxed ) )
1209  return Match();
1210 
1211  QgsWkbTypes::GeometryType geomType = mLayer->geometryType();
1212  if ( geomType == QgsWkbTypes::PointGeometry )
1213  return Match();
1214 
1215  Match m;
1216  QgsPointLocator_VisitorNearestEdge visitor( this, m, point, filter );
1217  QgsRectangle rect( point.x() - tolerance, point.y() - tolerance, point.x() + tolerance, point.y() + tolerance );
1218  mRTree->intersectsWithQuery( rect2region( rect ), visitor );
1219  if ( m.isValid() && m.distance() > tolerance )
1220  return Match(); // make sure that only match strictly within the tolerance is returned
1221  return m;
1222 }
1223 
1224 QgsPointLocator::Match QgsPointLocator::nearestArea( const QgsPointXY &point, double tolerance, MatchFilter *filter, bool relaxed )
1225 {
1226  if ( !prepare( relaxed ) )
1227  return Match();
1228 
1229  MatchList mlist = pointInPolygon( point );
1230  if ( !mlist.isEmpty() && mlist.at( 0 ).isValid() )
1231  {
1232  return mlist.at( 0 );
1233  }
1234 
1235  if ( tolerance == 0 )
1236  {
1237  return Match();
1238  }
1239 
1240  // discard point and line layers to keep only polygons
1241  QgsWkbTypes::GeometryType geomType = mLayer->geometryType();
1242  if ( geomType == QgsWkbTypes::PointGeometry || geomType == QgsWkbTypes::LineGeometry )
1243  return Match();
1244 
1245  // use edges for adding tolerance
1246  Match m = nearestEdge( point, tolerance, filter );
1247  if ( m.isValid() )
1248  return Match( Area, m.layer(), m.featureId(), m.distance(), m.point() );
1249  else
1250  return Match();
1251 }
1252 
1253 
1255 {
1256  if ( !prepare( relaxed ) )
1257  return MatchList();
1258 
1259  QgsWkbTypes::GeometryType geomType = mLayer->geometryType();
1260  if ( geomType == QgsWkbTypes::PointGeometry )
1261  return MatchList();
1262 
1263  MatchList lst;
1264  QgsPointLocator_VisitorEdgesInRect visitor( this, lst, rect, filter );
1265  mRTree->intersectsWithQuery( rect2region( rect ), visitor );
1266 
1267  return lst;
1268 }
1269 
1271 {
1272  QgsRectangle rect( point.x() - tolerance, point.y() - tolerance, point.x() + tolerance, point.y() + tolerance );
1273  return edgesInRect( rect, filter, relaxed );
1274 }
1275 
1277 {
1278  if ( !prepare( relaxed ) )
1279  return MatchList();
1280 
1281  MatchList lst;
1282  QgsPointLocator_VisitorVerticesInRect visitor( this, lst, rect, filter );
1283  mRTree->intersectsWithQuery( rect2region( rect ), visitor );
1284 
1285  return lst;
1286 }
1287 
1289 {
1290  QgsRectangle rect( point.x() - tolerance, point.y() - tolerance, point.x() + tolerance, point.y() + tolerance );
1291  return verticesInRect( rect, filter, relaxed );
1292 }
1293 
1295 {
1296  if ( !prepare( relaxed ) )
1297  return MatchList();
1298 
1299  QgsWkbTypes::GeometryType geomType = mLayer->geometryType();
1300  if ( geomType == QgsWkbTypes::PointGeometry || geomType == QgsWkbTypes::LineGeometry )
1301  return MatchList();
1302 
1303  MatchList lst;
1304  QgsPointLocator_VisitorArea visitor( this, point, lst );
1305  mRTree->intersectsWithQuery( point2point( point ), visitor );
1306  return lst;
1307 }
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:81
QgsMapLayer::crs
QgsCoordinateReferenceSystem crs
Definition: qgsmaplayer.h:88
QgsPointLocator_VisitorArea
Definition: qgspointlocator.cpp:306
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
QgsPointXY::y
double y
Definition: qgspointxy.h:48
QgsException
Definition: qgsexception.h:34
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:2836
QgsCoordinateTransformContext
Definition: qgscoordinatetransformcontext.h:57
QgsPointLocator_VisitorEdgesInRect::visitData
void visitData(std::vector< const IData * > &v) override
Definition: qgspointlocator.cpp:511
QgsRenderContext::expressionContext
QgsExpressionContext & expressionContext()
Gets the expression context.
Definition: qgsrendercontext.h:580
qgslinestring.h
QgsWkbTypes::NullGeometry
@ NullGeometry
Definition: qgswkbtypes.h:145
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:1895
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:781
QgsGeometry::isMultipart
bool isMultipart() const
Returns true if WKB of the geometry is of WKBMulti* type.
Definition: qgsgeometry.cpp:377
LEFT
#define LEFT(x)
Definition: priorityqueue.h:38
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:1224
QgsRectangle::xMaximum
double xMaximum() const
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:162
qgsfeatureiterator.h
QgsExpressionContextUtils::layerScope
static QgsExpressionContextScope * layerScope(const QgsMapLayer *layer)
Creates a new scope which contains variables and functions relating to a QgsMapLayer.
Definition: qgsexpressioncontextutils.cpp:264
QgsGeometry::centroid
QgsGeometry centroid() const
Returns the center of mass of a geometry.
Definition: qgsgeometry.cpp:2153
QgsFeature::geometry
QgsGeometry geometry
Definition: qgsfeature.h:71
qgis.h
QgsRenderContext
Definition: qgsrendercontext.h:57
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:595
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:1888
QgsPointLocator::~QgsPointLocator
~QgsPointLocator() override
Definition: qgspointlocator.cpp:755
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:190
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:696
QgsPointLocator_VisitorNearestVertex
Definition: qgspointlocator.cpp:96
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:876
QgsPointLocator_VisitorMiddlesInRect::visitData
void visitData(const IData &d) override
Definition: qgspointlocator.cpp:647
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:1254
QgsPointLocator_VisitorCentroidsInRect
Definition: qgspointlocator.cpp:591
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
Definition: qgsrectangle.h:41
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
Definition: qgspointlocator.cpp:196
QgsPointLocator::init
bool init(int maxFeaturesToIndex=-1, bool relaxed=false)
Prepare the index for queries.
Definition: qgspointlocator.cpp:826
QgsTaskManager::addTask
long addTask(QgsTask *task, int priority=0)
Adds a task to the manager.
Definition: qgstaskmanager.cpp:416
QgsPointLocator_VisitorNearestCentroid
Definition: qgspointlocator.cpp:144
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:1162
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:2815
QgsFeatureRequest::setFilterRect
QgsFeatureRequest & setFilterRect(const QgsRectangle &rectangle)
Sets the rectangle from which features will be taken.
Definition: qgsfeaturerequest.cpp:97
QgsVectorLayer::fields
QgsFields fields() const FINAL
Returns the list of fields of this layer.
Definition: qgsvectorlayer.cpp:3280
QgsPointLocator::rebuildIndex
bool rebuildIndex(int maxFeaturesToIndex=-1)
Definition: qgspointlocator.cpp:894
QgsFeature::id
QgsFeatureId id
Definition: qgsfeature.h:68
QgsPointLocator_VisitorCentroidsInRect::visitData
void visitData(std::vector< const IData * > &v) override
Definition: qgspointlocator.cpp:603
QgsFeatureRequest
Definition: qgsfeaturerequest.h:75
QgsPointLocator_VisitorMiddlesInRect::visitNode
void visitNode(const INode &n) override
Definition: qgspointlocator.cpp:644
QgsGeometry::intersects
bool intersects(const QgsRectangle &rectangle) const
Returns true if this geometry exactly intersects with a rectangle.
Definition: qgsgeometry.cpp:1144
_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:137
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:1276
_CohenSutherland::computeOutCode
OutCode computeOutCode(double x, double y)
Definition: qgspointlocator.cpp:351
QgsPointLocator_VisitorEdgesInRect::visitNode
void visitNode(const INode &n) override
Definition: qgspointlocator.cpp:510
QgsPointLocator::MatchList
class QList< QgsPointLocator::Match > MatchList
Definition: qgspointlocator.h:295
QgsAbstractGeometry::const_part_iterator
Definition: qgsabstractgeometry.h:772
QgsPointLocator_DumpTree
Definition: qgspointlocator.cpp:689
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:1191
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:869
QgsPointLocator_VisitorVerticesInRect::QgsPointLocator_VisitorVerticesInRect
QgsPointLocator_VisitorVerticesInRect(QgsPointLocator *pl, QgsPointLocator::MatchList &lst, const QgsRectangle &srcRect, QgsPointLocator::MatchFilter *filter=nullptr)
Constructs the visitor.
Definition: qgspointlocator.cpp:548
QgsPointLocator_VisitorNearestEdge
Definition: qgspointlocator.cpp:256
QgsApplication::taskManager
static QgsTaskManager * taskManager()
Returns the application's task manager, used for managing application wide background task handling.
Definition: qgsapplication.cpp:2084
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:902
QgsPointLocator::setExtent
void setExtent(const QgsRectangle *extent)
Configure extent - if not nullptr, it will index only that area.
Definition: qgspointlocator.cpp:770
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:645
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
Definition: qgspointlocator.cpp:544
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:558
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
Definition: qgspointlocator.cpp:633
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
qgsrenderer.h
_CohenSutherland::mRect
QgsRectangle mRect
Definition: qgspointlocator.cpp:349
QgsFeatureRequest::setNoAttributes
QgsFeatureRequest & setNoAttributes()
Set that no attributes will be fetched.
Definition: qgsfeaturerequest.cpp:197
QgsCoordinateReferenceSystem
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
QgsRectangle::yMaximum
double yMaximum() const
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:172
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:184
qgsvectorlayer.h
QgsPointXY
Definition: qgspointxy.h:43
QgsPointLocator::destinationCrs
QgsCoordinateReferenceSystem destinationCrs() const
Gets destination CRS - may be an invalid QgsCoordinateReferenceSystem if not doing OTF reprojection.
Definition: qgspointlocator.cpp:765
QgsPointLocator_VisitorEdgesInRect
Definition: qgspointlocator.cpp:500
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:1559
QgsPointLocator_VisitorVerticesInRect::visitData
void visitData(std::vector< const IData * > &v) override
Definition: qgspointlocator.cpp:556
_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:142
QgsPointLocator_VisitorNearestCentroid::QgsPointLocator_VisitorNearestCentroid
QgsPointLocator_VisitorNearestCentroid(QgsPointLocator *pl, QgsPointLocator::Match &m, const QgsPointXY &srcPoint, QgsPointLocator::MatchFilter *filter=nullptr)
Definition: qgspointlocator.cpp:154
QgsWkbTypes::PointGeometry
@ PointGeometry
Definition: qgswkbtypes.h:141
qgsgeometry.h
QgsWkbTypes::GeometryType
GeometryType
The geometry types are used to group QgsWkbTypes::Type in a coarse way.
Definition: qgswkbtypes.h:139
QgsAbstractGeometry::vertex_iterator
Definition: qgsabstractgeometry.h:832
QgsFeatureIterator::nextFeature
bool nextFeature(QgsFeature &f)
Definition: qgsfeatureiterator.h:373
QgsGeometry
Definition: qgsgeometry.h:122
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
Definition: qgsvectorlayer.h:385
QgsFeature::hasGeometry
bool hasGeometry() const
Returns true if the feature has an associated geometry.
Definition: qgsfeature.cpp:197
_CohenSutherland
Definition: qgspointlocator.cpp:337
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
QgsPointXY::x
double x
Definition: qgspointxy.h:47
QgsVectorLayerFeatureSource
Definition: qgsvectorlayerfeatureiterator.h:51
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:1294
QgsPointLocator
The class defines interface for querying point location:
Definition: qgspointlocator.h:99
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:735
QgsGeometry::convertToType
QgsGeometry convertToType(QgsWkbTypes::GeometryType destType, bool destMultipart=false) const
Try to convert the geometry to the requested type.
Definition: qgsgeometry.cpp:1450
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:3009
QgsPointLocator_VisitorNearestVertex::visitData
void visitData(std::vector< const IData * > &v) override
Definition: qgspointlocator.cpp:107
QgsPointLocator_VisitorArea::visitNode
void visitNode(const INode &n) override
Definition: qgspointlocator.cpp:316
QgsRectangle::yMinimum
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:177
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:1176
QgsPointLocator::destroyIndex
void destroyIndex()
Definition: qgspointlocator.cpp:1025
QgsPointLocator::MatchFilter
Interface that allows rejection of some matches in intersection queries (e.g.
Definition: qgspointlocator.h:305
QgsPointLocator_Stream
Definition: qgspointlocator.cpp:68
QgsGeometry::boundingBox
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
Definition: qgsgeometry.cpp:962
qgspointlocatorinittask.h
qgspointlocator.h
QgsPointLocator_VisitorNearestMiddleOfSegment::QgsPointLocator_VisitorNearestMiddleOfSegment
QgsPointLocator_VisitorNearestMiddleOfSegment(QgsPointLocator *pl, QgsPointLocator::Match &m, const QgsPointXY &srcPoint, QgsPointLocator::MatchFilter *filter=nullptr)
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:1206
QgsFeature
Definition: qgsfeature.h:55
QgsPointLocator_VisitorMiddlesInRect::QgsPointLocator_VisitorMiddlesInRect
QgsPointLocator_VisitorMiddlesInRect(QgsPointLocator *pl, QgsPointLocator::MatchList &lst, const QgsRectangle &srcRect, QgsPointLocator::MatchFilter *filter=nullptr)
Constructs the visitor.
Definition: qgspointlocator.cpp:637
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:1858
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:555
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:1851
QgsPointLocator_VisitorArea::QgsPointLocator_VisitorArea
QgsPointLocator_VisitorArea(QgsPointLocator *pl, const QgsPointXY &origPt, QgsPointLocator::MatchList &list)
constructor
Definition: qgspointlocator.cpp:310
QgsCoordinateTransform
Definition: qgscoordinatetransform.h:52
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:126
QgsFeatureIterator
Definition: qgsfeatureiterator.h:263
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:605
QgsPointLocator_VisitorCentroidsInRect::visitNode
void visitNode(const INode &n) override
Definition: qgspointlocator.cpp:602
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:861
QgsRectangle::xMinimum
double xMinimum() const
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:167
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:644
QgsPointLocator_VisitorEdgesInRect::visitData
void visitData(const IData &d) override
Definition: qgspointlocator.cpp:513
QgsFeatureId
qint64 QgsFeatureId
Definition: qgsfeatureid.h:25
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:503
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:881
QgsVectorLayer::featureAdded
void featureAdded(QgsFeatureId fid)
Emitted when a new feature has been added to the layer.