QGIS API Documentation  2.14.0-Essen
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 #include <QScopedPointer>
16 
17 #include "qgsmaphittest.h"
18 
19 #include "qgsmaplayerregistry.h"
20 #include "qgsrendercontext.h"
22 #include "qgsrendererv2.h"
24 #include "qgsvectorlayer.h"
25 #include "qgssymbollayerv2utils.h"
26 #include "qgsgeometry.h"
27 #include "qgscrscache.h"
28 
29 QgsMapHitTest::QgsMapHitTest( const QgsMapSettings& settings, const QgsGeometry& polygon, const LayerFilterExpression& layerFilterExpression )
30  : mSettings( settings ), mLayerFilterExpression( layerFilterExpression ), mOnlyExpressions( false )
31 {
32  if ( !polygon.isEmpty() && polygon.type() == QGis::Polygon )
33  {
34  mPolygon = polygon;
35  }
36 }
37 
38 QgsMapHitTest::QgsMapHitTest( const QgsMapSettings& settings, const LayerFilterExpression& layerFilterExpression )
39  : mSettings( settings ), mLayerFilterExpression( layerFilterExpression ), mOnlyExpressions( true )
40 {
41 }
42 
44 {
45  // TODO: do we need this temp image?
47  tmpImage.setDotsPerMeterX( mSettings.outputDpi() * 25.4 );
48  tmpImage.setDotsPerMeterY( mSettings.outputDpi() * 25.4 );
49  QPainter painter( &tmpImage );
50 
52  context.setPainter( &painter ); // we are not going to draw anything, but we still need a working painter
53 
54  Q_FOREACH ( const QString& layerID, mSettings.layers() )
55  {
56  QgsVectorLayer* vl = qobject_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( layerID ) );
57  if ( !vl || !vl->rendererV2() )
58  continue;
59 
60  if ( !mOnlyExpressions )
61  {
62  if ( vl->hasScaleBasedVisibility() && ( mSettings.scale() < vl->minimumScale() || mSettings.scale() > vl->maximumScale() ) )
63  {
64  mHitTest[vl] = SymbolV2Set(); // no symbols -> will not be shown
66  continue;
67  }
68 
70  {
73  }
74  }
75 
77  SymbolV2Set& usedSymbols = mHitTest[vl];
78  SymbolV2Set& usedSymbolsRuleKey = mHitTestRuleKey[vl];
79  runHitTestLayer( vl, usedSymbols, usedSymbolsRuleKey, context );
80  }
81 
82  painter.end();
83 }
84 
86 {
87  if ( !symbol || !layer || !mHitTest.contains( layer ) )
88  return false;
89 
90  return mHitTest.value( layer ).contains( QgsSymbolLayerV2Utils::symbolProperties( symbol ) );
91 }
92 
93 bool QgsMapHitTest::legendKeyVisible( const QString& ruleKey, QgsVectorLayer* layer ) const
94 {
95  if ( !layer || !mHitTestRuleKey.contains( layer ) )
96  return false;
97 
98  return mHitTestRuleKey.value( layer ).contains( ruleKey );
99 }
100 
101 void QgsMapHitTest::runHitTestLayer( QgsVectorLayer* vl, SymbolV2Set& usedSymbols, SymbolV2Set& usedSymbolsRuleKey, QgsRenderContext& context )
102 {
103  bool hasStyleOverride = mSettings.layerStyleOverrides().contains( vl->id() );
104  if ( hasStyleOverride )
106 
107  QgsFeatureRendererV2* r = vl->rendererV2();
108  bool moreSymbolsPerFeature = r->capabilities() & QgsFeatureRendererV2::MoreSymbolsPerFeature;
109  r->startRender( context, vl->fields() );
110 
111  QgsGeometry transformedPolygon = mPolygon;
112  if ( !mOnlyExpressions && !mPolygon.isEmpty() )
113  {
114  if ( mSettings.destinationCrs() != vl->crs() )
115  {
117  transformedPolygon.transform( *ct );
118  }
119  }
120 
121  QgsFeature f;
122  QgsFeatureRequest request;
123  if ( !mOnlyExpressions )
124  {
125  if ( mPolygon.isEmpty() )
126  {
127  request.setFilterRect( context.extent() );
129  }
130  else
131  {
132  request.setFilterRect( transformedPolygon.boundingBox() );
133  }
134  }
135  QgsFeatureIterator fi = vl->getFeatures( request );
136 
137  SymbolV2Set lUsedSymbols;
138  SymbolV2Set lUsedSymbolsRuleKey;
139  bool allExpressionFalse = false;
140  bool hasExpression = mLayerFilterExpression.contains( vl->id() );
142  if ( hasExpression )
143  {
144  expr.reset( new QgsExpression( mLayerFilterExpression[vl->id()] ) );
145  expr->prepare( &context.expressionContext() );
146  }
147  while ( fi.nextFeature( f ) )
148  {
149  context.expressionContext().setFeature( f );
150  // filter out elements outside of the polygon
151  if ( !mOnlyExpressions && !mPolygon.isEmpty() )
152  {
153  if ( !transformedPolygon.intersects( f.constGeometry() ) )
154  {
155  continue;
156  }
157  }
158 
159  // filter out elements where the expression is false
160  if ( hasExpression )
161  {
162  if ( !expr->evaluate( &context.expressionContext() ).toBool() )
163  continue;
164  else
165  allExpressionFalse = false;
166  }
167 
168  //make sure we store string representation of symbol, not pointer
169  //otherwise layer style override changes will delete original symbols and leave hanging pointers
170  Q_FOREACH ( const QString& legendKey, r->legendKeysForFeature( f, context ) )
171  {
172  lUsedSymbolsRuleKey.insert( legendKey );
173  }
174 
175  if ( moreSymbolsPerFeature )
176  {
177  Q_FOREACH ( QgsSymbolV2* s, r->originalSymbolsForFeature( f, context ) )
178  {
179  if ( s )
180  lUsedSymbols.insert( QgsSymbolLayerV2Utils::symbolProperties( s ) );
181  }
182  }
183  else
184  {
185  QgsSymbolV2* s = r->originalSymbolForFeature( f, context );
186  if ( s )
187  lUsedSymbols.insert( QgsSymbolLayerV2Utils::symbolProperties( s ) );
188  }
189  }
190  r->stopRender( context );
191 
192  if ( !allExpressionFalse )
193  {
194  // QSet is implicitly shared => constant time
195  usedSymbols = lUsedSymbols;
196  usedSymbolsRuleKey = lUsedSymbolsRuleKey;
197  }
198 
199  if ( hasStyleOverride )
201 }
202 
bool restoreOverrideStyle()
Restore the original store after a call to setOverrideStyle()
HitTest mHitTest
The hit test.
Definition: qgsmaphittest.h:89
Class for parsing and evaluation of expressions (formerly called "search strings").
Wrapper for iterator of features from vector data provider or vector layer.
HitTest mHitTestRuleKey
The hit test, using legend rule keys.
Definition: qgsmaphittest.h:92
void setDotsPerMeterX(int x)
virtual QSet< QString > legendKeysForFeature(QgsFeature &feature, QgsRenderContext &context)
Return legend keys matching a specified feature.
bool end()
bool contains(const Key &key) const
double scale() const
Return the calculated scale of the map.
Use exact geometry intersection (slower) instead of bounding boxes.
const QgsCoordinateTransform * layerTransform(QgsMapLayer *layer) const
Return coordinate transform from layer&#39;s CRS to destination CRS.
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
QgsFields fields() const
Returns the list of fields of this layer.
virtual Q_DECL_DEPRECATED QgsSymbolV2 * originalSymbolForFeature(QgsFeature &feature)
Return symbol for feature.
QgsMapLayerStyleManager * styleManager() const
Get access to the layer&#39;s style manager.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest())
Query the provider for features specified in request.
bool symbolVisible(QgsSymbolV2 *symbol, QgsVectorLayer *layer) const
Tests whether a symbol is visible for a specified layer.
bool legendKeyVisible(const QString &ruleKey, QgsVectorLayer *layer) const
Tests whether a given legend key is visible for a specified layer.
float minimumScale() const
Returns the minimum scale denominator at which the layer is visible.
QgsRectangle boundingBox() const
Returns the bounding box of this feature.
QgsRectangle visibleExtent() const
Return the actual extent derived from requested extent that takes takes output image size into accoun...
QGis::GeometryType type() const
Returns type of the geometry as a QGis::GeometryType.
QMap< QString, QString > layerStyleOverrides() const
Get map of map layer style overrides (key: layer ID, value: style name) where a different style shoul...
bool hasCrsTransformEnabled() const
returns true if projections are enabled for this layer set
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:76
const QgsRectangle & extent() const
QgsMapHitTest(const QgsMapSettings &settings, const QgsGeometry &polygon=QgsGeometry(), const LayerFilterExpression &layerFilterExpression=LayerFilterExpression())
const_iterator insert(const T &value)
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:187
static QgsCoordinateTransformCache * instance()
Definition: qgscrscache.cpp:22
void setExtent(const QgsRectangle &extent)
QgsMapLayer * mapLayer(const QString &theLayerId)
Retrieve a pointer to a loaded layer by id.
virtual void startRender(QgsRenderContext &context, const QgsFields &fields)=0
Needs to be called when a new render cycle is started.
void reset(T *other)
The QgsMapSettings class contains configuration for rendering of the map.
virtual void stopRender(QgsRenderContext &context)=0
Needs to be called when a render cycle has finished to clean up.
void setCoordinateTransform(const QgsCoordinateTransform *t)
Sets coordinate transformation.
virtual Q_DECL_DEPRECATED QgsSymbolV2List originalSymbolsForFeature(QgsFeature &feat)
Equivalent of originalSymbolsForFeature() call extended to support renderers that may use more symbol...
const QgsCoordinateTransform * transform(const QString &srcAuthId, const QString &destAuthId, int srcDatumTransform=-1, int destDatumTransform=-1)
Returns coordinate transformation.
Definition: qgscrscache.cpp:41
QgsFeatureRendererV2 * rendererV2()
Return renderer V2.
int outputDpi() const
Return DPI used for conversion between real world units (e.g.
LayerFilterExpression mLayerFilterExpression
List of expression filter for each layer.
Definition: qgsmaphittest.h:95
bool hasScaleBasedVisibility() const
Returns whether scale based visibility is enabled for the layer.
QSize outputSize() const
Return the size of the resulting map image.
float maximumScale() const
Returns the maximum scale denominator at which the layer is visible.
const QgsCoordinateReferenceSystem & destinationCrs() const
returns CRS of destination coordinate reference system
QSet< QString > SymbolV2Set
Definition: qgsmaphittest.h:70
This class wraps a request for features to a vector layer (or directly its vector data provider)...
void setPainter(QPainter *p)
QString id() const
Get this layer&#39;s unique ID, this ID is used to access this layer from map layer registry.
QgsFeatureRequest & setFlags(const QgsFeatureRequest::Flags &flags)
Set flags that affect how features will be fetched.
QgsExpressionContext & expressionContext()
Gets the expression context.
void run()
Runs the map hit test.
Contains information about the context of a rendering operation.
static QgsMapLayerRegistry * instance()
Returns the instance pointer, creating the object on the first call.
QgsGeometry mPolygon
Polygon used for filtering items. May be empty.
Definition: qgsmaphittest.h:98
static QgsRenderContext fromMapSettings(const QgsMapSettings &mapSettings)
create initialized QgsRenderContext instance from given QgsMapSettings
QImage::Format outputImageFormat() const
format of internal QImage, default QImage::Format_ARGB32_Premultiplied
static QString symbolProperties(QgsSymbolV2 *symbol)
Returns a string representing the symbol.
bool mOnlyExpressions
Whether to use only expressions during the filtering.
const QgsGeometry * constGeometry() const
Gets a const pointer to the geometry object associated with this feature.
Definition: qgsfeature.cpp:82
QString authid() const
Returns the authority identifier for the CRS, which includes both the authority (eg EPSG) and the CRS...
Class for doing transforms between two map coordinate systems.
int transform(const QgsCoordinateTransform &ct)
Transform this geometry as described by CoordinateTransform ct.
const QgsCoordinateReferenceSystem & crs() const
Returns layer&#39;s spatial reference system.
QStringList layers() const
Get list of layer IDs for map rendering The layers are stored in the reverse order of how they are re...
bool isEmpty() const
Returns true if the geometry is empty (ie, contains no underlying geometry accessible via geometry)...
bool setOverrideStyle(const QString &styleDef)
Temporarily apply a different style to the layer.
static QgsExpressionContextScope * layerScope(const QgsMapLayer *layer)
Creates a new scope which contains variables and functions relating to a QgsMapLayer.
virtual int capabilities()
returns bitwise OR-ed capabilities of the renderer
bool nextFeature(QgsFeature &f)
QgsRectangle outputExtentToLayerExtent(QgsMapLayer *theLayer, QgsRectangle extent) const
transform bounding box from output CRS to layer&#39;s CRS
bool intersects(const QgsRectangle &r) const
Test for intersection with a rectangle (uses GEOS)
Represents a vector layer which manages a vector based data sets.
void runHitTestLayer(QgsVectorLayer *vl, SymbolV2Set &usedSymbols, SymbolV2Set &usedSymbolsRuleKey, QgsRenderContext &context)
Runs test for visible symbols within a layer.
QgsFeatureRequest & setFilterRect(const QgsRectangle &rect)
Set rectangle from which features will be taken.
QgsMapSettings mSettings
The initial map settings.
Definition: qgsmaphittest.h:86
const T value(const Key &key) const