QGIS API Documentation  3.0.2-Girona (307d082)
qgsmaprendererjob.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsmaprendererjob.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 
16 #include "qgsmaprendererjob.h"
17 
18 #include <QPainter>
19 #include <QTime>
20 #include <QTimer>
21 #include <QtConcurrentMap>
22 
23 #include "qgslogger.h"
24 #include "qgsrendercontext.h"
25 #include "qgsmaplayer.h"
26 #include "qgsproject.h"
27 #include "qgsmaplayerrenderer.h"
29 #include "qgsmaprenderercache.h"
30 #include "qgsmessagelog.h"
31 #include "qgspallabeling.h"
32 #include "qgsvectorlayerrenderer.h"
33 #include "qgsvectorlayer.h"
34 #include "qgsexception.h"
35 #include "qgslabelingengine.h"
36 #include "qgsmaplayerlistutils.h"
37 #include "qgsvectorlayerlabeling.h"
38 #include "qgssettings.h"
39 
41 
42 const QString QgsMapRendererJob::LABEL_CACHE_ID = QStringLiteral( "_labels_" );
43 
45  : mSettings( settings )
46 
47 {
48 }
49 
50 
52  : QgsMapRendererJob( settings )
53 {
54 }
55 
56 
58 {
59  return mErrors;
60 }
61 
63 {
64  mCache = cache;
65 }
66 
67 QHash<QgsMapLayer *, int> QgsMapRendererJob::perLayerRenderingTime() const
68 {
69  QHash<QgsMapLayer *, int> result;
70  for ( auto it = mPerLayerRenderingTime.constBegin(); it != mPerLayerRenderingTime.constEnd(); ++it )
71  {
72  if ( it.key() )
73  result.insert( it.key(), it.value() );
74  }
75  return result;
76 }
77 
79 {
80  return mSettings;
81 }
82 
84 {
85  bool canCache = mCache;
86 
87  // calculate which layers will be labeled
88  QSet< QgsMapLayer * > labeledLayers;
89  Q_FOREACH ( const QgsMapLayer *ml, mSettings.layers() )
90  {
91  QgsVectorLayer *vl = const_cast< QgsVectorLayer * >( qobject_cast<const QgsVectorLayer *>( ml ) );
92  if ( vl && QgsPalLabeling::staticWillUseLayer( vl ) )
93  labeledLayers << vl;
94  if ( vl && vl->labelsEnabled() && vl->labeling()->requiresAdvancedEffects() )
95  {
96  canCache = false;
97  break;
98  }
99  }
100 
102  {
103  // we may need to clear label cache and re-register labeled features - check for that here
104 
105  // can we reuse the cached label solution?
106  bool canUseCache = canCache && mCache->dependentLayers( LABEL_CACHE_ID ).toSet() == labeledLayers;
107  if ( !canUseCache )
108  {
109  // no - participating layers have changed
111  }
112  }
113  return canCache;
114 }
115 
116 
117 bool QgsMapRendererJob::reprojectToLayerExtent( const QgsMapLayer *ml, const QgsCoordinateTransform &ct, QgsRectangle &extent, QgsRectangle &r2 )
118 {
119  bool split = false;
120 
121  try
122  {
123 #ifdef QGISDEBUG
124  // QgsLogger::debug<QgsRectangle>("Getting extent of canvas in layers CS. Canvas is ", extent, __FILE__, __FUNCTION__, __LINE__);
125 #endif
126  // Split the extent into two if the source CRS is
127  // geographic and the extent crosses the split in
128  // geographic coordinates (usually +/- 180 degrees,
129  // and is assumed to be so here), and draw each
130  // extent separately.
131  static const double SPLIT_COORD = 180.0;
132 
133  if ( ml->crs().isGeographic() )
134  {
135  if ( ml->type() == QgsMapLayer::VectorLayer && !ct.destinationCrs().isGeographic() )
136  {
137  // if we transform from a projected coordinate system check
138  // check if transforming back roughly returns the input
139  // extend - otherwise render the world.
142 
143  QgsDebugMsgLevel( QString( "\n0:%1 %2x%3\n1:%4\n2:%5 %6x%7 (w:%8 h:%9)" )
144  .arg( extent.toString() ).arg( extent.width() ).arg( extent.height() )
145  .arg( extent1.toString(), extent2.toString() ).arg( extent2.width() ).arg( extent2.height() )
146  .arg( std::fabs( 1.0 - extent2.width() / extent.width() ) )
147  .arg( std::fabs( 1.0 - extent2.height() / extent.height() ) )
148  , 3 );
149 
150  if ( std::fabs( 1.0 - extent2.width() / extent.width() ) < 0.5 &&
151  std::fabs( 1.0 - extent2.height() / extent.height() ) < 0.5 )
152  {
153  extent = extent1;
154  }
155  else
156  {
157  extent = QgsRectangle( -180.0, -90.0, 180.0, 90.0 );
158  }
159  }
160  else
161  {
162  // Note: ll = lower left point
163  QgsPointXY ll = ct.transform( extent.xMinimum(), extent.yMinimum(),
165 
166  // and ur = upper right point
167  QgsPointXY ur = ct.transform( extent.xMaximum(), extent.yMaximum(),
169 
170  QgsDebugMsgLevel( QString( "in:%1 (ll:%2 ur:%3)" ).arg( extent.toString(), ll.toString(), ur.toString() ), 4 );
171 
173 
174  QgsDebugMsgLevel( QString( "out:%1 (w:%2 h:%3)" ).arg( extent.toString() ).arg( extent.width() ).arg( extent.height() ), 4 );
175 
176  if ( ll.x() > ur.x() )
177  {
178  // the coordinates projected in reverse order than what one would expect.
179  // we are probably looking at an area that includes longitude of 180 degrees.
180  // we need to take into account coordinates from two intervals: (-180,x1) and (x2,180)
181  // so let's use (-180,180). This hopefully does not add too much overhead. It is
182  // more straightforward than rendering with two separate extents and more consistent
183  // for rendering, labeling and caching as everything is rendered just in one go
184  extent.setXMinimum( -SPLIT_COORD );
185  extent.setXMaximum( SPLIT_COORD );
186  }
187  }
188 
189  // TODO: the above rule still does not help if using a projection that covers the whole
190  // world. E.g. with EPSG:3857 the longitude spectrum -180 to +180 is mapped to approx.
191  // -2e7 to +2e7. Converting extent from -5e7 to +5e7 is transformed as -90 to +90,
192  // but in fact the extent should cover the whole world.
193  }
194  else // can't cross 180
195  {
196  if ( ct.destinationCrs().isGeographic() &&
197  ( extent.xMinimum() <= -180 || extent.xMaximum() >= 180 ||
198  extent.yMinimum() <= -90 || extent.yMaximum() >= 90 ) )
199  // Use unlimited rectangle because otherwise we may end up transforming wrong coordinates.
200  // E.g. longitude -200 to +160 would be understood as +40 to +160 due to periodicity.
201  // We could try to clamp coords to (-180,180) for lon resp. (-90,90) for lat,
202  // but this seems like a safer choice.
203  extent = QgsRectangle( -DBL_MAX, -DBL_MAX, DBL_MAX, DBL_MAX );
204  else
206  }
207  }
208  catch ( QgsCsException &cse )
209  {
210  Q_UNUSED( cse );
211  QgsDebugMsg( "Transform error caught" );
212  extent = QgsRectangle( -DBL_MAX, -DBL_MAX, DBL_MAX, DBL_MAX );
213  r2 = QgsRectangle( -DBL_MAX, -DBL_MAX, DBL_MAX, DBL_MAX );
214  }
215 
216  return split;
217 }
218 
219 
220 
221 LayerRenderJobs QgsMapRendererJob::prepareJobs( QPainter *painter, QgsLabelingEngine *labelingEngine2 )
222 {
223  LayerRenderJobs layerJobs;
224 
225  // render all layers in the stack, starting at the base
226  QListIterator<QgsMapLayer *> li( mSettings.layers() );
227  li.toBack();
228 
229  if ( mCache )
230  {
231  bool cacheValid = mCache->init( mSettings.visibleExtent(), mSettings.scale() );
232  Q_UNUSED( cacheValid );
233  QgsDebugMsgLevel( QString( "CACHE VALID: %1" ).arg( cacheValid ), 4 );
234  }
235 
236  bool requiresLabelRedraw = !( mCache && mCache->hasCacheImage( LABEL_CACHE_ID ) );
237 
238  while ( li.hasPrevious() )
239  {
240  QgsMapLayer *ml = li.previous();
241 
242  QgsDebugMsgLevel( QString( "layer %1: minscale:%2 maxscale:%3 scaledepvis:%4 blendmode:%5" )
243  .arg( ml->name() )
244  .arg( ml->minimumScale() )
245  .arg( ml->maximumScale() )
246  .arg( ml->hasScaleBasedVisibility() )
247  .arg( ml->blendMode() )
248  , 3 );
249 
250  if ( !ml->isInScaleRange( mSettings.scale() ) ) //|| mOverview )
251  {
252  QgsDebugMsgLevel( "Layer not rendered because it is not within the defined visibility scale range", 3 );
253  continue;
254  }
255 
258 
259  ct = mSettings.layerTransform( ml );
260  if ( ct.isValid() )
261  {
262  reprojectToLayerExtent( ml, ct, r1, r2 );
263  }
264  QgsDebugMsgLevel( "extent: " + r1.toString(), 3 );
265  if ( !r1.isFinite() || !r2.isFinite() )
266  {
267  mErrors.append( Error( ml->id(), tr( "There was a problem transforming the layer's extent. Layer skipped." ) ) );
268  continue;
269  }
270 
271  // Force render of layers that are being edited
272  // or if there's a labeling engine that needs the layer to register features
273  if ( mCache && ml->type() == QgsMapLayer::VectorLayer )
274  {
275  QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( ml );
276  bool requiresLabeling = false;
277  requiresLabeling = ( labelingEngine2 && QgsPalLabeling::staticWillUseLayer( vl ) ) && requiresLabelRedraw;
278  if ( vl->isEditable() || requiresLabeling )
279  {
280  mCache->clearCacheImage( ml->id() );
281  }
282  }
283 
284  layerJobs.append( LayerRenderJob() );
285  LayerRenderJob &job = layerJobs.last();
286  job.cached = false;
287  job.img = nullptr;
288  job.blendMode = ml->blendMode();
289  job.opacity = 1.0;
290  if ( QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( ml ) )
291  {
292  job.opacity = vl->opacity();
293  }
294  job.layer = ml;
295  job.renderingTime = -1;
296 
298  job.context.expressionContext().appendScope( QgsExpressionContextUtils::layerScope( ml ) );
299  job.context.setPainter( painter );
300  job.context.setLabelingEngine( labelingEngine2 );
301  job.context.setCoordinateTransform( ct );
302  job.context.setExtent( r1 );
303 
304  if ( mFeatureFilterProvider )
305  job.context.setFeatureFilterProvider( mFeatureFilterProvider );
306 
307  // if we can use the cache, let's do it and avoid rendering!
308  if ( mCache && mCache->hasCacheImage( ml->id() ) )
309  {
310  job.cached = true;
311  job.imageInitialized = true;
312  job.img = new QImage( mCache->cacheImage( ml->id() ) );
313  job.renderer = nullptr;
314  job.context.setPainter( nullptr );
315  continue;
316  }
317 
318  // If we are drawing with an alternative blending mode then we need to render to a separate image
319  // before compositing this on the map. This effectively flattens the layer and prevents
320  // blending occurring between objects on the layer
321  if ( mCache || !painter || needTemporaryImage( ml ) )
322  {
323  // Flattened image for drawing when a blending mode is set
324  QImage *mypFlattenedImage = nullptr;
325  mypFlattenedImage = new QImage( mSettings.outputSize().width(),
326  mSettings.outputSize().height(),
328  if ( mypFlattenedImage->isNull() )
329  {
330  mErrors.append( Error( ml->id(), tr( "Insufficient memory for image %1x%2" ).arg( mSettings.outputSize().width() ).arg( mSettings.outputSize().height() ) ) );
331  delete mypFlattenedImage;
332  layerJobs.removeLast();
333  continue;
334  }
335 
336  job.img = mypFlattenedImage;
337  QPainter *mypPainter = new QPainter( job.img );
338  mypPainter->setRenderHint( QPainter::Antialiasing, mSettings.testFlag( QgsMapSettings::Antialiasing ) );
339  job.context.setPainter( mypPainter );
340  }
341 
342  bool hasStyleOverride = mSettings.layerStyleOverrides().contains( ml->id() );
343  if ( hasStyleOverride )
344  ml->styleManager()->setOverrideStyle( mSettings.layerStyleOverrides().value( ml->id() ) );
345 
346  QTime layerTime;
347  layerTime.start();
348  job.renderer = ml->createMapRenderer( job.context );
349  job.renderingTime = layerTime.elapsed(); // include job preparation time in layer rendering time
350 
351  if ( hasStyleOverride )
353 
354  } // while (li.hasPrevious())
355 
356  return layerJobs;
357 }
358 
359 LabelRenderJob QgsMapRendererJob::prepareLabelingJob( QPainter *painter, QgsLabelingEngine *labelingEngine2, bool canUseLabelCache )
360 {
361  LabelRenderJob job;
363  job.context.setPainter( painter );
364  job.context.setLabelingEngine( labelingEngine2 );
365  job.context.setExtent( mSettings.visibleExtent() );
366 
367  // if we can use the cache, let's do it and avoid rendering!
368  bool hasCache = canUseLabelCache && mCache && mCache->hasCacheImage( LABEL_CACHE_ID );
369  if ( hasCache )
370  {
371  job.cached = true;
372  job.complete = true;
373  job.img = new QImage( mCache->cacheImage( LABEL_CACHE_ID ) );
374  job.context.setPainter( nullptr );
375  }
376  else
377  {
378  if ( canUseLabelCache && ( mCache || !painter ) )
379  {
380  // Flattened image for drawing labels
381  QImage *mypFlattenedImage = nullptr;
382  mypFlattenedImage = new QImage( mSettings.outputSize().width(),
383  mSettings.outputSize().height(),
385  if ( mypFlattenedImage->isNull() )
386  {
387  mErrors.append( Error( QStringLiteral( "labels" ), tr( "Insufficient memory for label image %1x%2" ).arg( mSettings.outputSize().width() ).arg( mSettings.outputSize().height() ) ) );
388  delete mypFlattenedImage;
389  }
390  else
391  {
392  job.img = mypFlattenedImage;
393  }
394  }
395  }
396 
397  return job;
398 }
399 
400 
401 void QgsMapRendererJob::cleanupJobs( LayerRenderJobs &jobs )
402 {
403  for ( LayerRenderJobs::iterator it = jobs.begin(); it != jobs.end(); ++it )
404  {
405  LayerRenderJob &job = *it;
406  if ( job.img )
407  {
408  delete job.context.painter();
409  job.context.setPainter( nullptr );
410 
411  if ( mCache && !job.cached && !job.context.renderingStopped() && job.layer )
412  {
413  QgsDebugMsg( "caching image for " + ( job.layer ? job.layer->id() : QString() ) );
414  mCache->setCacheImage( job.layer->id(), *job.img, QList< QgsMapLayer * >() << job.layer );
415  }
416 
417  delete job.img;
418  job.img = nullptr;
419  }
420 
421  if ( job.renderer )
422  {
423  Q_FOREACH ( const QString &message, job.renderer->errors() )
424  mErrors.append( Error( job.renderer->layerId(), message ) );
425 
426  delete job.renderer;
427  job.renderer = nullptr;
428  }
429 
430  if ( job.layer )
431  mPerLayerRenderingTime.insert( job.layer, job.renderingTime );
432  }
433 
434  jobs.clear();
435 }
436 
437 void QgsMapRendererJob::cleanupLabelJob( LabelRenderJob &job )
438 {
439  if ( job.img )
440  {
441  if ( mCache && !job.cached && !job.context.renderingStopped() )
442  {
443  QgsDebugMsg( "caching label result image" );
444  mCache->setCacheImage( LABEL_CACHE_ID, *job.img, _qgis_listQPointerToRaw( job.participatingLayers ) );
445  }
446 
447  delete job.img;
448  job.img = nullptr;
449  }
450 }
451 
452 
453 QImage QgsMapRendererJob::composeImage( const QgsMapSettings &settings, const LayerRenderJobs &jobs, const LabelRenderJob &labelJob )
454 {
455  QImage image( settings.outputSize(), settings.outputImageFormat() );
456  image.fill( settings.backgroundColor().rgba() );
457 
458  QPainter painter( &image );
459 
460 
461  for ( LayerRenderJobs::const_iterator it = jobs.constBegin(); it != jobs.constEnd(); ++it )
462  {
463  const LayerRenderJob &job = *it;
464 
465  if ( job.layer && job.layer->customProperty( QStringLiteral( "rendering/renderAboveLabels" ) ).toBool() )
466  continue; // skip layer for now, it will be rendered after labels
467 
468  if ( !job.imageInitialized )
469  continue; // img not safe to compose
470 
471  painter.setCompositionMode( job.blendMode );
472  painter.setOpacity( job.opacity );
473 
474  Q_ASSERT( job.img );
475 
476  painter.drawImage( 0, 0, *job.img );
477  }
478 
479  // IMPORTANT - don't draw labelJob img before the label job is complete,
480  // as the image is uninitialized and full of garbage before the label job
481  // commences
482  if ( labelJob.img && labelJob.complete )
483  {
484  painter.setCompositionMode( QPainter::CompositionMode_SourceOver );
485  painter.setOpacity( 1.0 );
486  painter.drawImage( 0, 0, *labelJob.img );
487  }
488 
489  // render any layers with the renderAboveLabels flag now
490  for ( LayerRenderJobs::const_iterator it = jobs.constBegin(); it != jobs.constEnd(); ++it )
491  {
492  const LayerRenderJob &job = *it;
493 
494  if ( !job.layer || !job.layer->customProperty( QStringLiteral( "rendering/renderAboveLabels" ) ).toBool() )
495  continue;
496 
497  if ( !job.imageInitialized )
498  continue; // img not safe to compose
499 
500  painter.setCompositionMode( job.blendMode );
501  painter.setOpacity( job.opacity );
502 
503  Q_ASSERT( job.img );
504 
505  painter.drawImage( 0, 0, *job.img );
506  }
507 
508  painter.end();
509  return image;
510 }
511 
512 void QgsMapRendererJob::logRenderingTime( const LayerRenderJobs &jobs, const LabelRenderJob &labelJob )
513 {
514  QgsSettings settings;
515  if ( !settings.value( QStringLiteral( "Map/logCanvasRefreshEvent" ), false ).toBool() )
516  return;
517 
518  QMultiMap<int, QString> elapsed;
519  Q_FOREACH ( const LayerRenderJob &job, jobs )
520  elapsed.insert( job.renderingTime, job.layer ? job.layer->id() : QString() );
521 
522  elapsed.insert( labelJob.renderingTime, tr( "Labeling" ) );
523 
524  QList<int> tt( elapsed.uniqueKeys() );
525  std::sort( tt.begin(), tt.end(), std::greater<int>() );
526  Q_FOREACH ( int t, tt )
527  {
528  QgsMessageLog::logMessage( tr( "%1 ms: %2" ).arg( t ).arg( QStringList( elapsed.values( t ) ).join( QStringLiteral( ", " ) ) ), tr( "Rendering" ) );
529  }
530  QgsMessageLog::logMessage( QStringLiteral( "---" ), tr( "Rendering" ) );
531 }
532 
bool restoreOverrideStyle()
Restore the original store after a call to setOverrideStyle()
QList< QgsMapLayer *> dependentLayers(const QString &cacheKey) const
Returns a list of map layers on which an image in the cache depends.
bool labelsEnabled() const
Returns whether the layer contains labels which are enabled and should be drawn.
A rectangle specified with double values.
Definition: qgsrectangle.h:39
Base class for all map layer types.
Definition: qgsmaplayer.h:56
const LayerRenderJobs & jobs() const
Abstract base class for map rendering implementations.
void setXMaximum(double x)
Set the maximum x value.
Definition: qgsrectangle.h:94
This class is a composition of two QSettings instances:
Definition: qgssettings.h:57
void cleanupJobs(LayerRenderJobs &jobs)
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
A class to represent a 2D point.
Definition: qgspointxy.h:43
QColor backgroundColor() const
Get the background color of the map.
void setCacheImage(const QString &cacheKey, const QImage &image, const QList< QgsMapLayer * > &dependentLayers=QList< QgsMapLayer * >())
Set the cached image for a particular cacheKey.
QgsRectangle transformBoundingBox(const QgsRectangle &rectangle, TransformDirection direction=ForwardTransform, const bool handle180Crossover=false) const
Transforms a rectangle from the source CRS to the destination CRS.
Errors errors() const
List of errors that happened during the rendering job - available when the rendering has been finishe...
QgsCoordinateReferenceSystem destinationCrs() const
Returns the destination coordinate reference system, which the transform will transform coordinates t...
bool isInScaleRange(double scale) const
Tests whether the layer should be visible at the specified scale.
QString toString(int precision=-1) const
Returns a string representation of the point (x, y) with a preset precision.
Definition: qgspointxy.cpp:45
QList< QgsMapLayer * > layers() const
Get list of layers for map rendering The layers are stored in the reverse order of how they are rende...
static const QString LABEL_CACHE_ID
QgsMapRendererCache ID string for cached label image.
bool isEditable() const override
Returns true if the provider is in editing mode.
QgsMapLayer::LayerType type() const
Returns the type of the layer.
QgsRectangle visibleExtent() const
Return the actual extent derived from requested extent that takes takes output image size into accoun...
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::Warning)
add a message to the instance (and create it if necessary)
bool isValid() const
Returns true if the coordinate transform is valid, ie both the source and destination CRS have been s...
void setCache(QgsMapRendererCache *cache)
Assign a cache to be used for reading and storing rendered images of individual layers.
The QgsMapSettings class contains configuration for rendering of the map.
QgsMapLayerStyleManager * styleManager() const
Get access to the layer&#39;s style manager.
static bool staticWillUseLayer(QgsVectorLayer *layer)
called to find out whether the layer is used for labeling
QgsCoordinateTransform layerTransform(const QgsMapLayer *layer) const
Return coordinate transform from layer&#39;s CRS to destination CRS.
static QImage composeImage(const QgsMapSettings &settings, const LayerRenderJobs &jobs, const LabelRenderJob &labelJob)
LabelRenderJob prepareLabelingJob(QPainter *painter, QgsLabelingEngine *labelingEngine2, bool canUseLabelCache=true)
Prepares a labeling job.
bool prepareLabelCache() const
Prepares the cache for storing the result of labeling.
virtual bool requiresAdvancedEffects() const =0
Returns true if drawing labels requires advanced effects like composition modes, which could prevent ...
QHash< QgsWeakMapLayerPointer, int > mPerLayerRenderingTime
Render time (in ms) per layer, by layer ID.
QString id() const
Returns the layer&#39;s unique ID, which is used to access this layer from QgsProject.
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
bool init(const QgsRectangle &extent, double scale)
Initialize cache: set new parameters and clears the cache if any parameters have changed since last i...
double scale() const
Returns the calculated map scale.
double width() const
Returns the width of the rectangle.
Definition: qgsrectangle.h:142
Enable anti-aliasing for map rendering.
QString toString(int precision=16) const
Returns a string representation of form xmin,ymin : xmax,ymax Coordinates will be truncated to the sp...
QImage::Format outputImageFormat() const
format of internal QImage, default QImage::Format_ARGB32_Premultiplied
QgsCoordinateReferenceSystem crs() const
Returns the layer&#39;s spatial reference system.
QImage cacheImage(const QString &cacheKey) const
Returns the cached image for the specified cacheKey.
bool isGeographic() const
Returns whether the CRS is a geographic CRS (using lat/lon coordinates)
const QgsAbstractVectorLayerLabeling * labeling() const
Access to const labeling configuration.
double minimumScale() const
Returns the minimum map scale (i.e.
double maximumScale() const
Returns the maximum map scale (i.e.
QHash< QgsMapLayer *, int > perLayerRenderingTime() const
Returns the render time (in ms) per layer.
QgsMapSettings mSettings
bool isFinite() const
Returns true if the rectangle has finite boundaries.
double x
Definition: qgspointxy.h:47
void cleanupLabelJob(LabelRenderJob &job)
Handles clean up tasks for a label job, including deletion of images and storing cached label results...
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:130
double xMaximum() const
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:115
bool hasCacheImage(const QString &cacheKey) const
Returns true if the cache contains an image with the specified cacheKey.
The QgsLabelingEngine class provides map labeling functionality.
QMap< QString, QString > layerStyleOverrides() const
Get map of map layer style overrides (key: layer ID, value: style name) where a different style shoul...
QList< QgsMapRendererJob::Error > Errors
LayerRenderJobs prepareJobs(QPainter *painter, QgsLabelingEngine *labelingEngine2)
Transform from destination to source CRS.
void logRenderingTime(const LayerRenderJobs &jobs, const LabelRenderJob &labelJob)
bool hasScaleBasedVisibility() const
Returns whether scale based visibility is enabled for the layer.
QgsPointXY transform(const QgsPointXY &point, TransformDirection direction=ForwardTransform) const
Transform the point from the source CRS to the destination CRS.
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), const Section section=NoSection) const
Returns the value for setting key.
static QgsRenderContext fromMapSettings(const QgsMapSettings &mapSettings)
create initialized QgsRenderContext instance from given QgsMapSettings
void clearCacheImage(const QString &cacheKey)
Removes an image from the cache with matching cacheKey.
Class for doing transforms between two map coordinate systems.
double xMinimum() const
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:120
virtual QgsMapLayerRenderer * createMapRenderer(QgsRenderContext &rendererContext)=0
Return new instance of QgsMapLayerRenderer that will be used for rendering of given context...
QgsMapRendererQImageJob(const QgsMapSettings &settings)
double yMaximum() const
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:125
QString name
Definition: qgsmaplayer.h:60
Transform from source to destination CRS.
This class is responsible for keeping cache of rendered images resulting from a map rendering job...
bool testFlag(Flag flag) const
Check whether a particular flag is enabled.
bool setOverrideStyle(const QString &styleDef)
Temporarily apply a different style to the layer.
Custom exception class for Coordinate Reference System related exceptions.
Definition: qgsexception.h:65
static QgsExpressionContextScope * layerScope(const QgsMapLayer *layer)
Creates a new scope which contains variables and functions relating to a QgsMapLayer.
Represents a vector layer which manages a vector based data sets.
const QgsMapSettings & mapSettings() const
Return map settings with which this job was started.
QgsMapRendererCache * mCache
QSize outputSize() const
Return the size of the resulting map image.
QgsMapRendererJob(const QgsMapSettings &settings)
void setXMinimum(double x)
Set the minimum x value.
Definition: qgsrectangle.h:89
QPainter::CompositionMode blendMode() const
Returns the current blending mode for a layer.
double height() const
Returns the height of the rectangle.
Definition: qgsrectangle.h:149