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