Branch data Line data Source code
1 : : /*************************************************************************** 2 : : qgsfeatureiterator.cpp 3 : : --------------------- 4 : : begin : Juli 2012 5 : : copyright : (C) 2012 by Martin Dobias 6 : : email : wonder dot sk at gmail dot com 7 : : *************************************************************************** 8 : : * * 9 : : * This program is free software; you can redistribute it and/or modify * 10 : : * it under the terms of the GNU General Public License as published by * 11 : : * the Free Software Foundation; either version 2 of the License, or * 12 : : * (at your option) any later version. * 13 : : * * 14 : : ***************************************************************************/ 15 : : #include "qgsfeatureiterator.h" 16 : : #include "qgslogger.h" 17 : : 18 : : #include "qgssimplifymethod.h" 19 : : #include "qgsexception.h" 20 : : #include "qgsexpressionsorter.h" 21 : : 22 : 318 : QgsAbstractFeatureIterator::QgsAbstractFeatureIterator( const QgsFeatureRequest &request ) 23 : 318 : : mRequest( request ) 24 : 318 : { 25 : 318 : } 26 : : 27 : 2501 : bool QgsAbstractFeatureIterator::nextFeature( QgsFeature &f ) 28 : : { 29 : 2501 : bool dataOk = false; 30 : 2501 : if ( mRequest.limit() >= 0 && mFetchedCount >= mRequest.limit() ) 31 : : { 32 : 0 : return false; 33 : : } 34 : : 35 : 2501 : if ( mUseCachedFeatures ) 36 : : { 37 : 0 : if ( mFeatureIterator != mCachedFeatures.constEnd() ) 38 : : { 39 : 0 : f = mFeatureIterator->mFeature; 40 : 0 : ++mFeatureIterator; 41 : 0 : dataOk = true; 42 : 0 : } 43 : : else 44 : : { 45 : 0 : dataOk = false; 46 : : // even the zombie dies at this point... 47 : 0 : mZombie = false; 48 : : } 49 : 0 : } 50 : : else 51 : : { 52 : 2501 : switch ( mRequest.filterType() ) 53 : : { 54 : : case QgsFeatureRequest::FilterExpression: 55 : 0 : dataOk = nextFeatureFilterExpression( f ); 56 : 0 : break; 57 : : 58 : : case QgsFeatureRequest::FilterFids: 59 : 246 : dataOk = nextFeatureFilterFids( f ); 60 : 246 : break; 61 : : 62 : : default: 63 : 2255 : dataOk = fetchFeature( f ); 64 : 2255 : break; 65 : : } 66 : : } 67 : : 68 : 2501 : if ( dataOk ) 69 : 2222 : mFetchedCount++; 70 : : 71 : 2501 : return dataOk; 72 : 2501 : } 73 : : 74 : 0 : bool QgsAbstractFeatureIterator::nextFeatureFilterExpression( QgsFeature &f ) 75 : : { 76 : 0 : while ( fetchFeature( f ) ) 77 : : { 78 : 0 : mRequest.expressionContext()->setFeature( f ); 79 : 0 : if ( mRequest.filterExpression()->evaluate( mRequest.expressionContext() ).toBool() ) 80 : 0 : return true; 81 : : } 82 : 0 : return false; 83 : 0 : } 84 : : 85 : 246 : bool QgsAbstractFeatureIterator::nextFeatureFilterFids( QgsFeature &f ) 86 : : { 87 : 246 : while ( fetchFeature( f ) ) 88 : : { 89 : 144 : if ( mRequest.filterFids().contains( f.id() ) ) 90 : 144 : return true; 91 : : } 92 : 102 : return false; 93 : 246 : } 94 : : 95 : 2222 : void QgsAbstractFeatureIterator::geometryToDestinationCrs( QgsFeature &feature, const QgsCoordinateTransform &transform ) const 96 : : { 97 : 2222 : if ( transform.isValid() && feature.hasGeometry() ) 98 : : { 99 : : try 100 : : { 101 : 0 : QgsGeometry g = feature.geometry(); 102 : 0 : g.transform( transform ); 103 : 0 : feature.setGeometry( g ); 104 : 0 : } 105 : : catch ( QgsCsException & ) 106 : : { 107 : : // transform error 108 : 0 : if ( mRequest.transformErrorCallback() ) 109 : : { 110 : 0 : mRequest.transformErrorCallback()( feature ); 111 : 0 : } 112 : : // remove geometry - we can't reproject so better not return a geometry in a different crs 113 : 0 : feature.clearGeometry(); 114 : 0 : } 115 : 0 : } 116 : 2222 : } 117 : : 118 : 318 : QgsRectangle QgsAbstractFeatureIterator::filterRectToSourceCrs( const QgsCoordinateTransform &transform ) const 119 : : { 120 : 318 : if ( mRequest.filterRect().isNull() ) 121 : 318 : return QgsRectangle(); 122 : : 123 : 0 : return transform.transformBoundingBox( mRequest.filterRect(), QgsCoordinateTransform::ReverseTransform ); 124 : 318 : } 125 : : 126 : 468 : void QgsAbstractFeatureIterator::ref() 127 : : { 128 : : // Prepare if required the simplification of geometries to fetch: 129 : : // This code runs here because of 'prepareSimplification()' is virtual and it can be overridden 130 : : // in inherited iterators who change the default behavior. 131 : : // It would be better to call this method in the constructor enabling virtual-calls as it is described by example at: 132 : : // http://www.parashift.com/c%2B%2B-faq-lite/calling-virtuals-from-ctor-idiom.html 133 : 468 : if ( refs == 0 ) 134 : : { 135 : 318 : prepareSimplification( mRequest.simplifyMethod() ); 136 : : 137 : : // Should be called as last preparation step since it possibly will already fetch all features 138 : 318 : setupOrderBy( mRequest.orderBy() ); 139 : 318 : } 140 : 468 : refs++; 141 : 468 : } 142 : : 143 : 468 : void QgsAbstractFeatureIterator::deref() 144 : : { 145 : 468 : refs--; 146 : 468 : if ( !refs ) 147 : 318 : delete this; 148 : 468 : } 149 : : 150 : 0 : bool QgsAbstractFeatureIterator::compileFailed() const 151 : : { 152 : 0 : return mCompileFailed; 153 : : } 154 : : 155 : 160 : bool QgsAbstractFeatureIterator::prepareSimplification( const QgsSimplifyMethod &simplifyMethod ) 156 : 318 : { 157 : 160 : Q_UNUSED( simplifyMethod ) 158 : 160 : return false; 159 : : } 160 : : 161 : 318 : void QgsAbstractFeatureIterator::setupOrderBy( const QList<QgsFeatureRequest::OrderByClause> &orderBys ) 162 : : { 163 : : // Let the provider try using an efficient order by strategy first 164 : 318 : if ( !orderBys.isEmpty() && !prepareOrderBy( orderBys ) ) 165 : 318 : { 166 : : // No success from the provider 167 : : 168 : : // Prepare the expressions 169 : 0 : QList<QgsFeatureRequest::OrderByClause> preparedOrderBys( orderBys ); 170 : 0 : QList<QgsFeatureRequest::OrderByClause>::iterator orderByIt( preparedOrderBys.begin() ); 171 : : 172 : 318 : QgsExpressionContext *expressionContext( mRequest.expressionContext() ); 173 : 0 : do 174 : : { 175 : 0 : orderByIt->prepare( expressionContext ); 176 : 0 : } 177 : 0 : while ( ++orderByIt != preparedOrderBys.end() ); 178 : : 179 : : // Fetch all features 180 : 318 : QgsIndexedFeature indexedFeature; 181 : 0 : indexedFeature.mIndexes.resize( preparedOrderBys.size() ); 182 : : 183 : 318 : while ( nextFeature( indexedFeature.mFeature ) ) 184 : : { 185 : 318 : expressionContext->setFeature( indexedFeature.mFeature ); 186 : 0 : int i = 0; 187 : 0 : const auto constPreparedOrderBys = preparedOrderBys; 188 : 0 : for ( const QgsFeatureRequest::OrderByClause &orderBy : constPreparedOrderBys ) 189 : : { 190 : 0 : indexedFeature.mIndexes.replace( i++, orderBy.expression().evaluate( expressionContext ) ); 191 : : } 192 : : 193 : : // We need all features, to ignore the limit for this pre-fetch 194 : : // keep the fetched count at 0. 195 : 0 : mFetchedCount = 0; 196 : 0 : mCachedFeatures.append( indexedFeature ); 197 : 0 : } 198 : 318 : 199 : 0 : std::sort( mCachedFeatures.begin(), mCachedFeatures.end(), QgsExpressionSorter( preparedOrderBys ) ); 200 : : 201 : 318 : mFeatureIterator = mCachedFeatures.constBegin(); 202 : 0 : mUseCachedFeatures = true; 203 : : // The real iterator is closed, we are only serving cached features 204 : 0 : mZombie = true; 205 : 0 : } 206 : 318 : } 207 : : 208 : 0 : bool QgsAbstractFeatureIterator::providerCanSimplify( QgsSimplifyMethod::MethodType methodType ) const 209 : : { 210 : : Q_UNUSED( methodType ) 211 : 0 : return false; 212 : : } 213 : : 214 : 0 : bool QgsAbstractFeatureIterator::prepareOrderBy( const QList<QgsFeatureRequest::OrderByClause> &orderBys ) 215 : : { 216 : 0 : Q_UNUSED( orderBys ) 217 : 0 : return false; 218 : : } 219 : : 220 : 2 : void QgsAbstractFeatureIterator::setInterruptionChecker( QgsFeedback * ) 221 : : { 222 : 2 : } 223 : : 224 : : /////// 225 : : 226 : 136 : QgsFeatureIterator &QgsFeatureIterator::operator=( const QgsFeatureIterator &other ) 227 : : { 228 : 136 : if ( this != &other ) 229 : : { 230 : 136 : if ( mIter ) 231 : 0 : mIter->deref(); 232 : 136 : mIter = other.mIter; 233 : 136 : if ( mIter ) 234 : 136 : mIter->ref(); 235 : 136 : } 236 : 136 : return *this; 237 : : } 238 : : 239 : 0 : bool QgsFeatureIterator::isValid() const 240 : : { 241 : 0 : return mIter && mIter->isValid(); 242 : : }