QGIS API Documentation  3.16.0-Hannover (43b64b13f3)
qgsvectortilelayerrenderer.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsvectortilelayerrenderer.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 <QElapsedTimer>
19 
21 #include "qgsfeedback.h"
22 #include "qgslogger.h"
23 
25 #include "qgsvectortilelayer.h"
26 #include "qgsvectortileloader.h"
27 #include "qgsvectortileutils.h"
28 
29 #include "qgslabelingengine.h"
30 #include "qgsvectortilelabeling.h"
31 #include "qgsmapclippingutils.h"
32 
34  : QgsMapLayerRenderer( layer->id(), &context )
35  , mSourceType( layer->sourceType() )
36  , mSourcePath( layer->sourcePath() )
37  , mSourceMinZoom( layer->sourceMinZoom() )
38  , mSourceMaxZoom( layer->sourceMaxZoom() )
39  , mRenderer( layer->renderer()->clone() )
40  , mDrawTileBoundaries( layer->isTileBorderRenderingEnabled() )
41  , mFeedback( new QgsFeedback )
42 {
43 
44  QgsDataSourceUri dsUri;
45  dsUri.setEncodedUri( layer->source() );
46  mAuthCfg = dsUri.authConfigId();
47  mReferer = dsUri.param( QStringLiteral( "referer" ) );
48 
49  if ( QgsLabelingEngine *engine = context.labelingEngine() )
50  {
51  if ( layer->labeling() )
52  {
53  mLabelProvider = layer->labeling()->provider( layer );
54  if ( mLabelProvider )
55  {
56  engine->addProvider( mLabelProvider );
57  }
58  }
59  }
60 
62 }
63 
65 {
67 
68  if ( ctx.renderingStopped() )
69  return false;
70 
71  QgsScopedQPainterState painterState( ctx.painter() );
72 
73  if ( !mClippingRegions.empty() )
74  {
75  bool needsPainterClipPath = false;
76  const QPainterPath path = QgsMapClippingUtils::calculatePainterClipRegion( mClippingRegions, *renderContext(), QgsMapLayerType::VectorTileLayer, needsPainterClipPath );
77  if ( needsPainterClipPath )
78  renderContext()->painter()->setClipPath( path, Qt::IntersectClip );
79  }
80 
81  QElapsedTimer tTotal;
82  tTotal.start();
83 
84  QgsDebugMsgLevel( QStringLiteral( "Vector tiles rendering extent: " ) + ctx.extent().toString( -1 ), 2 );
85  QgsDebugMsgLevel( QStringLiteral( "Vector tiles map scale 1 : %1" ).arg( ctx.rendererScale() ), 2 );
86 
87  mTileZoom = QgsVectorTileUtils::scaleToZoomLevel( ctx.rendererScale(), mSourceMinZoom, mSourceMaxZoom );
88  QgsDebugMsgLevel( QStringLiteral( "Vector tiles zoom level: %1" ).arg( mTileZoom ), 2 );
89 
90  mTileMatrix = QgsTileMatrix::fromWebMercator( mTileZoom );
91 
92  mTileRange = mTileMatrix.tileRangeFromExtent( ctx.extent() );
93  QgsDebugMsgLevel( QStringLiteral( "Vector tiles range X: %1 - %2 Y: %3 - %4" )
94  .arg( mTileRange.startColumn() ).arg( mTileRange.endColumn() )
95  .arg( mTileRange.startRow() ).arg( mTileRange.endRow() ), 2 );
96 
97  // view center is used to sort the order of tiles for fetching and rendering
98  QPointF viewCenter = mTileMatrix.mapToTileCoordinates( ctx.extent().center() );
99 
100  if ( !mTileRange.isValid() )
101  {
102  QgsDebugMsgLevel( QStringLiteral( "Vector tiles - outside of range" ), 2 );
103  return true; // nothing to do
104  }
105 
106  bool isAsync = ( mSourceType == QLatin1String( "xyz" ) );
107 
108  std::unique_ptr<QgsVectorTileLoader> asyncLoader;
109  QList<QgsVectorTileRawData> rawTiles;
110  if ( !isAsync )
111  {
112  QElapsedTimer tFetch;
113  tFetch.start();
114  rawTiles = QgsVectorTileLoader::blockingFetchTileRawData( mSourceType, mSourcePath, mTileMatrix, viewCenter, mTileRange, mAuthCfg, mReferer );
115  QgsDebugMsgLevel( QStringLiteral( "Tile fetching time: %1" ).arg( tFetch.elapsed() / 1000. ), 2 );
116  QgsDebugMsgLevel( QStringLiteral( "Fetched tiles: %1" ).arg( rawTiles.count() ), 2 );
117  }
118  else
119  {
120  asyncLoader.reset( new QgsVectorTileLoader( mSourcePath, mTileMatrix, mTileRange, viewCenter, mAuthCfg, mReferer, mFeedback.get() ) );
121  QObject::connect( asyncLoader.get(), &QgsVectorTileLoader::tileRequestFinished, [this]( const QgsVectorTileRawData & rawTile )
122  {
123  QgsDebugMsgLevel( QStringLiteral( "Got tile asynchronously: " ) + rawTile.id.toString(), 2 );
124  if ( !rawTile.data.isEmpty() )
125  decodeAndDrawTile( rawTile );
126  } );
127  }
128 
129  if ( ctx.renderingStopped() )
130  return false;
131 
132  // add @zoom_level variable which can be used in styling
133  QgsExpressionContextScope *scope = new QgsExpressionContextScope( QObject::tr( "Tiles" ) ); // will be deleted by popper
134  scope->setVariable( "zoom_level", mTileZoom, true );
135  scope->setVariable( "vector_tile_zoom", QgsVectorTileUtils::scaleToZoom( ctx.rendererScale() ), true );
136  QgsExpressionContextScopePopper popper( ctx.expressionContext(), scope );
137 
138  mRenderer->startRender( *renderContext(), mTileZoom, mTileRange );
139 
140  QMap<QString, QSet<QString> > requiredFields = mRenderer->usedAttributes( ctx );
141 
142  if ( mLabelProvider )
143  {
144  QMap<QString, QSet<QString> > requiredFieldsLabeling = mLabelProvider->usedAttributes( ctx, mTileZoom );
145  for ( QString layerName : requiredFieldsLabeling.keys() )
146  {
147  requiredFields[layerName].unite( requiredFieldsLabeling[layerName] );
148  }
149  }
150 
151  QMap<QString, QgsFields> perLayerFields;
152  for ( QString layerName : requiredFields.keys() )
153  mPerLayerFields[layerName] = QgsVectorTileUtils::makeQgisFields( requiredFields[layerName] );
154 
155  mRequiredLayers = mRenderer->requiredLayers( ctx, mTileZoom );
156 
157  if ( mLabelProvider )
158  {
159  mLabelProvider->setFields( mPerLayerFields );
160  QSet<QString> attributeNames; // we don't need this - already got referenced columns in provider constructor
161  if ( !mLabelProvider->prepare( ctx, attributeNames ) )
162  {
163  ctx.labelingEngine()->removeProvider( mLabelProvider );
164  mLabelProvider = nullptr; // provider is deleted by the engine
165  }
166 
167  mRequiredLayers.unite( mLabelProvider->requiredLayers( ctx, mTileZoom ) );
168  }
169 
170  if ( !isAsync )
171  {
172  for ( QgsVectorTileRawData &rawTile : rawTiles )
173  {
174  if ( ctx.renderingStopped() )
175  break;
176 
177  decodeAndDrawTile( rawTile );
178  }
179  }
180  else
181  {
182  // Block until tiles are fetched and rendered. If the rendering gets canceled at some point,
183  // the async loader will catch the signal, abort requests and return from downloadBlocking()
184  asyncLoader->downloadBlocking();
185  }
186 
187  mRenderer->stopRender( ctx );
188 
189  QgsDebugMsgLevel( QStringLiteral( "Total time for decoding: %1" ).arg( mTotalDecodeTime / 1000. ), 2 );
190  QgsDebugMsgLevel( QStringLiteral( "Drawing time: %1" ).arg( mTotalDrawTime / 1000. ), 2 );
191  QgsDebugMsgLevel( QStringLiteral( "Total time: %1" ).arg( tTotal.elapsed() / 1000. ), 2 );
192 
193  return !ctx.renderingStopped();
194 }
195 
196 void QgsVectorTileLayerRenderer::decodeAndDrawTile( const QgsVectorTileRawData &rawTile )
197 {
199 
200  QgsDebugMsgLevel( QStringLiteral( "Drawing tile " ) + rawTile.id.toString(), 2 );
201 
202  QElapsedTimer tLoad;
203  tLoad.start();
204 
205  // currently only MVT encoding supported
206  QgsVectorTileMVTDecoder decoder;
207  if ( !decoder.decode( rawTile.id, rawTile.data ) )
208  {
209  QgsDebugMsgLevel( QStringLiteral( "Failed to parse raw tile data! " ) + rawTile.id.toString(), 2 );
210  return;
211  }
212 
213  if ( ctx.renderingStopped() )
214  return;
215 
217 
218  QgsVectorTileRendererData tile( rawTile.id );
219  tile.setFields( mPerLayerFields );
220  tile.setFeatures( decoder.layerFeatures( mPerLayerFields, ct, &mRequiredLayers ) );
221  tile.setTilePolygon( QgsVectorTileUtils::tilePolygon( rawTile.id, ct, mTileMatrix, ctx.mapToPixel() ) );
222 
223  mTotalDecodeTime += tLoad.elapsed();
224 
225  // calculate tile polygon in screen coordinates
226 
227  if ( ctx.renderingStopped() )
228  return;
229 
230  // set up clipping so that rendering does not go behind tile's extent
231  QgsScopedQPainterState savePainterState( ctx.painter() );
232  // we have to intersect with any existing painter clip regions, or we risk overwriting valid clip
233  // regions setup outside of the vector tile renderer (e.g. layout map clip region)
234  ctx.painter()->setClipRegion( QRegion( tile.tilePolygon() ), Qt::IntersectClip );
235 
236  QElapsedTimer tDraw;
237  tDraw.start();
238 
239  mRenderer->renderTile( tile, ctx );
240  mTotalDrawTime += tDraw.elapsed();
241 
242  if ( mLabelProvider )
243  mLabelProvider->registerTileFeatures( tile, ctx );
244 
245  if ( mDrawTileBoundaries )
246  {
247  QgsScopedQPainterState savePainterState( ctx.painter() );
248  ctx.painter()->setClipping( false );
249 
250  QPen pen( Qt::red );
251  pen.setWidth( 3 );
252  ctx.painter()->setPen( pen );
253  ctx.painter()->drawPolygon( tile.tilePolygon() );
254  }
255 }
QgsMapClippingUtils::collectClippingRegionsForLayer
static QList< QgsMapClippingRegion > collectClippingRegionsForLayer(const QgsRenderContext &context, const QgsMapLayer *layer)
Collects the list of map clipping regions from a context which apply to a map layer.
Definition: qgsmapclippingutils.cpp:23
qgsexpressioncontextutils.h
QgsExpressionContextScopePopper
RAII class to pop scope from an expression context on destruction.
Definition: qgsexpressioncontextutils.h:355
QgsDataSourceUri
Class for storing the component parts of a RDBMS data source URI (e.g.
Definition: qgsdatasourceuri.h:36
QgsVectorTileLayer
Implements a map layer that is dedicated to rendering of vector tiles.
Definition: qgsvectortilelayer.h:84
QgsRenderContext::mapToPixel
const QgsMapToPixel & mapToPixel() const
Returns the context's map to pixel transform, which transforms between map coordinates and device coo...
Definition: qgsrendercontext.h:325
QgsExpressionContextScope::setVariable
void setVariable(const QString &name, const QVariant &value, bool isStatic=false)
Convenience method for setting a variable in the context scope by name name and value.
Definition: qgsexpressioncontext.cpp:78
QgsRenderContext::expressionContext
QgsExpressionContext & expressionContext()
Gets the expression context.
Definition: qgsrendercontext.h:596
QgsVectorTileUtils::makeQgisFields
static QgsFields makeQgisFields(QSet< QString > flds)
Returns QgsFields instance based on the set of field names.
Definition: qgsvectortileutils.cpp:51
QgsDebugMsgLevel
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
QgsVectorTileUtils::scaleToZoom
static double scaleToZoom(double mapScale)
Finds zoom level (assuming GoogleCRS84Quad tile matrix set) given map scale denominator.
Definition: qgsvectortileutils.cpp:63
QgsRectangle::center
QgsPointXY center() const SIP_HOLDGIL
Returns the center point of the rectangle.
Definition: qgsrectangle.h:230
QgsLabelingEngine::removeProvider
void removeProvider(QgsAbstractLabelProvider *provider)
Remove provider if the provider's initialization failed. Provider instance is deleted.
Definition: qgslabelingengine.cpp:194
qgsvectortilelabeling.h
QgsVectorTileLayerRenderer::QgsVectorTileLayerRenderer
QgsVectorTileLayerRenderer(QgsVectorTileLayer *layer, QgsRenderContext &context)
Creates the renderer. Always called from main thread, should copy whatever necessary from the layer.
Definition: qgsvectortilelayerrenderer.cpp:33
QgsVectorTileLoader::blockingFetchTileRawData
static QList< QgsVectorTileRawData > blockingFetchTileRawData(const QString &sourceType, const QString &sourcePath, const QgsTileMatrix &tileMatrix, const QPointF &viewCenter, const QgsTileRange &range, const QString &authid, const QString &referer)
Returns raw tile data for the specified range of tiles. Blocks the caller until all tiles are fetched...
Definition: qgsvectortileloader.cpp:159
QgsRenderContext
Contains information about the context of a rendering operation.
Definition: qgsrendercontext.h:58
QgsMapLayerRenderer::renderContext
QgsRenderContext * renderContext()
Returns the render context associated with the renderer.
Definition: qgsmaplayerrenderer.h:84
QgsVectorTileRendererData
Contains decoded features of a single vector tile and any other data necessary for rendering of it.
Definition: qgsvectortilerenderer.h:38
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:306
QgsVectorTileMVTDecoder
This class is responsible for decoding raw tile data written with Mapbox Vector Tiles encoding.
Definition: qgsvectortilemvtdecoder.h:37
QgsMapLayerRenderer
Base class for utility classes that encapsulate information necessary for rendering of map layers.
Definition: qgsmaplayerrenderer.h:51
QgsVectorTileLabeling::provider
virtual QgsVectorTileLabelProvider * provider(QgsVectorTileLayer *layer) const SIP_SKIP
Factory for label provider implementation.
Definition: qgsvectortilelabeling.h:98
QgsVectorTileMVTDecoder::layerFeatures
QgsVectorTileFeatures layerFeatures(const QMap< QString, QgsFields > &perLayerFields, const QgsCoordinateTransform &ct, const QSet< QString > *layerSubset=nullptr) const
Returns decoded features grouped by sub-layers.
Definition: qgsvectortilemvtdecoder.cpp:80
qgsvectortilelayer.h
QgsDataSourceUri::param
QString param(const QString &key) const
Returns a generic parameter value corresponding to the specified key.
Definition: qgsdatasourceuri.cpp:823
QgsRenderContext::renderingStopped
bool renderingStopped() const
Returns true if the rendering operation has been stopped and any ongoing rendering should be canceled...
Definition: qgsrendercontext.h:341
QgsRenderContext::coordinateTransform
QgsCoordinateTransform coordinateTransform() const
Returns the current coordinate transform for the context.
Definition: qgsrendercontext.h:245
QgsTileRange::endRow
int endRow() const
Returns index of the last row in the range.
Definition: qgstiles.h:82
QgsVectorTileLabelProvider::setFields
virtual void setFields(const QMap< QString, QgsFields > &perLayerFields)=0
Sets fields for each sub-layer.
QgsVectorTileLoader::tileRequestFinished
void tileRequestFinished(const QgsVectorTileRawData &rawTile)
Emitted when a tile request has finished. If a tile request has failed, the returned raw tile byte ar...
QgsVectorTileLabelProvider::usedAttributes
virtual QMap< QString, QSet< QString > > usedAttributes(const QgsRenderContext &context, int tileZoom) const =0
Returns field names for each sub-layer that are required for labeling.
qgsvectortilemvtdecoder.h
QgsMapClippingUtils::calculatePainterClipRegion
static QPainterPath calculatePainterClipRegion(const QList< QgsMapClippingRegion > &regions, const QgsRenderContext &context, QgsMapLayerType layerType, bool &shouldClip)
Returns a QPainterPath representing the intersection of clipping regions from context which should be...
Definition: qgsmapclippingutils.cpp:126
QgsFeedback
Base class for feedback objects to be used for cancellation of something running in a worker thread.
Definition: qgsfeedback.h:44
QgsVectorTileLabelProvider::requiredLayers
virtual QSet< QString > requiredLayers(QgsRenderContext &context, int tileZoom) const
Returns a list of the layers required for labeling.
Definition: qgsvectortilelabeling.h:53
QgsTileXYZ::toString
QString toString() const
Returns tile coordinates in a formatted string.
Definition: qgstiles.h:49
QgsVectorTileLoader
The loader class takes care of loading raw vector tile data from a tile source.
Definition: qgsvectortileloader.h:57
QgsTileRange::isValid
bool isValid() const
Returns whether the range is valid (when all row/column numbers are not negative)
Definition: qgstiles.h:73
QgsTileRange::endColumn
int endColumn() const
Returns index of the last column in the range.
Definition: qgstiles.h:78
QgsScopedQPainterState
Scoped object for saving and restoring a QPainter object's state.
Definition: qgsrendercontext.h:1120
QgsVectorTileUtils::scaleToZoomLevel
static int scaleToZoomLevel(double mapScale, int sourceMinZoom, int sourceMaxZoom)
Finds best fitting zoom level (assuming GoogleCRS84Quad tile matrix set) given map scale denominator ...
Definition: qgsvectortileutils.cpp:71
QgsExpressionContextScope
Single scope for storing variables and functions for use within a QgsExpressionContext.
Definition: qgsexpressioncontext.h:112
QgsLabelingEngine
The QgsLabelingEngine class provides map labeling functionality.
Definition: qgslabelingengine.h:215
qgsvectortileloader.h
QgsRectangle::toString
QString toString(int precision=16) const
Returns a string representation of form xmin,ymin : xmax,ymax Coordinates will be truncated to the sp...
Definition: qgsrectangle.cpp:127
QgsRenderContext::labelingEngine
QgsLabelingEngine * labelingEngine() const
Gets access to new labeling engine (may be nullptr)
Definition: qgsrendercontext.h:383
QgsMapLayer::source
QString source() const
Returns the source for the layer.
Definition: qgsmaplayer.cpp:192
QgsTileRange::startRow
int startRow() const
Returns index of the first row in the range.
Definition: qgstiles.h:80
QgsVectorTileLabelProvider::registerTileFeatures
virtual void registerTileFeatures(const QgsVectorTileRendererData &tile, QgsRenderContext &context)=0
Registers label features for given tile to the labeling engine.
QgsDataSourceUri::setEncodedUri
void setEncodedUri(const QByteArray &uri)
Sets the complete encoded uri.
Definition: qgsdatasourceuri.cpp:630
QgsVectorTileLayer::labeling
QgsVectorTileLabeling * labeling() const
Returns currently assigned labeling.
Definition: qgsvectortilelayer.cpp:629
QgsTileMatrix::mapToTileCoordinates
QPointF mapToTileCoordinates(const QgsPointXY &mapPoint) const
Returns row/column coordinates (floating point number) from the given point in map coordinates.
Definition: qgstiles.cpp:78
QgsVectorTileRawData
Keeps track of raw tile data that need to be decoded.
Definition: qgsvectortileloader.h:32
qgsvectortilelayerrenderer.h
QgsMapLayerType::VectorTileLayer
@ VectorTileLayer
Added in 3.14.
qgsmapclippingutils.h
QgsVectorTileRawData::id
QgsTileXYZ id
Tile position in tile matrix set.
Definition: qgsvectortileloader.h:39
QgsTileMatrix::fromWebMercator
static QgsTileMatrix fromWebMercator(int mZoomLevel)
Returns a tile matrix for the usual web mercator.
Definition: qgstiles.cpp:20
QgsDataSourceUri::authConfigId
QString authConfigId() const
Returns any associated authentication configuration ID stored in the URI.
Definition: qgsdatasourceuri.cpp:254
QgsVectorLayerLabelProvider::prepare
virtual bool prepare(QgsRenderContext &context, QSet< QString > &attributeNames)
Prepare for registration of features.
Definition: qgsvectorlayerlabelprovider.cpp:112
qgslogger.h
QgsRenderContext::painter
QPainter * painter()
Returns the destination QPainter for the render operation.
Definition: qgsrendercontext.h:179
QgsRenderContext::rendererScale
double rendererScale() const
Returns the renderer map scale.
Definition: qgsrendercontext.h:377
qgsvectortileutils.h
QgsCoordinateTransform
Class for doing transforms between two map coordinate systems.
Definition: qgscoordinatetransform.h:53
QgsVectorTileMVTDecoder::decode
bool decode(QgsTileXYZ tileID, const QByteArray &rawTileData)
Tries to decode raw tile data, returns true on success.
Definition: qgsvectortilemvtdecoder.cpp:36
qgsfeedback.h
QgsTileMatrix::tileRangeFromExtent
QgsTileRange tileRangeFromExtent(const QgsRectangle &mExtent)
Returns tile range that fully covers the given extent.
Definition: qgstiles.cpp:54
QgsVectorTileUtils::tilePolygon
static QPolygon tilePolygon(QgsTileXYZ id, const QgsCoordinateTransform &ct, const QgsTileMatrix &tm, const QgsMapToPixel &mtp)
Returns polygon (made by four corners of the tile) in screen coordinates.
Definition: qgsvectortileutils.cpp:36
qgslabelingengine.h
QgsTileRange::startColumn
int startColumn() const
Returns index of the first column in the range.
Definition: qgstiles.h:76
QgsVectorTileLayerRenderer::render
virtual bool render() override
Do the rendering (based on data stored in the class)
Definition: qgsvectortilelayerrenderer.cpp:64
QgsVectorTileRawData::data
QByteArray data
Raw tile data.
Definition: qgsvectortileloader.h:41