QGIS API Documentation  3.18.1-Zürich (202f1bf7e5)
qgsvectortilebasicrenderer.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsvectortilebasicrenderer.cpp
3  --------------------------------------
4  Date : March 2020
5  Copyright : (C) 2020 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 
17 
18 #include "qgsapplication.h"
19 #include "qgscolorschemeregistry.h"
21 #include "qgsfillsymbollayer.h"
22 #include "qgslinesymbollayer.h"
23 #include "qgsmarkersymbollayer.h"
24 #include "qgssymbollayerutils.h"
25 #include "qgsvectortileutils.h"
26 
28  : mStyleName( stName )
29  , mLayerName( laName )
30  , mGeometryType( geomType )
31 {
32 }
33 
35 {
36  operator=( other );
37 }
38 
40 {
41  mStyleName = other.mStyleName;
42  mLayerName = other.mLayerName;
43  mGeometryType = other.mGeometryType;
44  mSymbol.reset( other.mSymbol ? other.mSymbol->clone() : nullptr );
45  mEnabled = other.mEnabled;
46  mExpression = other.mExpression;
47  mMinZoomLevel = other.mMinZoomLevel;
48  mMaxZoomLevel = other.mMaxZoomLevel;
49  return *this;
50 }
51 
53 
55 {
56  mSymbol.reset( sym );
57 }
58 
59 void QgsVectorTileBasicRendererStyle::writeXml( QDomElement &elem, const QgsReadWriteContext &context ) const
60 {
61  elem.setAttribute( QStringLiteral( "name" ), mStyleName );
62  elem.setAttribute( QStringLiteral( "layer" ), mLayerName );
63  elem.setAttribute( QStringLiteral( "geometry" ), mGeometryType );
64  elem.setAttribute( QStringLiteral( "enabled" ), mEnabled ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
65  elem.setAttribute( QStringLiteral( "expression" ), mExpression );
66  elem.setAttribute( QStringLiteral( "min-zoom" ), mMinZoomLevel );
67  elem.setAttribute( QStringLiteral( "max-zoom" ), mMaxZoomLevel );
68 
69  QDomDocument doc = elem.ownerDocument();
70  QgsSymbolMap symbols;
71  symbols[QStringLiteral( "0" )] = mSymbol.get();
72  QDomElement symbolsElem = QgsSymbolLayerUtils::saveSymbols( symbols, QStringLiteral( "symbols" ), doc, context );
73  elem.appendChild( symbolsElem );
74 }
75 
76 void QgsVectorTileBasicRendererStyle::readXml( const QDomElement &elem, const QgsReadWriteContext &context )
77 {
78  mStyleName = elem.attribute( QStringLiteral( "name" ) );
79  mLayerName = elem.attribute( QStringLiteral( "layer" ) );
80  mGeometryType = static_cast<QgsWkbTypes::GeometryType>( elem.attribute( QStringLiteral( "geometry" ) ).toInt() );
81  mEnabled = elem.attribute( QStringLiteral( "enabled" ) ).toInt();
82  mExpression = elem.attribute( QStringLiteral( "expression" ) );
83  mMinZoomLevel = elem.attribute( QStringLiteral( "min-zoom" ) ).toInt();
84  mMaxZoomLevel = elem.attribute( QStringLiteral( "max-zoom" ) ).toInt();
85 
86  mSymbol.reset();
87  QDomElement symbolsElem = elem.firstChildElement( QStringLiteral( "symbols" ) );
88  if ( !symbolsElem.isNull() )
89  {
90  QgsSymbolMap symbolMap = QgsSymbolLayerUtils::loadSymbols( symbolsElem, context );
91  if ( symbolMap.contains( QStringLiteral( "0" ) ) )
92  {
93  mSymbol.reset( symbolMap.take( QStringLiteral( "0" ) ) );
94  }
95  }
96 }
97 
99 
100 
102 {
103 }
104 
106 {
107  return QStringLiteral( "basic" );
108 }
109 
111 {
113  r->mStyles = mStyles;
114  r->mStyles.detach(); // make a deep copy to make sure symbols get cloned
115  return r;
116 }
117 
118 void QgsVectorTileBasicRenderer::startRender( QgsRenderContext &context, int tileZoom, const QgsTileRange &tileRange )
119 {
120  Q_UNUSED( context )
121  Q_UNUSED( tileRange )
122  // figure out required fields for different layers
123  for ( const QgsVectorTileBasicRendererStyle &layerStyle : qgis::as_const( mStyles ) )
124  {
125  if ( layerStyle.isActive( tileZoom ) )
126  {
127  if ( !layerStyle.filterExpression().isEmpty() )
128  {
129  QgsExpression expr( layerStyle.filterExpression() );
130  mRequiredFields[layerStyle.layerName()].unite( expr.referencedColumns() );
131  }
132  if ( auto *lSymbol = layerStyle.symbol() )
133  {
134  mRequiredFields[layerStyle.layerName()].unite( lSymbol->usedAttributes( context ) );
135  }
136  }
137  }
138 }
139 
140 QMap<QString, QSet<QString> > QgsVectorTileBasicRenderer::usedAttributes( const QgsRenderContext & )
141 {
142  return mRequiredFields;
143 }
144 
145 QSet<QString> QgsVectorTileBasicRenderer::requiredLayers( QgsRenderContext &, int tileZoom ) const
146 {
147  QSet< QString > res;
148  for ( const QgsVectorTileBasicRendererStyle &layerStyle : qgis::as_const( mStyles ) )
149  {
150  if ( layerStyle.isActive( tileZoom ) )
151  {
152  res.insert( layerStyle.layerName() );
153  }
154  }
155  return res;
156 }
157 
159 {
160  Q_UNUSED( context )
161 }
162 
164 {
165  const QgsVectorTileFeatures tileData = tile.features();
166  int zoomLevel = tile.id().zoomLevel();
167 
168  for ( const QgsVectorTileBasicRendererStyle &layerStyle : qgis::as_const( mStyles ) )
169  {
170  if ( !layerStyle.isActive( zoomLevel ) )
171  continue;
172 
173  QgsExpressionContextScope *scope = new QgsExpressionContextScope( QObject::tr( "Layer" ) ); // will be deleted by popper
174  scope->setFields( tile.fields()[layerStyle.layerName()] );
175  QgsExpressionContextScopePopper popper( context.expressionContext(), scope );
176 
177  QgsExpression filterExpression( layerStyle.filterExpression() );
178  filterExpression.prepare( &context.expressionContext() );
179 
180  QgsSymbol *sym = layerStyle.symbol();
181  sym->startRender( context, QgsFields() );
182  if ( layerStyle.layerName().isEmpty() )
183  {
184  // matching all layers
185  for ( QString layerName : tileData.keys() )
186  {
187  for ( const QgsFeature &f : tileData[layerName] )
188  {
189  scope->setFeature( f );
190  if ( filterExpression.isValid() && !filterExpression.evaluate( &context.expressionContext() ).toBool() )
191  continue;
192 
193  const QgsWkbTypes::GeometryType featureType = QgsWkbTypes::geometryType( f.geometry().wkbType() );
194  if ( featureType == layerStyle.geometryType() )
195  {
196  sym->renderFeature( f, context );
197  }
198  else if ( featureType == QgsWkbTypes::PolygonGeometry && layerStyle.geometryType() == QgsWkbTypes::LineGeometry )
199  {
200  // be tolerant and permit rendering polygons with a line layer style, as some style definitions use this approach
201  // to render the polygon borders only
202  QgsFeature exterior = f;
203  exterior.setGeometry( QgsGeometry( f.geometry().constGet()->boundary() ) );
204  sym->renderFeature( exterior, context );
205  }
206  }
207  }
208  }
209  else if ( tileData.contains( layerStyle.layerName() ) )
210  {
211  // matching one particular layer
212  for ( const QgsFeature &f : tileData[layerStyle.layerName()] )
213  {
214  scope->setFeature( f );
215  if ( filterExpression.isValid() && !filterExpression.evaluate( &context.expressionContext() ).toBool() )
216  continue;
217 
218  const QgsWkbTypes::GeometryType featureType = QgsWkbTypes::geometryType( f.geometry().wkbType() );
219  if ( featureType == layerStyle.geometryType() )
220  {
221  sym->renderFeature( f, context );
222  }
223  else if ( featureType == QgsWkbTypes::PolygonGeometry && layerStyle.geometryType() == QgsWkbTypes::LineGeometry )
224  {
225  // be tolerant and permit rendering polygons with a line layer style, as some style definitions use this approach
226  // to render the polygon borders only
227  QgsFeature exterior = f;
228  exterior.setGeometry( QgsGeometry( f.geometry().constGet()->boundary() ) );
229  sym->renderFeature( exterior, context );
230  }
231  }
232  }
233  sym->stopRender( context );
234  }
235 }
236 
237 void QgsVectorTileBasicRenderer::writeXml( QDomElement &elem, const QgsReadWriteContext &context ) const
238 {
239  QDomDocument doc = elem.ownerDocument();
240  QDomElement elemStyles = doc.createElement( QStringLiteral( "styles" ) );
241  for ( const QgsVectorTileBasicRendererStyle &layerStyle : mStyles )
242  {
243  QDomElement elemStyle = doc.createElement( QStringLiteral( "style" ) );
244  layerStyle.writeXml( elemStyle, context );
245  elemStyles.appendChild( elemStyle );
246  }
247  elem.appendChild( elemStyles );
248 }
249 
250 void QgsVectorTileBasicRenderer::readXml( const QDomElement &elem, const QgsReadWriteContext &context )
251 {
252  mStyles.clear();
253 
254  QDomElement elemStyles = elem.firstChildElement( QStringLiteral( "styles" ) );
255  QDomElement elemStyle = elemStyles.firstChildElement( QStringLiteral( "style" ) );
256  while ( !elemStyle.isNull() )
257  {
259  layerStyle.readXml( elemStyle, context );
260  mStyles.append( layerStyle );
261  elemStyle = elemStyle.nextSiblingElement( QStringLiteral( "style" ) );
262  }
263 }
264 
265 void QgsVectorTileBasicRenderer::setStyles( const QList<QgsVectorTileBasicRendererStyle> &styles )
266 {
267  mStyles = styles;
268 }
269 
270 QList<QgsVectorTileBasicRendererStyle> QgsVectorTileBasicRenderer::styles() const
271 {
272  return mStyles;
273 }
274 
275 QList<QgsVectorTileBasicRendererStyle> QgsVectorTileBasicRenderer::simpleStyleWithRandomColors()
276 {
277  QColor polygonFillColor = QgsApplication::colorSchemeRegistry()->fetchRandomStyleColor();
278  QColor polygonStrokeColor = polygonFillColor;
279  polygonFillColor.setAlpha( 100 );
280  double polygonStrokeWidth = DEFAULT_LINE_WIDTH;
281 
282  QColor lineStrokeColor = QgsApplication::colorSchemeRegistry()->fetchRandomStyleColor();
283  double lineStrokeWidth = DEFAULT_LINE_WIDTH;
284 
285  QColor pointFillColor = QgsApplication::colorSchemeRegistry()->fetchRandomStyleColor();
286  QColor pointStrokeColor = pointFillColor;
287  pointFillColor.setAlpha( 100 );
288  double pointSize = DEFAULT_POINT_SIZE;
289 
290  return simpleStyle( polygonFillColor, polygonStrokeColor, polygonStrokeWidth,
291  lineStrokeColor, lineStrokeWidth,
292  pointFillColor, pointStrokeColor, pointSize );
293 }
294 
295 QList<QgsVectorTileBasicRendererStyle> QgsVectorTileBasicRenderer::simpleStyle(
296  const QColor &polygonFillColor, const QColor &polygonStrokeColor, double polygonStrokeWidth,
297  const QColor &lineStrokeColor, double lineStrokeWidth,
298  const QColor &pointFillColor, const QColor &pointStrokeColor, double pointSize )
299 {
300  QgsSimpleFillSymbolLayer *fillSymbolLayer = new QgsSimpleFillSymbolLayer();
301  fillSymbolLayer->setFillColor( polygonFillColor );
302  fillSymbolLayer->setStrokeColor( polygonStrokeColor );
303  fillSymbolLayer->setStrokeWidth( polygonStrokeWidth );
304  QgsFillSymbol *fillSymbol = new QgsFillSymbol( QgsSymbolLayerList() << fillSymbolLayer );
305 
306  QgsSimpleLineSymbolLayer *lineSymbolLayer = new QgsSimpleLineSymbolLayer;
307  lineSymbolLayer->setColor( lineStrokeColor );
308  lineSymbolLayer->setWidth( lineStrokeWidth );
309  QgsLineSymbol *lineSymbol = new QgsLineSymbol( QgsSymbolLayerList() << lineSymbolLayer );
310 
312  markerSymbolLayer->setFillColor( pointFillColor );
313  markerSymbolLayer->setStrokeColor( pointStrokeColor );
314  markerSymbolLayer->setSize( pointSize );
315  QgsMarkerSymbol *markerSymbol = new QgsMarkerSymbol( QgsSymbolLayerList() << markerSymbolLayer );
316 
317  QgsVectorTileBasicRendererStyle st1( QStringLiteral( "Polygons" ), QString(), QgsWkbTypes::PolygonGeometry );
318  st1.setSymbol( fillSymbol );
319 
320  QgsVectorTileBasicRendererStyle st2( QStringLiteral( "Lines" ), QString(), QgsWkbTypes::LineGeometry );
321  st2.setSymbol( lineSymbol );
322 
323  QgsVectorTileBasicRendererStyle st3( QStringLiteral( "Points" ), QString(), QgsWkbTypes::PointGeometry );
324  st3.setSymbol( markerSymbol );
325 
326  QList<QgsVectorTileBasicRendererStyle> lst;
327  lst << st1 << st2 << st3;
328  return lst;
329 }
static QgsColorSchemeRegistry * colorSchemeRegistry()
Returns the application's color scheme registry, used for managing color schemes.
QColor fetchRandomStyleColor() const
Returns a random color for use with a new symbol style (e.g.
RAII class to pop scope from an expression context on destruction.
Single scope for storing variables and functions for use within a QgsExpressionContext.
void setFields(const QgsFields &fields)
Convenience function for setting a fields for the scope.
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the scope.
Class for parsing and evaluation of expressions (formerly called "search strings").
bool prepare(const QgsExpressionContext *context)
Gets the expression ready for evaluation - find out column indexes.
QSet< QString > referencedColumns() const
Gets list of columns referenced by the expression.
QVariant evaluate()
Evaluate the feature and return the result.
bool isValid() const
Checks if this expression is valid.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:56
void setGeometry(const QgsGeometry &geometry)
Set the feature's geometry.
Definition: qgsfeature.cpp:144
Container of fields for a vector layer.
Definition: qgsfields.h:45
A fill symbol type, for rendering Polygon and MultiPolygon geometries.
Definition: qgssymbol.h:1307
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:124
virtual void setWidth(double width)
Sets the width of the line symbol layer.
A line symbol type, for rendering LineString and MultiLineString geometries.
Definition: qgssymbol.h:1204
virtual void setSize(double size)
Sets the symbol size.
A marker symbol type, for rendering Point and MultiPoint geometries.
Definition: qgssymbol.h:1004
The class is used as a container of context for various read/write operations on other objects.
Contains information about the context of a rendering operation.
QgsExpressionContext & expressionContext()
Gets the expression context.
void setStrokeWidth(double strokeWidth)
void setFillColor(const QColor &color) override
Set fill color.
void setStrokeColor(const QColor &strokeColor) override
Set stroke color.
A simple line symbol layer, which renders lines using a line in a variety of styles (e....
Simple marker symbol layer, consisting of a rendered shape with solid fill color and an stroke.
void setFillColor(const QColor &color) override
Set fill color.
void setStrokeColor(const QColor &color) override
Sets the marker's stroke color.
static QgsSymbolMap loadSymbols(QDomElement &element, const QgsReadWriteContext &context)
Reads a collection of symbols from XML and returns them in a map. Caller is responsible for deleting ...
static QDomElement saveSymbols(QgsSymbolMap &symbols, const QString &tagName, QDomDocument &doc, const QgsReadWriteContext &context)
Writes a collection of symbols to XML with specified tagName for the top-level element.
virtual void setColor(const QColor &color)
The fill color.
Abstract base class for all rendered symbols.
Definition: qgssymbol.h:65
void stopRender(QgsRenderContext &context)
Ends the rendering process.
Definition: qgssymbol.cpp:507
void renderFeature(const QgsFeature &feature, QgsRenderContext &context, int layer=-1, bool selected=false, bool drawVertexMarker=false, int currentVertexMarkerType=0, double currentVertexMarkerSize=0.0) SIP_THROW(QgsCsException)
Render a feature.
Definition: qgssymbol.cpp:890
void startRender(QgsRenderContext &context, const QgsFields &fields=QgsFields())
Begins the rendering process for the symbol.
Definition: qgssymbol.cpp:480
Range of tiles in a tile matrix to be rendered.
Definition: qgstiles.h:66
int zoomLevel() const
Returns tile's zoom level (Z)
Definition: qgstiles.h:46
Definition of map rendering of a subset of vector tile data.
void setSymbol(QgsSymbol *sym)
Sets symbol for rendering. Takes ownership of the symbol.
void writeXml(QDomElement &elem, const QgsReadWriteContext &context) const
Writes object content to given DOM element.
QgsVectorTileBasicRendererStyle(const QString &stName=QString(), const QString &laName=QString(), QgsWkbTypes::GeometryType geomType=QgsWkbTypes::UnknownGeometry)
Constructs a style object.
QgsVectorTileBasicRendererStyle & operator=(const QgsVectorTileBasicRendererStyle &other)
void readXml(const QDomElement &elem, const QgsReadWriteContext &context)
Reads object content from given DOM element.
The default vector tile renderer implementation.
void renderTile(const QgsVectorTileRendererData &tile, QgsRenderContext &context) override
Renders given vector tile. Must be called between startRender/stopRender.
QList< QgsVectorTileBasicRendererStyle > styles() const
Returns list of styles of the renderer.
void readXml(const QDomElement &elem, const QgsReadWriteContext &context) override
Reads renderer's properties from given XML element.
QMap< QString, QSet< QString > > usedAttributes(const QgsRenderContext &) override
Returns field names of sub-layers that will be used for rendering. Must be called between startRender...
QgsVectorTileBasicRenderer()
Constructs renderer with no styles.
void setStyles(const QList< QgsVectorTileBasicRendererStyle > &styles)
Sets list of styles of the renderer.
void startRender(QgsRenderContext &context, int tileZoom, const QgsTileRange &tileRange) override
Initializes rendering. It should be paired with a stopRender() call.
QString type() const override
Returns unique type name of the renderer implementation.
static QList< QgsVectorTileBasicRendererStyle > simpleStyle(const QColor &polygonFillColor, const QColor &polygonStrokeColor, double polygonStrokeWidth, const QColor &lineStrokeColor, double lineStrokeWidth, const QColor &pointFillColor, const QColor &pointStrokeColor, double pointSize)
Returns a list of styles to render all layers with the given fill/stroke colors, stroke widths and ma...
QgsVectorTileBasicRenderer * clone() const override
Returns a clone of the renderer.
static QList< QgsVectorTileBasicRendererStyle > simpleStyleWithRandomColors()
Returns a list of styles to render all layers, using random colors.
QSet< QString > requiredLayers(QgsRenderContext &context, int tileZoom) const override
Returns a list of the layers required for rendering.
void writeXml(QDomElement &elem, const QgsReadWriteContext &context) const override
Writes renderer's properties to given XML element.
void stopRender(QgsRenderContext &context) override
Finishes rendering and cleans up any resources.
Contains decoded features of a single vector tile and any other data necessary for rendering of it.
QgsVectorTileFeatures features() const
Returns features of the tile grouped by sub-layer names.
QMap< QString, QgsFields > fields() const
Returns per-layer fields.
QgsTileXYZ id() const
Returns coordinates of the tile.
static GeometryType geometryType(Type type) SIP_HOLDGIL
Returns the geometry type for a WKB type, e.g., both MultiPolygon and CurvePolygon would have a Polyg...
Definition: qgswkbtypes.h:938
GeometryType
The geometry types are used to group QgsWkbTypes::Type in a coarse way.
Definition: qgswkbtypes.h:141
const double DEFAULT_LINE_WIDTH
Definition: qgis.h:754
const double DEFAULT_POINT_SIZE
Magic number that determines the default point size for point symbols.
Definition: qgis.h:753
QMap< QString, QgsSymbol * > QgsSymbolMap
Definition: qgsrenderer.h:46
QList< QgsSymbolLayer * > QgsSymbolLayerList
Definition: qgssymbol.h:54
QMap< QString, QVector< QgsFeature > > QgsVectorTileFeatures
Features of a vector tile, grouped by sub-layer names (key of the map)