QGIS API Documentation  2.99.0-Master (08c2e66)
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 #include <QSettings>
23 
24 #include "qgslogger.h"
25 #include "qgsrendercontext.h"
26 #include "qgsmaplayer.h"
27 #include "qgsproject.h"
28 #include "qgsmaplayerrenderer.h"
30 #include "qgsmaprenderercache.h"
31 #include "qgsmessagelog.h"
32 #include "qgspallabeling.h"
33 #include "qgsvectorlayerrenderer.h"
34 #include "qgsvectorlayer.h"
35 #include "qgscsexception.h"
36 #include "qgslabelingengine.h"
37 #include "qgsmaplayerlistutils.h"
38 #include "qgsvectorlayerlabeling.h"
39 
41 
42 const QString QgsMapRendererJob::LABEL_CACHE_ID = QStringLiteral( "_labels_" );
43 
45  : mSettings( settings )
46  , mCache( nullptr )
47  , mRenderingTime( 0 )
48  , mFeatureFilterProvider( nullptr )
49 {
50 }
51 
52 
54  : QgsMapRendererJob( settings )
55 {
56 }
57 
58 
60 {
61  return mErrors;
62 }
63 
65 {
66  mCache = cache;
67 }
68 
70 {
71  return mSettings;
72 }
73 
75 {
76  bool canCache = mCache;
77 
78  // calculate which layers will be labeled
79  QSet< QgsMapLayer* > labeledLayers;
80  Q_FOREACH ( const QgsMapLayer* ml, mSettings.layers() )
81  {
82  QgsVectorLayer* vl = const_cast< QgsVectorLayer* >( qobject_cast<const QgsVectorLayer *>( ml ) );
83  if ( vl && QgsPalLabeling::staticWillUseLayer( vl ) )
84  labeledLayers << vl;
85  if ( vl && vl->labeling() && vl->labeling()->requiresAdvancedEffects( vl ) )
86  {
87  canCache = false;
88  break;
89  }
90  }
91 
93  {
94  // we may need to clear label cache and re-register labeled features - check for that here
95 
96  // can we reuse the cached label solution?
97  bool canUseCache = canCache && mCache->dependentLayers( LABEL_CACHE_ID ).toSet() == labeledLayers;
98  if ( !canUseCache )
99  {
100  // no - participating layers have changed
102  }
103  }
104  return canCache;
105 }
106 
107 
108 bool QgsMapRendererJob::reprojectToLayerExtent( const QgsMapLayer *ml, const QgsCoordinateTransform& ct, QgsRectangle &extent, QgsRectangle &r2 )
109 {
110  bool split = false;
111 
112  try
113  {
114 #ifdef QGISDEBUG
115  // QgsLogger::debug<QgsRectangle>("Getting extent of canvas in layers CS. Canvas is ", extent, __FILE__, __FUNCTION__, __LINE__);
116 #endif
117  // Split the extent into two if the source CRS is
118  // geographic and the extent crosses the split in
119  // geographic coordinates (usually +/- 180 degrees,
120  // and is assumed to be so here), and draw each
121  // extent separately.
122  static const double SPLIT_COORD = 180.0;
123 
124  if ( ml->crs().isGeographic() )
125  {
126  if ( ml->type() == QgsMapLayer::VectorLayer && !ct.destinationCrs().isGeographic() )
127  {
128  // if we transform from a projected coordinate system check
129  // check if transforming back roughly returns the input
130  // extend - otherwise render the world.
133 
134  QgsDebugMsgLevel( QString( "\n0:%1 %2x%3\n1:%4\n2:%5 %6x%7 (w:%8 h:%9)" )
135  .arg( extent.toString() ).arg( extent.width() ).arg( extent.height() )
136  .arg( extent1.toString(), extent2.toString() ).arg( extent2.width() ).arg( extent2.height() )
137  .arg( fabs( 1.0 - extent2.width() / extent.width() ) )
138  .arg( fabs( 1.0 - extent2.height() / extent.height() ) )
139  , 3 );
140 
141  if ( fabs( 1.0 - extent2.width() / extent.width() ) < 0.5 &&
142  fabs( 1.0 - extent2.height() / extent.height() ) < 0.5 )
143  {
144  extent = extent1;
145  }
146  else
147  {
148  extent = QgsRectangle( -180.0, -90.0, 180.0, 90.0 );
149  }
150  }
151  else
152  {
153  // Note: ll = lower left point
154  QgsPoint ll = ct.transform( extent.xMinimum(), extent.yMinimum(),
156 
157  // and ur = upper right point
158  QgsPoint ur = ct.transform( extent.xMaximum(), extent.yMaximum(),
160 
161  QgsDebugMsg( QString( "in:%1 (ll:%2 ur:%3)" ).arg( extent.toString(), ll.toString(), ur.toString() ) );
162 
164 
165  QgsDebugMsg( QString( "out:%1 (w:%2 h:%3)" ).arg( extent.toString() ).arg( extent.width() ).arg( extent.height() ) );
166 
167  if ( ll.x() > ur.x() )
168  {
169  // the coordinates projected in reverse order than what one would expect.
170  // we are probably looking at an area that includes longitude of 180 degrees.
171  // we need to take into account coordinates from two intervals: (-180,x1) and (x2,180)
172  // so let's use (-180,180). This hopefully does not add too much overhead. It is
173  // more straightforward than rendering with two separate extents and more consistent
174  // for rendering, labeling and caching as everything is rendered just in one go
175  extent.setXMinimum( -SPLIT_COORD );
176  extent.setXMaximum( SPLIT_COORD );
177  }
178  }
179 
180  // TODO: the above rule still does not help if using a projection that covers the whole
181  // world. E.g. with EPSG:3857 the longitude spectrum -180 to +180 is mapped to approx.
182  // -2e7 to +2e7. Converting extent from -5e7 to +5e7 is transformed as -90 to +90,
183  // but in fact the extent should cover the whole world.
184  }
185  else // can't cross 180
186  {
187  if ( ct.destinationCrs().isGeographic() &&
188  ( extent.xMinimum() <= -180 || extent.xMaximum() >= 180 ||
189  extent.yMinimum() <= -90 || extent.yMaximum() >= 90 ) )
190  // Use unlimited rectangle because otherwise we may end up transforming wrong coordinates.
191  // E.g. longitude -200 to +160 would be understood as +40 to +160 due to periodicity.
192  // We could try to clamp coords to (-180,180) for lon resp. (-90,90) for lat,
193  // but this seems like a safer choice.
194  extent = QgsRectangle( -DBL_MAX, -DBL_MAX, DBL_MAX, DBL_MAX );
195  else
197  }
198  }
199  catch ( QgsCsException &cse )
200  {
201  Q_UNUSED( cse );
202  QgsDebugMsg( "Transform error caught" );
203  extent = QgsRectangle( -DBL_MAX, -DBL_MAX, DBL_MAX, DBL_MAX );
204  r2 = QgsRectangle( -DBL_MAX, -DBL_MAX, DBL_MAX, DBL_MAX );
205  }
206 
207  return split;
208 }
209 
210 
211 
212 LayerRenderJobs QgsMapRendererJob::prepareJobs( QPainter* painter, QgsLabelingEngine* labelingEngine2 )
213 {
214  LayerRenderJobs layerJobs;
215 
216  // render all layers in the stack, starting at the base
217  QListIterator<QgsMapLayer*> li( mSettings.layers() );
218  li.toBack();
219 
220  if ( mCache )
221  {
222  bool cacheValid = mCache->init( mSettings.visibleExtent(), mSettings.scale() );
223  Q_UNUSED( cacheValid );
224  QgsDebugMsg( QString( "CACHE VALID: %1" ).arg( cacheValid ) );
225  }
226 
227  bool requiresLabelRedraw = !( mCache && mCache->hasCacheImage( LABEL_CACHE_ID ) );
228 
229  mGeometryCaches.clear();
230 
231  while ( li.hasPrevious() )
232  {
233  QgsMapLayer* ml = li.previous();
234 
235  QgsDebugMsgLevel( QString( "layer %1: minscale:%2 maxscale:%3 scaledepvis:%4 blendmode:%5" )
236  .arg( ml->name() )
237  .arg( ml->minimumScale() )
238  .arg( ml->maximumScale() )
239  .arg( ml->hasScaleBasedVisibility() )
240  .arg( ml->blendMode() )
241  , 3 );
242 
243  if ( !ml->isInScaleRange( mSettings.scale() ) ) //|| mOverview )
244  {
245  QgsDebugMsgLevel( "Layer not rendered because it is not within the defined visibility scale range", 3 );
246  continue;
247  }
248 
251 
253  {
254  ct = mSettings.layerTransform( ml );
255  if ( ct.isValid() )
256  {
257  reprojectToLayerExtent( ml, ct, r1, r2 );
258  }
259  QgsDebugMsgLevel( "extent: " + r1.toString(), 3 );
260  if ( !r1.isFinite() || !r2.isFinite() )
261  {
262  mErrors.append( Error( ml->id(), tr( "There was a problem transforming the layer's extent. Layer skipped." ) ) );
263  continue;
264  }
265  }
266 
267  // Force render of layers that are being edited
268  // or if there's a labeling engine that needs the layer to register features
269  if ( mCache && ml->type() == QgsMapLayer::VectorLayer )
270  {
271  QgsVectorLayer* vl = qobject_cast<QgsVectorLayer *>( ml );
272  bool requiresLabeling = false;
273  requiresLabeling = ( labelingEngine2 && QgsPalLabeling::staticWillUseLayer( vl ) ) && requiresLabelRedraw;
274  if ( vl->isEditable() || requiresLabeling )
275  {
276  mCache->clearCacheImage( ml->id() );
277  }
278  }
279 
280  layerJobs.append( LayerRenderJob() );
281  LayerRenderJob& job = layerJobs.last();
282  job.cached = false;
283  job.img = nullptr;
284  job.blendMode = ml->blendMode();
285  job.opacity = 1.0;
286  if ( QgsVectorLayer* vl = qobject_cast<QgsVectorLayer *>( ml ) )
287  {
288  job.opacity = 1.0 - vl->layerTransparency() / 100.0;
289  }
290  job.layer = ml;
291  job.renderingTime = -1;
292 
294  job.context.expressionContext().appendScope( QgsExpressionContextUtils::layerScope( ml ) );
295  job.context.setPainter( painter );
296  job.context.setLabelingEngine( labelingEngine2 );
297  job.context.setCoordinateTransform( ct );
298  job.context.setExtent( r1 );
299 
300  if ( mFeatureFilterProvider )
301  job.context.setFeatureFilterProvider( mFeatureFilterProvider );
302 
303  // if we can use the cache, let's do it and avoid rendering!
304  if ( mCache && mCache->hasCacheImage( ml->id() ) )
305  {
306  job.cached = true;
307  job.img = new QImage( mCache->cacheImage( ml->id() ) );
308  job.renderer = nullptr;
309  job.context.setPainter( nullptr );
310  continue;
311  }
312 
313  // If we are drawing with an alternative blending mode then we need to render to a separate image
314  // before compositing this on the map. This effectively flattens the layer and prevents
315  // blending occurring between objects on the layer
316  if ( mCache || !painter || needTemporaryImage( ml ) )
317  {
318  // Flattened image for drawing when a blending mode is set
319  QImage * mypFlattenedImage = nullptr;
320  mypFlattenedImage = new QImage( mSettings.outputSize().width(),
321  mSettings.outputSize().height(),
323  if ( mypFlattenedImage->isNull() )
324  {
325  mErrors.append( Error( ml->id(), tr( "Insufficient memory for image %1x%2" ).arg( mSettings.outputSize().width() ).arg( mSettings.outputSize().height() ) ) );
326  delete mypFlattenedImage;
327  layerJobs.removeLast();
328  continue;
329  }
330 
331  job.img = mypFlattenedImage;
332  QPainter* mypPainter = new QPainter( job.img );
333  mypPainter->setRenderHint( QPainter::Antialiasing, mSettings.testFlag( QgsMapSettings::Antialiasing ) );
334  job.context.setPainter( mypPainter );
335  }
336 
337  bool hasStyleOverride = mSettings.layerStyleOverrides().contains( ml->id() );
338  if ( hasStyleOverride )
339  ml->styleManager()->setOverrideStyle( mSettings.layerStyleOverrides().value( ml->id() ) );
340 
341  job.renderer = ml->createMapRenderer( job.context );
342 
343  if ( hasStyleOverride )
345 
346  if ( mRequestedGeomCacheForLayers.contains( ml->id() ) )
347  {
348  if ( QgsVectorLayerRenderer* vlr = dynamic_cast<QgsVectorLayerRenderer*>( job.renderer ) )
349  {
350  vlr->setGeometryCachePointer( &mGeometryCaches[ ml->id()] );
351  }
352  }
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 
431 
432  jobs.clear();
433 
434  updateLayerGeometryCaches();
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  painter.setCompositionMode( job.blendMode );
469  painter.setOpacity( job.opacity );
470 
471  Q_ASSERT( job.img );
472 
473  painter.drawImage( 0, 0, *job.img );
474  }
475 
476  // IMPORTANT - don't draw labelJob img before the label job is complete,
477  // as the image is uninitialized and full of garbage before the label job
478  // commences
479  if ( labelJob.img && labelJob.complete )
480  {
481  painter.setCompositionMode( QPainter::CompositionMode_SourceOver );
482  painter.setOpacity( 1.0 );
483  painter.drawImage( 0, 0, *labelJob.img );
484  }
485 
486  // render any layers with the renderAboveLabels flag now
487  for ( LayerRenderJobs::const_iterator it = jobs.constBegin(); it != jobs.constEnd(); ++it )
488  {
489  const LayerRenderJob& job = *it;
490 
491  if ( !job.layer || !job.layer->customProperty( QStringLiteral( "rendering/renderAboveLabels" ) ).toBool() )
492  continue;
493 
494  painter.setCompositionMode( job.blendMode );
495  painter.setOpacity( job.opacity );
496 
497  Q_ASSERT( job.img );
498 
499  painter.drawImage( 0, 0, *job.img );
500  }
501 
502  painter.end();
503  return image;
504 }
505 
506 void QgsMapRendererJob::logRenderingTime( const LayerRenderJobs& jobs, const LabelRenderJob& labelJob )
507 {
508  QSettings settings;
509  if ( !settings.value( QStringLiteral( "/Map/logCanvasRefreshEvent" ), false ).toBool() )
510  return;
511 
512  QMultiMap<int, QString> elapsed;
513  Q_FOREACH ( const LayerRenderJob& job, jobs )
514  elapsed.insert( job.renderingTime, job.layer ? job.layer->id() : QString() );
515 
516  elapsed.insert( labelJob.renderingTime, tr( "Labeling" ) );
517 
518  QList<int> tt( elapsed.uniqueKeys() );
519  std::sort( tt.begin(), tt.end(), std::greater<int>() );
520  Q_FOREACH ( int t, tt )
521  {
522  QgsMessageLog::logMessage( tr( "%1 ms: %2" ).arg( t ).arg( QStringList( elapsed.values( t ) ).join( QStringLiteral( ", " ) ) ), tr( "Rendering" ) );
523  }
524  QgsMessageLog::logMessage( QStringLiteral( "---" ), tr( "Rendering" ) );
525 }
526 
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.
QgsRectangle transformBoundingBox(const QgsRectangle &rectangle, TransformDirection direction=ForwardTransform, const bool handle180Crossover=false) const
Transforms a rectangle from the source CRS to the destination CRS.
A rectangle specified with double values.
Definition: qgsrectangle.h:36
Base class for all map layer types.
Definition: qgsmaplayer.h:52
QgsMapLayer::LayerType type() const
Returns the type of the layer.
Definition: qgsmaplayer.cpp:96
Abstract base class for map rendering implementations.
double scale() const
Return the calculated scale of the map.
void setXMaximum(double x)
Set the maximum x value.
Definition: qgsrectangle.h:177
void cleanupJobs(LayerRenderJobs &jobs)
Errors errors() const
List of errors that happened during the rendering job - available when the rendering has been finishe...
QList< Error > Errors
bool isFinite() const
Returns true if the rectangle has finite boundaries.
double yMaximum() const
Get the y maximum value (top side of rectangle)
Definition: qgsrectangle.h:202
#define QgsDebugMsg(str)
Definition: qgslogger.h:36
double maximumScale() const
Returns the maximum scale denominator at which the layer is visible.
QgsMapLayerStyleManager * styleManager() const
Get access to the layer&#39;s style manager.
void setCacheImage(const QString &cacheKey, const QImage &image, const QList< QgsMapLayer * > &dependentLayers=QList< QgsMapLayer * >())
Set the cached image for a particular cacheKey.
QgsRectangle visibleExtent() const
Return the actual extent derived from requested extent that takes takes output image size into accoun...
QMap< QString, QString > layerStyleOverrides() const
Get map of map layer style overrides (key: layer ID, value: style name) where a different style shoul...
bool hasCrsTransformEnabled() const
returns true if projections are enabled for this layer set
static const QString LABEL_CACHE_ID
QgsMapRendererCache ID string for cached label image.
QgsCoordinateTransform layerTransform(QgsMapLayer *layer) const
Return coordinate transform from layer&#39;s CRS to destination CRS.
virtual bool isEditable() const override
Returns true if the provider is in editing mode.
void setCache(QgsMapRendererCache *cache)
Assign a cache to be used for reading and storing rendered images of individual layers.
QgsCoordinateReferenceSystem destinationCrs() const
Returns the destination coordinate reference system, which the transform will transform coordinates t...
The QgsMapSettings class contains configuration for rendering of the map.
static bool staticWillUseLayer(QgsVectorLayer *layer)
called to find out whether the layer is used for labeling
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.
QList< QgsMapLayer * > layers() const
Get list of layers for map rendering The layers are stored in the reverse order of how they are rende...
QPainter::CompositionMode blendMode() const
Returns the current blending mode for a layer.
bool hasScaleBasedVisibility() const
Returns whether scale based visibility is enabled for the layer.
bool isInScaleRange(double scale) const
Tests whether the layer should be visible at the specified scale.
double yMinimum() const
Get the y minimum value (bottom side of rectangle)
Definition: qgsrectangle.h:207
const QgsAbstractVectorLayerLabeling * labeling() const
Access to labeling configuration.
QSize outputSize() const
Return the size of the resulting map image.
double xMaximum() const
Get the x maximum value (right side of rectangle)
Definition: qgsrectangle.h:192
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:37
bool init(const QgsRectangle &extent, double scale)
Initialize cache: set new parameters and clears the cache if any parameters have changed since last i...
const LayerRenderJobs & jobs() const
Enable anti-aliasing for map rendering.
static void logMessage(const QString &message, const QString &tag=QString::null, MessageLevel level=WARNING)
add a message to the instance (and create it if necessary)
QString toString() const
String representation of the point (x,y)
Definition: qgspoint.cpp:163
QString id() const
Returns the layer&#39;s unique ID, which is used to access this layer from QgsProject.
virtual bool requiresAdvancedEffects(QgsVectorLayer *layer) const =0
Returns true if drawing labels requires advanced effects like composition modes, which could prevent ...
A class to represent a point.
Definition: qgspoint.h:143
double minimumScale() const
Returns the minimum scale denominator at which the layer is visible.
QgsMapSettings mSettings
void cleanupLabelJob(LabelRenderJob &job)
Handles clean up tasks for a label job, including deletion of images and storing cached label results...
QColor backgroundColor() const
Get the background color of the map.
Implementation of threaded rendering for vector layers.
bool testFlag(Flag flag) const
Check whether a particular flag is enabled.
int layerTransparency() const
Returns the current transparency for the vector layer.
bool prepareLabelCache() const
Prepares the cache for storing the result of labeling.
The QgsLabelingEngine class provides map labeling functionality.
bool hasCacheImage(const QString &cacheKey) const
Returns true if the cache contains an image with the specified cacheKey.
LayerRenderJobs prepareJobs(QPainter *painter, QgsLabelingEngine *labelingEngine2)
Transform from destination to source CRS.
void logRenderingTime(const LayerRenderJobs &jobs, const LabelRenderJob &labelJob)
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.
QImage::Format outputImageFormat() const
format of internal QImage, default QImage::Format_ARGB32_Premultiplied
Class for doing transforms between two map coordinate systems.
QImage cacheImage(const QString &cacheKey) const
Returns the cached image for the specified cacheKey.
virtual QgsMapLayerRenderer * createMapRenderer(QgsRenderContext &rendererContext)=0
Return new instance of QgsMapLayerRenderer that will be used for rendering of given context...
QgsMapRendererQImageJob(const QgsMapSettings &settings)
QString name
Read property of QString layerName.
Definition: qgsmaplayer.h:56
Transform from source to destination CRS.
QgsPoint transform(const QgsPoint &point, TransformDirection direction=ForwardTransform) const
Transform the point from the source CRS to the destination CRS.
This class is responsible for keeping cache of rendered images resulting from a map rendering job...
bool setOverrideStyle(const QString &styleDef)
Temporarily apply a different style to the layer.
QgsCoordinateReferenceSystem crs() const
Returns the layer&#39;s spatial reference system.
Custom exception class for Coordinate Reference System related exceptions.
static QgsExpressionContextScope * layerScope(const QgsMapLayer *layer)
Creates a new scope which contains variables and functions relating to a QgsMapLayer.
const QgsMapSettings & mapSettings() const
Return map settings with which this job was started.
double width() const
Width of the rectangle.
Definition: qgsrectangle.h:212
Represents a vector layer which manages a vector based data sets.
QString toString(bool automaticPrecision=false) const
returns string representation of form xmin,ymin xmax,ymax
bool isGeographic() const
Returns whether the CRS is a geographic CRS (using lat/lon coordinates)
QgsMapRendererCache * mCache
double xMinimum() const
Get the x minimum value (left side of rectangle)
Definition: qgsrectangle.h:197
int renderingTime() const
Find out how long it took to finish the job (in milliseconds)
QgsMapRendererJob(const QgsMapSettings &settings)
void setXMinimum(double x)
Set the minimum x value.
Definition: qgsrectangle.h:172
double height() const
Height of the rectangle.
Definition: qgsrectangle.h:217
double x
Definition: qgspoint.h:147