QGIS API Documentation  2.99.0-Master (5d67572)
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 
68 {
69  return mSettings;
70 }
71 
73 {
74  bool canCache = mCache;
75 
76  // calculate which layers will be labeled
77  QSet< QgsMapLayer * > labeledLayers;
78  Q_FOREACH ( const QgsMapLayer *ml, mSettings.layers() )
79  {
80  QgsVectorLayer *vl = const_cast< QgsVectorLayer * >( qobject_cast<const QgsVectorLayer *>( ml ) );
81  if ( vl && QgsPalLabeling::staticWillUseLayer( vl ) )
82  labeledLayers << vl;
83  if ( vl && vl->labeling() && vl->labeling()->requiresAdvancedEffects() )
84  {
85  canCache = false;
86  break;
87  }
88  }
89 
91  {
92  // we may need to clear label cache and re-register labeled features - check for that here
93 
94  // can we reuse the cached label solution?
95  bool canUseCache = canCache && mCache->dependentLayers( LABEL_CACHE_ID ).toSet() == labeledLayers;
96  if ( !canUseCache )
97  {
98  // no - participating layers have changed
100  }
101  }
102  return canCache;
103 }
104 
105 
106 bool QgsMapRendererJob::reprojectToLayerExtent( const QgsMapLayer *ml, const QgsCoordinateTransform &ct, QgsRectangle &extent, QgsRectangle &r2 )
107 {
108  bool split = false;
109 
110  try
111  {
112 #ifdef QGISDEBUG
113  // QgsLogger::debug<QgsRectangle>("Getting extent of canvas in layers CS. Canvas is ", extent, __FILE__, __FUNCTION__, __LINE__);
114 #endif
115  // Split the extent into two if the source CRS is
116  // geographic and the extent crosses the split in
117  // geographic coordinates (usually +/- 180 degrees,
118  // and is assumed to be so here), and draw each
119  // extent separately.
120  static const double SPLIT_COORD = 180.0;
121 
122  if ( ml->crs().isGeographic() )
123  {
124  if ( ml->type() == QgsMapLayer::VectorLayer && !ct.destinationCrs().isGeographic() )
125  {
126  // if we transform from a projected coordinate system check
127  // check if transforming back roughly returns the input
128  // extend - otherwise render the world.
131 
132  QgsDebugMsgLevel( QString( "\n0:%1 %2x%3\n1:%4\n2:%5 %6x%7 (w:%8 h:%9)" )
133  .arg( extent.toString() ).arg( extent.width() ).arg( extent.height() )
134  .arg( extent1.toString(), extent2.toString() ).arg( extent2.width() ).arg( extent2.height() )
135  .arg( std::fabs( 1.0 - extent2.width() / extent.width() ) )
136  .arg( std::fabs( 1.0 - extent2.height() / extent.height() ) )
137  , 3 );
138 
139  if ( std::fabs( 1.0 - extent2.width() / extent.width() ) < 0.5 &&
140  std::fabs( 1.0 - extent2.height() / extent.height() ) < 0.5 )
141  {
142  extent = extent1;
143  }
144  else
145  {
146  extent = QgsRectangle( -180.0, -90.0, 180.0, 90.0 );
147  }
148  }
149  else
150  {
151  // Note: ll = lower left point
152  QgsPointXY ll = ct.transform( extent.xMinimum(), extent.yMinimum(),
154 
155  // and ur = upper right point
156  QgsPointXY ur = ct.transform( extent.xMaximum(), extent.yMaximum(),
158 
159  QgsDebugMsg( QString( "in:%1 (ll:%2 ur:%3)" ).arg( extent.toString(), ll.toString(), ur.toString() ) );
160 
162 
163  QgsDebugMsg( QString( "out:%1 (w:%2 h:%3)" ).arg( extent.toString() ).arg( extent.width() ).arg( extent.height() ) );
164 
165  if ( ll.x() > ur.x() )
166  {
167  // the coordinates projected in reverse order than what one would expect.
168  // we are probably looking at an area that includes longitude of 180 degrees.
169  // we need to take into account coordinates from two intervals: (-180,x1) and (x2,180)
170  // so let's use (-180,180). This hopefully does not add too much overhead. It is
171  // more straightforward than rendering with two separate extents and more consistent
172  // for rendering, labeling and caching as everything is rendered just in one go
173  extent.setXMinimum( -SPLIT_COORD );
174  extent.setXMaximum( SPLIT_COORD );
175  }
176  }
177 
178  // TODO: the above rule still does not help if using a projection that covers the whole
179  // world. E.g. with EPSG:3857 the longitude spectrum -180 to +180 is mapped to approx.
180  // -2e7 to +2e7. Converting extent from -5e7 to +5e7 is transformed as -90 to +90,
181  // but in fact the extent should cover the whole world.
182  }
183  else // can't cross 180
184  {
185  if ( ct.destinationCrs().isGeographic() &&
186  ( extent.xMinimum() <= -180 || extent.xMaximum() >= 180 ||
187  extent.yMinimum() <= -90 || extent.yMaximum() >= 90 ) )
188  // Use unlimited rectangle because otherwise we may end up transforming wrong coordinates.
189  // E.g. longitude -200 to +160 would be understood as +40 to +160 due to periodicity.
190  // We could try to clamp coords to (-180,180) for lon resp. (-90,90) for lat,
191  // but this seems like a safer choice.
192  extent = QgsRectangle( -DBL_MAX, -DBL_MAX, DBL_MAX, DBL_MAX );
193  else
195  }
196  }
197  catch ( QgsCsException &cse )
198  {
199  Q_UNUSED( cse );
200  QgsDebugMsg( "Transform error caught" );
201  extent = QgsRectangle( -DBL_MAX, -DBL_MAX, DBL_MAX, DBL_MAX );
202  r2 = QgsRectangle( -DBL_MAX, -DBL_MAX, DBL_MAX, DBL_MAX );
203  }
204 
205  return split;
206 }
207 
208 
209 
210 LayerRenderJobs QgsMapRendererJob::prepareJobs( QPainter *painter, QgsLabelingEngine *labelingEngine2 )
211 {
212  LayerRenderJobs layerJobs;
213 
214  // render all layers in the stack, starting at the base
215  QListIterator<QgsMapLayer *> li( mSettings.layers() );
216  li.toBack();
217 
218  if ( mCache )
219  {
220  bool cacheValid = mCache->init( mSettings.visibleExtent(), mSettings.scale() );
221  Q_UNUSED( cacheValid );
222  QgsDebugMsgLevel( QString( "CACHE VALID: %1" ).arg( cacheValid ), 4 );
223  }
224 
225  bool requiresLabelRedraw = !( mCache && mCache->hasCacheImage( LABEL_CACHE_ID ) );
226 
227  while ( li.hasPrevious() )
228  {
229  QgsMapLayer *ml = li.previous();
230 
231  QgsDebugMsgLevel( QString( "layer %1: minscale:%2 maxscale:%3 scaledepvis:%4 blendmode:%5" )
232  .arg( ml->name() )
233  .arg( ml->minimumScale() )
234  .arg( ml->maximumScale() )
235  .arg( ml->hasScaleBasedVisibility() )
236  .arg( ml->blendMode() )
237  , 3 );
238 
239  if ( !ml->isInScaleRange( mSettings.scale() ) ) //|| mOverview )
240  {
241  QgsDebugMsgLevel( "Layer not rendered because it is not within the defined visibility scale range", 3 );
242  continue;
243  }
244 
247 
248  ct = mSettings.layerTransform( ml );
249  if ( ct.isValid() )
250  {
251  reprojectToLayerExtent( ml, ct, r1, r2 );
252  }
253  QgsDebugMsgLevel( "extent: " + r1.toString(), 3 );
254  if ( !r1.isFinite() || !r2.isFinite() )
255  {
256  mErrors.append( Error( ml->id(), tr( "There was a problem transforming the layer's extent. Layer skipped." ) ) );
257  continue;
258  }
259 
260  // Force render of layers that are being edited
261  // or if there's a labeling engine that needs the layer to register features
262  if ( mCache && ml->type() == QgsMapLayer::VectorLayer )
263  {
264  QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( ml );
265  bool requiresLabeling = false;
266  requiresLabeling = ( labelingEngine2 && QgsPalLabeling::staticWillUseLayer( vl ) ) && requiresLabelRedraw;
267  if ( vl->isEditable() || requiresLabeling )
268  {
269  mCache->clearCacheImage( ml->id() );
270  }
271  }
272 
273  layerJobs.append( LayerRenderJob() );
274  LayerRenderJob &job = layerJobs.last();
275  job.cached = false;
276  job.img = nullptr;
277  job.blendMode = ml->blendMode();
278  job.opacity = 1.0;
279  if ( QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( ml ) )
280  {
281  job.opacity = vl->opacity();
282  }
283  job.layer = ml;
284  job.renderingTime = -1;
285 
287  job.context.expressionContext().appendScope( QgsExpressionContextUtils::layerScope( ml ) );
288  job.context.setPainter( painter );
289  job.context.setLabelingEngine( labelingEngine2 );
290  job.context.setCoordinateTransform( ct );
291  job.context.setExtent( r1 );
292 
293  if ( mFeatureFilterProvider )
294  job.context.setFeatureFilterProvider( mFeatureFilterProvider );
295 
296  // if we can use the cache, let's do it and avoid rendering!
297  if ( mCache && mCache->hasCacheImage( ml->id() ) )
298  {
299  job.cached = true;
300  job.imageInitialized = true;
301  job.img = new QImage( mCache->cacheImage( ml->id() ) );
302  job.renderer = nullptr;
303  job.context.setPainter( nullptr );
304  continue;
305  }
306 
307  // If we are drawing with an alternative blending mode then we need to render to a separate image
308  // before compositing this on the map. This effectively flattens the layer and prevents
309  // blending occurring between objects on the layer
310  if ( mCache || !painter || needTemporaryImage( ml ) )
311  {
312  // Flattened image for drawing when a blending mode is set
313  QImage *mypFlattenedImage = nullptr;
314  mypFlattenedImage = new QImage( mSettings.outputSize().width(),
315  mSettings.outputSize().height(),
317  if ( mypFlattenedImage->isNull() )
318  {
319  mErrors.append( Error( ml->id(), tr( "Insufficient memory for image %1x%2" ).arg( mSettings.outputSize().width() ).arg( mSettings.outputSize().height() ) ) );
320  delete mypFlattenedImage;
321  layerJobs.removeLast();
322  continue;
323  }
324 
325  job.img = mypFlattenedImage;
326  QPainter *mypPainter = new QPainter( job.img );
327  mypPainter->setRenderHint( QPainter::Antialiasing, mSettings.testFlag( QgsMapSettings::Antialiasing ) );
328  job.context.setPainter( mypPainter );
329  }
330 
331  bool hasStyleOverride = mSettings.layerStyleOverrides().contains( ml->id() );
332  if ( hasStyleOverride )
333  ml->styleManager()->setOverrideStyle( mSettings.layerStyleOverrides().value( ml->id() ) );
334 
335  job.renderer = ml->createMapRenderer( job.context );
336 
337  if ( hasStyleOverride )
339 
340  } // while (li.hasPrevious())
341 
342  return layerJobs;
343 }
344 
345 LabelRenderJob QgsMapRendererJob::prepareLabelingJob( QPainter *painter, QgsLabelingEngine *labelingEngine2, bool canUseLabelCache )
346 {
347  LabelRenderJob job;
349  job.context.setPainter( painter );
350  job.context.setLabelingEngine( labelingEngine2 );
351  job.context.setExtent( mSettings.visibleExtent() );
352 
353  // if we can use the cache, let's do it and avoid rendering!
354  bool hasCache = canUseLabelCache && mCache && mCache->hasCacheImage( LABEL_CACHE_ID );
355  if ( hasCache )
356  {
357  job.cached = true;
358  job.complete = true;
359  job.img = new QImage( mCache->cacheImage( LABEL_CACHE_ID ) );
360  job.context.setPainter( nullptr );
361  }
362  else
363  {
364  if ( canUseLabelCache && ( mCache || !painter ) )
365  {
366  // Flattened image for drawing labels
367  QImage *mypFlattenedImage = nullptr;
368  mypFlattenedImage = new QImage( mSettings.outputSize().width(),
369  mSettings.outputSize().height(),
371  if ( mypFlattenedImage->isNull() )
372  {
373  mErrors.append( Error( QStringLiteral( "labels" ), tr( "Insufficient memory for label image %1x%2" ).arg( mSettings.outputSize().width() ).arg( mSettings.outputSize().height() ) ) );
374  delete mypFlattenedImage;
375  }
376  else
377  {
378  job.img = mypFlattenedImage;
379  }
380  }
381  }
382 
383  return job;
384 }
385 
386 
387 void QgsMapRendererJob::cleanupJobs( LayerRenderJobs &jobs )
388 {
389  for ( LayerRenderJobs::iterator it = jobs.begin(); it != jobs.end(); ++it )
390  {
391  LayerRenderJob &job = *it;
392  if ( job.img )
393  {
394  delete job.context.painter();
395  job.context.setPainter( nullptr );
396 
397  if ( mCache && !job.cached && !job.context.renderingStopped() && job.layer )
398  {
399  QgsDebugMsg( "caching image for " + ( job.layer ? job.layer->id() : QString() ) );
400  mCache->setCacheImage( job.layer->id(), *job.img, QList< QgsMapLayer * >() << job.layer );
401  }
402 
403  delete job.img;
404  job.img = nullptr;
405  }
406 
407  if ( job.renderer )
408  {
409  Q_FOREACH ( const QString &message, job.renderer->errors() )
410  mErrors.append( Error( job.renderer->layerId(), message ) );
411 
412  delete job.renderer;
413  job.renderer = nullptr;
414  }
415  }
416 
417 
418  jobs.clear();
419 }
420 
421 void QgsMapRendererJob::cleanupLabelJob( LabelRenderJob &job )
422 {
423  if ( job.img )
424  {
425  if ( mCache && !job.cached && !job.context.renderingStopped() )
426  {
427  QgsDebugMsg( "caching label result image" );
428  mCache->setCacheImage( LABEL_CACHE_ID, *job.img, _qgis_listQPointerToRaw( job.participatingLayers ) );
429  }
430 
431  delete job.img;
432  job.img = nullptr;
433  }
434 }
435 
436 
437 QImage QgsMapRendererJob::composeImage( const QgsMapSettings &settings, const LayerRenderJobs &jobs, const LabelRenderJob &labelJob )
438 {
439  QImage image( settings.outputSize(), settings.outputImageFormat() );
440  image.fill( settings.backgroundColor().rgba() );
441 
442  QPainter painter( &image );
443 
444 
445  for ( LayerRenderJobs::const_iterator it = jobs.constBegin(); it != jobs.constEnd(); ++it )
446  {
447  const LayerRenderJob &job = *it;
448 
449  if ( job.layer && job.layer->customProperty( QStringLiteral( "rendering/renderAboveLabels" ) ).toBool() )
450  continue; // skip layer for now, it will be rendered after labels
451 
452  if ( !job.imageInitialized )
453  continue; // img not safe to compose
454 
455  painter.setCompositionMode( job.blendMode );
456  painter.setOpacity( job.opacity );
457 
458  Q_ASSERT( job.img );
459 
460  painter.drawImage( 0, 0, *job.img );
461  }
462 
463  // IMPORTANT - don't draw labelJob img before the label job is complete,
464  // as the image is uninitialized and full of garbage before the label job
465  // commences
466  if ( labelJob.img && labelJob.complete )
467  {
468  painter.setCompositionMode( QPainter::CompositionMode_SourceOver );
469  painter.setOpacity( 1.0 );
470  painter.drawImage( 0, 0, *labelJob.img );
471  }
472 
473  // render any layers with the renderAboveLabels flag now
474  for ( LayerRenderJobs::const_iterator it = jobs.constBegin(); it != jobs.constEnd(); ++it )
475  {
476  const LayerRenderJob &job = *it;
477 
478  if ( !job.layer || !job.layer->customProperty( QStringLiteral( "rendering/renderAboveLabels" ) ).toBool() )
479  continue;
480 
481  if ( !job.imageInitialized )
482  continue; // img not safe to compose
483 
484  painter.setCompositionMode( job.blendMode );
485  painter.setOpacity( job.opacity );
486 
487  Q_ASSERT( job.img );
488 
489  painter.drawImage( 0, 0, *job.img );
490  }
491 
492  painter.end();
493  return image;
494 }
495 
496 void QgsMapRendererJob::logRenderingTime( const LayerRenderJobs &jobs, const LabelRenderJob &labelJob )
497 {
498  QgsSettings settings;
499  if ( !settings.value( QStringLiteral( "Map/logCanvasRefreshEvent" ), false ).toBool() )
500  return;
501 
502  QMultiMap<int, QString> elapsed;
503  Q_FOREACH ( const LayerRenderJob &job, jobs )
504  elapsed.insert( job.renderingTime, job.layer ? job.layer->id() : QString() );
505 
506  elapsed.insert( labelJob.renderingTime, tr( "Labeling" ) );
507 
508  QList<int> tt( elapsed.uniqueKeys() );
509  std::sort( tt.begin(), tt.end(), std::greater<int>() );
510  Q_FOREACH ( int t, tt )
511  {
512  QgsMessageLog::logMessage( tr( "%1 ms: %2" ).arg( t ).arg( QStringList( elapsed.values( t ) ).join( QStringLiteral( ", " ) ) ), tr( "Rendering" ) );
513  }
514  QgsMessageLog::logMessage( QStringLiteral( "---" ), tr( "Rendering" ) );
515 }
516 
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.
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:83
This class is a composition of two QSettings instances:
Definition: qgssettings.h:55
void cleanupJobs(LayerRenderJobs &jobs)
#define QgsDebugMsg(str)
Definition: qgslogger.h:37
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.
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.
virtual 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...
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 ...
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:38
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:131
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.
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:119
double xMaximum() const
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:104
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.
static void logMessage(const QString &message, const QString &tag=QString(), MessageLevel level=QgsMessageLog::WARNING)
add a message to the instance (and create it if necessary)
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
QString toString() const
String representation of the point (x,y)
Definition: qgspointxy.cpp:45
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:109
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:114
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:66
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:78
QPainter::CompositionMode blendMode() const
Returns the current blending mode for a layer.
double height() const
Returns the height of the rectangle.
Definition: qgsrectangle.h:138