QGIS API Documentation  3.8.0-Zanzibar (11aff65)
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 
28 
30  : mFeatureCache( CACHE_SIZE )
31  , mLayer( layer )
32  , mGeometryType( layer->geometryType() )
33  , mFeatureSource( qgis::make_unique<QgsVectorLayerFeatureSource>( layer ) )
34  , mLayerName( layer->name() )
35 {
36 
37 }
38 
40 {
41  // Why is there a write lock acquired here? Weird, we only want to read a feature from the cache, right?
42  // A method like `QCache::object(const Key &key) const` certainly would not modify its internals.
43  // Mmmh. What if reality was different?
44  // If one reads the docs very, very carefully one will find the term "reentrant" in the
45  // small print of the QCache docs. This is the hint that reality is different.
46  //
47  // https://bugreports.qt.io/browse/QTBUG-19794
48 
49  QgsReadWriteLocker locker( mCacheLock, QgsReadWriteLocker::Write );
50  QgsFeature *cachedFeature = mFeatureCache.object( id );
51  if ( cachedFeature )
52  {
53  //feature was cached
54  feature = *cachedFeature;
55  }
56  else
57  {
58  // Feature not in cache, retrieve from layer
59  // TODO: avoid always querying all attributes (attribute values are needed when merging by attribute)
60  if ( !mFeatureSource->getFeatures( QgsFeatureRequest( id ) ).nextFeature( feature ) )
61  {
62  return false;
63  }
65  mFeatureCache.insert( id, new QgsFeature( feature ) );
66  mIndex.addFeature( feature );
67  }
68  return true;
69 }
70 
72 {
74  Q_UNUSED( feedback )
75  Q_ASSERT( QThread::currentThread() == qApp->thread() );
76 
77  mFeatureCache.clear();
78  mIndex = QgsSpatialIndex();
79 
80  QgsFeatureIds fids;
81 
82  mFeatureSource = qgis::make_unique<QgsVectorLayerFeatureSource>( mLayer );
83 
84  QgsFeatureIterator it = mFeatureSource->getFeatures( request );
85  QgsFeature feature;
86  while ( it.nextFeature( feature ) )
87  {
88  insertFeature( feature, true );
89  fids << feature.id();
90  }
91 
92  return fids;
93 }
94 
96 {
97  return mFeatureIds;
98 }
99 
101 {
102  QgsReadWriteLocker locker( mCacheLock, QgsReadWriteLocker::Read );
103  QgsFeatureIds ids = QgsFeatureIds::fromList( mIndex.intersects( rect ) );
104  return ids;
105 }
106 
108 {
109  Q_ASSERT( QThread::currentThread() == qApp->thread() );
110 
111  return mLayer.data();
112 }
113 
114 QPointer<QgsVectorLayer> QgsFeaturePool::layerPtr() const
115 {
116  return mLayer;
117 }
118 
119 void QgsFeaturePool::insertFeature( const QgsFeature &feature, bool skipLock )
120 {
121  QgsReadWriteLocker locker( mCacheLock, QgsReadWriteLocker::Unlocked );
122  if ( !skipLock )
124  mFeatureCache.insert( feature.id(), new QgsFeature( feature ) );
125  QgsFeature indexFeature( feature );
126  mIndex.addFeature( indexFeature );
127 }
128 
130 {
131  QgsReadWriteLocker locker( mCacheLock, QgsReadWriteLocker::Write );
132  mFeatureCache.remove( feature.id() );
133  mIndex.deleteFeature( feature );
134  locker.unlock();
135 
136  QgsFeature tempFeature;
137  getFeature( feature.id(), tempFeature );
138 }
139 
141 {
142  QgsFeature origFeature;
143  QgsReadWriteLocker locker( mCacheLock, QgsReadWriteLocker::Unlocked );
144  if ( getFeature( featureId, origFeature ) )
145  {
147  mIndex.deleteFeature( origFeature );
148  }
150  mFeatureCache.remove( origFeature.id() );
151 }
152 
154 {
155  mFeatureIds = ids;
156 }
157 
159 {
160  QgsReadWriteLocker locker( mCacheLock, QgsReadWriteLocker::Read );
161  return mFeatureCache.contains( fid );
162 }
163 
165 {
166  return mLayerName;
167 }
168 
170 {
172  return mFeatureSource->crs();
173 }
174 
176 {
177  return mGeometryType;
178 }
179 
180 QString QgsFeaturePool::layerId() const
181 {
183  return mFeatureSource->id();
184 }
bool isFeatureCached(QgsFeatureId fid)
Checks if the feature fid is cached.
QgsFeatureId id
Definition: qgsfeature.h:64
Wrapper for iterator of features from vector data provider or vector layer.
A rectangle specified with double values.
Definition: qgsrectangle.h:41
QgsFeatureIds getIntersects(const QgsRectangle &rect) const
Gets all feature ids in the bounding box rect.
QSet< QgsFeatureId > QgsFeatureIds
Definition: qgsfeatureid.h:34
QString layerName() const
Returns the name of the layer.
QgsFeaturePool(QgsVectorLayer *layer)
Creates a new feature pool for layer.
QPointer< QgsVectorLayer > layerPtr() const
Gets a QPointer to the underlying layer.
qint64 QgsFeatureId
Definition: qgsfeatureid.h:25
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:55
Base class for feedback objects to be used for cancellation of something running in a worker thread...
Definition: qgsfeedback.h:44
The QgsReadWriteLocker class is a convenience class that simplifies locking and unlocking QReadWriteL...
QgsVectorLayer * layer() const
Gets a pointer to the underlying layer.
QgsFeatureIds getFeatures(const QgsFeatureRequest &request, QgsFeedback *feedback=nullptr)
Gets features for the provided request.
bool getFeature(QgsFeatureId id, QgsFeature &feature)
Retrieves the feature with the specified id into feature.
void refreshCache(const QgsFeature &feature)
Changes a feature in the cache and the spatial index.
This class wraps a request for features to a vector layer (or directly its vector data provider)...
void insertFeature(const QgsFeature &feature, bool skipLock=false)
Inserts a feature into the cache and the spatial index.
Partial snapshot of vector layer&#39;s state (only the members necessary for access to features) ...
GeometryType
The geometry types are used to group QgsWkbTypes::Type in a coarse way.
Definition: qgswkbtypes.h:139
void unlock()
Unlocks the lock.
bool deleteFeature(const QgsFeature &feature)
Removes a feature from the index.
A spatial index for QgsFeature objects.
void setFeatureIds(const QgsFeatureIds &ids)
Sets all the feature ids governed by this feature pool.
This class represents a coordinate reference system (CRS).
void changeMode(Mode mode)
Change the mode of the lock to mode.
QgsCoordinateReferenceSystem crs() const
The coordinate reference system of this layer.
bool addFeature(QgsFeature &feature, QgsFeatureSink::Flags flags=nullptr) override
Adds a feature to the index.
QgsWkbTypes::GeometryType geometryType() const
The geometry type of this layer.
Represents a vector layer which manages a vector based data sets.
QgsFeatureIds allFeatureIds() const
Returns the complete set of feature ids in this pool.
QList< QgsFeatureId > intersects(const QgsRectangle &rectangle) const
Returns a list of features with a bounding box which intersects the specified rectangle.
void removeFeature(const QgsFeatureId featureId)
Removes a feature from the cache and the spatial index.
QString layerId() const
The layer id of the layer.