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         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           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       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       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       double fillFactor = 0.7;
 
  310       unsigned long indexCapacity = 10;
 
  311       unsigned long leafCapacity = 10;
 
  312       unsigned long dimension = 2;
 
  313       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     mutable QMutex mMutex;
 
  343   d = 
new QgsSpatialIndexData( flags );
 
  348   d = 
new QgsSpatialIndexData( fi, feedback, flags );
 
  354   d = 
new QgsSpatialIndexData( fi, 
nullptr, flags, &callback );
 
  374   if ( 
this != &other )
 
  382   if ( !featureInfo( f, rect, 
id ) )
 
  407   if ( !featureInfo( feature, rect, 
id ) )
 
  414       QMutexLocker locker( &d->mMutex );
 
  415       d->mGeometries.insert( feature.
id(), feature.
geometry() );
 
  424   QgsFeatureList::iterator fIt = features.begin();
 
  426   for ( ; fIt != features.end(); ++fIt )
 
  448   QMutexLocker locker( &d->mMutex );
 
  456   catch ( Tools::Exception &e )
 
  459     QgsDebugMsg( QStringLiteral( 
"Tools::Exception caught: " ).arg( e.what().c_str() ) );
 
  461   catch ( 
const std::exception &e )
 
  464     QgsDebugMsg( QStringLiteral( 
"std::exception caught: " ).arg( e.what() ) );
 
  468     QgsDebugMsg( QStringLiteral( 
"unknown spatial index exception caught" ) );
 
  476   SpatialIndex::Region r;
 
  478   if ( !featureInfo( f, r, 
id ) )
 
  481   QMutexLocker locker( &d->mMutex );
 
  484     d->mGeometries.remove( f.
id() );
 
  490   QList<QgsFeatureId> list;
 
  495   QMutexLocker locker( &d->mMutex );
 
  496   d->mRTree->intersectsWithQuery( r, visitor );
 
  503   QList<QgsFeatureId> list;
 
  506   double pt[2] = { point.
x(), point.
y() };
 
  509   QMutexLocker locker( &d->mMutex );
 
  511                                     point, maxDistance );
 
  512   d->mRTree->nearestNeighborQuery( neighbors, p, visitor, nnc );
 
  514   if ( maxDistance > 0 )
 
  517     list.erase( std::remove_if( list.begin(), list.end(),
 
  520       return nnc.mFeaturesOutsideMaxDistance.contains( id );
 
  529   QList<QgsFeatureId> list;
 
  534   QMutexLocker locker( &d->mMutex );
 
  537   d->mRTree->nearestNeighborQuery( neighbors, r, visitor, nnc );
 
  539   if ( maxDistance > 0 )
 
  542     list.erase( std::remove_if( list.begin(), list.end(),
 
  545       return nnc.mFeaturesOutsideMaxDistance.contains( id );
 
  554   QMutexLocker locker( &d->mMutex );
 
  555   return d->mGeometries.value( 
id );