QGIS API Documentation  3.20.0-Odense (decaadbb31)
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"
23 #include "qgsmaplayerlistutils.h"
24 
27  , mFlags( flags )
28 {
29 }
30 
32 {
33  // final cleanup
34  cleanupJobs( mLayerJobs );
35  cleanupLabelJob( mLabelJob );
36 }
37 
38 
39 void QgsMapRendererStagedRenderJob::startPrivate()
40 {
41  mRenderingStart.start();
42  mErrors.clear();
43 
44  QgsDebugMsgLevel( QStringLiteral( "Preparing list of layer jobs for rendering" ), 5 );
45  QElapsedTimer prepareTime;
46  prepareTime.start();
47 
48  mLabelingEngineV2.reset();
49 
51  {
52  if ( mFlags & RenderLabelsByMapLayer )
53  mLabelingEngineV2.reset( new QgsStagedRenderLabelingEngine() );
54  else
55  mLabelingEngineV2.reset( new QgsDefaultLabelingEngine() );
56  mLabelingEngineV2->setMapSettings( mSettings );
57  }
58 
59  mLayerJobs = prepareJobs( nullptr, mLabelingEngineV2.get(), true );
60  mLabelJob = prepareLabelingJob( nullptr, mLabelingEngineV2.get(), false );
61 
62  mJobIt = mLayerJobs.begin();
63 }
64 
66 {
67 }
68 
70 {
71 }
72 
74 {
75 }
76 
78 {
79  return true;
80 }
81 
83 {
84  return false;
85 }
86 
88 {
89  if ( mLabelingEngineV2 )
90  return mLabelingEngineV2->takeResults();
91  else
92  return nullptr;
93 }
94 
96 {
97  if ( isFinished() )
98  return false;
99 
100  preparePainter( painter );
101 
102  if ( mJobIt != mLayerJobs.end() )
103  {
104  LayerRenderJob &job = *mJobIt;
105  job.renderer->renderContext()->setPainter( painter );
106 
107  if ( job.context.useAdvancedEffects() )
108  {
109  // Set the QPainter composition mode so that this layer is rendered using
110  // the desired blending mode
111  painter->setCompositionMode( job.blendMode );
112  }
113 
114  if ( job.img )
115  {
116  job.img->fill( 0 );
117  job.imageInitialized = true;
118  }
119 
120  job.completed = job.renderer->render();
121 
122  if ( job.img )
123  {
124  // If we flattened this layer for alternate blend modes, composite it now
125  painter->setOpacity( job.opacity );
126  painter->drawImage( 0, 0, *job.img );
127  painter->setOpacity( 1.0 );
128  }
129  job.context.setPainter( nullptr );
130  }
131  else
132  {
133  if ( !mLabelingEngineV2 )
134  return false;
135 
136  if ( mFlags & RenderLabelsByMapLayer )
137  {
138  if ( !mPreparedStagedLabelJob || mLabelLayerIt == mLabelingLayers.end() )
139  return false;
140 
141  mLabelJob.context.setPainter( painter );
142 
143  // Reset the composition mode before rendering the labels
144  painter->setCompositionMode( QPainter::CompositionMode_SourceOver );
145 
146  // render just the current layer's labels
147  static_cast< QgsStagedRenderLabelingEngine * >( mLabelingEngineV2.get() )->renderLabelsForLayer( mLabelJob.context, *mLabelLayerIt );
148 
149  mLabelJob.context.setPainter( nullptr );
150  }
151  else
152  {
153  mLabelJob.context.setPainter( painter );
154  drawLabeling( mLabelJob.context, mLabelingEngineV2.get(), painter );
155  mLabelJob.complete = true;
156  mLabelJob.participatingLayers = _qgis_listRawToQPointer( mLabelingEngineV2->participatingLayers() );
157  mLabelJob.context.setPainter( nullptr );
158  }
159  }
160  return true;
161 }
162 
164 {
165  if ( isFinished() )
166  return false;
167 
168  if ( mJobIt != mLayerJobs.end() )
169  {
170  ++mJobIt;
171  if ( mJobIt != mLayerJobs.end() )
172  return true;
173  }
174 
175  if ( mLabelingEngineV2 )
176  {
177  if ( mFlags & RenderLabelsByMapLayer )
178  {
179  if ( !mPreparedStagedLabelJob )
180  {
181  mLabelingEngineV2->run( mLabelJob.context );
182  mPreparedStagedLabelJob = true;
183  mLabelingLayers = mLabelingEngineV2->participatingLayerIds();
184  mLabelLayerIt = mLabelingLayers.begin();
185  if ( mLabelLayerIt == mLabelingLayers.end() )
186  {
187  // no label layers to render!
188  static_cast< QgsStagedRenderLabelingEngine * >( mLabelingEngineV2.get() )->finalize();
189  return false;
190  }
191  return true;
192  }
193  else
194  {
195  if ( mLabelLayerIt != mLabelingLayers.end() )
196  {
197  ++mLabelLayerIt;
198  if ( mLabelLayerIt != mLabelingLayers.end() )
199  return true;
200  }
201  }
202  return false;
203  }
204  else
205  {
206  if ( mNextIsLabel )
207  {
208  mExportedLabels = true;
209  }
210  else if ( !mExportedLabels )
211  {
212  mNextIsLabel = true;
213  return true;
214  }
215  }
216  }
217  return false;
218 }
219 
221 {
222  return currentStage() == Finished;
223 }
224 
226 {
227  if ( mJobIt != mLayerJobs.end() )
228  {
229  LayerRenderJob &job = *mJobIt;
230  return job.layerId;
231  }
232  else if ( mFlags & RenderLabelsByMapLayer && mPreparedStagedLabelJob )
233  {
234  if ( mLabelLayerIt != mLabelingLayers.end() )
235  return *mLabelLayerIt;
236  }
237  return QString();
238 }
239 
241 {
242  if ( mJobIt != mLayerJobs.end() )
243  {
244  LayerRenderJob &job = *mJobIt;
245  return job.opacity;
246  }
247  return 1.0;
248 }
249 
251 {
252  if ( mJobIt != mLayerJobs.end() )
253  {
254  LayerRenderJob &job = *mJobIt;
255  return job.blendMode;
256  }
257  return QPainter::CompositionMode_SourceOver;
258 }
259 
261 {
262  if ( mJobIt != mLayerJobs.end() )
263  return Symbology;
264  else if ( mLabelingEngineV2 && mFlags & RenderLabelsByMapLayer )
265  {
266  if ( !mPreparedStagedLabelJob )
267  return Labels;
268  if ( mLabelLayerIt != mLabelingLayers.end() )
269  return Labels;
270  }
271  else if ( mNextIsLabel && !mExportedLabels )
272  return Labels;
273 
274  return Finished;
275 }
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)
LayerRenderJobs prepareJobs(QPainter *painter, QgsLabelingEngine *labelingEngine2, bool deferredPainterSet=false)
Creates a list of layer rendering jobs and prepares them for later render.
QElapsedTimer mRenderingStart
QgsMapSettings mSettings
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...
void cleanupJobs(LayerRenderJobs &jobs)
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(Flag flag) const
Check whether a particular flag is enabled.
@ DrawLabeling
Enable drawing of labels on top of the map.
A QgsLabelingEngine implementation, which only calculates the labeling solution during its run() meth...
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39