Skip to content

Commit

Permalink
Speed up legend map hit test by considering the layer's renderer
Browse files Browse the repository at this point in the history
filter

This can avoid unnecessary fetching and testing of many features
for eg categorised/rule based renderers which don't display all
features in the layer
  • Loading branch information
nyalldawson committed Feb 1, 2023
1 parent 9db4472 commit 72877bc
Showing 1 changed file with 24 additions and 13 deletions.
37 changes: 24 additions & 13 deletions src/core/qgsmaphittest.cpp
Expand Up @@ -16,17 +16,14 @@
#include "qgsmaphittest.h"

#include "qgsfeatureiterator.h"
#include "qgsproject.h"
#include "qgsrendercontext.h"
#include "qgsmaplayerstylemanager.h"
#include "qgsrenderer.h"
#include "qgspointdisplacementrenderer.h"
#include "qgsvectorlayer.h"
#include "qgssymbollayerutils.h"
#include "qgsgeometry.h"
#include "qgsgeometryengine.h"
#include "qgsexpressioncontextutils.h"
#include "qgsmarkersymbol.h"
#include "qgsmaplayerstylemanager.h"

QgsMapHitTest::QgsMapHitTest( const QgsMapSettings &settings, const QgsGeometry &polygon, const LayerFilterExpression &layerFilterExpression )
: mSettings( settings )
Expand Down Expand Up @@ -57,8 +54,8 @@ void QgsMapHitTest::run()
QgsRenderContext context = QgsRenderContext::fromMapSettings( mSettings );
context.setPainter( &painter ); // we are not going to draw anything, but we still need a working painter

const auto constLayers = mSettings.layers( true );
for ( QgsMapLayer *layer : constLayers )
const QList< QgsMapLayer * > layers = mSettings.layers( true );
for ( QgsMapLayer *layer : layers )
{
QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( layer );
if ( !vl || !vl->renderer() )
Expand Down Expand Up @@ -112,6 +109,10 @@ void QgsMapHitTest::runHitTestLayer( QgsVectorLayer *vl, SymbolSet &usedSymbols,
const bool moreSymbolsPerFeature = r->capabilities() & QgsFeatureRenderer::MoreSymbolsPerFeature;
r->startRender( context, vl->fields() );

const QString rendererFilterExpression = r->filter( vl->fields() );

QSet<QString> requiredAttributes = r->usedAttributes( context );

QgsGeometry transformedPolygon = mPolygon;
if ( !mOnlyExpressions && !mPolygon.isNull() )
{
Expand All @@ -122,8 +123,24 @@ void QgsMapHitTest::runHitTestLayer( QgsVectorLayer *vl, SymbolSet &usedSymbols,
}
}

const bool hasExpression = mLayerFilterExpression.contains( vl->id() );
std::unique_ptr<QgsExpression> expr;
if ( hasExpression )
{
expr.reset( new QgsExpression( mLayerFilterExpression[vl->id()] ) );
expr->prepare( &context.expressionContext() );

requiredAttributes.unite( expr->referencedColumns() );
}

QgsFeature f;
QgsFeatureRequest request;
request.setSubsetOfAttributes( requiredAttributes, vl->fields() );
if ( !rendererFilterExpression.isEmpty() )
{
request.setFilterExpression( rendererFilterExpression );
}

std::unique_ptr< QgsGeometryEngine > polygonEngine;
if ( !mOnlyExpressions )
{
Expand All @@ -144,13 +161,7 @@ void QgsMapHitTest::runHitTestLayer( QgsVectorLayer *vl, SymbolSet &usedSymbols,
SymbolSet lUsedSymbols;
SymbolSet lUsedSymbolsRuleKey;
bool allExpressionFalse = false;
const bool hasExpression = mLayerFilterExpression.contains( vl->id() );
std::unique_ptr<QgsExpression> expr;
if ( hasExpression )
{
expr.reset( new QgsExpression( mLayerFilterExpression[vl->id()] ) );
expr->prepare( &context.expressionContext() );
}

while ( fi.nextFeature( f ) )
{
context.expressionContext().setFeature( f );
Expand Down

0 comments on commit 72877bc

Please sign in to comment.