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