QGIS API Documentation  2.10.1-Pisa
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
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 "qgsgeometry.h"
19 #include "qgsvectorlayer.h"
20 #include "qgswkbptr.h"
21 
22 #include <spatialindex/SpatialIndex.h>
23 
24 #include <QLinkedListIterator>
25 
26 using namespace SpatialIndex;
27 
28 
29 
30 static SpatialIndex::Point point2point( const QgsPoint& point )
31 {
32  double plow[2];
33  plow[0] = point.x();
34  plow[1] = point.y();
35  return Point( plow, 2 );
36 }
37 
38 
39 static SpatialIndex::Region rect2region( const QgsRectangle& rect )
40 {
41  double pLow[2], pHigh[2];
42  pLow[0] = rect.xMinimum();
43  pLow[1] = rect.yMinimum();
44  pHigh[0] = rect.xMaximum();
45  pHigh[1] = rect.yMaximum();
46  return SpatialIndex::Region( pLow, pHigh, 2 );
47 }
48 
49 
50 // Ahh.... another magic number. Taken from QgsVectorLayer::snapToGeometry() call to closestSegmentWithContext().
51 // The default epsilon used for sqrDistToSegment (1e-8) is too high when working with lat/lon coordinates
52 // I still do not fully understand why the sqrDistToSegment() code uses epsilon and if the square distance
53 // is lower than epsilon it will have a special logic...
54 static const double POINT_LOC_EPSILON = 1e-12;
55 
57 
58 
60 class QgsPointLocator_Stream : public IDataStream
61 {
62  public:
63  QgsPointLocator_Stream( const QLinkedList<RTree::Data*>& dataList ) : mDataList( dataList ), mIt( mDataList ) { }
65 
66  virtual IData* getNext() override { return mIt.next(); }
67  virtual bool hasNext() override { return mIt.hasNext(); }
68 
69  virtual uint32_t size() override { Q_ASSERT( 0 && "not available" ); return 0; }
70  virtual void rewind() override { Q_ASSERT( 0 && "not available" ); }
71 
72  private:
73  QLinkedList<RTree::Data*> mDataList;
75 };
76 
77 
79 
80 
82 class QgsPointLocator_VisitorNearestVertex : public IVisitor
83 {
84  public:
86  : mLocator( pl ), mBest( m ), mSrcPoint( srcPoint ), mFilter( filter ) {}
87 
88  void visitNode( const INode& n ) override { Q_UNUSED( n ); }
89  void visitData( std::vector<const IData*>& v ) override { Q_UNUSED( v ); }
90 
91  void visitData( const IData& d ) override
92  {
93  QgsFeatureId id = d.getIdentifier();
94  QgsGeometry* geom = mLocator->mGeoms.value( id );
95  int vertexIndex, beforeVertex, afterVertex;
96  double sqrDist;
97  QgsPoint pt = geom->closestVertex( mSrcPoint, vertexIndex, beforeVertex, afterVertex, sqrDist );
98 
99  QgsPointLocator::Match m( QgsPointLocator::Vertex, mLocator->mLayer, id, sqrt( sqrDist ), pt, vertexIndex );
100  // in range queries the filter may reject some matches
101  if ( mFilter && !mFilter->acceptMatch( m ) )
102  return;
103 
104  if ( !mBest.isValid() || m.distance() < mBest.distance() )
105  mBest = m;
106  }
107 
108  private:
109  QgsPointLocator* mLocator;
110  QgsPointLocator::Match& mBest;
111  QgsPoint mSrcPoint;
113 };
114 
115 
117 
118 
120 class QgsPointLocator_VisitorNearestEdge : public IVisitor
121 {
122  public:
124  : mLocator( pl ), mBest( m ), mSrcPoint( srcPoint ), mFilter( filter ) {}
125 
126  void visitNode( const INode& n ) override { Q_UNUSED( n ); }
127  void visitData( std::vector<const IData*>& v ) override { Q_UNUSED( v ); }
128 
129  void visitData( const IData& d ) override
130  {
131  QgsFeatureId id = d.getIdentifier();
132  QgsGeometry* geom = mLocator->mGeoms.value( id );
133  QgsPoint pt;
134  int afterVertex;
135  double sqrDist = geom->closestSegmentWithContext( mSrcPoint, pt, afterVertex, 0, POINT_LOC_EPSILON );
136  if ( sqrDist < 0 )
137  return;
138 
139  QgsPoint edgePoints[2];
140  edgePoints[0] = geom->vertexAt( afterVertex - 1 );
141  edgePoints[1] = geom->vertexAt( afterVertex );
142  QgsPointLocator::Match m( QgsPointLocator::Edge, mLocator->mLayer, id, sqrt( sqrDist ), pt, afterVertex - 1, edgePoints );
143  // in range queries the filter may reject some matches
144  if ( mFilter && !mFilter->acceptMatch( m ) )
145  return;
146 
147  if ( !mBest.isValid() || m.distance() < mBest.distance() )
148  mBest = m;
149  }
150 
151  private:
152  QgsPointLocator* mLocator;
153  QgsPointLocator::Match& mBest;
154  QgsPoint mSrcPoint;
156 };
157 
158 
160 
161 
163 class QgsPointLocator_VisitorArea : public IVisitor
164 {
165  public:
168  : mLocator( pl ), mList( list ), mGeomPt( QgsGeometry::fromPoint( origPt ) ) {}
169 
170  ~QgsPointLocator_VisitorArea() { delete mGeomPt; }
171 
172  void visitNode( const INode& n ) override { Q_UNUSED( n ); }
173  void visitData( std::vector<const IData*>& v ) override { Q_UNUSED( v ); }
174 
175  void visitData( const IData& d ) override
176  {
177  QgsFeatureId id = d.getIdentifier();
178  QgsGeometry* g = mLocator->mGeoms.value( id );
179  if ( g->intersects( mGeomPt ) )
180  mList << QgsPointLocator::Match( QgsPointLocator::Area, mLocator->mLayer, id, 0, QgsPoint() );
181  }
182  private:
183  QgsPointLocator* mLocator;
185  QgsGeometry* mGeomPt;
186 };
187 
188 
190 
191 // code adapted from
192 // http://en.wikipedia.org/wiki/Cohen%E2%80%93Sutherland_algorithm
194 {
195  _CohenSutherland( const QgsRectangle& rect ) : mRect( rect ) {}
196 
197  typedef int OutCode;
198 
199  static const int INSIDE = 0; // 0000
200  static const int LEFT = 1; // 0001
201  static const int RIGHT = 2; // 0010
202  static const int BOTTOM = 4; // 0100
203  static const int TOP = 8; // 1000
204 
206 
207  OutCode computeOutCode( double x, double y )
208  {
209  OutCode code = INSIDE; // initialised as being inside of clip window
210  if ( x < mRect.xMinimum() ) // to the left of clip window
211  code |= LEFT;
212  else if ( x > mRect.xMaximum() ) // to the right of clip window
213  code |= RIGHT;
214  if ( y < mRect.yMinimum() ) // below the clip window
215  code |= BOTTOM;
216  else if ( y > mRect.yMaximum() ) // above the clip window
217  code |= TOP;
218  return code;
219  }
220 
221  bool isSegmentInRect( double x0, double y0, double x1, double y1 )
222  {
223  // compute outcodes for P0, P1, and whatever point lies outside the clip rectangle
224  OutCode outcode0 = computeOutCode( x0, y0 );
225  OutCode outcode1 = computeOutCode( x1, y1 );
226  bool accept = false;
227 
228  while ( true )
229  {
230  if ( !( outcode0 | outcode1 ) )
231  {
232  // Bitwise OR is 0. Trivially accept and get out of loop
233  accept = true;
234  break;
235  }
236  else if ( outcode0 & outcode1 )
237  {
238  // Bitwise AND is not 0. Trivially reject and get out of loop
239  break;
240  }
241  else
242  {
243  // failed both tests, so calculate the line segment to clip
244  // from an outside point to an intersection with clip edge
245  double x, y;
246 
247  // At least one endpoint is outside the clip rectangle; pick it.
248  OutCode outcodeOut = outcode0 ? outcode0 : outcode1;
249 
250  // Now find the intersection point;
251  // use formulas y = y0 + slope * (x - x0), x = x0 + (1 / slope) * (y - y0)
252  if ( outcodeOut & TOP )
253  { // point is above the clip rectangle
254  x = x0 + ( x1 - x0 ) * ( mRect.yMaximum() - y0 ) / ( y1 - y0 );
255  y = mRect.yMaximum();
256  }
257  else if ( outcodeOut & BOTTOM )
258  { // point is below the clip rectangle
259  x = x0 + ( x1 - x0 ) * ( mRect.yMinimum() - y0 ) / ( y1 - y0 );
260  y = mRect.yMinimum();
261  }
262  else if ( outcodeOut & RIGHT )
263  { // point is to the right of clip rectangle
264  y = y0 + ( y1 - y0 ) * ( mRect.xMaximum() - x0 ) / ( x1 - x0 );
265  x = mRect.xMaximum();
266  }
267  else if ( outcodeOut & LEFT )
268  { // point is to the left of clip rectangle
269  y = y0 + ( y1 - y0 ) * ( mRect.xMinimum() - x0 ) / ( x1 - x0 );
270  x = mRect.xMinimum();
271  }
272  else
273  break;
274 
275  // Now we move outside point to intersection point to clip
276  // and get ready for next pass.
277  if ( outcodeOut == outcode0 )
278  {
279  x0 = x;
280  y0 = y;
281  outcode0 = computeOutCode( x0, y0 );
282  }
283  else
284  {
285  x1 = x;
286  y1 = y;
287  outcode1 = computeOutCode( x1, y1 );
288  }
289  }
290  }
291  return accept;
292  }
293 };
294 
295 
297 {
298  // this code is stupidly based on QgsGeometry::closestSegmentWithContext
299  // we need iterator for segments...
300 
302  unsigned char* wkb = const_cast<unsigned char*>( geom->asWkb() ); // we're not changing wkb, just need non-const for QgsWkbPtr
303  if ( !wkb )
304  return lst;
305 
306  _CohenSutherland cs( rect );
307 
308  QgsWkbPtr wkbPtr( wkb + 1 );
309  QGis::WkbType wkbType;
310  wkbPtr >> wkbType;
311 
312  bool hasZValue = false;
313  switch ( wkbType )
314  {
315  case QGis::WKBPoint25D:
316  case QGis::WKBPoint:
318  case QGis::WKBMultiPoint:
319  {
320  // Points have no lines
321  return lst;
322  }
323 
325  hasZValue = true;
326  //intentional fall-through
327  case QGis::WKBLineString:
328  {
329  int nPoints;
330  wkbPtr >> nPoints;
331 
332  double prevx = 0.0, prevy = 0.0;
333  for ( int index = 0; index < nPoints; ++index )
334  {
335  double thisx, thisy;
336  wkbPtr >> thisx >> thisy;
337  if ( hasZValue )
338  wkbPtr += sizeof( double );
339 
340  if ( index > 0 )
341  {
342  if ( cs.isSegmentInRect( prevx, prevy, thisx, thisy ) )
343  {
344  QgsPoint edgePoints[2];
345  edgePoints[0].set( prevx, prevy );
346  edgePoints[1].set( thisx, thisy );
347  lst << QgsPointLocator::Match( QgsPointLocator::Edge, vl, fid, 0, QgsPoint(), index - 1, edgePoints );
348  }
349  }
350 
351  prevx = thisx;
352  prevy = thisy;
353  }
354  break;
355  }
356 
358  hasZValue = true;
359  //intentional fall-through
361  {
362  int nLines;
363  wkbPtr >> nLines;
364  for ( int linenr = 0, pointIndex = 0; linenr < nLines; ++linenr )
365  {
366  wkbPtr += 1 + sizeof( int );
367  int nPoints;
368  wkbPtr >> nPoints;
369 
370  double prevx = 0.0, prevy = 0.0;
371  for ( int pointnr = 0; pointnr < nPoints; ++pointnr )
372  {
373  double thisx, thisy;
374  wkbPtr >> thisx >> thisy;
375  if ( hasZValue )
376  wkbPtr += sizeof( double );
377 
378  if ( pointnr > 0 )
379  {
380  if ( cs.isSegmentInRect( prevx, prevy, thisx, thisy ) )
381  {
382  QgsPoint edgePoints[2];
383  edgePoints[0].set( prevx, prevy );
384  edgePoints[1].set( thisx, thisy );
385  lst << QgsPointLocator::Match( QgsPointLocator::Edge, vl, fid, 0, QgsPoint(), pointIndex - 1, edgePoints );
386  }
387  }
388 
389  prevx = thisx;
390  prevy = thisy;
391  ++pointIndex;
392  }
393  }
394  break;
395  }
396 
397  case QGis::WKBPolygon25D:
398  hasZValue = true;
399  //intentional fall-through
400  case QGis::WKBPolygon:
401  {
402  int nRings;
403  wkbPtr >> nRings;
404 
405  for ( int ringnr = 0, pointIndex = 0; ringnr < nRings; ++ringnr )//loop over rings
406  {
407  int nPoints;
408  wkbPtr >> nPoints;
409 
410  double prevx = 0.0, prevy = 0.0;
411  for ( int pointnr = 0; pointnr < nPoints; ++pointnr )//loop over points in a ring
412  {
413  double thisx, thisy;
414  wkbPtr >> thisx >> thisy;
415  if ( hasZValue )
416  wkbPtr += sizeof( double );
417 
418  if ( pointnr > 0 )
419  {
420  if ( cs.isSegmentInRect( prevx, prevy, thisx, thisy ) )
421  {
422  QgsPoint edgePoints[2];
423  edgePoints[0].set( prevx, prevy );
424  edgePoints[1].set( thisx, thisy );
425  lst << QgsPointLocator::Match( QgsPointLocator::Edge, vl, fid, 0, QgsPoint(), pointIndex - 1, edgePoints );
426  }
427  }
428 
429  prevx = thisx;
430  prevy = thisy;
431  ++pointIndex;
432  }
433  }
434  break;
435  }
436 
438  hasZValue = true;
439  //intentional fall-through
441  {
442  int nPolygons;
443  wkbPtr >> nPolygons;
444  for ( int polynr = 0, pointIndex = 0; polynr < nPolygons; ++polynr )
445  {
446  wkbPtr += 1 + sizeof( int );
447  int nRings;
448  wkbPtr >> nRings;
449  for ( int ringnr = 0; ringnr < nRings; ++ringnr )
450  {
451  int nPoints;
452  wkbPtr >> nPoints;
453 
454  double prevx = 0.0, prevy = 0.0;
455  for ( int pointnr = 0; pointnr < nPoints; ++pointnr )
456  {
457  double thisx, thisy;
458  wkbPtr >> thisx >> thisy;
459  if ( hasZValue )
460  wkbPtr += sizeof( double );
461 
462  if ( pointnr > 0 )
463  {
464  if ( cs.isSegmentInRect( prevx, prevy, thisx, thisy ) )
465  {
466  QgsPoint edgePoints[2];
467  edgePoints[0].set( prevx, prevy );
468  edgePoints[1].set( thisx, thisy );
469  lst << QgsPointLocator::Match( QgsPointLocator::Edge, vl, fid, 0, QgsPoint(), pointIndex - 1, edgePoints );
470  }
471  }
472 
473  prevx = thisx;
474  prevy = thisy;
475  ++pointIndex;
476  }
477  }
478  }
479  break;
480  }
481 
482  case QGis::WKBUnknown:
483  default:
484  return lst;
485  break;
486  } // switch (wkbType)
487 
488  return lst;
489 }
490 
492 class QgsPointLocator_VisitorEdgesInRect : public IVisitor
493 {
494  public:
496  : mLocator( pl ), mList( lst ), mSrcRect( srcRect ), mFilter( filter ) {}
497 
498  void visitNode( const INode& n ) override { Q_UNUSED( n ); }
499  void visitData( std::vector<const IData*>& v ) override { Q_UNUSED( v ); }
500 
501  void visitData( const IData& d ) override
502  {
503  QgsFeatureId id = d.getIdentifier();
504  QgsGeometry* geom = mLocator->mGeoms.value( id );
505 
506  foreach ( const QgsPointLocator::Match& m, _geometrySegmentsInRect( geom, mSrcRect, mLocator->mLayer, id ) )
507  {
508  // in range queries the filter may reject some matches
509  if ( mFilter && !mFilter->acceptMatch( m ) )
510  continue;
511 
512  mList << m;
513  }
514  }
515 
516  private:
517  QgsPointLocator* mLocator;
519  QgsRectangle mSrcRect;
521 };
522 
523 
524 
526 #include <QStack>
527 
529 class QgsPointLocator_DumpTree : public SpatialIndex::IQueryStrategy
530 {
531  private:
532  QStack<id_type> ids;
533 
534  public:
535 
536  void getNextEntry( const IEntry& entry, id_type& nextEntry, bool& hasNext ) override
537  {
538  const INode* n = dynamic_cast<const INode*>( &entry );
539  if ( !n )
540  return;
541 
542  QgsDebugMsg( QString( "NODE: %1" ).arg( n->getIdentifier() ) );
543  if ( n->getLevel() > 0 )
544  {
545  // inner nodes
546  for ( uint32_t cChild = 0; cChild < n->getChildrenCount(); cChild++ )
547  {
548  QgsDebugMsg( QString( "- CH: %1" ).arg( n->getChildIdentifier( cChild ) ) );
549  ids.push( n->getChildIdentifier( cChild ) );
550  }
551  }
552  else
553  {
554  // leaves
555  for ( uint32_t cChild = 0; cChild < n->getChildrenCount(); cChild++ )
556  {
557  QgsDebugMsg( QString( "- L: %1" ).arg( n->getChildIdentifier( cChild ) ) );
558  }
559  }
560 
561  if ( ! ids.empty() )
562  {
563  nextEntry = ids.back(); ids.pop();
564  hasNext = true;
565  }
566  else
567  hasNext = false;
568  }
569 };
570 
572 
573 
575  : mStorage( 0 )
576  , mRTree( 0 )
577  , mIsEmptyLayer( false )
578  , mTransform( 0 )
579  , mLayer( layer )
580  , mExtent( 0 )
581 {
582  if ( destCRS )
583  {
584  mTransform = new QgsCoordinateTransform( layer->crs(), *destCRS );
585  }
586 
587  if ( extent )
588  {
589  mExtent = new QgsRectangle( *extent );
590  }
591 
592  mStorage = StorageManager::createNewMemoryStorageManager();
593 
594  connect( mLayer, SIGNAL( featureAdded( QgsFeatureId ) ), this, SLOT( onFeatureAdded( QgsFeatureId ) ) );
595  connect( mLayer, SIGNAL( featureDeleted( QgsFeatureId ) ), this, SLOT( onFeatureDeleted( QgsFeatureId ) ) );
596  connect( mLayer, SIGNAL( geometryChanged( QgsFeatureId, QgsGeometry& ) ), this, SLOT( onGeometryChanged( QgsFeatureId, QgsGeometry& ) ) );
597 }
598 
599 
601 {
602  destroyIndex();
603  delete mStorage;
604  delete mTransform;
605  delete mExtent;
606 }
607 
608 
609 bool QgsPointLocator::init( int maxFeaturesToIndex )
610 {
611  return hasIndex() ? true : rebuildIndex( maxFeaturesToIndex );
612 }
613 
615 {
616  return mRTree != 0 || mIsEmptyLayer;
617 }
618 
619 
620 
621 bool QgsPointLocator::rebuildIndex( int maxFeaturesToIndex )
622 {
623  destroyIndex();
624 
625  QLinkedList<RTree::Data*> dataList;
626  QgsFeature f;
627  QGis::GeometryType geomType = mLayer->geometryType();
628  if ( geomType == QGis::NoGeometry )
629  return true; // nothing to index
630 
631  QgsFeatureRequest request;
633  if ( mExtent )
634  {
635  QgsRectangle rect = *mExtent;
636  if ( mTransform )
637  {
638  try
639  {
641  }
642  catch ( const QgsException& e )
643  {
644  // See http://hub.qgis.org/issues/12634
645  QgsDebugMsg( QString( "could not transform bounding box to map, skipping the snap filter (%1)" ).arg( e.what() ) );
646  }
647  }
648  request.setFilterRect( rect );
649  }
650  QgsFeatureIterator fi = mLayer->getFeatures( request );
651  int indexedCount = 0;
652  while ( fi.nextFeature( f ) )
653  {
654  if ( !f.constGeometry() )
655  continue;
656 
657  if ( mTransform )
658  {
659  try
660  {
661  f.geometry()->transform( *mTransform );
662  }
663  catch ( const QgsException& e )
664  {
665  // See http://hub.qgis.org/issues/12634
666  QgsDebugMsg( QString( "could not transform geometry to map, skipping the snap for it (%1)" ).arg( e.what() ) );
667  continue;
668  }
669  }
670 
671  SpatialIndex::Region r( rect2region( f.constGeometry()->boundingBox() ) );
672  dataList << new RTree::Data( 0, 0, r, f.id() );
673  mGeoms[f.id()] = new QgsGeometry( *f.constGeometry() );
674  ++indexedCount;
675 
676  if ( maxFeaturesToIndex != -1 && indexedCount > maxFeaturesToIndex )
677  {
678  qDeleteAll( dataList );
679  destroyIndex();
680  return false;
681  }
682  }
683 
684  // R-Tree parameters
685  double fillFactor = 0.7;
686  unsigned long indexCapacity = 10;
687  unsigned long leafCapacity = 10;
688  unsigned long dimension = 2;
689  RTree::RTreeVariant variant = RTree::RV_RSTAR;
690  SpatialIndex::id_type indexId;
691 
692  if ( dataList.isEmpty() )
693  {
694  mIsEmptyLayer = true;
695  return true; // no features
696  }
697 
698  QgsPointLocator_Stream stream( dataList );
699  mRTree = RTree::createAndBulkLoadNewRTree( RTree::BLM_STR, stream, *mStorage, fillFactor, indexCapacity,
700  leafCapacity, dimension, variant, indexId );
701  return true;
702 }
703 
704 
706 {
707  delete mRTree;
708  mRTree = 0;
709 
710  mIsEmptyLayer = false;
711 
712  qDeleteAll( mGeoms );
713 
714  mGeoms.clear();
715 }
716 
717 void QgsPointLocator::onFeatureAdded( QgsFeatureId fid )
718 {
719  if ( !mRTree )
720  {
721  if ( mIsEmptyLayer )
722  rebuildIndex(); // first feature - let's built the index
723  return; // nothing to do if we are not initialized yet
724  }
725 
726  QgsFeature f;
727  if ( mLayer->getFeatures( QgsFeatureRequest( fid ) ).nextFeature( f ) )
728  {
729  if ( !f.constGeometry() )
730  return;
731 
732  if ( mTransform )
733  {
734  try
735  {
736  f.geometry()->transform( *mTransform );
737  }
738  catch ( const QgsException& e )
739  {
740  // See http://hub.qgis.org/issues/12634
741  QgsDebugMsg( QString( "could not transform geometry to map, skipping the snap for it (%1)" ).arg( e.what() ) );
742  return;
743  }
744  }
745 
746  QgsRectangle bbox = f.constGeometry()->boundingBox();
747  if ( !bbox.isNull() )
748  {
749  SpatialIndex::Region r( rect2region( bbox ) );
750  mRTree->insertData( 0, 0, r, f.id() );
751  mGeoms[fid] = new QgsGeometry( *f.constGeometry() );
752  }
753  }
754 }
755 
756 void QgsPointLocator::onFeatureDeleted( QgsFeatureId fid )
757 {
758  if ( !mRTree )
759  return; // nothing to do if we are not initialized yet
760 
761  if ( mGeoms.contains( fid ) )
762  {
763  mRTree->deleteData( rect2region( mGeoms[fid]->boundingBox() ), fid );
764  mGeoms.remove( fid );
765  }
766 }
767 
768 void QgsPointLocator::onGeometryChanged( QgsFeatureId fid, QgsGeometry& geom )
769 {
770  Q_UNUSED( geom );
771  onFeatureDeleted( fid );
772  onFeatureAdded( fid );
773 }
774 
775 
777 {
778  if ( !mRTree )
779  {
780  init();
781  if ( !mRTree ) // still invalid?
782  return Match();
783  }
784 
785  Match m;
786  QgsPointLocator_VisitorNearestVertex visitor( this, m, point, filter );
787  QgsRectangle rect( point.x() - tolerance, point.y() - tolerance, point.x() + tolerance, point.y() + tolerance );
788  mRTree->intersectsWithQuery( rect2region( rect ), visitor );
789  if ( m.isValid() && m.distance() > tolerance )
790  return Match(); // // make sure that only match strictly within the tolerance is returned
791  return m;
792 }
793 
795 {
796  if ( !mRTree )
797  {
798  init();
799  if ( !mRTree ) // still invalid?
800  return Match();
801  }
802 
803  Match m;
804  QgsPointLocator_VisitorNearestEdge visitor( this, m, point, filter );
805  QgsRectangle rect( point.x() - tolerance, point.y() - tolerance, point.x() + tolerance, point.y() + tolerance );
806  mRTree->intersectsWithQuery( rect2region( rect ), visitor );
807  if ( m.isValid() && m.distance() > tolerance )
808  return Match(); // // make sure that only match strictly within the tolerance is returned
809  return m;
810 }
811 
813 {
814  if ( !mRTree )
815  {
816  init();
817  if ( !mRTree ) // still invalid?
818  return MatchList();
819  }
820 
821  MatchList lst;
822  QgsPointLocator_VisitorEdgesInRect visitor( this, lst, rect, filter );
823  mRTree->intersectsWithQuery( rect2region( rect ), visitor );
824 
825  return lst;
826 }
827 
829 {
830  QgsRectangle rect( point.x() - tolerance, point.y() - tolerance, point.x() + tolerance, point.y() + tolerance );
831  return edgesInRect( rect, filter );
832 }
833 
834 
836 {
837  if ( !mRTree )
838  {
839  init();
840  if ( !mRTree ) // still invalid?
841  return MatchList();
842  }
843 
844  MatchList lst;
845  QgsPointLocator_VisitorArea visitor( this, point, lst );
846  mRTree->intersectsWithQuery( point2point( point ), visitor );
847  return lst;
848 }
QgsFeatureId id() const
Get the feature ID for this feature.
Definition: qgsfeature.cpp:51
#define LEFT(x)
Definition: priorityqueue.h:39
The class defines interface for querying point location:
QgsPointLocator(QgsVectorLayer *layer, const QgsCoordinateReferenceSystem *destCRS=0, const QgsRectangle *extent=0)
Construct point locator for a layer.
QgsPointLocator_Stream(const QLinkedList< RTree::Data * > &dataList)
Wrapper for iterator of features from vector data provider or vector layer.
static unsigned index
A rectangle specified with double values.
Definition: qgsrectangle.h:35
GeometryType
Definition: qgis.h:155
static QgsPointLocator::MatchList _geometrySegmentsInRect(QgsGeometry *geom, const QgsRectangle &rect, QgsVectorLayer *vl, QgsFeatureId fid)
void visitData(const IData &d) override
double yMaximum() const
Get the y maximum value (top side of rectangle)
Definition: qgsrectangle.h:192
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
QgsPointLocator_VisitorNearestEdge(QgsPointLocator *pl, QgsPointLocator::Match &m, const QgsPoint &srcPoint, QgsPointLocator::MatchFilter *filter=0)
Match nearestEdge(const QgsPoint &point, double tolerance, MatchFilter *filter=0)
Find nearest edges to the specified point - up to distance specified by tolerance Optional filter may...
QgsPointLocator_VisitorArea(QgsPointLocator *pl, const QgsPoint &origPt, QgsPointLocator::MatchList &list)
constructor
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest())
Query the provider for features specified in request.
bool isNull() const
test if the rectangle is null (all coordinates zero or after call to setMinimal()).
QgsRectangle boundingBox() const
Returns the bounding box of this feature.
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
Helper class used when traversing the index looking for edges - builds a list of matches.
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:75
WkbType
Used for symbology operations.
Definition: qgis.h:53
bool rebuildIndex(int maxFeaturesToIndex=-1)
void visitNode(const INode &n) override
static SpatialIndex::Point point2point(const QgsPoint &point)
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:162
Interface that allows rejection of some matches in intersection queries (e.g.
void visitData(std::vector< const IData * > &v) override
virtual uint32_t size() override
double x() const
Definition: qgspoint.h:126
static SpatialIndex::Region rect2region(const QgsRectangle &rect)
virtual bool hasNext() override
double yMinimum() const
Get the y minimum value (bottom side of rectangle)
Definition: qgsrectangle.h:197
bool isEmpty() const
double xMaximum() const
Get the x maximum value (right side of rectangle)
Definition: qgsrectangle.h:182
OutCode computeOutCode(double x, double y)
virtual IData * getNext() override
static const double POINT_LOC_EPSILON
QgsPoint closestVertex(const QgsPoint &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 ...
Helper class to dump the R-index nodes and their content.
This class wraps a request for features to a vector layer (or directly its vector data provider)...
bool isSegmentInRect(double x0, double y0, double x1, double y1)
QList< int > QgsAttributeList
void visitNode(const INode &n) override
QGis::GeometryType geometryType() const
Returns point, line or polygon.
Helper class used when traversing the index with areas - builds a list of matches.
double closestSegmentWithContext(const QgsPoint &point, QgsPoint &minDistPoint, int &afterVertex, double *leftOf=0, double epsilon=DEFAULT_SEGMENT_EPSILON) const
Searches for the closest segment of geometry to the given point.
int remove(const Key &key)
double distance() const
for vertex / edge match units depending on what class returns it (geom.cache: layer units...
void set(double x, double y)
Definition: qgspoint.h:117
void visitData(const IData &d) override
Helper class used when traversing the index looking for vertices - builds a list of matches...
class QList< Match > MatchList
A class to represent a point.
Definition: qgspoint.h:63
void clear()
QgsGeometry * geometry()
Get the geometry object associated with this feature.
Definition: qgsfeature.cpp:62
QString what() const
Definition: qgsexception.h:35
Helper class for bulk loading of R-trees.
#define RIGHT(x)
Definition: priorityqueue.h:40
void visitData(const IData &d) override
void visitNode(const INode &n) override
bool init(int maxFeaturesToIndex=-1)
Prepare the index for queries.
void visitData(std::vector< const IData * > &v) override
Class for storing a coordinate reference system (CRS)
_CohenSutherland(const QgsRectangle &rect)
void getNextEntry(const IEntry &entry, id_type &nextEntry, bool &hasNext) override
const QgsGeometry * constGeometry() const
Gets a const pointer to the geometry object associated with this feature.
Definition: qgsfeature.cpp:68
void visitData(const IData &d) override
Class for doing transforms between two map coordinate systems.
int transform(const QgsCoordinateTransform &ct)
Transform this geometry as described by CoordinateTransform ct.
qint64 QgsFeatureId
Definition: qgsfeature.h:31
QgsPointLocator_VisitorNearestVertex(QgsPointLocator *pl, QgsPointLocator::Match &m, const QgsPoint &srcPoint, QgsPointLocator::MatchFilter *filter=0)
double y() const
Definition: qgspoint.h:134
const QgsCoordinateReferenceSystem & crs() const
Returns layer's spatial reference system.
Helper class used when traversing the index looking for edges - builds a list of matches.
void visitNode(const INode &n) override
MatchList pointInPolygon(const QgsPoint &point)
find out if the point is in any polygons
bool contains(const Key &key) const
virtual void rewind() override
bool nextFeature(QgsFeature &f)
bool hasIndex() const
Indicate whether the data have been already indexed.
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
bool intersects(const QgsRectangle &r) const
Test for intersection with a rectangle (uses GEOS)
Represents a vector layer which manages a vector based data sets.
const unsigned char * asWkb() const
Returns the buffer containing this geometry in WKB format.
double xMinimum() const
Get the x minimum value (left side of rectangle)
Definition: qgsrectangle.h:187
Defines a qgis exception class.
Definition: qgsexception.h:25
QgsPoint vertexAt(int atVertex) const
Returns coordinates of a vertex.
void visitData(std::vector< const IData * > &v) override
QgsPointLocator_VisitorEdgesInRect(QgsPointLocator *pl, QgsPointLocator::MatchList &lst, const QgsRectangle &srcRect, QgsPointLocator::MatchFilter *filter=0)
void visitData(std::vector< const IData * > &v) override
QgsFeatureRequest & setFilterRect(const QgsRectangle &rect)
Set rectangle from which features will be taken.
QgsRectangle transformBoundingBox(const QgsRectangle &theRect, TransformDirection direction=ForwardTransform, const bool handle180Crossover=false) const
Match nearestVertex(const QgsPoint &point, double tolerance, MatchFilter *filter=0)
Find nearest vertex to the specified point - up to distance specified by tolerance Optional filter ma...
MatchList edgesInRect(const QgsRectangle &rect, MatchFilter *filter=0)
Find edges within a specified recangle Optional filter may discard unwanted matches.