QGIS API Documentation  2.12.0-Lyon
qgsspatialindex.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsspatialindex.cpp - wrapper class for spatial index library
3  ----------------------
4  begin : December 2006
5  copyright : (C) 2006 by Martin Dobias
6  email : wonder.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 "qgsspatialindex.h"
17 
18 #include "qgsgeometry.h"
19 #include "qgsfeature.h"
20 #include "qgsfeatureiterator.h"
21 #include "qgsrectangle.h"
22 #include "qgslogger.h"
23 
24 #include "SpatialIndex.h"
25 
26 using namespace SpatialIndex;
27 
28 
29 
30 // custom visitor that adds found features to list
31 class QgisVisitor : public SpatialIndex::IVisitor
32 {
33  public:
34  explicit QgisVisitor( QList<QgsFeatureId> & list )
35  : mList( list ) {}
36 
37  void visitNode( const INode& n ) override
38  { Q_UNUSED( n ); }
39 
40  void visitData( const IData& d ) override
41  {
42  mList.append( d.getIdentifier() );
43  }
44 
45  void visitData( std::vector<const IData*>& v ) override
46  { Q_UNUSED( v ); }
47 
48  private:
49  QList<QgsFeatureId>& mList;
50 };
51 
52 class QgsSpatialIndexCopyVisitor : public SpatialIndex::IVisitor
53 {
54  public:
55  explicit QgsSpatialIndexCopyVisitor( SpatialIndex::ISpatialIndex* newIndex )
56  : mNewIndex( newIndex ) {}
57 
58  void visitNode( const INode& n ) override
59  { Q_UNUSED( n ); }
60 
61  void visitData( const IData& d ) override
62  {
63  SpatialIndex::IShape* shape;
64  d.getShape( &shape );
65  mNewIndex->insertData( 0, 0, *shape, d.getIdentifier() );
66  delete shape;
67  }
68 
69  void visitData( std::vector<const IData*>& v ) override
70  { Q_UNUSED( v ); }
71 
72  private:
73  SpatialIndex::ISpatialIndex* mNewIndex;
74 };
75 
76 
78 class QgsFeatureIteratorDataStream : public IDataStream
79 {
80  public:
83  : mFi( fi )
84  , mNextData( 0 )
85  {
86  readNextEntry();
87  }
88 
90  {
91  delete mNextData;
92  }
93 
95  virtual IData* getNext() override
96  {
97  RTree::Data* ret = mNextData;
98  mNextData = 0;
99  readNextEntry();
100  return ret;
101  }
102 
104  virtual bool hasNext() override { return mNextData != 0; }
105 
107  virtual uint32_t size() override { Q_ASSERT( 0 && "not available" ); return 0; }
108 
110  virtual void rewind() override { Q_ASSERT( 0 && "not available" ); }
111 
112  protected:
114  {
115  QgsFeature f;
116  SpatialIndex::Region r;
117  QgsFeatureId id;
118  while ( mFi.nextFeature( f ) )
119  {
120  if ( QgsSpatialIndex::featureInfo( f, r, id ) )
121  {
122  mNextData = new RTree::Data( 0, 0, r, id );
123  return;
124  }
125  }
126  }
127 
128  private:
129  QgsFeatureIterator mFi;
130  RTree::Data* mNextData;
131 };
132 
133 
136 {
137  public:
139  {
140  initTree();
141  }
142 
144  {
145  QgsFeatureIteratorDataStream fids( fi );
146  initTree( &fids );
147  }
148 
150  : QSharedData( other )
151  {
152  initTree();
153 
154  // copy R-tree data one by one (is there a faster way??)
155  double low[] = { DBL_MIN, DBL_MIN };
156  double high[] = { DBL_MAX, DBL_MAX };
157  SpatialIndex::Region query( low, high, 2 );
158  QgsSpatialIndexCopyVisitor visitor( mRTree );
159  other.mRTree->intersectsWithQuery( query, visitor );
160  }
161 
163  {
164  delete mRTree;
165  delete mStorage;
166  }
167 
168  void initTree( IDataStream* inputStream = 0 )
169  {
170  // for now only memory manager
171  mStorage = StorageManager::createNewMemoryStorageManager();
172 
173  // R-Tree parameters
174  double fillFactor = 0.7;
175  unsigned long indexCapacity = 10;
176  unsigned long leafCapacity = 10;
177  unsigned long dimension = 2;
178  RTree::RTreeVariant variant = RTree::RV_RSTAR;
179 
180  // create R-tree
181  SpatialIndex::id_type indexId;
182 
183  if ( inputStream )
184  mRTree = RTree::createAndBulkLoadNewRTree( RTree::BLM_STR, *inputStream, *mStorage, fillFactor, indexCapacity,
185  leafCapacity, dimension, variant, indexId );
186  else
187  mRTree = RTree::createNewRTree( *mStorage, fillFactor, indexCapacity,
188  leafCapacity, dimension, variant, indexId );
189  }
190 
192  SpatialIndex::IStorageManager* mStorage;
193 
195  SpatialIndex::ISpatialIndex* mRTree;
196 };
197 
198 // -------------------------------------------------------------------------
199 
200 
202 {
203  d = new QgsSpatialIndexData;
204 }
205 
207 {
208  d = new QgsSpatialIndexData( fi );
209 }
210 
212  : d( other.d )
213 {
214 }
215 
217 {
218 }
219 
221 {
222  if ( this != &other )
223  d = other.d;
224  return *this;
225 }
226 
228 {
229  double pt1[2], pt2[2];
230  pt1[0] = rect.xMinimum();
231  pt1[1] = rect.yMinimum();
232  pt2[0] = rect.xMaximum();
233  pt2[1] = rect.yMaximum();
234  return Region( pt1, pt2, 2 );
235 }
236 
237 bool QgsSpatialIndex::featureInfo( const QgsFeature& f, SpatialIndex::Region& r, QgsFeatureId &id )
238 {
239  if ( !f.constGeometry() )
240  return false;
241 
242  QgsGeometry g( *f.constGeometry() );
243 
244  id = f.id();
245  r = rectToRegion( g.boundingBox() );
246  return true;
247 }
248 
249 
251 {
252  Region r;
253  QgsFeatureId id;
254  if ( !featureInfo( f, r, id ) )
255  return false;
256 
257  // TODO: handle possible exceptions correctly
258  try
259  {
260  d->mRTree->insertData( 0, 0, r, FID_TO_NUMBER( id ) );
261  return true;
262  }
263  catch ( Tools::Exception &e )
264  {
265  Q_UNUSED( e );
266  QgsDebugMsg( QString( "Tools::Exception caught: " ).arg( e.what().c_str() ) );
267  }
268  catch ( const std::exception &e )
269  {
270  Q_UNUSED( e );
271  QgsDebugMsg( QString( "std::exception caught: " ).arg( e.what() ) );
272  }
273  catch ( ... )
274  {
275  QgsDebugMsg( "unknown spatial index exception caught" );
276  }
277 
278  return false;
279 }
280 
282 {
283  Region r;
284  QgsFeatureId id;
285  if ( !featureInfo( f, r, id ) )
286  return false;
287 
288  // TODO: handle exceptions
289  return d->mRTree->deleteData( r, FID_TO_NUMBER( id ) );
290 }
291 
293 {
294  QList<QgsFeatureId> list;
295  QgisVisitor visitor( list );
296 
297  Region r = rectToRegion( rect );
298 
299  d->mRTree->intersectsWithQuery( r, visitor );
300 
301  return list;
302 }
303 
305 {
306  QList<QgsFeatureId> list;
307  QgisVisitor visitor( list );
308 
309  double pt[2];
310  pt[0] = point.x();
311  pt[1] = point.y();
312  Point p( pt, 2 );
313 
314  d->mRTree->nearestNeighborQuery( neighbors, p, visitor );
315 
316  return list;
317 }
318 
320 {
321  return d->ref;
322 }
QgsFeatureId id() const
Get the feature ID for this feature.
Definition: qgsfeature.cpp:53
Wrapper for iterator of features from vector data provider or vector layer.
virtual uint32_t size() override
returns the total number of entries available in the stream.
A rectangle specified with double values.
Definition: qgsrectangle.h:35
virtual bool hasNext() override
returns true if there are more items in the stream.
SpatialIndex::IStorageManager * mStorage
Storage manager.
QgsSpatialIndex & operator=(const QgsSpatialIndex &other)
Implement assignment operator.
SpatialIndex::ISpatialIndex * mRTree
R-tree containing spatial index.
void initTree(IDataStream *inputStream=0)
QList< QgsFeatureId > intersects(const QgsRectangle &rect) const
Returns features that intersect the specified rectangle.
bool deleteFeature(const QgsFeature &f)
Remove feature from index.
double yMaximum() const
Get the y maximum value (top side of rectangle)
Definition: qgsrectangle.h:196
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
QgsSpatialIndexData(const QgsFeatureIterator &fi)
void visitData(std::vector< const IData * > &v) override
static SpatialIndex::Region rectToRegion(const QgsRectangle &rect)
void visitNode(const INode &n) override
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:76
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:176
QgsSpatialIndexCopyVisitor(SpatialIndex::ISpatialIndex *newIndex)
virtual void rewind() override
sets the stream pointer to the first entry, if possible.
void visitData(std::vector< const IData * > &v) override
double x() const
Get the x value of the point.
Definition: qgspoint.h:126
QgsSpatialIndexData(const QgsSpatialIndexData &other)
void visitNode(const INode &n) override
QgisVisitor(QList< QgsFeatureId > &list)
QgsFeatureIteratorDataStream(const QgsFeatureIterator &fi)
constructor - needs to load all data to a vector for later access when bulk loading ...
double yMinimum() const
Get the y minimum value (bottom side of rectangle)
Definition: qgsrectangle.h:201
double xMaximum() const
Get the x maximum value (right side of rectangle)
Definition: qgsrectangle.h:186
#define FID_TO_NUMBER(fid)
Definition: qgsfeature.h:88
Data of spatial index that may be implicitly shared.
void visitData(const IData &d) override
QgsSpatialIndex()
Constructor - creates R-tree.
Utility class for bulk loading of R-trees.
A class to represent a point.
Definition: qgspoint.h:63
QList< QgsFeatureId > nearestNeighbor(const QgsPoint &point, int neighbors) const
Returns nearest neighbors (their count is specified by second parameter)
QAtomicInt refs() const
get reference count - just for debugging!
void visitData(const IData &d) override
bool insertFeature(const QgsFeature &f)
Add feature to index.
~QgsSpatialIndex()
Destructor finalizes work with spatial index.
const QgsGeometry * constGeometry() const
Gets a const pointer to the geometry object associated with this feature.
Definition: qgsfeature.cpp:70
qint64 QgsFeatureId
Definition: qgsfeature.h:31
double y() const
Get the y value of the point.
Definition: qgspoint.h:134
static bool featureInfo(const QgsFeature &f, SpatialIndex::Region &r, QgsFeatureId &id)
virtual IData * getNext() override
returns a pointer to the next entry in the stream or 0 at the end of the stream.
double xMinimum() const
Get the x minimum value (left side of rectangle)
Definition: qgsrectangle.h:191