QGIS API Documentation  3.21.0-Master (5b68dc587e)
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 #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  job.renderer->renderContext()->setPainter( painter );
107 
108  if ( job.context()->useAdvancedEffects() )
109  {
110  // Set the QPainter composition mode so that this layer is rendered using
111  // the desired blending mode
112  painter->setCompositionMode( job.blendMode );
113  }
114 
115  if ( job.img )
116  {
117  job.img->fill( 0 );
118  job.imageInitialized = true;
119  }
120 
121  job.completed = job.renderer->render();
122 
123  if ( job.img )
124  {
125  // If we flattened this layer for alternate blend modes, composite it now
126  painter->setOpacity( job.opacity );
127  painter->drawImage( 0, 0, *job.img );
128  painter->setOpacity( 1.0 );
129  }
130  job.context()->setPainter( nullptr );
131  }
132  else
133  {
134  if ( !mLabelingEngineV2 )
135  return false;
136 
137  if ( mFlags & RenderLabelsByMapLayer )
138  {
139  if ( !mPreparedStagedLabelJob || mLabelLayerIt == mLabelingLayers.end() )
140  return false;
141 
142  mLabelJob.context.setPainter( painter );
143 
144  // Reset the composition mode before rendering the labels
145  painter->setCompositionMode( QPainter::CompositionMode_SourceOver );
146 
147  // render just the current layer's labels
148  static_cast< QgsStagedRenderLabelingEngine * >( mLabelingEngineV2.get() )->renderLabelsForLayer( mLabelJob.context, *mLabelLayerIt );
149 
150  mLabelJob.context.setPainter( nullptr );
151  }
152  else
153  {
154  mLabelJob.context.setPainter( painter );
155  drawLabeling( mLabelJob.context, mLabelingEngineV2.get(), painter );
156  mLabelJob.complete = true;
157  mLabelJob.participatingLayers = _qgis_listRawToQPointer( mLabelingEngineV2->participatingLayers() );
158  mLabelJob.context.setPainter( nullptr );
159  }
160  }
161  return true;
162 }
163 
165 {
166  if ( isFinished() )
167  return false;
168 
169  if ( mJobIt != mLayerJobs.end() )
170  {
171  ++mJobIt;
172  if ( mJobIt != mLayerJobs.end() )
173  return true;
174  }
175 
176  if ( mLabelingEngineV2 )
177  {
178  if ( mFlags & RenderLabelsByMapLayer )
179  {
180  if ( !mPreparedStagedLabelJob )
181  {
182  mLabelingEngineV2->run( mLabelJob.context );
183  mPreparedStagedLabelJob = true;
184  mLabelingLayers = mLabelingEngineV2->participatingLayerIds();
185  mLabelLayerIt = mLabelingLayers.begin();
186  if ( mLabelLayerIt == mLabelingLayers.end() )
187  {
188  // no label layers to render!
189  static_cast< QgsStagedRenderLabelingEngine * >( mLabelingEngineV2.get() )->finalize();
190  return false;
191  }
192  return true;
193  }
194  else
195  {
196  if ( mLabelLayerIt != mLabelingLayers.end() )
197  {
198  ++mLabelLayerIt;
199  if ( mLabelLayerIt != mLabelingLayers.end() )
200  return true;
201  }
202  }
203  return false;
204  }
205  else
206  {
207  if ( mNextIsLabel )
208  {
209  mExportedLabels = true;
210  }
211  else if ( !mExportedLabels )
212  {
213  mNextIsLabel = true;
214  return true;
215  }
216  }
217  }
218  return false;
219 }
220 
222 {
223  return currentStage() == Finished;
224 }
225 
227 {
228  if ( mJobIt != mLayerJobs.end() )
229  {
230  const LayerRenderJob &job = *mJobIt;
231  return job.layerId;
232  }
233  else if ( mFlags & RenderLabelsByMapLayer && mPreparedStagedLabelJob )
234  {
235  if ( mLabelLayerIt != mLabelingLayers.end() )
236  return *mLabelLayerIt;
237  }
238  return QString();
239 }
240 
242 {
243  if ( mJobIt != mLayerJobs.end() )
244  {
245  const LayerRenderJob &job = *mJobIt;
246  return job.opacity;
247  }
248  return 1.0;
249 }
250 
252 {
253  if ( mJobIt != mLayerJobs.end() )
254  {
255  const LayerRenderJob &job = *mJobIt;
256  return job.blendMode;
257  }
258  return QPainter::CompositionMode_SourceOver;
259 }
260 
262 {
263  if ( mJobIt != mLayerJobs.end() )
264  return Symbology;
265  else if ( mLabelingEngineV2 && mFlags & RenderLabelsByMapLayer )
266  {
267  if ( !mPreparedStagedLabelJob )
268  return Labels;
269  if ( mLabelLayerIt != mLabelingLayers.end() )
270  return Labels;
271  }
272  else if ( mNextIsLabel && !mExportedLabels )
273  return Labels;
274 
275  return Finished;
276 }
@ 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)
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
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