QGIS API Documentation  2.18.21-Las Palmas (9fba24a)
qgsmaprendererparalleljob.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsmaprendererparalleljob.cpp
3  --------------------------------------
4  Date : December 2013
5  Copyright : (C) 2013 by Martin Dobias
6  Email : wonder dot sk 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 "qgslabelingenginev2.h"
20 #include "qgslogger.h"
21 #include "qgsmaplayerrenderer.h"
22 #include "qgspallabeling.h"
23 
24 #include <QtConcurrentMap>
25 
26 #define LABELING_V2
27 
29  : QgsMapRendererQImageJob( settings )
30  , mStatus( Idle )
31  , mLabelingEngine( nullptr )
32  , mLabelingEngineV2( nullptr )
33 {
34 }
35 
37 {
38  if ( isActive() )
39  {
40  cancel();
41  }
42 
43  delete mLabelingEngine;
44  mLabelingEngine = nullptr;
45 
46  delete mLabelingEngineV2;
47  mLabelingEngineV2 = nullptr;
48 }
49 
51 {
52  if ( isActive() )
53  return;
54 
56 
58 
59  delete mLabelingEngine;
60  mLabelingEngine = nullptr;
61 
62  delete mLabelingEngineV2;
63  mLabelingEngineV2 = nullptr;
64 
66  {
67 #ifdef LABELING_V2
71 #else
75 #endif
76  }
77 
79 
80  QgsDebugMsg( QString( "QThreadPool max thread count is %1" ).arg( QThreadPool::globalInstance()->maxThreadCount() ) );
81 
82  // start async job
83 
84  connect( &mFutureWatcher, SIGNAL( finished() ), SLOT( renderLayersFinished() ) );
85 
88 }
89 
91 {
92  if ( !isActive() )
93  return;
94 
95  QgsDebugMsg( QString( "PARALLEL cancel at status %1" ).arg( mStatus ) );
96 
98  for ( LayerRenderJobs::iterator it = mLayerJobs.begin(); it != mLayerJobs.end(); ++it )
99  {
100  it->context.setRenderingStopped( true );
101  if ( it->renderer && it->renderer->feedback() )
102  it->renderer->feedback()->cancel();
103  }
104 
105  if ( mStatus == RenderingLayers )
106  {
107  disconnect( &mFutureWatcher, SIGNAL( finished() ), this, SLOT( renderLayersFinished() ) );
108 
110 
112  }
113 
114  if ( mStatus == RenderingLabels )
115  {
116  disconnect( &mLabelingFutureWatcher, SIGNAL( finished() ), this, SLOT( renderingFinished() ) );
117 
119 
121  }
122 
123  Q_ASSERT( mStatus == Idle );
124 }
125 
127 {
128  if ( !isActive() )
129  return;
130 
131  QgsDebugMsg( QString( "PARALLEL cancel at status %1" ).arg( mStatus ) );
132 
134  for ( LayerRenderJobs::iterator it = mLayerJobs.begin(); it != mLayerJobs.end(); ++it )
135  {
136  it->context.setRenderingStopped( true );
137  if ( it->renderer && it->renderer->feedback() )
138  it->renderer->feedback()->cancel();
139  }
140 
141  if ( mStatus == RenderingLayers )
142  {
143  disconnect( &mFutureWatcher, SIGNAL( finished() ), this, SLOT( renderLayersFinished() ) );
144  connect( &mFutureWatcher, SIGNAL( finished() ), this, SLOT( renderLayersFinishedWhenJobCanceled() ) );
145  }
146 }
147 
149 {
150  if ( !isActive() )
151  return;
152 
153  if ( mStatus == RenderingLayers )
154  {
155  disconnect( &mFutureWatcher, SIGNAL( finished() ), this, SLOT( renderLayersFinished() ) );
156 
157  QTime t;
158  t.start();
159 
161 
162  QgsDebugMsg( QString( "waitForFinished (1): %1 ms" ).arg( t.elapsed() / 1000.0 ) );
163 
165  }
166 
167  if ( mStatus == RenderingLabels )
168  {
169  disconnect( &mLabelingFutureWatcher, SIGNAL( finished() ), this, SLOT( renderingFinished() ) );
170 
171  QTime t;
172  t.start();
173 
175 
176  QgsDebugMsg( QString( "waitForFinished (2): %1 ms" ).arg( t.elapsed() / 1000.0 ) );
177 
179  }
180 
181  Q_ASSERT( mStatus == Idle );
182 }
183 
185 {
186  return mStatus != Idle;
187 }
188 
190 {
191  if ( mLabelingEngine )
192  return mLabelingEngine->takeResults();
193  else if ( mLabelingEngineV2 )
194  return mLabelingEngineV2->takeResults();
195  else
196  return nullptr;
197 }
198 
200 {
201  if ( mStatus == RenderingLayers )
202  return composeImage( mSettings, mLayerJobs );
203  else
204  return mFinalImage; // when rendering labels or idle
205 }
206 
208 {
209  Q_ASSERT( mStatus == RenderingLayers );
210 
211  // compose final image
213 
215 
217 
218  QgsDebugMsg( "PARALLEL layers finished" );
219 
221  {
223 
224  connect( &mLabelingFutureWatcher, SIGNAL( finished() ), this, SLOT( renderingFinished() ) );
225 
226  // now start rendering of labeling!
229  }
230  else
231  {
233  }
234 }
235 
237 {
238  QgsDebugMsg( "PARALLEL finished" );
239 
240  mStatus = Idle;
241 
243 
244  emit finished();
245 }
246 
248 {
249  if ( job.context.renderingStopped() )
250  return;
251 
252  if ( job.cached )
253  return;
254 
255  QTime t;
256  t.start();
257  QgsDebugMsg( QString( "job %1 start (layer %2)" ).arg( reinterpret_cast< ulong >( &job ), 0, 16 ).arg( job.layerId ) );
258 
259  try
260  {
261  job.renderer->render();
262  }
263  catch ( QgsException & e )
264  {
265  Q_UNUSED( e );
266  QgsDebugMsg( "Caught unhandled QgsException: " + e.what() );
267  }
268  catch ( std::exception & e )
269  {
270  Q_UNUSED( e );
271  QgsDebugMsg( "Caught unhandled std::exception: " + QString::fromAscii( e.what() ) );
272  }
273  catch ( ... )
274  {
275  QgsDebugMsg( "Caught unhandled unknown exception" );
276  }
277 
278  job.renderingTime = t.elapsed();
279  QgsDebugMsg( QString( "job %1 end [%2 ms] (layer %3)" ).arg( reinterpret_cast< ulong >( &job ), 0, 16 ).arg( job.renderingTime ).arg( job.layerId ) );
280 }
281 
282 
284 {
285  QPainter painter( &self->mFinalImage );
286 
287  try
288  {
289  drawLabeling( self->mSettings, self->mLabelingRenderContext, self->mLabelingEngine, self->mLabelingEngineV2, &painter );
290  }
291  catch ( QgsException & e )
292  {
293  Q_UNUSED( e );
294  QgsDebugMsg( "Caught unhandled QgsException: " + e.what() );
295  }
296  catch ( std::exception & e )
297  {
298  Q_UNUSED( e );
299  QgsDebugMsg( "Caught unhandled std::exception: " + QString::fromAscii( e.what() ) );
300  }
301  catch ( ... )
302  {
303  QgsDebugMsg( "Caught unhandled unknown exception" );
304  }
305 
306  painter.end();
307 }
308 
309 void QgsMapRendererParallelJob::renderLayersFinishedWhenJobCanceled()
310 {
312 
315 }
316 
QString fromAscii(const char *str, int size)
void finished()
emitted when asynchronous rendering is finished (or canceled).
void setRenderingStopped(bool stopped)
void renderingFinished()
all rendering is finished, including labeling
bool end()
virtual void waitForFinished() override
Block until the job has finished.
void cleanupJobs(LayerRenderJobs &jobs)
QgsLabelingResults * takeResults()
Return pointer to recently computed results (in drawLabeling()) and pass the ownership of results to ...
static QImage composeImage(const QgsMapSettings &settings, const LayerRenderJobs &jobs)
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
void loadEngineSettings()
load/save engine settings to project file
void logRenderingTime(const LayerRenderJobs &jobs)
QThreadPool * globalInstance()
bool renderingStopped() const
The QgsLabelingEngineV2 class provides map labeling functionality.
void readSettingsFromProject()
Read configuration of the labeling engine from the current project file.
bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method)
QgsPalLabeling * mLabelingEngine
Old labeling engine.
virtual void cancel() override
Stop the rendering job - does not return until the job has terminated.
Enable drawing of labels on top of the map.
QFutureWatcher< void > mFutureWatcher
QString what() const
Definition: qgsexception.h:36
The QgsMapSettings class contains configuration for rendering of the map.
virtual Q_DECL_DEPRECATED void init(QgsMapRenderer *mr) override
called when we&#39;re going to start with rendering
QgsMapRendererParallelJob(const QgsMapSettings &settings)
int elapsed() const
Job implementation that renders all layers in parallel.
static void renderLabelsStatic(QgsMapRendererParallelJob *self)
QFuture< T > run(Function function,...)
QFuture< void > map(Sequence &sequence, MapFunction function)
void renderLayersFinished()
layers are rendered, labeling is still pending
void setFuture(const QFuture< T > &future)
QgsMapSettings mSettings
iterator end()
void setMapSettings(const QgsMapSettings &mapSettings)
Associate map settings instance.
void waitForFinished()
QgsLabelingEngineV2 * mLabelingEngineV2
New labeling engine.
enum QgsMapRendererParallelJob::@0 mStatus
static void drawLabeling(const QgsMapSettings &settings, QgsRenderContext &renderContext, QgsPalLabeling *labelingEngine, QgsLabelingEngineV2 *labelingEngine2, QPainter *painter)
virtual bool render()=0
Do the rendering (based on data stored in the class)
LayerRenderJobs prepareJobs(QPainter *painter, QgsPalLabeling *labelingEngine, QgsLabelingEngineV2 *labelingEngine2)
int renderingTime
time it took to render the layer in ms (it is -1 if not rendered or still rendering) ...
virtual void cancelWithoutBlocking() override
Triggers cancellation of the rendering job without blocking.
Intermediate base class adding functionality that allows client to query the rendered image...
virtual void start() override
Start the rendering job and immediately return.
QFutureWatcher< void > mLabelingFutureWatcher
QgsMapLayerRenderer * renderer
QgsRenderContext context
void start()
Class that stores computed placement from labeling engine.
bool testFlag(Flag flag) const
Check whether a particular flag is enabled.
static void renderLayerStatic(LayerRenderJob &job)
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
Defines a qgis exception class.
Definition: qgsexception.h:25
QgsLabelingResults * takeResults()
Return pointer to recently computed results and pass the ownership of results to the caller...
iterator begin()
Structure keeping low-level rendering job information.
virtual bool isActive() const override
Tell whether the rendering job is currently running in background.
virtual QImage renderedImage() override
Get a preview/resulting image.
virtual QgsLabelingResults * takeLabelingResults() override
Get pointer to internal labeling engine (in order to get access to the results)