37#include <QElapsedTimer>
42 , mLayerName( layer->name() )
44 , mRenderer( layer->renderer()->clone() )
45 , mLayerBlendMode( layer->blendMode() )
46 , mDrawTileBoundaries( layer->isTileBorderRenderingEnabled() )
47 , mLabelsEnabled( layer->labelsEnabled() )
49 , mSelectedFeatures( layer->selectedFeatures() )
50 , mLayerOpacity( layer->opacity() )
51 , mTileMatrixSet( layer->tileMatrixSet() )
52 , mEnableProfile( context.
flags() &
Qgis::RenderContextFlag::RecordProfile )
59 if ( layer->labelsEnabled() )
61 mLabelProvider = layer->labeling()->provider( layer );
64 engine->addProvider( mLabelProvider );
71 mDataProvider->moveToThread(
nullptr );
73 mPreparationTime = timer.elapsed();
82 std::unique_ptr< QgsScopedRuntimeProfile > profile;
85 profile = std::make_unique< QgsScopedRuntimeProfile >( mLayerName, QStringLiteral(
"rendering" ),
layerId() );
86 if ( mPreparationTime > 0 )
95 std::unique_ptr< QgsScopedRuntimeProfile > preparingProfile;
98 preparingProfile = std::make_unique< QgsScopedRuntimeProfile >( QObject::tr(
"Preparing render" ), QStringLiteral(
"rendering" ) );
101 mDataProvider->moveToThread( QThread::currentThread() );
105 if ( !mClippingRegions.empty() )
107 bool needsPainterClipPath =
false;
109 if ( needsPainterClipPath )
113 QElapsedTimer tTotal;
116 const double tileRenderScale = mTileMatrixSet.scaleForRenderContext( ctx );
139 QgsDebugError( QStringLiteral(
"Could not transform map extent to layer extent -- cannot calculate valid extent for vector tiles, aborting: %1" ).arg( cs.
what() ) );
145 QgsDebugMsgLevel( QStringLiteral(
"Vector tiles map scale 1 : %1" ).arg( tileRenderScale ), 2 );
147 mTileZoomToFetch = mTileMatrixSet.scaleToZoomLevel( tileRenderScale );
148 QgsDebugMsgLevel( QStringLiteral(
"Vector tiles zoom level: %1" ).arg( mTileZoomToFetch ), 2 );
149 mTileZoomToRender = mTileMatrixSet.scaleToZoomLevel( tileRenderScale,
false );
150 QgsDebugMsgLevel( QStringLiteral(
"Render zoom level: %1" ).arg( mTileZoomToRender ), 2 );
152 mTileMatrix = mTileMatrixSet.tileMatrix( mTileZoomToFetch );
154 mTileRange = mTileMatrix.tileRangeFromExtent( extent );
155 QgsDebugMsgLevel( QStringLiteral(
"Vector tiles range X: %1 - %2 Y: %3 - %4 (%5 tiles total)" )
156 .arg( mTileRange.startColumn() ).arg( mTileRange.endColumn() )
157 .arg( mTileRange.startRow() ).arg( mTileRange.endRow() ).arg( mTileRange.count() ), 2 );
160 const QPointF viewCenter = mTileMatrix.mapToTileCoordinates( extent.
center() );
162 if ( !mTileRange.isValid() )
168 preparingProfile.reset();
169 std::unique_ptr< QgsScopedRuntimeProfile > renderingProfile;
170 if ( mEnableProfile )
172 renderingProfile = std::make_unique< QgsScopedRuntimeProfile >( QObject::tr(
"Rendering" ), QStringLiteral(
"rendering" ) );
175 std::unique_ptr<QgsVectorTileLoader> asyncLoader;
176 QList<QgsVectorTileRawData> rawTiles;
177 if ( !mDataProvider->supportsAsync() )
179 QElapsedTimer tFetch;
182 QgsDebugMsgLevel( QStringLiteral(
"Tile fetching time: %1" ).arg( tFetch.elapsed() / 1000. ), 2 );
183 QgsDebugMsgLevel( QStringLiteral(
"Fetched tiles: %1" ).arg( rawTiles.count() ), 2 );
187 asyncLoader = std::make_unique<QgsVectorTileLoader>( mDataProvider.get(), mTileMatrixSet, mTileRange, mTileZoomToFetch, viewCenter, mFeedback.get(),
renderContext()->rendererUsage() );
190 QgsDebugMsgLevel( QStringLiteral(
"Got tile asynchronously: " ) + rawTile.id.toString(), 2 );
191 if ( !rawTile.data.isEmpty() )
192 decodeAndDrawTile( rawTile );
201 scope->
setVariable( QStringLiteral(
"zoom_level" ), mTileZoomToRender,
true );
202 scope->
setVariable( QStringLiteral(
"vector_tile_zoom" ), mTileMatrixSet.scaleToZoom( tileRenderScale ),
true );
205 mRenderer->startRender( *
renderContext(), mTileZoomToRender, mTileRange );
208 mRenderer->renderBackground( ctx );
210 QMap<QString, QSet<QString> > requiredFields = mRenderer->usedAttributes( ctx );
212 if ( mLabelProvider )
214 const QMap<QString, QSet<QString> > requiredFieldsLabeling = mLabelProvider->usedAttributes( ctx, mTileZoomToRender );
215 for (
auto it = requiredFieldsLabeling.begin(); it != requiredFieldsLabeling.end(); ++it )
217 requiredFields[it.key()].unite( it.value() );
221 for (
auto it = requiredFields.constBegin(); it != requiredFields.constEnd(); ++it )
224 mRequiredLayers = mRenderer->requiredLayers( ctx, mTileZoomToRender );
226 if ( mLabelProvider )
228 mLabelProvider->setFields( mPerLayerFields );
229 QSet<QString> attributeNames;
230 if ( !mLabelProvider->prepare( ctx, attributeNames ) )
233 mLabelProvider =
nullptr;
237 mRequiredLayers.unite( mLabelProvider->requiredLayers( ctx, mTileZoomToRender ) );
241 if ( !mDataProvider->supportsAsync() )
248 decodeAndDrawTile( rawTile );
255 asyncLoader->downloadBlocking();
256 if ( !asyncLoader->error().isEmpty() )
257 mErrors.append( asyncLoader->error() );
261 if ( mLabelProvider )
263 for (
const auto &tile : mTileDataMap )
265 mLabelProvider->registerTileFeatures( tile, ctx );
270 mRenderer->renderSelectedFeatures( mSelectedFeatures, ctx );
272 mRenderer->stopRender( ctx );
274 QgsDebugMsgLevel( QStringLiteral(
"Total time for decoding: %1" ).arg( mTotalDecodeTime / 1000. ), 2 );
275 QgsDebugMsgLevel( QStringLiteral(
"Drawing time: %1" ).arg( mTotalDrawTime / 1000. ), 2 );
276 QgsDebugMsgLevel( QStringLiteral(
"Total time: %1" ).arg( tTotal.elapsed() / 1000. ), 2 );
296 if ( mLayerBlendMode != QPainter::CompositionMode_SourceOver )
313 if ( !decoder.decode( rawTile ) )
324 QgsVectorTileRendererData tile( rawTile.
id );
325 tile.setRenderZoomLevel( mTileZoomToRender );
327 tile.setFields( mPerLayerFields );
328 tile.setFeatures( decoder.layerFeatures( mPerLayerFields, ct, &mRequiredLayers ) );
334 catch ( QgsCsException & )
340 mTotalDecodeTime += tLoad.elapsed();
349 const QgsScopedQPainterState savePainterState( ctx.
painter() );
352 ctx.
painter()->setClipRegion( QRegion( tile.tilePolygon() ), Qt::IntersectClip );
357 mRenderer->renderTile( tile, ctx );
358 mTotalDrawTime += tDraw.elapsed();
362 if ( mLabelProvider )
363 mTileDataMap.insert( tile.id().toString(), tile );
365 if ( mDrawTileBoundaries )
367 const QgsScopedQPainterState savePainterState( ctx.
painter() );
368 ctx.
painter()->setClipping(
false );
372 QBrush brush( QColor( 255, 0, 0, 40 ), Qt::BrushStyle::Dense3Pattern );
375 ctx.
painter()->setBrush( brush );
376 ctx.
painter()->drawPolygon( tile.tilePolygon() );
378 QgsTextFormat format;
379 format.
setColor( QColor( 255, 0, 0 ) );
Provides global constants and enumerations for use throughout the application.
@ Default
Allow raster-based rendering in situations where it is required for correct rendering or where it wil...
@ PreferVector
Prefer vector-based rendering, when the result will still be visually near-identical to a raster-base...
@ ForceVector
Always force vector-based rendering, even when the result will be visually different to a raster-base...
@ VectorTile
Vector tile layer. Added in QGIS 3.14.
@ DrawSelection
Whether vector selections should be shown in the rendered map.
@ VerticalCenter
Center align.
@ Reverse
Reverse/inverse transform (from destination to source).
static QgsRuntimeProfiler * profiler()
Returns the application runtime profiler.
Custom exception class for Coordinate Reference System related exceptions.
RAII class to pop scope from an expression context on destruction.
Single scope for storing variables and functions for use within a QgsExpressionContext.
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.
Base class for feedback objects to be used for cancellation of something running in a worker thread.
Provides map labeling functionality.
void removeProvider(QgsAbstractLabelProvider *provider)
Remove provider if the provider's initialization failed. Provider instance is deleted.
static QPainterPath calculatePainterClipRegion(const QList< QgsMapClippingRegion > ®ions, const QgsRenderContext &context, Qgis::LayerType layerType, bool &shouldClip)
Returns a QPainterPath representing the intersection of clipping regions from context which should be...
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.
QString layerId() const
Gets access to the ID of the layer rendered by this class.
virtual Qgis::MapLayerRendererFlags flags() const
Returns flags which control how the map layer rendering behaves.
QgsRenderContext * renderContext()
Returns the render context associated with the renderer.
QgsMapLayerRenderer(const QString &layerID, QgsRenderContext *context=nullptr)
Constructor for QgsMapLayerRenderer, with the associated layerID and render context.
A rectangle specified with double values.
Q_INVOKABLE QString toString(int precision=16) const
Returns a string representation of form xmin,ymin : xmax,ymax Coordinates will be truncated to the sp...
bool isMaximal() const
Test if the rectangle is the maximal possible rectangle.
Contains information about the context of a rendering operation.
QPainter * painter()
Returns the destination QPainter for the render operation.
QgsExpressionContext & expressionContext()
Gets the expression context.
QSize outputSize() const
Returns the size of the resulting rendered image, in pixels.
const QgsRectangle & extent() const
When rendering a map layer, calling this method returns the "clipping" extent for the layer (in the l...
QgsRectangle mapExtent() const
Returns the original extent of the map being rendered.
const QgsMapToPixel & mapToPixel() const
Returns the context's map to pixel transform, which transforms between map coordinates and device coo...
bool renderingStopped() const
Returns true if the rendering operation has been stopped and any ongoing rendering should be canceled...
QgsLabelingEngine * labelingEngine() const
Gets access to new labeling engine (may be nullptr).
QgsCoordinateTransform coordinateTransform() const
Returns the current coordinate transform for the context.
Qgis::RenderContextFlags flags() const
Returns combination of flags used for rendering.
void record(const QString &name, double time, const QString &group="startup", const QString &id=QString())
Manually adds a profile event with the given name and total time (in seconds).
Scoped object for saving and restoring a QPainter object's state.
Scoped object for setting the current thread name.
void setEnabled(bool enabled)
Sets whether the text buffer will be drawn.
void setColor(const QColor &color)
Sets the color that text will be rendered in.
QgsTextBufferSettings & buffer()
Returns a reference to the text buffer settings.
static void drawText(const QRectF &rect, double rotation, Qgis::TextHorizontalAlignment alignment, const QStringList &textLines, QgsRenderContext &context, const QgsTextFormat &format, bool drawAsOutlines=true, Qgis::TextVerticalAlignment vAlignment=Qgis::TextVerticalAlignment::Top, Qgis::TextRendererFlags flags=Qgis::TextRendererFlags(), Qgis::TextLayoutMode mode=Qgis::TextLayoutMode::Rectangle)
Draws text within a rectangle using the specified settings.
QString toString() const
Returns tile coordinates in a formatted string.
int zoomLevel() const
Returns tile's zoom level (Z).
Base class for vector tile layer data providers.
bool forceRasterRender() const override
Returns true if the renderer must be rendered to a raster paint device (e.g.
~QgsVectorTileLayerRenderer() override
QgsVectorTileLayerRenderer(QgsVectorTileLayer *layer, QgsRenderContext &context)
Creates the renderer. Always called from main thread, should copy whatever necessary from the layer.
bool render() override
Do the rendering (based on data stored in the class).
Implements a map layer that is dedicated to rendering of vector tiles.
void tileRequestFinished(const QgsVectorTileRawData &rawTile)
Emitted when a tile request has finished. If a tile request has failed, the returned raw tile byte ar...
static QList< QgsVectorTileRawData > blockingFetchTileRawData(const QgsVectorTileDataProvider *provider, const QgsTileMatrixSet &tileMatrixSet, const QPointF &viewCenter, const QgsTileRange &range, int zoomLevel, QgsFeedback *feedback=nullptr, Qgis::RendererUsage usage=Qgis::RendererUsage::Unknown)
Returns raw tile data for the specified range of tiles. Blocks the caller until all tiles are fetched...
Responsible for decoding raw tile data written with Mapbox Vector Tiles encoding.
Keeps track of raw tile data from one or more sources that need to be decoded.
QgsTileXYZ id
Tile position in tile matrix set.
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.
static QgsFields makeQgisFields(const QSet< QString > &flds)
Returns QgsFields instance based on the set of field names.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).
#define QgsDebugMsgLevel(str, level)
#define QgsDebugError(str)