QGIS API Documentation  2.7.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules 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 #include <QtConcurrentMap>
23 
24 
26  : QgsMapRendererQImageJob( settings )
27  , mStatus( Idle )
28  , mLabelingEngine( 0 )
29 {
30 }
31 
33 {
34  if ( isActive() )
35  {
36  cancel();
37  }
38 
39  delete mLabelingEngine;
40  mLabelingEngine = 0;
41 }
42 
44 {
45  if ( isActive() )
46  return;
47 
48  mRenderingStart.start();
49 
51 
52  delete mLabelingEngine;
53  mLabelingEngine = 0;
54 
56  {
60  }
61 
62 
64 
65  QgsDebugMsg( QString( "QThreadPool max thread count is %1" ).arg( QThreadPool::globalInstance()->maxThreadCount() ) );
66 
67  // start async job
68 
69  connect( &mFutureWatcher, SIGNAL( finished() ), SLOT( renderLayersFinished() ) );
70 
71  mFuture = QtConcurrent::map( mLayerJobs, renderLayerStatic );
72  mFutureWatcher.setFuture( mFuture );
73 }
74 
76 {
77  if ( !isActive() )
78  return;
79 
80  QgsDebugMsg( QString( "PARALLEL cancel at status %1" ).arg( mStatus ) );
81 
83  for ( LayerRenderJobs::iterator it = mLayerJobs.begin(); it != mLayerJobs.end(); ++it )
84  {
85  it->context.setRenderingStopped( true );
86  }
87 
88  if ( mStatus == RenderingLayers )
89  {
90  disconnect( &mFutureWatcher, SIGNAL( finished() ), this, SLOT( renderLayersFinished() ) );
91 
92  mFutureWatcher.waitForFinished();
93 
95  }
96 
97  if ( mStatus == RenderingLabels )
98  {
99  disconnect( &mLabelingFutureWatcher, SIGNAL( finished() ), this, SLOT( renderingFinished() ) );
100 
101  mLabelingFutureWatcher.waitForFinished();
102 
104  }
105 
106  Q_ASSERT( mStatus == Idle );
107 }
108 
110 {
111  if ( !isActive() )
112  return;
113 
114  if ( mStatus == RenderingLayers )
115  {
116  disconnect( &mFutureWatcher, SIGNAL( finished() ), this, SLOT( renderLayersFinished() ) );
117 
118  QTime t;
119  t.start();
120 
121  mFutureWatcher.waitForFinished();
122 
123  QgsDebugMsg( QString( "waitForFinished (1): %1 ms" ).arg( t.elapsed() / 1000.0 ) );
124 
126  }
127 
128  if ( mStatus == RenderingLabels )
129  {
130  disconnect( &mLabelingFutureWatcher, SIGNAL( finished() ), this, SLOT( renderingFinished() ) );
131 
132  QTime t;
133  t.start();
134 
135  mLabelingFutureWatcher.waitForFinished();
136 
137  QgsDebugMsg( QString( "waitForFinished (2): %1 ms" ).arg( t.elapsed() / 1000.0 ) );
138 
140  }
141 
142  Q_ASSERT( mStatus == Idle );
143 }
144 
146 {
147  return mStatus != Idle;
148 }
149 
151 {
153 }
154 
156 {
157  if ( mStatus == RenderingLayers )
158  return composeImage( mSettings, mLayerJobs );
159  else
160  return mFinalImage; // when rendering labels or idle
161 }
162 
164 {
165  Q_ASSERT( mStatus == RenderingLayers );
166 
167  // compose final image
169 
171 
172  QgsDebugMsg( "PARALLEL layers finished" );
173 
175  {
177 
178  connect( &mLabelingFutureWatcher, SIGNAL( finished() ), this, SLOT( renderingFinished() ) );
179 
180  // now start rendering of labeling!
181  mLabelingFuture = QtConcurrent::run( renderLabelsStatic, this );
183  }
184  else
185  {
187  }
188 }
189 
191 {
192  QgsDebugMsg( "PARALLEL finished" );
193 
194  mStatus = Idle;
195 
196  mRenderingTime = mRenderingStart.elapsed();
197 
198  emit finished();
199 }
200 
202 {
203  if ( job.context.renderingStopped() )
204  return;
205 
206  if ( job.cached )
207  return;
208 
209  QTime t;
210  t.start();
211  QgsDebugMsg( QString( "job %1 start" ).arg(( ulong ) &job, 0, 16 ) );
212 
213  try
214  {
215  job.renderer->render();
216  }
217  catch ( QgsException & e )
218  {
219  QgsDebugMsg( "Caught unhandled QgsException: " + e.what() );
220  }
221  catch ( std::exception & e )
222  {
223  QgsDebugMsg( "Caught unhandled std::exception: " + QString::fromAscii( e.what() ) );
224  }
225  catch ( ... )
226  {
227  QgsDebugMsg( "Caught unhandled unknown exception" );
228  }
229 
230  int tt = t.elapsed();
231  QgsDebugMsg( QString( "job %1 end [%2 ms]" ).arg(( ulong ) &job, 0, 16 ).arg( tt ) );
232  Q_UNUSED( tt );
233 }
234 
235 
237 {
238  QPainter painter( &self->mFinalImage );
239 
240  try
241  {
242  drawLabeling( self->mSettings, self->mLabelingRenderContext, self->mLabelingEngine, &painter );
243  }
244  catch ( QgsException & e )
245  {
246  QgsDebugMsg( "Caught unhandled QgsException: " + e.what() );
247  }
248  catch ( std::exception & e )
249  {
250  QgsDebugMsg( "Caught unhandled std::exception: " + QString::fromAscii( e.what() ) );
251  }
252  catch ( ... )
253  {
254  QgsDebugMsg( "Caught unhandled unknown exception" );
255  }
256 
257  painter.end();
258 }
259 
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:33
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.