27 #include <spatialindex/SpatialIndex.h>
29 #include <QMutexLocker>
52 mList.append( d.getIdentifier() );
55 void visitData( std::vector<const IData *> &v )
override
59 QList<QgsFeatureId> &mList;
71 : mNewIndex( newIndex ) {}
78 SpatialIndex::IShape *shape =
nullptr;
80 mNewIndex->insertData( 0,
nullptr, *shape, d.getIdentifier() );
84 void visitData( std::vector<const IData *> &v )
override
88 SpatialIndex::ISpatialIndex *mNewIndex =
nullptr;
92 class QgsNearestNeighborComparator :
public INearestNeighborComparator
96 QgsNearestNeighborComparator(
const QHash< QgsFeatureId, QgsGeometry > *geometries,
const QgsPointXY &point,
double maxDistance )
97 : mGeometries( geometries )
99 , mMaxDistance( maxDistance )
103 QgsNearestNeighborComparator(
const QHash< QgsFeatureId, QgsGeometry > *geometries,
const QgsGeometry &geometry,
double maxDistance )
104 : mGeometries( geometries )
106 , mMaxDistance( maxDistance )
110 const QHash< QgsFeatureId, QgsGeometry > *mGeometries =
nullptr;
112 double mMaxDistance = 0;
113 QSet< QgsFeatureId > mFeaturesOutsideMaxDistance;
115 double getMinimumDistance(
const IShape &query,
const IShape &entry )
override
117 return query.getMinimumDistance( entry );
120 double getMinimumDistance(
const IShape &query,
const IData &data )
override
124 data.getShape( &pS );
125 double dist = query.getMinimumDistance( *pS );
133 if ( mGeometries && ( mMaxDistance <= 0.0 || dist <= mMaxDistance ) )
135 const QgsGeometry other = mGeometries->value( data.getIdentifier() );
139 if ( mMaxDistance > 0 && dist > mMaxDistance )
149 mFeaturesOutsideMaxDistance.insert( data.getIdentifier() );
150 return mMaxDistance + 0.00000001;
162 class QgsFeatureIteratorDataStream :
public IDataStream
166 explicit QgsFeatureIteratorDataStream(
const QgsFeatureIterator &fi,
QgsFeedback *feedback =
nullptr, QgsSpatialIndex::Flags flags = QgsSpatialIndex::Flags(),
167 const std::function<
bool(
const QgsFeature & ) > *callback =
nullptr )
169 , mFeedback( feedback )
171 , mCallback( callback )
176 ~QgsFeatureIteratorDataStream()
override
182 IData *getNext()
override
184 if ( mFeedback && mFeedback->isCanceled() )
187 RTree::Data *ret = mNextData;
194 bool hasNext()
override {
return nullptr != mNextData; }
197 uint32_t size()
override { Q_ASSERT(
false &&
"not available" );
return 0; }
200 void rewind()
override { Q_ASSERT(
false &&
"not available" ); }
202 QHash< QgsFeatureId, QgsGeometry > geometries;
208 SpatialIndex::Region r;
210 while ( mFi.nextFeature( f ) )
214 const bool res = ( *mCallback )( f );
221 if ( QgsSpatialIndex::featureInfo( f, r,
id ) )
223 mNextData =
new RTree::Data( 0,
nullptr, r,
id );
233 RTree::Data *mNextData =
nullptr;
235 QgsSpatialIndex::Flags mFlags = QgsSpatialIndex::Flags();
236 const std::function< bool(
const QgsFeature & ) > *mCallback =
nullptr;
247 class QgsSpatialIndexData :
public QSharedData
250 QgsSpatialIndexData( QgsSpatialIndex::Flags flags )
256 QgsSpatialIndex::Flags mFlags = QgsSpatialIndex::Flags();
258 QHash< QgsFeatureId, QgsGeometry > mGeometries;
268 explicit QgsSpatialIndexData(
const QgsFeatureIterator &fi,
QgsFeedback *feedback =
nullptr, QgsSpatialIndex::Flags flags = QgsSpatialIndex::Flags(),
269 const std::function<
bool(
const QgsFeature & ) > *callback =
nullptr )
272 QgsFeatureIteratorDataStream fids( fi, feedback, mFlags, callback );
275 mGeometries = fids.geometries;
278 QgsSpatialIndexData(
const QgsSpatialIndexData &other )
279 : QSharedData( other )
280 , mFlags( other.mFlags )
281 , mGeometries( other.mGeometries )
283 const QMutexLocker locker( &other.mMutex );
288 double low[] = { std::numeric_limits<double>::lowest(), std::numeric_limits<double>::lowest() };
289 double high[] = { std::numeric_limits<double>::max(), std::numeric_limits<double>::max() };
290 const SpatialIndex::Region query( low, high, 2 );
292 other.mRTree->intersectsWithQuery( query, visitor );
295 ~QgsSpatialIndexData()
301 QgsSpatialIndexData &operator=(
const QgsSpatialIndexData &rh ) =
delete;
303 void initTree( IDataStream *inputStream =
nullptr )
306 mStorage = StorageManager::createNewMemoryStorageManager();
309 const double fillFactor = 0.7;
310 const unsigned long indexCapacity = 10;
311 const unsigned long leafCapacity = 10;
312 const unsigned long dimension = 2;
313 const RTree::RTreeVariant variant = RTree::RV_RSTAR;
316 SpatialIndex::id_type indexId;
318 if ( inputStream && inputStream->hasNext() )
319 mRTree = RTree::createAndBulkLoadNewRTree( RTree::BLM_STR, *inputStream, *mStorage, fillFactor, indexCapacity,
320 leafCapacity, dimension, variant, indexId );
322 mRTree = RTree::createNewRTree( *mStorage, fillFactor, indexCapacity,
323 leafCapacity, dimension, variant, indexId );
327 SpatialIndex::IStorageManager *mStorage =
nullptr;
330 SpatialIndex::ISpatialIndex *mRTree =
nullptr;
332 #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
333 mutable QMutex mMutex;
335 mutable QRecursiveMutex mMutex;
347 d =
new QgsSpatialIndexData( flags );
352 d =
new QgsSpatialIndexData( fi, feedback, flags );
358 d =
new QgsSpatialIndexData( fi,
nullptr, flags, &callback );
378 if (
this != &other )
386 if ( !featureInfo( f, rect,
id ) )
411 if ( !featureInfo( feature, rect,
id ) )
418 const QMutexLocker locker( &d->mMutex );
419 d->mGeometries.insert( feature.
id(), feature.
geometry() );
428 QgsFeatureList::iterator fIt = features.begin();
430 for ( ; fIt != features.end(); ++fIt )
452 const QMutexLocker locker( &d->mMutex );
460 catch ( Tools::Exception &e )
463 QgsDebugMsg( QStringLiteral(
"Tools::Exception caught: " ).arg( e.what().c_str() ) );
465 catch (
const std::exception &e )
468 QgsDebugMsg( QStringLiteral(
"std::exception caught: " ).arg( e.what() ) );
472 QgsDebugMsg( QStringLiteral(
"unknown spatial index exception caught" ) );
480 SpatialIndex::Region r;
482 if ( !featureInfo( f, r,
id ) )
485 const QMutexLocker locker( &d->mMutex );
488 d->mGeometries.remove( f.
id() );
494 QList<QgsFeatureId> list;
499 const QMutexLocker locker( &d->mMutex );
500 d->mRTree->intersectsWithQuery( r, visitor );
507 QList<QgsFeatureId> list;
510 double pt[2] = { point.
x(), point.
y() };
511 const Point p( pt, 2 );
513 const QMutexLocker locker( &d->mMutex );
515 point, maxDistance );
516 d->mRTree->nearestNeighborQuery( neighbors, p, visitor, nnc );
518 if ( maxDistance > 0 )
521 list.erase( std::remove_if( list.begin(), list.end(),
524 return nnc.mFeaturesOutsideMaxDistance.contains( id );
533 QList<QgsFeatureId> list;
538 const QMutexLocker locker( &d->mMutex );
541 d->mRTree->nearestNeighborQuery( neighbors, r, visitor, nnc );
543 if ( maxDistance > 0 )
546 list.erase( std::remove_if( list.begin(), list.end(),
549 return nnc.mFeaturesOutsideMaxDistance.contains( id );
558 const QMutexLocker locker( &d->mMutex );
559 return d->mGeometries.value(
id );