bool QgsCachedFeatureIterator::fetchFeature( QgsFeature &f ) { f.setValid( false ); if ( mClosed ) return false; while ( mFeatureIdIterator != mFeatureIds.constEnd() ) { if ( !mVectorLayerCache->mCache.contains( *mFeatureIdIterator ) ) { ++mFeatureIdIterator; continue; } f = QgsFeature( *mVectorLayerCache->mCache[*mFeatureIdIterator]->feature() ); ++mFeatureIdIterator; if ( mRequest.acceptFeature( f ) ) { f.setValid( true ); geometryToDestinationCrs( f, mTransform ); return true; } } close(); return false; }
bool QgsOgrFeatureIterator::fetchFeatureWithId( QgsFeatureId id, QgsFeature &feature ) const { feature.setValid( false ); gdal::ogr_feature_unique_ptr fet; #if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(2,2,0) if ( !QgsOgrProviderUtils::canDriverShareSameDatasetAmongLayers( mSource->mDriverName ) ) { OGRLayerH nextFeatureBelongingLayer; bool found = false; // First pass: try to read from the last feature, in the hope the dataset // returns them in increasing feature id number (and as we use a std::set // for mFilterFids, we get them in increasing number by the iterator) // Second pass: reset before reading for ( int passNumber = 0; passNumber < 2; passNumber++ ) { while ( fet.reset( GDALDatasetGetNextFeature( mConn->ds, &nextFeatureBelongingLayer, nullptr, nullptr, nullptr ) ), fet ) { if ( nextFeatureBelongingLayer == mOgrLayer ) { if ( OGR_F_GetFID( fet.get() ) == FID_TO_NUMBER( id ) ) { found = true; break; } } } if ( found || passNumber == 1 ) { break; } GDALDatasetResetReading( mConn->ds ); } if ( !found ) { return false; } } else #endif { fet.reset( OGR_L_GetFeature( mOgrLayer, FID_TO_NUMBER( id ) ) ); } if ( !fet ) { return false; } if ( !readFeature( std::move( fet ), feature ) ) return false; feature.setValid( true ); geometryToDestinationCrs( feature, mTransform ); return true; }
bool QgsMemoryFeatureIterator::nextFeatureTraverseAll( QgsFeature &feature ) { bool hasFeature = false; // option 2: traversing the whole layer while ( mSelectIterator != mSource->mFeatures.constEnd() ) { if ( mFilterRect.isNull() ) { // selection rect empty => using all features hasFeature = true; } else { if ( mRequest.flags() & QgsFeatureRequest::ExactIntersect ) { // using exact test when checking for intersection if ( mSelectIterator->hasGeometry() && mSelectRectEngine->intersects( mSelectIterator->geometry().constGet() ) ) hasFeature = true; } else { // check just bounding box against rect when not using intersection if ( mSelectIterator->hasGeometry() && mSelectIterator->geometry().boundingBox().intersects( mFilterRect ) ) hasFeature = true; } } if ( mSubsetExpression ) { mSource->mExpressionContext.setFeature( *mSelectIterator ); if ( !mSubsetExpression->evaluate( &mSource->mExpressionContext ).toBool() ) hasFeature = false; } if ( hasFeature ) break; ++mSelectIterator; } // copy feature if ( hasFeature ) { feature = mSelectIterator.value(); ++mSelectIterator; feature.setValid( true ); feature.setFields( mSource->mFields ); // allow name-based attribute lookups geometryToDestinationCrs( feature, mTransform ); } else close(); return hasFeature; }
bool QgsOgrFeatureIterator::checkFeature( gdal::ogr_feature_unique_ptr &fet, QgsFeature &feature ) { if ( !readFeature( std::move( fet ), feature ) ) return false; if ( !mFilterRect.isNull() && ( !feature.hasGeometry() || feature.geometry().isEmpty() ) ) return false; // we have a feature, end this cycle feature.setValid( true ); geometryToDestinationCrs( feature, mTransform ); return true; }
bool QgsMemoryFeatureIterator::nextFeatureUsingList( QgsFeature &feature ) { bool hasFeature = false; // option 1: we have a list of features to traverse while ( mFeatureIdListIterator != mFeatureIdList.constEnd() ) { if ( !mFilterRect.isNull() && mRequest.flags() & QgsFeatureRequest::ExactIntersect ) { // do exact check in case we're doing intersection if ( mSource->mFeatures.value( *mFeatureIdListIterator ).hasGeometry() && mSelectRectEngine->intersects( mSource->mFeatures.value( *mFeatureIdListIterator ).geometry().constGet() ) ) hasFeature = true; } else hasFeature = true; if ( mSubsetExpression ) { mSource->mExpressionContext.setFeature( mSource->mFeatures.value( *mFeatureIdListIterator ) ); if ( !mSubsetExpression->evaluate( &mSource->mExpressionContext ).toBool() ) hasFeature = false; } if ( hasFeature ) break; ++mFeatureIdListIterator; } // copy feature if ( hasFeature ) { feature = mSource->mFeatures.value( *mFeatureIdListIterator ); ++mFeatureIdListIterator; } else close(); if ( hasFeature ) { feature.setFields( mSource->mFields ); // allow name-based attribute lookups geometryToDestinationCrs( feature, mTransform ); } return hasFeature; }
bool QgsCachedFeatureWriterIterator::fetchFeature( QgsFeature &f ) { if ( mClosed ) { f.setValid( false ); return false; } if ( mFeatIt.nextFeature( f ) ) { // As long as features can be fetched from the provider: Write them to cache mVectorLayerCache->cacheFeature( f ); mFids.insert( f.id() ); geometryToDestinationCrs( f, mTransform ); return true; } else { // Once no more features can be fetched: Inform the cache, that // the request has been completed mVectorLayerCache->requestCompleted( mRequest, mFids ); return false; } }
bool QgsVirtualLayerFeatureIterator::fetchFeature( QgsFeature &feature ) { feature.setValid( false ); if ( mClosed ) { return false; } bool skipFeature = false; do { if ( mQuery->step() != SQLITE_ROW ) { return false; } feature.setFields( mSource->mFields, /* init */ true ); if ( mSource->mDefinition.uid().isNull() && mRequest.filterType() != QgsFeatureRequest::FilterFid ) { // no id column => autoincrement feature.setId( mFid++ ); } else { // first column: uid feature.setId( mQuery->columnInt64( 0 ) ); } int n = mQuery->columnCount(); int i = 0; const auto constMAttributes = mAttributes; for ( int idx : constMAttributes ) { int type = mQuery->columnType( i + 1 ); switch ( type ) { case SQLITE_INTEGER: feature.setAttribute( idx, mQuery->columnInt64( i + 1 ) ); break; case SQLITE_FLOAT: feature.setAttribute( idx, mQuery->columnDouble( i + 1 ) ); break; case SQLITE_TEXT: default: feature.setAttribute( idx, mQuery->columnText( i + 1 ) ); break; }; i++; } if ( n > mAttributes.size() + 1 ) { // geometry field QByteArray blob( mQuery->columnBlob( n - 1 ) ); if ( blob.size() > 0 ) { feature.setGeometry( spatialiteBlobToQgsGeometry( blob.constData(), blob.size() ) ); } else { feature.clearGeometry(); } } feature.setValid( true ); geometryToDestinationCrs( feature, mTransform ); // if the FilterRect has not been applied on the query // apply it here by skipping features until they intersect if ( mSource->mDefinition.uid().isNull() && feature.hasGeometry() && mSource->mDefinition.hasDefinedGeometry() && !mFilterRect.isNull() ) { if ( mRequest.flags() & QgsFeatureRequest::ExactIntersect ) { // using exact test when checking for intersection skipFeature = !mRectEngine->intersects( feature.geometry().constGet() ); } else { // check just bounding box against rect when not using intersection skipFeature = !feature.geometry().boundingBox().intersects( mFilterRect ); } } } while ( skipFeature ); return true; }
bool QgsGPXFeatureIterator::fetchFeature( QgsFeature &feature ) { feature.setValid( false ); if ( mClosed ) return false; if ( mRequest.filterType() == QgsFeatureRequest::FilterFid ) { bool res = readFid( feature ); close(); if ( res ) geometryToDestinationCrs( feature, mTransform ); return res; } if ( mSource->mFeatureType == QgsGPXProvider::WaypointType ) { // go through the list of waypoints and return the first one that is in // the bounds rectangle for ( ; mWptIter != mSource->data->waypointsEnd(); ++mWptIter ) { if ( readWaypoint( *mWptIter, feature ) ) { ++mWptIter; geometryToDestinationCrs( feature, mTransform ); return true; } } } else if ( mSource->mFeatureType == QgsGPXProvider::RouteType ) { // go through the routes and return the first one that is in the bounds // rectangle for ( ; mRteIter != mSource->data->routesEnd(); ++mRteIter ) { if ( readRoute( *mRteIter, feature ) ) { ++mRteIter; geometryToDestinationCrs( feature, mTransform ); return true; } } } else if ( mSource->mFeatureType == QgsGPXProvider::TrackType ) { // go through the tracks and return the first one that is in the bounds // rectangle for ( ; mTrkIter != mSource->data->tracksEnd(); ++mTrkIter ) { if ( readTrack( *mTrkIter, feature ) ) { ++mTrkIter; geometryToDestinationCrs( feature, mTransform ); return true; } } } close(); return false; }