QGIS API Documentation  3.14.0-Pi (9f7028fd23)
qgslayoutitemmap.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgslayoutitemmap.cpp
3  ---------------------
4  begin : July 2017
5  copyright : (C) 2017 by Nyall Dawson
6  email : nyall dot dawson at gmail dot com
7  ***************************************************************************/
8 /***************************************************************************
9  * *
10  * This program is free software; you can redistribute it and/or modify *
11  * it under the terms of the GNU General Public License as published by *
12  * the Free Software Foundation; either version 2 of the License, or *
13  * (at your option) any later version. *
14  * *
15  ***************************************************************************/
16 
17 #include "qgslayoutitemmap.h"
18 #include "qgslayout.h"
19 #include "qgslayoutrendercontext.h"
20 #include "qgslayoutreportcontext.h"
21 #include "qgslayoututils.h"
22 #include "qgslayoutmodel.h"
23 #include "qgsmapthemecollection.h"
24 #include "qgsannotationmanager.h"
25 #include "qgsannotation.h"
26 #include "qgsmapsettingsutils.h"
27 #include "qgslayertree.h"
28 #include "qgsmaplayerref.h"
29 #include "qgsmaplayerlistutils.h"
31 #include "qgsvectorlayer.h"
32 #include "qgsexpressioncontext.h"
33 #include "qgsapplication.h"
35 #include "qgsstyleentityvisitor.h"
36 
37 #include <QPainter>
38 #include <QStyleOptionGraphicsItem>
39 
41  : QgsLayoutItem( layout )
42 {
43  mBackgroundUpdateTimer = new QTimer( this );
44  mBackgroundUpdateTimer->setSingleShot( true );
45  connect( mBackgroundUpdateTimer, &QTimer::timeout, this, &QgsLayoutItemMap::recreateCachedImageInBackground );
46 
47  assignFreeId();
48 
49  setCacheMode( QGraphicsItem::NoCache );
50 
51  connect( this, &QgsLayoutItem::sizePositionChanged, this, [ = ]
52  {
53  shapeChanged();
54  } );
55 
56  mGridStack = qgis::make_unique< QgsLayoutItemMapGridStack >( this );
57  mOverviewStack = qgis::make_unique< QgsLayoutItemMapOverviewStack >( this );
58 
59  if ( layout )
60  connectUpdateSlot();
61 }
62 
64 {
65  if ( mPainterJob )
66  {
67  disconnect( mPainterJob.get(), &QgsMapRendererCustomPainterJob::finished, this, &QgsLayoutItemMap::painterJobFinished );
69  mPainterJob->cancel(); // blocks
70  mPainter->end();
71  }
72 }
73 
75 {
77 }
78 
80 {
81  return QgsApplication::getThemeIcon( QStringLiteral( "/mLayoutItemMap.svg" ) );
82 }
83 
84 QgsLayoutItem::Flags QgsLayoutItemMap::itemFlags() const
85 {
87 }
88 
90 {
91  if ( !mLayout )
92  return;
93 
94  QList<QgsLayoutItemMap *> mapsList;
95  mLayout->layoutItems( mapsList );
96 
97  int maxId = -1;
98  bool used = false;
99  for ( QgsLayoutItemMap *map : qgis::as_const( mapsList ) )
100  {
101  if ( map == this )
102  continue;
103 
104  if ( map->mMapId == mMapId )
105  used = true;
106 
107  maxId = std::max( maxId, map->mMapId );
108  }
109  if ( used )
110  {
111  mMapId = maxId + 1;
112  mLayout->itemsModel()->updateItemDisplayName( this );
113  }
114  updateToolTip();
115 }
116 
118 {
119  if ( !QgsLayoutItem::id().isEmpty() )
120  {
121  return QgsLayoutItem::id();
122  }
123 
124  return tr( "Map %1" ).arg( mMapId );
125 }
126 
128 {
129  return new QgsLayoutItemMap( layout );
130 }
131 
133 {
135 
136  mCachedLayerStyleOverridesPresetName.clear();
137 
138  invalidateCache();
139 
140  updateAtlasFeature();
141 }
142 
144 {
145  if ( rect().isEmpty() )
146  return 0;
147 
148  QgsScaleCalculator calculator;
149  calculator.setMapUnits( crs().mapUnits() );
150  calculator.setDpi( 25.4 ); //Using mm
151  double widthInMm = mLayout->convertFromLayoutUnits( rect().width(), QgsUnitTypes::LayoutMillimeters ).length();
152  return calculator.calculate( extent(), widthInMm );
153 }
154 
155 void QgsLayoutItemMap::setScale( double scaleDenominator, bool forceUpdate )
156 {
157  double currentScaleDenominator = scale();
158 
159  if ( qgsDoubleNear( scaleDenominator, currentScaleDenominator ) || qgsDoubleNear( scaleDenominator, 0.0 ) )
160  {
161  return;
162  }
163 
164  double scaleRatio = scaleDenominator / currentScaleDenominator;
165  mExtent.scale( scaleRatio );
166 
167  if ( mAtlasDriven && mAtlasScalingMode == Fixed )
168  {
169  //if map is atlas controlled and set to fixed scaling mode, then scale changes should be treated as permanent
170  //and also apply to the map's original extent (see #9602)
171  //we can't use the scaleRatio calculated earlier, as the scale can vary depending on extent for geographic coordinate systems
172  QgsScaleCalculator calculator;
173  calculator.setMapUnits( crs().mapUnits() );
174  calculator.setDpi( 25.4 ); //QGraphicsView units are mm
175  scaleRatio = scaleDenominator / calculator.calculate( mExtent, rect().width() );
176  mExtent.scale( scaleRatio );
177  }
178 
179  invalidateCache();
180  if ( forceUpdate )
181  {
182  emit changed();
183  update();
184  }
185  emit extentChanged();
186 }
187 
189 {
190  if ( mExtent == extent )
191  {
192  return;
193  }
194  mExtent = extent;
195 
196  //recalculate data defined scale and extents, since that may override extent
197  refreshMapExtents();
198 
199  //adjust height
200  QRectF currentRect = rect();
201 
202  double newHeight = currentRect.width() * mExtent.height() / mExtent.width();
203 
204  attemptSetSceneRect( QRectF( pos().x(), pos().y(), currentRect.width(), newHeight ) );
205  update();
206 }
207 
209 {
210  QgsRectangle newExtent = extent;
211  QgsRectangle currentExtent = mExtent;
212  //Make sure the width/height ratio is the same as the current layout map extent.
213  //This is to keep the map item frame size fixed
214  double currentWidthHeightRatio = 1.0;
215  if ( !currentExtent.isNull() )
216  currentWidthHeightRatio = currentExtent.width() / currentExtent.height();
217  else
218  currentWidthHeightRatio = rect().width() / rect().height();
219  double newWidthHeightRatio = newExtent.width() / newExtent.height();
220 
221  if ( currentWidthHeightRatio < newWidthHeightRatio )
222  {
223  //enlarge height of new extent, ensuring the map center stays the same
224  double newHeight = newExtent.width() / currentWidthHeightRatio;
225  double deltaHeight = newHeight - newExtent.height();
226  newExtent.setYMinimum( newExtent.yMinimum() - deltaHeight / 2 );
227  newExtent.setYMaximum( newExtent.yMaximum() + deltaHeight / 2 );
228  }
229  else
230  {
231  //enlarge width of new extent, ensuring the map center stays the same
232  double newWidth = currentWidthHeightRatio * newExtent.height();
233  double deltaWidth = newWidth - newExtent.width();
234  newExtent.setXMinimum( newExtent.xMinimum() - deltaWidth / 2 );
235  newExtent.setXMaximum( newExtent.xMaximum() + deltaWidth / 2 );
236  }
237 
238  if ( mExtent == newExtent )
239  {
240  return;
241  }
242  mExtent = newExtent;
243 
244  //recalculate data defined scale and extents, since that may override extent
245  refreshMapExtents();
246 
247  invalidateCache();
248  emit changed();
249  emit extentChanged();
250 }
251 
253 {
254  return mExtent;
255 }
256 
258 {
259  QPolygonF poly;
260  mapPolygon( mExtent, poly );
261  return poly;
262 }
263 
265 {
266  if ( mCrs.isValid() )
267  return mCrs;
268  else if ( mLayout && mLayout->project() )
269  return mLayout->project()->crs();
271 }
272 
274 {
275  mCrs = crs;
276 }
277 
278 QList<QgsMapLayer *> QgsLayoutItemMap::layers() const
279 {
280  return _qgis_listRefToRaw( mLayers );
281 }
282 
283 void QgsLayoutItemMap::setLayers( const QList<QgsMapLayer *> &layers )
284 {
285  mLayers = _qgis_listRawToRef( layers );
286 }
287 
288 void QgsLayoutItemMap::setLayerStyleOverrides( const QMap<QString, QString> &overrides )
289 {
290  if ( overrides == mLayerStyleOverrides )
291  return;
292 
293  mLayerStyleOverrides = overrides;
294  emit layerStyleOverridesChanged(); // associated legends may listen to this
295 
296 }
297 
299 {
300  mLayerStyleOverrides.clear();
301  for ( const QgsMapLayerRef &layerRef : qgis::as_const( mLayers ) )
302  {
303  if ( QgsMapLayer *layer = layerRef.get() )
304  {
305  QgsMapLayerStyle style;
306  style.readFromLayer( layer );
307  mLayerStyleOverrides.insert( layer->id(), style.xmlData() );
308  }
309  }
310 }
311 
313 {
314  if ( mFollowVisibilityPreset == follow )
315  return;
316 
317  mFollowVisibilityPreset = follow;
318  if ( !mFollowVisibilityPresetName.isEmpty() )
319  emit themeChanged( mFollowVisibilityPreset ? mFollowVisibilityPresetName : QString() );
320 }
321 
323 {
324  if ( name == mFollowVisibilityPresetName )
325  return;
326 
327  mFollowVisibilityPresetName = name;
328  if ( mFollowVisibilityPreset )
329  emit themeChanged( mFollowVisibilityPresetName );
330 }
331 
332 void QgsLayoutItemMap::moveContent( double dx, double dy )
333 {
334  mLastRenderedImageOffsetX -= dx;
335  mLastRenderedImageOffsetY -= dy;
336  if ( !mDrawing )
337  {
338  transformShift( dx, dy );
339  mExtent.setXMinimum( mExtent.xMinimum() + dx );
340  mExtent.setXMaximum( mExtent.xMaximum() + dx );
341  mExtent.setYMinimum( mExtent.yMinimum() + dy );
342  mExtent.setYMaximum( mExtent.yMaximum() + dy );
343 
344  //in case data defined extents are set, these override the calculated values
345  refreshMapExtents();
346 
347  invalidateCache();
348  emit changed();
349  emit extentChanged();
350  }
351 }
352 
353 void QgsLayoutItemMap::zoomContent( double factor, QPointF point )
354 {
355  if ( mDrawing )
356  {
357  return;
358  }
359 
360  //find out map coordinates of position
361  double mapX = mExtent.xMinimum() + ( point.x() / rect().width() ) * ( mExtent.xMaximum() - mExtent.xMinimum() );
362  double mapY = mExtent.yMinimum() + ( 1 - ( point.y() / rect().height() ) ) * ( mExtent.yMaximum() - mExtent.yMinimum() );
363 
364  //find out new center point
365  double centerX = ( mExtent.xMaximum() + mExtent.xMinimum() ) / 2;
366  double centerY = ( mExtent.yMaximum() + mExtent.yMinimum() ) / 2;
367 
368  centerX = mapX + ( centerX - mapX ) * ( 1.0 / factor );
369  centerY = mapY + ( centerY - mapY ) * ( 1.0 / factor );
370 
371  double newIntervalX, newIntervalY;
372 
373  if ( factor > 0 )
374  {
375  newIntervalX = ( mExtent.xMaximum() - mExtent.xMinimum() ) / factor;
376  newIntervalY = ( mExtent.yMaximum() - mExtent.yMinimum() ) / factor;
377  }
378  else //no need to zoom
379  {
380  return;
381  }
382 
383  mExtent.setXMaximum( centerX + newIntervalX / 2 );
384  mExtent.setXMinimum( centerX - newIntervalX / 2 );
385  mExtent.setYMaximum( centerY + newIntervalY / 2 );
386  mExtent.setYMinimum( centerY - newIntervalY / 2 );
387 
388  if ( mAtlasDriven && mAtlasScalingMode == Fixed )
389  {
390  //if map is atlas controlled and set to fixed scaling mode, then scale changes should be treated as permanent
391  //and also apply to the map's original extent (see #9602)
392  //we can't use the scaleRatio calculated earlier, as the scale can vary depending on extent for geographic coordinate systems
393  QgsScaleCalculator calculator;
394  calculator.setMapUnits( crs().mapUnits() );
395  calculator.setDpi( 25.4 ); //QGraphicsView units are mm
396  double scaleRatio = scale() / calculator.calculate( mExtent, rect().width() );
397  mExtent.scale( scaleRatio );
398  }
399 
400  //recalculate data defined scale and extents, since that may override zoom
401  refreshMapExtents();
402 
403  invalidateCache();
404  emit changed();
405  emit extentChanged();
406 }
407 
409 {
410  const QList< QgsMapLayer * > layers = layersToRender();
411  for ( QgsMapLayer *layer : layers )
412  {
413  if ( layer->dataProvider() && layer->providerType() == QLatin1String( "wms" ) )
414  {
415  return true;
416  }
417  }
418  return false;
419 }
420 
422 {
424  return true;
425 
426  // we MUST force the whole layout to render as a raster if any map item
427  // uses blend modes, and we are not drawing on a solid opaque background
428  // because in this case the map item needs to be rendered as a raster, but
429  // it also needs to interact with items below it
430  if ( !containsAdvancedEffects() )
431  return false;
432 
433  // TODO layer transparency is probably ok to allow without forcing rasterization
434 
435  if ( hasBackground() && qgsDoubleNear( backgroundColor().alphaF(), 1.0 ) )
436  return false;
437 
438  return true;
439 }
440 
442 {
444  return true;
445 
446  //check easy things first
447 
448  //overviews
449  if ( mOverviewStack->containsAdvancedEffects() )
450  {
451  return true;
452  }
453 
454  //grids
455  if ( mGridStack->containsAdvancedEffects() )
456  {
457  return true;
458  }
459 
460  QgsMapSettings ms;
461  ms.setLayers( layersToRender() );
462  return ( !QgsMapSettingsUtils::containsAdvancedEffects( ms ).isEmpty() );
463 }
464 
465 void QgsLayoutItemMap::setMapRotation( double rotation )
466 {
467  mMapRotation = rotation;
468  mEvaluatedMapRotation = mMapRotation;
469  invalidateCache();
470  emit mapRotationChanged( rotation );
471  emit changed();
472 }
473 
475 {
476  return valueType == QgsLayoutObject::EvaluatedValue ? mEvaluatedMapRotation : mMapRotation;
477 
478 }
479 
481 {
482  mAtlasDriven = enabled;
483 
484  if ( !enabled )
485  {
486  //if not enabling the atlas, we still need to refresh the map extents
487  //so that data defined extents and scale are recalculated
488  refreshMapExtents();
489  }
490 }
491 
493 {
494  if ( valueType == QgsLayoutObject::EvaluatedValue )
495  {
496  //evaluate data defined atlas margin
497 
498  //start with user specified margin
499  double margin = mAtlasMargin;
501 
502  bool ok = false;
503  double ddMargin = mDataDefinedProperties.valueAsDouble( QgsLayoutObject::MapAtlasMargin, context, 0.0, &ok );
504  if ( ok )
505  {
506  //divide by 100 to convert to 0 -> 1.0 range
507  margin = ddMargin / 100;
508  }
509  return margin;
510  }
511  else
512  {
513  return mAtlasMargin;
514  }
515 }
516 
518 {
519  if ( mGridStack->size() < 1 )
520  {
521  QgsLayoutItemMapGrid *grid = new QgsLayoutItemMapGrid( tr( "Grid %1" ).arg( 1 ), this );
522  mGridStack->addGrid( grid );
523  }
524  return mGridStack->grid( 0 );
525 }
526 
528 {
529  if ( mOverviewStack->size() < 1 )
530  {
531  QgsLayoutItemMapOverview *overview = new QgsLayoutItemMapOverview( tr( "Overview %1" ).arg( 1 ), this );
532  mOverviewStack->addOverview( overview );
533  }
534  return mOverviewStack->overview( 0 );
535 }
536 
538 {
539 }
540 
541 bool QgsLayoutItemMap::writePropertiesToElement( QDomElement &mapElem, QDomDocument &doc, const QgsReadWriteContext &context ) const
542 {
543  if ( mKeepLayerSet )
544  {
545  mapElem.setAttribute( QStringLiteral( "keepLayerSet" ), QStringLiteral( "true" ) );
546  }
547  else
548  {
549  mapElem.setAttribute( QStringLiteral( "keepLayerSet" ), QStringLiteral( "false" ) );
550  }
551 
552  if ( mDrawAnnotations )
553  {
554  mapElem.setAttribute( QStringLiteral( "drawCanvasItems" ), QStringLiteral( "true" ) );
555  }
556  else
557  {
558  mapElem.setAttribute( QStringLiteral( "drawCanvasItems" ), QStringLiteral( "false" ) );
559  }
560 
561  //extent
562  QDomElement extentElem = doc.createElement( QStringLiteral( "Extent" ) );
563  extentElem.setAttribute( QStringLiteral( "xmin" ), qgsDoubleToString( mExtent.xMinimum() ) );
564  extentElem.setAttribute( QStringLiteral( "xmax" ), qgsDoubleToString( mExtent.xMaximum() ) );
565  extentElem.setAttribute( QStringLiteral( "ymin" ), qgsDoubleToString( mExtent.yMinimum() ) );
566  extentElem.setAttribute( QStringLiteral( "ymax" ), qgsDoubleToString( mExtent.yMaximum() ) );
567  mapElem.appendChild( extentElem );
568 
569  if ( mCrs.isValid() )
570  {
571  QDomElement crsElem = doc.createElement( QStringLiteral( "crs" ) );
572  mCrs.writeXml( crsElem, doc );
573  mapElem.appendChild( crsElem );
574  }
575 
576  // follow map theme
577  mapElem.setAttribute( QStringLiteral( "followPreset" ), mFollowVisibilityPreset ? QStringLiteral( "true" ) : QStringLiteral( "false" ) );
578  mapElem.setAttribute( QStringLiteral( "followPresetName" ), mFollowVisibilityPresetName );
579 
580  //map rotation
581  mapElem.setAttribute( QStringLiteral( "mapRotation" ), QString::number( mMapRotation ) );
582 
583  //layer set
584  QDomElement layerSetElem = doc.createElement( QStringLiteral( "LayerSet" ) );
585  for ( const QgsMapLayerRef &layerRef : mLayers )
586  {
587  if ( !layerRef )
588  continue;
589  QDomElement layerElem = doc.createElement( QStringLiteral( "Layer" ) );
590  QDomText layerIdText = doc.createTextNode( layerRef.layerId );
591  layerElem.appendChild( layerIdText );
592 
593  layerElem.setAttribute( QStringLiteral( "name" ), layerRef.name );
594  layerElem.setAttribute( QStringLiteral( "source" ), layerRef.source );
595  layerElem.setAttribute( QStringLiteral( "provider" ), layerRef.provider );
596 
597  layerSetElem.appendChild( layerElem );
598  }
599  mapElem.appendChild( layerSetElem );
600 
601  // override styles
602  if ( mKeepLayerStyles )
603  {
604  QDomElement stylesElem = doc.createElement( QStringLiteral( "LayerStyles" ) );
605  for ( auto styleIt = mLayerStyleOverrides.constBegin(); styleIt != mLayerStyleOverrides.constEnd(); ++styleIt )
606  {
607  QDomElement styleElem = doc.createElement( QStringLiteral( "LayerStyle" ) );
608 
609  QgsMapLayerRef ref( styleIt.key() );
610  ref.resolve( mLayout->project() );
611 
612  styleElem.setAttribute( QStringLiteral( "layerid" ), ref.layerId );
613  styleElem.setAttribute( QStringLiteral( "name" ), ref.name );
614  styleElem.setAttribute( QStringLiteral( "source" ), ref.source );
615  styleElem.setAttribute( QStringLiteral( "provider" ), ref.provider );
616 
617  QgsMapLayerStyle style( styleIt.value() );
618  style.writeXml( styleElem );
619  stylesElem.appendChild( styleElem );
620  }
621  mapElem.appendChild( stylesElem );
622  }
623 
624  //grids
625  mGridStack->writeXml( mapElem, doc, context );
626 
627  //overviews
628  mOverviewStack->writeXml( mapElem, doc, context );
629 
630  //atlas
631  QDomElement atlasElem = doc.createElement( QStringLiteral( "AtlasMap" ) );
632  atlasElem.setAttribute( QStringLiteral( "atlasDriven" ), mAtlasDriven );
633  atlasElem.setAttribute( QStringLiteral( "scalingMode" ), mAtlasScalingMode );
634  atlasElem.setAttribute( QStringLiteral( "margin" ), qgsDoubleToString( mAtlasMargin ) );
635  mapElem.appendChild( atlasElem );
636 
637  mapElem.setAttribute( QStringLiteral( "labelMargin" ), mLabelMargin.encodeMeasurement() );
638  mapElem.setAttribute( QStringLiteral( "mapFlags" ), static_cast< int>( mMapFlags ) );
639 
640  QDomElement labelBlockingItemsElem = doc.createElement( QStringLiteral( "labelBlockingItems" ) );
641  for ( const auto &item : qgis::as_const( mBlockingLabelItems ) )
642  {
643  if ( !item )
644  continue;
645 
646  QDomElement blockingItemElem = doc.createElement( QStringLiteral( "item" ) );
647  blockingItemElem.setAttribute( QStringLiteral( "uuid" ), item->uuid() );
648  labelBlockingItemsElem.appendChild( blockingItemElem );
649  }
650  mapElem.appendChild( labelBlockingItemsElem );
651 
652  //temporal settings
653  mapElem.setAttribute( QStringLiteral( "isTemporal" ), isTemporal() ? 1 : 0 );
654  if ( isTemporal() )
655  {
656  mapElem.setAttribute( QStringLiteral( "temporalRangeBegin" ), temporalRange().begin().toString( Qt::ISODate ) );
657  mapElem.setAttribute( QStringLiteral( "temporalRangeEnd" ), temporalRange().end().toString( Qt::ISODate ) );
658  }
659 
660  return true;
661 }
662 
663 bool QgsLayoutItemMap::readPropertiesFromElement( const QDomElement &itemElem, const QDomDocument &doc, const QgsReadWriteContext &context )
664 {
665  mUpdatesEnabled = false;
666 
667  //extent
668  QDomNodeList extentNodeList = itemElem.elementsByTagName( QStringLiteral( "Extent" ) );
669  if ( !extentNodeList.isEmpty() )
670  {
671  QDomElement extentElem = extentNodeList.at( 0 ).toElement();
672  double xmin, xmax, ymin, ymax;
673  xmin = extentElem.attribute( QStringLiteral( "xmin" ) ).toDouble();
674  xmax = extentElem.attribute( QStringLiteral( "xmax" ) ).toDouble();
675  ymin = extentElem.attribute( QStringLiteral( "ymin" ) ).toDouble();
676  ymax = extentElem.attribute( QStringLiteral( "ymax" ) ).toDouble();
677  setExtent( QgsRectangle( xmin, ymin, xmax, ymax ) );
678  }
679 
680  QDomNodeList crsNodeList = itemElem.elementsByTagName( QStringLiteral( "crs" ) );
681  if ( !crsNodeList.isEmpty() )
682  {
683  QDomElement crsElem = crsNodeList.at( 0 ).toElement();
684  mCrs.readXml( crsElem );
685  }
686  else
687  {
689  }
690 
691  //map rotation
692  mMapRotation = itemElem.attribute( QStringLiteral( "mapRotation" ), QStringLiteral( "0" ) ).toDouble();
693  mEvaluatedMapRotation = mMapRotation;
694 
695  // follow map theme
696  mFollowVisibilityPreset = itemElem.attribute( QStringLiteral( "followPreset" ) ).compare( QLatin1String( "true" ) ) == 0;
697  mFollowVisibilityPresetName = itemElem.attribute( QStringLiteral( "followPresetName" ) );
698 
699  //mKeepLayerSet flag
700  QString keepLayerSetFlag = itemElem.attribute( QStringLiteral( "keepLayerSet" ) );
701  if ( keepLayerSetFlag.compare( QLatin1String( "true" ), Qt::CaseInsensitive ) == 0 )
702  {
703  mKeepLayerSet = true;
704  }
705  else
706  {
707  mKeepLayerSet = false;
708  }
709 
710  QString drawCanvasItemsFlag = itemElem.attribute( QStringLiteral( "drawCanvasItems" ), QStringLiteral( "true" ) );
711  if ( drawCanvasItemsFlag.compare( QLatin1String( "true" ), Qt::CaseInsensitive ) == 0 )
712  {
713  mDrawAnnotations = true;
714  }
715  else
716  {
717  mDrawAnnotations = false;
718  }
719 
720  mLayerStyleOverrides.clear();
721 
722  //mLayers
723  mLayers.clear();
724  QDomNodeList layerSetNodeList = itemElem.elementsByTagName( QStringLiteral( "LayerSet" ) );
725  if ( !layerSetNodeList.isEmpty() )
726  {
727  QDomElement layerSetElem = layerSetNodeList.at( 0 ).toElement();
728  QDomNodeList layerIdNodeList = layerSetElem.elementsByTagName( QStringLiteral( "Layer" ) );
729  mLayers.reserve( layerIdNodeList.size() );
730  for ( int i = 0; i < layerIdNodeList.size(); ++i )
731  {
732  QDomElement layerElem = layerIdNodeList.at( i ).toElement();
733  QString layerId = layerElem.text();
734  QString layerName = layerElem.attribute( QStringLiteral( "name" ) );
735  QString layerSource = layerElem.attribute( QStringLiteral( "source" ) );
736  QString layerProvider = layerElem.attribute( QStringLiteral( "provider" ) );
737 
738  QgsMapLayerRef ref( layerId, layerName, layerSource, layerProvider );
739  ref.resolveWeakly( mLayout->project() );
740  mLayers << ref;
741  }
742  }
743 
744  // override styles
745  QDomNodeList layerStylesNodeList = itemElem.elementsByTagName( QStringLiteral( "LayerStyles" ) );
746  mKeepLayerStyles = !layerStylesNodeList.isEmpty();
747  if ( mKeepLayerStyles )
748  {
749  QDomElement layerStylesElem = layerStylesNodeList.at( 0 ).toElement();
750  QDomNodeList layerStyleNodeList = layerStylesElem.elementsByTagName( QStringLiteral( "LayerStyle" ) );
751  for ( int i = 0; i < layerStyleNodeList.size(); ++i )
752  {
753  const QDomElement &layerStyleElement = layerStyleNodeList.at( i ).toElement();
754  QString layerId = layerStyleElement.attribute( QStringLiteral( "layerid" ) );
755  QString layerName = layerStyleElement.attribute( QStringLiteral( "name" ) );
756  QString layerSource = layerStyleElement.attribute( QStringLiteral( "source" ) );
757  QString layerProvider = layerStyleElement.attribute( QStringLiteral( "provider" ) );
758  QgsMapLayerRef ref( layerId, layerName, layerSource, layerProvider );
759  ref.resolveWeakly( mLayout->project() );
760 
761  QgsMapLayerStyle style;
762  style.readXml( layerStyleElement );
763  mLayerStyleOverrides.insert( ref.layerId, style.xmlData() );
764  }
765  }
766 
767  mDrawing = false;
768  mNumCachedLayers = 0;
769  mCacheInvalidated = true;
770 
771  //overviews
772  mOverviewStack->readXml( itemElem, doc, context );
773 
774  //grids
775  mGridStack->readXml( itemElem, doc, context );
776 
777  //atlas
778  QDomNodeList atlasNodeList = itemElem.elementsByTagName( QStringLiteral( "AtlasMap" ) );
779  if ( !atlasNodeList.isEmpty() )
780  {
781  QDomElement atlasElem = atlasNodeList.at( 0 ).toElement();
782  mAtlasDriven = ( atlasElem.attribute( QStringLiteral( "atlasDriven" ), QStringLiteral( "0" ) ) != QLatin1String( "0" ) );
783  if ( atlasElem.hasAttribute( QStringLiteral( "fixedScale" ) ) ) // deprecated XML
784  {
785  mAtlasScalingMode = ( atlasElem.attribute( QStringLiteral( "fixedScale" ), QStringLiteral( "0" ) ) != QLatin1String( "0" ) ) ? Fixed : Auto;
786  }
787  else if ( atlasElem.hasAttribute( QStringLiteral( "scalingMode" ) ) )
788  {
789  mAtlasScalingMode = static_cast<AtlasScalingMode>( atlasElem.attribute( QStringLiteral( "scalingMode" ) ).toInt() );
790  }
791  mAtlasMargin = atlasElem.attribute( QStringLiteral( "margin" ), QStringLiteral( "0.1" ) ).toDouble();
792  }
793 
794  setLabelMargin( QgsLayoutMeasurement::decodeMeasurement( itemElem.attribute( QStringLiteral( "labelMargin" ), QStringLiteral( "0" ) ) ) );
795 
796  mMapFlags = static_cast< MapItemFlags>( itemElem.attribute( QStringLiteral( "mapFlags" ), nullptr ).toInt() );
797 
798  // label blocking items
799  mBlockingLabelItems.clear();
800  mBlockingLabelItemUuids.clear();
801  QDomNodeList labelBlockingNodeList = itemElem.elementsByTagName( QStringLiteral( "labelBlockingItems" ) );
802  if ( !labelBlockingNodeList.isEmpty() )
803  {
804  QDomElement blockingItems = labelBlockingNodeList.at( 0 ).toElement();
805  QDomNodeList labelBlockingNodeList = blockingItems.childNodes();
806  for ( int i = 0; i < labelBlockingNodeList.size(); ++i )
807  {
808  const QDomElement &itemBlockingElement = labelBlockingNodeList.at( i ).toElement();
809  const QString itemUuid = itemBlockingElement.attribute( QStringLiteral( "uuid" ) );
810  mBlockingLabelItemUuids << itemUuid;
811  }
812  }
813 
815 
816  //temporal settings
817  setIsTemporal( itemElem.attribute( QStringLiteral( "isTemporal" ) ).toInt() );
818  if ( isTemporal() )
819  {
820  QDateTime begin = QDateTime::fromString( itemElem.attribute( QStringLiteral( "temporalRangeBegin" ) ), Qt::ISODate );
821  QDateTime end = QDateTime::fromString( itemElem.attribute( QStringLiteral( "temporalRangeEnd" ) ), Qt::ISODate );
822  setTemporalRange( QgsDateTimeRange( begin, end ) );
823  }
824 
825  mUpdatesEnabled = true;
826  return true;
827 }
828 
829 void QgsLayoutItemMap::paint( QPainter *painter, const QStyleOptionGraphicsItem *style, QWidget * )
830 {
831  if ( !mLayout || !painter || !painter->device() || !mUpdatesEnabled )
832  {
833  return;
834  }
835  if ( !shouldDrawItem() )
836  {
837  return;
838  }
839 
840  QRectF thisPaintRect = rect();
841  if ( qgsDoubleNear( thisPaintRect.width(), 0.0 ) || qgsDoubleNear( thisPaintRect.height(), 0 ) )
842  return;
843 
844  //TODO - try to reduce the amount of duplicate code here!
845 
846  if ( mLayout->renderContext().isPreviewRender() )
847  {
848  painter->save();
849  painter->setClipRect( thisPaintRect );
850  if ( !mCacheFinalImage || mCacheFinalImage->isNull() )
851  {
852  // No initial render available - so draw some preview text alerting user
853  painter->setBrush( QBrush( QColor( 125, 125, 125, 125 ) ) );
854  painter->drawRect( thisPaintRect );
855  painter->setBrush( Qt::NoBrush );
856  QFont messageFont;
857  messageFont.setPointSize( 12 );
858  painter->setFont( messageFont );
859  painter->setPen( QColor( 255, 255, 255, 255 ) );
860  painter->drawText( thisPaintRect, Qt::AlignCenter | Qt::AlignHCenter, tr( "Rendering map" ) );
861  if ( mPainterJob && mCacheInvalidated && !mDrawingPreview )
862  {
863  // current job was invalidated - start a new one
864  mPreviewScaleFactor = QgsLayoutUtils::scaleFactorFromItemStyle( style );
865  mBackgroundUpdateTimer->start( 1 );
866  }
867  else if ( !mPainterJob && !mDrawingPreview )
868  {
869  // this is the map's very first paint - trigger a cache update
870  mPreviewScaleFactor = QgsLayoutUtils::scaleFactorFromItemStyle( style );
871  mBackgroundUpdateTimer->start( 1 );
872  }
873  }
874  else
875  {
876  if ( mCacheInvalidated && !mDrawingPreview )
877  {
878  // cache was invalidated - trigger a background update
879  mPreviewScaleFactor = QgsLayoutUtils::scaleFactorFromItemStyle( style );
880  mBackgroundUpdateTimer->start( 1 );
881  }
882 
883  //Background color is already included in cached image, so no need to draw
884 
885  double imagePixelWidth = mCacheFinalImage->width(); //how many pixels of the image are for the map extent?
886  double scale = rect().width() / imagePixelWidth;
887 
888  painter->save();
889 
890  painter->translate( mLastRenderedImageOffsetX + mXOffset, mLastRenderedImageOffsetY + mYOffset );
891  painter->scale( scale, scale );
892  painter->drawImage( 0, 0, *mCacheFinalImage );
893 
894  //restore rotation
895  painter->restore();
896  }
897 
898  painter->setClipRect( thisPaintRect, Qt::NoClip );
899 
900  mOverviewStack->drawItems( painter, false );
901  mGridStack->drawItems( painter );
902  drawAnnotations( painter );
903  drawMapFrame( painter );
904  painter->restore();
905  }
906  else
907  {
908  if ( mDrawing )
909  return;
910 
911  mDrawing = true;
912  QPaintDevice *paintDevice = painter->device();
913  if ( !paintDevice )
914  return;
915 
916  QgsRectangle cExtent = extent();
917  QSizeF size( cExtent.width() * mapUnitsToLayoutUnits(), cExtent.height() * mapUnitsToLayoutUnits() );
918 
919  if ( containsAdvancedEffects() && ( !mLayout || !( mLayout->renderContext().flags() & QgsLayoutRenderContext::FlagForceVectorOutput ) ) )
920  {
921  // rasterize
922  double destinationDpi = QgsLayoutUtils::scaleFactorFromItemStyle( style ) * 25.4;
923  double layoutUnitsInInches = mLayout ? mLayout->convertFromLayoutUnits( 1, QgsUnitTypes::LayoutInches ).length() : 1;
924  int widthInPixels = static_cast< int >( std::round( boundingRect().width() * layoutUnitsInInches * destinationDpi ) );
925  int heightInPixels = static_cast< int >( std::round( boundingRect().height() * layoutUnitsInInches * destinationDpi ) );
926  QImage image = QImage( widthInPixels, heightInPixels, QImage::Format_ARGB32 );
927 
928  image.fill( Qt::transparent );
929  image.setDotsPerMeterX( static_cast< int >( std::round( 1000 * destinationDpi / 25.4 ) ) );
930  image.setDotsPerMeterY( static_cast< int >( std::round( 1000 * destinationDpi / 25.4 ) ) );
931  double dotsPerMM = destinationDpi / 25.4;
932  QPainter p( &image );
933 
934  QPointF tl = -boundingRect().topLeft();
935  QRect imagePaintRect( static_cast< int >( std::round( tl.x() * dotsPerMM ) ),
936  static_cast< int >( std::round( tl.y() * dotsPerMM ) ),
937  static_cast< int >( std::round( thisPaintRect.width() * dotsPerMM ) ),
938  static_cast< int >( std::round( thisPaintRect.height() * dotsPerMM ) ) );
939  p.setClipRect( imagePaintRect );
940 
941  p.translate( imagePaintRect.topLeft() );
942 
943  // Fill with background color - must be drawn onto the flattened image
944  // so that layers with opacity or blend modes can correctly interact with it
945  if ( shouldDrawPart( Background ) )
946  {
947  p.scale( dotsPerMM, dotsPerMM );
948  drawMapBackground( &p );
949  p.scale( 1.0 / dotsPerMM, 1.0 / dotsPerMM );
950  }
951 
952  drawMap( &p, cExtent, imagePaintRect.size(), image.logicalDpiX() );
953 
954  // important - all other items, overviews, grids etc must be rendered to the
955  // flattened image, in case these have blend modes must need to interact
956  // with the map
957  p.scale( dotsPerMM, dotsPerMM );
958 
959  if ( shouldDrawPart( OverviewMapExtent ) )
960  {
961  mOverviewStack->drawItems( &p, false );
962  }
963  if ( shouldDrawPart( Grid ) )
964  {
965  mGridStack->drawItems( &p );
966  }
967  drawAnnotations( &p );
968 
969  painter->save();
970  painter->scale( 1 / dotsPerMM, 1 / dotsPerMM ); // scale painter from mm to dots
971  painter->drawImage( QPointF( -tl.x()* dotsPerMM, -tl.y() * dotsPerMM ), image );
972  painter->scale( dotsPerMM, dotsPerMM );
973  painter->restore();
974  }
975  else
976  {
977  // Fill with background color
978  if ( shouldDrawPart( Background ) )
979  {
980  drawMapBackground( painter );
981  }
982 
983  painter->save();
984  painter->setClipRect( thisPaintRect );
985 
986  if ( shouldDrawPart( Layer ) && !qgsDoubleNear( size.width(), 0.0 ) && !qgsDoubleNear( size.height(), 0.0 ) )
987  {
988  painter->save();
989  painter->translate( mXOffset, mYOffset );
990 
991  double dotsPerMM = paintDevice->logicalDpiX() / 25.4;
992  size *= dotsPerMM; // output size will be in dots (pixels)
993  painter->scale( 1 / dotsPerMM, 1 / dotsPerMM ); // scale painter from mm to dots
994 
995  if ( mCurrentExportPart != NotLayered )
996  {
997  if ( !mStagedRendererJob )
998  {
999  createStagedRenderJob( cExtent, size, paintDevice->logicalDpiX() );
1000  }
1001 
1002  mStagedRendererJob->renderCurrentPart( painter );
1003  }
1004  else
1005  {
1006  drawMap( painter, cExtent, size, paintDevice->logicalDpiX() );
1007  }
1008 
1009  painter->restore();
1010  }
1011 
1012  painter->setClipRect( thisPaintRect, Qt::NoClip );
1013 
1014  if ( shouldDrawPart( OverviewMapExtent ) )
1015  {
1016  mOverviewStack->drawItems( painter, false );
1017  }
1018  if ( shouldDrawPart( Grid ) )
1019  {
1020  mGridStack->drawItems( painter );
1021  }
1022  drawAnnotations( painter );
1023  painter->restore();
1024  }
1025 
1026  if ( shouldDrawPart( Frame ) )
1027  {
1028  drawMapFrame( painter );
1029  }
1030 
1031  mDrawing = false;
1032  }
1033 }
1034 
1036 {
1037  const int layerCount = layersToRender().length();
1038  return ( hasBackground() ? 1 : 0 )
1039  + ( layerCount + ( layerCount ? 1 : 0 ) ) // +1 for label layer, if labels present
1040  + ( mGridStack->hasEnabledItems() ? 1 : 0 )
1041  + ( mOverviewStack->hasEnabledItems() ? 1 : 0 )
1042  + ( frameEnabled() ? 1 : 0 );
1043 }
1044 
1046 {
1047  mCurrentExportPart = Start;
1048  // only follow export themes if the map isn't set to follow a fixed theme
1049  mExportThemes = !mFollowVisibilityPreset ? mLayout->renderContext().exportThemes() : QStringList();
1050  mExportThemeIt = mExportThemes.begin();
1051 }
1052 
1054 {
1055  mCurrentExportPart = NotLayered;
1056  mExportThemes.clear();
1057  mExportThemeIt = mExportThemes.begin();
1058 }
1059 
1061 {
1062  switch ( mCurrentExportPart )
1063  {
1064  case Start:
1065  if ( hasBackground() )
1066  {
1067  mCurrentExportPart = Background;
1068  return true;
1069  }
1070  FALLTHROUGH
1071 
1072  case Background:
1073  mCurrentExportPart = Layer;
1074  return true;
1075 
1076  case Layer:
1077  if ( mStagedRendererJob )
1078  {
1079  if ( mStagedRendererJob->nextPart() )
1080  return true;
1081  else
1082  mStagedRendererJob.reset(); // no more map layer parts
1083  }
1084 
1085  if ( mExportThemeIt != mExportThemes.end() && ++mExportThemeIt != mExportThemes.end() )
1086  {
1087  // move to next theme and continue exporting map layers
1088  return true;
1089  }
1090 
1091  if ( mGridStack->hasEnabledItems() )
1092  {
1093  mCurrentExportPart = Grid;
1094  return true;
1095  }
1096  FALLTHROUGH
1097 
1098  case Grid:
1099  for ( int i = 0; i < mOverviewStack->size(); ++i )
1100  {
1101  QgsLayoutItemMapItem *item = mOverviewStack->item( i );
1103  {
1104  mCurrentExportPart = OverviewMapExtent;
1105  return true;
1106  }
1107  }
1108  FALLTHROUGH
1109 
1110  case OverviewMapExtent:
1111  if ( frameEnabled() )
1112  {
1113  mCurrentExportPart = Frame;
1114  return true;
1115  }
1116 
1117  FALLTHROUGH
1118 
1119  case Frame:
1120  if ( isSelected() && !mLayout->renderContext().isPreviewRender() )
1121  {
1122  mCurrentExportPart = SelectionBoxes;
1123  return true;
1124  }
1125  FALLTHROUGH
1126 
1127  case SelectionBoxes:
1128  mCurrentExportPart = End;
1129  return false;
1130 
1131  case End:
1132  return false;
1133 
1134  case NotLayered:
1135  return false;
1136  }
1137  return false;
1138 }
1139 
1141 {
1142  return ItemContainsSubLayers;
1143 }
1144 
1146 {
1147  ExportLayerDetail detail;
1148 
1149  switch ( mCurrentExportPart )
1150  {
1151  case Start:
1152  break;
1153 
1154  case Background:
1155  detail.name = tr( "%1: Background" ).arg( displayName() );
1156  return detail;
1157 
1158  case Layer:
1159  if ( !mExportThemes.empty() && mExportThemeIt != mExportThemes.end() )
1160  detail.mapTheme = *mExportThemeIt;
1161 
1162  if ( mStagedRendererJob )
1163  {
1164  switch ( mStagedRendererJob->currentStage() )
1165  {
1167  {
1168  detail.mapLayerId = mStagedRendererJob->currentLayerId();
1169  detail.compositionMode = mStagedRendererJob->currentLayerCompositionMode();
1170  detail.opacity = mStagedRendererJob->currentLayerOpacity();
1171  if ( const QgsMapLayer *layer = mLayout->project()->mapLayer( detail.mapLayerId ) )
1172  {
1173  if ( !detail.mapTheme.isEmpty() )
1174  detail.name = QStringLiteral( "%1 (%2): %3" ).arg( displayName(), detail.mapTheme, layer->name() );
1175  else
1176  detail.name = QStringLiteral( "%1: %2" ).arg( displayName(), layer->name() );
1177  }
1178  else
1179  {
1180  // might be an item based layer
1181  const QList<QgsLayoutItemMapOverview *> res = mOverviewStack->asList();
1182  for ( QgsLayoutItemMapOverview *item : res )
1183  {
1184  if ( !item || !item->enabled() || item->stackingPosition() == QgsLayoutItemMapItem::StackAboveMapLabels )
1185  continue;
1186 
1187  if ( item->mapLayer() && detail.mapLayerId == item->mapLayer()->id() )
1188  {
1189  if ( !detail.mapTheme.isEmpty() )
1190  detail.name = QStringLiteral( "%1 (%2): %3" ).arg( displayName(), detail.mapTheme, item->mapLayer()->name() );
1191  else
1192  detail.name = QStringLiteral( "%1: %2" ).arg( displayName(), item->mapLayer()->name() );
1193  break;
1194  }
1195  }
1196  }
1197  return detail;
1198  }
1199 
1201  detail.mapLayerId = mStagedRendererJob->currentLayerId();
1202  if ( const QgsMapLayer *layer = mLayout->project()->mapLayer( detail.mapLayerId ) )
1203  {
1204  if ( !detail.mapTheme.isEmpty() )
1205  detail.name = QStringLiteral( "%1 (%2): %3 (Labels)" ).arg( displayName(), detail.mapTheme, layer->name() );
1206  else
1207  detail.name = tr( "%1: %2 (Labels)" ).arg( displayName(), layer->name() );
1208  }
1209  else
1210  {
1211  if ( !detail.mapTheme.isEmpty() )
1212  detail.name = tr( "%1 (%2): Labels" ).arg( displayName(), detail.mapTheme );
1213  else
1214  detail.name = tr( "%1: Labels" ).arg( displayName() );
1215  }
1216  return detail;
1217 
1219  break;
1220  }
1221  }
1222  else
1223  {
1224  // we must be on the first layer, not having had a chance to create the render job yet
1225  const QList< QgsMapLayer * > layers = layersToRender();
1226  if ( !layers.isEmpty() )
1227  {
1228  const QgsMapLayer *layer = layers.constLast();
1229  if ( !detail.mapTheme.isEmpty() )
1230  detail.name = QStringLiteral( "%1 (%2): %3" ).arg( displayName(), detail.mapTheme, layer->name() );
1231  else
1232  detail.name = QStringLiteral( "%1: %2" ).arg( displayName(), layer->name() );
1233  detail.mapLayerId = layer->id();
1234  }
1235  }
1236  break;
1237 
1238  case Grid:
1239  detail.name = tr( "%1: Grids" ).arg( displayName() );
1240  return detail;
1241 
1242  case OverviewMapExtent:
1243  detail.name = tr( "%1: Overviews" ).arg( displayName() );
1244  return detail;
1245 
1246  case Frame:
1247  detail.name = tr( "%1: Frame" ).arg( displayName() );
1248  return detail;
1249 
1250  case SelectionBoxes:
1251  case End:
1252  case NotLayered:
1253  break;
1254  }
1255 
1256  return detail;
1257 }
1258 
1260 {
1263 }
1264 
1265 void QgsLayoutItemMap::drawMap( QPainter *painter, const QgsRectangle &extent, QSizeF size, double dpi )
1266 {
1267  if ( !painter )
1268  {
1269  return;
1270  }
1271  if ( qgsDoubleNear( size.width(), 0.0 ) || qgsDoubleNear( size.height(), 0.0 ) )
1272  {
1273  //don't attempt to draw if size is invalid
1274  return;
1275  }
1276 
1277  // render
1278  QgsMapSettings ms( mapSettings( extent, size, dpi, true ) );
1279  if ( shouldDrawPart( OverviewMapExtent ) )
1280  {
1281  ms.setLayers( mOverviewStack->modifyMapLayerList( ms.layers() ) );
1282  }
1283 
1284  QgsMapRendererCustomPainterJob job( ms, painter );
1285  // Render the map in this thread. This is done because of problems
1286  // with printing to printer on Windows (printing to PDF is fine though).
1287  // Raster images were not displayed - see #10599
1288  job.renderSynchronously();
1289 
1290  mRenderingErrors = job.errors();
1291 }
1292 
1293 void QgsLayoutItemMap::recreateCachedImageInBackground()
1294 {
1295  if ( mPainterJob )
1296  {
1297  disconnect( mPainterJob.get(), &QgsMapRendererCustomPainterJob::finished, this, &QgsLayoutItemMap::painterJobFinished );
1298  QgsMapRendererCustomPainterJob *oldJob = mPainterJob.release();
1299  QPainter *oldPainter = mPainter.release();
1300  QImage *oldImage = mCacheRenderingImage.release();
1301  connect( oldJob, &QgsMapRendererCustomPainterJob::finished, this, [oldPainter, oldJob, oldImage]
1302  {
1303  oldJob->deleteLater();
1304  delete oldPainter;
1305  delete oldImage;
1306  } );
1307  oldJob->cancelWithoutBlocking();
1308  }
1309  else
1310  {
1311  mCacheRenderingImage.reset( nullptr );
1312  emit backgroundTaskCountChanged( 1 );
1313  }
1314 
1315  Q_ASSERT( !mPainterJob );
1316  Q_ASSERT( !mPainter );
1317  Q_ASSERT( !mCacheRenderingImage );
1318 
1319  QgsRectangle ext = extent();
1320  double widthLayoutUnits = ext.width() * mapUnitsToLayoutUnits();
1321  double heightLayoutUnits = ext.height() * mapUnitsToLayoutUnits();
1322 
1323  int w = static_cast< int >( std::round( widthLayoutUnits * mPreviewScaleFactor ) );
1324  int h = static_cast< int >( std::round( heightLayoutUnits * mPreviewScaleFactor ) );
1325 
1326  // limit size of image for better performance
1327  if ( w > 5000 || h > 5000 )
1328  {
1329  if ( w > h )
1330  {
1331  w = 5000;
1332  h = static_cast< int>( std::round( w * heightLayoutUnits / widthLayoutUnits ) );
1333  }
1334  else
1335  {
1336  h = 5000;
1337  w = static_cast< int >( std::round( h * widthLayoutUnits / heightLayoutUnits ) );
1338  }
1339  }
1340 
1341  if ( w <= 0 || h <= 0 )
1342  return;
1343 
1344  mCacheRenderingImage.reset( new QImage( w, h, QImage::Format_ARGB32 ) );
1345 
1346  // set DPI of the image
1347  mCacheRenderingImage->setDotsPerMeterX( static_cast< int >( std::round( 1000 * w / widthLayoutUnits ) ) );
1348  mCacheRenderingImage->setDotsPerMeterY( static_cast< int >( std::round( 1000 * h / heightLayoutUnits ) ) );
1349 
1350  if ( hasBackground() )
1351  {
1352  //Initially fill image with specified background color. This ensures that layers with blend modes will
1353  //preview correctly
1354  mCacheRenderingImage->fill( backgroundColor().rgba() );
1355  }
1356  else
1357  {
1358  //no background, but start with empty fill to avoid artifacts
1359  mCacheRenderingImage->fill( QColor( 255, 255, 255, 0 ).rgba() );
1360  }
1361 
1362  mCacheInvalidated = false;
1363  mPainter.reset( new QPainter( mCacheRenderingImage.get() ) );
1364  QgsMapSettings settings( mapSettings( ext, QSizeF( w, h ), mCacheRenderingImage->logicalDpiX(), true ) );
1365 
1366  if ( shouldDrawPart( OverviewMapExtent ) )
1367  {
1368  settings.setLayers( mOverviewStack->modifyMapLayerList( settings.layers() ) );
1369  }
1370 
1371  mPainterJob.reset( new QgsMapRendererCustomPainterJob( settings, mPainter.get() ) );
1372  connect( mPainterJob.get(), &QgsMapRendererCustomPainterJob::finished, this, &QgsLayoutItemMap::painterJobFinished );
1373  mPainterJob->start();
1374 
1375  // from now on we can accept refresh requests again
1376  // this must be reset only after the job has been started, because
1377  // some providers (yes, it's you WCS and AMS!) during preparation
1378  // do network requests and start an internal event loop, which may
1379  // end up calling refresh() and would schedule another refresh,
1380  // deleting the one we have just started.
1381 
1382  // ^^ that comment was directly copied from a similar fix in QgsMapCanvas. And
1383  // with little surprise, both those providers are still badly behaved and causing
1384  // annoying bugs for us to deal with...
1385  mDrawingPreview = false;
1386 }
1387 
1388 QgsLayoutItemMap::MapItemFlags QgsLayoutItemMap::mapFlags() const
1389 {
1390  return mMapFlags;
1391 }
1392 
1393 void QgsLayoutItemMap::setMapFlags( QgsLayoutItemMap::MapItemFlags mapFlags )
1394 {
1395  mMapFlags = mapFlags;
1396 }
1397 
1398 QgsMapSettings QgsLayoutItemMap::mapSettings( const QgsRectangle &extent, QSizeF size, double dpi, bool includeLayerSettings ) const
1399 {
1400  QgsExpressionContext expressionContext = createExpressionContext();
1401  QgsCoordinateReferenceSystem renderCrs = crs();
1402 
1403  QgsMapSettings jobMapSettings;
1404  jobMapSettings.setDestinationCrs( renderCrs );
1405  jobMapSettings.setExtent( extent );
1406  jobMapSettings.setOutputSize( size.toSize() );
1407  jobMapSettings.setOutputDpi( dpi );
1408  jobMapSettings.setBackgroundColor( Qt::transparent );
1409  jobMapSettings.setRotation( mEvaluatedMapRotation );
1410  if ( mLayout )
1411  jobMapSettings.setEllipsoid( mLayout->project()->ellipsoid() );
1412 
1413  if ( includeLayerSettings )
1414  {
1415  //set layers to render
1416  QList<QgsMapLayer *> layers = layersToRender( &expressionContext );
1417  jobMapSettings.setLayers( layers );
1418  jobMapSettings.setLayerStyleOverrides( layerStyleOverridesToRender( expressionContext ) );
1419  }
1420 
1421  if ( !mLayout->renderContext().isPreviewRender() )
1422  {
1423  //if outputting layout, we disable optimisations like layer simplification by default, UNLESS the context specifically tells us to use them
1424  jobMapSettings.setFlag( QgsMapSettings::UseRenderingOptimization, mLayout->renderContext().simplifyMethod().simplifyHints() != QgsVectorSimplifyMethod::NoSimplification );
1425  jobMapSettings.setSimplifyMethod( mLayout->renderContext().simplifyMethod() );
1426  }
1427  else
1428  {
1429  // preview render - always use optimization
1430  jobMapSettings.setFlag( QgsMapSettings::UseRenderingOptimization, true );
1431  }
1432 
1433  jobMapSettings.setExpressionContext( expressionContext );
1434 
1435  // layout-specific overrides of flags
1436  jobMapSettings.setFlag( QgsMapSettings::ForceVectorOutput, true ); // force vector output (no caching of marker images etc.)
1437  jobMapSettings.setFlag( QgsMapSettings::Antialiasing, mLayout->renderContext().flags() & QgsLayoutRenderContext::FlagAntialiasing );
1438  jobMapSettings.setFlag( QgsMapSettings::DrawEditingInfo, false );
1439  jobMapSettings.setSelectionColor( mLayout->renderContext().selectionColor() );
1440  jobMapSettings.setFlag( QgsMapSettings::DrawSelection, mLayout->renderContext().flags() & QgsLayoutRenderContext::FlagDrawSelection );
1443  jobMapSettings.setTransformContext( mLayout->project()->transformContext() );
1444  jobMapSettings.setPathResolver( mLayout->project()->pathResolver() );
1445 
1446  QgsLabelingEngineSettings labelSettings = mLayout->project()->labelingEngineSettings();
1447 
1448  // override project "show partial labels" setting with this map's setting
1451  jobMapSettings.setLabelingEngineSettings( labelSettings );
1452 
1453  // override the default text render format inherited from the labeling engine settings using the layout's render context setting
1454  jobMapSettings.setTextRenderFormat( mLayout->renderContext().textRenderFormat() );
1455 
1456  if ( mEvaluatedLabelMargin.length() > 0 )
1457  {
1458  QPolygonF visiblePoly = jobMapSettings.visiblePolygon();
1459  visiblePoly.append( visiblePoly.at( 0 ) ); //close polygon
1460  const double layoutLabelMargin = mLayout->convertToLayoutUnits( mEvaluatedLabelMargin );
1461  const double layoutLabelMarginInMapUnits = layoutLabelMargin / rect().width() * jobMapSettings.extent().width();
1462  QgsGeometry mapBoundaryGeom = QgsGeometry::fromQPolygonF( visiblePoly );
1463  mapBoundaryGeom = mapBoundaryGeom.buffer( -layoutLabelMarginInMapUnits, 0 );
1464  jobMapSettings.setLabelBoundaryGeometry( mapBoundaryGeom );
1465  }
1466 
1467  if ( !mBlockingLabelItems.isEmpty() )
1468  {
1469  jobMapSettings.setLabelBlockingRegions( createLabelBlockingRegions( jobMapSettings ) );
1470  }
1471 
1472  for ( QgsRenderedFeatureHandlerInterface *handler : qgis::as_const( mRenderedFeatureHandlers ) )
1473  {
1474  jobMapSettings.addRenderedFeatureHandler( handler );
1475  }
1476 
1477  if ( isTemporal() )
1478  jobMapSettings.setTemporalRange( temporalRange() );
1479 
1480  return jobMapSettings;
1481 }
1482 
1484 {
1485  assignFreeId();
1486 
1487  mBlockingLabelItems.clear();
1488  for ( const QString &uuid : qgis::as_const( mBlockingLabelItemUuids ) )
1489  {
1490  QgsLayoutItem *item = mLayout->itemByUuid( uuid, true );
1491  if ( item )
1492  {
1493  addLabelBlockingItem( item );
1494  }
1495  }
1496 
1497  mOverviewStack->finalizeRestoreFromXml();
1498  mGridStack->finalizeRestoreFromXml();
1499 }
1500 
1501 void QgsLayoutItemMap::setMoveContentPreviewOffset( double xOffset, double yOffset )
1502 {
1503  mXOffset = xOffset;
1504  mYOffset = yOffset;
1505 }
1506 
1508 {
1509  return mCurrentRectangle;
1510 }
1511 
1513 {
1515 
1516  //Can't utilize QgsExpressionContextUtils::mapSettingsScope as we don't always
1517  //have a QgsMapSettings object available when the context is required, so we manually
1518  //add the same variables here
1519  QgsExpressionContextScope *scope = new QgsExpressionContextScope( tr( "Map Settings" ) );
1520 
1521  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_id" ), id(), true ) );
1522  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_rotation" ), mMapRotation, true ) );
1523  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_scale" ), scale(), true ) );
1524 
1525  QgsRectangle currentExtent( extent() );
1526  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_extent" ), QVariant::fromValue( QgsGeometry::fromRect( currentExtent ) ), true ) );
1527  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_extent_width" ), currentExtent.width(), true ) );
1528  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_extent_height" ), currentExtent.height(), true ) );
1529  QgsGeometry centerPoint = QgsGeometry::fromPointXY( currentExtent.center() );
1530  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_extent_center" ), QVariant::fromValue( centerPoint ), true ) );
1531 
1532  QgsCoordinateReferenceSystem mapCrs = crs();
1533  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_crs" ), mapCrs.authid(), true ) );
1534  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_crs_definition" ), mapCrs.toProj(), true ) );
1535  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_crs_description" ), mapCrs.description(), true ) );
1536  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_units" ), QgsUnitTypes::toString( mapCrs.mapUnits() ), true ) );
1537  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_crs_acronym" ), mapCrs.projectionAcronym(), true ) );
1538  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_crs_ellipsoid" ), mapCrs.ellipsoidAcronym(), true ) );
1539  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_crs_proj4" ), mapCrs.toProj(), true ) );
1540  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_crs_wkt" ), mapCrs.toWkt( QgsCoordinateReferenceSystem::WKT_PREFERRED ), true ) );
1541 
1542  QVariantList layersIds;
1543  QVariantList layers;
1544  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_layer_ids" ), layersIds, true ) );
1545  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_layers" ), layers, true ) );
1546 
1547  context.appendScope( scope );
1548 
1549  // The scope map_layer_ids and map_layers variables have been added to the context, only now we can
1550  // call layersToRender (just in case layersToRender relies on evaluating an expression which uses
1551  // other variables contained within the map settings scope
1552  const QList<QgsMapLayer *> layersInMap = layersToRender( &context );
1553 
1554  layersIds.reserve( layersInMap.count() );
1555  layers.reserve( layersInMap.count() );
1556  for ( QgsMapLayer *layer : layersInMap )
1557  {
1558  layersIds << layer->id();
1559  layers << QVariant::fromValue<QgsWeakMapLayerPointer>( QgsWeakMapLayerPointer( layer ) );
1560  }
1561  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_layer_ids" ), layersIds, true ) );
1562  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_layers" ), layers, true ) );
1563 
1564  scope->addFunction( QStringLiteral( "is_layer_visible" ), new QgsExpressionContextUtils::GetLayerVisibility( layersInMap, scale() ) );
1565 
1566  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_start_time" ), isTemporal() ? temporalRange().begin() : QVariant(), true ) );
1567  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_end_time" ), isTemporal() ? temporalRange().end() : QVariant(), true ) );
1568  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_interval" ), isTemporal() ? ( temporalRange().end() - temporalRange().begin() ) : QVariant(), true ) );
1569 
1570  return context;
1571 }
1572 
1574 {
1575  double extentWidth = extent().width();
1576  if ( extentWidth <= 0 )
1577  {
1578  return 1;
1579  }
1580  return rect().width() / extentWidth;
1581 }
1582 
1584 {
1585  double dx = mXOffset;
1586  double dy = mYOffset;
1587  transformShift( dx, dy );
1588  QPolygonF poly = visibleExtentPolygon();
1589  poly.translate( -dx, -dy );
1590  return poly;
1591 }
1592 
1594 {
1595  if ( !mBlockingLabelItems.contains( item ) )
1596  mBlockingLabelItems.append( item );
1597 
1598  connect( item, &QgsLayoutItem::sizePositionChanged, this, &QgsLayoutItemMap::invalidateCache, Qt::UniqueConnection );
1599 }
1600 
1602 {
1603  mBlockingLabelItems.removeAll( item );
1604  if ( item )
1606 }
1607 
1609 {
1610  return mBlockingLabelItems.contains( item );
1611 }
1612 
1614 {
1615  // NOTE: if visitEnter returns false it means "don't visit the item", not "abort all further visitations"
1617  return true;
1618 
1619  if ( mOverviewStack )
1620  {
1621  for ( int i = 0; i < mOverviewStack->size(); ++i )
1622  {
1623  if ( mOverviewStack->item( i )->accept( visitor ) )
1624  return false;
1625  }
1626  }
1627 
1628  if ( mGridStack )
1629  {
1630  for ( int i = 0; i < mGridStack->size(); ++i )
1631  {
1632  if ( mGridStack->item( i )->accept( visitor ) )
1633  return false;
1634  }
1635  }
1636 
1638  return false;
1639 
1640  return true;
1641 }
1642 
1644 {
1645  mRenderedFeatureHandlers.append( handler );
1646 }
1647 
1649 {
1650  mRenderedFeatureHandlers.removeAll( handler );
1651 }
1652 
1653 QPointF QgsLayoutItemMap::mapToItemCoords( QPointF mapCoords ) const
1654 {
1655  QPolygonF mapPoly = transformedMapPolygon();
1656  if ( mapPoly.empty() )
1657  {
1658  return QPointF( 0, 0 );
1659  }
1660 
1661  QgsRectangle tExtent = transformedExtent();
1662  QgsPointXY rotationPoint( ( tExtent.xMaximum() + tExtent.xMinimum() ) / 2.0, ( tExtent.yMaximum() + tExtent.yMinimum() ) / 2.0 );
1663  double dx = mapCoords.x() - rotationPoint.x();
1664  double dy = mapCoords.y() - rotationPoint.y();
1665  QgsLayoutUtils::rotate( -mEvaluatedMapRotation, dx, dy );
1666  QgsPointXY backRotatedCoords( rotationPoint.x() + dx, rotationPoint.y() + dy );
1667 
1668  QgsRectangle unrotatedExtent = transformedExtent();
1669  double xItem = rect().width() * ( backRotatedCoords.x() - unrotatedExtent.xMinimum() ) / unrotatedExtent.width();
1670  double yItem = rect().height() * ( 1 - ( backRotatedCoords.y() - unrotatedExtent.yMinimum() ) / unrotatedExtent.height() );
1671  return QPointF( xItem, yItem );
1672 }
1673 
1675 {
1677  QgsRectangle newExtent = mExtent;
1678  if ( qgsDoubleNear( mEvaluatedMapRotation, 0.0 ) )
1679  {
1680  extent = newExtent;
1681  }
1682  else
1683  {
1684  QPolygonF poly;
1685  mapPolygon( newExtent, poly );
1686  QRectF bRect = poly.boundingRect();
1687  extent.setXMinimum( bRect.left() );
1688  extent.setXMaximum( bRect.right() );
1689  extent.setYMinimum( bRect.top() );
1690  extent.setYMaximum( bRect.bottom() );
1691  }
1692  return extent;
1693 }
1694 
1696 {
1697  if ( mDrawing )
1698  return;
1699 
1700  mCacheInvalidated = true;
1701  update();
1702 }
1703 
1705 {
1706  QRectF rectangle = rect();
1707  double frameExtension = frameEnabled() ? pen().widthF() / 2.0 : 0.0;
1708 
1709  double topExtension = 0.0;
1710  double rightExtension = 0.0;
1711  double bottomExtension = 0.0;
1712  double leftExtension = 0.0;
1713 
1714  if ( mGridStack )
1715  mGridStack->calculateMaxGridExtension( topExtension, rightExtension, bottomExtension, leftExtension );
1716 
1717  topExtension = std::max( topExtension, frameExtension );
1718  rightExtension = std::max( rightExtension, frameExtension );
1719  bottomExtension = std::max( bottomExtension, frameExtension );
1720  leftExtension = std::max( leftExtension, frameExtension );
1721 
1722  rectangle.setLeft( rectangle.left() - leftExtension );
1723  rectangle.setRight( rectangle.right() + rightExtension );
1724  rectangle.setTop( rectangle.top() - topExtension );
1725  rectangle.setBottom( rectangle.bottom() + bottomExtension );
1726  if ( rectangle != mCurrentRectangle )
1727  {
1728  prepareGeometryChange();
1729  mCurrentRectangle = rectangle;
1730  }
1731 }
1732 
1734 {
1736  if ( property == QgsLayoutObject::MapCrs || property == QgsLayoutObject::AllProperties )
1737  {
1738  bool ok;
1739  QString crsVar = mDataDefinedProperties.valueAsString( QgsLayoutObject::MapCrs, context, QString(), &ok );
1740  if ( ok && QgsCoordinateReferenceSystem( crsVar ).isValid() )
1741  mCrs = QgsCoordinateReferenceSystem( crsVar );
1742  }
1743  //updates data defined properties and redraws item to match
1744  if ( property == QgsLayoutObject::MapRotation || property == QgsLayoutObject::MapScale ||
1745  property == QgsLayoutObject::MapXMin || property == QgsLayoutObject::MapYMin ||
1746  property == QgsLayoutObject::MapXMax || property == QgsLayoutObject::MapYMax ||
1747  property == QgsLayoutObject::MapAtlasMargin ||
1748  property == QgsLayoutObject::AllProperties )
1749  {
1750  QgsRectangle beforeExtent = mExtent;
1751  refreshMapExtents( &context );
1752  emit changed();
1753  if ( mExtent != beforeExtent )
1754  {
1755  emit extentChanged();
1756  }
1757  }
1758  if ( property == QgsLayoutObject::MapLabelMargin || property == QgsLayoutObject::AllProperties )
1759  {
1760  refreshLabelMargin( false );
1761  }
1762  if ( property == QgsLayoutObject::MapStylePreset || property == QgsLayoutObject::AllProperties )
1763  {
1764  const QString previousTheme = mLastEvaluatedThemeName.isEmpty() ? mFollowVisibilityPresetName : mLastEvaluatedThemeName;
1765  mLastEvaluatedThemeName = mDataDefinedProperties.valueAsString( QgsLayoutObject::MapStylePreset, context, mFollowVisibilityPresetName );
1766  if ( mLastEvaluatedThemeName != previousTheme )
1767  emit themeChanged( mLastEvaluatedThemeName );
1768  }
1769 
1770  if ( isTemporal() && ( property == QgsLayoutObject::StartDateTime || property == QgsLayoutObject::EndDateTime || property == QgsLayoutObject::AllProperties ) )
1771  {
1772  QDateTime begin = temporalRange().begin();
1773  QDateTime end = temporalRange().end();
1774 
1775  if ( property == QgsLayoutObject::StartDateTime || property == QgsLayoutObject::AllProperties )
1777  if ( property == QgsLayoutObject::EndDateTime || property == QgsLayoutObject::AllProperties )
1779 
1780  setTemporalRange( QgsDateTimeRange( begin, end ) );
1781  }
1782 
1783  //force redraw
1784  mCacheInvalidated = true;
1785 
1787 }
1788 
1789 void QgsLayoutItemMap::layersAboutToBeRemoved( const QList<QgsMapLayer *> &layers )
1790 {
1791  if ( !mLayers.isEmpty() || mLayerStyleOverrides.isEmpty() )
1792  {
1793  for ( QgsMapLayer *layer : layers )
1794  {
1795  mLayerStyleOverrides.remove( layer->id() );
1796  }
1797  _qgis_removeLayers( mLayers, layers );
1798  }
1799 }
1800 
1801 void QgsLayoutItemMap::painterJobFinished()
1802 {
1803  mPainter->end();
1804  mPainterJob.reset( nullptr );
1805  mPainter.reset( nullptr );
1806  mCacheFinalImage = std::move( mCacheRenderingImage );
1807  mLastRenderedImageOffsetX = 0;
1808  mLastRenderedImageOffsetY = 0;
1809  emit backgroundTaskCountChanged( 0 );
1810  update();
1811 }
1812 
1813 void QgsLayoutItemMap::shapeChanged()
1814 {
1815  // keep center as center
1816  QgsPointXY oldCenter = mExtent.center();
1817 
1818  double w = rect().width();
1819  double h = rect().height();
1820 
1821  // keep same width as before
1822  double newWidth = mExtent.width();
1823  // but scale height to match item's aspect ratio
1824  double newHeight = newWidth * h / w;
1825 
1826  mExtent = QgsRectangle::fromCenterAndSize( oldCenter, newWidth, newHeight );
1827 
1828  //recalculate data defined scale and extents
1829  refreshMapExtents();
1831  invalidateCache();
1832  emit changed();
1833  emit extentChanged();
1834 }
1835 
1836 void QgsLayoutItemMap::mapThemeChanged( const QString &theme )
1837 {
1838  if ( theme == mCachedLayerStyleOverridesPresetName )
1839  mCachedLayerStyleOverridesPresetName.clear(); // force cache regeneration at next redraw
1840 }
1841 
1842 void QgsLayoutItemMap::currentMapThemeRenamed( const QString &theme, const QString &newTheme )
1843 {
1844  if ( theme == mFollowVisibilityPresetName )
1845  {
1846  mFollowVisibilityPresetName = newTheme;
1847  }
1848 }
1849 
1850 void QgsLayoutItemMap::connectUpdateSlot()
1851 {
1852  //connect signal from layer registry to update in case of new or deleted layers
1853  QgsProject *project = mLayout->project();
1854  if ( project )
1855  {
1856  // handles updating the stored layer state BEFORE the layers are removed
1857  connect( project, static_cast < void ( QgsProject::* )( const QList<QgsMapLayer *>& layers ) > ( &QgsProject::layersWillBeRemoved ),
1858  this, &QgsLayoutItemMap::layersAboutToBeRemoved );
1859  // redraws the map AFTER layers are removed
1860  connect( project->layerTreeRoot(), &QgsLayerTree::layerOrderChanged, this, [ = ]
1861  {
1862  if ( layers().isEmpty() )
1863  {
1864  //using project layers, and layer order has changed
1865  invalidateCache();
1866  }
1867  } );
1868 
1869  connect( project, &QgsProject::crsChanged, this, [ = ]
1870  {
1871  if ( !mCrs.isValid() )
1872  {
1873  //using project CRS, which just changed....
1874  invalidateCache();
1875  }
1876  } );
1877 
1878  // If project colors change, we need to redraw the map, as layer symbols may rely on project colors
1879  connect( project, &QgsProject::projectColorsChanged, this, [ = ]
1880  {
1881  invalidateCache();
1882  } );
1883 
1884  connect( project->mapThemeCollection(), &QgsMapThemeCollection::mapThemeChanged, this, &QgsLayoutItemMap::mapThemeChanged );
1885  connect( project->mapThemeCollection(), &QgsMapThemeCollection::mapThemeRenamed, this, &QgsLayoutItemMap::currentMapThemeRenamed );
1886  }
1887  connect( mLayout, &QgsLayout::refreshed, this, &QgsLayoutItemMap::invalidateCache );
1888  connect( &mLayout->renderContext(), &QgsLayoutRenderContext::predefinedScalesChanged, this, [ = ]
1889  {
1890  if ( mAtlasScalingMode == Predefined )
1891  updateAtlasFeature();
1892  } );
1893 }
1894 
1896 {
1897  QPolygonF thisExtent = visibleExtentPolygon();
1898  QTransform mapTransform;
1899  QPolygonF thisRectPoly = QPolygonF( QRectF( 0, 0, rect().width(), rect().height() ) );
1900  //workaround QT Bug #21329
1901  thisRectPoly.pop_back();
1902  thisExtent.pop_back();
1903 
1904  QPolygonF thisItemPolyInLayout = mapToScene( thisRectPoly );
1905 
1906  //create transform from layout coordinates to map coordinates
1907  QTransform::quadToQuad( thisItemPolyInLayout, thisExtent, mapTransform );
1908  return mapTransform;
1909 }
1910 
1911 QList<QgsLabelBlockingRegion> QgsLayoutItemMap::createLabelBlockingRegions( const QgsMapSettings & ) const
1912 {
1913  const QTransform mapTransform = layoutToMapCoordsTransform();
1914  QList< QgsLabelBlockingRegion > blockers;
1915  blockers.reserve( mBlockingLabelItems.count() );
1916  for ( const auto &item : qgis::as_const( mBlockingLabelItems ) )
1917  {
1918  // invisible items don't block labels!
1919  if ( !item )
1920  continue;
1921 
1922  // layout items may be temporarily hidden during layered exports
1923  if ( item->property( "wasVisible" ).isValid() )
1924  {
1925  if ( !item->property( "wasVisible" ).toBool() )
1926  continue;
1927  }
1928  else if ( !item->isVisible() )
1929  continue;
1930 
1931  QPolygonF itemRectInMapCoordinates = mapTransform.map( item->mapToScene( item->rect() ) );
1932  itemRectInMapCoordinates.append( itemRectInMapCoordinates.at( 0 ) ); //close polygon
1933  QgsGeometry blockingRegion = QgsGeometry::fromQPolygonF( itemRectInMapCoordinates );
1934  blockers << QgsLabelBlockingRegion( blockingRegion );
1935  }
1936  return blockers;
1937 }
1938 
1940 {
1941  return mLabelMargin;
1942 }
1943 
1945 {
1946  mLabelMargin = margin;
1947  refreshLabelMargin( false );
1948 }
1949 
1950 void QgsLayoutItemMap::updateToolTip()
1951 {
1952  setToolTip( displayName() );
1953 }
1954 
1955 QString QgsLayoutItemMap::themeToRender( const QgsExpressionContext &context ) const
1956 {
1957  QString presetName;
1958 
1959  if ( mFollowVisibilityPreset )
1960  {
1961  presetName = mFollowVisibilityPresetName;
1962  // preset name can be overridden by data-defined one
1963  presetName = mDataDefinedProperties.valueAsString( QgsLayoutObject::MapStylePreset, context, presetName );
1964  }
1965  else if ( !mExportThemes.empty() && mExportThemeIt != mExportThemes.end() )
1966  presetName = *mExportThemeIt;
1967  return presetName;
1968 }
1969 
1970 QList<QgsMapLayer *> QgsLayoutItemMap::layersToRender( const QgsExpressionContext *context ) const
1971 {
1972  QgsExpressionContext scopedContext;
1973  if ( !context )
1974  scopedContext = createExpressionContext();
1975  const QgsExpressionContext *evalContext = context ? context : &scopedContext;
1976 
1977  QList<QgsMapLayer *> renderLayers;
1978 
1979  QString presetName = themeToRender( *evalContext );
1980  if ( !presetName.isEmpty() )
1981  {
1982  if ( mLayout->project()->mapThemeCollection()->hasMapTheme( presetName ) )
1983  renderLayers = mLayout->project()->mapThemeCollection()->mapThemeVisibleLayers( presetName );
1984  else // fallback to using map canvas layers
1985  renderLayers = mLayout->project()->mapThemeCollection()->masterVisibleLayers();
1986  }
1987  else if ( !layers().isEmpty() )
1988  {
1989  renderLayers = layers();
1990  }
1991  else
1992  {
1993  renderLayers = mLayout->project()->mapThemeCollection()->masterVisibleLayers();
1994  }
1995 
1996  bool ok = false;
1997  QString ddLayers = mDataDefinedProperties.valueAsString( QgsLayoutObject::MapLayers, *evalContext, QString(), &ok );
1998  if ( ok )
1999  {
2000  renderLayers.clear();
2001 
2002  const QStringList layerNames = ddLayers.split( '|' );
2003  //need to convert layer names to layer ids
2004  for ( const QString &name : layerNames )
2005  {
2006  const QList< QgsMapLayer * > matchingLayers = mLayout->project()->mapLayersByName( name );
2007  for ( QgsMapLayer *layer : matchingLayers )
2008  {
2009  renderLayers << layer;
2010  }
2011  }
2012  }
2013 
2014  //remove atlas coverage layer if required
2015  if ( mLayout->renderContext().flags() & QgsLayoutRenderContext::FlagHideCoverageLayer )
2016  {
2017  //hiding coverage layer
2018  int removeAt = renderLayers.indexOf( mLayout->reportContext().layer() );
2019  if ( removeAt != -1 )
2020  {
2021  renderLayers.removeAt( removeAt );
2022  }
2023  }
2024 
2025  // remove any invalid layers
2026  renderLayers.erase( std::remove_if( renderLayers.begin(), renderLayers.end(), []( QgsMapLayer * layer )
2027  {
2028  return !layer || !layer->isValid();
2029  } ), renderLayers.end() );
2030 
2031  return renderLayers;
2032 }
2033 
2034 QMap<QString, QString> QgsLayoutItemMap::layerStyleOverridesToRender( const QgsExpressionContext &context ) const
2035 {
2036  QString presetName = themeToRender( context );
2037  if ( !presetName.isEmpty() )
2038  {
2039  if ( mLayout->project()->mapThemeCollection()->hasMapTheme( presetName ) )
2040  {
2041  if ( presetName != mCachedLayerStyleOverridesPresetName )
2042  {
2043  // have to regenerate cache of style overrides
2044  mCachedPresetLayerStyleOverrides = mLayout->project()->mapThemeCollection()->mapThemeStyleOverrides( presetName );
2045  mCachedLayerStyleOverridesPresetName = presetName;
2046  }
2047 
2048  return mCachedPresetLayerStyleOverrides;
2049  }
2050  else
2051  return QMap<QString, QString>();
2052  }
2053  else if ( mFollowVisibilityPreset )
2054  {
2055  QString presetName = mFollowVisibilityPresetName;
2056  // data defined preset name?
2057  presetName = mDataDefinedProperties.valueAsString( QgsLayoutObject::MapStylePreset, context, presetName );
2058  if ( mLayout->project()->mapThemeCollection()->hasMapTheme( presetName ) )
2059  {
2060  if ( presetName.isEmpty() || presetName != mCachedLayerStyleOverridesPresetName )
2061  {
2062  // have to regenerate cache of style overrides
2063  mCachedPresetLayerStyleOverrides = mLayout->project()->mapThemeCollection()->mapThemeStyleOverrides( presetName );
2064  mCachedLayerStyleOverridesPresetName = presetName;
2065  }
2066 
2067  return mCachedPresetLayerStyleOverrides;
2068  }
2069  else
2070  return QMap<QString, QString>();
2071  }
2072  else if ( mKeepLayerStyles )
2073  {
2074  return mLayerStyleOverrides;
2075  }
2076  else
2077  {
2078  return QMap<QString, QString>();
2079  }
2080 }
2081 
2082 QgsRectangle QgsLayoutItemMap::transformedExtent() const
2083 {
2084  double dx = mXOffset;
2085  double dy = mYOffset;
2086  transformShift( dx, dy );
2087  return QgsRectangle( mExtent.xMinimum() - dx, mExtent.yMinimum() - dy, mExtent.xMaximum() - dx, mExtent.yMaximum() - dy );
2088 }
2089 
2090 void QgsLayoutItemMap::mapPolygon( const QgsRectangle &extent, QPolygonF &poly ) const
2091 {
2092  poly.clear();
2093  if ( qgsDoubleNear( mEvaluatedMapRotation, 0.0 ) )
2094  {
2095  poly << QPointF( extent.xMinimum(), extent.yMaximum() );
2096  poly << QPointF( extent.xMaximum(), extent.yMaximum() );
2097  poly << QPointF( extent.xMaximum(), extent.yMinimum() );
2098  poly << QPointF( extent.xMinimum(), extent.yMinimum() );
2099  //ensure polygon is closed by readding first point
2100  poly << QPointF( poly.at( 0 ) );
2101  return;
2102  }
2103 
2104  //there is rotation
2105  QgsPointXY rotationPoint( ( extent.xMaximum() + extent.xMinimum() ) / 2.0, ( extent.yMaximum() + extent.yMinimum() ) / 2.0 );
2106  double dx, dy; //x-, y- shift from rotation point to corner point
2107 
2108  //top left point
2109  dx = rotationPoint.x() - extent.xMinimum();
2110  dy = rotationPoint.y() - extent.yMaximum();
2111  QgsLayoutUtils::rotate( mEvaluatedMapRotation, dx, dy );
2112  poly << QPointF( rotationPoint.x() - dx, rotationPoint.y() - dy );
2113 
2114  //top right point
2115  dx = rotationPoint.x() - extent.xMaximum();
2116  dy = rotationPoint.y() - extent.yMaximum();
2117  QgsLayoutUtils::rotate( mEvaluatedMapRotation, dx, dy );
2118  poly << QPointF( rotationPoint.x() - dx, rotationPoint.y() - dy );
2119 
2120  //bottom right point
2121  dx = rotationPoint.x() - extent.xMaximum();
2122  dy = rotationPoint.y() - extent.yMinimum();
2123  QgsLayoutUtils::rotate( mEvaluatedMapRotation, dx, dy );
2124  poly << QPointF( rotationPoint.x() - dx, rotationPoint.y() - dy );
2125 
2126  //bottom left point
2127  dx = rotationPoint.x() - extent.xMinimum();
2128  dy = rotationPoint.y() - extent.yMinimum();
2129  QgsLayoutUtils::rotate( mEvaluatedMapRotation, dx, dy );
2130  poly << QPointF( rotationPoint.x() - dx, rotationPoint.y() - dy );
2131 
2132  //ensure polygon is closed by readding first point
2133  poly << QPointF( poly.at( 0 ) );
2134 }
2135 
2136 void QgsLayoutItemMap::transformShift( double &xShift, double &yShift ) const
2137 {
2138  double mmToMapUnits = 1.0 / mapUnitsToLayoutUnits();
2139  double dxScaled = xShift * mmToMapUnits;
2140  double dyScaled = - yShift * mmToMapUnits;
2141 
2142  QgsLayoutUtils::rotate( mEvaluatedMapRotation, dxScaled, dyScaled );
2143 
2144  xShift = dxScaled;
2145  yShift = dyScaled;
2146 }
2147 
2148 void QgsLayoutItemMap::drawAnnotations( QPainter *painter )
2149 {
2150  if ( !mLayout || !mLayout->project() || !mDrawAnnotations )
2151  {
2152  return;
2153  }
2154 
2155  const QList< QgsAnnotation * > annotations = mLayout->project()->annotationManager()->annotations();
2156  if ( annotations.isEmpty() )
2157  return;
2158 
2160  rc.setForceVectorOutput( true );
2162  QList< QgsMapLayer * > layers = layersToRender( &rc.expressionContext() );
2163 
2164  for ( QgsAnnotation *annotation : annotations )
2165  {
2166  if ( !annotation || !annotation->isVisible() )
2167  {
2168  continue;
2169  }
2170  if ( annotation->mapLayer() && !layers.contains( annotation->mapLayer() ) )
2171  continue;
2172 
2173  drawAnnotation( annotation, rc );
2174  }
2175 }
2176 
2177 void QgsLayoutItemMap::drawAnnotation( const QgsAnnotation *annotation, QgsRenderContext &context )
2178 {
2179  if ( !annotation || !annotation->isVisible() || !context.painter() || !context.painter()->device() )
2180  {
2181  return;
2182  }
2183 
2184  context.painter()->save();
2185  context.painter()->setRenderHint( QPainter::Antialiasing, context.flags() & QgsRenderContext::Antialiasing );
2186 
2187  double itemX, itemY;
2188  if ( annotation->hasFixedMapPosition() )
2189  {
2190  QPointF mapPos = layoutMapPosForItem( annotation );
2191  itemX = mapPos.x();
2192  itemY = mapPos.y();
2193  }
2194  else
2195  {
2196  itemX = annotation->relativePosition().x() * rect().width();
2197  itemY = annotation->relativePosition().y() * rect().height();
2198  }
2199  context.painter()->translate( itemX, itemY );
2200 
2201  //setup painter scaling to dots so that symbology is drawn to scale
2202  double dotsPerMM = context.painter()->device()->logicalDpiX() / 25.4;
2203  context.painter()->scale( 1 / dotsPerMM, 1 / dotsPerMM ); // scale painter from mm to dots
2204 
2205  annotation->render( context );
2206  context.painter()->restore();
2207 }
2208 
2209 QPointF QgsLayoutItemMap::layoutMapPosForItem( const QgsAnnotation *annotation ) const
2210 {
2211  if ( !annotation )
2212  return QPointF( 0, 0 );
2213 
2214  double mapX = 0.0;
2215  double mapY = 0.0;
2216 
2217  mapX = annotation->mapPosition().x();
2218  mapY = annotation->mapPosition().y();
2219  QgsCoordinateReferenceSystem annotationCrs = annotation->mapPositionCrs();
2220 
2221  if ( annotationCrs != crs() )
2222  {
2223  //need to reproject
2224  QgsCoordinateTransform t( annotationCrs, crs(), mLayout->project() );
2225  double z = 0.0;
2226  try
2227  {
2228  t.transformInPlace( mapX, mapY, z );
2229  }
2230  catch ( const QgsCsException & )
2231  {
2232  }
2233  }
2234 
2235  return mapToItemCoords( QPointF( mapX, mapY ) );
2236 }
2237 
2238 void QgsLayoutItemMap::drawMapFrame( QPainter *p )
2239 {
2240  if ( frameEnabled() && p )
2241  {
2244 
2246  }
2247 }
2248 
2249 void QgsLayoutItemMap::drawMapBackground( QPainter *p )
2250 {
2251  if ( hasBackground() && p )
2252  {
2255 
2257  }
2258 }
2259 
2260 bool QgsLayoutItemMap::shouldDrawPart( QgsLayoutItemMap::PartType part ) const
2261 {
2262  if ( mCurrentExportPart == NotLayered )
2263  {
2264  //all parts of the map are visible
2265  return true;
2266  }
2267 
2268  switch ( part )
2269  {
2270  case NotLayered:
2271  return true;
2272 
2273  case Start:
2274  return false;
2275 
2276  case Background:
2277  return mCurrentExportPart == Background && hasBackground();
2278 
2279  case Layer:
2280  return mCurrentExportPart == Layer;
2281 
2282  case Grid:
2283  return mCurrentExportPart == Grid && mGridStack->hasEnabledItems();
2284 
2285  case OverviewMapExtent:
2286  return mCurrentExportPart == OverviewMapExtent && mOverviewStack->hasEnabledItems();
2287 
2288  case Frame:
2289  return mCurrentExportPart == Frame && frameEnabled();
2290 
2291  case SelectionBoxes:
2292  return mCurrentExportPart == SelectionBoxes && isSelected();
2293 
2294  case End:
2295  return false;
2296  }
2297 
2298  return false;
2299 }
2300 
2301 void QgsLayoutItemMap::refreshMapExtents( const QgsExpressionContext *context )
2302 {
2303  QgsExpressionContext scopedContext;
2304  if ( !context )
2305  scopedContext = createExpressionContext();
2306 
2307  bool ok = false;
2308  const QgsExpressionContext *evalContext = context ? context : &scopedContext;
2309 
2310 
2311  //data defined map extents set?
2312  QgsRectangle newExtent = extent();
2313  bool useDdXMin = false;
2314  bool useDdXMax = false;
2315  bool useDdYMin = false;
2316  bool useDdYMax = false;
2317  double minXD = 0;
2318  double minYD = 0;
2319  double maxXD = 0;
2320  double maxYD = 0;
2321 
2322  minXD = mDataDefinedProperties.valueAsDouble( QgsLayoutObject::MapXMin, *evalContext, 0.0, &ok );
2323  if ( ok )
2324  {
2325  useDdXMin = true;
2326  newExtent.setXMinimum( minXD );
2327  }
2328  minYD = mDataDefinedProperties.valueAsDouble( QgsLayoutObject::MapYMin, *evalContext, 0.0, &ok );
2329  if ( ok )
2330  {
2331  useDdYMin = true;
2332  newExtent.setYMinimum( minYD );
2333  }
2334  maxXD = mDataDefinedProperties.valueAsDouble( QgsLayoutObject::MapXMax, *evalContext, 0.0, &ok );
2335  if ( ok )
2336  {
2337  useDdXMax = true;
2338  newExtent.setXMaximum( maxXD );
2339  }
2340  maxYD = mDataDefinedProperties.valueAsDouble( QgsLayoutObject::MapYMax, *evalContext, 0.0, &ok );
2341  if ( ok )
2342  {
2343  useDdYMax = true;
2344  newExtent.setYMaximum( maxYD );
2345  }
2346 
2347  if ( newExtent != mExtent )
2348  {
2349  //calculate new extents to fit data defined extents
2350 
2351  //Make sure the width/height ratio is the same as in current map extent.
2352  //This is to keep the map item frame and the page layout fixed
2353  double currentWidthHeightRatio = mExtent.width() / mExtent.height();
2354  double newWidthHeightRatio = newExtent.width() / newExtent.height();
2355 
2356  if ( currentWidthHeightRatio < newWidthHeightRatio )
2357  {
2358  //enlarge height of new extent, ensuring the map center stays the same
2359  double newHeight = newExtent.width() / currentWidthHeightRatio;
2360  double deltaHeight = newHeight - newExtent.height();
2361  newExtent.setYMinimum( newExtent.yMinimum() - deltaHeight / 2 );
2362  newExtent.setYMaximum( newExtent.yMaximum() + deltaHeight / 2 );
2363  }
2364  else
2365  {
2366  //enlarge width of new extent, ensuring the map center stays the same
2367  double newWidth = currentWidthHeightRatio * newExtent.height();
2368  double deltaWidth = newWidth - newExtent.width();
2369  newExtent.setXMinimum( newExtent.xMinimum() - deltaWidth / 2 );
2370  newExtent.setXMaximum( newExtent.xMaximum() + deltaWidth / 2 );
2371  }
2372 
2373  mExtent = newExtent;
2374  }
2375 
2376  //now refresh scale, as this potentially overrides extents
2377 
2378  //data defined map scale set?
2379  double scaleD = mDataDefinedProperties.valueAsDouble( QgsLayoutObject::MapScale, *evalContext, 0.0, &ok );
2380  if ( ok )
2381  {
2382  setScale( scaleD, false );
2383  newExtent = mExtent;
2384  }
2385 
2386  if ( useDdXMax || useDdXMin || useDdYMax || useDdYMin )
2387  {
2388  //if only one of min/max was set for either x or y, then make sure our extent is locked on that value
2389  //as we can do this without altering the scale
2390  if ( useDdXMin && !useDdXMax )
2391  {
2392  double xMax = mExtent.xMaximum() - ( mExtent.xMinimum() - minXD );
2393  newExtent.setXMinimum( minXD );
2394  newExtent.setXMaximum( xMax );
2395  }
2396  else if ( !useDdXMin && useDdXMax )
2397  {
2398  double xMin = mExtent.xMinimum() - ( mExtent.xMaximum() - maxXD );
2399  newExtent.setXMinimum( xMin );
2400  newExtent.setXMaximum( maxXD );
2401  }
2402  if ( useDdYMin && !useDdYMax )
2403  {
2404  double yMax = mExtent.yMaximum() - ( mExtent.yMinimum() - minYD );
2405  newExtent.setYMinimum( minYD );
2406  newExtent.setYMaximum( yMax );
2407  }
2408  else if ( !useDdYMin && useDdYMax )
2409  {
2410  double yMin = mExtent.yMinimum() - ( mExtent.yMaximum() - maxYD );
2411  newExtent.setYMinimum( yMin );
2412  newExtent.setYMaximum( maxYD );
2413  }
2414 
2415  if ( newExtent != mExtent )
2416  {
2417  mExtent = newExtent;
2418  }
2419  }
2420 
2421  //lastly, map rotation overrides all
2422  double mapRotation = mMapRotation;
2423 
2424  //data defined map rotation set?
2426 
2427  if ( !qgsDoubleNear( mEvaluatedMapRotation, mapRotation ) )
2428  {
2429  mEvaluatedMapRotation = mapRotation;
2431  }
2432 }
2433 
2434 void QgsLayoutItemMap::refreshLabelMargin( bool updateItem )
2435 {
2436  //data defined label margin set?
2438  mEvaluatedLabelMargin.setLength( labelMargin );
2439  mEvaluatedLabelMargin.setUnits( mLabelMargin.units() );
2440 
2441  if ( updateItem )
2442  {
2443  update();
2444  }
2445 }
2446 
2447 void QgsLayoutItemMap::updateAtlasFeature()
2448 {
2449  if ( !atlasDriven() || !mLayout->reportContext().layer() )
2450  return; // nothing to do
2451 
2452  QgsRectangle bounds = computeAtlasRectangle();
2453  if ( bounds.isNull() )
2454  return;
2455 
2456  double xa1 = bounds.xMinimum();
2457  double xa2 = bounds.xMaximum();
2458  double ya1 = bounds.yMinimum();
2459  double ya2 = bounds.yMaximum();
2460  QgsRectangle newExtent = bounds;
2461  QgsRectangle originalExtent = mExtent;
2462 
2463  //sanity check - only allow fixed scale mode for point layers
2464  bool isPointLayer = QgsWkbTypes::geometryType( mLayout->reportContext().layer()->wkbType() ) == QgsWkbTypes::PointGeometry;
2465 
2466  if ( mAtlasScalingMode == Fixed || mAtlasScalingMode == Predefined || isPointLayer )
2467  {
2468  QgsScaleCalculator calc;
2469  calc.setMapUnits( crs().mapUnits() );
2470  calc.setDpi( 25.4 );
2471  double originalScale = calc.calculate( originalExtent, rect().width() );
2472  double geomCenterX = ( xa1 + xa2 ) / 2.0;
2473  double geomCenterY = ( ya1 + ya2 ) / 2.0;
2474  QVector<qreal> scales;
2476  if ( !mLayout->reportContext().predefinedScales().empty() ) // remove when deprecated method is removed
2477  scales = mLayout->reportContext().predefinedScales();
2478  else
2479  scales = mLayout->renderContext().predefinedScales();
2481  if ( mAtlasScalingMode == Fixed || isPointLayer || scales.isEmpty() )
2482  {
2483  // only translate, keep the original scale (i.e. width x height)
2484  double xMin = geomCenterX - originalExtent.width() / 2.0;
2485  double yMin = geomCenterY - originalExtent.height() / 2.0;
2486  newExtent = QgsRectangle( xMin,
2487  yMin,
2488  xMin + originalExtent.width(),
2489  yMin + originalExtent.height() );
2490 
2491  //scale newExtent to match original scale of map
2492  //this is required for geographic coordinate systems, where the scale varies by extent
2493  double newScale = calc.calculate( newExtent, rect().width() );
2494  newExtent.scale( originalScale / newScale );
2495  }
2496  else if ( mAtlasScalingMode == Predefined )
2497  {
2498  // choose one of the predefined scales
2499  double newWidth = originalExtent.width();
2500  double newHeight = originalExtent.height();
2501  for ( int i = 0; i < scales.size(); i++ )
2502  {
2503  double ratio = scales[i] / originalScale;
2504  newWidth = originalExtent.width() * ratio;
2505  newHeight = originalExtent.height() * ratio;
2506 
2507  // compute new extent, centered on feature
2508  double xMin = geomCenterX - newWidth / 2.0;
2509  double yMin = geomCenterY - newHeight / 2.0;
2510  newExtent = QgsRectangle( xMin,
2511  yMin,
2512  xMin + newWidth,
2513  yMin + newHeight );
2514 
2515  //scale newExtent to match desired map scale
2516  //this is required for geographic coordinate systems, where the scale varies by extent
2517  double newScale = calc.calculate( newExtent, rect().width() );
2518  newExtent.scale( scales[i] / newScale );
2519 
2520  if ( ( newExtent.width() >= bounds.width() ) && ( newExtent.height() >= bounds.height() ) )
2521  {
2522  // this is the smallest extent that embeds the feature, stop here
2523  break;
2524  }
2525  }
2526  }
2527  }
2528  else if ( mAtlasScalingMode == Auto )
2529  {
2530  // auto scale
2531 
2532  double geomRatio = bounds.width() / bounds.height();
2533  double mapRatio = originalExtent.width() / originalExtent.height();
2534 
2535  // geometry height is too big
2536  if ( geomRatio < mapRatio )
2537  {
2538  // extent the bbox's width
2539  double adjWidth = ( mapRatio * bounds.height() - bounds.width() ) / 2.0;
2540  xa1 -= adjWidth;
2541  xa2 += adjWidth;
2542  }
2543  // geometry width is too big
2544  else if ( geomRatio > mapRatio )
2545  {
2546  // extent the bbox's height
2547  double adjHeight = ( bounds.width() / mapRatio - bounds.height() ) / 2.0;
2548  ya1 -= adjHeight;
2549  ya2 += adjHeight;
2550  }
2551  newExtent = QgsRectangle( xa1, ya1, xa2, ya2 );
2552 
2553  const double evaluatedAtlasMargin = atlasMargin();
2554  if ( evaluatedAtlasMargin > 0.0 )
2555  {
2556  newExtent.scale( 1 + evaluatedAtlasMargin );
2557  }
2558  }
2559 
2560  // set the new extent (and render)
2561  setExtent( newExtent );
2562  emit preparedForAtlas();
2563 }
2564 
2565 QgsRectangle QgsLayoutItemMap::computeAtlasRectangle()
2566 {
2567  // QgsGeometry::boundingBox is expressed in the geometry"s native CRS
2568  // We have to transform the geometry to the destination CRS and ask for the bounding box
2569  // Note: we cannot directly take the transformation of the bounding box, since transformations are not linear
2570  QgsGeometry g = mLayout->reportContext().currentGeometry( crs() );
2571  // Rotating the geometry, so the bounding box is correct wrt map rotation
2572  if ( mEvaluatedMapRotation != 0.0 )
2573  {
2574  QgsPointXY prevCenter = g.boundingBox().center();
2575  g.rotate( mEvaluatedMapRotation, g.boundingBox().center() );
2576  // Rotation center will be still the bounding box center of an unrotated geometry.
2577  // Which means, if the center of bbox moves after rotation, the viewport will
2578  // also be offset, and part of the geometry will fall out of bounds.
2579  // Here we compensate for that roughly: by extending the rotated bounds
2580  // so that its center is the same as the original.
2581  QgsRectangle bounds = g.boundingBox();
2582  double dx = std::max( std::abs( prevCenter.x() - bounds.xMinimum() ),
2583  std::abs( prevCenter.x() - bounds.xMaximum() ) );
2584  double dy = std::max( std::abs( prevCenter.y() - bounds.yMinimum() ),
2585  std::abs( prevCenter.y() - bounds.yMaximum() ) );
2586  QgsPointXY center = g.boundingBox().center();
2587  return QgsRectangle( center.x() - dx, center.y() - dy,
2588  center.x() + dx, center.y() + dy );
2589  }
2590  else
2591  {
2592  return g.boundingBox();
2593  }
2594 }
2595 
2596 void QgsLayoutItemMap::createStagedRenderJob( const QgsRectangle &extent, const QSizeF size, double dpi )
2597 {
2598  QgsMapSettings settings = mapSettings( extent, size, dpi, true );
2599  settings.setLayers( mOverviewStack->modifyMapLayerList( settings.layers() ) );
2600 
2601  mStagedRendererJob = qgis::make_unique< QgsMapRendererStagedRenderJob >( settings,
2604  : QgsMapRendererStagedRenderJob::Flags( nullptr ) );
2605  mStagedRendererJob->start();
2606 }
2607 
2608 
QgsLayoutRenderContext::FlagUseAdvancedEffects
@ FlagUseAdvancedEffects
Enable advanced effects such as blend modes.
Definition: qgslayoutrendercontext.h:45
QgsGeometry::fromPointXY
static QgsGeometry fromPointXY(const QgsPointXY &point)
Creates a new geometry from a QgsPointXY object.
Definition: qgsgeometry.cpp:164
QgsLayoutItem::shouldDrawItem
bool shouldDrawItem() const
Returns whether the item should be drawn in the current context.
Definition: qgslayoutitem.cpp:594
QgsExpressionContext
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
Definition: qgsexpressioncontext.h:369
QgsLayoutItem::id
QString id() const
Returns the item's ID name.
Definition: qgslayoutitem.h:354
QgsExpressionContextScope::addFunction
void addFunction(const QString &name, QgsScopedExpressionFunction *function)
Adds a function to the scope.
Definition: qgsexpressioncontext.cpp:189
QgsMapSettings::setDestinationCrs
void setDestinationCrs(const QgsCoordinateReferenceSystem &crs)
sets destination coordinate reference system
Definition: qgsmapsettings.cpp:309
QgsLayoutObject::layout
const QgsLayout * layout() const
Returns the layout the object is attached to.
Definition: qgslayoutobject.cpp:118
QgsMapRendererStagedRenderJob::Symbology
@ Symbology
Rendering layer symbology.
Definition: qgsmaprendererstagedrenderjob.h:51
QgsLayoutItemMap::addLabelBlockingItem
void addLabelBlockingItem(QgsLayoutItem *item)
Sets the specified layout item as a "label blocking item" for this map.
Definition: qgslayoutitemmap.cpp:1593
QgsLayoutItemMap::grid
QgsLayoutItemMapGrid * grid()
Returns the map item's first grid.
Definition: qgslayoutitemmap.cpp:517
qgsexpressioncontextutils.h
QgsLayoutItemMap::startLayeredExport
void startLayeredExport() override
Starts a multi-layer export operation.
Definition: qgslayoutitemmap.cpp:1045
QgsLayoutItemMapGrid
An individual grid which is drawn above the map content in a QgsLayoutItemMap.
Definition: qgslayoutitemmapgrid.h:138
QgsVectorSimplifyMethod::NoSimplification
@ NoSimplification
No simplification can be applied.
Definition: qgsvectorsimplifymethod.h:52
QgsLayoutItemMap::assignFreeId
void assignFreeId()
Sets the map id() to a number not yet used in the layout.
Definition: qgslayoutitemmap.cpp:89
QgsAbstractPropertyCollection::valueAsDouble
double valueAsDouble(int key, const QgsExpressionContext &context, double defaultValue=0.0, bool *ok=nullptr) const
Calculates the current value of the property with the specified key and interprets it as a double.
Definition: qgspropertycollection.cpp:66
QgsPointXY::y
double y
Definition: qgspointxy.h:48
QgsLayoutRenderContext::FlagRenderLabelsByMapLayer
@ FlagRenderLabelsByMapLayer
When rendering map items to multi-layered exports, render labels belonging to different layers into s...
Definition: qgslayoutrendercontext.h:50
QgsMapSettings::setLabelBoundaryGeometry
void setLabelBoundaryGeometry(const QgsGeometry &boundary)
Sets the label boundary geometry, which restricts where in the rendered map labels are permitted to b...
Definition: qgsmapsettings.cpp:680
QgsLayoutObject::StartDateTime
@ StartDateTime
Temporal range's start DateTime.
Definition: qgslayoutobject.h:195
qgsmaplayerstylemanager.h
QgsCoordinateReferenceSystem::description
QString description() const
Returns the descriptive name of the CRS, e.g., "WGS 84" or "GDA 94 / Vicgrid94".
Definition: qgscoordinatereferencesystem.cpp:1304
QgsMapThemeCollection::mapThemeRenamed
void mapThemeRenamed(const QString &name, const QString &newName)
Emitted when a map theme within the collection is renamed.
QgsProject::layersWillBeRemoved
void layersWillBeRemoved(const QStringList &layerIds)
Emitted when one or more layers are about to be removed from the registry.
QgsLayoutMeasurement::setUnits
void setUnits(const QgsUnitTypes::LayoutUnit units)
Sets the units for the measurement.
Definition: qgslayoutmeasurement.h:67
QgsApplication::getThemeIcon
static QIcon getThemeIcon(const QString &name)
Helper to get a theme icon.
Definition: qgsapplication.cpp:605
QgsLayoutItem::sizePositionChanged
void sizePositionChanged()
Emitted when the item's size or position changes.
QgsLayoutItemMap::draw
void draw(QgsLayoutItemRenderContext &context) override
Draws the item's contents using the specified item render context.
Definition: qgslayoutitemmap.cpp:537
QgsAnnotation::mapPosition
QgsPointXY mapPosition
Definition: qgsannotation.h:69
QgsMapSettings::setFlag
void setFlag(Flag flag, bool on=true)
Enable or disable a particular flag (other flags are not affected)
Definition: qgsmapsettings.cpp:341
QgsLayoutItemMap::Auto
@ Auto
The extent is adjusted so that each feature is fully visible.
Definition: qgslayoutitemmap.h:66
QgsScaleCalculator::setMapUnits
void setMapUnits(QgsUnitTypes::DistanceUnit mapUnits)
Set the map units.
Definition: qgsscalecalculator.cpp:38
QgsRenderContext::expressionContext
QgsExpressionContext & expressionContext()
Gets the expression context.
Definition: qgsrendercontext.h:580
QgsLayoutItem::frameEnabled
bool frameEnabled() const
Returns true if the item includes a frame.
Definition: qgslayoutitem.h:727
_LayerRef::resolveWeakly
TYPE * resolveWeakly(const QgsProject *project, MatchType matchType=MatchType::All)
Resolves the map layer by attempting to find a matching layer in a project using a weak match.
Definition: qgsmaplayerref.h:210
QgsLayoutItemMap::updateBoundingRect
void updateBoundingRect()
Updates the bounding rect of this item. Call this function before doing any changes related to annota...
Definition: qgslayoutitemmap.cpp:1704
QgsReadWriteContext
Definition: qgsreadwritecontext.h:34
QgsScaleCalculator::setDpi
void setDpi(double dpi)
Sets the dpi (dots per inch) for the output resolution, to be used in scale calculations.
Definition: qgsscalecalculator.cpp:29
QgsCoordinateReferenceSystem::projectionAcronym
QString projectionAcronym() const
Returns the projection acronym for the projection used by the CRS.
Definition: qgscoordinatereferencesystem.cpp:1339
QgsMapSettings::setRotation
void setRotation(double rotation)
Sets the rotation of the resulting map image, in degrees clockwise.
Definition: qgsmapsettings.cpp:106
qgsmapthemecollection.h
QgsLayoutItemMap::QgsLayoutItemMapGrid
friend class QgsLayoutItemMapGrid
Definition: qgslayoutitemmap.h:858
QgsExpressionContextScope::addVariable
void addVariable(const QgsExpressionContextScope::StaticVariable &variable)
Adds a variable into the context scope.
Definition: qgsexpressioncontext.cpp:93
QgsLayoutItemMap::writePropertiesToElement
bool writePropertiesToElement(QDomElement &element, QDomDocument &document, const QgsReadWriteContext &context) const override
Stores item state within an XML DOM element.
Definition: qgslayoutitemmap.cpp:541
qgsannotation.h
QgsLayoutItemMap::mapToItemCoords
QPointF mapToItemCoords(QPointF mapCoords) const
Transforms map coordinates to item coordinates (considering rotation and move offset)
Definition: qgslayoutitemmap.cpp:1653
QgsRectangle::setXMinimum
void setXMinimum(double x)
Set the minimum x value.
Definition: qgsrectangle.h:130
QgsLayoutItem::setFrameStrokeWidth
virtual void setFrameStrokeWidth(QgsLayoutMeasurement width)
Sets the frame stroke width.
Definition: qgslayoutitem.cpp:860
QgsLayoutItemMap::numberExportLayers
Q_DECL_DEPRECATED int numberExportLayers() const override
Returns the number of layers that this item requires for exporting during layered exports (e....
Definition: qgslayoutitemmap.cpp:1035
QgsLayoutMeasurement::length
double length() const
Returns the length of the measurement.
Definition: qgslayoutmeasurement.h:48
QgsLayoutItemMap::exportLayerBehavior
ExportLayerBehavior exportLayerBehavior() const override
Returns the behavior of this item during exporting to layered exports (e.g.
Definition: qgslayoutitemmap.cpp:1140
QgsCoordinateReferenceSystem::WKT_PREFERRED
@ WKT_PREFERRED
Preferred format, matching the most recent WKT ISO standard. Currently an alias to WKT2_2019,...
Definition: qgscoordinatereferencesystem.h:678
QgsScaleCalculator::calculate
double calculate(const QgsRectangle &mapExtent, double canvasWidth) const
Calculate the scale denominator.
Definition: qgsscalecalculator.cpp:50
QgsTemporalRangeObject::isTemporal
bool isTemporal() const
Returns true if the object's temporal range is enabled, and the object will be filtered when renderin...
Definition: qgstemporalrangeobject.cpp:30
QgsLayoutItemMap::refresh
void refresh() override
Definition: qgslayoutitemmap.cpp:132
QgsLayoutMeasurement::setLength
void setLength(const double length)
Sets the length of the measurement.
Definition: qgslayoutmeasurement.h:54
QgsLayoutItemMap::extentChanged
void extentChanged()
Emitted when the map's extent changes.
crs
const QgsCoordinateReferenceSystem & crs
Definition: qgswfsgetfeature.cpp:105
QgsLayoutRenderContext::predefinedScalesChanged
void predefinedScalesChanged()
Emitted when the list of predefined scales changes.
QgsMapSettings::setTextRenderFormat
void setTextRenderFormat(QgsRenderContext::TextRenderFormat format)
Sets the text render format, which dictates how text is rendered (e.g.
Definition: qgsmapsettings.h:347
QgsAnnotation::render
void render(QgsRenderContext &context) const
Renders the annotation to a target render context.
Definition: qgsannotation.cpp:133
QgsLayoutItemMap::setFollowVisibilityPresetName
void setFollowVisibilityPresetName(const QString &name)
Sets preset name for map rendering.
Definition: qgslayoutitemmap.cpp:322
QgsTemporalRangeObject::setIsTemporal
void setIsTemporal(bool enabled)
Sets whether the temporal range is enabled (i.e.
Definition: qgstemporalrangeobject.cpp:25
QgsRectangle::xMaximum
double xMaximum() const
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:162
QgsLayoutItemMap::layerStyleOverridesChanged
void layerStyleOverridesChanged()
Emitted when layer style overrides are changed...
QgsMapThemeCollection::mapThemeChanged
void mapThemeChanged(const QString &theme)
Emitted when a map theme changes definition.
QgsMapRendererStagedRenderJob::Finished
@ Finished
Rendering is finished.
Definition: qgsmaprendererstagedrenderjob.h:53
QgsLayoutItemRenderContext
Definition: qgslayoutitem.h:44
QgsLayoutItem::attemptSetSceneRect
void attemptSetSceneRect(const QRectF &rect, bool includesFrame=false)
Attempts to update the item's position and size to match the passed rect in layout coordinates.
Definition: qgslayoutitem.cpp:514
QgsLayoutItemMap::~QgsLayoutItemMap
~QgsLayoutItemMap() override
Definition: qgslayoutitemmap.cpp:63
QgsMapLayerStyle::readFromLayer
void readFromLayer(QgsMapLayer *layer)
Store layer's active style information in the instance.
Definition: qgsmaplayerstyle.cpp:48
QgsLayoutItem::ExportLayerDetail::mapTheme
QString mapTheme
Associated map theme, or an empty string if this export layer does not need to be associated with a m...
Definition: qgslayoutitem.h:508
QgsLayoutItemMap::atlasDriven
bool atlasDriven() const
Returns whether the map extent is set to follow the current atlas feature.
Definition: qgslayoutitemmap.h:357
QgsLayoutItemMap::mapSettings
QgsMapSettings mapSettings(const QgsRectangle &extent, QSizeF size, double dpi, bool includeLayerSettings) const
Returns map settings that will be used for drawing of the map.
Definition: qgslayoutitemmap.cpp:1398
QgsLayoutObject::mDataDefinedProperties
QgsPropertyCollection mDataDefinedProperties
Definition: qgslayoutobject.h:337
QgsTemporalRangeObject::temporalRange
const QgsDateTimeRange & temporalRange() const
Returns the datetime range for the object.
Definition: qgstemporalrangeobject.cpp:43
QgsRenderContext
Definition: qgsrendercontext.h:57
QgsLayoutItemMap::addRenderedFeatureHandler
void addRenderedFeatureHandler(QgsRenderedFeatureHandlerInterface *handler)
Adds a rendered feature handler to use while rendering the map.
Definition: qgslayoutitemmap.cpp:1643
QgsLayoutItemMapItem
An item which is drawn inside a QgsLayoutItemMap, e.g., a grid or map overview.
Definition: qgslayoutitemmapitem.h:33
QgsLayoutItemMap::AtlasScalingMode
AtlasScalingMode
Scaling modes used for the serial rendering (atlas)
Definition: qgslayoutitemmap.h:49
QgsStyleEntityVisitorInterface
Definition: qgsstyleentityvisitor.h:33
QgsLayoutItemMap::createExpressionContext
QgsExpressionContext createExpressionContext() const override
This method needs to be reimplemented in all classes which implement this interface and return an exp...
Definition: qgslayoutitemmap.cpp:1512
QgsGeometry::rotate
OperationResult rotate(double rotation, const QgsPointXY &center)
Rotate this geometry around the Z axis.
Definition: qgsgeometry.cpp:803
QgsLayoutItem::refreshDataDefinedProperty
virtual void refreshDataDefinedProperty(QgsLayoutObject::DataDefinedProperty property=QgsLayoutObject::AllProperties)
Refreshes a data defined property for the item by reevaluating the property's value and redrawing the...
Definition: qgslayoutitem.cpp:1082
QgsStyleEntityVisitorInterface::visitExit
virtual bool visitExit(const QgsStyleEntityVisitorInterface::Node &node)
Called when the visitor stops visiting a node.
Definition: qgsstyleentityvisitor.h:183
QgsLayoutItemMap::isLabelBlockingItem
bool isLabelBlockingItem(QgsLayoutItem *item) const
Returns true if the specified item is a "label blocking item".
Definition: qgslayoutitemmap.cpp:1608
QgsMapSettings::RenderPartialOutput
@ RenderPartialOutput
Whether to make extra effort to update map image with partially rendered layers (better for interacti...
Definition: qgsmapsettings.h:311
QgsLayoutItemMap::drawAnnotations
bool drawAnnotations() const
Returns whether annotations are drawn within the map.
Definition: qgslayoutitemmap.h:348
QgsLayout::refreshed
void refreshed()
Emitted when the layout has been refreshed and items should also be refreshed and updated.
QgsLayoutItemMap::storeCurrentLayerStyles
void storeCurrentLayerStyles()
Stores the current project layer styles into style overrides.
Definition: qgslayoutitemmap.cpp:298
FALLTHROUGH
#define FALLTHROUGH
Definition: qgis.h:783
QgsMapSettings::setOutputDpi
void setOutputDpi(double dpi)
Sets DPI used for conversion between real world units (e.g. mm) and pixels.
Definition: qgsmapsettings.cpp:267
QgsLayoutItemMap::ShowPartialLabels
@ ShowPartialLabels
Whether to draw labels which are partially outside of the map view.
Definition: qgslayoutitemmap.h:75
QgsLayoutItemMap::setCrs
void setCrs(const QgsCoordinateReferenceSystem &crs)
Sets the map's preset crs (coordinate reference system).
Definition: qgslayoutitemmap.cpp:273
QgsLayoutItem::drawFrame
virtual void drawFrame(QgsRenderContext &context)
Draws the frame around the item.
Definition: qgslayoutitem.cpp:1210
QgsStyleEntityVisitorInterface::NodeType::LayoutItem
@ LayoutItem
Individual item in a print layout.
QgsCoordinateReferenceSystem::readXml
bool readXml(const QDomNode &node)
Restores state from the given DOM node.
Definition: qgscoordinatereferencesystem.cpp:1995
QgsLayoutObject::changed
void changed()
Emitted when the object's properties change.
QgsGeometry::buffer
QgsGeometry buffer(double distance, int segments) const
Returns a buffer region around this geometry having the given width and with a specified number of se...
Definition: qgsgeometry.cpp:1919
QgsLayoutItemMap::preparedForAtlas
void preparedForAtlas()
Emitted when the map has been prepared for atlas rendering, just before actual rendering.
QgsLayoutRenderContext::FlagDisableTiledRasterLayerRenders
@ FlagDisableTiledRasterLayerRenders
If set, then raster layers will not be drawn as separate tiles. This may improve the appearance in ex...
Definition: qgslayoutrendercontext.h:49
QgsLayoutItem::ExportLayerDetail::compositionMode
QPainter::CompositionMode compositionMode
Associated composition mode if this layer is associated with a map layer.
Definition: qgslayoutitem.h:499
QgsLayoutObject::MapXMin
@ MapXMin
Map extent x minimum.
Definition: qgslayoutobject.h:159
QgsLayoutItemMap::setFrameStrokeWidth
void setFrameStrokeWidth(QgsLayoutMeasurement width) override
Sets the frame stroke width.
Definition: qgslayoutitemmap.cpp:1259
QgsRectangle
Definition: qgsrectangle.h:41
QgsLayoutItem::backgroundTaskCountChanged
void backgroundTaskCountChanged(int count)
Emitted whenever the number of background tasks an item is executing changes.
QgsLayoutItemMap::itemFlags
QgsLayoutItem::Flags itemFlags() const override
Returns the item's flags, which indicate how the item behaves.
Definition: qgslayoutitemmap.cpp:84
qgsDoubleToString
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
Definition: qgis.h:275
QgsProject
Definition: qgsproject.h:92
QgsLayoutMeasurement::encodeMeasurement
QString encodeMeasurement() const
Encodes the layout measurement to a string.
Definition: qgslayoutmeasurement.cpp:28
QgsLayoutItemMap::nextExportPart
bool nextExportPart() override
Moves to the next export part for a multi-layered export item, during a multi-layered export.
Definition: qgslayoutitemmap.cpp:1060
QgsLayerTree::layerOrderChanged
void layerOrderChanged()
Emitted when the layer order has changed.
QgsRenderedFeatureHandlerInterface
Definition: qgsrenderedfeaturehandlerinterface.h:46
QgsGeometry::fromRect
static QgsGeometry fromRect(const QgsRectangle &rect)
Creates a new geometry from a QgsRectangle.
Definition: qgsgeometry.cpp:229
QgsLayoutItemMap::paint
void paint(QPainter *painter, const QStyleOptionGraphicsItem *itemStyle, QWidget *pWidget) override
Definition: qgslayoutitemmap.cpp:829
QgsLayoutObject::MapCrs
@ MapCrs
Map CRS.
Definition: qgslayoutobject.h:194
QgsMapSettings::UseAdvancedEffects
@ UseAdvancedEffects
Enable layer opacity and blending effects.
Definition: qgsmapsettings.h:305
QgsMapSettings::extent
QgsRectangle extent() const
Returns geographical coordinates of the rectangle that should be rendered.
Definition: qgsmapsettings.cpp:74
QgsLayoutItemMap::mapRotation
double mapRotation(QgsLayoutObject::PropertyValueType valueType=QgsLayoutObject::EvaluatedValue) const
Returns the rotation used for drawing the map within the layout item, in degrees clockwise.
Definition: qgslayoutitemmap.cpp:474
qgsapplication.h
QgsLayoutObject::MapYMin
@ MapYMin
Map extent y minimum.
Definition: qgslayoutobject.h:160
qgslayoututils.h
QgsUnitTypes::LayoutInches
@ LayoutInches
Inches.
Definition: qgsunittypes.h:185
QgsLayoutItemMap::atlasMargin
double atlasMargin(QgsLayoutObject::PropertyValueType valueType=QgsLayoutObject::EvaluatedValue)
Returns the margin size (percentage) used when the map is in atlas mode.
Definition: qgslayoutitemmap.cpp:492
QgsLayoutItem::drawBackground
virtual void drawBackground(QgsRenderContext &context)
Draws the background for the item.
Definition: qgslayoutitem.cpp:1227
QgsLayoutItemMap::exportLayerDetails
QgsLayoutItem::ExportLayerDetail exportLayerDetails() const override
Returns the details for the specified current export layer.
Definition: qgslayoutitemmap.cpp:1145
QgsMapSettings::ForceVectorOutput
@ ForceVectorOutput
Vector graphics should not be cached and drawn as raster images.
Definition: qgsmapsettings.h:304
QgsLayoutItem::containsAdvancedEffects
virtual bool containsAdvancedEffects() const
Returns true if the item contains contents with blend modes or transparency effects which can only be...
Definition: qgslayoutitem.cpp:926
_LayerRef::layerId
QString layerId
Original layer ID.
Definition: qgsmaplayerref.h:116
Q_NOWARN_DEPRECATED_POP
#define Q_NOWARN_DEPRECATED_POP
Definition: qgis.h:752
QgsProject::crsChanged
void crsChanged()
Emitted when the CRS of the project has changed.
QgsMapSettings::addRenderedFeatureHandler
void addRenderedFeatureHandler(QgsRenderedFeatureHandlerInterface *handler)
Adds a rendered feature handler to use while rendering the map settings.
Definition: qgsmapsettings.cpp:685
QgsLayoutItem::hasBackground
bool hasBackground() const
Returns true if the item has a background.
Definition: qgslayoutitem.h:797
QgsRectangle::scale
void scale(double scaleFactor, const QgsPointXY *c=nullptr)
Scale the rectangle around its center point.
Definition: qgsrectangle.h:235
QgsLayoutItemMap::requiresRasterization
bool requiresRasterization() const override
Returns true if the item is drawn in such a way that forces the whole layout to be rasterized when ex...
Definition: qgslayoutitemmap.cpp:421
QgsMapSettings::DrawSelection
@ DrawSelection
Whether vector selections should be shown in the rendered map.
Definition: qgsmapsettings.h:308
QgsLayoutObject::AllProperties
@ AllProperties
All properties for item.
Definition: qgslayoutobject.h:135
QgsLayoutItemMap::type
int type() const override
Definition: qgslayoutitemmap.cpp:74
QgsProject::layerTreeRoot
QgsLayerTree * layerTreeRoot() const
Returns pointer to the root (invisible) node of the project's layer tree.
Definition: qgsproject.cpp:3016
qgsexpressioncontext.h
QgsCsException
Definition: qgsexception.h:65
QgsMapRendererCustomPainterJob::cancelWithoutBlocking
void cancelWithoutBlocking() override
Triggers cancellation of the rendering job without blocking.
Definition: qgsmaprenderercustompainterjob.cpp:152
QgsLayoutItemMap::layoutToMapCoordsTransform
QTransform layoutToMapCoordsTransform() const
Creates a transform from layout coordinates to map coordinates.
Definition: qgslayoutitemmap.cpp:1895
QgsAnnotation
Abstract base class for annotation items which are drawn over a map.
Definition: qgsannotation.h:49
QgsMapSettings::setBackgroundColor
void setBackgroundColor(const QColor &color)
Sets the background color of the map.
Definition: qgsmapsettings.h:290
QgsLayoutItem::backgroundColor
QColor backgroundColor() const
Returns the background color for this item.
Definition: qgslayoutitem.h:812
QgsLayoutItem::ExportLayerDetail
Contains details of a particular export layer relating to a layout item.
Definition: qgslayoutitem.h:487
QgsScaleCalculator
Definition: qgsscalecalculator.h:34
QgsLayoutItemMap::layers
QList< QgsMapLayer * > layers() const
Returns the stored layer set.
Definition: qgslayoutitemmap.cpp:278
QgsLayoutItem::ExportLayerDetail::name
QString name
User-friendly name for the export layer.
Definition: qgslayoutitem.h:490
qgsmapsettingsutils.h
QgsLayoutItem::ExportLayerBehavior
ExportLayerBehavior
Behavior of item when exporting to layered outputs.
Definition: qgslayoutitem.h:424
QgsCoordinateReferenceSystem::writeXml
bool writeXml(QDomNode &node, QDomDocument &doc) const
Stores state to the given Dom node in the given document.
Definition: qgscoordinatereferencesystem.cpp:2094
_LayerRef::provider
QString provider
Weak reference to layer provider.
Definition: qgsmaplayerref.h:123
QgsLayoutItemMap::QgsLayoutItemMap
QgsLayoutItemMap(QgsLayout *layout)
Constructor for QgsLayoutItemMap, with the specified parent layout.
Definition: qgslayoutitemmap.cpp:40
QgsLabelingEngineSettings
Definition: qgslabelingenginesettings.h:30
QgsLayoutObject::MapRotation
@ MapRotation
Map rotation.
Definition: qgslayoutobject.h:157
QgsUnitTypes::toString
static Q_INVOKABLE QString toString(QgsUnitTypes::DistanceUnit unit)
Returns a translated string representing a distance unit.
Definition: qgsunittypes.cpp:199
QgsLayoutItem::requiresRasterization
virtual bool requiresRasterization() const
Returns true if the item is drawn in such a way that forces the whole layout to be rasterized when ex...
Definition: qgslayoutitem.cpp:931
qgsDoubleNear
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:315
QgsLayoutObject::MapXMax
@ MapXMax
Map extent x maximum.
Definition: qgslayoutobject.h:161
QgsMapRendererStagedRenderJob::Labels
@ Labels
Rendering labels.
Definition: qgsmaprendererstagedrenderjob.h:52
QgsLayoutObject::MapYMax
@ MapYMax
Map extent y maximum.
Definition: qgslayoutobject.h:162
QgsLayoutItemMap::overview
QgsLayoutItemMapOverview * overview()
Returns the map item's first overview.
Definition: qgslayoutitemmap.cpp:527
QgsLayoutMeasurement::units
QgsUnitTypes::LayoutUnit units() const
Returns the units for the measurement.
Definition: qgslayoutmeasurement.h:60
QgsCoordinateReferenceSystem::authid
QString authid() const
Returns the authority identifier for the CRS.
Definition: qgscoordinatereferencesystem.cpp:1299
QgsLayoutItem::FlagOverridesPaint
@ FlagOverridesPaint
Item overrides the default layout item painting method.
Definition: qgslayoutitem.h:301
QgsProject::projectColorsChanged
void projectColorsChanged()
Emitted whenever the project's color scheme has been changed.
QgsLayoutItemMap::setMoveContentPreviewOffset
void setMoveContentPreviewOffset(double dx, double dy) override
Sets temporary offset for the item, by a specified dx and dy in layout units.
Definition: qgslayoutitemmap.cpp:1501
QgsMapSettings::visiblePolygon
QPolygonF visiblePolygon() const
Returns the visible area as a polygon (may be rotated)
Definition: qgsmapsettings.cpp:375
QgsMapSettings::Antialiasing
@ Antialiasing
Enable anti-aliasing for map rendering.
Definition: qgsmapsettings.h:302
QgsLayoutItemMap::zoomToExtent
void zoomToExtent(const QgsRectangle &extent)
Zooms the map so that the specified extent is fully visible within the map item.
Definition: qgslayoutitemmap.cpp:208
_LayerRef::name
QString name
Weak reference to layer name.
Definition: qgsmaplayerref.h:121
QgsCoordinateReferenceSystem::toWkt
QString toWkt(WktVariant variant=WKT1_GDAL, bool multiline=false, int indentationWidth=4) const
Returns a WKT representation of this CRS.
Definition: qgscoordinatereferencesystem.cpp:1931
QgsLayoutItemMap::extent
QgsRectangle extent() const
Returns the current map extent.
Definition: qgslayoutitemmap.cpp:252
QgsMapSettings::setSelectionColor
void setSelectionColor(const QColor &color)
Sets color that is used for drawing of selected vector features.
Definition: qgsmapsettings.h:295
QgsMapSettings::setSimplifyMethod
void setSimplifyMethod(const QgsVectorSimplifyMethod &method)
Sets the simplification setting to use when rendering vector layers.
Definition: qgsmapsettings.h:597
QgsWkbTypes::geometryType
static GeometryType geometryType(Type type)
Returns the geometry type for a WKB type, e.g., both MultiPolygon and CurvePolygon would have a Polyg...
Definition: qgswkbtypes.h:937
QgsLayoutItemMap::invalidateCache
void invalidateCache() override
Definition: qgslayoutitemmap.cpp:1695
QgsLayoutItemMap::Fixed
@ Fixed
The current scale of the map is used for each feature of the atlas.
Definition: qgslayoutitemmap.h:51
QgsCoordinateReferenceSystem::isValid
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
Definition: qgscoordinatereferencesystem.cpp:902
QgsRectangle::setXMaximum
void setXMaximum(double x)
Set the maximum x value.
Definition: qgsrectangle.h:135
QgsLayoutItemMap::create
static QgsLayoutItemMap * create(QgsLayout *layout)
Returns a new map item for the specified layout.
Definition: qgslayoutitemmap.cpp:127
QgsMapLayer::id
QString id() const
Returns the layer's unique ID, which is used to access this layer from QgsProject.
Definition: qgsmaplayer.cpp:148
QgsLayoutItemMap::layersToRender
QList< QgsMapLayer * > layersToRender(const QgsExpressionContext *context=nullptr) const
Returns a list of the layers which will be rendered within this map item, considering any locked laye...
Definition: qgslayoutitemmap.cpp:1970
QgsAnnotation::isVisible
bool isVisible() const
Returns true if the annotation is visible and should be rendered.
Definition: qgsannotation.h:89
QgsLayoutItem::ItemContainsSubLayers
@ ItemContainsSubLayers
Item contains multiple sublayers which must be individually exported.
Definition: qgslayoutitem.h:429
QgsMapSettingsUtils::containsAdvancedEffects
static QStringList containsAdvancedEffects(const QgsMapSettings &mapSettings, EffectsCheckFlags flags=QgsMapSettingsUtils::EffectsCheckFlags())
Checks whether any of the layers attached to a map settings object contain advanced effects.
Definition: qgsmapsettingsutils.cpp:27
QgsWeakMapLayerPointer
QPointer< QgsMapLayer > QgsWeakMapLayerPointer
Weak pointer for QgsMapLayer.
Definition: qgsmaplayer.h:1670
qgsannotationmanager.h
QgsProject::mapThemeCollection
QgsMapThemeCollection mapThemeCollection
Definition: qgsproject.h:101
QgsLayoutItemMap::boundingRect
QRectF boundingRect() const override
Definition: qgslayoutitemmap.cpp:1507
QgsStyleEntityVisitorInterface::Node
Contains information relating to a node (i.e.
Definition: qgsstyleentityvisitor.h:110
QgsLayoutItem
Base class for graphical items within a QgsLayout.
Definition: qgslayoutitem.h:112
QgsMapSettings::setTransformContext
void setTransformContext(const QgsCoordinateTransformContext &context)
Sets the coordinate transform context, which stores various information regarding which datum transfo...
Definition: qgsmapsettings.cpp:410
QgsAnnotation::hasFixedMapPosition
bool hasFixedMapPosition
Definition: qgsannotation.h:68
QgsLayoutUtils::createRenderContextForMap
static QgsRenderContext createRenderContextForMap(QgsLayoutItemMap *map, QPainter *painter, double dpi=-1)
Creates a render context suitable for the specified layout map and painter destination.
Definition: qgslayoututils.cpp:94
QgsCoordinateReferenceSystem::toProj
QString toProj() const
Returns a Proj string representation of this CRS.
Definition: qgscoordinatereferencesystem.cpp:1398
QgsLayoutItem::ExportLayerDetail::opacity
double opacity
Associated opacity, if this layer is associated with a map layer.
Definition: qgslayoutitem.h:505
qgslayertree.h
QgsLayoutItemMap::requestedExtent
QgsRectangle requestedExtent() const
Calculates the extent to request and the yShift of the top-left point in case of rotation.
Definition: qgslayoutitemmap.cpp:1674
QgsLayoutItemMap::setMapFlags
void setMapFlags(QgsLayoutItemMap::MapItemFlags flags)
Sets the map item's flags, which control how the map content is drawn.
Definition: qgslayoutitemmap.cpp:1393
qgslayout.h
QgsLayoutObject::MapScale
@ MapScale
Map scale.
Definition: qgslayoutobject.h:158
QgsLayoutItemMap::crs
QgsCoordinateReferenceSystem crs() const
Returns coordinate reference system used for rendering the map.
Definition: qgslayoutitemmap.cpp:264
QgsCoordinateReferenceSystem
Definition: qgscoordinatereferencesystem.h:206
QgsLayoutItemMap::mapUnitsToLayoutUnits
double mapUnitsToLayoutUnits() const
Returns the conversion factor from map units to layout units.
Definition: qgslayoutitemmap.cpp:1573
QgsLayoutObject::MapLabelMargin
@ MapLabelMargin
Map label margin.
Definition: qgslayoutobject.h:166
QgsRectangle::yMaximum
double yMaximum() const
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:172
QgsExpressionContextScope
Single scope for storing variables and functions for use within a QgsExpressionContext....
Definition: qgsexpressioncontext.h:111
QgsMapRendererStagedRenderJob::RenderLabelsByMapLayer
@ RenderLabelsByMapLayer
Labels should be rendered in individual stages by map layer. This allows separation of labels belongi...
Definition: qgsmaprendererstagedrenderjob.h:42
QgsMapSettings::setLabelingEngineSettings
void setLabelingEngineSettings(const QgsLabelingEngineSettings &settings)
Sets the global configuration of the labeling engine.
Definition: qgsmapsettings.h:522
QgsAbstractPropertyCollection::valueAsString
QString valueAsString(int key, const QgsExpressionContext &context, const QString &defaultString=QString(), bool *ok=nullptr) const
Calculates the current value of the property with the specified key and interprets it as a string.
Definition: qgspropertycollection.cpp:42
QgsMapSettings::setLayers
void setLayers(const QList< QgsMapLayer * > &layers)
Set list of layers for map rendering.
Definition: qgsmapsettings.cpp:286
QgsAbstractPropertyCollection::valueAsDateTime
QDateTime valueAsDateTime(int key, const QgsExpressionContext &context, const QDateTime &defaultDateTime=QDateTime(), bool *ok=nullptr) const
Calculates the current value of the property with the specified key and interprets it as a datetime.
Definition: qgspropertycollection.cpp:30
QgsExpressionContext::appendScope
void appendScope(QgsExpressionContextScope *scope)
Appends a scope to the end of the context.
Definition: qgsexpressioncontext.cpp:490
QgsLayoutItem::refresh
void refresh() override
Refreshes the item, causing a recalculation of any property overrides and recalculation of its positi...
Definition: qgslayoutitem.cpp:1172
qgsvectorlayer.h
QgsPointXY
Definition: qgspointxy.h:43
QgsLayoutItemMap::transformedMapPolygon
QPolygonF transformedMapPolygon() const
Returns extent that considers rotation and shift with mOffsetX / mOffsetY.
Definition: qgslayoutitemmap.cpp:1583
QgsLayoutItemMapOverview
An individual overview which is drawn above the map content in a QgsLayoutItemMap,...
Definition: qgslayoutitemmapoverview.h:126
QgsStyleEntityVisitorInterface::visitEnter
virtual bool visitEnter(const QgsStyleEntityVisitorInterface::Node &node)
Called when the visitor starts visiting a node.
Definition: qgsstyleentityvisitor.h:169
QgsLayoutItemMap::setLayerStyleOverrides
void setLayerStyleOverrides(const QMap< QString, QString > &overrides)
Sets the stored overrides of styles for layers.
Definition: qgslayoutitemmap.cpp:288
QgsLayoutObject::MapAtlasMargin
@ MapAtlasMargin
Map atlas margin.
Definition: qgslayoutobject.h:163
QgsRenderContext::setForceVectorOutput
void setForceVectorOutput(bool force)
Sets whether rendering operations should use vector operations instead of any faster raster shortcuts...
Definition: qgsrendercontext.cpp:250
QgsMapRendererCustomPainterJob
Definition: qgsmaprenderercustompainterjob.h:63
QgsLayoutItemMap
Layout graphical items for displaying a map.
Definition: qgslayoutitemmap.h:39
QgsLayoutItemMap::mapFlags
QgsLayoutItemMap::MapItemFlags mapFlags() const
Returns the map item's flags, which control how the map content is drawn.
Definition: qgslayoutitemmap.cpp:1388
QgsLayoutItemMap::stopLayeredExport
void stopLayeredExport() override
Stops a multi-layer export operation.
Definition: qgslayoutitemmap.cpp:1053
QgsLabelingEngineSettings::setFlag
void setFlag(Flag f, bool enabled=true)
Sets whether a particual flag is enabled.
Definition: qgslabelingenginesettings.h:84
QgsLayoutItemMap::displayName
QString displayName() const override
Gets item display name.
Definition: qgslayoutitemmap.cpp:117
QgsMapSettings::setExpressionContext
void setExpressionContext(const QgsExpressionContext &context)
Sets the expression context.
Definition: qgsmapsettings.h:385
QgsLayoutItemMap::QgsLayoutItemMapOverview
friend class QgsLayoutItemMapOverview
Definition: qgslayoutitemmap.h:859
QgsLayoutItemMap::labelMargin
QgsLayoutMeasurement labelMargin() const
Returns the margin from the map edges in which no labels may be placed.
Definition: qgslayoutitemmap.cpp:1939
QgsLayoutItemMap::setLabelMargin
void setLabelMargin(const QgsLayoutMeasurement &margin)
Sets the margin from the map edges in which no labels may be placed.
Definition: qgslayoutitemmap.cpp:1944
QgsLayoutItem::uuid
virtual QString uuid() const
Returns the item identification string.
Definition: qgslayoutitem.h:340
QgsMapSettings::UseRenderingOptimization
@ UseRenderingOptimization
Enable vector simplification and other rendering optimizations.
Definition: qgsmapsettings.h:307
QgsWkbTypes::PointGeometry
@ PointGeometry
Definition: qgswkbtypes.h:141
qgslayoutrendercontext.h
QgsLayoutItemMap::Predefined
@ Predefined
A scale is chosen from the predefined scales.
Definition: qgslayoutitemmap.h:59
QgsLayoutItemMapItem::stackingPosition
StackingPosition stackingPosition() const
Returns the item's stacking position, which specifies where the in the map's stack the item should be...
Definition: qgslayoutitemmapitem.h:140
QgsLayoutItemMap::themeChanged
void themeChanged(const QString &theme)
Emitted when the map's associated theme is changed.
QgsCoordinateReferenceSystem::mapUnits
QgsUnitTypes::DistanceUnit mapUnits
Definition: qgscoordinatereferencesystem.h:210
QgsLayoutUtils::rotate
static void rotate(double angle, double &x, double &y)
Rotates a point / vector around the origin.
Definition: qgslayoututils.cpp:30
QgsRectangle::center
QgsPointXY center() const
Returns the center point of the rectangle.
Definition: qgsrectangle.h:230
QgsLayoutObject::mLayout
QPointer< QgsLayout > mLayout
Definition: qgslayoutobject.h:335
qgslayoutreportcontext.h
QgsGeometry
Definition: qgsgeometry.h:122
QgsLayoutItemMapItem::StackAboveMapLabels
@ StackAboveMapLabels
Render above all map layers and labels.
Definition: qgslayoutitemmapitem.h:46
QgsLabelingEngineSettings::UsePartialCandidates
@ UsePartialCandidates
Whether to use also label candidates that are partially outside of the map view.
Definition: qgslabelingenginesettings.h:37
QgsLayout
Base class for layouts, which can contain items such as maps, labels, scalebars, etc.
Definition: qgslayout.h:49
QgsMapSettings::setLayerStyleOverrides
void setLayerStyleOverrides(const QMap< QString, QString > &overrides)
Set map of map layer style overrides (key: layer ID, value: style name) where a different style shoul...
Definition: qgsmapsettings.cpp:304
_LayerRef::source
QString source
Weak reference to layer public source.
Definition: qgsmaplayerref.h:119
QgsLayoutItemMap::mapRotationChanged
void mapRotationChanged(double newRotation)
Emitted when the map's rotation changes.
QgsMapSettings::DrawEditingInfo
@ DrawEditingInfo
Enable drawing of vertex markers for layers in editing mode.
Definition: qgsmapsettings.h:303
QgsMapLayer
Definition: qgsmaplayer.h:81
QgsLayoutItemMap::setMapRotation
void setMapRotation(double rotation)
Sets the rotation for the map - this does not affect the layout item shape, only the way the map is d...
Definition: qgslayoutitemmap.cpp:465
QgsLayoutItemMap::containsWmsLayer
bool containsWmsLayer() const
Returns true if the map contains a WMS layer.
Definition: qgslayoutitemmap.cpp:408
QgsPointXY::x
double x
Definition: qgspointxy.h:47
QgsLayoutItemMap::removeRenderedFeatureHandler
void removeRenderedFeatureHandler(QgsRenderedFeatureHandlerInterface *handler)
Removes a previously added rendered feature handler.
Definition: qgslayoutitemmap.cpp:1648
QgsLayoutItemMap::icon
QIcon icon() const override
Returns the item's icon.
Definition: qgslayoutitemmap.cpp:79
QgsRectangle::height
double height() const
Returns the height of the rectangle.
Definition: qgsrectangle.h:209
QgsLayoutItemRegistry::LayoutMap
@ LayoutMap
Map item.
Definition: qgslayoutitemregistry.h:317
QgsLayoutItemMap::scale
double scale() const
Returns the map scale.
Definition: qgslayoutitemmap.cpp:143
QgsLayoutItemMap::setScale
void setScale(double scale, bool forceUpdate=true)
Sets new map scale and changes only the map extent.
Definition: qgslayoutitemmap.cpp:155
QgsLayoutItemMap::setFollowVisibilityPreset
void setFollowVisibilityPreset(bool follow)
Sets whether the map should follow a map theme.
Definition: qgslayoutitemmap.cpp:312
QgsMapLayerStyle::xmlData
QString xmlData() const
Returns XML content of the style.
Definition: qgsmaplayerstyle.cpp:43
QgsMapLayer::name
QString name
Definition: qgsmaplayer.h:85
QgsLayoutRenderContext::FlagDrawSelection
@ FlagDrawSelection
Draw selection.
Definition: qgslayoutrendercontext.h:48
QgsRectangle::yMinimum
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:177
QgsAnnotation::relativePosition
QPointF relativePosition() const
Returns the relative position of the annotation, if it is not attached to a fixed map position.
Definition: qgsannotation.h:149
QgsLayoutObject::PropertyValueType
PropertyValueType
Specifies whether the value returned by a function should be the original, user set value,...
Definition: qgslayoutobject.h:204
QgsLayoutItemMap::refreshDataDefinedProperty
void refreshDataDefinedProperty(QgsLayoutObject::DataDefinedProperty property=QgsLayoutObject::AllProperties) override
Definition: qgslayoutitemmap.cpp:1733
QgsRenderContext::Antialiasing
@ Antialiasing
Use antialiasing while drawing.
Definition: qgsrendercontext.h:78
QgsLayoutRenderContext::FlagForceVectorOutput
@ FlagForceVectorOutput
Force output in vector format where possible, even if items require rasterization to keep their corre...
Definition: qgslayoutrendercontext.h:46
QgsMapSettings::layers
QList< QgsMapLayer * > layers() const
Gets list of layers for map rendering The layers are stored in the reverse order of how they are rend...
Definition: qgsmapsettings.cpp:281
QgsTemporalRangeObject::setTemporalRange
void setTemporalRange(const QgsDateTimeRange &range)
Sets the temporal range for the object.
Definition: qgstemporalrangeobject.cpp:35
QgsRenderContext::setExpressionContext
void setExpressionContext(const QgsExpressionContext &context)
Sets the expression context.
Definition: qgsrendercontext.h:572
qgsmaplayerref.h
QgsGeometry::boundingBox
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
Definition: qgsgeometry.cpp:962
QgsAnnotation::mapPositionCrs
QgsCoordinateReferenceSystem mapPositionCrs() const
Returns the CRS of the map position, or an invalid CRS if the annotation does not have a fixed map po...
Definition: qgsannotation.h:135
QgsLayoutItemMap::moveContent
void moveContent(double dx, double dy) override
Moves the content of the item, by a specified dx and dy in layout units.
Definition: qgslayoutitemmap.cpp:332
QgsLayoutItemMap::containsAdvancedEffects
bool containsAdvancedEffects() const override
Returns true if the item contains contents with blend modes or transparency effects which can only be...
Definition: qgslayoutitemmap.cpp:441
QgsMapSettings::setLabelBlockingRegions
void setLabelBlockingRegions(const QList< QgsLabelBlockingRegion > &regions)
Sets a list of regions to avoid placing labels within.
Definition: qgsmapsettings.h:571
QgsCoordinateReferenceSystem::ellipsoidAcronym
QString ellipsoidAcronym() const
Returns the ellipsoid acronym for the ellipsoid used by the CRS.
Definition: qgscoordinatereferencesystem.cpp:1351
QgsLabelBlockingRegion
Definition: qgsmapsettings.h:52
QgsGeometry::fromQPolygonF
static QgsGeometry fromQPolygonF(const QPolygonF &polygon)
Construct geometry from a QPolygonF.
Definition: qgsgeometry.cpp:3095
_LayerRef< QgsMapLayer >
QgsUnitTypes::LayoutMillimeters
@ LayoutMillimeters
Millimeters.
Definition: qgsunittypes.h:182
QgsMapLayerStyle
Definition: qgsmaplayerstyle.h:42
QgsLayoutItemMap::accept
bool accept(QgsStyleEntityVisitorInterface *visitor) const override
Accepts the specified style entity visitor, causing it to visit all style entities associated with th...
Definition: qgslayoutitemmap.cpp:1613
QgsMapSettings::setOutputSize
void setOutputSize(QSize size)
Sets the size of the resulting map image.
Definition: qgsmapsettings.cpp:239
qgsmaplayerlistutils.h
QgsRectangle::fromCenterAndSize
static QgsRectangle fromCenterAndSize(QgsPointXY center, double width, double height)
Creates a new rectangle, given the specified center point and width and height.
Definition: qgsrectangle.cpp:52
QgsRenderContext::painter
QPainter * painter()
Returns the destination QPainter for the render operation.
Definition: qgsrendercontext.h:174
QgsLayoutItemMap::finalizeRestoreFromXml
void finalizeRestoreFromXml() override
Called after all pending items have been restored from XML.
Definition: qgslayoutitemmap.cpp:1483
QgsExpressionContextScope::StaticVariable
Single variable definition for use within a QgsExpressionContextScope.
Definition: qgsexpressioncontext.h:118
QgsLayoutObject::EndDateTime
@ EndDateTime
Temporal range's end DateTime.
Definition: qgslayoutobject.h:196
QgsMapSettings::setPathResolver
void setPathResolver(const QgsPathResolver &resolver)
Sets the path resolver for conversion between relative and absolute paths during rendering operations...
Definition: qgsmapsettings.h:431
QgsMapSettings
Definition: qgsmapsettings.h:86
QgsLayoutRenderContext::FlagAntialiasing
@ FlagAntialiasing
Use antialiasing when drawing items.
Definition: qgslayoutrendercontext.h:44
QgsLayoutItem::ExportLayerDetail::mapLayerId
QString mapLayerId
Associated map layer ID, or an empty string if this export layer is not associated with a map layer.
Definition: qgslayoutitem.h:493
QgsLayoutObject::MapStylePreset
@ MapStylePreset
Layer and style map theme.
Definition: qgslayoutobject.h:165
QgsCoordinateTransform
Definition: qgscoordinatetransform.h:52
QgsLayoutItemMap::setAtlasDriven
void setAtlasDriven(bool enabled)
Sets whether the map extent will follow the current atlas feature.
Definition: qgslayoutitemmap.cpp:480
Q_NOWARN_DEPRECATED_PUSH
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:751
QgsMapSettings::setExtent
void setExtent(const QgsRectangle &rect, bool magnified=true)
Set coordinates of the rectangle which should be rendered.
Definition: qgsmapsettings.cpp:79
QgsLayoutUtils::scaleFactorFromItemStyle
static double scaleFactorFromItemStyle(const QStyleOptionGraphicsItem *style)
Extracts the scale factor from an item style.
Definition: qgslayoututils.cpp:390
QgsMapLayerStyle::writeXml
void writeXml(QDomElement &styleElement) const
Write style configuration (for project file writing)
Definition: qgsmaplayerstyle.cpp:93
QgsLayoutItemMap::setExtent
void setExtent(const QgsRectangle &extent)
Sets a new extent for the map.
Definition: qgslayoutitemmap.cpp:188
QgsLayoutObject::EvaluatedValue
@ EvaluatedValue
Return the current evaluated value for the property.
Definition: qgslayoutobject.h:206
QgsLayoutItem::createExpressionContext
QgsExpressionContext createExpressionContext() const override
This method needs to be reimplemented in all classes which implement this interface and return an exp...
Definition: qgslayoutitem.cpp:1159
qgslayoutmodel.h
QgsRectangle::isNull
bool isNull() const
Test if the rectangle is null (all coordinates zero or after call to setMinimal()).
Definition: qgsrectangle.h:447
QgsRectangle::width
double width() const
Returns the width of the rectangle.
Definition: qgsrectangle.h:202
QgsLayoutItemMapItem::enabled
bool enabled() const
Returns whether the item will be drawn.
Definition: qgslayoutitemmapitem.cpp:104
QgsLayoutItemMap::ShowUnplacedLabels
@ ShowUnplacedLabels
Whether to render unplaced labels in the map view.
Definition: qgslayoutitemmap.h:76
QgsRectangle::setYMinimum
void setYMinimum(double y)
Set the minimum y value.
Definition: qgsrectangle.h:140
QgsMapSettings::setEllipsoid
bool setEllipsoid(const QString &ellipsoid)
Sets the ellipsoid by its acronym.
Definition: qgsmapsettings.cpp:322
QgsLayoutMeasurement
This class provides a method of storing measurements for use in QGIS layouts using a variety of diffe...
Definition: qgslayoutmeasurement.h:33
QgsLabelingEngineSettings::DrawUnplacedLabels
@ DrawUnplacedLabels
Whether to render unplaced labels as an indicator/warning for users.
Definition: qgslabelingenginesettings.h:42
QgsRectangle::setYMaximum
void setYMaximum(double y)
Set the maximum y value.
Definition: qgsrectangle.h:145
QgsLayoutItemMap::zoomContent
void zoomContent(double factor, QPointF point) override
Zooms content of item.
Definition: qgslayoutitemmap.cpp:353
_LayerRef::resolve
TYPE * resolve(const QgsProject *project)
Resolves the map layer by attempting to find a layer with matching ID within a project.
Definition: qgsmaplayerref.h:149
QgsLayoutItemMap::readPropertiesFromElement
bool readPropertiesFromElement(const QDomElement &element, const QDomDocument &document, const QgsReadWriteContext &context) override
Sets item state from a DOM element.
Definition: qgslayoutitemmap.cpp:663
QgsRectangle::xMinimum
double xMinimum() const
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:167
QgsLayoutObject::DataDefinedProperty
DataDefinedProperty
Data defined properties for different item types.
Definition: qgslayoutobject.h:132
qgsstyleentityvisitor.h
QgsLayoutItemMap::visibleExtentPolygon
QPolygonF visibleExtentPolygon() const
Returns a polygon representing the current visible map extent, considering map extents and rotation.
Definition: qgslayoutitemmap.cpp:257
QgsLayoutItemMap::removeLabelBlockingItem
void removeLabelBlockingItem(QgsLayoutItem *item)
Removes the specified layout item from the map's "label blocking items".
Definition: qgslayoutitemmap.cpp:1601
QgsMapLayerStyle::readXml
void readXml(const QDomElement &styleElement)
Read style configuration (for project file reading)
Definition: qgsmaplayerstyle.cpp:86
QgsLayoutItemMap::setLayers
void setLayers(const QList< QgsMapLayer * > &layers)
Sets the stored layers set.
Definition: qgslayoutitemmap.cpp:283
QgsRenderContext::flags
Flags flags() const
Returns combination of flags used for rendering.
Definition: qgsrendercontext.cpp:160
qgslayoutitemmap.h
QgsLayoutObject::MapLayers
@ MapLayers
Map layer set.
Definition: qgslayoutobject.h:164
QgsMapRendererJob::finished
void finished()
emitted when asynchronous rendering is finished (or canceled).
QgsLayoutRenderContext::FlagHideCoverageLayer
@ FlagHideCoverageLayer
Hide coverage layer in outputs.
Definition: qgslayoutrendercontext.h:47
QgsLayoutMeasurement::decodeMeasurement
static QgsLayoutMeasurement decodeMeasurement(const QString &string)
Decodes a measurement from a string.
Definition: qgslayoutmeasurement.cpp:33