Branch data Line data Source code
1 : : /*************************************************************************** 2 : : * qgsfeaturepool.cpp * 3 : : * ------------------- * 4 : : * copyright : (C) 2014 by Sandro Mani / Sourcepole AG * 5 : : * email : smani@sourcepole.ch * 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 : : 31 : 64 : QgsFeaturePool::QgsFeaturePool( QgsVectorLayer *layer ) 32 : 64 : : mFeatureCache( CACHE_SIZE ) 33 : 64 : , mLayer( layer ) 34 : 64 : , mGeometryType( layer->geometryType() ) 35 : 64 : , mFeatureSource( std::make_unique<QgsVectorLayerFeatureSource>( layer ) ) 36 : 64 : , mLayerName( layer->name() ) 37 : 128 : { 38 : : 39 : 64 : } 40 : : 41 : 1204 : bool QgsFeaturePool::getFeature( QgsFeatureId id, QgsFeature &feature ) 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 : 1204 : QgsReadWriteLocker locker( mCacheLock, QgsReadWriteLocker::Write ); 52 : 1204 : QgsFeature *cachedFeature = mFeatureCache.object( id ); 53 : 1204 : if ( cachedFeature ) 54 : : { 55 : : //feature was cached 56 : 1181 : feature = *cachedFeature; 57 : 1181 : } 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 : 23 : if ( !mFeatureSource->getFeatures( QgsFeatureRequest( id ) ).nextFeature( feature ) ) 63 : : { 64 : 8 : return false; 65 : : } 66 : 15 : locker.changeMode( QgsReadWriteLocker::Write ); 67 : 15 : mFeatureCache.insert( id, new QgsFeature( feature ) ); 68 : 15 : mIndex.addFeature( feature ); 69 : : } 70 : 1196 : return true; 71 : 1204 : } 72 : : 73 : 0 : QgsFeatureIds QgsFeaturePool::getFeatures( const QgsFeatureRequest &request, QgsFeedback *feedback ) 74 : : { 75 : 0 : QgsReadWriteLocker( mCacheLock, QgsReadWriteLocker::Write ); 76 : : Q_UNUSED( feedback ) 77 : : Q_ASSERT( QThread::currentThread() == qApp->thread() ); 78 : : 79 : 0 : mFeatureCache.clear(); 80 : 0 : mIndex = QgsSpatialIndex(); 81 : : 82 : 0 : QgsFeatureIds fids; 83 : : 84 : 0 : mFeatureSource = std::make_unique<QgsVectorLayerFeatureSource>( mLayer ); 85 : : 86 : 0 : QgsFeatureIterator it = mFeatureSource->getFeatures( request ); 87 : 0 : QgsFeature feature; 88 : 0 : while ( it.nextFeature( feature ) ) 89 : : { 90 : 0 : insertFeature( feature, true ); 91 : 0 : fids << feature.id(); 92 : : } 93 : : 94 : 0 : return fids; 95 : 0 : } 96 : : 97 : 66 : QgsFeatureIds QgsFeaturePool::allFeatureIds() const 98 : : { 99 : 66 : return mFeatureIds; 100 : : } 101 : : 102 : 276 : QgsFeatureIds QgsFeaturePool::getIntersects( const QgsRectangle &rect ) const 103 : : { 104 : 276 : QgsReadWriteLocker locker( mCacheLock, QgsReadWriteLocker::Read ); 105 : 276 : QgsFeatureIds ids = qgis::listToSet( mIndex.intersects( rect ) ); 106 : 276 : return ids; 107 : 276 : } 108 : : 109 : 160 : QgsVectorLayer *QgsFeaturePool::layer() const 110 : : { 111 : : Q_ASSERT( QThread::currentThread() == qApp->thread() ); 112 : : 113 : 160 : return mLayer.data(); 114 : : } 115 : : 116 : 717 : QPointer<QgsVectorLayer> QgsFeaturePool::layerPtr() const 117 : : { 118 : 717 : return mLayer; 119 : : } 120 : : 121 : 941 : void QgsFeaturePool::insertFeature( const QgsFeature &feature, bool skipLock ) 122 : : { 123 : 941 : QgsReadWriteLocker locker( mCacheLock, QgsReadWriteLocker::Unlocked ); 124 : 941 : if ( !skipLock ) 125 : 941 : locker.changeMode( QgsReadWriteLocker::Write ); 126 : 941 : mFeatureCache.insert( feature.id(), new QgsFeature( feature ) ); 127 : 941 : QgsFeature indexFeature( feature ); 128 : 941 : mIndex.addFeature( indexFeature ); 129 : 941 : } 130 : : 131 : 15 : void QgsFeaturePool::refreshCache( const QgsFeature &feature ) 132 : : { 133 : 15 : QgsReadWriteLocker locker( mCacheLock, QgsReadWriteLocker::Write ); 134 : 15 : mFeatureCache.remove( feature.id() ); 135 : 15 : mIndex.deleteFeature( feature ); 136 : 15 : locker.unlock(); 137 : : 138 : 15 : QgsFeature tempFeature; 139 : 15 : getFeature( feature.id(), tempFeature ); 140 : 15 : } 141 : : 142 : 8 : void QgsFeaturePool::removeFeature( const QgsFeatureId featureId ) 143 : : { 144 : 8 : QgsFeature origFeature; 145 : 8 : QgsReadWriteLocker locker( mCacheLock, QgsReadWriteLocker::Unlocked ); 146 : 8 : if ( getFeature( featureId, origFeature ) ) 147 : : { 148 : 8 : locker.changeMode( QgsReadWriteLocker::Write ); 149 : 8 : mIndex.deleteFeature( origFeature ); 150 : 8 : } 151 : 8 : locker.changeMode( QgsReadWriteLocker::Write ); 152 : 8 : mFeatureCache.remove( origFeature.id() ); 153 : 8 : } 154 : : 155 : 64 : void QgsFeaturePool::setFeatureIds( const QgsFeatureIds &ids ) 156 : : { 157 : 64 : mFeatureIds = ids; 158 : 64 : } 159 : : 160 : 0 : bool QgsFeaturePool::isFeatureCached( QgsFeatureId fid ) 161 : : { 162 : 0 : QgsReadWriteLocker locker( mCacheLock, QgsReadWriteLocker::Read ); 163 : 0 : return mFeatureCache.contains( fid ); 164 : 0 : } 165 : : 166 : 29 : QString QgsFeaturePool::layerName() const 167 : : { 168 : 29 : return mLayerName; 169 : : } 170 : : 171 : 1354 : QgsCoordinateReferenceSystem QgsFeaturePool::crs() const 172 : : { 173 : 1354 : QgsReadWriteLocker( mCacheLock, QgsReadWriteLocker::Read ); 174 : 1354 : return mFeatureSource->crs(); 175 : : } 176 : : 177 : 926 : QgsWkbTypes::GeometryType QgsFeaturePool::geometryType() const 178 : : { 179 : 926 : return mGeometryType; 180 : : } 181 : : 182 : 818 : QString QgsFeaturePool::layerId() const 183 : : { 184 : 818 : QgsReadWriteLocker( mCacheLock, QgsReadWriteLocker::Read ); 185 : 818 : return mFeatureSource->id(); 186 : : }