QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
qgsmaphittest.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsmaphittest.cpp
3  ---------------------
4  begin : September 2014
5  copyright : (C) 2014 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 
16 #include "qgsmaphittest.h"
17 
18 #include "qgsfeatureiterator.h"
19 #include "qgsproject.h"
20 #include "qgsrendercontext.h"
22 #include "qgsrenderer.h"
24 #include "qgsvectorlayer.h"
25 #include "qgssymbollayerutils.h"
26 #include "qgsgeometry.h"
27 #include "qgsgeometryengine.h"
29 #include "qgsmarkersymbol.h"
30 
31 QgsMapHitTest::QgsMapHitTest( const QgsMapSettings &settings, const QgsGeometry &polygon, const LayerFilterExpression &layerFilterExpression )
32  : mSettings( settings )
33  , mLayerFilterExpression( layerFilterExpression )
34  , mOnlyExpressions( false )
35 {
36  if ( !polygon.isNull() && polygon.type() == QgsWkbTypes::PolygonGeometry )
37  {
38  mPolygon = polygon;
39  }
40 }
41 
42 QgsMapHitTest::QgsMapHitTest( const QgsMapSettings &settings, const LayerFilterExpression &layerFilterExpression )
43  : mSettings( settings )
44  , mLayerFilterExpression( layerFilterExpression )
45  , mOnlyExpressions( true )
46 {
47 }
48 
50 {
51  // TODO: do we need this temp image?
52  QImage tmpImage( mSettings.outputSize(), mSettings.outputImageFormat() );
53  tmpImage.setDotsPerMeterX( mSettings.outputDpi() * 25.4 );
54  tmpImage.setDotsPerMeterY( mSettings.outputDpi() * 25.4 );
55  QPainter painter( &tmpImage );
56 
58  context.setPainter( &painter ); // we are not going to draw anything, but we still need a working painter
59 
60  const auto constLayers = mSettings.layers( true );
61  for ( QgsMapLayer *layer : constLayers )
62  {
63  QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( layer );
64  if ( !vl || !vl->renderer() )
65  continue;
66 
67  if ( !mOnlyExpressions )
68  {
69  if ( !vl->isInScaleRange( mSettings.scale() ) )
70  {
71  mHitTest[vl] = SymbolSet(); // no symbols -> will not be shown
72  mHitTestRuleKey[vl] = SymbolSet();
73  continue;
74  }
75 
76  context.setCoordinateTransform( mSettings.layerTransform( vl ) );
77  context.setExtent( mSettings.outputExtentToLayerExtent( vl, mSettings.visibleExtent() ) );
78  }
79 
81  SymbolSet &usedSymbols = mHitTest[vl];
82  SymbolSet &usedSymbolsRuleKey = mHitTestRuleKey[vl];
83  runHitTestLayer( vl, usedSymbols, usedSymbolsRuleKey, context );
84  }
85 
86  painter.end();
87 }
88 
90 {
91  if ( !symbol || !layer || !mHitTest.contains( layer ) )
92  return false;
93 
94  return mHitTest.value( layer ).contains( QgsSymbolLayerUtils::symbolProperties( symbol ) );
95 }
96 
97 bool QgsMapHitTest::legendKeyVisible( const QString &ruleKey, QgsVectorLayer *layer ) const
98 {
99  if ( !layer || !mHitTestRuleKey.contains( layer ) )
100  return false;
101 
102  return mHitTestRuleKey.value( layer ).contains( ruleKey );
103 }
104 
105 void QgsMapHitTest::runHitTestLayer( QgsVectorLayer *vl, SymbolSet &usedSymbols, SymbolSet &usedSymbolsRuleKey, QgsRenderContext &context )
106 {
107  QgsMapLayerStyleOverride styleOverride( vl );
108  if ( mSettings.layerStyleOverrides().contains( vl->id() ) )
109  styleOverride.setOverrideStyle( mSettings.layerStyleOverrides().value( vl->id() ) );
110 
111  std::unique_ptr< QgsFeatureRenderer > r( vl->renderer()->clone() );
112  const bool moreSymbolsPerFeature = r->capabilities() & QgsFeatureRenderer::MoreSymbolsPerFeature;
113  r->startRender( context, vl->fields() );
114 
115  QgsGeometry transformedPolygon = mPolygon;
116  if ( !mOnlyExpressions && !mPolygon.isNull() )
117  {
118  if ( mSettings.destinationCrs() != vl->crs() )
119  {
120  const QgsCoordinateTransform ct( mSettings.destinationCrs(), vl->crs(), mSettings.transformContext() );
121  transformedPolygon.transform( ct );
122  }
123  }
124 
125  QgsFeature f;
126  QgsFeatureRequest request;
127  std::unique_ptr< QgsGeometryEngine > polygonEngine;
128  if ( !mOnlyExpressions )
129  {
130  if ( mPolygon.isNull() )
131  {
132  request.setFilterRect( context.extent() );
134  }
135  else
136  {
137  request.setFilterRect( transformedPolygon.boundingBox() );
138  polygonEngine.reset( QgsGeometry::createGeometryEngine( transformedPolygon.constGet() ) );
139  polygonEngine->prepareGeometry();
140  }
141  }
142  QgsFeatureIterator fi = vl->getFeatures( request );
143 
144  SymbolSet lUsedSymbols;
145  SymbolSet lUsedSymbolsRuleKey;
146  bool allExpressionFalse = false;
147  const bool hasExpression = mLayerFilterExpression.contains( vl->id() );
148  std::unique_ptr<QgsExpression> expr;
149  if ( hasExpression )
150  {
151  expr.reset( new QgsExpression( mLayerFilterExpression[vl->id()] ) );
152  expr->prepare( &context.expressionContext() );
153  }
154  while ( fi.nextFeature( f ) )
155  {
156  context.expressionContext().setFeature( f );
157  // filter out elements outside of the polygon
158  if ( f.hasGeometry() && polygonEngine )
159  {
160  if ( !polygonEngine->intersects( f.geometry().constGet() ) )
161  {
162  continue;
163  }
164  }
165 
166  // filter out elements where the expression is false
167  if ( hasExpression )
168  {
169  if ( !expr->evaluate( &context.expressionContext() ).toBool() )
170  continue;
171  else
172  allExpressionFalse = false;
173  }
174 
175  //make sure we store string representation of symbol, not pointer
176  //otherwise layer style override changes will delete original symbols and leave hanging pointers
177  const auto constLegendKeysForFeature = r->legendKeysForFeature( f, context );
178  for ( const QString &legendKey : constLegendKeysForFeature )
179  {
180  lUsedSymbolsRuleKey.insert( legendKey );
181  }
182 
183  if ( moreSymbolsPerFeature )
184  {
185  const auto constOriginalSymbolsForFeature = r->originalSymbolsForFeature( f, context );
186  for ( QgsSymbol *s : constOriginalSymbolsForFeature )
187  {
188  if ( s )
189  lUsedSymbols.insert( QgsSymbolLayerUtils::symbolProperties( s ) );
190  }
191  }
192  else
193  {
194  QgsSymbol *s = r->originalSymbolForFeature( f, context );
195  if ( s )
196  lUsedSymbols.insert( QgsSymbolLayerUtils::symbolProperties( s ) );
197  }
198  }
199  r->stopRender( context );
200 
201  if ( !allExpressionFalse )
202  {
203  // QSet is implicitly shared => constant time
204  usedSymbols = lUsedSymbols;
205  usedSymbolsRuleKey = lUsedSymbolsRuleKey;
206  }
207 }
208 
QgsVectorLayer::getFeatures
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Queries the layer for features specified in request.
Definition: qgsvectorlayer.cpp:1052
QgsMapHitTest::symbolVisible
bool symbolVisible(QgsSymbol *symbol, QgsVectorLayer *layer) const
Tests whether a symbol is visible for a specified layer.
Definition: qgsmaphittest.cpp:89
QgsMapLayer::crs
QgsCoordinateReferenceSystem crs
Definition: qgsmaplayer.h:79
qgsexpressioncontextutils.h
qgsmaplayerstylemanager.h
QgsRenderContext::expressionContext
QgsExpressionContext & expressionContext()
Gets the expression context.
Definition: qgsrendercontext.h:625
QgsFeatureRequest::ExactIntersect
@ ExactIntersect
Use exact geometry intersection (slower) instead of bounding boxes.
Definition: qgsfeaturerequest.h:117
QgsMapSettings::outputSize
QSize outputSize() const
Returns the size of the resulting map image, in pixels.
Definition: qgsmapsettings.cpp:239
QgsMapSettings::layerTransform
QgsCoordinateTransform layerTransform(const QgsMapLayer *layer) const
Returns the coordinate transform from layer's CRS to destination CRS.
Definition: qgsmapsettings.cpp:481
QgsRenderContext::fromMapSettings
static QgsRenderContext fromMapSettings(const QgsMapSettings &mapSettings)
create initialized QgsRenderContext instance from given QgsMapSettings
Definition: qgsrendercontext.cpp:234
QgsGeometry::transform
Qgis::GeometryOperationResult transform(const QgsCoordinateTransform &ct, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward, bool transformZ=false) SIP_THROW(QgsCsException)
Transforms this geometry as described by the coordinate transform ct.
Definition: qgsgeometry.cpp:3128
QgsMapSettings::outputExtentToLayerExtent
QgsRectangle outputExtentToLayerExtent(const QgsMapLayer *layer, QgsRectangle extent) const
transform bounding box from output CRS to layer's CRS
Definition: qgsmapsettings.cpp:553
QgsRenderContext::setPainter
void setPainter(QPainter *p)
Sets the destination QPainter for the render operation.
Definition: qgsrendercontext.h:512
qgssymbollayerutils.h
qgsfeatureiterator.h
QgsExpressionContextUtils::layerScope
static QgsExpressionContextScope * layerScope(const QgsMapLayer *layer)
Creates a new scope which contains variables and functions relating to a QgsMapLayer.
Definition: qgsexpressioncontextutils.cpp:334
QgsFeature::geometry
QgsGeometry geometry
Definition: qgsfeature.h:71
QgsRenderContext
Contains information about the context of a rendering operation.
Definition: qgsrendercontext.h:59
QgsMapHitTest::LayerFilterExpression
QMap< QString, QString > LayerFilterExpression
Maps an expression string to a layer id.
Definition: qgsmaphittest.h:41
QgsMapSettings::layerStyleOverrides
QMap< QString, QString > layerStyleOverrides() const
Returns the map of map layer style overrides (key: layer ID, value: style name) where a different sty...
Definition: qgsmapsettings.cpp:340
QgsMapSettings::outputImageFormat
QImage::Format outputImageFormat() const
format of internal QImage, default QImage::Format_ARGB32_Premultiplied
Definition: qgsmapsettings.h:444
QgsSymbol
Abstract base class for all rendered symbols.
Definition: qgssymbol.h:92
QgsRenderContext::extent
const QgsRectangle & extent() const
When rendering a map layer, calling this method returns the "clipping" extent for the layer (in the l...
Definition: qgsrendercontext.h:239
QgsMapLayerStyleOverride
Restore overridden layer style on destruction.
Definition: qgsmaplayerstyle.h:81
QgsWkbTypes::PolygonGeometry
@ PolygonGeometry
Definition: qgswkbtypes.h:144
QgsSymbolLayerUtils::symbolProperties
static QString symbolProperties(QgsSymbol *symbol)
Returns a string representing the symbol.
Definition: qgssymbollayerutils.cpp:1454
QgsFeatureRequest::setFilterRect
QgsFeatureRequest & setFilterRect(const QgsRectangle &rectangle)
Sets the rectangle from which features will be taken.
Definition: qgsfeaturerequest.cpp:101
QgsVectorLayer::fields
QgsFields fields() const FINAL
Returns the list of fields of this layer.
Definition: qgsvectorlayer.cpp:3436
QgsMapLayer::isInScaleRange
bool isInScaleRange(double scale) const
Tests whether the layer should be visible at the specified scale.
Definition: qgsmaplayer.cpp:832
QgsFeatureRequest
This class wraps a request for features to a vector layer (or directly its vector data provider).
Definition: qgsfeaturerequest.h:83
qgsgeometryengine.h
QgsMapSettings::transformContext
QgsCoordinateTransformContext transformContext() const
Returns the coordinate transform context, which stores various information regarding which datum tran...
Definition: qgsmapsettings.cpp:463
QgsSymbol::stopRender
void stopRender(QgsRenderContext &context)
Ends the rendering process.
Definition: qgssymbol.cpp:842
QgsRenderContext::setExtent
void setExtent(const QgsRectangle &extent)
When rendering a map layer, calling this method sets the "clipping" extent for the layer (in the laye...
Definition: qgsrendercontext.h:426
QgsFeatureRenderer::clone
virtual QgsFeatureRenderer * clone() const =0
Create a deep copy of this renderer.
QgsRenderContext::setCoordinateTransform
void setCoordinateTransform(const QgsCoordinateTransform &t)
Sets the current coordinate transform for the context.
Definition: qgsrendercontext.cpp:320
qgsrendercontext.h
QgsFeatureRenderer::MoreSymbolsPerFeature
@ MoreSymbolsPerFeature
May use more than one symbol to render a feature: symbolsForFeature() will return them.
Definition: qgsrenderer.h:264
QgsMapLayer::id
QString id() const
Returns the layer's unique ID, which is used to access this layer from QgsProject.
Definition: qgsmaplayer.cpp:169
QgsGeometry::isNull
bool isNull
Definition: qgsgeometry.h:127
QgsMapSettings::scale
double scale() const
Returns the calculated map scale.
Definition: qgsmapsettings.cpp:458
qgsrenderer.h
QgsGeometry::constGet
const QgsAbstractGeometry * constGet() const SIP_HOLDGIL
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
Definition: qgsgeometry.cpp:136
QgsMapHitTest::run
void run()
Runs the map hit test.
Definition: qgsmaphittest.cpp:49
qgsvectorlayer.h
QgsMapSettings::destinationCrs
QgsCoordinateReferenceSystem destinationCrs() const
Returns the destination coordinate reference system for the map render.
Definition: qgsmapsettings.cpp:358
QgsGeometry::createGeometryEngine
static QgsGeometryEngine * createGeometryEngine(const QgsAbstractGeometry *geometry)
Creates and returns a new geometry engine representing the specified geometry.
Definition: qgsgeometry.cpp:3972
qgsgeometry.h
QgsMapHitTest::legendKeyVisible
bool legendKeyVisible(const QString &ruleKey, QgsVectorLayer *layer) const
Tests whether a given legend key is visible for a specified layer.
Definition: qgsmaphittest.cpp:97
QgsFeatureIterator::nextFeature
bool nextFeature(QgsFeature &f)
Definition: qgsfeatureiterator.h:399
QgsGeometry
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:124
QgsVectorLayer
Represents a vector layer which manages a vector based data sets.
Definition: qgsvectorlayer.h:391
QgsFeature::hasGeometry
bool hasGeometry() const
Returns true if the feature has an associated geometry.
Definition: qgsfeature.cpp:230
QgsMapLayer
Base class for all map layer types. This is the base class for all map layer types (vector,...
Definition: qgsmaplayer.h:72
qgsmarkersymbol.h
qgspointdisplacementrenderer.h
QgsGeometry::boundingBox
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
Definition: qgsgeometry.cpp:1080
QgsFeature
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition: qgsfeature.h:55
QgsMapHitTest::QgsMapHitTest
QgsMapHitTest(const QgsMapSettings &settings, const QgsGeometry &polygon=QgsGeometry(), const QgsMapHitTest::LayerFilterExpression &layerFilterExpression=QgsMapHitTest::LayerFilterExpression())
Definition: qgsmaphittest.cpp:31
QgsMapSettings::outputDpi
double outputDpi() const
Returns the DPI (dots per inch) used for conversion between real world units (e.g.
Definition: qgsmapsettings.cpp:267
QgsExpression
Class for parsing and evaluation of expressions (formerly called "search strings")....
Definition: qgsexpression.h:102
QgsMapSettings
The QgsMapSettings class contains configuration for rendering of the map. The rendering itself is don...
Definition: qgsmapsettings.h:88
QgsMapSettings::visibleExtent
QgsRectangle visibleExtent() const
Returns the actual extent derived from requested extent that takes output image size into account.
Definition: qgsmapsettings.cpp:411
qgsmaphittest.h
QgsCoordinateTransform
Class for doing transforms between two map coordinate systems.
Definition: qgscoordinatetransform.h:57
QgsGeometry::type
QgsWkbTypes::GeometryType type
Definition: qgsgeometry.h:128
QgsFeatureIterator
Wrapper for iterator of features from vector data provider or vector layer.
Definition: qgsfeatureiterator.h:289
QgsFeatureRequest::setFlags
QgsFeatureRequest & setFlags(QgsFeatureRequest::Flags flags)
Sets flags that affect how features will be fetched.
Definition: qgsfeaturerequest.cpp:222
qgsproject.h
QgsMapSettings::layers
QList< QgsMapLayer * > layers(bool expandGroupLayers=false) const
Returns the list of layers which will be rendered in the map.
Definition: qgsmapsettings.cpp:299
QgsExpressionContext::setFeature
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
Definition: qgsexpressioncontext.cpp:525
QgsVectorLayer::renderer
QgsFeatureRenderer * renderer()
Returns the feature renderer used for rendering the features in the layer in 2D map views.
Definition: qgsvectorlayer.h:903