QGIS API Documentation 3.99.0-Master (7d2ca374f2d)
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
28#define SIP_NO_FILE
29
30using namespace Qt::StringLiterals;
31
32
33#include <functional>
34#include <spatialindex/SpatialIndex.h>
35
36class QgsRectangle;
37
47template <typename T>
49{
50 public:
51
56 {
57 mStorageManager.reset( SpatialIndex::StorageManager::createNewMemoryStorageManager() );
58 mRTree = createSpatialIndex( *mStorageManager );
59 }
60
67 bool insert( T *data, const QgsRectangle &bounds )
68 {
69 const SpatialIndex::Region r( QgsSpatialIndexUtils::rectangleToRegion( bounds ) );
70
71 const QMutexLocker locker( &mMutex );
72
73 const qint64 id = mNextId++;
74 mIdToData.insert( id, data );
75 mDataToId.insert( data, id );
76 try
77 {
78 mRTree->insertData( 0, nullptr, r, static_cast< qint64 >( id ) );
79 return true;
80 }
81 catch ( Tools::Exception &e )
82 {
83 Q_UNUSED( e )
84 QgsDebugError( u"Tools::Exception caught when inserting data to QgsGenericSpatialIndex: %1"_s.arg( e.what().c_str() ) );
85 }
86 catch ( const std::exception &e )
87 {
88 Q_UNUSED( e )
89 QgsDebugError( u"std::exception caught when inserting data to QgsGenericSpatialIndex: %1"_s.arg( e.what() ) );
90 }
91 catch ( ... )
92 {
93 QgsDebugError( u"unknown spatial index exception caught when inserting data to QgsGenericSpatialIndex"_s );
94 }
95
96 return false;
97 }
98
105 bool remove( T *data, const QgsRectangle &bounds )
106 {
107 const SpatialIndex::Region r = QgsSpatialIndexUtils::rectangleToRegion( bounds );
108
109 const QMutexLocker locker( &mMutex );
110
111 const qint64 id = mDataToId.value( data, 0 );
112 if ( id == 0 )
113 return false;
114
115 // TODO: handle exceptions
116 const bool res = mRTree->deleteData( r, id );
117 mDataToId.remove( data );
118 mIdToData.remove( id );
119 return res;
120 }
121
127 bool intersects( const QgsRectangle &bounds, const std::function< bool( T *data )> &callback ) const
128 {
129 GenericIndexVisitor<T> visitor( callback, mIdToData );
130 const SpatialIndex::Region r = QgsSpatialIndexUtils::rectangleToRegion( bounds );
131
132 const QMutexLocker locker( &mMutex );
133 try
134 {
135 mRTree->intersectsWithQuery( r, visitor );
136 }
137 catch ( Tools::Exception &e )
138 {
139 Q_UNUSED( e )
140 QgsDebugError( u"Tools::Exception caught in QgsGenericSpatialIndex::intersects: %1"_s.arg( e.what().c_str() ) );
141 }
142 catch ( const std::exception &e )
143 {
144 Q_UNUSED( e )
145 QgsDebugError( u"std::exception caught in QgsGenericSpatialIndex::intersects: %1"_s.arg( e.what() ) );
146 }
147 catch ( ... )
148 {
149 QgsDebugError( u"unknown spatial index exception caught in QgsGenericSpatialIndex::intersects"_s );
150 }
151
152 return true;
153 }
154
158 bool isEmpty( ) const
159 {
160 const QMutexLocker locker( &mMutex );
161 return mIdToData.isEmpty();
162 }
163
164 private:
165
166 std::unique_ptr< SpatialIndex::ISpatialIndex > createSpatialIndex( SpatialIndex::IStorageManager &storageManager )
167 {
168 // R-Tree parameters
169 constexpr double fillFactor = 0.7;
170 constexpr unsigned long indexCapacity = 10;
171 constexpr unsigned long leafCapacity = 10;
172 constexpr unsigned long dimension = 2;
173 constexpr SpatialIndex::RTree::RTreeVariant variant = SpatialIndex::RTree::RV_RSTAR;
174
175 // create R-tree
176 SpatialIndex::id_type indexId;
177 return std::unique_ptr< SpatialIndex::ISpatialIndex >( SpatialIndex::RTree::createNewRTree( storageManager, fillFactor, indexCapacity,
178 leafCapacity, dimension, variant, indexId ) );
179 }
180
181 std::unique_ptr< SpatialIndex::IStorageManager > mStorageManager;
182 std::unique_ptr< SpatialIndex::ISpatialIndex > mRTree;
183
184 mutable QMutex mMutex;
185
186 qint64 mNextId = 1;
187 QHash< qint64, T * > mIdToData;
188 QHash< T *, qint64 > mDataToId;
189
190 template <typename TT>
191 class GenericIndexVisitor : public SpatialIndex::IVisitor
192 {
193 public:
194 explicit GenericIndexVisitor( const std::function< bool( TT *data )> &callback, const QHash< qint64, TT * > &data )
195 : mCallback( callback )
196 , mData( data )
197 {}
198
199 void visitNode( const SpatialIndex::INode &n ) override
200 { Q_UNUSED( n ) }
201
202 void visitData( const SpatialIndex::IData &d ) override
203 {
204 const qint64 id = d.getIdentifier();
205 T *data = mData.value( id );
206 mCallback( data );
207 }
208
209 void visitData( std::vector<const SpatialIndex::IData *> &v ) override
210 { Q_UNUSED( v ) }
211
212 private:
213 const std::function< bool( TT *data )> &mCallback;
214 QHash< qint64, TT * > mData;
215 };
216
217};
218
219#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