QGIS API Documentation  2.9.0-Master
 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 
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