QGIS API Documentation  2.13.0-Master
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 "qgslabelingenginev2.h"
19 #include "qgslogger.h"
20 #include "qgsmaplayerrenderer.h"
21 #include "qgspallabeling.h"
22 
23 #include <QtConcurrentMap>
24 
25 #define LABELING_V2
26 
28  : QgsMapRendererQImageJob( settings )
29  , mStatus( Idle )
30  , mLabelingEngine( nullptr )
31  , mLabelingEngineV2( nullptr )
32 {
33 }
34 
36 {
37  if ( isActive() )
38  {
39  cancel();
40  }
41 
42  delete mLabelingEngine;
43  mLabelingEngine = nullptr;
44 
45  delete mLabelingEngineV2;
46  mLabelingEngineV2 = nullptr;
47 }
48 
50 {
51  if ( isActive() )
52  return;
53 
55 
57 
58  delete mLabelingEngine;
59  mLabelingEngine = nullptr;
60 
61  delete mLabelingEngineV2;
62  mLabelingEngineV2 = nullptr;
63 
65  {
66 #ifdef LABELING_V2
70 #else
74 #endif
75  }
76 
78 
79  QgsDebugMsg( QString( "QThreadPool max thread count is %1" ).arg( QThreadPool::globalInstance()->maxThreadCount() ) );
80 
81  // start async job
82 
83  connect( &mFutureWatcher, SIGNAL( finished() ), SLOT( renderLayersFinished() ) );
84 
87 }
88 
90 {
91  if ( !isActive() )
92  return;
93 
94  QgsDebugMsg( QString( "PARALLEL cancel at status %1" ).arg( mStatus ) );
95 
97  for ( LayerRenderJobs::iterator it = mLayerJobs.begin(); it != mLayerJobs.end(); ++it )
98  {
99  it->context.setRenderingStopped( true );
100  }
101 
102  if ( mStatus == RenderingLayers )
103  {
104  disconnect( &mFutureWatcher, SIGNAL( finished() ), this, SLOT( renderLayersFinished() ) );
105 
107 
109  }
110 
111  if ( mStatus == RenderingLabels )
112  {
113  disconnect( &mLabelingFutureWatcher, SIGNAL( finished() ), this, SLOT( renderingFinished() ) );
114 
116 
118  }
119 
120  Q_ASSERT( mStatus == Idle );
121 }
122 
124 {
125  if ( !isActive() )
126  return;
127 
128  if ( mStatus == RenderingLayers )
129  {
130  disconnect( &mFutureWatcher, SIGNAL( finished() ), this, SLOT( renderLayersFinished() ) );
131 
132  QTime t;
133  t.start();
134 
136 
137  QgsDebugMsg( QString( "waitForFinished (1): %1 ms" ).arg( t.elapsed() / 1000.0 ) );
138 
140  }
141 
142  if ( mStatus == RenderingLabels )
143  {
144  disconnect( &mLabelingFutureWatcher, SIGNAL( finished() ), this, SLOT( renderingFinished() ) );
145 
146  QTime t;
147  t.start();
148 
150 
151  QgsDebugMsg( QString( "waitForFinished (2): %1 ms" ).arg( t.elapsed() / 1000.0 ) );
152 
154  }
155 
156  Q_ASSERT( mStatus == Idle );
157 }
158 
160 {
161  return mStatus != Idle;
162 }
163 
165 {
166  if ( mLabelingEngine )
167  return mLabelingEngine->takeResults();
168  else if ( mLabelingEngineV2 )
169  return mLabelingEngineV2->takeResults();
170  else
171  return nullptr;
172 }
173 
175 {
176  if ( mStatus == RenderingLayers )
177  return composeImage( mSettings, mLayerJobs );
178  else
179  return mFinalImage; // when rendering labels or idle
180 }
181 
183 {
184  Q_ASSERT( mStatus == RenderingLayers );
185 
186  // compose final image
188 
190 
191  QgsDebugMsg( "PARALLEL layers finished" );
192 
194  {
196 
197  connect( &mLabelingFutureWatcher, SIGNAL( finished() ), this, SLOT( renderingFinished() ) );
198 
199  // now start rendering of labeling!
202  }
203  else
204  {
206  }
207 }
208 
210 {
211  QgsDebugMsg( "PARALLEL finished" );
212 
213  mStatus = Idle;
214 
216 
217  emit finished();
218 }
219 
221 {
222  if ( job.context.renderingStopped() )
223  return;
224 
225  if ( job.cached )
226  return;
227 
228  QTime t;
229  t.start();
230  QgsDebugMsg( QString( "job %1 start" ).arg( reinterpret_cast< ulong >( &job ), 0, 16 ) );
231 
232  try
233  {
234  job.renderer->render();
235  }
236  catch ( QgsException & e )
237  {
238  QgsDebugMsg( "Caught unhandled QgsException: " + e.what() );
239  }
240  catch ( std::exception & e )
241  {
242  QgsDebugMsg( "Caught unhandled std::exception: " + QString::fromAscii( e.what() ) );
243  }
244  catch ( ... )
245  {
246  QgsDebugMsg( "Caught unhandled unknown exception" );
247  }
248 
249  int tt = t.elapsed();
250  QgsDebugMsg( QString( "job %1 end [%2 ms]" ).arg( reinterpret_cast< ulong >( &job ), 0, 16 ).arg( tt ) );
251  Q_UNUSED( tt );
252 }
253 
254 
256 {
257  QPainter painter( &self->mFinalImage );
258 
259  try
260  {
261  drawLabeling( self->mSettings, self->mLabelingRenderContext, self->mLabelingEngine, self->mLabelingEngineV2, &painter );
262  }
263  catch ( QgsException & e )
264  {
265  QgsDebugMsg( "Caught unhandled QgsException: " + e.what() );
266  }
267  catch ( std::exception & e )
268  {
269  QgsDebugMsg( "Caught unhandled std::exception: " + QString::fromAscii( e.what() ) );
270  }
271  catch ( ... )
272  {
273  QgsDebugMsg( "Caught unhandled unknown exception" );
274  }
275 
276  painter.end();
277 }
278 
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()
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
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
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()
void setMapSettings(const QgsMapSettings &mapSettings)
Associate map settings instance.
bool testFlag(Flag flag) const
Check whether a particular flag is enabled.
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)
QString what() const
Definition: qgsexception.h:36
virtual bool render()=0
Do the rendering (based on data stored in the class)
LayerRenderJobs prepareJobs(QPainter *painter, QgsPalLabeling *labelingEngine, QgsLabelingEngineV2 *labelingEngine2)
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.
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
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)