QGIS API Documentation  3.20.0-Odense (decaadbb31)
qgsfeaturepool.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * qgsfeaturepool.cpp *
3  * ------------------- *
4  * copyright : (C) 2014 by Sandro Mani / Sourcepole AG *
5  * email : [email protected] *
6  ***************************************************************************/
7 
8 /***************************************************************************
9  * *
10  * This program is free software; you can redistribute it and/or modify *
11  * it under the terms of the GNU General Public License as published by *
12  * the Free Software Foundation; either version 2 of the License, or *
13  * (at your option) any later version. *
14  * *
15  ***************************************************************************/
16 
17 #include "qgsfeaturepool.h"
18 #include "qgsfeature.h"
19 #include "qgsfeatureiterator.h"
20 #include "qgsgeometry.h"
21 #include "qgsvectorlayer.h"
22 #include "qgsvectordataprovider.h"
23 #include "qgsvectorlayerutils.h"
24 #include "qgsreadwritelocker.h"
25 
26 #include <QMutexLocker>
27 #include <QThread>
28 
29 
30 
32  : mFeatureCache( CACHE_SIZE )
33  , mLayer( layer )
34  , mGeometryType( layer->geometryType() )
35  , mFeatureSource( std::make_unique<QgsVectorLayerFeatureSource>( layer ) )
36  , mLayerName( layer->name() )
37 {
38 
39 }
40 
42 {
43  // Why is there a write lock acquired here? Weird, we only want to read a feature from the cache, right?
44  // A method like `QCache::object(const Key &key) const` certainly would not modify its internals.
45  // Mmmh. What if reality was different?
46  // If one reads the docs very, very carefully one will find the term "reentrant" in the
47  // small print of the QCache docs. This is the hint that reality is different.
48  //
49  // https://bugreports.qt.io/browse/QTBUG-19794
50 
51  QgsReadWriteLocker locker( mCacheLock, QgsReadWriteLocker::Write );
52  QgsFeature *cachedFeature = mFeatureCache.object( id );
53  if ( cachedFeature )
54  {
55  //feature was cached
56  feature = *cachedFeature;
57  }
58  else
59  {
60  // Feature not in cache, retrieve from layer
61  // TODO: avoid always querying all attributes (attribute values are needed when merging by attribute)
62  if ( !mFeatureSource->getFeatures( QgsFeatureRequest( id ) ).nextFeature( feature ) )
63  {
64  return false;
65  }
67  mFeatureCache.insert( id, new QgsFeature( feature ) );
68  mIndex.addFeature( feature );
69  }
70  return true;
71 }
72 
74 {
76  Q_UNUSED( feedback )
77  Q_ASSERT( QThread::currentThread() == qApp->thread() );
78 
79  mFeatureCache.clear();
80  mIndex = QgsSpatialIndex();
81 
82  QgsFeatureIds fids;
83 
84  mFeatureSource = std::make_unique<QgsVectorLayerFeatureSource>( mLayer );
85 
86  QgsFeatureIterator it = mFeatureSource->getFeatures( request );
87  QgsFeature feature;
88  while ( it.nextFeature( feature ) )
89  {
90  insertFeature( feature, true );
91  fids << feature.id();
92  }
93 
94  return fids;
95 }
96 
98 {
99  return mFeatureIds;
100 }
101 
103 {
104  QgsReadWriteLocker locker( mCacheLock, QgsReadWriteLocker::Read );
105  QgsFeatureIds ids = qgis::listToSet( mIndex.intersects( rect ) );
106  return ids;
107 }
108 
110 {
111  Q_ASSERT( QThread::currentThread() == qApp->thread() );
112 
113  return mLayer.data();
114 }
115 
116 QPointer<QgsVectorLayer> QgsFeaturePool::layerPtr() const
117 {
118  return mLayer;
119 }
120 
121 void QgsFeaturePool::insertFeature( const QgsFeature &feature, bool skipLock )
122 {
123  QgsReadWriteLocker locker( mCacheLock, QgsReadWriteLocker::Unlocked );
124  if ( !skipLock )
126  mFeatureCache.insert( feature.id(), new QgsFeature( feature ) );
127  QgsFeature indexFeature( feature );
128  mIndex.addFeature( indexFeature );
129 }
130 
132 {
133  QgsReadWriteLocker locker( mCacheLock, QgsReadWriteLocker::Write );
134  mFeatureCache.remove( feature.id() );
135  mIndex.deleteFeature( feature );
136  locker.unlock();
137 
138  QgsFeature tempFeature;
139  getFeature( feature.id(), tempFeature );
140 }
141 
143 {
144  QgsFeature origFeature;
145  QgsReadWriteLocker locker( mCacheLock, QgsReadWriteLocker::Unlocked );
146  if ( getFeature( featureId, origFeature ) )
147  {
149  mIndex.deleteFeature( origFeature );
150  }
152  mFeatureCache.remove( origFeature.id() );
153 }
154 
156 {
157  mFeatureIds = ids;
158 }
159 
161 {
162  QgsReadWriteLocker locker( mCacheLock, QgsReadWriteLocker::Read );
163  return mFeatureCache.contains( fid );
164 }
165 
167 {
168  return mLayerName;
169 }
170 
172 {
174  return mFeatureSource->crs();
175 }
176 
178 {
179  return mGeometryType;
180 }
181 
182 QString QgsFeaturePool::layerId() const
183 {
185  return mFeatureSource->id();
186 }
This class represents a coordinate reference system (CRS).
Wrapper for iterator of features from vector data provider or vector layer.
bool nextFeature(QgsFeature &f)
void refreshCache(const QgsFeature &feature)
Changes a feature in the cache and the spatial index.
QgsWkbTypes::GeometryType geometryType() const
The geometry type of this layer.
QgsFeaturePool(QgsVectorLayer *layer)
Creates a new feature pool for layer.
QgsFeatureIds allFeatureIds() const
Returns the complete set of feature ids in this pool.
QString layerId() const
The layer id of the layer.
void insertFeature(const QgsFeature &feature, bool skipLock=false)
Inserts a feature into the cache and the spatial index.
QPointer< QgsVectorLayer > layerPtr() const
Gets a QPointer to the underlying layer.
bool isFeatureCached(QgsFeatureId fid)
Checks if the feature fid is cached.
QgsCoordinateReferenceSystem crs() const
The coordinate reference system of this layer.
QgsFeatureIds getFeatures(const QgsFeatureRequest &request, QgsFeedback *feedback=nullptr)
Gets features for the provided request.
QgsFeatureIds getIntersects(const QgsRectangle &rect) const
Gets all feature ids in the bounding box rect.
QString layerName() const
Returns the name of the layer.
void setFeatureIds(const QgsFeatureIds &ids)
Sets all the feature ids governed by this feature pool.
void removeFeature(const QgsFeatureId featureId)
Removes a feature from the cache and the spatial index.
QgsVectorLayer * layer() const
Gets a pointer to the underlying layer.
bool getFeature(QgsFeatureId id, QgsFeature &feature)
Retrieves the feature with the specified id into feature.
This class wraps a request for features to a vector layer (or directly its vector data provider).
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition: qgsfeature.h:56
Q_GADGET QgsFeatureId id
Definition: qgsfeature.h:64
Base class for feedback objects to be used for cancellation of something running in a worker thread.
Definition: qgsfeedback.h:45
The QgsReadWriteLocker class is a convenience class that simplifies locking and unlocking QReadWriteL...
@ Write
Lock for write.
@ Read
Lock for read.
void unlock()
Unlocks the lock.
void changeMode(Mode mode)
Change the mode of the lock to mode.
A rectangle specified with double values.
Definition: qgsrectangle.h:42
A spatial index for QgsFeature objects.
QList< QgsFeatureId > intersects(const QgsRectangle &rectangle) const
Returns a list of features with a bounding box which intersects the specified rectangle.
bool addFeature(QgsFeature &feature, QgsFeatureSink::Flags flags=QgsFeatureSink::Flags()) override
Adds a feature to the index.
bool deleteFeature(const QgsFeature &feature)
Removes a feature from the index.
Partial snapshot of vector layer's state (only the members necessary for access to features)
Represents a vector layer which manages a vector based data sets.
GeometryType
The geometry types are used to group QgsWkbTypes::Type in a coarse way.
Definition: qgswkbtypes.h:141
QSet< QgsFeatureId > QgsFeatureIds
Definition: qgsfeatureid.h:37
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features
Definition: qgsfeatureid.h:28