QGIS API Documentation 3.99.0-Master (d270888f95f)
Loading...
Searching...
No Matches
qgsgenericspatialindex.h
Go to the documentation of this file.
1/***************************************************************************
2 qgsgenericspatialindex.h
3 ------------------------
4 Date : December 2019
5 Copyright : (C) 2019 by Nyall Dawson
6 Email : nyall dot dawson 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#ifndef QGSGENERICSPATIALINDEX_H
17#define QGSGENERICSPATIALINDEX_H
18
19#include <memory>
20
21#include "qgis_core.h"
22#include "qgslogger.h"
24
25#include <QMutex>
26#include <QString>
27
28using namespace Qt::StringLiterals;
29
30#define SIP_NO_FILE
31
32#include <functional>
33#include <spatialindex/SpatialIndex.h>
34
35class QgsRectangle;
36
46template <typename T>
48{
49 public:
50
55 {
56 mStorageManager.reset( SpatialIndex::StorageManager::createNewMemoryStorageManager() );
57 mRTree = createSpatialIndex( *mStorageManager );
58 }
59
66 bool insert( T *data, const QgsRectangle &bounds )
67 {
68 const SpatialIndex::Region r( QgsSpatialIndexUtils::rectangleToRegion( bounds ) );
69
70 const QMutexLocker locker( &mMutex );
71
72 const qint64 id = mNextId++;
73 mIdToData.insert( id, data );
74 mDataToId.insert( data, id );
75 try
76 {
77 mRTree->insertData( 0, nullptr, r, static_cast< qint64 >( id ) );
78 return true;
79 }
80 catch ( Tools::Exception &e )
81 {
82 Q_UNUSED( e )
83 QgsDebugError( u"Tools::Exception caught when inserting data to QgsGenericSpatialIndex: %1"_s.arg( e.what().c_str() ) );
84 }
85 catch ( const std::exception &e )
86 {
87 Q_UNUSED( e )
88 QgsDebugError( u"std::exception caught when inserting data to QgsGenericSpatialIndex: %1"_s.arg( e.what() ) );
89 }
90 catch ( ... )
91 {
92 QgsDebugError( u"unknown spatial index exception caught when inserting data to QgsGenericSpatialIndex"_s );
93 }
94
95 return false;
96 }
97
104 bool remove( T *data, const QgsRectangle &bounds )
105 {
106 const SpatialIndex::Region r = QgsSpatialIndexUtils::rectangleToRegion( bounds );
107
108 const QMutexLocker locker( &mMutex );
109
110 const qint64 id = mDataToId.value( data, 0 );
111 if ( id == 0 )
112 return false;
113
114 // TODO: handle exceptions
115 const bool res = mRTree->deleteData( r, id );
116 mDataToId.remove( data );
117 mIdToData.remove( id );
118 return res;
119 }
120
126 bool intersects( const QgsRectangle &bounds, const std::function< bool( T *data )> &callback ) const
127 {
128 GenericIndexVisitor<T> visitor( callback, mIdToData );
129 const SpatialIndex::Region r = QgsSpatialIndexUtils::rectangleToRegion( bounds );
130
131 const QMutexLocker locker( &mMutex );
132 try
133 {
134 mRTree->intersectsWithQuery( r, visitor );
135 }
136 catch ( Tools::Exception &e )
137 {
138 Q_UNUSED( e )
139 QgsDebugError( u"Tools::Exception caught in QgsGenericSpatialIndex::intersects: %1"_s.arg( e.what().c_str() ) );
140 }
141 catch ( const std::exception &e )
142 {
143 Q_UNUSED( e )
144 QgsDebugError( u"std::exception caught in QgsGenericSpatialIndex::intersects: %1"_s.arg( e.what() ) );
145 }
146 catch ( ... )
147 {
148 QgsDebugError( u"unknown spatial index exception caught in QgsGenericSpatialIndex::intersects"_s );
149 }
150
151 return true;
152 }
153
157 bool isEmpty( ) const
158 {
159 const QMutexLocker locker( &mMutex );
160 return mIdToData.isEmpty();
161 }
162
163 private:
164
165 std::unique_ptr< SpatialIndex::ISpatialIndex > createSpatialIndex( SpatialIndex::IStorageManager &storageManager )
166 {
167 // R-Tree parameters
168 constexpr double fillFactor = 0.7;
169 constexpr unsigned long indexCapacity = 10;
170 constexpr unsigned long leafCapacity = 10;
171 constexpr unsigned long dimension = 2;
172 constexpr SpatialIndex::RTree::RTreeVariant variant = SpatialIndex::RTree::RV_RSTAR;
173
174 // create R-tree
175 SpatialIndex::id_type indexId;
176 return std::unique_ptr< SpatialIndex::ISpatialIndex >( SpatialIndex::RTree::createNewRTree( storageManager, fillFactor, indexCapacity,
177 leafCapacity, dimension, variant, indexId ) );
178 }
179
180 std::unique_ptr< SpatialIndex::IStorageManager > mStorageManager;
181 std::unique_ptr< SpatialIndex::ISpatialIndex > mRTree;
182
183 mutable QMutex mMutex;
184
185 qint64 mNextId = 1;
186 QHash< qint64, T * > mIdToData;
187 QHash< T *, qint64 > mDataToId;
188
189 template <typename TT>
190 class GenericIndexVisitor : public SpatialIndex::IVisitor
191 {
192 public:
193 explicit GenericIndexVisitor( const std::function< bool( TT *data )> &callback, const QHash< qint64, TT * > &data )
194 : mCallback( callback )
195 , mData( data )
196 {}
197
198 void visitNode( const SpatialIndex::INode &n ) override
199 { Q_UNUSED( n ) }
200
201 void visitData( const SpatialIndex::IData &d ) override
202 {
203 const qint64 id = d.getIdentifier();
204 T *data = mData.value( id );
205 mCallback( data );
206 }
207
208 void visitData( std::vector<const SpatialIndex::IData *> &v ) override
209 { Q_UNUSED( v ) }
210
211 private:
212 const std::function< bool( TT *data )> &mCallback;
213 QHash< qint64, TT * > mData;
214 };
215
216};
217
218#endif // QGSGENERICSPATIALINDEX_H
bool intersects(const QgsRectangle &bounds, const std::function< bool(T *data)> &callback) const
Performs an intersection check against the index, for data intersecting the specified bounds.
QgsGenericSpatialIndex()
Constructor for QgsGenericSpatialIndex.
bool isEmpty() const
Returns true if the index contains no items.
bool insert(T *data, const QgsRectangle &bounds)
Inserts new data into the spatial index, with the specified bounds.
bool remove(T *data, const QgsRectangle &bounds)
Removes existing data from the spatial index, with the specified bounds.
A rectangle specified with double values.
static SpatialIndex::Region rectangleToRegion(const QgsRectangle &rectangle)
Converts a QGIS rectangle to a SpatialIndex region.
#define QgsDebugError(str)
Definition qgslogger.h:59