QGIS API Documentation 3.99.0-Master (d270888f95f)
Loading...
Searching...
No Matches
qgsgrouplayerrenderer.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsgrouplayerrenderer.cpp
3 ----------------
4 Date : September 2021
5 Copyright : (C) 2021 by Nyall Dawson
6 Email : nyall dot dawson at gmail dot com
7 ***************************************************************************/
8
9/***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
19
20#include <optional>
21
22#include "qgsfeedback.h"
23#include "qgsgrouplayer.h"
24#include "qgslogger.h"
25#include "qgspainteffect.h"
26#include "qgsrendercontext.h"
27
28#include <QString>
29
30using namespace Qt::StringLiterals;
31
33 : QgsMapLayerRenderer( layer->id(), &context )
34 , mFeedback( std::make_unique< QgsFeedback >() )
35 , mLayerOpacity( layer->opacity() )
36{
37 const QList< QgsMapLayer * > layers = layer->childLayers();
38 const QgsCoordinateReferenceSystem destinationCrs = context.coordinateTransform().destinationCrs();
39 for ( QgsMapLayer *childLayer : layers )
40 {
41 // we have to temporarily set the context's crs and extent to the correct one for the child layer, BEFORE creating the
42 // child layer's renderer
43 QgsCoordinateTransform layerToDestTransform( childLayer->crs(), destinationCrs, context.transformContext() );
44 layerToDestTransform.setBallparkTransformsAreAppropriate( true );
45 context.setCoordinateTransform( layerToDestTransform );
46 try
47 {
48 const QgsRectangle extentInChildLayerCrs = layerToDestTransform.transformBoundingBox( context.mapExtent(), Qgis::TransformDirection::Reverse );
49 context.setExtent( extentInChildLayerCrs );
50 }
51 catch ( QgsCsException & )
52 {
53 QgsDebugError( u"Error transforming extent of %1 to destination CRS"_s.arg( childLayer->id() ) );
54 continue;
55 }
56
57 mChildRenderers.emplace_back( childLayer->createMapRenderer( context ) );
58 mRendererCompositionModes.emplace_back( childLayer->blendMode() );
59 mRendererOpacity.emplace_back( childLayer->type() != Qgis::LayerType::Raster ? childLayer->opacity() : 1.0 );
60 mTransforms.emplace_back( layerToDestTransform );
61 }
62
63 mPaintEffect.reset( layer->paintEffect() && layer->paintEffect()->enabled() ? layer->paintEffect()->clone() : nullptr );
64
65 mForceRasterRender = layer->blendMode() != QPainter::CompositionMode_SourceOver;
66}
67
69
71{
72 return mFeedback.get();
73}
74
76{
77 QgsRenderContext &context = *renderContext();
78
79 context.painter()->save();
80 if ( mPaintEffect )
81 {
82 mPaintEffect->begin( context );
83 }
84
85 const QgsCoordinateReferenceSystem destinationCrs = context.coordinateTransform().destinationCrs();
86 bool canceled = false;
87 int i = 0;
88 for ( const std::unique_ptr< QgsMapLayerRenderer > &renderer : std::as_const( mChildRenderers ) )
89 {
90 if ( mFeedback->isCanceled() )
91 {
92 canceled = true;
93 break;
94 }
95
96 context.setCoordinateTransform( mTransforms[i] );
97
98 // don't need to catch exceptions here -- it would have already been caught in the QgsGroupLayerRenderer constructor!
99 const QgsRectangle extentInChildLayerCrs = mTransforms[i].transformBoundingBox( context.mapExtent(), Qgis::TransformDirection::Reverse );
100 context.setExtent( extentInChildLayerCrs );
101
102 QImage image;
104 {
105 context.painter()->setCompositionMode( mRendererCompositionModes[i] );
106 }
107
108 QPainter *prevPainter = context.painter();
109 std::unique_ptr< QPainter > imagePainter;
110 if ( renderer->forceRasterRender() )
111 {
112 image = QImage( context.deviceOutputSize(), context.imageFormat() );
113 image.setDevicePixelRatio( static_cast<qreal>( context.devicePixelRatio() ) );
114 image.fill( 0 );
115 imagePainter = std::make_unique< QPainter >( &image );
116
117 context.setPainterFlagsUsingContext( imagePainter.get() );
118 context.setPainter( imagePainter.get() );
119 }
120 renderer->render();
121
122 if ( imagePainter )
123 {
124 imagePainter->end();
125 context.setPainter( prevPainter );
126
127 context.painter()->setOpacity( mRendererOpacity[i] );
128 context.painter()->drawImage( 0, 0, image );
129 context.painter()->setOpacity( 1.0 );
130 }
131 context.painter()->setCompositionMode( QPainter::CompositionMode_SourceOver );
132 i++;
133 }
134
135 if ( mPaintEffect )
136 {
137 mPaintEffect->end( context );
138 }
139
140 context.painter()->restore();
141
142 return !canceled;
143}
144
146{
147 switch ( renderContext()->rasterizedRenderingPolicy() )
148 {
151 break;
152
154 return false;
155 }
156
157 if ( mForceRasterRender || !qgsDoubleNear( mLayerOpacity, 1.0 ) )
158 return true;
159
160 for ( QPainter::CompositionMode mode : mRendererCompositionModes )
161 {
162 if ( mode != QPainter::CompositionMode_SourceOver )
163 return true;
164 }
165
166 return false;
167}
@ Default
Allow raster-based rendering in situations where it is required for correct rendering or where it wil...
Definition qgis.h:2762
@ PreferVector
Prefer vector-based rendering, when the result will still be visually near-identical to a raster-base...
Definition qgis.h:2763
@ ForceVector
Always force vector-based rendering, even when the result will be visually different to a raster-base...
Definition qgis.h:2764
@ Raster
Raster layer.
Definition qgis.h:195
@ Reverse
Reverse/inverse transform (from destination to source).
Definition qgis.h:2731
Represents a coordinate reference system (CRS).
Handles coordinate transforms between two coordinate systems.
void setBallparkTransformsAreAppropriate(bool appropriate)
Sets whether approximate "ballpark" results are appropriate for this coordinate transform.
QgsRectangle transformBoundingBox(const QgsRectangle &rectangle, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward, bool handle180Crossover=false) const
Transforms a rectangle from the source CRS to the destination CRS.
QgsCoordinateReferenceSystem destinationCrs() const
Returns the destination coordinate reference system, which the transform will transform coordinates t...
Custom exception class for Coordinate Reference System related exceptions.
Base class for feedback objects to be used for cancellation of something running in a worker thread.
Definition qgsfeedback.h:44
~QgsGroupLayerRenderer() override
QgsGroupLayerRenderer(QgsGroupLayer *layer, QgsRenderContext &context)
Constructor for a QgsGroupLayerRenderer, for the specified layer.
bool forceRasterRender() const override
Returns true if the renderer must be rendered to a raster paint device (e.g.
QgsFeedback * feedback() const override
Access to feedback object of the layer renderer (may be nullptr).
bool render() override
Do the rendering (based on data stored in the class).
A map layer which consists of a set of child layers, where all component layers are rendered as a sin...
QgsPaintEffect * paintEffect() const
Returns the current paint effect for the group layer.
QList< QgsMapLayer * > childLayers() const
Returns the child layers contained by the group.
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.
Base class for all map layer types.
Definition qgsmaplayer.h:83
QPainter::CompositionMode blendMode() const
Returns the current blending mode for a layer.
bool enabled() const
Returns whether the effect is enabled.
virtual QgsPaintEffect * clone() const =0
Duplicates an effect by creating a deep copy of the effect.
A rectangle specified with double values.
Contains information about the context of a rendering operation.
void setCoordinateTransform(const QgsCoordinateTransform &t)
Sets the current coordinate transform for the context.
QPainter * painter()
Returns the destination QPainter for the render operation.
void setPainterFlagsUsingContext(QPainter *painter=nullptr) const
Sets relevant flags on a destination painter, using the flags and settings currently defined for the ...
QgsCoordinateTransformContext transformContext() const
Returns the context's coordinate transform context, which stores various information regarding which ...
float devicePixelRatio() const
Returns the device pixel ratio.
QgsRectangle mapExtent() const
Returns the original extent of the map being rendered.
void setExtent(const QgsRectangle &extent)
When rendering a map layer, calling this method sets the "clipping" extent for the layer (in the laye...
Qgis::RasterizedRenderingPolicy rasterizedRenderingPolicy() const
Returns the policy controlling when rasterisation of content during renders is permitted.
void setPainter(QPainter *p)
Sets the destination QPainter for the render operation.
QSize deviceOutputSize() const
Returns the device output size of the render.
QgsCoordinateTransform coordinateTransform() const
Returns the current coordinate transform for the context.
QImage::Format imageFormat() const
Returns the QImage format which should be used for QImages created during rendering.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).
Definition qgis.h:6900
#define QgsDebugError(str)
Definition qgslogger.h:59