void QgsAttributeTableFilterModel::generateListOfVisibleFeatures() { if ( !layer() ) return; bool filter = false; QgsRectangle rect = mCanvas->mapSettings().mapToLayerCoordinates( layer(), mCanvas->extent() ); QgsRenderContext renderContext; renderContext.expressionContext() << QgsExpressionContextUtils::globalScope() << QgsExpressionContextUtils::projectScope() << QgsExpressionContextUtils::layerScope( layer() ); QgsFeatureRenderer* renderer = layer()->renderer(); mFilteredFeatures.clear(); if ( !renderer ) { QgsDebugMsg( "Cannot get renderer" ); return; } const QgsMapSettings& ms = mCanvas->mapSettings(); if ( !layer()->isInScaleRange( ms.scale() ) ) { QgsDebugMsg( "Out of scale limits" ); } else { if ( renderer && renderer->capabilities() & QgsFeatureRenderer::ScaleDependent ) { // setup scale // mapRenderer()->renderContext()->scale is not automaticaly updated when // render extent changes (because it's scale is used to identify if changed // since last render) -> use local context renderContext.setExtent( ms.visibleExtent() ); renderContext.setMapToPixel( ms.mapToPixel() ); renderContext.setRendererScale( ms.scale() ); } filter = renderer && renderer->capabilities() & QgsFeatureRenderer::Filter; } renderer->startRender( renderContext, layer()->fields() ); QgsFeatureRequest r( masterModel()->request() ); if ( !r.filterRect().isNull() ) { r.setFilterRect( r.filterRect().intersect( &rect ) ); } else { r.setFilterRect( rect ); } QgsFeatureIterator features = masterModel()->layerCache()->getFeatures( r ); QgsFeature f; while ( features.nextFeature( f ) ) { renderContext.expressionContext().setFeature( f ); if ( !filter || renderer->willRenderFeature( f, renderContext ) ) { mFilteredFeatures << f.id(); } #if 0 if ( t.elapsed() > 5000 ) { bool cancel = false; emit progress( i, cancel ); if ( cancel ) break; t.restart(); } #endif } features.close(); if ( renderer && renderer->capabilities() & QgsFeatureRenderer::ScaleDependent ) { renderer->stopRender( renderContext ); } }
bool QgsMapToolIdentify::identifyVectorLayer( QList<IdentifyResult> *results, QgsVectorLayer *layer, const QgsPoint& point ) { if ( !layer || !layer->hasGeometryType() ) return false; if ( !layer->isInScaleRange( mCanvas->mapSettings().scale() ) ) { QgsDebugMsg( "Out of scale limits" ); return false; } QApplication::setOverrideCursor( Qt::WaitCursor ); QMap< QString, QString > commonDerivedAttributes; commonDerivedAttributes.insert( tr( "(clicked coordinate X)" ), formatXCoordinate( point ) ); commonDerivedAttributes.insert( tr( "(clicked coordinate Y)" ), formatYCoordinate( point ) ); int featureCount = 0; QgsFeatureList featureList; // toLayerCoordinates will throw an exception for an 'invalid' point. // For example, if you project a world map onto a globe using EPSG 2163 // and then click somewhere off the globe, an exception will be thrown. try { // create the search rectangle double searchRadius = searchRadiusMU( mCanvas ); QgsRectangle r; r.setXMinimum( point.x() - searchRadius ); r.setXMaximum( point.x() + searchRadius ); r.setYMinimum( point.y() - searchRadius ); r.setYMaximum( point.y() + searchRadius ); r = toLayerCoordinates( layer, r ); QgsFeatureIterator fit = layer->getFeatures( QgsFeatureRequest().setFilterRect( r ).setFlags( QgsFeatureRequest::ExactIntersect ) ); QgsFeature f; while ( fit.nextFeature( f ) ) featureList << QgsFeature( f ); } catch ( QgsCsException & cse ) { Q_UNUSED( cse ); // catch exception for 'invalid' point and proceed with no features found QgsDebugMsg( QString( "Caught CRS exception %1" ).arg( cse.what() ) ); } QgsFeatureList::iterator f_it = featureList.begin(); bool filter = false; QgsRenderContext context( QgsRenderContext::fromMapSettings( mCanvas->mapSettings() ) ); context.expressionContext() << QgsExpressionContextUtils::layerScope( layer ); QgsFeatureRenderer* renderer = layer->renderer(); if ( renderer && renderer->capabilities() & QgsFeatureRenderer::ScaleDependent ) { // setup scale for scale dependent visibility (rule based) renderer->startRender( context, layer->fields() ); filter = renderer->capabilities() & QgsFeatureRenderer::Filter; } for ( ; f_it != featureList.end(); ++f_it ) { QMap< QString, QString > derivedAttributes = commonDerivedAttributes; QgsFeatureId fid = f_it->id(); context.expressionContext().setFeature( *f_it ); if ( filter && !renderer->willRenderFeature( *f_it, context ) ) continue; featureCount++; derivedAttributes.unite( featureDerivedAttributes( &( *f_it ), layer, toLayerCoordinates( layer, point ) ) ); derivedAttributes.insert( tr( "feature id" ), fid < 0 ? tr( "new feature" ) : FID_TO_STRING( fid ) ); results->append( IdentifyResult( qobject_cast<QgsMapLayer *>( layer ), *f_it, derivedAttributes ) ); } if ( renderer && renderer->capabilities() & QgsFeatureRenderer::ScaleDependent ) { renderer->stopRender( context ); } QgsDebugMsg( "Feature count on identify: " + QString::number( featureCount ) ); QApplication::restoreOverrideCursor(); return featureCount > 0; }
QgsFeatureList QgsQuickIdentifyKit::identifyVectorLayer( QgsVectorLayer *layer, const QgsPointXY &point ) const { QgsFeatureList results; if ( !layer || !layer->isSpatial() ) return results; if ( !layer->isInScaleRange( mMapSettings->mapSettings().scale() ) ) return results; QgsFeatureList featureList; // toLayerCoordinates will throw an exception for an 'invalid' point. // For example, if you project a world map onto a globe using EPSG 2163 // and then click somewhere off the globe, an exception will be thrown. try { // create the search rectangle double searchRadius = searchRadiusMU(); QgsRectangle r; r.setXMinimum( point.x() - searchRadius ); r.setXMaximum( point.x() + searchRadius ); r.setYMinimum( point.y() - searchRadius ); r.setYMaximum( point.y() + searchRadius ); r = toLayerCoordinates( layer, r ); QgsFeatureRequest req; req.setFilterRect( r ); req.setLimit( mFeaturesLimit ); req.setFlags( QgsFeatureRequest::ExactIntersect ); QgsFeatureIterator fit = layer->getFeatures( req ); QgsFeature f; while ( fit.nextFeature( f ) ) featureList << QgsFeature( f ); } catch ( QgsCsException &cse ) { QgsDebugMsg( QStringLiteral( "Invalid point, proceed without a found features." ) ); Q_UNUSED( cse ); } bool filter = false; QgsRenderContext context( QgsRenderContext::fromMapSettings( mMapSettings->mapSettings() ) ); context.expressionContext() << QgsExpressionContextUtils::layerScope( layer ); QgsFeatureRenderer *renderer = layer->renderer(); if ( renderer && renderer->capabilities() & QgsFeatureRenderer::ScaleDependent ) { // setup scale for scale dependent visibility (rule based) renderer->startRender( context, layer->fields() ); filter = renderer->capabilities() & QgsFeatureRenderer::Filter; } for ( const QgsFeature &feature : featureList ) { context.expressionContext().setFeature( feature ); if ( filter && !renderer->willRenderFeature( const_cast<QgsFeature &>( feature ), context ) ) continue; results.append( feature ); } if ( renderer && renderer->capabilities() & QgsFeatureRenderer::ScaleDependent ) { renderer->stopRender( context ); } return results; }