QGIS API Documentation  2.99.0-Master (8ec3eaf)
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 "qgslabelingengine.h"
20 #include "qgslogger.h"
21 #include "qgsmaplayerrenderer.h"
22 #include "qgspallabeling.h"
23 
24 #include <QtConcurrentMap>
25 
26 
28  : QgsMapRendererQImageJob( settings )
29  , mStatus( Idle )
30  , mLabelingEngineV2( nullptr )
31 {
32 }
33 
35 {
36  if ( isActive() )
37  {
38  cancel();
39  }
40 
41  delete mLabelingEngineV2;
42  mLabelingEngineV2 = nullptr;
43 }
44 
46 {
47  if ( isActive() )
48  return;
49 
50  mRenderingStart.start();
51 
53 
54  delete mLabelingEngineV2;
55  mLabelingEngineV2 = nullptr;
56 
58  {
62  }
63 
65 
66  QgsDebugMsg( QString( "QThreadPool max thread count is %1" ).arg( QThreadPool::globalInstance()->maxThreadCount() ) );
67 
68  // start async job
69 
70  connect( &mFutureWatcher, SIGNAL( finished() ), SLOT( renderLayersFinished() ) );
71 
72  mFuture = QtConcurrent::map( mLayerJobs, renderLayerStatic );
73  mFutureWatcher.setFuture( mFuture );
74 }
75 
77 {
78  if ( !isActive() )
79  return;
80 
81  QgsDebugMsg( QString( "PARALLEL cancel at status %1" ).arg( mStatus ) );
82 
84  for ( LayerRenderJobs::iterator it = mLayerJobs.begin(); it != mLayerJobs.end(); ++it )
85  {
86  it->context.setRenderingStopped( true );
87  if ( it->renderer && it->renderer->feedback() )
88  it->renderer->feedback()->cancel();
89  }
90 
91  if ( mStatus == RenderingLayers )
92  {
93  disconnect( &mFutureWatcher, SIGNAL( finished() ), this, SLOT( renderLayersFinished() ) );
94 
95  mFutureWatcher.waitForFinished();
96 
98  }
99 
100  if ( mStatus == RenderingLabels )
101  {
102  disconnect( &mLabelingFutureWatcher, SIGNAL( finished() ), this, SLOT( renderingFinished() ) );
103 
104  mLabelingFutureWatcher.waitForFinished();
105 
107  }
108 
109  Q_ASSERT( mStatus == Idle );
110 }
111 
113 {
114  if ( !isActive() )
115  return;
116 
117  if ( mStatus == RenderingLayers )
118  {
119  disconnect( &mFutureWatcher, SIGNAL( finished() ), this, SLOT( renderLayersFinished() ) );
120 
121  QTime t;
122  t.start();
123 
124  mFutureWatcher.waitForFinished();
125 
126  QgsDebugMsg( QString( "waitForFinished (1): %1 ms" ).arg( t.elapsed() / 1000.0 ) );
127 
129  }
130 
131  if ( mStatus == RenderingLabels )
132  {
133  disconnect( &mLabelingFutureWatcher, SIGNAL( finished() ), this, SLOT( renderingFinished() ) );
134 
135  QTime t;
136  t.start();
137 
138  mLabelingFutureWatcher.waitForFinished();
139 
140  QgsDebugMsg( QString( "waitForFinished (2): %1 ms" ).arg( t.elapsed() / 1000.0 ) );
141 
143  }
144 
145  Q_ASSERT( mStatus == Idle );
146 }
147 
149 {
150  return mStatus != Idle;
151 }
152 
154 {
155  if ( mLabelingEngineV2 )
156  return mLabelingEngineV2->takeResults();
157  else
158  return nullptr;
159 }
160 
162 {
163  if ( mStatus == RenderingLayers )
164  return composeImage( mSettings, mLayerJobs );
165  else
166  return mFinalImage; // when rendering labels or idle
167 }
168 
170 {
171  Q_ASSERT( mStatus == RenderingLayers );
172 
173  // compose final image
175 
177 
179 
180  QgsDebugMsg( "PARALLEL layers finished" );
181 
183  {
185 
186  connect( &mLabelingFutureWatcher, SIGNAL( finished() ), this, SLOT( renderingFinished() ) );
187 
188  // now start rendering of labeling!
189  mLabelingFuture = QtConcurrent::run( renderLabelsStatic, this );
192  }
193  else
194  {
196  }
197 }
198 
200 {
201  QgsDebugMsg( "PARALLEL finished" );
202 
203  mStatus = Idle;
204 
205  mRenderingTime = mRenderingStart.elapsed();
206 
207  emit finished();
208 }
209 
211 {
212  if ( job.context.renderingStopped() )
213  return;
214 
215  if ( job.cached )
216  return;
217 
218  if ( job.img )
219  job.img->fill( 0 );
220 
221  QTime t;
222  t.start();
223  QgsDebugMsgLevel( QString( "job %1 start (layer %2)" ).arg( reinterpret_cast< ulong >( &job ), 0, 16 ).arg( job.layerId ), 2 );
224 
225  try
226  {
227  job.renderer->render();
228  }
229  catch ( QgsException & e )
230  {
231  Q_UNUSED( e );
232  QgsDebugMsg( "Caught unhandled QgsException: " + e.what() );
233  }
234  catch ( std::exception & e )
235  {
236  Q_UNUSED( e );
237  QgsDebugMsg( "Caught unhandled std::exception: " + QString::fromAscii( e.what() ) );
238  }
239  catch ( ... )
240  {
241  QgsDebugMsg( "Caught unhandled unknown exception" );
242  }
243 
244  job.renderingTime = t.elapsed();
245  QgsDebugMsgLevel( QString( "job %1 end [%2 ms] (layer %3)" ).arg( reinterpret_cast< ulong >( &job ), 0, 16 ).arg( job.renderingTime ).arg( job.layerId ), 2 );
246 }
247 
248 
250 {
251  QPainter painter( &self->mFinalImage );
252 
253  try
254  {
255  drawLabeling( self->mSettings, self->mLabelingRenderContext, self->mLabelingEngineV2, &painter );
256  }
257  catch ( QgsException & e )
258  {
259  Q_UNUSED( e );
260  QgsDebugMsg( "Caught unhandled QgsException: " + e.what() );
261  }
262  catch ( std::exception & e )
263  {
264  Q_UNUSED( e );
265  QgsDebugMsg( "Caught unhandled std::exception: " + QString::fromAscii( e.what() ) );
266  }
267  catch ( ... )
268  {
269  QgsDebugMsg( "Caught unhandled unknown exception" );
270  }
271 
272  painter.end();
273 }
274 
void finished()
emitted when asynchronous rendering is finished (or canceled).
void setRenderingStopped(bool stopped)
void renderingFinished()
all rendering is finished, including labeling
virtual void waitForFinished() override
Block until the job has finished.
void cleanupJobs(LayerRenderJobs &jobs)
static QImage composeImage(const QgsMapSettings &settings, const LayerRenderJobs &jobs)
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
void logRenderingTime(const LayerRenderJobs &jobs)
static void drawLabeling(const QgsMapSettings &settings, QgsRenderContext &renderContext, QgsLabelingEngine *labelingEngine2, QPainter *painter)
bool renderingStopped() const
void setMapSettings(const QgsMapSettings &mapSettings)
Associate map settings instance.
void renderingLayersFinished()
Emitted when the layers are rendered.
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.
QgsMapRendererParallelJob(const QgsMapSettings &settings)
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:34
Job implementation that renders all layers in parallel.
static void renderLabelsStatic(QgsMapRendererParallelJob *self)
void renderLayersFinished()
layers are rendered, labeling is still pending
QgsMapSettings mSettings
The QgsLabelingEngine class provides map labeling functionality.
enum QgsMapRendererParallelJob::@0 mStatus
LayerRenderJobs prepareJobs(QPainter *painter, QgsLabelingEngine *labelingEngine2)
virtual bool render()=0
Do the rendering (based on data stored in the class)
int renderingTime
Time it took to render the layer in ms (it is -1 if not rendered or still rendering) ...
QgsLabelingResults * takeResults()
Return pointer to recently computed results and pass the ownership of results to the caller...
QgsLabelingEngine * mLabelingEngineV2
New labeling engine.
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
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)
void readSettingsFromProject()
Read configuration of the labeling engine from the current project file.
Defines a qgis exception class.
Definition: qgsexception.h:25
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)