QGIS API Documentation 3.37.0-Master (fdefdf9c27f)
qgsmaprendererstagedrenderjob.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsmaprendererstagedrenderjob.cpp
3 --------------------------------------
4 Date : August 2019
5 Copyright : (C) 2019 by Nyall Dawson
6 Email : nyall dot dawson 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 "qgsfeedback.h"
19#include "qgslabelingengine.h"
20#include "qgslogger.h"
21#include "qgsproject.h"
22#include "qgsmaplayerrenderer.h"
25
28 , mFlags( flags )
29{
30}
31
33{
34 // final cleanup
35 cleanupJobs( mLayerJobs );
36 cleanupLabelJob( mLabelJob );
37}
38
39
40void QgsMapRendererStagedRenderJob::startPrivate()
41{
42 mRenderingStart.start();
43 mErrors.clear();
44
45 QgsDebugMsgLevel( QStringLiteral( "Preparing list of layer jobs for rendering" ), 5 );
46 QElapsedTimer prepareTime;
47 prepareTime.start();
48
49 mLabelingEngineV2.reset();
50
52 {
53 if ( mFlags & RenderLabelsByMapLayer )
54 mLabelingEngineV2.reset( new QgsStagedRenderLabelingEngine() );
55 else
56 mLabelingEngineV2.reset( new QgsDefaultLabelingEngine() );
57 mLabelingEngineV2->setMapSettings( mSettings );
58 }
59
60 mLayerJobs = prepareJobs( nullptr, mLabelingEngineV2.get(), true );
61 mLabelJob = prepareLabelingJob( nullptr, mLabelingEngineV2.get(), false );
62
63 mJobIt = mLayerJobs.begin();
64}
65
67{
68}
69
71{
72}
73
75{
76}
77
79{
80 return true;
81}
82
84{
85 return false;
86}
87
89{
90 if ( mLabelingEngineV2 )
91 return mLabelingEngineV2->takeResults();
92 else
93 return nullptr;
94}
95
97{
98 if ( isFinished() )
99 return false;
100
101 preparePainter( painter );
102
103 if ( mJobIt != mLayerJobs.end() )
104 {
105 LayerRenderJob &job = *mJobIt;
106 emit layerRenderingStarted( job.layerId );
107 job.renderer->renderContext()->setPainter( painter );
108
109 if ( job.context()->useAdvancedEffects() )
110 {
111 // Set the QPainter composition mode so that this layer is rendered using
112 // the desired blending mode
113 painter->setCompositionMode( job.blendMode );
114 }
115
116 if ( job.previewRenderImage && !job.previewRenderImageInitialized )
117 {
118 job.previewRenderImage->fill( 0 );
119 job.previewRenderImageInitialized = true;
120 }
121
122 if ( job.img )
123 {
124 job.img->fill( 0 );
125 job.imageInitialized = true;
126 }
127
128 job.completed = job.renderer->render();
129
130 if ( job.img )
131 {
132 // If we flattened this layer for alternate blend modes, composite it now
133 painter->setOpacity( job.opacity );
134 painter->drawImage( 0, 0, *job.img );
135 painter->setOpacity( 1.0 );
136 }
137 job.context()->setPainter( nullptr );
138
139 emit layerRendered( job.layerId );
140 }
141 else
142 {
143 if ( !mLabelingEngineV2 )
144 return false;
145
146 if ( mFlags & RenderLabelsByMapLayer )
147 {
148 if ( !mPreparedStagedLabelJob || mLabelLayerIt == mLabelingLayers.end() )
149 return false;
150
151 mLabelJob.context.setPainter( painter );
152
153 // Reset the composition mode before rendering the labels
154 painter->setCompositionMode( QPainter::CompositionMode_SourceOver );
155
156 // render just the current layer's labels
157 static_cast< QgsStagedRenderLabelingEngine * >( mLabelingEngineV2.get() )->renderLabelsForLayer( mLabelJob.context, *mLabelLayerIt );
158
159 mLabelJob.context.setPainter( nullptr );
160 }
161 else
162 {
163 mLabelJob.context.setPainter( painter );
164 drawLabeling( mLabelJob.context, mLabelingEngineV2.get(), painter );
165 mLabelJob.complete = true;
166 mLabelJob.participatingLayers = _qgis_listRawToQPointer( mLabelingEngineV2->participatingLayers() );
167 mLabelJob.context.setPainter( nullptr );
168 }
169 }
170 return true;
171}
172
174{
175 if ( isFinished() )
176 return false;
177
178 if ( mJobIt != mLayerJobs.end() )
179 {
180 ++mJobIt;
181 if ( mJobIt != mLayerJobs.end() )
182 return true;
183 }
184
185 if ( mLabelingEngineV2 )
186 {
187 if ( mFlags & RenderLabelsByMapLayer )
188 {
189 if ( !mPreparedStagedLabelJob )
190 {
191 mLabelingEngineV2->run( mLabelJob.context );
192 mPreparedStagedLabelJob = true;
193 mLabelingLayers = mLabelingEngineV2->participatingLayerIds();
194 mLabelLayerIt = mLabelingLayers.begin();
195 if ( mLabelLayerIt == mLabelingLayers.end() )
196 {
197 // no label layers to render!
198 static_cast< QgsStagedRenderLabelingEngine * >( mLabelingEngineV2.get() )->finalize();
199 return false;
200 }
201 return true;
202 }
203 else
204 {
205 if ( mLabelLayerIt != mLabelingLayers.end() )
206 {
207 ++mLabelLayerIt;
208 if ( mLabelLayerIt != mLabelingLayers.end() )
209 return true;
210 }
211 }
212 return false;
213 }
214 else
215 {
216 if ( mNextIsLabel )
217 {
218 mExportedLabels = true;
219 }
220 else if ( !mExportedLabels )
221 {
222 mNextIsLabel = true;
223 return true;
224 }
225 }
226 }
227 return false;
228}
229
231{
232 return currentStage() == Finished;
233}
234
236{
237 if ( mJobIt != mLayerJobs.end() )
238 {
239 const LayerRenderJob &job = *mJobIt;
240 return job.layerId;
241 }
242 else if ( mFlags & RenderLabelsByMapLayer && mPreparedStagedLabelJob )
243 {
244 if ( mLabelLayerIt != mLabelingLayers.end() )
245 return *mLabelLayerIt;
246 }
247 return QString();
248}
249
251{
252 if ( mJobIt != mLayerJobs.end() )
253 {
254 const LayerRenderJob &job = *mJobIt;
255 return job.opacity;
256 }
257 return 1.0;
258}
259
261{
262 if ( mJobIt != mLayerJobs.end() )
263 {
264 const LayerRenderJob &job = *mJobIt;
265 return job.blendMode;
266 }
267 return QPainter::CompositionMode_SourceOver;
268}
269
271{
272 if ( mJobIt != mLayerJobs.end() )
273 return Symbology;
274 else if ( mLabelingEngineV2 && mFlags & RenderLabelsByMapLayer )
275 {
276 if ( !mPreparedStagedLabelJob )
277 return Labels;
278 if ( mLabelLayerIt != mLabelingLayers.end() )
279 return Labels;
280 }
281 else if ( mNextIsLabel && !mExportedLabels )
282 return Labels;
283
284 return Finished;
285}
@ DrawLabeling
Enable drawing of labels on top of the map.
Default QgsLabelingEngine implementation, which completes the whole labeling operation (including lab...
Class that stores computed placement from labeling engine.
Abstract base class for map renderer jobs which use custom painters.
void preparePainter(QPainter *painter, const QColor &backgroundColor=Qt::transparent)
Prepares the given painter ready for a map render.
static Q_DECL_DEPRECATED void drawLabeling(const QgsMapSettings &settings, QgsRenderContext &renderContext, QgsLabelingEngine *labelingEngine2, QPainter *painter)
void layerRendered(const QString &layerId)
Emitted when a layer has completed rendering.
std::vector< LayerRenderJob > prepareJobs(QPainter *painter, QgsLabelingEngine *labelingEngine2, bool deferredPainterSet=false)
Creates a list of layer rendering jobs and prepares them for later render.
void cleanupJobs(std::vector< LayerRenderJob > &jobs)
QElapsedTimer mRenderingStart
QgsMapSettings mSettings
void layerRenderingStarted(const QString &layerId)
Emitted just before rendering starts for a particular layer.
LabelRenderJob prepareLabelingJob(QPainter *painter, QgsLabelingEngine *labelingEngine2, bool canUseLabelCache=true)
Prepares a labeling job.
void cleanupLabelJob(LabelRenderJob &job)
Handles clean up tasks for a label job, including deletion of images and storing cached label results...
double currentLayerOpacity() const
Returns the opacity for the current layer about to be rendered in the next render operation.
void cancel() override
Stop the rendering job - does not return until the job has terminated.
@ RenderLabelsByMapLayer
Labels should be rendered in individual stages by map layer. This allows separation of labels belongi...
bool usedCachedLabels() const override
Returns true if the render job was able to use a cached labeling solution.
RenderStage currentStage() const
Returns the current stage which will be rendered in the next render operation.
void waitForFinished() override
Block until the job has finished.
QPainter::CompositionMode currentLayerCompositionMode() const
Returns the composition mode for the current layer about to be rendered in the next render operation.
QString currentLayerId() const
Returns the ID of the current layer about to be rendered in the next render operation.
QgsLabelingResults * takeLabelingResults() override
Gets pointer to internal labeling engine (in order to get access to the results).
bool isActive() const override
Tell whether the rendering job is currently running in background.
QgsMapRendererStagedRenderJob(const QgsMapSettings &settings, Flags flags=Flags())
Constructor for QgsMapRendererStagedRenderJob, using the given map settings.
bool isFinished() const
Returns true if the job is finished, and nothing remains to render.
RenderStage
Represents the stages of a rendering job.
bool nextPart()
Iterates to the next part to render.
bool renderCurrentPart(QPainter *painter)
Renders the current part of the map to the specified painter.
void cancelWithoutBlocking() override
Triggers cancellation of the rendering job without blocking.
The QgsMapSettings class contains configuration for rendering of the map.
bool testFlag(Qgis::MapSettingsFlag flag) const
Check whether a particular flag is enabled.
A QgsLabelingEngine implementation, which only calculates the labeling solution during its run() meth...
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39