QGIS API Documentation  3.10.0-A Coruña (6c816b4204)
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 #include "qgsrenderer.h"
41 
43 
44 const QString QgsMapRendererJob::LABEL_CACHE_ID = QStringLiteral( "_labels_" );
45 
47  : mSettings( settings )
48 
49 {
50 }
51 
52 
54  : QgsMapRendererJob( settings )
55 {
56 }
57 
58 
60 {
61  return mErrors;
62 }
63 
65 {
66  mCache = cache;
67 }
68 
69 QHash<QgsMapLayer *, int> QgsMapRendererJob::perLayerRenderingTime() const
70 {
71  QHash<QgsMapLayer *, int> result;
72  for ( auto it = mPerLayerRenderingTime.constBegin(); it != mPerLayerRenderingTime.constEnd(); ++it )
73  {
74  if ( it.key() )
75  result.insert( it.key(), it.value() );
76  }
77  return result;
78 }
79 
81 {
82  return mSettings;
83 }
84 
86 {
87  bool canCache = mCache;
88 
89  // calculate which layers will be labeled
90  QSet< QgsMapLayer * > labeledLayers;
91  const QList<QgsMapLayer *> layers = mSettings.layers();
92  for ( const QgsMapLayer *ml : layers )
93  {
94  QgsVectorLayer *vl = const_cast< QgsVectorLayer * >( qobject_cast<const QgsVectorLayer *>( ml ) );
95  if ( vl && QgsPalLabeling::staticWillUseLayer( vl ) )
96  labeledLayers << vl;
97  if ( vl && vl->labelsEnabled() && vl->labeling()->requiresAdvancedEffects() )
98  {
99  canCache = false;
100  break;
101  }
102  }
103 
105  {
106  // we may need to clear label cache and re-register labeled features - check for that here
107 
108  // can we reuse the cached label solution?
109  bool canUseCache = canCache && mCache->dependentLayers( LABEL_CACHE_ID ).toSet() == labeledLayers;
110  if ( !canUseCache )
111  {
112  // no - participating layers have changed
114  }
115  }
116  return canCache;
117 }
118 
119 
120 bool QgsMapRendererJob::reprojectToLayerExtent( const QgsMapLayer *ml, const QgsCoordinateTransform &ct, QgsRectangle &extent, QgsRectangle &r2 )
121 {
122  bool split = false;
123 
124  try
125  {
126 #ifdef QGISDEBUG
127  // QgsLogger::debug<QgsRectangle>("Getting extent of canvas in layers CS. Canvas is ", extent, __FILE__, __FUNCTION__, __LINE__);
128 #endif
129  // Split the extent into two if the source CRS is
130  // geographic and the extent crosses the split in
131  // geographic coordinates (usually +/- 180 degrees,
132  // and is assumed to be so here), and draw each
133  // extent separately.
134  static const double SPLIT_COORD = 180.0;
135 
136  if ( ml->crs().isGeographic() )
137  {
139  {
140  // if we transform from a projected coordinate system check
141  // check if transforming back roughly returns the input
142  // extend - otherwise render the world.
145 
146  QgsDebugMsgLevel( QStringLiteral( "\n0:%1 %2x%3\n1:%4\n2:%5 %6x%7 (w:%8 h:%9)" )
147  .arg( extent.toString() ).arg( extent.width() ).arg( extent.height() )
148  .arg( extent1.toString(), extent2.toString() ).arg( extent2.width() ).arg( extent2.height() )
149  .arg( std::fabs( 1.0 - extent2.width() / extent.width() ) )
150  .arg( std::fabs( 1.0 - extent2.height() / extent.height() ) )
151  , 3 );
152 
153  if ( std::fabs( 1.0 - extent2.width() / extent.width() ) < 0.5 &&
154  std::fabs( 1.0 - extent2.height() / extent.height() ) < 0.5 )
155  {
156  extent = extent1;
157  }
158  else
159  {
160  extent = QgsRectangle( -180.0, -90.0, 180.0, 90.0 );
161  }
162  }
163  else
164  {
165  // Note: ll = lower left point
166  QgsPointXY ll = ct.transform( extent.xMinimum(), extent.yMinimum(),
168 
169  // and ur = upper right point
170  QgsPointXY ur = ct.transform( extent.xMaximum(), extent.yMaximum(),
172 
173  QgsDebugMsgLevel( QStringLiteral( "in:%1 (ll:%2 ur:%3)" ).arg( extent.toString(), ll.toString(), ur.toString() ), 4 );
174 
176 
177  QgsDebugMsgLevel( QStringLiteral( "out:%1 (w:%2 h:%3)" ).arg( extent.toString() ).arg( extent.width() ).arg( extent.height() ), 4 );
178 
179  if ( ll.x() > ur.x() )
180  {
181  // the coordinates projected in reverse order than what one would expect.
182  // we are probably looking at an area that includes longitude of 180 degrees.
183  // we need to take into account coordinates from two intervals: (-180,x1) and (x2,180)
184  // so let's use (-180,180). This hopefully does not add too much overhead. It is
185  // more straightforward than rendering with two separate extents and more consistent
186  // for rendering, labeling and caching as everything is rendered just in one go
187  extent.setXMinimum( -SPLIT_COORD );
188  extent.setXMaximum( SPLIT_COORD );
189  }
190  }
191 
192  // TODO: the above rule still does not help if using a projection that covers the whole
193  // world. E.g. with EPSG:3857 the longitude spectrum -180 to +180 is mapped to approx.
194  // -2e7 to +2e7. Converting extent from -5e7 to +5e7 is transformed as -90 to +90,
195  // but in fact the extent should cover the whole world.
196  }
197  else // can't cross 180
198  {
199  if ( ct.destinationCrs().isGeographic() &&
200  ( extent.xMinimum() <= -180 || extent.xMaximum() >= 180 ||
201  extent.yMinimum() <= -90 || extent.yMaximum() >= 90 ) )
202  // Use unlimited rectangle because otherwise we may end up transforming wrong coordinates.
203  // E.g. longitude -200 to +160 would be understood as +40 to +160 due to periodicity.
204  // We could try to clamp coords to (-180,180) for lon resp. (-90,90) for lat,
205  // but this seems like a safer choice.
206  extent = QgsRectangle( std::numeric_limits<double>::lowest(), std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max(), std::numeric_limits<double>::max() );
207  else
209  }
210  }
211  catch ( QgsCsException &cse )
212  {
213  Q_UNUSED( cse )
214  QgsDebugMsg( QStringLiteral( "Transform error caught" ) );
215  extent = QgsRectangle( std::numeric_limits<double>::lowest(), std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max(), std::numeric_limits<double>::max() );
216  r2 = QgsRectangle( std::numeric_limits<double>::lowest(), std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max(), std::numeric_limits<double>::max() );
217  }
218 
219  return split;
220 }
221 
222 LayerRenderJobs QgsMapRendererJob::prepareJobs( QPainter *painter, QgsLabelingEngine *labelingEngine2, bool deferredPainterSet )
223 {
224  LayerRenderJobs layerJobs;
225 
226  // render all layers in the stack, starting at the base
227  QListIterator<QgsMapLayer *> li( mSettings.layers() );
228  li.toBack();
229 
230  if ( mCache )
231  {
232  bool cacheValid = mCache->init( mSettings.visibleExtent(), mSettings.scale() );
233  Q_UNUSED( cacheValid )
234  QgsDebugMsgLevel( QStringLiteral( "CACHE VALID: %1" ).arg( cacheValid ), 4 );
235  }
236 
237  bool requiresLabelRedraw = !( mCache && mCache->hasCacheImage( LABEL_CACHE_ID ) );
238 
239  while ( li.hasPrevious() )
240  {
241  QgsMapLayer *ml = li.previous();
242 
243  QgsDebugMsgLevel( QStringLiteral( "layer %1: minscale:%2 maxscale:%3 scaledepvis:%4 blendmode:%5 isValid:%6" )
244  .arg( ml->name() )
245  .arg( ml->minimumScale() )
246  .arg( ml->maximumScale() )
247  .arg( ml->hasScaleBasedVisibility() )
248  .arg( ml->blendMode() )
249  .arg( ml->isValid() )
250  , 3 );
251 
252  if ( !ml->isValid() )
253  {
254  QgsDebugMsgLevel( QStringLiteral( "Invalid Layer skipped" ), 3 );
255  continue;
256  }
257 
258  if ( !ml->isInScaleRange( mSettings.scale() ) ) //|| mOverview )
259  {
260  QgsDebugMsgLevel( QStringLiteral( "Layer not rendered because it is not within the defined visibility scale range" ), 3 );
261  continue;
262  }
263 
265  r1.grow( mSettings.extentBuffer() );
267 
268  ct = mSettings.layerTransform( ml );
269  if ( ct.isValid() )
270  {
271  reprojectToLayerExtent( ml, ct, r1, r2 );
272  }
273  QgsDebugMsgLevel( "extent: " + r1.toString(), 3 );
274  if ( !r1.isFinite() || !r2.isFinite() )
275  {
276  mErrors.append( Error( ml->id(), tr( "There was a problem transforming the layer's extent. Layer skipped." ) ) );
277  continue;
278  }
279 
280  // Force render of layers that are being edited
281  // or if there's a labeling engine that needs the layer to register features
282  if ( mCache && ml->type() == QgsMapLayerType::VectorLayer )
283  {
284  QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( ml );
285  bool requiresLabeling = false;
286  requiresLabeling = ( labelingEngine2 && QgsPalLabeling::staticWillUseLayer( vl ) ) && requiresLabelRedraw;
287  if ( vl->isEditable() || requiresLabeling )
288  {
289  mCache->clearCacheImage( ml->id() );
290  }
291  }
292 
293  layerJobs.append( LayerRenderJob() );
294  LayerRenderJob &job = layerJobs.last();
295  job.cached = false;
296  job.img = nullptr;
297  job.layer = ml;
298  job.layerId = ml->id();
299  job.renderingTime = -1;
300 
302  job.context.expressionContext().appendScope( QgsExpressionContextUtils::layerScope( ml ) );
303  job.context.setPainter( painter );
304  job.context.setLabelingEngine( labelingEngine2 );
305  job.context.setCoordinateTransform( ct );
306  job.context.setExtent( r1 );
307 
308  if ( mFeatureFilterProvider )
309  job.context.setFeatureFilterProvider( mFeatureFilterProvider );
310 
311  QgsMapLayerStyleOverride styleOverride( ml );
312  if ( mSettings.layerStyleOverrides().contains( ml->id() ) )
313  styleOverride.setOverrideStyle( mSettings.layerStyleOverrides().value( ml->id() ) );
314 
315  job.blendMode = ml->blendMode();
316  job.opacity = 1.0;
317  if ( QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( ml ) )
318  {
319  job.opacity = vl->opacity();
320  }
321 
322  // if we can use the cache, let's do it and avoid rendering!
323  if ( mCache && mCache->hasCacheImage( ml->id() ) )
324  {
325  job.cached = true;
326  job.imageInitialized = true;
327  job.img = new QImage( mCache->cacheImage( ml->id() ) );
328  job.img->setDevicePixelRatio( static_cast<qreal>( mSettings.devicePixelRatio() ) );
329  job.renderer = nullptr;
330  job.context.setPainter( nullptr );
331  continue;
332  }
333 
334  // If we are drawing with an alternative blending mode then we need to render to a separate image
335  // before compositing this on the map. This effectively flattens the layer and prevents
336  // blending occurring between objects on the layer
337  if ( mCache || ( !painter && !deferredPainterSet ) || needTemporaryImage( ml ) )
338  {
339  // Flattened image for drawing when a blending mode is set
340  QImage *mypFlattenedImage = new QImage( mSettings.deviceOutputSize(),
342  mypFlattenedImage->setDevicePixelRatio( static_cast<qreal>( mSettings.devicePixelRatio() ) );
343  if ( mypFlattenedImage->isNull() )
344  {
345  mErrors.append( Error( ml->id(), tr( "Insufficient memory for image %1x%2" ).arg( mSettings.outputSize().width() ).arg( mSettings.outputSize().height() ) ) );
346  delete mypFlattenedImage;
347  layerJobs.removeLast();
348  continue;
349  }
350 
351  job.img = mypFlattenedImage;
352  QPainter *mypPainter = new QPainter( job.img );
353  mypPainter->setRenderHint( QPainter::Antialiasing, mSettings.testFlag( QgsMapSettings::Antialiasing ) );
354  job.context.setPainter( mypPainter );
355  }
356 
357  QTime layerTime;
358  layerTime.start();
359  job.renderer = ml->createMapRenderer( job.context );
360  job.renderingTime = layerTime.elapsed(); // include job preparation time in layer rendering time
361  } // while (li.hasPrevious())
362 
363  return layerJobs;
364 }
365 
366 LabelRenderJob QgsMapRendererJob::prepareLabelingJob( QPainter *painter, QgsLabelingEngine *labelingEngine2, bool canUseLabelCache )
367 {
368  LabelRenderJob job;
370  job.context.setPainter( painter );
371  job.context.setLabelingEngine( labelingEngine2 );
372  job.context.setExtent( mSettings.visibleExtent() );
373  job.context.setFeatureFilterProvider( mFeatureFilterProvider );
374 
375  // if we can use the cache, let's do it and avoid rendering!
376  bool hasCache = canUseLabelCache && mCache && mCache->hasCacheImage( LABEL_CACHE_ID );
377  if ( hasCache )
378  {
379  job.cached = true;
380  job.complete = true;
381  job.img = new QImage( mCache->cacheImage( LABEL_CACHE_ID ) );
382  Q_ASSERT( job.img->devicePixelRatio() == mSettings.devicePixelRatio() );
383  job.context.setPainter( nullptr );
384  }
385  else
386  {
387  if ( canUseLabelCache && ( mCache || !painter ) )
388  {
389  // Flattened image for drawing labels
390  QImage *mypFlattenedImage = nullptr;
391  mypFlattenedImage = new QImage( mSettings.deviceOutputSize(),
393  mypFlattenedImage->setDevicePixelRatio( mSettings.devicePixelRatio() );
394  if ( mypFlattenedImage->isNull() )
395  {
396  mErrors.append( Error( QStringLiteral( "labels" ), tr( "Insufficient memory for label image %1x%2" ).arg( mSettings.outputSize().width() ).arg( mSettings.outputSize().height() ) ) );
397  delete mypFlattenedImage;
398  }
399  else
400  {
401  job.img = mypFlattenedImage;
402  }
403  }
404  }
405 
406  return job;
407 }
408 
409 
410 void QgsMapRendererJob::cleanupJobs( LayerRenderJobs &jobs )
411 {
412  for ( LayerRenderJobs::iterator it = jobs.begin(); it != jobs.end(); ++it )
413  {
414  LayerRenderJob &job = *it;
415  if ( job.img )
416  {
417  delete job.context.painter();
418  job.context.setPainter( nullptr );
419 
420  if ( mCache && !job.cached && !job.context.renderingStopped() && job.layer )
421  {
422  QgsDebugMsgLevel( QStringLiteral( "caching image for %1" ).arg( job.layerId ), 2 );
423  mCache->setCacheImage( job.layerId, *job.img, QList< QgsMapLayer * >() << job.layer );
424  }
425 
426  delete job.img;
427  job.img = nullptr;
428  }
429 
430  if ( job.renderer )
431  {
432  const auto constErrors = job.renderer->errors();
433  for ( const QString &message : constErrors )
434  mErrors.append( Error( job.renderer->layerId(), message ) );
435 
436  delete job.renderer;
437  job.renderer = nullptr;
438  }
439 
440  if ( job.layer )
441  mPerLayerRenderingTime.insert( job.layer, job.renderingTime );
442  }
443 
444  jobs.clear();
445 }
446 
447 void QgsMapRendererJob::cleanupLabelJob( LabelRenderJob &job )
448 {
449  if ( job.img )
450  {
451  if ( mCache && !job.cached && !job.context.renderingStopped() )
452  {
453  QgsDebugMsgLevel( QStringLiteral( "caching label result image" ), 2 );
454  mCache->setCacheImage( LABEL_CACHE_ID, *job.img, _qgis_listQPointerToRaw( job.participatingLayers ) );
455  }
456 
457  delete job.img;
458  job.img = nullptr;
459  }
460 }
461 
462 
463 QImage QgsMapRendererJob::composeImage( const QgsMapSettings &settings, const LayerRenderJobs &jobs, const LabelRenderJob &labelJob )
464 {
465  QImage image( settings.deviceOutputSize(), settings.outputImageFormat() );
466  image.setDevicePixelRatio( settings.devicePixelRatio() );
467  image.fill( settings.backgroundColor().rgba() );
468 
469  QPainter painter( &image );
470 
471 
472  for ( LayerRenderJobs::const_iterator it = jobs.constBegin(); it != jobs.constEnd(); ++it )
473  {
474  const LayerRenderJob &job = *it;
475 
476  if ( job.layer && job.layer->customProperty( QStringLiteral( "rendering/renderAboveLabels" ) ).toBool() )
477  continue; // skip layer for now, it will be rendered after labels
478 
479  if ( !job.imageInitialized )
480  continue; // img not safe to compose
481 
482  painter.setCompositionMode( job.blendMode );
483  painter.setOpacity( job.opacity );
484 
485  Q_ASSERT( job.img );
486 
487  painter.drawImage( 0, 0, *job.img );
488  }
489 
490  // IMPORTANT - don't draw labelJob img before the label job is complete,
491  // as the image is uninitialized and full of garbage before the label job
492  // commences
493  if ( labelJob.img && labelJob.complete )
494  {
495  painter.setCompositionMode( QPainter::CompositionMode_SourceOver );
496  painter.setOpacity( 1.0 );
497  painter.drawImage( 0, 0, *labelJob.img );
498  }
499 
500  // render any layers with the renderAboveLabels flag now
501  for ( LayerRenderJobs::const_iterator it = jobs.constBegin(); it != jobs.constEnd(); ++it )
502  {
503  const LayerRenderJob &job = *it;
504 
505  if ( !job.layer || !job.layer->customProperty( QStringLiteral( "rendering/renderAboveLabels" ) ).toBool() )
506  continue;
507 
508  if ( !job.imageInitialized )
509  continue; // img not safe to compose
510 
511  painter.setCompositionMode( job.blendMode );
512  painter.setOpacity( job.opacity );
513 
514  Q_ASSERT( job.img );
515 
516  painter.drawImage( 0, 0, *job.img );
517  }
518 
519  painter.end();
520  return image;
521 }
522 
523 void QgsMapRendererJob::logRenderingTime( const LayerRenderJobs &jobs, const LabelRenderJob &labelJob )
524 {
525  QgsSettings settings;
526  if ( !settings.value( QStringLiteral( "Map/logCanvasRefreshEvent" ), false ).toBool() )
527  return;
528 
529  QMultiMap<int, QString> elapsed;
530  const auto constJobs = jobs;
531  for ( const LayerRenderJob &job : constJobs )
532  elapsed.insert( job.renderingTime, job.layerId );
533 
534  elapsed.insert( labelJob.renderingTime, tr( "Labeling" ) );
535 
536  QList<int> tt( elapsed.uniqueKeys() );
537  std::sort( tt.begin(), tt.end(), std::greater<int>() );
538  const auto constTt = tt;
539  for ( int t : constTt )
540  {
541  QgsMessageLog::logMessage( tr( "%1 ms: %2" ).arg( t ).arg( QStringList( elapsed.values( t ) ).join( QStringLiteral( ", " ) ) ), tr( "Rendering" ) );
542  }
543  QgsMessageLog::logMessage( QStringLiteral( "---" ), tr( "Rendering" ) );
544 }
545 
546 bool QgsMapRendererJob::needTemporaryImage( QgsMapLayer *ml )
547 {
548  switch ( ml->type() )
549  {
551  {
552  QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( ml );
553  if ( vl->renderer() && vl->renderer()->forceRasterRender() )
554  {
555  //raster rendering is forced for this layer
556  return true;
557  }
559  ( ( vl->blendMode() != QPainter::CompositionMode_SourceOver )
560  || ( vl->featureBlendMode() != QPainter::CompositionMode_SourceOver )
561  || ( !qgsDoubleNear( vl->opacity(), 1.0 ) ) ) )
562  {
563  //layer properties require rasterization
564  return true;
565  }
566  break;
567  }
569  {
570  // preview of intermediate raster rendering results requires a temporary output image
572  return true;
573  break;
574  }
575 
578  break;
579  }
580 
581  return false;
582 }
583 
584 void QgsMapRendererJob::drawLabeling( QgsRenderContext &renderContext, QgsLabelingEngine *labelingEngine2, QPainter *painter )
585 {
586  QgsDebugMsgLevel( QStringLiteral( "Draw labeling start" ), 5 );
587 
588  QTime t;
589  t.start();
590 
591  // Reset the composition mode before rendering the labels
592  painter->setCompositionMode( QPainter::CompositionMode_SourceOver );
593 
594  renderContext.setPainter( painter );
595 
596  if ( labelingEngine2 )
597  {
598  labelingEngine2->run( renderContext );
599  }
600 
601  QgsDebugMsgLevel( QStringLiteral( "Draw labeling took (seconds): %1" ).arg( t.elapsed() / 1000. ), 2 );
602 }
603 
604 void QgsMapRendererJob::drawLabeling( const QgsMapSettings &settings, QgsRenderContext &renderContext, QgsLabelingEngine *labelingEngine2, QPainter *painter )
605 {
606  Q_UNUSED( settings )
607 
608  drawLabeling( renderContext, labelingEngine2, painter );
609 }
610 
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:79
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
static Q_DECL_DEPRECATED void drawLabeling(const QgsMapSettings &settings, QgsRenderContext &renderContext, QgsLabelingEngine *labelingEngine2, QPainter *painter)
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
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:280
QColor backgroundColor() const
Gets the background color of the map.
Whether to make extra effort to update map image with partially rendered layers (better for interacti...
bool forceRasterRender() const
Returns whether the renderer must render as a raster.
Definition: qgsrenderer.h:401
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:51
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.
bool isValid() const
Returns the status of the layer.
Enable layer opacity and blending effects.
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.
LayerRenderJobs prepareJobs(QPainter *painter, QgsLabelingEngine *labelingEngine2, bool deferredPainterSet=false)
Creates a list of layer rendering jobs and prepares them for later render.
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
void grow(double delta)
Grows the rectangle in place by the specified amount.
Definition: qgsrectangle.h:275
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.
virtual void run(QgsRenderContext &context)=0
Runs the labeling job.
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
double extentBuffer() const
Returns the buffer in map units to use around the visible extent for rendering symbols whose correspo...
void setPainter(QPainter *p)
Sets the destination QPainter for the render operation.
QImage cacheImage(const QString &cacheKey) const
Returns the cached image for the specified cacheKey.
QgsFeatureRenderer * renderer()
Returns renderer.
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...
QPainter::CompositionMode featureBlendMode() const
Returns the current blending mode for features.
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.
Contains information about the context of a rendering operation.
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
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:83
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:86
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