Skip to content

Commit 5386324

Browse files
committed
Made QgsSpatialIndex implicitly shared class.
As a bonus, spatial index is a bit faster (10%) as we do not use random eviction buffer anymore (which makes sense only when using disk storage manager). Added basic tests for spatial index
1 parent 9d00185 commit 5386324

File tree

4 files changed

+261
-46
lines changed

4 files changed

+261
-46
lines changed

src/core/qgsspatialindex.cpp

+103-32
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
using namespace SpatialIndex;
2626

2727

28+
2829
// custom visitor that adds found features to list
2930
class QgisVisitor : public SpatialIndex::IVisitor
3031
{
@@ -47,38 +48,102 @@ class QgisVisitor : public SpatialIndex::IVisitor
4748
QList<QgsFeatureId>& mList;
4849
};
4950

51+
class QgsSpatialIndexCopyVisitor : public SpatialIndex::IVisitor
52+
{
53+
public:
54+
QgsSpatialIndexCopyVisitor( SpatialIndex::ISpatialIndex* newIndex )
55+
: mNewIndex( newIndex ) {}
56+
57+
void visitNode( const INode& n )
58+
{ Q_UNUSED( n ); }
59+
60+
void visitData( const IData& d )
61+
{
62+
SpatialIndex::IShape* shape;
63+
d.getShape( &shape );
64+
mNewIndex->insertData( 0, 0, *shape, d.getIdentifier() );
65+
delete shape;
66+
}
67+
68+
void visitData( std::vector<const IData*>& v )
69+
{ Q_UNUSED( v ); }
70+
71+
private:
72+
SpatialIndex::ISpatialIndex* mNewIndex;
73+
};
74+
75+
76+
/** Data of spatial index that may be implicitly shared */
77+
class QgsSpatialIndexData : public QSharedData
78+
{
79+
public:
80+
QgsSpatialIndexData()
81+
{
82+
initTree();
83+
}
84+
85+
QgsSpatialIndexData( const QgsSpatialIndexData& other )
86+
: QSharedData( other )
87+
{
88+
initTree();
89+
90+
// copy R-tree data one by one (is there a faster way??)
91+
double low[] = { DBL_MIN, DBL_MIN };
92+
double high[] = { DBL_MAX, DBL_MAX };
93+
SpatialIndex::Region query( low, high, 2 );
94+
QgsSpatialIndexCopyVisitor visitor( mRTree );
95+
other.mRTree->intersectsWithQuery( query, visitor );
96+
}
97+
98+
~QgsSpatialIndexData()
99+
{
100+
delete mRTree;
101+
delete mStorage;
102+
}
103+
104+
void initTree()
105+
{
106+
// for now only memory manager
107+
mStorage = StorageManager::createNewMemoryStorageManager();
108+
109+
// R-Tree parameters
110+
double fillFactor = 0.7;
111+
unsigned long indexCapacity = 10;
112+
unsigned long leafCapacity = 10;
113+
unsigned long dimension = 2;
114+
RTree::RTreeVariant variant = RTree::RV_RSTAR;
115+
116+
// create R-tree
117+
SpatialIndex::id_type indexId;
118+
mRTree = RTree::createNewRTree( *mStorage, fillFactor, indexCapacity,
119+
leafCapacity, dimension, variant, indexId );
120+
}
121+
122+
/** storage manager */
123+
SpatialIndex::IStorageManager* mStorage;
124+
125+
/** R-tree containing spatial index */
126+
SpatialIndex::ISpatialIndex* mRTree;
127+
};
128+
129+
// -------------------------------------------------------------------------
130+
50131

51132
QgsSpatialIndex::QgsSpatialIndex()
52133
{
53-
// for now only memory manager
54-
mStorageManager = StorageManager::createNewMemoryStorageManager();
55-
56-
// create buffer
57-
58-
unsigned int capacity = 10;
59-
bool writeThrough = false;
60-
mStorage = StorageManager::createNewRandomEvictionsBuffer( *mStorageManager, capacity, writeThrough );
61-
62-
// R-Tree parameters
63-
double fillFactor = 0.7;
64-
unsigned long indexCapacity = 10;
65-
unsigned long leafCapacity = 10;
66-
unsigned long dimension = 2;
67-
RTree::RTreeVariant variant = RTree::RV_RSTAR;
68-
69-
// create R-tree
70-
SpatialIndex::id_type indexId;
71-
mRTree = RTree::createNewRTree( *mStorage, fillFactor, indexCapacity,
72-
leafCapacity, dimension, variant, indexId );
134+
d = new QgsSpatialIndexData;
135+
}
136+
137+
QgsSpatialIndex::QgsSpatialIndex( const QgsSpatialIndex& other )
138+
: d( other.d )
139+
{
73140
}
74141

75142
QgsSpatialIndex:: ~QgsSpatialIndex()
76143
{
77-
delete mRTree;
78-
delete mStorage;
79-
delete mStorageManager;
80144
}
81145

146+
82147
Region QgsSpatialIndex::rectToRegion( QgsRectangle rect )
83148
{
84149
double pt1[2], pt2[2];
@@ -89,7 +154,7 @@ Region QgsSpatialIndex::rectToRegion( QgsRectangle rect )
89154
return Region( pt1, pt2, 2 );
90155
}
91156

92-
bool QgsSpatialIndex::featureInfo( QgsFeature& f, SpatialIndex::Region& r, QgsFeatureId &id )
157+
bool QgsSpatialIndex::featureInfo( const QgsFeature& f, SpatialIndex::Region& r, QgsFeatureId &id )
93158
{
94159
QgsGeometry *g = f.geometry();
95160
if ( !g )
@@ -100,7 +165,8 @@ bool QgsSpatialIndex::featureInfo( QgsFeature& f, SpatialIndex::Region& r, QgsFe
100165
return true;
101166
}
102167

103-
bool QgsSpatialIndex::insertFeature( QgsFeature& f )
168+
169+
bool QgsSpatialIndex::insertFeature( const QgsFeature& f )
104170
{
105171
Region r;
106172
QgsFeatureId id;
@@ -110,7 +176,7 @@ bool QgsSpatialIndex::insertFeature( QgsFeature& f )
110176
// TODO: handle possible exceptions correctly
111177
try
112178
{
113-
mRTree->insertData( 0, 0, r, FID_TO_NUMBER( id ) );
179+
d->mRTree->insertData( 0, 0, r, FID_TO_NUMBER( id ) );
114180
return true;
115181
}
116182
catch ( Tools::Exception &e )
@@ -131,30 +197,30 @@ bool QgsSpatialIndex::insertFeature( QgsFeature& f )
131197
return false;
132198
}
133199

134-
bool QgsSpatialIndex::deleteFeature( QgsFeature& f )
200+
bool QgsSpatialIndex::deleteFeature( const QgsFeature& f )
135201
{
136202
Region r;
137203
QgsFeatureId id;
138204
if ( !featureInfo( f, r, id ) )
139205
return false;
140206

141207
// TODO: handle exceptions
142-
return mRTree->deleteData( r, FID_TO_NUMBER( id ) );
208+
return d->mRTree->deleteData( r, FID_TO_NUMBER( id ) );
143209
}
144210

145-
QList<QgsFeatureId> QgsSpatialIndex::intersects( QgsRectangle rect )
211+
QList<QgsFeatureId> QgsSpatialIndex::intersects( QgsRectangle rect ) const
146212
{
147213
QList<QgsFeatureId> list;
148214
QgisVisitor visitor( list );
149215

150216
Region r = rectToRegion( rect );
151217

152-
mRTree->intersectsWithQuery( r, visitor );
218+
d->mRTree->intersectsWithQuery( r, visitor );
153219

154220
return list;
155221
}
156222

157-
QList<QgsFeatureId> QgsSpatialIndex::nearestNeighbor( QgsPoint point, int neighbors )
223+
QList<QgsFeatureId> QgsSpatialIndex::nearestNeighbor( QgsPoint point, int neighbors ) const
158224
{
159225
QList<QgsFeatureId> list;
160226
QgisVisitor visitor( list );
@@ -164,7 +230,12 @@ QList<QgsFeatureId> QgsSpatialIndex::nearestNeighbor( QgsPoint point, int neighb
164230
pt[1] = point.y();
165231
Point p( pt, 2 );
166232

167-
mRTree->nearestNeighborQuery( neighbors, p, visitor );
233+
d->mRTree->nearestNeighborQuery( neighbors, p, visitor );
168234

169235
return list;
170236
}
237+
238+
int QgsSpatialIndex::refs() const
239+
{
240+
return d->ref;
241+
}

src/core/qgsspatialindex.h

+17-14
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,12 @@ class QgsRectangle;
3535
class QgsPoint;
3636

3737
#include <QList>
38+
#include <QSharedDataPointer>
3839

3940
#include "qgsfeature.h"
4041

42+
class QgsSpatialIndexData;
43+
4144
class CORE_EXPORT QgsSpatialIndex
4245
{
4346

@@ -48,44 +51,44 @@ class CORE_EXPORT QgsSpatialIndex
4851
/** constructor - creates R-tree */
4952
QgsSpatialIndex();
5053

54+
/** copy constructor */
55+
QgsSpatialIndex( const QgsSpatialIndex& other );
56+
5157
/** destructor finalizes work with spatial index */
5258
~QgsSpatialIndex();
5359

5460

5561
/* operations */
5662

5763
/** add feature to index */
58-
bool insertFeature( QgsFeature& f );
64+
bool insertFeature( const QgsFeature& f );
5965

6066
/** remove feature from index */
61-
bool deleteFeature( QgsFeature& f );
67+
bool deleteFeature( const QgsFeature& f );
6268

6369

6470
/* queries */
6571

6672
/** returns features that intersect the specified rectangle */
67-
QList<QgsFeatureId> intersects( QgsRectangle rect );
73+
QList<QgsFeatureId> intersects( QgsRectangle rect ) const;
6874

6975
/** returns nearest neighbors (their count is specified by second parameter) */
70-
QList<QgsFeatureId> nearestNeighbor( QgsPoint point, int neighbors );
76+
QList<QgsFeatureId> nearestNeighbor( QgsPoint point, int neighbors ) const;
77+
78+
/* debugging */
7179

80+
//! get reference count - just for debugging!
81+
int refs() const;
7282

7383
protected:
7484
// @note not available in python bindings
75-
SpatialIndex::Region rectToRegion( QgsRectangle rect );
85+
static SpatialIndex::Region rectToRegion( QgsRectangle rect );
7686
// @note not available in python bindings
77-
bool featureInfo( QgsFeature& f, SpatialIndex::Region& r, QgsFeatureId &id );
87+
bool featureInfo( const QgsFeature& f, SpatialIndex::Region& r, QgsFeatureId &id );
7888

7989
private:
8090

81-
/** storage manager */
82-
SpatialIndex::IStorageManager* mStorageManager;
83-
84-
/** buffer for index data */
85-
SpatialIndex::StorageManager::IBuffer* mStorage;
86-
87-
/** R-tree containing spatial index */
88-
SpatialIndex::ISpatialIndex* mRTree;
91+
QSharedDataPointer<QgsSpatialIndexData> d;
8992

9093
};
9194

tests/src/core/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -113,3 +113,4 @@ ADD_QGIS_TEST(composerscalebartest testqgscomposerscalebar.cpp )
113113
ADD_QGIS_TEST(ogcutilstest testqgsogcutils.cpp)
114114
ADD_QGIS_TEST(vectorlayercachetest testqgsvectorlayercache.cpp )
115115
ADD_QGIS_TEST(maprendererjobtest testmaprendererjob.cpp )
116+
ADD_QGIS_TEST(spatialindextest testqgsspatialindex.cpp)

0 commit comments

Comments
 (0)