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 );
 
Custom visitor that adds found features to list.
void visitNode(const INode &n) override
void visitData(std::vector< const IData * > &v) override
QgisVisitor(QList< QgsFeatureId > &list)
void visitData(const IData &d) override
Wrapper for iterator of features from vector data provider or vector layer.
This class wraps a request for features to a vector layer (or directly its vector data provider).
An interface for objects which provide features via a getFeatures method.
virtual QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const =0
Returns an iterator for the features in the source.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
bool hasGeometry() const
Returns true if the feature has an associated geometry.
Base class for feedback objects to be used for cancellation of something running in a worker thread.
A geometry is the spatial representation of a feature.
double distance(const QgsGeometry &geom) const
Returns the minimum distance between this geometry and another geometry.
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
A class to represent a 2D point.
A rectangle specified with double values.
bool isFinite() const
Returns true if the rectangle has finite boundaries.
void visitData(std::vector< const IData * > &v) override
void visitData(const IData &d) override
QgsSpatialIndexCopyVisitor(SpatialIndex::ISpatialIndex *newIndex)
void visitNode(const INode &n) override
static SpatialIndex::Region rectangleToRegion(const QgsRectangle &rectangle)
Converts a QGIS rectangle to a SpatialIndex region.
A spatial index for QgsFeature objects.
bool addFeatures(QgsFeatureList &features, QgsFeatureSink::Flags flags=QgsFeatureSink::Flags()) override
Adds a list of features to the index.
@ FlagStoreFeatureGeometries
Indicates that the spatial index should also store feature geometries. This requires more memory,...
QgsSpatialIndex & operator=(const QgsSpatialIndex &other)
Implement assignment operator.
QgsSpatialIndex(QgsSpatialIndex::Flags flags=QgsSpatialIndex::Flags())
Constructor for QgsSpatialIndex.
QAtomicInt refs() const
Gets reference count - just for debugging!
QList< QgsFeatureId > nearestNeighbor(const QgsPointXY &point, int neighbors=1, double maxDistance=0) const
Returns nearest neighbors to a point.
QList< QgsFeatureId > intersects(const QgsRectangle &rectangle) const
Returns a list of features with a bounding box which intersects the specified rectangle.
~QgsSpatialIndex() override
Destructor finalizes work with spatial index.
bool addFeature(QgsFeature &feature, QgsFeatureSink::Flags flags=QgsFeatureSink::Flags()) override
Adds a feature to the index.
Q_DECL_DEPRECATED bool insertFeature(const QgsFeature &feature)
Adds a feature to the index.
QgsGeometry geometry(QgsFeatureId id) const
Returns the stored geometry for the indexed feature with matching id.
bool deleteFeature(const QgsFeature &feature)
Removes a feature from the index.
QList< QgsFeature > QgsFeatureList
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features
#define FID_TO_NUMBER(fid)