QGIS API Documentation  2.4.0-Chugiak
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
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 "qgslogger.h"
19 #include "qgsmaplayerrenderer.h"
20 #include "qgspallabeling.h"
21 
22 
24  : QgsMapRendererQImageJob( settings )
25  , mStatus( Idle )
26  , mLabelingEngine( 0 )
27 {
28 }
29 
31 {
32  if ( isActive() )
33  {
34  cancel();
35  }
36 
37  delete mLabelingEngine;
38  mLabelingEngine = 0;
39 }
40 
42 {
43  if ( isActive() )
44  return;
45 
46  mRenderingStart.start();
47 
49 
50  delete mLabelingEngine;
51  mLabelingEngine = 0;
52 
54  {
58  }
59 
60 
62 
63  QgsDebugMsg( QString( "QThreadPool max thread count is %1" ).arg( QThreadPool::globalInstance()->maxThreadCount() ) );
64 
65  // start async job
66 
67  connect( &mFutureWatcher, SIGNAL( finished() ), SLOT( renderLayersFinished() ) );
68 
69  mFuture = QtConcurrent::map( mLayerJobs, renderLayerStatic );
70  mFutureWatcher.setFuture( mFuture );
71 }
72 
74 {
75  if ( !isActive() )
76  return;
77 
78  QgsDebugMsg( QString( "PARALLEL cancel at status %1" ).arg( mStatus ) );
79 
81  for ( LayerRenderJobs::iterator it = mLayerJobs.begin(); it != mLayerJobs.end(); ++it )
82  {
83  it->context.setRenderingStopped( true );
84  }
85 
86  if ( mStatus == RenderingLayers )
87  {
88  disconnect( &mFutureWatcher, SIGNAL( finished() ), this, SLOT( renderLayersFinished() ) );
89 
90  mFutureWatcher.waitForFinished();
91 
93  }
94 
95  if ( mStatus == RenderingLabels )
96  {
97  disconnect( &mLabelingFutureWatcher, SIGNAL( finished() ), this, SLOT( renderingFinished() ) );
98 
99  mLabelingFutureWatcher.waitForFinished();
100 
102  }
103 
104  Q_ASSERT( mStatus == Idle );
105 }
106 
108 {
109  if ( !isActive() )
110  return;
111 
112  if ( mStatus == RenderingLayers )
113  {
114  disconnect( &mFutureWatcher, SIGNAL( finished() ), this, SLOT( renderLayersFinished() ) );
115 
116  QTime t;
117  t.start();
118 
119  mFutureWatcher.waitForFinished();
120 
121  QgsDebugMsg( QString( "waitForFinished (1): %1 ms" ).arg( t.elapsed() / 1000.0 ) );
122 
124  }
125 
126  if ( mStatus == RenderingLabels )
127  {
128  disconnect( &mLabelingFutureWatcher, SIGNAL( finished() ), this, SLOT( renderingFinished() ) );
129 
130  QTime t;
131  t.start();
132 
133  mLabelingFutureWatcher.waitForFinished();
134 
135  QgsDebugMsg( QString( "waitForFinished (2): %1 ms" ).arg( t.elapsed() / 1000.0 ) );
136 
138  }
139 
140  Q_ASSERT( mStatus == Idle );
141 }
142 
144 {
145  return mStatus != Idle;
146 }
147 
149 {
151 }
152 
154 {
155  if ( mStatus == RenderingLayers )
156  return composeImage( mSettings, mLayerJobs );
157  else
158  return mFinalImage; // when rendering labels or idle
159 }
160 
162 {
163  Q_ASSERT( mStatus == RenderingLayers );
164 
165  // compose final image
167 
169 
170  QgsDebugMsg( "PARALLEL layers finished" );
171 
173  {
175 
176  connect( &mLabelingFutureWatcher, SIGNAL( finished() ), this, SLOT( renderingFinished() ) );
177 
178  // now start rendering of labeling!
179  mLabelingFuture = QtConcurrent::run( renderLabelsStatic, this );
181  }
182  else
183  {
185  }
186 }
187 
189 {
190  QgsDebugMsg( "PARALLEL finished" );
191 
192  mStatus = Idle;
193 
194  mRenderingTime = mRenderingStart.elapsed();
195 
196  emit finished();
197 }
198 
200 {
201  if ( job.context.renderingStopped() )
202  return;
203 
204  if ( job.cached )
205  return;
206 
207  QTime t;
208  t.start();
209  QgsDebugMsg( QString( "job %1 start" ).arg(( ulong ) &job, 0, 16 ) );
210 
211  try
212  {
213  job.renderer->render();
214  }
215  catch ( QgsException & e )
216  {
217  QgsDebugMsg( "Caught unhandled QgsException: " + e.what() );
218  }
219  catch ( std::exception & e )
220  {
221  QgsDebugMsg( "Caught unhandled std::exception: " + QString::fromAscii( e.what() ) );
222  }
223  catch ( ... )
224  {
225  QgsDebugMsg( "Caught unhandled unknown exception" );
226  }
227 
228  int tt = t.elapsed();
229  QgsDebugMsg( QString( "job %1 end [%2 ms]" ).arg(( ulong ) &job, 0, 16 ).arg( tt ) );
230  Q_UNUSED( tt );
231 }
232 
233 
235 {
236  QPainter painter( &self->mFinalImage );
237 
238  try
239  {
240  drawLabeling( self->mSettings, self->mLabelingRenderContext, self->mLabelingEngine, &painter );
241  }
242  catch ( QgsException & e )
243  {
244  QgsDebugMsg( "Caught unhandled QgsException: " + e.what() );
245  }
246  catch ( std::exception & e )
247  {
248  QgsDebugMsg( "Caught unhandled std::exception: " + QString::fromAscii( e.what() ) );
249  }
250  catch ( ... )
251  {
252  QgsDebugMsg( "Caught unhandled unknown exception" );
253  }
254 
255  painter.end();
256 }
257 
void finished()
emitted when asynchronous rendering is finished (or canceled).
void setRenderingStopped(bool stopped)
void renderingFinished()
all rendering is finished, including labeling
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:36
virtual Q_DECL_DEPRECATED void init(QgsMapRenderer *mr)
called when we're going to start with rendering
void loadEngineSettings()
load/save engine settings to project file
virtual QgsLabelingResults * takeLabelingResults()
Get pointer to internal labeling engine (in order to get access to the results)
LayerRenderJobs prepareJobs(QPainter *painter, QgsPalLabeling *labelingEngine)
Enable drawing of labels on top of the map.
QFutureWatcher< void > mFutureWatcher
The QgsMapSettings class contains configuration for rendering of the map.
QgsMapRendererParallelJob(const QgsMapSettings &settings)
virtual QImage renderedImage()
Get a preview/resulting image.
bool renderingStopped() const
virtual void waitForFinished()
Block until the job has finished.
Job implementation that renders all layers in parallel.
static void renderLabelsStatic(QgsMapRendererParallelJob *self)
void renderLayersFinished()
layers are rendered, labeling is still pending
QgsMapSettings mSettings
virtual bool isActive() const
Tell whether the rendering job is currently running in background.
virtual void cancel()
Stop the rendering job - does not return until the job has terminated.
bool testFlag(Flag flag) const
Check whether a particular flag is enabled.
enum QgsMapRendererParallelJob::@0 mStatus
QString what() const
Definition: qgsexception.h:35
Intermediate base class adding functionality that allows client to query the rendered image...
QFutureWatcher< void > mLabelingFutureWatcher
static void drawLabeling(const QgsMapSettings &settings, QgsRenderContext &renderContext, QgsPalLabeling *labelingEngine, QPainter *painter)
QgsRenderContext context
Class that stores computed placement from labeling engine.
static void renderLayerStatic(LayerRenderJob &job)
virtual void start()
Start the rendering job and immediately return.
Defines a qgis exception class.
Definition: qgsexception.h:25
Structure keeping low-level rendering job information.