QGIS API Documentation  3.27.0-Master (aef1b1ec20)
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_p.h"
24 #include "qgsrendereditemresults.h"
25 
28  , mFlags( flags )
29 {
30 }
31 
33 {
34  // final cleanup
35  cleanupJobs( mLayerJobs );
36  cleanupLabelJob( mLabelJob );
37 }
38 
39 
40 void 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.img )
117  {
118  job.img->fill( 0 );
119  job.imageInitialized = true;
120  }
121 
122  job.completed = job.renderer->render();
123 
124  if ( job.img )
125  {
126  // If we flattened this layer for alternate blend modes, composite it now
127  painter->setOpacity( job.opacity );
128  painter->drawImage( 0, 0, *job.img );
129  painter->setOpacity( 1.0 );
130  }
131  job.context()->setPainter( nullptr );
132 
133  emit layerRendered( job.layerId );
134  }
135  else
136  {
137  if ( !mLabelingEngineV2 )
138  return false;
139 
140  if ( mFlags & RenderLabelsByMapLayer )
141  {
142  if ( !mPreparedStagedLabelJob || mLabelLayerIt == mLabelingLayers.end() )
143  return false;
144 
145  mLabelJob.context.setPainter( painter );
146 
147  // Reset the composition mode before rendering the labels
148  painter->setCompositionMode( QPainter::CompositionMode_SourceOver );
149 
150  // render just the current layer's labels
151  static_cast< QgsStagedRenderLabelingEngine * >( mLabelingEngineV2.get() )->renderLabelsForLayer( mLabelJob.context, *mLabelLayerIt );
152 
153  mLabelJob.context.setPainter( nullptr );
154  }
155  else
156  {
157  mLabelJob.context.setPainter( painter );
158  drawLabeling( mLabelJob.context, mLabelingEngineV2.get(), painter );
159  mLabelJob.complete = true;
160  mLabelJob.participatingLayers = _qgis_listRawToQPointer( mLabelingEngineV2->participatingLayers() );
161  mLabelJob.context.setPainter( nullptr );
162  }
163  }
164  return true;
165 }
166 
168 {
169  if ( isFinished() )
170  return false;
171 
172  if ( mJobIt != mLayerJobs.end() )
173  {
174  ++mJobIt;
175  if ( mJobIt != mLayerJobs.end() )
176  return true;
177  }
178 
179  if ( mLabelingEngineV2 )
180  {
181  if ( mFlags & RenderLabelsByMapLayer )
182  {
183  if ( !mPreparedStagedLabelJob )
184  {
185  mLabelingEngineV2->run( mLabelJob.context );
186  mPreparedStagedLabelJob = true;
187  mLabelingLayers = mLabelingEngineV2->participatingLayerIds();
188  mLabelLayerIt = mLabelingLayers.begin();
189  if ( mLabelLayerIt == mLabelingLayers.end() )
190  {
191  // no label layers to render!
192  static_cast< QgsStagedRenderLabelingEngine * >( mLabelingEngineV2.get() )->finalize();
193  return false;
194  }
195  return true;
196  }
197  else
198  {
199  if ( mLabelLayerIt != mLabelingLayers.end() )
200  {
201  ++mLabelLayerIt;
202  if ( mLabelLayerIt != mLabelingLayers.end() )
203  return true;
204  }
205  }
206  return false;
207  }
208  else
209  {
210  if ( mNextIsLabel )
211  {
212  mExportedLabels = true;
213  }
214  else if ( !mExportedLabels )
215  {
216  mNextIsLabel = true;
217  return true;
218  }
219  }
220  }
221  return false;
222 }
223 
225 {
226  return currentStage() == Finished;
227 }
228 
230 {
231  if ( mJobIt != mLayerJobs.end() )
232  {
233  const LayerRenderJob &job = *mJobIt;
234  return job.layerId;
235  }
236  else if ( mFlags & RenderLabelsByMapLayer && mPreparedStagedLabelJob )
237  {
238  if ( mLabelLayerIt != mLabelingLayers.end() )
239  return *mLabelLayerIt;
240  }
241  return QString();
242 }
243 
245 {
246  if ( mJobIt != mLayerJobs.end() )
247  {
248  const LayerRenderJob &job = *mJobIt;
249  return job.opacity;
250  }
251  return 1.0;
252 }
253 
255 {
256  if ( mJobIt != mLayerJobs.end() )
257  {
258  const LayerRenderJob &job = *mJobIt;
259  return job.blendMode;
260  }
261  return QPainter::CompositionMode_SourceOver;
262 }
263 
265 {
266  if ( mJobIt != mLayerJobs.end() )
267  return Symbology;
268  else if ( mLabelingEngineV2 && mFlags & RenderLabelsByMapLayer )
269  {
270  if ( !mPreparedStagedLabelJob )
271  return Labels;
272  if ( mLabelLayerIt != mLabelingLayers.end() )
273  return Labels;
274  }
275  else if ( mNextIsLabel && !mExportedLabels )
276  return Labels;
277 
278  return Finished;
279 }
@ 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