QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
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 
18 #include "qgsgrouplayerrenderer.h"
19 #include "qgsgrouplayer.h"
20 #include "qgsfeedback.h"
21 #include "qgspainteffect.h"
22 #include "qgsrendercontext.h"
23 #include "qgslogger.h"
24 #include <optional>
25 
27  : QgsMapLayerRenderer( layer->id(), &context )
28  , mFeedback( std::make_unique< QgsFeedback >() )
29  , mLayerOpacity( layer->opacity() )
30 {
31  const QList< QgsMapLayer * > layers = layer->childLayers();
32  const QgsCoordinateReferenceSystem destinationCrs = context.coordinateTransform().destinationCrs();
33  for ( QgsMapLayer *childLayer : layers )
34  {
35  // we have to temporarily set the context's crs and extent to the correct one for the child layer, BEFORE creating the
36  // child layer's renderer
37  QgsCoordinateTransform layerToDestTransform( childLayer->crs(), destinationCrs, context.transformContext() );
38  layerToDestTransform.setBallparkTransformsAreAppropriate( true );
39  context.setCoordinateTransform( layerToDestTransform );
40  try
41  {
42  const QgsRectangle extentInChildLayerCrs = layerToDestTransform.transformBoundingBox( context.mapExtent(), Qgis::TransformDirection::Reverse );
43  context.setExtent( extentInChildLayerCrs );
44  }
45  catch ( QgsCsException & )
46  {
47  QgsDebugMsg( QStringLiteral( "Error transforming extent of %1 to destination CRS" ).arg( childLayer->id() ) );
48  continue;
49  }
50 
51  mChildRenderers.emplace_back( childLayer->createMapRenderer( context ) );
52  mRendererCompositionModes.emplace_back( childLayer->blendMode() );
53  mRendererOpacity.emplace_back( childLayer->type() != QgsMapLayerType::RasterLayer ? childLayer->opacity() : 1.0 );
54  mTransforms.emplace_back( layerToDestTransform );
55  }
56 
57  mPaintEffect.reset( layer->paintEffect() && layer->paintEffect()->enabled() ? layer->paintEffect()->clone() : nullptr );
58 
59  mForceRasterRender = layer->blendMode() != QPainter::CompositionMode_SourceOver;
60 }
61 
63 
65 {
66  return mFeedback.get();
67 }
68 
70 {
71  QgsRenderContext &context = *renderContext();
72 
73  context.painter()->save();
74  if ( mPaintEffect )
75  {
76  mPaintEffect->begin( context );
77  }
78 
79  const QgsCoordinateReferenceSystem destinationCrs = context.coordinateTransform().destinationCrs();
80  bool canceled = false;
81  int i = 0;
82  for ( const std::unique_ptr< QgsMapLayerRenderer > &renderer : std::as_const( mChildRenderers ) )
83  {
84  if ( mFeedback->isCanceled() )
85  {
86  canceled = true;
87  break;
88  }
89 
90  context.setCoordinateTransform( mTransforms[i] );
91 
92  // don't need to catch exceptions here -- it would have already been caught in the QgsGroupLayerRenderer constructor!
93  const QgsRectangle extentInChildLayerCrs = mTransforms[i].transformBoundingBox( context.mapExtent(), Qgis::TransformDirection::Reverse );
94  context.setExtent( extentInChildLayerCrs );
95 
96  QImage image;
97  if ( context.useAdvancedEffects() )
98  context.painter()->setCompositionMode( mRendererCompositionModes[i] );
99 
100  QPainter *prevPainter = context.painter();
101  std::unique_ptr< QPainter > imagePainter;
102  if ( renderer->forceRasterRender() )
103  {
104  image = QImage( context.deviceOutputSize(), context.imageFormat() );
105  image.setDevicePixelRatio( static_cast<qreal>( context.devicePixelRatio() ) );
106  image.fill( 0 );
107  imagePainter = std::make_unique< QPainter >( &image );
108 
109  context.setPainterFlagsUsingContext( imagePainter.get() );
110  context.setPainter( imagePainter.get() );
111  }
112  renderer->render();
113 
114  if ( imagePainter )
115  {
116  imagePainter->end();
117  context.setPainter( prevPainter );
118 
119  context.painter()->setOpacity( mRendererOpacity[i] );
120  context.painter()->drawImage( 0, 0, image );
121  context.painter()->setOpacity( 1.0 );
122  }
123  context.painter()->setCompositionMode( QPainter::CompositionMode_SourceOver );
124  i++;
125  }
126 
127  if ( mPaintEffect )
128  {
129  mPaintEffect->end( context );
130  }
131 
132  context.painter()->restore();
133 
134  return !canceled;
135 }
136 
138 {
140  return false;
141 
142  if ( mForceRasterRender || !qgsDoubleNear( mLayerOpacity, 1.0 ) )
143  return true;
144 
145  for ( QPainter::CompositionMode mode : mRendererCompositionModes )
146  {
147  if ( mode != QPainter::CompositionMode_SourceOver )
148  return true;
149  }
150 
151  return false;
152 }
QgsGroupLayerRenderer::QgsGroupLayerRenderer
QgsGroupLayerRenderer(QgsGroupLayer *layer, QgsRenderContext &context)
Constructor for a QgsGroupLayerRenderer, for the specified layer.
Definition: qgsgrouplayerrenderer.cpp:26
QgsRenderContext::deviceOutputSize
QSize deviceOutputSize() const
Returns the device output size of the render.
Definition: qgsrendercontext.cpp:680
QgsRenderContext::setPainterFlagsUsingContext
void setPainterFlagsUsingContext(QPainter *painter=nullptr) const
Sets relevant flags on a destination painter, using the flags and settings currently defined for the ...
Definition: qgsrendercontext.cpp:169
QgsRenderContext::imageFormat
QImage::Format imageFormat() const
Returns the QImage format which should be used for QImages created during rendering.
Definition: qgsrendercontext.h:992
QgsMapLayer::blendMode
QPainter::CompositionMode blendMode() const
Returns the current blending mode for a layer.
Definition: qgsmaplayer.cpp:320
QgsRenderContext::setPainter
void setPainter(QPainter *p)
Sets the destination QPainter for the render operation.
Definition: qgsrendercontext.h:512
QgsCoordinateTransform::transformBoundingBox
QgsRectangle transformBoundingBox(const QgsRectangle &rectangle, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward, bool handle180Crossover=false) const SIP_THROW(QgsCsException)
Transforms a rectangle from the source CRS to the destination CRS.
Definition: qgscoordinatetransform.cpp:560
QgsRenderContext
Contains information about the context of a rendering operation.
Definition: qgsrendercontext.h:59
QgsMapLayerRenderer::renderContext
QgsRenderContext * renderContext()
Returns the render context associated with the renderer.
Definition: qgsmaplayerrenderer.h:111
QgsGroupLayer
A map layer which consists of a set of child layers, where all component layers are rendered as a sin...
Definition: qgsgrouplayer.h:41
QgsDebugMsg
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
qgspainteffect.h
QgsGroupLayer::paintEffect
QgsPaintEffect * paintEffect() const
Returns the current paint effect for the group layer.
Definition: qgsgrouplayer.cpp:294
QgsRectangle
A rectangle specified with double values.
Definition: qgsrectangle.h:41
QgsGroupLayerRenderer::~QgsGroupLayerRenderer
~QgsGroupLayerRenderer() override
QgsMapLayerRenderer
Base class for utility classes that encapsulate information necessary for rendering of map layers.
Definition: qgsmaplayerrenderer.h:54
QgsCoordinateTransform::destinationCrs
QgsCoordinateReferenceSystem destinationCrs() const
Returns the destination coordinate reference system, which the transform will transform coordinates t...
Definition: qgscoordinatetransform.cpp:267
QgsRenderContext::coordinateTransform
QgsCoordinateTransform coordinateTransform() const
Returns the current coordinate transform for the context.
Definition: qgsrendercontext.h:178
QgsCsException
Custom exception class for Coordinate Reference System related exceptions.
Definition: qgsexception.h:65
QgsRenderContext::useAdvancedEffects
bool useAdvancedEffects() const
Returns true if advanced effects such as blend modes such be used.
Definition: qgsrendercontext.cpp:300
qgsgrouplayer.h
QgsCoordinateTransform::setBallparkTransformsAreAppropriate
void setBallparkTransformsAreAppropriate(bool appropriate)
Sets whether approximate "ballpark" results are appropriate for this coordinate transform.
Definition: qgscoordinatetransform.cpp:939
qgsDoubleNear
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:2265
QgsFeedback
Base class for feedback objects to be used for cancellation of something running in a worker thread.
Definition: qgsfeedback.h:44
QgsRenderContext::setExtent
void setExtent(const QgsRectangle &extent)
When rendering a map layer, calling this method sets the "clipping" extent for the layer (in the laye...
Definition: qgsrendercontext.h:426
QgsRenderContext::setCoordinateTransform
void setCoordinateTransform(const QgsCoordinateTransform &t)
Sets the current coordinate transform for the context.
Definition: qgsrendercontext.cpp:320
QgsGroupLayerRenderer::forceRasterRender
bool forceRasterRender() const override
Returns true if the renderer must be rendered to a raster paint device (e.g.
Definition: qgsgrouplayerrenderer.cpp:137
QgsMapLayerType::RasterLayer
@ RasterLayer
Raster layer.
QgsPaintEffect::clone
virtual QgsPaintEffect * clone() const =0
Duplicates an effect by creating a deep copy of the effect.
qgsrendercontext.h
QgsGroupLayerRenderer::render
bool render() override
Do the rendering (based on data stored in the class).
Definition: qgsgrouplayerrenderer.cpp:69
QgsGroupLayer::childLayers
QList< QgsMapLayer * > childLayers() const
Returns the child layers contained by the group.
Definition: qgsgrouplayer.cpp:289
QgsCoordinateReferenceSystem
This class represents a coordinate reference system (CRS).
Definition: qgscoordinatereferencesystem.h:211
QgsRenderContext::mapExtent
QgsRectangle mapExtent() const
Returns the original extent of the map being rendered.
Definition: qgsrendercontext.h:251
QgsRenderContext::transformContext
QgsCoordinateTransformContext transformContext() const
Returns the context's coordinate transform context, which stores various information regarding which ...
Definition: qgsrendercontext.cpp:184
QgsMapLayer
Base class for all map layer types. This is the base class for all map layer types (vector,...
Definition: qgsmaplayer.h:72
qgsgrouplayerrenderer.h
qgslogger.h
QgsRenderContext::painter
QPainter * painter()
Returns the destination QPainter for the render operation.
Definition: qgsrendercontext.h:112
QgsPaintEffect::enabled
bool enabled() const
Returns whether the effect is enabled.
Definition: qgspainteffect.h:197
QgsCoordinateTransform
Class for doing transforms between two map coordinate systems.
Definition: qgscoordinatetransform.h:57
qgsfeedback.h
Qgis::RenderContextFlag::UseAdvancedEffects
@ UseAdvancedEffects
Enable layer opacity and blending effects.
QgsRenderContext::devicePixelRatio
float devicePixelRatio() const
Returns the device pixel ratio.
Definition: qgsrendercontext.cpp:670
QgsGroupLayerRenderer::feedback
QgsFeedback * feedback() const override
Access to feedback object of the layer renderer (may be nullptr)
Definition: qgsgrouplayerrenderer.cpp:64