QGIS API Documentation  2.10.1-Pisa
 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 #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 
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 
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 
93 
95  }
96 
97  if ( mStatus == RenderingLabels )
98  {
99  disconnect( &mLabelingFutureWatcher, SIGNAL( finished() ), this, SLOT( renderingFinished() ) );
100 
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 
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 
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!
183  }
184  else
185  {
187  }
188 }
189 
191 {
192  QgsDebugMsg( "PARALLEL finished" );
193 
194  mStatus = Idle;
195 
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 
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
QThreadPool * globalInstance()
bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method)
virtual void cancel() override
Stop the rendering job - does not return until the job has terminated.
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.
virtual Q_DECL_DEPRECATED void init(QgsMapRenderer *mr) override
called when we're going to start with rendering
QgsMapRendererParallelJob(const QgsMapSettings &settings)
int elapsed() const
bool renderingStopped() 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()
bool testFlag(Flag flag) const
Check whether a particular flag is enabled.
void waitForFinished()
enum QgsMapRendererParallelJob::@0 mStatus
QString what() const
Definition: qgsexception.h:35
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
static void drawLabeling(const QgsMapSettings &settings, QgsRenderContext &renderContext, QgsPalLabeling *labelingEngine, QPainter *painter)
QgsRenderContext context
void start()
Class that stores computed placement from labeling engine.
static void renderLayerStatic(LayerRenderJob &job)
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
Defines a qgis exception class.
Definition: qgsexception.h:25
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)