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