QGIS API Documentation
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 
192 
193  QgsDebugMsg( "PARALLEL layers finished" );
194 
196  {
198 
199  connect( &mLabelingFutureWatcher, SIGNAL( finished() ), this, SLOT( renderingFinished() ) );
200 
201  // now start rendering of labeling!
204  }
205  else
206  {
208  }
209 }
210 
212 {
213  QgsDebugMsg( "PARALLEL finished" );
214 
215  mStatus = Idle;
216 
218 
219  emit finished();
220 }
221 
223 {
224  if ( job.context.renderingStopped() )
225  return;
226 
227  if ( job.cached )
228  return;
229 
230  QTime t;
231  t.start();
232  QgsDebugMsg( QString( "job %1 start (layer %2)" ).arg( reinterpret_cast< ulong >( &job ), 0, 16 ).arg( job.layerId ) );
233 
234  try
235  {
236  job.renderer->render();
237  }
238  catch ( QgsException & e )
239  {
240  Q_UNUSED( e );
241  QgsDebugMsg( "Caught unhandled QgsException: " + e.what() );
242  }
243  catch ( std::exception & e )
244  {
245  Q_UNUSED( e );
246  QgsDebugMsg( "Caught unhandled std::exception: " + QString::fromAscii( e.what() ) );
247  }
248  catch ( ... )
249  {
250  QgsDebugMsg( "Caught unhandled unknown exception" );
251  }
252 
253  job.renderingTime = t.elapsed();
254  QgsDebugMsg( QString( "job %1 end [%2 ms] (layer %3)" ).arg( reinterpret_cast< ulong >( &job ), 0, 16 ).arg( job.renderingTime ).arg( job.layerId ) );
255 }
256 
257 
259 {
260  QPainter painter( &self->mFinalImage );
261 
262  try
263  {
264  drawLabeling( self->mSettings, self->mLabelingRenderContext, self->mLabelingEngine, self->mLabelingEngineV2, &painter );
265  }
266  catch ( QgsException & e )
267  {
268  Q_UNUSED( e );
269  QgsDebugMsg( "Caught unhandled QgsException: " + e.what() );
270  }
271  catch ( std::exception & e )
272  {
273  Q_UNUSED( e );
274  QgsDebugMsg( "Caught unhandled std::exception: " + QString::fromAscii( e.what() ) );
275  }
276  catch ( ... )
277  {
278  QgsDebugMsg( "Caught unhandled unknown exception" );
279  }
280 
281  painter.end();
282 }
283 
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
void logRenderingTime(const LayerRenderJobs &jobs)
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)
int renderingTime
time it took to render the layer in ms (it is -1 if not rendered or still rendering) ...
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)
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
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)