QGIS API Documentation 4.0.0-Norrköping (1ddcee3d0e4)
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> class QgsGenericSpatialIndex
48{
49 public:
54 {
55 mStorageManager.reset( SpatialIndex::StorageManager::createNewMemoryStorageManager() );
56 mRTree = createSpatialIndex( *mStorageManager );
57 }
58
65 bool insert( T *data, const QgsRectangle &bounds )
66 {
67 const SpatialIndex::Region r( QgsSpatialIndexUtils::rectangleToRegion( bounds ) );
68
69 const QMutexLocker locker( &mMutex );
70
71 const qint64 id = mNextId++;
72 mIdToData.insert( id, data );
73 mDataToId.insert( data, id );
74 try
75 {
76 mRTree->insertData( 0, nullptr, r, static_cast< qint64 >( id ) );
77 return true;
78 }
79 catch ( Tools::Exception &e )
80 {
81 Q_UNUSED( e )
82 QgsDebugError( u"Tools::Exception caught when inserting data to QgsGenericSpatialIndex: %1"_s.arg( e.what().c_str() ) );
83 }
84 catch ( const std::exception &e )
85 {
86 Q_UNUSED( e )
87 QgsDebugError( u"std::exception caught when inserting data to QgsGenericSpatialIndex: %1"_s.arg( e.what() ) );
88 }
89 catch ( ... )
90 {
91 QgsDebugError( u"unknown spatial index exception caught when inserting data to QgsGenericSpatialIndex"_s );
92 }
93
94 return false;
95 }
96
103 bool remove( T *data, const QgsRectangle &bounds )
104 {
105 const SpatialIndex::Region r = QgsSpatialIndexUtils::rectangleToRegion( bounds );
106
107 const QMutexLocker locker( &mMutex );
108
109 const qint64 id = mDataToId.value( data, 0 );
110 if ( id == 0 )
111 return false;
112
113 // TODO: handle exceptions
114 const bool res = mRTree->deleteData( r, id );
115 mDataToId.remove( data );
116 mIdToData.remove( id );
117 return res;
118 }
119
125 bool intersects( const QgsRectangle &bounds, const std::function< bool( T *data )> &callback ) const
126 {
127 GenericIndexVisitor<T> visitor( callback, mIdToData );
128 const SpatialIndex::Region r = QgsSpatialIndexUtils::rectangleToRegion( bounds );
129
130 const QMutexLocker locker( &mMutex );
131 try
132 {
133 mRTree->intersectsWithQuery( r, visitor );
134 }
135 catch ( Tools::Exception &e )
136 {
137 Q_UNUSED( e )
138 QgsDebugError( u"Tools::Exception caught in QgsGenericSpatialIndex::intersects: %1"_s.arg( e.what().c_str() ) );
139 }
140 catch ( const std::exception &e )
141 {
142 Q_UNUSED( e )
143 QgsDebugError( u"std::exception caught in QgsGenericSpatialIndex::intersects: %1"_s.arg( e.what() ) );
144 }
145 catch ( ... )
146 {
147 QgsDebugError( u"unknown spatial index exception caught in QgsGenericSpatialIndex::intersects"_s );
148 }
149
150 return true;
151 }
152
156 bool isEmpty() const
157 {
158 const QMutexLocker locker( &mMutex );
159 return mIdToData.isEmpty();
160 }
161
162 private:
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, leafCapacity, dimension, variant, indexId ) );
175 }
176
177 std::unique_ptr< SpatialIndex::IStorageManager > mStorageManager;
178 std::unique_ptr< SpatialIndex::ISpatialIndex > mRTree;
179
180 mutable QMutex mMutex;
181
182 qint64 mNextId = 1;
183 QHash< qint64, T * > mIdToData;
184 QHash< T *, qint64 > mDataToId;
185
186 template<typename TT> class GenericIndexVisitor : public SpatialIndex::IVisitor
187 {
188 public:
189 explicit GenericIndexVisitor( const std::function< bool( TT *data )> &callback, const QHash< qint64, TT * > &data )
190 : mCallback( callback )
191 , mData( data )
192 {}
193
194 void visitNode( const SpatialIndex::INode &n ) override { Q_UNUSED( n ) }
195
196 void visitData( const SpatialIndex::IData &d ) override
197 {
198 const qint64 id = d.getIdentifier();
199 T *data = mData.value( id );
200 mCallback( data );
201 }
202
203 void visitData( std::vector<const SpatialIndex::IData *> &v ) override { Q_UNUSED( v ) }
204
205 private:
206 const std::function< bool( TT *data )> &mCallback;
207 QHash< qint64, TT * > mData;
208 };
209};
210
211#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