QGIS API Documentation  3.8.0-Zanzibar (11aff65)
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"
40 
42 
43 const QString QgsMapRendererJob::LABEL_CACHE_ID = QStringLiteral( "_labels_" );
44 
46  : mSettings( settings )
47 
48 {
49 }
50 
51 
53  : QgsMapRendererJob( settings )
54 {
55 }
56 
57 
59 {
60  return mErrors;
61 }
62 
64 {
65  mCache = cache;
66 }
67 
68 QHash<QgsMapLayer *, int> QgsMapRendererJob::perLayerRenderingTime() const
69 {
70  QHash<QgsMapLayer *, int> result;
71  for ( auto it = mPerLayerRenderingTime.constBegin(); it != mPerLayerRenderingTime.constEnd(); ++it )
72  {
73  if ( it.key() )
74  result.insert( it.key(), it.value() );
75  }
76  return result;
77 }
78 
80 {
81  return mSettings;
82 }
83 
85 {
86  bool canCache = mCache;
87 
88  // calculate which layers will be labeled
89  QSet< QgsMapLayer * > labeledLayers;
90  const QList<QgsMapLayer *> layers = mSettings.layers();
91  for ( const QgsMapLayer *ml : layers )
92  {
93  QgsVectorLayer *vl = const_cast< QgsVectorLayer * >( qobject_cast<const QgsVectorLayer *>( ml ) );
94  if ( vl && QgsPalLabeling::staticWillUseLayer( vl ) )
95  labeledLayers << vl;
96  if ( vl && vl->labelsEnabled() && vl->labeling()->requiresAdvancedEffects() )
97  {
98  canCache = false;
99  break;
100  }
101  }
102 
104  {
105  // we may need to clear label cache and re-register labeled features - check for that here
106 
107  // can we reuse the cached label solution?
108  bool canUseCache = canCache && mCache->dependentLayers( LABEL_CACHE_ID ).toSet() == labeledLayers;
109  if ( !canUseCache )
110  {
111  // no - participating layers have changed
113  }
114  }
115  return canCache;
116 }
117 
118 
119 bool QgsMapRendererJob::reprojectToLayerExtent( const QgsMapLayer *ml, const QgsCoordinateTransform &ct, QgsRectangle &extent, QgsRectangle &r2 )
120 {
121  bool split = false;
122 
123  try
124  {
125 #ifdef QGISDEBUG
126  // QgsLogger::debug<QgsRectangle>("Getting extent of canvas in layers CS. Canvas is ", extent, __FILE__, __FUNCTION__, __LINE__);
127 #endif
128  // Split the extent into two if the source CRS is
129  // geographic and the extent crosses the split in
130  // geographic coordinates (usually +/- 180 degrees,
131  // and is assumed to be so here), and draw each
132  // extent separately.
133  static const double SPLIT_COORD = 180.0;
134 
135  if ( ml->crs().isGeographic() )
136  {
138  {
139  // if we transform from a projected coordinate system check
140  // check if transforming back roughly returns the input
141  // extend - otherwise render the world.
144 
145  QgsDebugMsgLevel( QStringLiteral( "\n0:%1 %2x%3\n1:%4\n2:%5 %6x%7 (w:%8 h:%9)" )
146  .arg( extent.toString() ).arg( extent.width() ).arg( extent.height() )
147  .arg( extent1.toString(), extent2.toString() ).arg( extent2.width() ).arg( extent2.height() )
148  .arg( std::fabs( 1.0 - extent2.width() / extent.width() ) )
149  .arg( std::fabs( 1.0 - extent2.height() / extent.height() ) )
150  , 3 );
151 
152  if ( std::fabs( 1.0 - extent2.width() / extent.width() ) < 0.5 &&
153  std::fabs( 1.0 - extent2.height() / extent.height() ) < 0.5 )
154  {
155  extent = extent1;
156  }
157  else
158  {
159  extent = QgsRectangle( -180.0, -90.0, 180.0, 90.0 );
160  }
161  }
162  else
163  {
164  // Note: ll = lower left point
165  QgsPointXY ll = ct.transform( extent.xMinimum(), extent.yMinimum(),
167 
168  // and ur = upper right point
169  QgsPointXY ur = ct.transform( extent.xMaximum(), extent.yMaximum(),
171 
172  QgsDebugMsgLevel( QStringLiteral( "in:%1 (ll:%2 ur:%3)" ).arg( extent.toString(), ll.toString(), ur.toString() ), 4 );
173 
175 
176  QgsDebugMsgLevel( QStringLiteral( "out:%1 (w:%2 h:%3)" ).arg( extent.toString() ).arg( extent.width() ).arg( extent.height() ), 4 );
177 
178  if ( ll.x() > ur.x() )
179  {
180  // the coordinates projected in reverse order than what one would expect.
181  // we are probably looking at an area that includes longitude of 180 degrees.
182  // we need to take into account coordinates from two intervals: (-180,x1) and (x2,180)
183  // so let's use (-180,180). This hopefully does not add too much overhead. It is
184  // more straightforward than rendering with two separate extents and more consistent
185  // for rendering, labeling and caching as everything is rendered just in one go
186  extent.setXMinimum( -SPLIT_COORD );
187  extent.setXMaximum( SPLIT_COORD );
188  }
189  }
190 
191  // TODO: the above rule still does not help if using a projection that covers the whole
192  // world. E.g. with EPSG:3857 the longitude spectrum -180 to +180 is mapped to approx.
193  // -2e7 to +2e7. Converting extent from -5e7 to +5e7 is transformed as -90 to +90,
194  // but in fact the extent should cover the whole world.
195  }
196  else // can't cross 180
197  {
198  if ( ct.destinationCrs().isGeographic() &&
199  ( extent.xMinimum() <= -180 || extent.xMaximum() >= 180 ||
200  extent.yMinimum() <= -90 || extent.yMaximum() >= 90 ) )
201  // Use unlimited rectangle because otherwise we may end up transforming wrong coordinates.
202  // E.g. longitude -200 to +160 would be understood as +40 to +160 due to periodicity.
203  // We could try to clamp coords to (-180,180) for lon resp. (-90,90) for lat,
204  // but this seems like a safer choice.
205  extent = QgsRectangle( std::numeric_limits<double>::lowest(), std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max(), std::numeric_limits<double>::max() );
206  else
208  }
209  }
210  catch ( QgsCsException &cse )
211  {
212  Q_UNUSED( cse )
213  QgsDebugMsg( QStringLiteral( "Transform error caught" ) );
214  extent = QgsRectangle( std::numeric_limits<double>::lowest(), std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max(), std::numeric_limits<double>::max() );
215  r2 = QgsRectangle( std::numeric_limits<double>::lowest(), std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max(), std::numeric_limits<double>::max() );
216  }
217 
218  return split;
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( QStringLiteral( "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( QStringLiteral( "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( QStringLiteral( "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() == QgsMapLayerType::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.layer = ml;
289  job.renderingTime = -1;
290 
292  job.context.expressionContext().appendScope( QgsExpressionContextUtils::layerScope( ml ) );
293  job.context.setPainter( painter );
294  job.context.setLabelingEngine( labelingEngine2 );
295  job.context.setCoordinateTransform( ct );
296  job.context.setExtent( r1 );
297 
298  if ( mFeatureFilterProvider )
299  job.context.setFeatureFilterProvider( mFeatureFilterProvider );
300 
301  QgsMapLayerStyleOverride styleOverride( ml );
302  if ( mSettings.layerStyleOverrides().contains( ml->id() ) )
303  styleOverride.setOverrideStyle( mSettings.layerStyleOverrides().value( ml->id() ) );
304 
305  job.blendMode = ml->blendMode();
306  job.opacity = 1.0;
307  if ( QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( ml ) )
308  {
309  job.opacity = vl->opacity();
310  }
311 
312  // if we can use the cache, let's do it and avoid rendering!
313  if ( mCache && mCache->hasCacheImage( ml->id() ) )
314  {
315  job.cached = true;
316  job.imageInitialized = true;
317  job.img = new QImage( mCache->cacheImage( ml->id() ) );
318  job.img->setDevicePixelRatio( static_cast<qreal>( mSettings.devicePixelRatio() ) );
319  job.renderer = nullptr;
320  job.context.setPainter( nullptr );
321  continue;
322  }
323 
324  // If we are drawing with an alternative blending mode then we need to render to a separate image
325  // before compositing this on the map. This effectively flattens the layer and prevents
326  // blending occurring between objects on the layer
327  if ( mCache || !painter || needTemporaryImage( ml ) )
328  {
329  // Flattened image for drawing when a blending mode is set
330  QImage *mypFlattenedImage = new QImage( mSettings.deviceOutputSize(),
332  mypFlattenedImage->setDevicePixelRatio( static_cast<qreal>( mSettings.devicePixelRatio() ) );
333  if ( mypFlattenedImage->isNull() )
334  {
335  mErrors.append( Error( ml->id(), tr( "Insufficient memory for image %1x%2" ).arg( mSettings.outputSize().width() ).arg( mSettings.outputSize().height() ) ) );
336  delete mypFlattenedImage;
337  layerJobs.removeLast();
338  continue;
339  }
340 
341  job.img = mypFlattenedImage;
342  QPainter *mypPainter = new QPainter( job.img );
343  mypPainter->setRenderHint( QPainter::Antialiasing, mSettings.testFlag( QgsMapSettings::Antialiasing ) );
344  job.context.setPainter( mypPainter );
345  }
346 
347  QTime layerTime;
348  layerTime.start();
349  job.renderer = ml->createMapRenderer( job.context );
350  job.renderingTime = layerTime.elapsed(); // include job preparation time in layer rendering time
351  } // while (li.hasPrevious())
352 
353  return layerJobs;
354 }
355 
356 LabelRenderJob QgsMapRendererJob::prepareLabelingJob( QPainter *painter, QgsLabelingEngine *labelingEngine2, bool canUseLabelCache )
357 {
358  LabelRenderJob job;
360  job.context.setPainter( painter );
361  job.context.setLabelingEngine( labelingEngine2 );
362  job.context.setExtent( mSettings.visibleExtent() );
363  job.context.setFeatureFilterProvider( mFeatureFilterProvider );
364 
365  // if we can use the cache, let's do it and avoid rendering!
366  bool hasCache = canUseLabelCache && mCache && mCache->hasCacheImage( LABEL_CACHE_ID );
367  if ( hasCache )
368  {
369  job.cached = true;
370  job.complete = true;
371  job.img = new QImage( mCache->cacheImage( LABEL_CACHE_ID ) );
372  Q_ASSERT( job.img->devicePixelRatio() == mSettings.devicePixelRatio() );
373  job.context.setPainter( nullptr );
374  }
375  else
376  {
377  if ( canUseLabelCache && ( mCache || !painter ) )
378  {
379  // Flattened image for drawing labels
380  QImage *mypFlattenedImage = nullptr;
381  mypFlattenedImage = new QImage( mSettings.deviceOutputSize(),
383  mypFlattenedImage->setDevicePixelRatio( mSettings.devicePixelRatio() );
384  if ( mypFlattenedImage->isNull() )
385  {
386  mErrors.append( Error( QStringLiteral( "labels" ), tr( "Insufficient memory for label image %1x%2" ).arg( mSettings.outputSize().width() ).arg( mSettings.outputSize().height() ) ) );
387  delete mypFlattenedImage;
388  }
389  else
390  {
391  job.img = mypFlattenedImage;
392  }
393  }
394  }
395 
396  return job;
397 }
398 
399 
400 void QgsMapRendererJob::cleanupJobs( LayerRenderJobs &jobs )
401 {
402  for ( LayerRenderJobs::iterator it = jobs.begin(); it != jobs.end(); ++it )
403  {
404  LayerRenderJob &job = *it;
405  if ( job.img )
406  {
407  delete job.context.painter();
408  job.context.setPainter( nullptr );
409 
410  if ( mCache && !job.cached && !job.context.renderingStopped() && job.layer )
411  {
412  QgsDebugMsgLevel( "caching image for " + ( job.layer ? job.layer->id() : QString() ), 2 );
413  mCache->setCacheImage( job.layer->id(), *job.img, QList< QgsMapLayer * >() << job.layer );
414  }
415 
416  delete job.img;
417  job.img = nullptr;
418  }
419 
420  if ( job.renderer )
421  {
422  const auto constErrors = job.renderer->errors();
423  for ( const QString &message : constErrors )
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( QStringLiteral( "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.deviceOutputSize(), settings.outputImageFormat() );
456  image.setDevicePixelRatio( settings.devicePixelRatio() );
457  image.fill( settings.backgroundColor().rgba() );
458 
459  QPainter painter( &image );
460 
461 
462  for ( LayerRenderJobs::const_iterator it = jobs.constBegin(); it != jobs.constEnd(); ++it )
463  {
464  const LayerRenderJob &job = *it;
465 
466  if ( job.layer && job.layer->customProperty( QStringLiteral( "rendering/renderAboveLabels" ) ).toBool() )
467  continue; // skip layer for now, it will be rendered after labels
468 
469  if ( !job.imageInitialized )
470  continue; // img not safe to compose
471 
472  painter.setCompositionMode( job.blendMode );
473  painter.setOpacity( job.opacity );
474 
475  Q_ASSERT( job.img );
476 
477  painter.drawImage( 0, 0, *job.img );
478  }
479 
480  // IMPORTANT - don't draw labelJob img before the label job is complete,
481  // as the image is uninitialized and full of garbage before the label job
482  // commences
483  if ( labelJob.img && labelJob.complete )
484  {
485  painter.setCompositionMode( QPainter::CompositionMode_SourceOver );
486  painter.setOpacity( 1.0 );
487  painter.drawImage( 0, 0, *labelJob.img );
488  }
489 
490  // render any layers with the renderAboveLabels flag now
491  for ( LayerRenderJobs::const_iterator it = jobs.constBegin(); it != jobs.constEnd(); ++it )
492  {
493  const LayerRenderJob &job = *it;
494 
495  if ( !job.layer || !job.layer->customProperty( QStringLiteral( "rendering/renderAboveLabels" ) ).toBool() )
496  continue;
497 
498  if ( !job.imageInitialized )
499  continue; // img not safe to compose
500 
501  painter.setCompositionMode( job.blendMode );
502  painter.setOpacity( job.opacity );
503 
504  Q_ASSERT( job.img );
505 
506  painter.drawImage( 0, 0, *job.img );
507  }
508 
509  painter.end();
510  return image;
511 }
512 
513 void QgsMapRendererJob::logRenderingTime( const LayerRenderJobs &jobs, const LabelRenderJob &labelJob )
514 {
515  QgsSettings settings;
516  if ( !settings.value( QStringLiteral( "Map/logCanvasRefreshEvent" ), false ).toBool() )
517  return;
518 
519  QMultiMap<int, QString> elapsed;
520  const auto constJobs = jobs;
521  for ( const LayerRenderJob &job : constJobs )
522  elapsed.insert( job.renderingTime, job.layer ? job.layer->id() : QString() );
523 
524  elapsed.insert( labelJob.renderingTime, tr( "Labeling" ) );
525 
526  QList<int> tt( elapsed.uniqueKeys() );
527  std::sort( tt.begin(), tt.end(), std::greater<int>() );
528  const auto constTt = tt;
529  for ( int t : constTt )
530  {
531  QgsMessageLog::logMessage( tr( "%1 ms: %2" ).arg( t ).arg( QStringList( elapsed.values( t ) ).join( QStringLiteral( ", " ) ) ), tr( "Rendering" ) );
532  }
533  QgsMessageLog::logMessage( QStringLiteral( "---" ), tr( "Rendering" ) );
534 }
535 
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:41
Base class for all map layer types.
Definition: qgsmaplayer.h:78
const LayerRenderJobs & jobs() const
Abstract base class for map rendering implementations.
QgsMapLayerType type() const
Returns the type of the layer.
void setXMaximum(double x)
Set the maximum x value.
Definition: qgsrectangle.h:135
This class is a composition of two QSettings instances:
Definition: qgssettings.h:58
void cleanupJobs(LayerRenderJobs &jobs)
Restore overridden layer style on destruction.
QSize deviceOutputSize() const
Returns the device output size of the map canvas This is equivalent to the output size multiplicated ...
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
QgsPointXY transform(const QgsPointXY &point, TransformDirection direction=ForwardTransform) const SIP_THROW(QgsCsException)
Transform the point from the source CRS to the destination CRS.
A class to represent a 2D point.
Definition: qgspointxy.h:43
QColor backgroundColor() const
Gets 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.
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:40
QList< QgsMapLayer * > layers() const
Gets list of layers for map rendering The layers are stored in the reverse order of how they are rend...
static const QString LABEL_CACHE_ID
QgsMapRendererCache ID string for cached label image.
QgsRectangle visibleExtent() const
Returns the actual extent derived from requested extent that takes takes output image size into accou...
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.
static bool staticWillUseLayer(QgsVectorLayer *layer)
called to find out whether the layer is used for labeling
QgsCoordinateTransform layerTransform(const QgsMapLayer *layer) const
Returns the 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 isEditable() const FINAL
Returns true if the provider is in editing mode.
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:202
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
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
QImage cacheImage(const QString &cacheKey) const
Returns the cached image for the specified cacheKey.
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.
float devicePixelRatio() const
Returns device pixel ratio Common values are 1 for normal-dpi displays and 2 for high-dpi "retina" di...
QgsMapSettings mSettings
bool isFinite() const
Returns true if the rectangle has finite boundaries.
Definition: qgsrectangle.h:516
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:177
double xMaximum() const
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:162
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
Gets map of map layer style overrides (key: layer ID, value: style name) where a different style shou...
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.
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:167
virtual QgsMapLayerRenderer * createMapRenderer(QgsRenderContext &rendererContext)=0
Returns 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:172
QString name
Definition: qgsmaplayer.h:82
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.
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
Returns map settings with which this job was started.
QgsMapRendererCache * mCache
QSize outputSize() const
Returns the size of the resulting map image.
QgsMapRendererJob(const QgsMapSettings &settings)
QgsRectangle transformBoundingBox(const QgsRectangle &rectangle, TransformDirection direction=ForwardTransform, bool handle180Crossover=false) const SIP_THROW(QgsCsException)
Transforms a rectangle from the source CRS to the destination CRS.
void setXMinimum(double x)
Set the minimum x value.
Definition: qgsrectangle.h:130
QgsCoordinateReferenceSystem crs
Definition: qgsmaplayer.h:85
QPainter::CompositionMode blendMode() const
Returns the current blending mode for a layer.
double height() const
Returns the height of the rectangle.
Definition: qgsrectangle.h:209