QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
qgslayoutitemmapgrid.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgslayoutitemmapgrid.cpp
3  ----------------------
4  begin : October 2017
5  copyright : (C) 2017 by Marco Hugentobler, Nyall Dawson
6  email : marco dot hugentobler at sourcepole dot ch
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 
18 #include "qgsmessagelog.h"
19 #include "qgslayoutitemmapgrid.h"
20 #include "qgslayoututils.h"
21 #include "qgsclipper.h"
22 #include "qgsgeometry.h"
23 #include "qgslayoutitemmap.h"
24 #include "qgslayout.h"
25 #include "qgsmapsettings.h"
26 #include "qgspathresolver.h"
27 #include "qgsreadwritecontext.h"
28 #include "qgsrendercontext.h"
29 #include "qgssymbollayerutils.h"
30 #include "qgssymbol.h"
32 #include "qgslogger.h"
33 #include "qgsfontutils.h"
34 #include "qgsexpressioncontext.h"
35 #include "qgsexception.h"
36 #include "qgssettings.h"
37 #include "qgscoordinateformatter.h"
38 #include "qgsstyleentityvisitor.h"
39 #include "qgstextrenderer.h"
40 #include "qgslinesymbol.h"
41 #include "qgsmarkersymbol.h"
42 
43 #include <QVector2D>
44 #include <math.h>
45 
46 #include <QPainter>
47 #include <QPen>
48 
49 #define MAX_GRID_LINES 1000 //maximum number of horizontal or vertical grid lines to draw
50 
53 {
54 
55 }
56 
58 {
60 }
61 
62 void QgsLayoutItemMapGridStack::removeGrid( const QString &gridId )
63 {
65 }
66 
67 void QgsLayoutItemMapGridStack::moveGridUp( const QString &gridId )
68 {
70 }
71 
72 void QgsLayoutItemMapGridStack::moveGridDown( const QString &gridId )
73 {
75 }
76 
78 {
80  return qobject_cast<QgsLayoutItemMapGrid *>( item );
81 }
82 
84 {
86  return qobject_cast<QgsLayoutItemMapGrid *>( item );
87 }
88 
89 QList<QgsLayoutItemMapGrid *> QgsLayoutItemMapGridStack::asList() const
90 {
91  QList< QgsLayoutItemMapGrid * > list;
93  {
94  if ( QgsLayoutItemMapGrid *grid = qobject_cast<QgsLayoutItemMapGrid *>( item ) )
95  {
96  list.append( grid );
97  }
98  }
99  return list;
100 }
101 
103 {
104  QgsLayoutItemMapItem *item = mItems.at( idx );
105  QgsLayoutItemMapGrid *grid = qobject_cast<QgsLayoutItemMapGrid *>( item );
106  return *grid;
107 }
108 
109 bool QgsLayoutItemMapGridStack::readXml( const QDomElement &elem, const QDomDocument &doc, const QgsReadWriteContext &context )
110 {
111  removeItems();
112 
113  //read grid stack
114  const QDomNodeList mapGridNodeList = elem.elementsByTagName( QStringLiteral( "ComposerMapGrid" ) );
115  for ( int i = 0; i < mapGridNodeList.size(); ++i )
116  {
117  const QDomElement mapGridElem = mapGridNodeList.at( i ).toElement();
118  QgsLayoutItemMapGrid *mapGrid = new QgsLayoutItemMapGrid( mapGridElem.attribute( QStringLiteral( "name" ) ), mMap );
119  mapGrid->readXml( mapGridElem, doc, context );
120  mItems.append( mapGrid );
121  }
122 
123  return true;
124 }
125 
127 {
128  double top = 0.0;
129  double right = 0.0;
130  double bottom = 0.0;
131  double left = 0.0;
132  calculateMaxGridExtension( top, right, bottom, left );
133  return std::max( std::max( std::max( top, right ), bottom ), left );
134 }
135 
136 void QgsLayoutItemMapGridStack::calculateMaxGridExtension( double &top, double &right, double &bottom, double &left ) const
137 {
138  top = 0.0;
139  right = 0.0;
140  bottom = 0.0;
141  left = 0.0;
142 
143  for ( QgsLayoutItemMapItem *item : mItems )
144  {
145  if ( QgsLayoutItemMapGrid *grid = qobject_cast<QgsLayoutItemMapGrid *>( item ) )
146  {
147  double gridTop = 0.0;
148  double gridRight = 0.0;
149  double gridBottom = 0.0;
150  double gridLeft = 0.0;
151  grid->calculateMaxExtension( gridTop, gridRight, gridBottom, gridLeft );
152  top = std::max( top, gridTop );
153  right = std::max( right, gridRight );
154  bottom = std::max( bottom, gridBottom );
155  left = std::max( left, gridLeft );
156  }
157  }
158 }
159 
160 
161 //
162 // QgsLayoutItemMapGrid
163 //
164 
166 {
167  // returns a border as a vector2D for vector arithmetic
168  switch ( border )
169  {
171  return QVector2D( 0, 1 );
173  return QVector2D( -1, 0 );
175  return QVector2D( 0, -1 );
177  return QVector2D( 1, 0 );
178  }
179  return QVector2D();
180 }
182 {
183  // returns a border normal (towards center) as a vector2D for vector arithmetic
184  const QVector2D borderVector = borderToVector2D( border );
185  return QVector2D( borderVector.y(), -borderVector.x() );
186 }
187 
189  : QgsLayoutItemMapItem( name, map )
190  , mGridFrameSides( QgsLayoutItemMapGrid::FrameLeft | QgsLayoutItemMapGrid::FrameRight |
191  QgsLayoutItemMapGrid::FrameTop | QgsLayoutItemMapGrid::FrameBottom )
192 {
193  //get default layout font from settings
194  const QgsSettings settings;
195  const QString defaultFontString = settings.value( QStringLiteral( "LayoutDesigner/defaultFont" ), QVariant(), QgsSettings::Gui ).toString();
196  if ( !defaultFontString.isEmpty() )
197  {
198  QFont font;
199  font.setFamily( defaultFontString );
200  mAnnotationFormat.setFont( font );
201  }
202 
203  createDefaultGridLineSymbol();
204  createDefaultGridMarkerSymbol();
205 
206  connect( mMap, &QgsLayoutItemMap::extentChanged, this, &QgsLayoutItemMapGrid::refreshDataDefinedProperties );
207  connect( mMap, &QgsLayoutItemMap::mapRotationChanged, this, &QgsLayoutItemMapGrid::refreshDataDefinedProperties );
208  connect( mMap, &QgsLayoutItemMap::crsChanged, this, [ = ]
209  {
210  if ( !mCRS.isValid() )
211  emit crsChanged();
212  } );
213 }
214 
216 
217 void QgsLayoutItemMapGrid::createDefaultGridLineSymbol()
218 {
219  QVariantMap properties;
220  properties.insert( QStringLiteral( "color" ), QStringLiteral( "0,0,0,255" ) );
221  properties.insert( QStringLiteral( "width" ), QStringLiteral( "0.3" ) );
222  properties.insert( QStringLiteral( "capstyle" ), QStringLiteral( "flat" ) );
223  mGridLineSymbol.reset( QgsLineSymbol::createSimple( properties ) );
224 }
225 
226 void QgsLayoutItemMapGrid::createDefaultGridMarkerSymbol()
227 {
228  QVariantMap properties;
229  properties.insert( QStringLiteral( "name" ), QStringLiteral( "circle" ) );
230  properties.insert( QStringLiteral( "size" ), QStringLiteral( "2.0" ) );
231  properties.insert( QStringLiteral( "color" ), QStringLiteral( "0,0,0,255" ) );
232  mGridMarkerSymbol.reset( QgsMarkerSymbol::createSimple( properties ) );
233 }
234 
235 void QgsLayoutItemMapGrid::setGridLineWidth( const double width )
236 {
237  if ( mGridLineSymbol )
238  {
239  mGridLineSymbol->setWidth( width );
240  }
241 }
242 
244 {
245  if ( mGridLineSymbol )
246  {
247  mGridLineSymbol->setColor( c );
248  }
249 }
250 
251 bool QgsLayoutItemMapGrid::writeXml( QDomElement &elem, QDomDocument &doc, const QgsReadWriteContext &context ) const
252 {
253  if ( elem.isNull() )
254  {
255  return false;
256  }
257 
258  QDomElement mapGridElem = doc.createElement( QStringLiteral( "ComposerMapGrid" ) );
259  mapGridElem.setAttribute( QStringLiteral( "gridStyle" ), mGridStyle );
260  mapGridElem.setAttribute( QStringLiteral( "intervalX" ), qgsDoubleToString( mGridIntervalX ) );
261  mapGridElem.setAttribute( QStringLiteral( "intervalY" ), qgsDoubleToString( mGridIntervalY ) );
262  mapGridElem.setAttribute( QStringLiteral( "offsetX" ), qgsDoubleToString( mGridOffsetX ) );
263  mapGridElem.setAttribute( QStringLiteral( "offsetY" ), qgsDoubleToString( mGridOffsetY ) );
264  mapGridElem.setAttribute( QStringLiteral( "crossLength" ), qgsDoubleToString( mCrossLength ) );
265 
266  QDomElement lineStyleElem = doc.createElement( QStringLiteral( "lineStyle" ) );
267  const QDomElement gridLineStyleElem = QgsSymbolLayerUtils::saveSymbol( QString(), mGridLineSymbol.get(), doc, context );
268  lineStyleElem.appendChild( gridLineStyleElem );
269  mapGridElem.appendChild( lineStyleElem );
270 
271  QDomElement markerStyleElem = doc.createElement( QStringLiteral( "markerStyle" ) );
272  const QDomElement gridMarkerStyleElem = QgsSymbolLayerUtils::saveSymbol( QString(), mGridMarkerSymbol.get(), doc, context );
273  markerStyleElem.appendChild( gridMarkerStyleElem );
274  mapGridElem.appendChild( markerStyleElem );
275 
276  mapGridElem.setAttribute( QStringLiteral( "gridFrameStyle" ), mGridFrameStyle );
277  mapGridElem.setAttribute( QStringLiteral( "gridFrameSideFlags" ), mGridFrameSides );
278  mapGridElem.setAttribute( QStringLiteral( "gridFrameWidth" ), qgsDoubleToString( mGridFrameWidth ) );
279  mapGridElem.setAttribute( QStringLiteral( "gridFrameMargin" ), qgsDoubleToString( mGridFrameMargin ) );
280  mapGridElem.setAttribute( QStringLiteral( "gridFramePenThickness" ), qgsDoubleToString( mGridFramePenThickness ) );
281  mapGridElem.setAttribute( QStringLiteral( "gridFramePenColor" ), QgsSymbolLayerUtils::encodeColor( mGridFramePenColor ) );
282  mapGridElem.setAttribute( QStringLiteral( "frameFillColor1" ), QgsSymbolLayerUtils::encodeColor( mGridFrameFillColor1 ) );
283  mapGridElem.setAttribute( QStringLiteral( "frameFillColor2" ), QgsSymbolLayerUtils::encodeColor( mGridFrameFillColor2 ) );
284  mapGridElem.setAttribute( QStringLiteral( "leftFrameDivisions" ), mLeftFrameDivisions );
285  mapGridElem.setAttribute( QStringLiteral( "rightFrameDivisions" ), mRightFrameDivisions );
286  mapGridElem.setAttribute( QStringLiteral( "topFrameDivisions" ), mTopFrameDivisions );
287  mapGridElem.setAttribute( QStringLiteral( "bottomFrameDivisions" ), mBottomFrameDivisions );
288  mapGridElem.setAttribute( QStringLiteral( "rotatedTicksLengthMode" ), mRotatedTicksLengthMode );
289  mapGridElem.setAttribute( QStringLiteral( "rotatedTicksEnabled" ), mRotatedTicksEnabled );
290  mapGridElem.setAttribute( QStringLiteral( "rotatedTicksMinimumAngle" ), QString::number( mRotatedTicksMinimumAngle ) );
291  mapGridElem.setAttribute( QStringLiteral( "rotatedTicksMarginToCorner" ), QString::number( mRotatedTicksMarginToCorner ) );
292  mapGridElem.setAttribute( QStringLiteral( "rotatedAnnotationsLengthMode" ), mRotatedAnnotationsLengthMode );
293  mapGridElem.setAttribute( QStringLiteral( "rotatedAnnotationsEnabled" ), mRotatedAnnotationsEnabled );
294  mapGridElem.setAttribute( QStringLiteral( "rotatedAnnotationsMinimumAngle" ), QString::number( mRotatedAnnotationsMinimumAngle ) );
295  mapGridElem.setAttribute( QStringLiteral( "rotatedAnnotationsMarginToCorner" ), QString::number( mRotatedAnnotationsMarginToCorner ) );
296  if ( mCRS.isValid() )
297  {
298  mCRS.writeXml( mapGridElem, doc );
299  }
300 
301  mapGridElem.setAttribute( QStringLiteral( "annotationFormat" ), mGridAnnotationFormat );
302  mapGridElem.setAttribute( QStringLiteral( "showAnnotation" ), mShowGridAnnotation );
303  mapGridElem.setAttribute( QStringLiteral( "annotationExpression" ), mGridAnnotationExpressionString );
304  mapGridElem.setAttribute( QStringLiteral( "leftAnnotationDisplay" ), mLeftGridAnnotationDisplay );
305  mapGridElem.setAttribute( QStringLiteral( "rightAnnotationDisplay" ), mRightGridAnnotationDisplay );
306  mapGridElem.setAttribute( QStringLiteral( "topAnnotationDisplay" ), mTopGridAnnotationDisplay );
307  mapGridElem.setAttribute( QStringLiteral( "bottomAnnotationDisplay" ), mBottomGridAnnotationDisplay );
308  mapGridElem.setAttribute( QStringLiteral( "leftAnnotationPosition" ), mLeftGridAnnotationPosition );
309  mapGridElem.setAttribute( QStringLiteral( "rightAnnotationPosition" ), mRightGridAnnotationPosition );
310  mapGridElem.setAttribute( QStringLiteral( "topAnnotationPosition" ), mTopGridAnnotationPosition );
311  mapGridElem.setAttribute( QStringLiteral( "bottomAnnotationPosition" ), mBottomGridAnnotationPosition );
312  mapGridElem.setAttribute( QStringLiteral( "leftAnnotationDirection" ), mLeftGridAnnotationDirection );
313  mapGridElem.setAttribute( QStringLiteral( "rightAnnotationDirection" ), mRightGridAnnotationDirection );
314  mapGridElem.setAttribute( QStringLiteral( "topAnnotationDirection" ), mTopGridAnnotationDirection );
315  mapGridElem.setAttribute( QStringLiteral( "bottomAnnotationDirection" ), mBottomGridAnnotationDirection );
316  mapGridElem.setAttribute( QStringLiteral( "frameAnnotationDistance" ), QString::number( mAnnotationFrameDistance ) );
317  mapGridElem.appendChild( mAnnotationFormat.writeXml( doc, context ) );
318  mapGridElem.setAttribute( QStringLiteral( "annotationPrecision" ), mGridAnnotationPrecision );
319  mapGridElem.setAttribute( QStringLiteral( "unit" ), mGridUnit );
320  mapGridElem.setAttribute( QStringLiteral( "blendMode" ), mBlendMode );
321  mapGridElem.setAttribute( QStringLiteral( "minimumIntervalWidth" ), QString::number( mMinimumIntervalWidth ) );
322  mapGridElem.setAttribute( QStringLiteral( "maximumIntervalWidth" ), QString::number( mMaximumIntervalWidth ) );
323 
324  const bool ok = QgsLayoutItemMapItem::writeXml( mapGridElem, doc, context );
325  elem.appendChild( mapGridElem );
326  return ok;
327 }
328 
329 bool QgsLayoutItemMapGrid::readXml( const QDomElement &itemElem, const QDomDocument &doc, const QgsReadWriteContext &context )
330 {
331  Q_UNUSED( doc )
332  if ( itemElem.isNull() )
333  {
334  return false;
335  }
336 
337  const bool ok = QgsLayoutItemMapItem::readXml( itemElem, doc, context );
338 
339  //grid
340  mGridStyle = QgsLayoutItemMapGrid::GridStyle( itemElem.attribute( QStringLiteral( "gridStyle" ), QStringLiteral( "0" ) ).toInt() );
341  mGridIntervalX = itemElem.attribute( QStringLiteral( "intervalX" ), QStringLiteral( "0" ) ).toDouble();
342  mGridIntervalY = itemElem.attribute( QStringLiteral( "intervalY" ), QStringLiteral( "0" ) ).toDouble();
343  mGridOffsetX = itemElem.attribute( QStringLiteral( "offsetX" ), QStringLiteral( "0" ) ).toDouble();
344  mGridOffsetY = itemElem.attribute( QStringLiteral( "offsetY" ), QStringLiteral( "0" ) ).toDouble();
345  mCrossLength = itemElem.attribute( QStringLiteral( "crossLength" ), QStringLiteral( "3" ) ).toDouble();
346  mGridFrameStyle = static_cast< QgsLayoutItemMapGrid::FrameStyle >( itemElem.attribute( QStringLiteral( "gridFrameStyle" ), QStringLiteral( "0" ) ).toInt() );
347  mGridFrameSides = static_cast< QgsLayoutItemMapGrid::FrameSideFlags >( itemElem.attribute( QStringLiteral( "gridFrameSideFlags" ), QStringLiteral( "15" ) ).toInt() );
348  mGridFrameWidth = itemElem.attribute( QStringLiteral( "gridFrameWidth" ), QStringLiteral( "2.0" ) ).toDouble();
349  mGridFrameMargin = itemElem.attribute( QStringLiteral( "gridFrameMargin" ), QStringLiteral( "0.0" ) ).toDouble();
350  mGridFramePenThickness = itemElem.attribute( QStringLiteral( "gridFramePenThickness" ), QStringLiteral( "0.3" ) ).toDouble();
351  mGridFramePenColor = QgsSymbolLayerUtils::decodeColor( itemElem.attribute( QStringLiteral( "gridFramePenColor" ), QStringLiteral( "0,0,0" ) ) );
352  mGridFrameFillColor1 = QgsSymbolLayerUtils::decodeColor( itemElem.attribute( QStringLiteral( "frameFillColor1" ), QStringLiteral( "255,255,255,255" ) ) );
353  mGridFrameFillColor2 = QgsSymbolLayerUtils::decodeColor( itemElem.attribute( QStringLiteral( "frameFillColor2" ), QStringLiteral( "0,0,0,255" ) ) );
354  mLeftFrameDivisions = QgsLayoutItemMapGrid::DisplayMode( itemElem.attribute( QStringLiteral( "leftFrameDivisions" ), QStringLiteral( "0" ) ).toInt() );
355  mRightFrameDivisions = QgsLayoutItemMapGrid::DisplayMode( itemElem.attribute( QStringLiteral( "rightFrameDivisions" ), QStringLiteral( "0" ) ).toInt() );
356  mTopFrameDivisions = QgsLayoutItemMapGrid::DisplayMode( itemElem.attribute( QStringLiteral( "topFrameDivisions" ), QStringLiteral( "0" ) ).toInt() );
357  mBottomFrameDivisions = QgsLayoutItemMapGrid::DisplayMode( itemElem.attribute( QStringLiteral( "bottomFrameDivisions" ), QStringLiteral( "0" ) ).toInt() );
358  mRotatedTicksLengthMode = TickLengthMode( itemElem.attribute( QStringLiteral( "rotatedTicksLengthMode" ), QStringLiteral( "0" ) ).toInt() );
359  mRotatedTicksEnabled = itemElem.attribute( QStringLiteral( "rotatedTicksEnabled" ), QStringLiteral( "0" ) ) != QLatin1String( "0" );
360  mRotatedTicksMinimumAngle = itemElem.attribute( QStringLiteral( "rotatedTicksMinimumAngle" ), QStringLiteral( "0" ) ).toDouble();
361  mRotatedTicksMarginToCorner = itemElem.attribute( QStringLiteral( "rotatedTicksMarginToCorner" ), QStringLiteral( "0" ) ).toDouble();
362  mRotatedAnnotationsLengthMode = TickLengthMode( itemElem.attribute( QStringLiteral( "rotatedAnnotationsLengthMode" ), QStringLiteral( "0" ) ).toInt() );
363  mRotatedAnnotationsEnabled = itemElem.attribute( QStringLiteral( "rotatedAnnotationsEnabled" ), QStringLiteral( "0" ) ) != QLatin1String( "0" );
364  mRotatedAnnotationsMinimumAngle = itemElem.attribute( QStringLiteral( "rotatedAnnotationsMinimumAngle" ), QStringLiteral( "0" ) ).toDouble();
365  mRotatedAnnotationsMarginToCorner = itemElem.attribute( QStringLiteral( "rotatedAnnotationsMarginToCorner" ), QStringLiteral( "0" ) ).toDouble();
366 
367  const QDomElement lineStyleElem = itemElem.firstChildElement( QStringLiteral( "lineStyle" ) );
368  if ( !lineStyleElem.isNull() )
369  {
370  const QDomElement symbolElem = lineStyleElem.firstChildElement( QStringLiteral( "symbol" ) );
371  if ( !symbolElem.isNull() )
372  {
373  mGridLineSymbol.reset( QgsSymbolLayerUtils::loadSymbol<QgsLineSymbol>( symbolElem, context ) );
374  }
375  }
376  else
377  {
378  //old project file, read penWidth /penColorRed, penColorGreen, penColorBlue
379  mGridLineSymbol.reset( QgsLineSymbol::createSimple( QVariantMap() ) );
380  mGridLineSymbol->setWidth( itemElem.attribute( QStringLiteral( "penWidth" ), QStringLiteral( "0" ) ).toDouble() );
381  mGridLineSymbol->setColor( QColor( itemElem.attribute( QStringLiteral( "penColorRed" ), QStringLiteral( "0" ) ).toInt(),
382  itemElem.attribute( QStringLiteral( "penColorGreen" ), QStringLiteral( "0" ) ).toInt(),
383  itemElem.attribute( QStringLiteral( "penColorBlue" ), QStringLiteral( "0" ) ).toInt() ) );
384  }
385 
386  const QDomElement markerStyleElem = itemElem.firstChildElement( QStringLiteral( "markerStyle" ) );
387  if ( !markerStyleElem.isNull() )
388  {
389  const QDomElement symbolElem = markerStyleElem.firstChildElement( QStringLiteral( "symbol" ) );
390  if ( !symbolElem.isNull() )
391  {
392  mGridMarkerSymbol.reset( QgsSymbolLayerUtils::loadSymbol<QgsMarkerSymbol>( symbolElem, context ) );
393  }
394  }
395 
396  if ( !mCRS.readXml( itemElem ) )
398 
399  mBlendMode = static_cast< QPainter::CompositionMode >( itemElem.attribute( QStringLiteral( "blendMode" ), QStringLiteral( "0" ) ).toUInt() );
400 
401  //annotation
402  mShowGridAnnotation = ( itemElem.attribute( QStringLiteral( "showAnnotation" ), QStringLiteral( "0" ) ) != QLatin1String( "0" ) );
403  mGridAnnotationFormat = QgsLayoutItemMapGrid::AnnotationFormat( itemElem.attribute( QStringLiteral( "annotationFormat" ), QStringLiteral( "0" ) ).toInt() );
404  mGridAnnotationExpressionString = itemElem.attribute( QStringLiteral( "annotationExpression" ) );
405  mGridAnnotationExpression.reset();
406  mLeftGridAnnotationPosition = QgsLayoutItemMapGrid::AnnotationPosition( itemElem.attribute( QStringLiteral( "leftAnnotationPosition" ), QStringLiteral( "0" ) ).toInt() );
407  mRightGridAnnotationPosition = QgsLayoutItemMapGrid::AnnotationPosition( itemElem.attribute( QStringLiteral( "rightAnnotationPosition" ), QStringLiteral( "0" ) ).toInt() );
408  mTopGridAnnotationPosition = QgsLayoutItemMapGrid::AnnotationPosition( itemElem.attribute( QStringLiteral( "topAnnotationPosition" ), QStringLiteral( "0" ) ).toInt() );
409  mBottomGridAnnotationPosition = QgsLayoutItemMapGrid::AnnotationPosition( itemElem.attribute( QStringLiteral( "bottomAnnotationPosition" ), QStringLiteral( "0" ) ).toInt() );
410  mLeftGridAnnotationDisplay = QgsLayoutItemMapGrid::DisplayMode( itemElem.attribute( QStringLiteral( "leftAnnotationDisplay" ), QStringLiteral( "0" ) ).toInt() );
411  mRightGridAnnotationDisplay = QgsLayoutItemMapGrid::DisplayMode( itemElem.attribute( QStringLiteral( "rightAnnotationDisplay" ), QStringLiteral( "0" ) ).toInt() );
412  mTopGridAnnotationDisplay = QgsLayoutItemMapGrid::DisplayMode( itemElem.attribute( QStringLiteral( "topAnnotationDisplay" ), QStringLiteral( "0" ) ).toInt() );
413  mBottomGridAnnotationDisplay = QgsLayoutItemMapGrid::DisplayMode( itemElem.attribute( QStringLiteral( "bottomAnnotationDisplay" ), QStringLiteral( "0" ) ).toInt() );
414 
415  mLeftGridAnnotationDirection = QgsLayoutItemMapGrid::AnnotationDirection( itemElem.attribute( QStringLiteral( "leftAnnotationDirection" ), QStringLiteral( "0" ) ).toInt() );
416  mRightGridAnnotationDirection = QgsLayoutItemMapGrid::AnnotationDirection( itemElem.attribute( QStringLiteral( "rightAnnotationDirection" ), QStringLiteral( "0" ) ).toInt() );
417  mTopGridAnnotationDirection = QgsLayoutItemMapGrid::AnnotationDirection( itemElem.attribute( QStringLiteral( "topAnnotationDirection" ), QStringLiteral( "0" ) ).toInt() );
418  mBottomGridAnnotationDirection = QgsLayoutItemMapGrid::AnnotationDirection( itemElem.attribute( QStringLiteral( "bottomAnnotationDirection" ), QStringLiteral( "0" ) ).toInt() );
419  mAnnotationFrameDistance = itemElem.attribute( QStringLiteral( "frameAnnotationDistance" ), QStringLiteral( "0" ) ).toDouble();
420 
421  if ( !itemElem.firstChildElement( "text-style" ).isNull() )
422  {
423  mAnnotationFormat.readXml( itemElem, context );
424  }
425  else
426  {
427  QFont font;
428  if ( !QgsFontUtils::setFromXmlChildNode( font, itemElem, "annotationFontProperties" ) )
429  {
430  font.fromString( itemElem.attribute( "annotationFont", QString() ) );
431  }
432  mAnnotationFormat.setFont( font );
433  mAnnotationFormat.setSize( font.pointSizeF() );
434  mAnnotationFormat.setSizeUnit( QgsUnitTypes::RenderPoints );
435  mAnnotationFormat.setColor( QgsSymbolLayerUtils::decodeColor( itemElem.attribute( "annotationFontColor", "0,0,0,255" ) ) );
436  }
437 
438  mGridAnnotationPrecision = itemElem.attribute( QStringLiteral( "annotationPrecision" ), QStringLiteral( "3" ) ).toInt();
439  const int gridUnitInt = itemElem.attribute( QStringLiteral( "unit" ), QString::number( MapUnit ) ).toInt();
440  mGridUnit = ( gridUnitInt <= static_cast< int >( DynamicPageSizeBased ) ) ? static_cast< GridUnit >( gridUnitInt ) : MapUnit;
441  mMinimumIntervalWidth = itemElem.attribute( QStringLiteral( "minimumIntervalWidth" ), QStringLiteral( "50" ) ).toDouble();
442  mMaximumIntervalWidth = itemElem.attribute( QStringLiteral( "maximumIntervalWidth" ), QStringLiteral( "100" ) ).toDouble();
443 
444  refreshDataDefinedProperties();
445  return ok;
446 }
447 
449 {
450  if ( mCRS == crs )
451  return;
452 
453  mCRS = crs;
454  mTransformDirty = true;
455  emit crsChanged();
456 }
457 
459 {
460  return mBlendMode != QPainter::CompositionMode_SourceOver;
461 }
462 
463 QPolygonF QgsLayoutItemMapGrid::scalePolygon( const QPolygonF &polygon, const double scale ) const
464 {
465  const QTransform t = QTransform::fromScale( scale, scale );
466  return t.map( polygon );
467 }
468 
469 void QgsLayoutItemMapGrid::drawGridCrsTransform( QgsRenderContext &context, double dotsPerMM, bool calculateLinesOnly ) const
470 {
471  if ( !mMap || !mEvaluatedEnabled )
472  {
473  return;
474  }
475 
476  //has map extent/scale changed?
477  const QPolygonF mapPolygon = mMap->transformedMapPolygon();
478  if ( mapPolygon != mPrevMapPolygon )
479  {
480  mTransformDirty = true;
481  mPrevMapPolygon = mapPolygon;
482  }
483 
484  if ( mTransformDirty )
485  {
486  calculateCrsTransformLines();
487  }
488 
489  //draw lines
490  if ( !calculateLinesOnly )
491  {
492  if ( mGridStyle == QgsLayoutItemMapGrid::Solid )
493  {
494  QList< GridLine >::const_iterator gridIt = mGridLines.constBegin();
495  for ( ; gridIt != mGridLines.constEnd(); ++gridIt )
496  {
497  drawGridLine( scalePolygon( gridIt->line, dotsPerMM ), context );
498  }
499  }
500  else if ( mGridStyle == QgsLayoutItemMapGrid::Cross || mGridStyle == QgsLayoutItemMapGrid::Markers )
501  {
502  const double maxX = mMap->rect().width();
503  const double maxY = mMap->rect().height();
504 
505  QList< QgsPointXY >::const_iterator intersectionIt = mTransformedIntersections.constBegin();
506  for ( ; intersectionIt != mTransformedIntersections.constEnd(); ++intersectionIt )
507  {
508  const double x = intersectionIt->x();
509  const double y = intersectionIt->y();
510  if ( mGridStyle == QgsLayoutItemMapGrid::Cross )
511  {
512  //ensure that crosses don't overshoot the map item bounds
513  const QLineF line1 = QLineF( x - mEvaluatedCrossLength, y, x + mEvaluatedCrossLength, y );
514  line1.p1().rx() = line1.p1().x() < 0 ? 0 : line1.p1().x();
515  line1.p2().rx() = line1.p2().x() > maxX ? maxX : line1.p2().x();
516  const QLineF line2 = QLineF( x, y - mEvaluatedCrossLength, x, y + mEvaluatedCrossLength );
517  line2.p1().ry() = line2.p1().y() < 0 ? 0 : line2.p1().y();
518  line2.p2().ry() = line2.p2().y() > maxY ? maxY : line2.p2().y();
519 
520  //draw line using coordinates scaled to dots
521  drawGridLine( QLineF( line1.p1() * dotsPerMM, line1.p2() * dotsPerMM ), context );
522  drawGridLine( QLineF( line2.p1() * dotsPerMM, line2.p2() * dotsPerMM ), context );
523  }
524  else if ( mGridStyle == QgsLayoutItemMapGrid::Markers )
525  {
526  drawGridMarker( QPointF( x, y ) * dotsPerMM, context );
527  }
528  }
529  }
530  }
531 }
532 
533 void QgsLayoutItemMapGrid::calculateCrsTransformLines() const
534 {
535  QgsRectangle crsBoundingRect;
536  QgsCoordinateTransform inverseTr;
537  if ( crsGridParams( crsBoundingRect, inverseTr ) != 0 )
538  {
539  return;
540  }
541 
542  // calculate grid lines
543  mGridLines.clear();
544  xGridLinesCrsTransform( crsBoundingRect, inverseTr );
545  yGridLinesCrsTransform( crsBoundingRect, inverseTr );
546 
547  if ( mGridStyle == QgsLayoutItemMapGrid::Cross || mGridStyle == QgsLayoutItemMapGrid::Markers )
548  {
549  //cross or markers style - we also need to calculate intersections of lines
550 
551  //first convert lines to QgsGeometry
552  QList< QgsGeometry > xLines;
553  QList< QgsGeometry > yLines;
554  QList< GridLine >::const_iterator gridIt = mGridLines.constBegin();
555  for ( ; gridIt != mGridLines.constEnd(); ++gridIt )
556  {
557 
558  QgsPolylineXY line;
559  for ( int i = 0; i < gridIt->line.size(); ++i )
560  {
561  line.append( QgsPointXY( gridIt->line.at( i ).x(), gridIt->line.at( i ).y() ) );
562  }
563  if ( gridIt->coordinateType == AnnotationCoordinate::Longitude )
564  yLines << QgsGeometry::fromPolylineXY( line );
565  else if ( gridIt->coordinateType == AnnotationCoordinate::Latitude )
566  xLines << QgsGeometry::fromPolylineXY( line );
567  }
568 
569  //now, loop through geometries and calculate intersection points
570  mTransformedIntersections.clear();
571  QList< QgsGeometry >::const_iterator yLineIt = yLines.constBegin();
572  for ( ; yLineIt != yLines.constEnd(); ++yLineIt )
573  {
574  QList< QgsGeometry >::const_iterator xLineIt = xLines.constBegin();
575  for ( ; xLineIt != xLines.constEnd(); ++xLineIt )
576  {
577  //look for intersections between lines
578  const QgsGeometry intersects = ( *yLineIt ).intersection( ( *xLineIt ) );
579  if ( intersects.isNull() )
580  continue;
581 
582  //go through all intersections and draw grid markers/crosses
583  int i = 0;
584  QgsPointXY vertex = intersects.vertexAt( i );
585  while ( !vertex.isEmpty() )
586  {
587  mTransformedIntersections << vertex;
588  i = i + 1;
589  vertex = intersects.vertexAt( i );
590  }
591  }
592  }
593  }
594 
595  mTransformDirty = false;
596 }
597 
598 void QgsLayoutItemMapGrid::draw( QPainter *p )
599 {
600  if ( !mMap || !mEvaluatedEnabled )
601  {
602  return;
603  }
604  QPaintDevice *paintDevice = p->device();
605  if ( !paintDevice )
606  {
607  return;
608  }
609 
610  p->save();
611  p->setCompositionMode( mBlendMode );
612  p->setRenderHint( QPainter::Antialiasing, mMap->layout()->renderContext().flags() & QgsLayoutRenderContext::FlagAntialiasing );
613 
614  const QRectF thisPaintRect = QRectF( 0, 0, mMap->rect().width(), mMap->rect().height() );
615  p->setClipRect( thisPaintRect );
616  if ( thisPaintRect != mPrevPaintRect )
617  {
618  //rect has changed, so need to recalculate transform
619  mTransformDirty = true;
620  mPrevPaintRect = thisPaintRect;
621  }
622 
623  //setup painter scaling to dots so that raster symbology is drawn to scale
624  const double dotsPerMM = paintDevice->logicalDpiX() / 25.4;
625  p->scale( 1 / dotsPerMM, 1 / dotsPerMM ); //scale painter from mm to dots
626 
627  //setup render context
629  context.setForceVectorOutput( true );
631  const QgsExpressionContext expressionContext = createExpressionContext();
632  context.setExpressionContext( expressionContext );
633 
634  //is grid in a different crs than map?
635  switch ( mGridUnit )
636  {
637  case MapUnit:
639  if ( mCRS.isValid() && mCRS != mMap->crs() )
640  {
641  drawGridCrsTransform( context, dotsPerMM );
642  break;
643  }
644 
646  case CM:
647  case MM:
648  drawGridNoTransform( context, dotsPerMM );
649  break;
650  }
651  p->restore();
652 
653  p->setClipping( false );
654 #ifdef Q_OS_MAC
655  //QPainter::setClipping(false) seems to be broken on OSX (#12747). So we hack around it by
656  //setting a larger clip rect
657  p->setClipRect( mMap->mapRectFromScene( mMap->sceneBoundingRect() ).adjusted( -10, -10, 10, 10 ) );
658 #endif
659 
660 
661  if ( mGridFrameStyle != QgsLayoutItemMapGrid::NoFrame || mShowGridAnnotation )
662  updateGridLinesAnnotationsPositions();
663 
664  if ( mGridFrameStyle != QgsLayoutItemMapGrid::NoFrame )
665  {
666  drawGridFrame( p );
667  }
668 
669  if ( mShowGridAnnotation )
670  {
671  drawCoordinateAnnotations( context, context.expressionContext() );
672  }
673 }
674 
675 void QgsLayoutItemMapGrid::updateGridLinesAnnotationsPositions() const
676 {
677  QList< GridLine >::iterator it = mGridLines.begin();
678  for ( ; it != mGridLines.end(); ++it )
679  {
680  it->startAnnotation.border = borderForLineCoord( it->line.first(), it->coordinateType );
681  it->endAnnotation.border = borderForLineCoord( it->line.last(), it->coordinateType );
682  it->startAnnotation.position = QVector2D( it->line.first() );
683  it->endAnnotation.position = QVector2D( it->line.last() );
684  it->startAnnotation.vector = QVector2D( it->line.at( 1 ) - it->line.first() ).normalized();
685  it->endAnnotation.vector = QVector2D( it->line.at( it->line.count() - 2 ) - it->line.last() ).normalized();
686  const QVector2D normS = borderToNormal2D( it->startAnnotation.border );
687  it->startAnnotation.angle = atan2( it->startAnnotation.vector.x() * normS.y() - it->startAnnotation.vector.y() * normS.x(), it->startAnnotation.vector.x() * normS.x() + it->startAnnotation.vector.y() * normS.y() );
688  const QVector2D normE = borderToNormal2D( it->endAnnotation.border );
689  it->endAnnotation.angle = atan2( it->endAnnotation.vector.x() * normE.y() - it->endAnnotation.vector.y() * normE.x(), it->endAnnotation.vector.x() * normE.x() + it->endAnnotation.vector.y() * normE.y() );
690  }
691 }
692 
693 void QgsLayoutItemMapGrid::drawGridNoTransform( QgsRenderContext &context, double dotsPerMM, bool calculateLinesOnly ) const
694 {
695  //get line positions
696  mGridLines.clear();
697  yGridLines();
698  xGridLines();
699 
700  if ( calculateLinesOnly )
701  return;
702 
703  QList< GridLine >::const_iterator vIt = mGridLines.constBegin();
704  QList< GridLine >::const_iterator hIt = mGridLines.constBegin();
705 
706  //simple approach: draw vertical lines first, then horizontal ones
707  if ( mGridStyle == QgsLayoutItemMapGrid::Solid )
708  {
709  //we need to scale line coordinates to dots, rather than mm, since the painter has already been scaled to dots
710  //this is done by multiplying each line coordinate by dotsPerMM
711  QLineF line;
712  for ( ; vIt != mGridLines.constEnd(); ++vIt )
713  {
714  if ( vIt->coordinateType != AnnotationCoordinate::Longitude )
715  continue;
716  line = QLineF( vIt->line.first() * dotsPerMM, vIt->line.last() * dotsPerMM );
717  drawGridLine( line, context );
718  }
719 
720  for ( ; hIt != mGridLines.constEnd(); ++hIt )
721  {
722  if ( hIt->coordinateType != AnnotationCoordinate::Latitude )
723  continue;
724  line = QLineF( hIt->line.first() * dotsPerMM, hIt->line.last() * dotsPerMM );
725  drawGridLine( line, context );
726  }
727  }
728  else if ( mGridStyle != QgsLayoutItemMapGrid::FrameAnnotationsOnly ) //cross or markers
729  {
730  QLineF l1, l2;
731  QPointF intersectionPoint, crossEnd1, crossEnd2;
732  for ( ; vIt != mGridLines.constEnd(); ++vIt )
733  {
734  if ( vIt->coordinateType != AnnotationCoordinate::Longitude )
735  continue;
736 
737  l1 = QLineF( vIt->line.first(), vIt->line.last() );
738 
739  //test for intersection with every horizontal line
740  hIt = mGridLines.constBegin();
741  for ( ; hIt != mGridLines.constEnd(); ++hIt )
742  {
743  if ( hIt->coordinateType != AnnotationCoordinate::Latitude )
744  continue;
745 
746  l2 = QLineF( hIt->line.first(), hIt->line.last() );
747 
748 #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
749  if ( l2.intersect( l1, &intersectionPoint ) == QLineF::BoundedIntersection )
750 #else
751  if ( l2.intersects( l1, &intersectionPoint ) == QLineF::BoundedIntersection )
752 #endif
753  {
754  if ( mGridStyle == QgsLayoutItemMapGrid::Cross )
755  {
756  //apply a threshold to avoid calculate point if the two points are very close together (can lead to artifacts)
757  crossEnd1 = ( ( intersectionPoint - l1.p1() ).manhattanLength() > 0.01 ) ?
758  QgsSymbolLayerUtils::pointOnLineWithDistance( intersectionPoint, l1.p1(), mEvaluatedCrossLength ) : intersectionPoint;
759  crossEnd2 = ( ( intersectionPoint - l1.p2() ).manhattanLength() > 0.01 ) ?
760  QgsSymbolLayerUtils::pointOnLineWithDistance( intersectionPoint, l1.p2(), mEvaluatedCrossLength ) : intersectionPoint;
761  //draw line using coordinates scaled to dots
762  drawGridLine( QLineF( crossEnd1 * dotsPerMM, crossEnd2 * dotsPerMM ), context );
763  }
764  else if ( mGridStyle == QgsLayoutItemMapGrid::Markers )
765  {
766  drawGridMarker( intersectionPoint * dotsPerMM, context );
767  }
768  }
769  }
770  }
771  if ( mGridStyle == QgsLayoutItemMapGrid::Markers )
772  {
773  //markers mode, so we have no need to process horizontal lines (we've already
774  //drawn markers on the intersections between horizontal and vertical lines)
775  return;
776  }
777 
778  hIt = mGridLines.constBegin();
779  for ( ; hIt != mGridLines.constEnd(); ++hIt )
780  {
781  if ( hIt->coordinateType != AnnotationCoordinate::Latitude )
782  continue;
783 
784  l1 = QLineF( hIt->line.first(), hIt->line.last() );
785 
786  vIt = mGridLines.constBegin();
787  for ( ; vIt != mGridLines.constEnd(); ++vIt )
788  {
789  if ( vIt->coordinateType != AnnotationCoordinate::Longitude )
790  continue;
791 
792  l2 = QLineF( vIt->line.first(), vIt->line.last() );
793 
794 #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
795  if ( l2.intersect( l1, &intersectionPoint ) == QLineF::BoundedIntersection )
796 #else
797  if ( l2.intersects( l1, &intersectionPoint ) == QLineF::BoundedIntersection )
798 #endif
799  {
800  //apply a threshold to avoid calculate point if the two points are very close together (can lead to artifacts)
801  crossEnd1 = ( ( intersectionPoint - l1.p1() ).manhattanLength() > 0.01 ) ?
802  QgsSymbolLayerUtils::pointOnLineWithDistance( intersectionPoint, l1.p1(), mEvaluatedCrossLength ) : intersectionPoint;
803  crossEnd2 = ( ( intersectionPoint - l1.p2() ).manhattanLength() > 0.01 ) ?
804  QgsSymbolLayerUtils::pointOnLineWithDistance( intersectionPoint, l1.p2(), mEvaluatedCrossLength ) : intersectionPoint;
805  //draw line using coordinates scaled to dots
806  drawGridLine( QLineF( crossEnd1 * dotsPerMM, crossEnd2 * dotsPerMM ), context );
807  }
808  }
809  }
810  }
811 }
812 
813 void QgsLayoutItemMapGrid::drawGridFrame( QPainter *p, GridExtension *extension ) const
814 {
815  if ( p )
816  {
817  p->save();
818  p->setRenderHint( QPainter::Antialiasing, mMap->layout()->renderContext().flags() & QgsLayoutRenderContext::FlagAntialiasing );
819  }
820 
821 
822  switch ( mGridFrameStyle )
823  {
826  drawGridFrameZebra( p, extension );
827  break;
831  drawGridFrameTicks( p, extension );
832  break;
833 
836  drawGridFrameLine( p, extension );
837  break;
838 
840  break;
841  }
842 
843  if ( p )
844  p->restore();
845 }
846 
847 void QgsLayoutItemMapGrid::drawGridLine( const QLineF &line, QgsRenderContext &context ) const
848 {
849  QPolygonF poly;
850  poly << line.p1() << line.p2();
851  drawGridLine( poly, context );
852 }
853 
854 void QgsLayoutItemMapGrid::drawGridLine( const QPolygonF &line, QgsRenderContext &context ) const
855 {
856  if ( !mMap || !mMap->layout() || !mGridLineSymbol )
857  {
858  return;
859  }
860 
861  mGridLineSymbol->startRender( context );
862  mGridLineSymbol->renderPolyline( line, nullptr, context );
863  mGridLineSymbol->stopRender( context );
864 }
865 
866 void QgsLayoutItemMapGrid::drawGridMarker( QPointF point, QgsRenderContext &context ) const
867 {
868  if ( !mMap || !mMap->layout() || !mGridMarkerSymbol )
869  {
870  return;
871  }
872 
873  mGridMarkerSymbol->startRender( context );
874  mGridMarkerSymbol->renderPoint( point, nullptr, context );
875  mGridMarkerSymbol->stopRender( context );
876 }
877 
878 void QgsLayoutItemMapGrid::drawGridFrameZebra( QPainter *p, GridExtension *extension ) const
879 {
881  {
882  drawGridFrameZebraBorder( p, QgsLayoutItemMapGrid::Left, extension ? &extension->left : nullptr );
883  }
885  {
886  drawGridFrameZebraBorder( p, QgsLayoutItemMapGrid::Right, extension ? &extension->right : nullptr );
887  }
889  {
890  drawGridFrameZebraBorder( p, QgsLayoutItemMapGrid::Top, extension ? &extension->top : nullptr );
891  }
893  {
894  drawGridFrameZebraBorder( p, QgsLayoutItemMapGrid::Bottom, extension ? &extension->bottom : nullptr );
895  }
896 }
897 
898 void QgsLayoutItemMapGrid::drawGridFrameZebraBorder( QPainter *p, BorderSide border, double *extension ) const
899 {
900  if ( !mMap )
901  {
902  return;
903  }
904 
905  if ( extension )
906  {
907  *extension = mEvaluatedGridFrameMargin + mEvaluatedGridFrameWidth + mEvaluatedGridFrameLineThickness / 2.0;
908  return;
909  }
910 
911  double currentCoord = 0.0;
912  bool color1 = false;
913  double x = 0;
914  double y = 0;
915  double width = 0;
916  double height = 0;
917 
918  bool drawTLBox = false;
919  bool drawTRBox = false;
920  bool drawBLBox = false;
921  bool drawBRBox = false;
922 
923  QMap< double, double > pos = QMap< double, double >();
924  QList< GridLine >::const_iterator it = mGridLines.constBegin();
925  for ( ; it != mGridLines.constEnd(); ++it )
926  {
927  // for first and last point of the line
928  for ( int i = 0 ; i < 2 ; ++i )
929  {
930  const GridLineAnnotation annot = ( i == 0 ) ? it->startAnnotation : it->endAnnotation;
931 
932  // we skip if the point is on another border
933  if ( annot.border != border )
934  continue;
935 
936  if ( ! shouldShowDivisionForSide( it->coordinateType, annot.border ) )
937  continue;
938 
939  if ( border == QgsLayoutItemMapGrid::Left || border == QgsLayoutItemMapGrid::Right )
940  pos.insert( annot.position.y(), it->coordinate );
941  else
942  pos.insert( annot.position.x(), it->coordinate );
943  }
944  }
945 
946 
947  if ( border == QgsLayoutItemMapGrid::Left || border == QgsLayoutItemMapGrid::Right )
948  {
949  pos.insert( mMap->rect().height(), mMap->rect().height() );
951  {
952  drawBLBox = border == QgsLayoutItemMapGrid::Left;
953  drawBRBox = border == QgsLayoutItemMapGrid::Right;
954  }
956  {
957  drawTLBox = border == QgsLayoutItemMapGrid::Left;
958  drawTRBox = border == QgsLayoutItemMapGrid::Right;
959  }
960  if ( !drawTLBox && border == QgsLayoutItemMapGrid::Left )
961  color1 = true;
962  }
963  else if ( border == QgsLayoutItemMapGrid::Top || border == QgsLayoutItemMapGrid::Bottom )
964  {
965  pos.insert( mMap->rect().width(), mMap->rect().width() );
966  }
967 
968  //set pen to current frame pen
969  QPen framePen = QPen( mGridFramePenColor );
970  framePen.setWidthF( mEvaluatedGridFrameLineThickness );
971  framePen.setJoinStyle( Qt::MiterJoin );
972  p->setPen( framePen );
973 
974  QMap< double, double >::const_iterator posIt = pos.constBegin();
975  for ( ; posIt != pos.constEnd(); ++posIt )
976  {
977  p->setBrush( QBrush( color1 ? mGridFrameFillColor1 : mGridFrameFillColor2 ) );
978  if ( border == QgsLayoutItemMapGrid::Left || border == QgsLayoutItemMapGrid::Right )
979  {
980  height = posIt.key() - currentCoord;
981  width = mEvaluatedGridFrameWidth;
982  x = ( border == QgsLayoutItemMapGrid::Left ) ? -( mEvaluatedGridFrameWidth + mEvaluatedGridFrameMargin ) : mMap->rect().width() + mEvaluatedGridFrameMargin;
983  y = currentCoord;
984  }
985  else //top or bottom
986  {
987  height = mEvaluatedGridFrameWidth;
988  width = posIt.key() - currentCoord;
989  x = currentCoord;
990  y = ( border == QgsLayoutItemMapGrid::Top ) ? -( mEvaluatedGridFrameWidth + mEvaluatedGridFrameMargin ) : mMap->rect().height() + mEvaluatedGridFrameMargin;
991  }
992  p->drawRect( QRectF( x, y, width, height ) );
993  currentCoord = posIt.key();
994  color1 = !color1;
995  }
996 
997  if ( mGridFrameStyle == ZebraNautical || qgsDoubleNear( mEvaluatedGridFrameMargin, 0.0 ) )
998  {
999  //draw corners
1000  width = height = ( mEvaluatedGridFrameWidth + mEvaluatedGridFrameMargin ) ;
1001  p->setBrush( QBrush( mGridFrameFillColor1 ) );
1002  if ( drawTLBox )
1003  p->drawRect( QRectF( -( mEvaluatedGridFrameWidth + mEvaluatedGridFrameMargin ), -( mEvaluatedGridFrameWidth + mEvaluatedGridFrameMargin ), width, height ) );
1004  if ( drawTRBox )
1005  p->drawRect( QRectF( mMap->rect().width(), -( mEvaluatedGridFrameWidth + mEvaluatedGridFrameMargin ), width, height ) );
1006  if ( drawBLBox )
1007  p->drawRect( QRectF( -( mEvaluatedGridFrameWidth + mEvaluatedGridFrameMargin ), mMap->rect().height(), width, height ) );
1008  if ( drawBRBox )
1009  p->drawRect( QRectF( mMap->rect().width(), mMap->rect().height(), width, height ) );
1010  }
1011 }
1012 
1013 void QgsLayoutItemMapGrid::drawGridFrameTicks( QPainter *p, GridExtension *extension ) const
1014 {
1015  if ( !mMap )
1016  {
1017  return;
1018  }
1019 
1020  //set pen to current frame pen
1021  if ( p )
1022  {
1023  QPen framePen = QPen( mGridFramePenColor );
1024  framePen.setWidthF( mEvaluatedGridFrameLineThickness );
1025  framePen.setCapStyle( Qt::FlatCap );
1026  p->setBrush( Qt::NoBrush );
1027  p->setPen( framePen );
1028  }
1029 
1030  QList< GridLine >::iterator it = mGridLines.begin();
1031  for ( ; it != mGridLines.end(); ++it )
1032  {
1033  // for first and last point of the line
1034  for ( int i = 0 ; i < 2 ; ++i )
1035  {
1036  const GridLineAnnotation annot = ( i == 0 ) ? it->startAnnotation : it->endAnnotation;
1037 
1038  if ( ! shouldShowDivisionForSide( it->coordinateType, annot.border ) )
1039  continue;
1040 
1041  // If the angle is below the threshold, we don't draw the annotation
1042  if ( abs( annot.angle ) / M_PI * 180.0 > 90.0 - mRotatedTicksMinimumAngle + 0.0001 )
1043  continue;
1044 
1045  // Skip outwards facing annotations that are below mRotatedTicksMarginToCorner
1046  bool facingLeft;
1047  bool facingRight;
1048  if ( mGridFrameStyle == QgsLayoutItemMapGrid::InteriorExteriorTicks )
1049  {
1050  facingLeft = ( annot.angle != 0 );
1051  facingRight = ( annot.angle != 0 );
1052  }
1053  else if ( mGridFrameStyle == QgsLayoutItemMapGrid::ExteriorTicks )
1054  {
1055  facingLeft = ( annot.angle > 0 );
1056  facingRight = ( annot.angle < 0 );
1057  }
1058  else
1059  {
1060  facingLeft = ( annot.angle < 0 );
1061  facingRight = ( annot.angle > 0 );
1062  }
1063 
1064  if ( annot.border == BorderSide::Top && ( ( facingLeft && annot.position.x() < mRotatedTicksMarginToCorner ) ||
1065  ( facingRight && annot.position.x() > mMap->rect().width() - mRotatedTicksMarginToCorner ) ) )
1066  continue;
1067  if ( annot.border == BorderSide::Bottom && ( ( facingLeft && annot.position.x() > mMap->rect().width() - mRotatedTicksMarginToCorner ) ||
1068  ( facingRight && annot.position.x() < mRotatedTicksMarginToCorner ) ) )
1069  continue;
1070  if ( annot.border == BorderSide::Left && ( ( facingLeft && annot.position.y() > mMap->rect().height() - mRotatedTicksMarginToCorner ) ||
1071  ( facingRight && annot.position.y() < mRotatedTicksMarginToCorner ) ) )
1072  continue;
1073  if ( annot.border == BorderSide::Right && ( ( facingLeft && annot.position.y() < mRotatedTicksMarginToCorner ) ||
1074  ( facingRight && annot.position.y() > mMap->rect().height() - mRotatedTicksMarginToCorner ) ) )
1075  continue;
1076 
1077  const QVector2D normalVector = borderToNormal2D( annot.border );
1078  const QVector2D vector = ( mRotatedTicksEnabled ) ? annot.vector : normalVector;
1079 
1080  double fA = mEvaluatedGridFrameMargin; // point near to frame
1081  double fB = mEvaluatedGridFrameMargin + mEvaluatedGridFrameWidth; // point far from frame
1082 
1083  if ( mRotatedTicksEnabled && mRotatedTicksLengthMode == OrthogonalTicks )
1084  {
1085  fA /= QVector2D::dotProduct( vector, normalVector );
1086  fB /= QVector2D::dotProduct( vector, normalVector );
1087  }
1088 
1089  // extents isn't computed accurately
1090  if ( extension )
1091  {
1092  if ( mGridFrameStyle != QgsLayoutItemMapGrid::InteriorTicks )
1093  extension->UpdateBorder( annot.border, fB );
1094  continue;
1095  }
1096 
1097  QVector2D pA;
1098  QVector2D pB;
1099  if ( mGridFrameStyle == QgsLayoutItemMapGrid::InteriorTicks )
1100  {
1101  pA = annot.position + fA * vector;
1102  pB = annot.position + fB * vector;
1103  }
1104  else if ( mGridFrameStyle == QgsLayoutItemMapGrid::ExteriorTicks )
1105  {
1106  pA = annot.position - fA * vector;
1107  pB = annot.position - fB * vector;
1108  }
1109  else // InteriorExteriorTicks
1110  {
1111  pA = annot.position - fB * vector;
1112  pB = annot.position + ( fB - 2.0 * mEvaluatedGridFrameMargin ) * vector;
1113  }
1114  p->drawLine( QLineF( pA.toPointF(), pB.toPointF() ) );
1115 
1116  }
1117  }
1118 }
1119 
1120 void QgsLayoutItemMapGrid::drawGridFrameLine( QPainter *p, GridExtension *extension ) const
1121 {
1122  if ( !mMap )
1123  {
1124  return;
1125  }
1126 
1127  if ( p )
1128  {
1129  //set pen to current frame pen
1130  QPen framePen = QPen( mGridFramePenColor );
1131  framePen.setWidthF( mEvaluatedGridFrameLineThickness );
1132  framePen.setCapStyle( Qt::SquareCap );
1133  p->setBrush( Qt::NoBrush );
1134  p->setPen( framePen );
1135  }
1136 
1137  const bool drawDiagonals = mGridFrameStyle == LineBorderNautical && !qgsDoubleNear( mEvaluatedGridFrameMargin, 0.0 );
1138 
1140  {
1141  if ( extension )
1142  extension->UpdateBorder( QgsLayoutItemMapGrid::Left, mEvaluatedGridFrameMargin + mEvaluatedGridFrameLineThickness / 2.0 );
1143  else
1144  p->drawLine( QLineF( 0 - mEvaluatedGridFrameMargin, 0 - mEvaluatedGridFrameMargin, 0 - mEvaluatedGridFrameMargin, mMap->rect().height() + mEvaluatedGridFrameMargin ) );
1145  }
1146 
1148  {
1149  if ( extension )
1150  extension->UpdateBorder( QgsLayoutItemMapGrid::Right, mEvaluatedGridFrameMargin + mEvaluatedGridFrameLineThickness / 2.0 );
1151  else
1152  p->drawLine( QLineF( mMap->rect().width() + mEvaluatedGridFrameMargin, 0 - mEvaluatedGridFrameMargin, mMap->rect().width() + mEvaluatedGridFrameMargin, mMap->rect().height() + mEvaluatedGridFrameMargin ) );
1153  }
1154 
1156  {
1157  if ( extension )
1158  extension->UpdateBorder( QgsLayoutItemMapGrid::Top, mEvaluatedGridFrameMargin + mEvaluatedGridFrameLineThickness / 2.0 );
1159  else
1160  p->drawLine( QLineF( 0 - mEvaluatedGridFrameMargin, 0 - mEvaluatedGridFrameMargin, mMap->rect().width() + mEvaluatedGridFrameMargin, 0 - mEvaluatedGridFrameMargin ) );
1161  }
1162 
1164  {
1165  if ( extension )
1166  extension->UpdateBorder( QgsLayoutItemMapGrid::Bottom, mEvaluatedGridFrameMargin + mEvaluatedGridFrameLineThickness / 2.0 );
1167  else
1168  p->drawLine( QLineF( 0 - mEvaluatedGridFrameMargin, mMap->rect().height() + mEvaluatedGridFrameMargin, mMap->rect().width() + mEvaluatedGridFrameMargin, mMap->rect().height() + mEvaluatedGridFrameMargin ) );
1169  }
1170 
1171  if ( ! extension && drawDiagonals )
1172  {
1174  {
1175  //corner left-top
1176  const double X1 = 0 - mEvaluatedGridFrameMargin + mEvaluatedGridFrameLineThickness / 2.0;
1177  const double Y1 = 0 - mEvaluatedGridFrameMargin + mEvaluatedGridFrameLineThickness / 2.0;
1178  p->drawLine( QLineF( 0, 0, X1, Y1 ) );
1179  }
1181  {
1182  //corner right-bottom
1183  const double X1 = mMap->rect().width() + mEvaluatedGridFrameMargin - mEvaluatedGridFrameLineThickness / 2.0 ;
1184  const double Y1 = mMap->rect().height() + mEvaluatedGridFrameMargin - mEvaluatedGridFrameLineThickness / 2.0 ;
1185  p->drawLine( QLineF( mMap->rect().width(), mMap->rect().height(), X1, Y1 ) );
1186  }
1188  {
1189  //corner right-top
1190  const double X1 = mMap->rect().width() + mEvaluatedGridFrameMargin - mEvaluatedGridFrameLineThickness / 2.0 ;
1191  const double Y1 = 0 - mEvaluatedGridFrameMargin + mEvaluatedGridFrameLineThickness / 2.0 ;
1192  p->drawLine( QLineF( mMap->rect().width(), 0, X1, Y1 ) );
1193  }
1195  {
1196  //corner left-bottom
1197  const double X1 = 0 - mEvaluatedGridFrameMargin + mEvaluatedGridFrameLineThickness / 2.0 ;
1198  const double Y1 = mMap->rect().height() + mEvaluatedGridFrameMargin - mEvaluatedGridFrameLineThickness / 2.0 ;
1199  p->drawLine( QLineF( 0, mMap->rect().height(), X1, Y1 ) );
1200  }
1201  }
1202 }
1203 
1204 void QgsLayoutItemMapGrid::drawCoordinateAnnotations( QgsRenderContext &context, QgsExpressionContext &expressionContext,
1205  GridExtension *extension ) const
1206 {
1207  QString currentAnnotationString;
1208  QList< GridLine >::const_iterator it = mGridLines.constBegin();
1209  for ( ; it != mGridLines.constEnd(); ++it )
1210  {
1211  currentAnnotationString = gridAnnotationString( it->coordinate, it->coordinateType, expressionContext );
1212  drawCoordinateAnnotation( context, it->startAnnotation, currentAnnotationString, it->coordinateType, extension );
1213  drawCoordinateAnnotation( context, it->endAnnotation, currentAnnotationString, it->coordinateType, extension );
1214  }
1215 }
1216 
1217 void QgsLayoutItemMapGrid::drawCoordinateAnnotation( QgsRenderContext &context, GridLineAnnotation annot, const QString &annotationString, const AnnotationCoordinate coordinateType, GridExtension *extension ) const
1218 {
1219  if ( !mMap )
1220  {
1221  return;
1222  }
1223 
1224  if ( ! shouldShowAnnotationForSide( coordinateType, annot.border ) )
1225  return;
1226 
1227  const QgsLayoutItemMapGrid::BorderSide frameBorder = annot.border;
1228  double textWidth = QgsTextRenderer::textWidth( context, mAnnotationFormat, QStringList() << annotationString ) / context.convertToPainterUnits( 1, QgsUnitTypes::RenderMillimeters );
1229  if ( extension )
1230  textWidth *= 1.1; // little bit of extra padding when we are calculating the bounding rect, to account for antialiasing
1231 
1232  //relevant for annotations is the height of digits
1233  const double textHeight = ( extension ? ( QgsTextRenderer::textHeight( context, mAnnotationFormat, QChar(), true ) )
1234  : ( QgsTextRenderer::textHeight( context, mAnnotationFormat, '0', false ) ) ) / context.convertToPainterUnits( 1, QgsUnitTypes::RenderMillimeters );
1235 
1236  double xpos = annot.position.x();
1237  double ypos = annot.position.y();
1238  QPointF anchor = QPointF();
1239  int rotation = 0;
1240 
1241  const AnnotationPosition anotPos = annotationPosition( frameBorder );
1242  const AnnotationDirection anotDir = annotationDirection( frameBorder );
1243 
1244  // If the angle is below the threshold, we don't draw the annotation
1245  if ( abs( annot.angle ) / M_PI * 180.0 > 90.0 - mRotatedAnnotationsMinimumAngle + 0.0001 )
1246  return;
1247 
1248  const QVector2D normalVector = borderToNormal2D( annot.border );
1249  const QVector2D vector = ( mRotatedAnnotationsEnabled ) ? annot.vector : normalVector;
1250 
1251  // Distance to frame
1252  double f = mEvaluatedAnnotationFrameDistance;
1253 
1254  // Adapt distance to frame using the frame width and line thickness into account
1255  const bool isOverTick = ( anotDir == QgsLayoutItemMapGrid::AboveTick || anotDir == QgsLayoutItemMapGrid::OnTick || anotDir == QgsLayoutItemMapGrid::UnderTick );
1256  const bool hasInteriorMargin = ! isOverTick && ( mGridFrameStyle == QgsLayoutItemMapGrid::InteriorTicks || mGridFrameStyle == QgsLayoutItemMapGrid::InteriorExteriorTicks );
1257  const bool hasExteriorMargin = ! isOverTick && ( mGridFrameStyle == QgsLayoutItemMapGrid::Zebra || mGridFrameStyle == QgsLayoutItemMapGrid::ExteriorTicks || mGridFrameStyle == QgsLayoutItemMapGrid::InteriorExteriorTicks || mGridFrameStyle == QgsLayoutItemMapGrid::ZebraNautical );
1258  const bool hasBorderWidth = ( mGridFrameStyle == QgsLayoutItemMapGrid::Zebra || mGridFrameStyle == QgsLayoutItemMapGrid::ZebraNautical || mGridFrameStyle == QgsLayoutItemMapGrid::LineBorder || mGridFrameStyle == QgsLayoutItemMapGrid::LineBorderNautical );
1259  if ( ( anotPos == QgsLayoutItemMapGrid::InsideMapFrame && hasInteriorMargin ) || ( anotPos == QgsLayoutItemMapGrid::OutsideMapFrame && hasExteriorMargin ) )
1260  f += mEvaluatedGridFrameWidth;
1261  if ( hasBorderWidth )
1262  f += mEvaluatedGridFrameLineThickness / 2.0;
1263 
1264  if ( anotPos == QgsLayoutItemMapGrid::OutsideMapFrame )
1265  f *= -1;
1266 
1267  if ( mRotatedAnnotationsEnabled && mRotatedAnnotationsLengthMode == OrthogonalTicks )
1268  {
1269  f /= QVector2D::dotProduct( vector, normalVector );
1270  }
1271 
1272  const QVector2D pos = annot.position + f * vector;
1273  xpos = pos.x();
1274  ypos = pos.y();
1275 
1276  const bool outside = ( anotPos == QgsLayoutItemMapGrid::OutsideMapFrame );
1277 
1278  if (
1279  anotDir == QgsLayoutItemMapGrid::AboveTick ||
1280  anotDir == QgsLayoutItemMapGrid::OnTick ||
1282  )
1283  {
1284 
1285  rotation = atan2( vector.y(), vector.x() ) / M_PI * 180;
1286 
1287  if ( rotation <= -90 || rotation > 90 )
1288  {
1289  rotation += 180;
1290  anchor.setX( outside ? 0 : textWidth ); // left / right
1291  }
1292  else
1293  {
1294  anchor.setX( outside ? textWidth : 0 ); // right / left
1295  }
1296 
1297  if ( anotDir == QgsLayoutItemMapGrid::AboveTick )
1298  anchor.setY( 0.5 * textHeight ); // bottom
1299  else if ( anotDir == QgsLayoutItemMapGrid::UnderTick )
1300  anchor.setY( -1.5 * textHeight ); // top
1301  else // OnTick
1302  anchor.setY( -0.5 * textHeight ); // middle
1303 
1304  }
1305  else if ( anotDir == QgsLayoutItemMapGrid::Horizontal )
1306  {
1307  rotation = 0;
1308  anchor.setX( 0.5 * textWidth ); // center
1309  anchor.setY( -0.5 * textHeight ); // middle
1310  if ( frameBorder == QgsLayoutItemMapGrid::Top )
1311  anchor.setY( outside ? 0 : -textHeight ); // bottom / top
1312  else if ( frameBorder == QgsLayoutItemMapGrid::Right )
1313  anchor.setX( outside ? 0 : textWidth ); // left / right
1314  else if ( frameBorder == QgsLayoutItemMapGrid::Bottom )
1315  anchor.setY( outside ? -textHeight : 0 ); // top / bottom
1316  else if ( frameBorder == QgsLayoutItemMapGrid::Left )
1317  anchor.setX( outside ? textWidth : 0 ); // right / left
1318  }
1319  else if ( anotDir == QgsLayoutItemMapGrid::Vertical )
1320  {
1321  rotation = -90;
1322  anchor.setX( 0.5 * textWidth ); // center
1323  anchor.setY( -0.5 * textHeight ); // middle
1324  if ( frameBorder == QgsLayoutItemMapGrid::Top )
1325  anchor.setX( outside ? 0 : textWidth ); // left / right
1326  else if ( frameBorder == QgsLayoutItemMapGrid::Right )
1327  anchor.setY( outside ? -textHeight : 0 ); // top / bottom
1328  else if ( frameBorder == QgsLayoutItemMapGrid::Bottom )
1329  anchor.setX( outside ? textWidth : 0 ); // right / left
1330  else if ( frameBorder == QgsLayoutItemMapGrid::Left )
1331  anchor.setY( outside ? 0 : -textHeight ); // bottom / top
1332  }
1333  else if ( anotDir == QgsLayoutItemMapGrid::VerticalDescending )
1334  {
1335  rotation = 90;
1336  anchor.setX( 0.5 * textWidth ); // center
1337  anchor.setY( -0.5 * textHeight ); // middle
1338  if ( frameBorder == QgsLayoutItemMapGrid::Top )
1339  anchor.setX( outside ? textWidth : 0 ); // right / left
1340  else if ( frameBorder == QgsLayoutItemMapGrid::Right )
1341  anchor.setY( outside ? 0 : -textHeight ); // bottom / top
1342  else if ( frameBorder == QgsLayoutItemMapGrid::Bottom )
1343  anchor.setX( outside ? 0 : textWidth ); // left / right
1344  else if ( frameBorder == QgsLayoutItemMapGrid::Left )
1345  anchor.setY( outside ? -textHeight : 0 ); // top / bottom
1346  }
1347  else // ( anotDir == QgsLayoutItemMapGrid::BoundaryDirection )
1348  {
1349  const QVector2D borderVector = borderToVector2D( annot.border );
1350  rotation = atan2( borderVector.y(), borderVector.x() ) / M_PI * 180;
1351  anchor.setX( 0.5 * textWidth ); // center
1352  if ( anotPos == QgsLayoutItemMapGrid::OutsideMapFrame )
1353  anchor.setY( -textHeight ); // top
1354  else
1355  anchor.setY( 0 ); // bottom
1356  }
1357 
1358  // extents isn't computed accurately
1359  if ( extension && anotPos == QgsLayoutItemMapGrid::OutsideMapFrame )
1360  {
1361  extension->UpdateBorder( frameBorder, -f + textWidth );
1362  // We also add a general margin, can be useful for labels near corners
1363  extension->UpdateAll( textWidth / 2.0 );
1364  }
1365 
1366  if ( extension || !context.painter() )
1367  return;
1368 
1369  // Skip outwards facing annotations that are below mRotatedAnnotationsMarginToCorner
1370  bool facingLeft = ( annot.angle < 0 );
1371  bool facingRight = ( annot.angle > 0 );
1372  if ( anotPos == QgsLayoutItemMapGrid::OutsideMapFrame )
1373  {
1374  facingLeft = !facingLeft;
1375  facingRight = !facingRight;
1376  }
1377  if ( annot.border == BorderSide::Top && ( ( facingLeft && annot.position.x() < mRotatedAnnotationsMarginToCorner ) ||
1378  ( facingRight && annot.position.x() > mMap->rect().width() - mRotatedAnnotationsMarginToCorner ) ) )
1379  return;
1380  if ( annot.border == BorderSide::Bottom && ( ( facingLeft && annot.position.x() > mMap->rect().width() - mRotatedAnnotationsMarginToCorner ) ||
1381  ( facingRight && annot.position.x() < mRotatedAnnotationsMarginToCorner ) ) )
1382  return;
1383  if ( annot.border == BorderSide::Left && ( ( facingLeft && annot.position.y() > mMap->rect().height() - mRotatedAnnotationsMarginToCorner ) ||
1384  ( facingRight && annot.position.y() < mRotatedAnnotationsMarginToCorner ) ) )
1385  return;
1386  if ( annot.border == BorderSide::Right && ( ( facingLeft && annot.position.y() < mRotatedAnnotationsMarginToCorner ) ||
1387  ( facingRight && annot.position.y() > mMap->rect().height() - mRotatedAnnotationsMarginToCorner ) ) )
1388  return;
1389 
1390  const QgsScopedQPainterState painterState( context.painter() );
1391  context.painter()->translate( QPointF( xpos, ypos ) );
1392  context.painter()->rotate( rotation );
1393  context.painter()->translate( -anchor );
1394  const QgsScopedRenderContextScaleToPixels scale( context );
1395  QgsTextRenderer::drawText( QPointF( 0, 0 ), 0, QgsTextRenderer::AlignLeft, QStringList() << annotationString, context, mAnnotationFormat );
1396 }
1397 
1398 QString QgsLayoutItemMapGrid::gridAnnotationString( double value, QgsLayoutItemMapGrid::AnnotationCoordinate coord, QgsExpressionContext &expressionContext ) const
1399 {
1400  //check if we are using degrees (ie, geographic crs)
1401  bool geographic = false;
1402  if ( mCRS.isValid() )
1403  {
1404  geographic = mCRS.isGeographic();
1405  }
1406  else if ( mMap && mMap->layout() )
1407  {
1408  geographic = mMap->crs().isGeographic();
1409  }
1410 
1411  if ( geographic && coord == QgsLayoutItemMapGrid::Longitude &&
1412  ( mGridAnnotationFormat == QgsLayoutItemMapGrid::Decimal || mGridAnnotationFormat == QgsLayoutItemMapGrid::DecimalWithSuffix ) )
1413  {
1414  // wrap around longitudes > 180 or < -180 degrees, so that, e.g., "190E" -> "170W"
1415  const double wrappedX = std::fmod( value, 360.0 );
1416  if ( wrappedX > 180.0 )
1417  {
1418  value = wrappedX - 360.0;
1419  }
1420  else if ( wrappedX < -180.0 )
1421  {
1422  value = wrappedX + 360.0;
1423  }
1424  }
1425 
1426  if ( mGridAnnotationFormat == QgsLayoutItemMapGrid::Decimal )
1427  {
1428  return QString::number( value, 'f', mGridAnnotationPrecision );
1429  }
1430  else if ( mGridAnnotationFormat == QgsLayoutItemMapGrid::DecimalWithSuffix )
1431  {
1432  QString hemisphere;
1433 
1434  const double coordRounded = qgsRound( value, mGridAnnotationPrecision );
1435  if ( coord == QgsLayoutItemMapGrid::Longitude )
1436  {
1437  //don't use E/W suffixes if ambiguous (e.g., 180 degrees)
1438  if ( !geographic || ( coordRounded != 180.0 && coordRounded != 0.0 ) )
1439  {
1440  hemisphere = value < 0 ? QObject::tr( "W" ) : QObject::tr( "E" );
1441  }
1442  }
1443  else
1444  {
1445  //don't use N/S suffixes if ambiguous (e.g., 0 degrees)
1446  if ( !geographic || coordRounded != 0.0 )
1447  {
1448  hemisphere = value < 0 ? QObject::tr( "S" ) : QObject::tr( "N" );
1449  }
1450  }
1451  if ( geographic )
1452  {
1453  //insert degree symbol for geographic coordinates
1454  return QString::number( std::fabs( value ), 'f', mGridAnnotationPrecision ) + QChar( 176 ) + hemisphere;
1455  }
1456  else
1457  {
1458  return QString::number( std::fabs( value ), 'f', mGridAnnotationPrecision ) + hemisphere;
1459  }
1460  }
1461  else if ( mGridAnnotationFormat == CustomFormat )
1462  {
1463  expressionContext.lastScope()->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "grid_number" ), value, true ) );
1464  expressionContext.lastScope()->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "grid_axis" ), coord == QgsLayoutItemMapGrid::Longitude ? "x" : "y", true ) );
1465  if ( !mGridAnnotationExpression )
1466  {
1467  mGridAnnotationExpression.reset( new QgsExpression( mGridAnnotationExpressionString ) );
1468  mGridAnnotationExpression->prepare( &expressionContext );
1469  }
1470  return mGridAnnotationExpression->evaluate( &expressionContext ).toString();
1471  }
1472 
1474  QgsCoordinateFormatter::FormatFlags flags = QgsCoordinateFormatter::FormatFlags();
1475  switch ( mGridAnnotationFormat )
1476  {
1477  case Decimal:
1478  case DecimalWithSuffix:
1479  case CustomFormat:
1480  break; // already handled above
1481 
1482  case DegreeMinute:
1485  break;
1486 
1487  case DegreeMinuteSecond:
1490  break;
1491 
1492  case DegreeMinuteNoSuffix:
1494  flags = QgsCoordinateFormatter::FormatFlags();
1495  break;
1496 
1497  case DegreeMinutePadded:
1500  break;
1501 
1504  flags = QgsCoordinateFormatter::FormatFlags();
1505  break;
1506 
1510  break;
1511  }
1512 
1513  switch ( coord )
1514  {
1515  case Longitude:
1516  return QgsCoordinateFormatter::formatX( value, format, mGridAnnotationPrecision, flags );
1517 
1518  case Latitude:
1519  return QgsCoordinateFormatter::formatY( value, format, mGridAnnotationPrecision, flags );
1520  }
1521 
1522  return QString(); // no warnings
1523 }
1524 
1525 int QgsLayoutItemMapGrid::xGridLines() const
1526 {
1527  if ( !mMap || mEvaluatedIntervalY <= 0.0 )
1528  {
1529  return 1;
1530  }
1531 
1532 
1533  QPolygonF mapPolygon = mMap->transformedMapPolygon();
1534  QRectF mapBoundingRect = mapPolygon.boundingRect();
1535  double gridIntervalY = mEvaluatedIntervalY;
1536  double gridOffsetY = mEvaluatedOffsetY;
1537  double annotationScale = 1.0;
1538  switch ( mGridUnit )
1539  {
1540  case CM:
1541  case MM:
1542  {
1543  mapBoundingRect = mMap->rect();
1544  mapPolygon = QPolygonF( mMap->rect() );
1545  if ( mGridUnit == CM )
1546  {
1547  annotationScale = 0.1;
1548  gridIntervalY *= 10;
1549  gridOffsetY *= 10;
1550  }
1551  break;
1552  }
1553 
1554  case MapUnit:
1555  case DynamicPageSizeBased:
1556  break;
1557  }
1558 
1559  //consider to round up to the next step in case the left boundary is > 0
1560  const double roundCorrection = mapBoundingRect.top() > 0 ? 1.0 : 0.0;
1561  double currentLevel = static_cast< int >( ( mapBoundingRect.top() - gridOffsetY ) / gridIntervalY + roundCorrection ) * gridIntervalY + gridOffsetY;
1562 
1563  int gridLineCount = 0;
1564  if ( qgsDoubleNear( mMap->mapRotation(), 0.0 ) || ( mGridUnit != MapUnit && mGridUnit != DynamicPageSizeBased ) )
1565  {
1566  //no rotation. Do it 'the easy way'
1567 
1568  double yCanvasCoord;
1569  while ( currentLevel <= mapBoundingRect.bottom() && gridLineCount < MAX_GRID_LINES )
1570  {
1571  yCanvasCoord = mMap->rect().height() * ( 1 - ( currentLevel - mapBoundingRect.top() ) / mapBoundingRect.height() );
1572  GridLine newLine;
1573  newLine.coordinate = currentLevel * annotationScale;
1574  newLine.coordinateType = AnnotationCoordinate::Latitude;
1575  newLine.line = QPolygonF() << QPointF( 0, yCanvasCoord ) << QPointF( mMap->rect().width(), yCanvasCoord );
1576  mGridLines.append( newLine );
1577  currentLevel += gridIntervalY;
1578  gridLineCount++;
1579  }
1580  return 0;
1581  }
1582 
1583  //the four border lines
1584  QVector<QLineF> borderLines;
1585  borderLines << QLineF( mapPolygon.at( 0 ), mapPolygon.at( 1 ) );
1586  borderLines << QLineF( mapPolygon.at( 1 ), mapPolygon.at( 2 ) );
1587  borderLines << QLineF( mapPolygon.at( 2 ), mapPolygon.at( 3 ) );
1588  borderLines << QLineF( mapPolygon.at( 3 ), mapPolygon.at( 0 ) );
1589 
1590  QVector<QPointF> intersectionList; //intersects between border lines and grid lines
1591 
1592  while ( currentLevel <= mapBoundingRect.bottom() && gridLineCount < MAX_GRID_LINES )
1593  {
1594  intersectionList.clear();
1595  const QLineF gridLine( mapBoundingRect.left(), currentLevel, mapBoundingRect.right(), currentLevel );
1596 
1597  QVector<QLineF>::const_iterator it = borderLines.constBegin();
1598  for ( ; it != borderLines.constEnd(); ++it )
1599  {
1600  QPointF intersectionPoint;
1601 #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
1602  if ( it->intersect( gridLine, &intersectionPoint ) == QLineF::BoundedIntersection )
1603 #else
1604  if ( it->intersects( gridLine, &intersectionPoint ) == QLineF::BoundedIntersection )
1605 #endif
1606  {
1607  intersectionList.push_back( intersectionPoint );
1608  if ( intersectionList.size() >= 2 )
1609  {
1610  break; //we already have two intersections, skip further tests
1611  }
1612  }
1613  }
1614 
1615  if ( intersectionList.size() >= 2 )
1616  {
1617  GridLine newLine;
1618  newLine.coordinate = currentLevel;
1619  newLine.coordinateType = AnnotationCoordinate::Latitude;
1620  newLine.line = QPolygonF() << mMap->mapToItemCoords( intersectionList.at( 0 ) ) << mMap->mapToItemCoords( intersectionList.at( 1 ) );
1621  mGridLines.append( newLine );
1622  gridLineCount++;
1623  }
1624  currentLevel += gridIntervalY;
1625  }
1626 
1627 
1628  return 0;
1629 }
1630 
1631 int QgsLayoutItemMapGrid::yGridLines() const
1632 {
1633  if ( !mMap || mEvaluatedIntervalX <= 0.0 )
1634  {
1635  return 1;
1636  }
1637 
1638  QPolygonF mapPolygon = mMap->transformedMapPolygon();
1639  QRectF mapBoundingRect = mapPolygon.boundingRect();
1640  double gridIntervalX = mEvaluatedIntervalX;
1641  double gridOffsetX = mEvaluatedOffsetX;
1642  double annotationScale = 1.0;
1643  switch ( mGridUnit )
1644  {
1645  case CM:
1646  case MM:
1647  {
1648  mapBoundingRect = mMap->rect();
1649  mapPolygon = QPolygonF( mMap->rect() );
1650  if ( mGridUnit == CM )
1651  {
1652  annotationScale = 0.1;
1653  gridIntervalX *= 10;
1654  gridOffsetX *= 10;
1655  }
1656  break;
1657  }
1658 
1659  case MapUnit:
1660  case DynamicPageSizeBased:
1661  break;
1662  }
1663 
1664  //consider to round up to the next step in case the left boundary is > 0
1665  const double roundCorrection = mapBoundingRect.left() > 0 ? 1.0 : 0.0;
1666  double currentLevel = static_cast< int >( ( mapBoundingRect.left() - gridOffsetX ) / gridIntervalX + roundCorrection ) * gridIntervalX + gridOffsetX;
1667 
1668  int gridLineCount = 0;
1669  if ( qgsDoubleNear( mMap->mapRotation(), 0.0 ) || ( mGridUnit != MapUnit && mGridUnit != DynamicPageSizeBased ) )
1670  {
1671  //no rotation. Do it 'the easy way'
1672  double xCanvasCoord;
1673  while ( currentLevel <= mapBoundingRect.right() && gridLineCount < MAX_GRID_LINES )
1674  {
1675  xCanvasCoord = mMap->rect().width() * ( currentLevel - mapBoundingRect.left() ) / mapBoundingRect.width();
1676 
1677  GridLine newLine;
1678  newLine.coordinate = currentLevel * annotationScale;
1679  newLine.coordinateType = AnnotationCoordinate::Longitude;
1680  newLine.line = QPolygonF() << QPointF( xCanvasCoord, 0 ) << QPointF( xCanvasCoord, mMap->rect().height() );
1681  mGridLines.append( newLine );
1682  currentLevel += gridIntervalX;
1683  gridLineCount++;
1684  }
1685  return 0;
1686  }
1687 
1688  //the four border lines
1689  QVector<QLineF> borderLines;
1690  borderLines << QLineF( mapPolygon.at( 0 ), mapPolygon.at( 1 ) );
1691  borderLines << QLineF( mapPolygon.at( 1 ), mapPolygon.at( 2 ) );
1692  borderLines << QLineF( mapPolygon.at( 2 ), mapPolygon.at( 3 ) );
1693  borderLines << QLineF( mapPolygon.at( 3 ), mapPolygon.at( 0 ) );
1694 
1695  QVector<QPointF> intersectionList; //intersects between border lines and grid lines
1696 
1697  while ( currentLevel <= mapBoundingRect.right() && gridLineCount < MAX_GRID_LINES )
1698  {
1699  intersectionList.clear();
1700  const QLineF gridLine( currentLevel, mapBoundingRect.bottom(), currentLevel, mapBoundingRect.top() );
1701 
1702  QVector<QLineF>::const_iterator it = borderLines.constBegin();
1703  for ( ; it != borderLines.constEnd(); ++it )
1704  {
1705  QPointF intersectionPoint;
1706 #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
1707  if ( it->intersect( gridLine, &intersectionPoint ) == QLineF::BoundedIntersection )
1708 #else
1709  if ( it->intersects( gridLine, &intersectionPoint ) == QLineF::BoundedIntersection )
1710 #endif
1711  {
1712  intersectionList.push_back( intersectionPoint );
1713  if ( intersectionList.size() >= 2 )
1714  {
1715  break; //we already have two intersections, skip further tests
1716  }
1717  }
1718  }
1719 
1720  if ( intersectionList.size() >= 2 )
1721  {
1722  GridLine newLine;
1723  newLine.coordinate = currentLevel;
1724  newLine.coordinateType = AnnotationCoordinate::Longitude;
1725  newLine.line = QPolygonF() << mMap->mapToItemCoords( intersectionList.at( 0 ) ) << mMap->mapToItemCoords( intersectionList.at( 1 ) );
1726  mGridLines.append( newLine );
1727  gridLineCount++;
1728  }
1729  currentLevel += gridIntervalX;
1730  }
1731 
1732  return 0;
1733 }
1734 
1735 int QgsLayoutItemMapGrid::xGridLinesCrsTransform( const QgsRectangle &bbox, const QgsCoordinateTransform &t ) const
1736 {
1737  if ( !mMap || mEvaluatedIntervalY <= 0.0 )
1738  {
1739  return 1;
1740  }
1741 
1742  const double roundCorrection = bbox.yMaximum() > 0 ? 1.0 : 0.0;
1743  double currentLevel = static_cast< int >( ( bbox.yMaximum() - mEvaluatedOffsetY ) / mEvaluatedIntervalY + roundCorrection ) * mEvaluatedIntervalY + mEvaluatedOffsetY;
1744 
1745  const double minX = bbox.xMinimum();
1746  const double maxX = bbox.xMaximum();
1747  double step = ( maxX - minX ) / 20;
1748 
1749  bool crosses180 = false;
1750  bool crossed180 = false;
1751  if ( mCRS.isGeographic() && ( minX > maxX ) )
1752  {
1753  //handle 180 degree longitude crossover
1754  crosses180 = true;
1755  step = ( maxX + 360.0 - minX ) / 20;
1756  }
1757 
1758  if ( qgsDoubleNear( step, 0.0 ) )
1759  return 1;
1760 
1761  int gridLineCount = 0;
1762  while ( currentLevel >= bbox.yMinimum() && gridLineCount < MAX_GRID_LINES )
1763  {
1764  QPolygonF gridLine;
1765  double currentX = minX;
1766  bool cont = true;
1767  while ( cont )
1768  {
1769  if ( ( !crosses180 || crossed180 ) && ( currentX > maxX ) )
1770  {
1771  cont = false;
1772  }
1773 
1774  try
1775  {
1776  const QgsPointXY mapPoint = t.transform( currentX, currentLevel ); //transform back to map crs
1777  gridLine.append( mMap->mapToItemCoords( QPointF( mapPoint.x(), mapPoint.y() ) ) ); //transform back to composer coords
1778  }
1779  catch ( QgsCsException &cse )
1780  {
1781  Q_UNUSED( cse )
1782  QgsDebugMsg( QStringLiteral( "Caught CRS exception %1" ).arg( cse.what() ) );
1783  }
1784 
1785  currentX += step;
1786  if ( crosses180 && currentX > 180.0 )
1787  {
1788  currentX -= 360.0;
1789  crossed180 = true;
1790  }
1791  }
1792  crossed180 = false;
1793 
1794  const QList<QPolygonF> lineSegments = trimLinesToMap( gridLine, QgsRectangle( mMap->rect() ) );
1795  QList<QPolygonF>::const_iterator lineIt = lineSegments.constBegin();
1796  for ( ; lineIt != lineSegments.constEnd(); ++lineIt )
1797  {
1798  if ( !( *lineIt ).isEmpty() )
1799  {
1800  GridLine newLine;
1801  newLine.coordinate = currentLevel;
1802  newLine.coordinateType = AnnotationCoordinate::Latitude;
1803  newLine.line = QPolygonF( *lineIt );
1804  mGridLines.append( newLine );
1805  gridLineCount++;
1806  }
1807  }
1808  currentLevel -= mEvaluatedIntervalY;
1809  }
1810 
1811  return 0;
1812 }
1813 
1814 int QgsLayoutItemMapGrid::yGridLinesCrsTransform( const QgsRectangle &bbox, const QgsCoordinateTransform &t ) const
1815 {
1816  if ( !mMap || mEvaluatedIntervalX <= 0.0 )
1817  {
1818  return 1;
1819  }
1820 
1821  const double roundCorrection = bbox.xMinimum() > 0 ? 1.0 : 0.0;
1822  double currentLevel = static_cast< int >( ( bbox.xMinimum() - mEvaluatedOffsetX ) / mEvaluatedIntervalX + roundCorrection ) * mEvaluatedIntervalX + mEvaluatedOffsetX;
1823 
1824  const double minY = bbox.yMinimum();
1825  const double maxY = bbox.yMaximum();
1826  const double step = ( maxY - minY ) / 20;
1827 
1828  if ( qgsDoubleNear( step, 0.0 ) )
1829  return 1;
1830 
1831  bool crosses180 = false;
1832  bool crossed180 = false;
1833  if ( mCRS.isGeographic() && ( bbox.xMinimum() > bbox.xMaximum() ) )
1834  {
1835  //handle 180 degree longitude crossover
1836  crosses180 = true;
1837  }
1838 
1839  int gridLineCount = 0;
1840  while ( ( currentLevel <= bbox.xMaximum() || ( crosses180 && !crossed180 ) ) && gridLineCount < MAX_GRID_LINES )
1841  {
1842  QPolygonF gridLine;
1843  double currentY = minY;
1844  bool cont = true;
1845  while ( cont )
1846  {
1847  if ( currentY > maxY )
1848  {
1849  cont = false;
1850  }
1851  try
1852  {
1853  //transform back to map crs
1854  const QgsPointXY mapPoint = t.transform( currentLevel, currentY );
1855  //transform back to composer coords
1856  gridLine.append( mMap->mapToItemCoords( QPointF( mapPoint.x(), mapPoint.y() ) ) );
1857  }
1858  catch ( QgsCsException &cse )
1859  {
1860  Q_UNUSED( cse )
1861  QgsDebugMsg( QStringLiteral( "Caught CRS exception %1" ).arg( cse.what() ) );
1862  }
1863 
1864  currentY += step;
1865  }
1866  //clip grid line to map polygon
1867  const QList<QPolygonF> lineSegments = trimLinesToMap( gridLine, QgsRectangle( mMap->rect() ) );
1868  QList<QPolygonF>::const_iterator lineIt = lineSegments.constBegin();
1869  for ( ; lineIt != lineSegments.constEnd(); ++lineIt )
1870  {
1871  if ( !( *lineIt ).isEmpty() )
1872  {
1873  GridLine newLine;
1874  newLine.coordinate = currentLevel;
1875  newLine.coordinateType = AnnotationCoordinate::Longitude;
1876  newLine.line = QPolygonF( *lineIt );
1877  mGridLines.append( newLine );
1878  gridLineCount++;
1879  }
1880  }
1881  currentLevel += mEvaluatedIntervalX;
1882  if ( crosses180 && currentLevel > 180.0 )
1883  {
1884  currentLevel -= 360.0;
1885  crossed180 = true;
1886  }
1887  }
1888 
1889  return 0;
1890 }
1891 
1892 bool QgsLayoutItemMapGrid::shouldShowDivisionForSide( QgsLayoutItemMapGrid::AnnotationCoordinate coordinate, QgsLayoutItemMapGrid::BorderSide side ) const
1893 {
1894  switch ( side )
1895  {
1897  return testFrameSideFlag( QgsLayoutItemMapGrid::FrameLeft ) && shouldShowForDisplayMode( coordinate, mEvaluatedLeftFrameDivisions );
1899  return testFrameSideFlag( QgsLayoutItemMapGrid::FrameRight ) && shouldShowForDisplayMode( coordinate, mEvaluatedRightFrameDivisions );
1901  return testFrameSideFlag( QgsLayoutItemMapGrid::FrameTop ) && shouldShowForDisplayMode( coordinate, mEvaluatedTopFrameDivisions );
1903  return testFrameSideFlag( QgsLayoutItemMapGrid::FrameBottom ) && shouldShowForDisplayMode( coordinate, mEvaluatedBottomFrameDivisions );
1904  }
1905  return false; // no warnings
1906 }
1907 
1908 bool QgsLayoutItemMapGrid::shouldShowAnnotationForSide( QgsLayoutItemMapGrid::AnnotationCoordinate coordinate, QgsLayoutItemMapGrid::BorderSide side ) const
1909 {
1910  switch ( side )
1911  {
1913  return shouldShowForDisplayMode( coordinate, mEvaluatedLeftGridAnnotationDisplay );
1915  return shouldShowForDisplayMode( coordinate, mEvaluatedRightGridAnnotationDisplay );
1917  return shouldShowForDisplayMode( coordinate, mEvaluatedTopGridAnnotationDisplay );
1919  return shouldShowForDisplayMode( coordinate, mEvaluatedBottomGridAnnotationDisplay );
1920  }
1921  return false; // no warnings
1922 }
1923 
1924 bool QgsLayoutItemMapGrid::shouldShowForDisplayMode( QgsLayoutItemMapGrid::AnnotationCoordinate coordinate, QgsLayoutItemMapGrid::DisplayMode mode ) const
1925 {
1926  return mode == QgsLayoutItemMapGrid::ShowAll
1929 }
1930 
1931 
1933 {
1934  if ( ddValue.compare( QLatin1String( "x_only" ), Qt::CaseInsensitive ) == 0 )
1936  else if ( ddValue.compare( QLatin1String( "y_only" ), Qt::CaseInsensitive ) == 0 )
1938  else if ( ddValue.compare( QLatin1String( "disabled" ), Qt::CaseInsensitive ) == 0 )
1940  else if ( ddValue.compare( QLatin1String( "all" ), Qt::CaseInsensitive ) == 0 )
1942  else
1943  return defValue;
1944 }
1945 
1946 
1947 void QgsLayoutItemMapGrid::refreshDataDefinedProperties()
1948 {
1950 
1951  // if we are changing the grid interval or offset, then we also have to mark the transform as dirty
1952  mTransformDirty = mTransformDirty
1957 
1959  switch ( mGridUnit )
1960  {
1961  case MapUnit:
1962  case MM:
1963  case CM:
1964  {
1965  mEvaluatedIntervalX = mDataDefinedProperties.valueAsDouble( QgsLayoutObject::MapGridIntervalX, context, mGridIntervalX );
1966  mEvaluatedIntervalY = mDataDefinedProperties.valueAsDouble( QgsLayoutObject::MapGridIntervalY, context, mGridIntervalY );
1967  break;
1968  }
1969 
1970  case DynamicPageSizeBased:
1971  {
1972  if ( mMaximumIntervalWidth < mMinimumIntervalWidth )
1973  {
1974  mEvaluatedEnabled = false;
1975  }
1976  else
1977  {
1978  const double mapWidthMm = mLayout->renderContext().measurementConverter().convert( mMap->sizeWithUnits(), QgsUnitTypes::LayoutMillimeters ).width();
1979  const double mapWidthMapUnits = mapWidth();
1980  const double minUnitsPerSeg = ( mMinimumIntervalWidth * mapWidthMapUnits ) / mapWidthMm;
1981  const double maxUnitsPerSeg = ( mMaximumIntervalWidth * mapWidthMapUnits ) / mapWidthMm;
1982  const double interval = QgsLayoutUtils::calculatePrettySize( minUnitsPerSeg, maxUnitsPerSeg );
1983  mEvaluatedIntervalX = interval;
1984  mEvaluatedIntervalY = interval;
1985  mTransformDirty = true;
1986  }
1987  break;
1988  }
1989  }
1990  mEvaluatedOffsetX = mDataDefinedProperties.valueAsDouble( QgsLayoutObject::MapGridOffsetX, context, mGridOffsetX );
1991  mEvaluatedOffsetY = mDataDefinedProperties.valueAsDouble( QgsLayoutObject::MapGridOffsetY, context, mGridOffsetY );
1992  mEvaluatedGridFrameWidth = mDataDefinedProperties.valueAsDouble( QgsLayoutObject::MapGridFrameSize, context, mGridFrameWidth );
1993  mEvaluatedGridFrameMargin = mDataDefinedProperties.valueAsDouble( QgsLayoutObject::MapGridFrameMargin, context, mGridFrameMargin );
1994  mEvaluatedAnnotationFrameDistance = mDataDefinedProperties.valueAsDouble( QgsLayoutObject::MapGridLabelDistance, context, mAnnotationFrameDistance );
1995  mEvaluatedCrossLength = mDataDefinedProperties.valueAsDouble( QgsLayoutObject::MapGridCrossSize, context, mCrossLength );
1996  mEvaluatedGridFrameLineThickness = mDataDefinedProperties.valueAsDouble( QgsLayoutObject::MapGridFrameLineThickness, context, mGridFramePenThickness );
1997  mEvaluatedLeftGridAnnotationDisplay = gridAnnotationDisplayModeFromDD( mDataDefinedProperties.valueAsString( QgsLayoutObject::MapGridAnnotationDisplayLeft, context ), mLeftGridAnnotationDisplay );
1998  mEvaluatedRightGridAnnotationDisplay = gridAnnotationDisplayModeFromDD( mDataDefinedProperties.valueAsString( QgsLayoutObject::MapGridAnnotationDisplayRight, context ), mRightGridAnnotationDisplay );
1999  mEvaluatedTopGridAnnotationDisplay = gridAnnotationDisplayModeFromDD( mDataDefinedProperties.valueAsString( QgsLayoutObject::MapGridAnnotationDisplayTop, context ), mTopGridAnnotationDisplay );
2000  mEvaluatedBottomGridAnnotationDisplay = gridAnnotationDisplayModeFromDD( mDataDefinedProperties.valueAsString( QgsLayoutObject::MapGridAnnotationDisplayBottom, context ), mBottomGridAnnotationDisplay );
2001  mEvaluatedLeftFrameDivisions = gridAnnotationDisplayModeFromDD( mDataDefinedProperties.valueAsString( QgsLayoutObject::MapGridFrameDivisionsLeft, context ), mLeftFrameDivisions );
2002  mEvaluatedRightFrameDivisions = gridAnnotationDisplayModeFromDD( mDataDefinedProperties.valueAsString( QgsLayoutObject::MapGridFrameDivisionsRight, context ), mRightFrameDivisions );
2003  mEvaluatedTopFrameDivisions = gridAnnotationDisplayModeFromDD( mDataDefinedProperties.valueAsString( QgsLayoutObject::MapGridFrameDivisionsTop, context ), mTopFrameDivisions );
2004  mEvaluatedBottomFrameDivisions = gridAnnotationDisplayModeFromDD( mDataDefinedProperties.valueAsString( QgsLayoutObject::MapGridFrameDivisionsBottom, context ), mBottomFrameDivisions );
2005 
2006 }
2007 
2008 double QgsLayoutItemMapGrid::mapWidth() const
2009 {
2010  if ( !mMap )
2011  {
2012  return 0.0;
2013  }
2014 
2015  const QgsRectangle mapExtent = mMap->extent();
2016  const QgsUnitTypes::DistanceUnit distanceUnit = mCRS.isValid() ? mCRS.mapUnits() : mMap->crs().mapUnits();
2017  if ( distanceUnit == QgsUnitTypes::DistanceUnknownUnit )
2018  {
2019  return mapExtent.width();
2020  }
2021  else
2022  {
2023  QgsDistanceArea da;
2024 
2025  da.setSourceCrs( mMap->crs(), mLayout->project()->transformContext() );
2026  da.setEllipsoid( mLayout->project()->ellipsoid() );
2027 
2029  double measure = da.measureLine( QgsPointXY( mapExtent.xMinimum(), mapExtent.yMinimum() ),
2030  QgsPointXY( mapExtent.xMaximum(), mapExtent.yMinimum() ) );
2031  measure /= QgsUnitTypes::fromUnitToUnitFactor( distanceUnit, units );
2032  return measure;
2033  }
2034 }
2035 
2036 bool sortByDistance( QPair<qreal, QgsLayoutItemMapGrid::BorderSide> a, QPair<qreal, QgsLayoutItemMapGrid::BorderSide> b )
2037 {
2038  return a.first < b.first;
2039 }
2040 
2041 QgsLayoutItemMapGrid::BorderSide QgsLayoutItemMapGrid::borderForLineCoord( QPointF p, const AnnotationCoordinate coordinateType ) const
2042 {
2043  if ( !mMap )
2044  {
2046  }
2047 
2048  const double tolerance = std::max( mMap->frameEnabled() ? mMap->pen().widthF() : 0.0, 1.0 );
2049 
2050  //check for corner coordinates
2051  if ( ( p.y() <= tolerance && p.x() <= tolerance ) // top left
2052  || ( p.y() <= tolerance && p.x() >= ( mMap->rect().width() - tolerance ) ) //top right
2053  || ( p.y() >= ( mMap->rect().height() - tolerance ) && p.x() <= tolerance ) //bottom left
2054  || ( p.y() >= ( mMap->rect().height() - tolerance ) && p.x() >= ( mMap->rect().width() - tolerance ) ) //bottom right
2055  )
2056  {
2057  //coordinate is in corner - fall back to preferred side for coordinate type
2058  if ( coordinateType == QgsLayoutItemMapGrid::Latitude )
2059  {
2060  if ( p.x() <= tolerance )
2061  {
2063  }
2064  else
2065  {
2067  }
2068  }
2069  else
2070  {
2071  if ( p.y() <= tolerance )
2072  {
2074  }
2075  else
2076  {
2078  }
2079  }
2080  }
2081 
2082  //otherwise, guess side based on closest map side to point
2083  QList< QPair<qreal, QgsLayoutItemMapGrid::BorderSide > > distanceToSide;
2084  distanceToSide << qMakePair( p.x(), QgsLayoutItemMapGrid::Left );
2085  distanceToSide << qMakePair( mMap->rect().width() - p.x(), QgsLayoutItemMapGrid::Right );
2086  distanceToSide << qMakePair( p.y(), QgsLayoutItemMapGrid::Top );
2087  distanceToSide << qMakePair( mMap->rect().height() - p.y(), QgsLayoutItemMapGrid::Bottom );
2088 
2089  std::sort( distanceToSide.begin(), distanceToSide.end(), sortByDistance );
2090  return distanceToSide.at( 0 ).second;
2091 }
2092 
2094 {
2095  mGridLineSymbol.reset( symbol );
2096 }
2097 
2099 {
2100  return mGridLineSymbol.get();
2101 }
2102 
2104 {
2105  return mGridLineSymbol.get();
2106 }
2107 
2109 {
2110  mGridMarkerSymbol.reset( symbol );
2111 }
2112 
2114 {
2115  return mGridMarkerSymbol.get();
2116 }
2117 
2119 {
2120  return mGridMarkerSymbol.get();
2121 }
2122 
2124 {
2125  mAnnotationFormat.setFont( font );
2126  if ( font.pointSizeF() > 0 )
2127  {
2128  mAnnotationFormat.setSize( font.pointSizeF() );
2129  mAnnotationFormat.setSizeUnit( QgsUnitTypes::RenderPoints );
2130  }
2131  else if ( font.pixelSize() > 0 )
2132  {
2133  mAnnotationFormat.setSize( font.pixelSize() );
2134  mAnnotationFormat.setSizeUnit( QgsUnitTypes::RenderPixels );
2135  }
2136 }
2137 
2139 {
2140  return mAnnotationFormat.toQFont();
2141 }
2142 
2144 {
2145  mAnnotationFormat.setColor( color );
2146 }
2147 
2149 {
2150  return mAnnotationFormat.color();
2151 }
2152 
2154 {
2155  switch ( border )
2156  {
2158  mLeftGridAnnotationDisplay = display;
2159  break;
2161  mRightGridAnnotationDisplay = display;
2162  break;
2164  mTopGridAnnotationDisplay = display;
2165  break;
2167  mBottomGridAnnotationDisplay = display;
2168  break;
2169  }
2170 
2171  refreshDataDefinedProperties();
2172 
2173  if ( mMap )
2174  {
2176  mMap->update();
2177  }
2178 }
2179 
2181 {
2182  switch ( border )
2183  {
2185  return mLeftGridAnnotationDisplay;
2187  return mRightGridAnnotationDisplay;
2189  return mTopGridAnnotationDisplay;
2191  return mBottomGridAnnotationDisplay;
2192  }
2193  return mBottomGridAnnotationDisplay; // no warnings
2194 }
2195 
2197 {
2198  double top = 0.0;
2199  double right = 0.0;
2200  double bottom = 0.0;
2201  double left = 0.0;
2202  calculateMaxExtension( top, right, bottom, left );
2203  return std::max( std::max( std::max( top, right ), bottom ), left );
2204 }
2205 
2206 void QgsLayoutItemMapGrid::calculateMaxExtension( double &top, double &right, double &bottom, double &left ) const
2207 {
2208  top = 0.0;
2209  right = 0.0;
2210  bottom = 0.0;
2211  left = 0.0;
2212 
2213  if ( !mMap || !mEvaluatedEnabled )
2214  {
2215  return;
2216  }
2217 
2218  //setup render context
2220  const QgsExpressionContext expressionContext = createExpressionContext();
2221  context.setExpressionContext( expressionContext );
2222 
2223  GridExtension extension;
2224 
2225  //collect grid lines
2226  switch ( mGridUnit )
2227  {
2228  case MapUnit:
2229  case DynamicPageSizeBased:
2230  {
2231  if ( mCRS.isValid() && mCRS != mMap->crs() )
2232  {
2233  drawGridCrsTransform( context, 0, true );
2234  break;
2235  }
2236  }
2237  FALLTHROUGH
2238  case CM:
2239  case MM:
2240  drawGridNoTransform( context, 0, true );
2241  break;
2242  }
2243 
2244  if ( mGridFrameStyle != QgsLayoutItemMapGrid::NoFrame || mShowGridAnnotation )
2245  updateGridLinesAnnotationsPositions();
2246 
2247  if ( mGridFrameStyle != QgsLayoutItemMapGrid::NoFrame )
2248  {
2249  drawGridFrame( nullptr, &extension );
2250  }
2251 
2252  if ( mShowGridAnnotation )
2253  {
2254  drawCoordinateAnnotations( context, context.expressionContext(), &extension );
2255  }
2256 
2257  top = extension.top;
2258  right = extension.right;
2259  bottom = extension.bottom;
2260  left = extension.left;
2261 }
2262 
2264 {
2266  refreshDataDefinedProperties();
2267 }
2268 
2270 {
2271  if ( unit == mGridUnit )
2272  {
2273  return;
2274  }
2275  mGridUnit = unit;
2276  mTransformDirty = true;
2277 }
2278 
2279 void QgsLayoutItemMapGrid::setIntervalX( const double interval )
2280 {
2281  if ( qgsDoubleNear( interval, mGridIntervalX ) )
2282  {
2283  return;
2284  }
2285  mGridIntervalX = interval;
2286  mTransformDirty = true;
2287  refreshDataDefinedProperties();
2288 }
2289 
2290 void QgsLayoutItemMapGrid::setIntervalY( const double interval )
2291 {
2292  if ( qgsDoubleNear( interval, mGridIntervalY ) )
2293  {
2294  return;
2295  }
2296  mGridIntervalY = interval;
2297  mTransformDirty = true;
2298  refreshDataDefinedProperties();
2299 }
2300 
2301 void QgsLayoutItemMapGrid::setOffsetX( const double offset )
2302 {
2303  if ( qgsDoubleNear( offset, mGridOffsetX ) )
2304  {
2305  return;
2306  }
2307  mGridOffsetX = offset;
2308  mTransformDirty = true;
2309  refreshDataDefinedProperties();
2310 }
2311 
2312 void QgsLayoutItemMapGrid::setOffsetY( const double offset )
2313 {
2314  if ( qgsDoubleNear( offset, mGridOffsetY ) )
2315  {
2316  return;
2317  }
2318  mGridOffsetY = offset;
2319  mTransformDirty = true;
2320  refreshDataDefinedProperties();
2321 }
2322 
2324 {
2325  if ( qgsDoubleNear( minWidth, mMinimumIntervalWidth ) )
2326  {
2327  return;
2328  }
2329  mMinimumIntervalWidth = minWidth;
2330  mTransformDirty = true;
2331  refreshDataDefinedProperties();
2332 }
2333 
2335 {
2336  if ( qgsDoubleNear( maxWidth, mMaximumIntervalWidth ) )
2337  {
2338  return;
2339  }
2340  mMaximumIntervalWidth = maxWidth;
2341  mTransformDirty = true;
2342  refreshDataDefinedProperties();
2343 }
2344 
2346 {
2347  if ( style == mGridStyle )
2348  {
2349  return;
2350  }
2351  mGridStyle = style;
2352  mTransformDirty = true;
2353 }
2354 
2355 void QgsLayoutItemMapGrid::setCrossLength( const double length )
2356 {
2357  mCrossLength = length;
2358  refreshDataDefinedProperties();
2359 }
2360 
2362 {
2363  switch ( border )
2364  {
2366  mLeftGridAnnotationDirection = direction;
2367  break;
2369  mRightGridAnnotationDirection = direction;
2370  break;
2372  mTopGridAnnotationDirection = direction;
2373  break;
2375  mBottomGridAnnotationDirection = direction;
2376  break;
2377  }
2378 
2379  if ( mMap )
2380  {
2382  mMap->update();
2383  }
2384 }
2385 
2386 void QgsLayoutItemMapGrid::setFrameSideFlags( FrameSideFlags flags )
2387 {
2388  mGridFrameSides = flags;
2389 }
2390 
2392 {
2393  if ( on )
2394  mGridFrameSides |= flag;
2395  else
2396  mGridFrameSides &= ~flag;
2397 }
2398 
2399 QgsLayoutItemMapGrid::FrameSideFlags QgsLayoutItemMapGrid::frameSideFlags() const
2400 {
2401  return mGridFrameSides;
2402 }
2403 
2405 {
2407  context.appendScope( new QgsExpressionContextScope( tr( "Grid" ) ) );
2408  context.lastScope()->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "grid_number" ), 0, true ) );
2409  context.lastScope()->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "grid_axis" ), "x", true ) );
2410  context.setHighlightedVariables( QStringList() << QStringLiteral( "grid_number" ) << QStringLiteral( "grid_axis" ) );
2411  return context;
2412 }
2413 
2415 {
2416  if ( mGridLineSymbol )
2417  {
2418  QgsStyleSymbolEntity entity( mGridLineSymbol.get() );
2419  if ( !visitor->visit( QgsStyleEntityVisitorInterface::StyleLeaf( &entity, QStringLiteral( "grid" ), QObject::tr( "Grid" ) ) ) )
2420  return false;
2421  }
2422  if ( mGridMarkerSymbol )
2423  {
2424  QgsStyleSymbolEntity entity( mGridMarkerSymbol.get() );
2425  if ( !visitor->visit( QgsStyleEntityVisitorInterface::StyleLeaf( &entity, QStringLiteral( "grid" ), QObject::tr( "Grid" ) ) ) )
2426  return false;
2427  }
2428 
2429  return true;
2430 }
2431 
2433 {
2434  mTransformDirty = true;
2435  refreshDataDefinedProperties();
2437  mMap->update();
2438 }
2439 
2441 {
2442  return mGridFrameSides.testFlag( flag );
2443 }
2444 
2445 void QgsLayoutItemMapGrid::setFrameWidth( const double width )
2446 {
2447  mGridFrameWidth = width;
2448  refreshDataDefinedProperties();
2449 }
2450 
2451 void QgsLayoutItemMapGrid::setFrameMargin( const double margin )
2452 {
2453  mGridFrameMargin = margin;
2454  refreshDataDefinedProperties();
2455 }
2456 
2457 void QgsLayoutItemMapGrid::setFramePenSize( const double width )
2458 {
2459  mGridFramePenThickness = width;
2460  refreshDataDefinedProperties();
2461 }
2462 
2464 {
2465  mLeftGridAnnotationDirection = direction;
2466  mRightGridAnnotationDirection = direction;
2467  mTopGridAnnotationDirection = direction;
2468  mBottomGridAnnotationDirection = direction;
2469 }
2470 
2472 {
2473  switch ( border )
2474  {
2476  mLeftGridAnnotationPosition = position;
2477  break;
2479  mRightGridAnnotationPosition = position;
2480  break;
2482  mTopGridAnnotationPosition = position;
2483  break;
2485  mBottomGridAnnotationPosition = position;
2486  break;
2487  }
2488 
2489  if ( mMap )
2490  {
2492  mMap->update();
2493  }
2494 }
2495 
2497 {
2498  switch ( border )
2499  {
2501  return mLeftGridAnnotationPosition;
2503  return mRightGridAnnotationPosition;
2505  return mTopGridAnnotationPosition;
2507  return mBottomGridAnnotationPosition;
2508  }
2509  return mLeftGridAnnotationPosition; // no warnings
2510 }
2511 
2513 {
2514  mAnnotationFrameDistance = distance;
2515  refreshDataDefinedProperties();
2516 }
2517 
2519 {
2520  if ( !mMap )
2521  {
2522  return mLeftGridAnnotationDirection;
2523  }
2524 
2525  switch ( border )
2526  {
2528  return mLeftGridAnnotationDirection;
2530  return mRightGridAnnotationDirection;
2532  return mTopGridAnnotationDirection;
2534  return mBottomGridAnnotationDirection;
2535  }
2536  return mLeftGridAnnotationDirection; // no warnings
2537 }
2538 
2540 {
2541  switch ( border )
2542  {
2544  mLeftFrameDivisions = divisions;
2545  break;
2547  mRightFrameDivisions = divisions;
2548  break;
2550  mTopFrameDivisions = divisions;
2551  break;
2553  mBottomFrameDivisions = divisions;
2554  break;
2555  }
2556 
2557  refreshDataDefinedProperties();
2558 
2559  if ( mMap )
2560  {
2561  mMap->update();
2562  }
2563 }
2564 
2566 {
2567  switch ( border )
2568  {
2570  return mLeftFrameDivisions;
2572  return mRightFrameDivisions;
2574  return mTopFrameDivisions;
2576  return mBottomFrameDivisions;
2577  }
2578  return mLeftFrameDivisions; // no warnings
2579 }
2580 
2581 int QgsLayoutItemMapGrid::crsGridParams( QgsRectangle &crsRect, QgsCoordinateTransform &inverseTransform ) const
2582 {
2583  if ( !mMap )
2584  {
2585  return 1;
2586  }
2587 
2588  try
2589  {
2590  const QgsCoordinateTransform tr( mMap->crs(), mCRS, mLayout->project() );
2591  QgsCoordinateTransform extentTransform = tr;
2592  extentTransform.setBallparkTransformsAreAppropriate( true );
2593  const QPolygonF mapPolygon = mMap->transformedMapPolygon();
2594  const QRectF mbr = mapPolygon.boundingRect();
2595  const QgsRectangle mapBoundingRect( mbr.left(), mbr.bottom(), mbr.right(), mbr.top() );
2596 
2597 
2598  if ( mCRS.isGeographic() )
2599  {
2600  //handle crossing the 180 degree longitude line
2601  QgsPointXY lowerLeft( mapBoundingRect.xMinimum(), mapBoundingRect.yMinimum() );
2602  QgsPointXY upperRight( mapBoundingRect.xMaximum(), mapBoundingRect.yMaximum() );
2603 
2604  lowerLeft = tr.transform( lowerLeft.x(), lowerLeft.y() );
2605  upperRight = tr.transform( upperRight.x(), upperRight.y() );
2606 
2607  if ( lowerLeft.x() > upperRight.x() )
2608  {
2609  //we've crossed the line
2610  crsRect = extentTransform.transformBoundingBox( mapBoundingRect, Qgis::TransformDirection::Forward, true );
2611  }
2612  else
2613  {
2614  //didn't cross the line
2615  crsRect = extentTransform.transformBoundingBox( mapBoundingRect );
2616  }
2617  }
2618  else
2619  {
2620  crsRect = extentTransform.transformBoundingBox( mapBoundingRect );
2621  }
2622 
2623  inverseTransform = QgsCoordinateTransform( mCRS, mMap->crs(), mLayout->project() );
2624  }
2625  catch ( QgsCsException &cse )
2626  {
2627  Q_UNUSED( cse )
2628  QgsDebugMsg( QStringLiteral( "Caught CRS exception %1" ).arg( cse.what() ) );
2629  return 1;
2630  }
2631  return 0;
2632 }
2633 
2634 QList<QPolygonF> QgsLayoutItemMapGrid::trimLinesToMap( const QPolygonF &line, const QgsRectangle &rect )
2635 {
2636  const QgsGeometry lineGeom = QgsGeometry::fromQPolygonF( line );
2637  const QgsGeometry rectGeom = QgsGeometry::fromRect( rect );
2638 
2639  const QgsGeometry intersected = lineGeom.intersection( rectGeom );
2640  const QVector<QgsGeometry> intersectedParts = intersected.asGeometryCollection();
2641 
2642  QList<QPolygonF> trimmedLines;
2643  QVector<QgsGeometry>::const_iterator geomIt = intersectedParts.constBegin();
2644  for ( ; geomIt != intersectedParts.constEnd(); ++geomIt )
2645  {
2646  trimmedLines << ( *geomIt ).asQPolygonF();
2647  }
2648  return trimmedLines;
2649 }
QgsLayoutItemMapGrid::TickLengthMode
TickLengthMode
Tick length mode (useful for rotated grids)
Definition: qgslayoutitemmapgrid.h:248
QgsLayoutItemMapGrid::setMinimumIntervalWidth
void setMinimumIntervalWidth(double width)
Sets the minimum width (in millimeters) for grid segments.
Definition: qgslayoutitemmapgrid.cpp:2323
QgsExpressionContext
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
Definition: qgsexpressioncontext.h:406
QgsLayoutItemMapItem::setEnabled
virtual void setEnabled(bool enabled)
Controls whether the item will be drawn.
Definition: qgslayoutitemmapitem.cpp:99
QgsLayoutObject::MapGridAnnotationDisplayTop
@ MapGridAnnotationDisplayTop
Map annotation display top.
Definition: qgslayoutobject.h:179
QgsLayoutItemMapGrid::FrameRight
@ FrameRight
Right side of map.
Definition: qgslayoutitemmapgrid.h:260
QgsLayoutObject::layout
const QgsLayout * layout() const
Returns the layout the object is attached to.
Definition: qgslayoutobject.cpp:216
QgsLayoutItemMapGrid::Zebra
@ Zebra
Black/white pattern.
Definition: qgslayoutitemmapgrid.h:236
QgsLayoutItemMapGridStack::grid
QgsLayoutItemMapGrid * grid(const QString &gridId) const
Returns a reference to a grid with matching gridId within the stack.
Definition: qgslayoutitemmapgrid.cpp:77
QgsLayoutRenderContext::flags
QgsLayoutRenderContext::Flags flags() const
Returns the current combination of flags used for rendering the layout.
Definition: qgslayoutrendercontext.cpp:52
QgsCoordinateFormatter::FormatDecimalDegrees
@ FormatDecimalDegrees
Decimal degrees, eg 30.7555 degrees.
Definition: qgscoordinateformatter.h:52
QgsLayoutItemMapGridStack::readXml
bool readXml(const QDomElement &elem, const QDomDocument &doc, const QgsReadWriteContext &context) override
Sets the item stack's state from a DOM document, where element is a DOM node corresponding to a 'Layo...
Definition: qgslayoutitemmapgrid.cpp:109
QgsLayoutItemMapGrid
An individual grid which is drawn above the map content in a QgsLayoutItemMap.
Definition: qgslayoutitemmapgrid.h:140
QgsLayoutItemMapGrid::InteriorTicks
@ InteriorTicks
Tick markers drawn inside map frame.
Definition: qgslayoutitemmapgrid.h:237
qgslayoutitemmapgrid.h
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
QgsLayoutObject::MapGridFrameLineThickness
@ MapGridFrameLineThickness
Map grid frame line thickness.
Definition: qgslayoutobject.h:176
QgsLayoutItemMapGrid::VerticalDescending
@ VerticalDescending
Draw annotations vertically, descending.
Definition: qgslayoutitemmapgrid.h:196
QgsSymbolLayerUtils::encodeColor
static QString encodeColor(const QColor &color)
Definition: qgssymbollayerutils.cpp:64
QgsLayoutItemMapGrid::LongitudeOnly
@ LongitudeOnly
Show longitude/x annotations/divisions only.
Definition: qgslayoutitemmapgrid.h:176
QgsPointXY::y
double y
Definition: qgspointxy.h:63
QgsLayoutItemMapGrid::setFrameWidth
void setFrameWidth(const double width)
Sets the grid frame width (in layout units).
Definition: qgslayoutitemmapgrid.cpp:2445
QgsLayoutItemMapGrid::style
GridStyle style() const
Returns the grid's style, which controls how the grid is drawn over the map's contents.
Definition: qgslayoutitemmapgrid.h:471
QgsTextFormat::setFont
void setFont(const QFont &font)
Sets the font used for rendering text.
Definition: qgstextformat.cpp:207
QgsLayoutItemMapGrid::setOffsetX
void setOffsetX(double offset)
Sets the offset for grid lines in the x-direction.
Definition: qgslayoutitemmapgrid.cpp:2301
QgsRenderContext::expressionContext
QgsExpressionContext & expressionContext()
Gets the expression context.
Definition: qgsrendercontext.h:625
QgsLayoutItem::frameEnabled
bool frameEnabled() const
Returns true if the item includes a frame.
Definition: qgslayoutitem.h:732
QgsSettings::value
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
Definition: qgssettings.cpp:161
QgsLayoutItemMapGrid::DynamicPageSizeBased
@ DynamicPageSizeBased
Dynamically sized, based on a on-page size range.
Definition: qgslayoutitemmapgrid.h:155
QgsLayoutItemMap::updateBoundingRect
void updateBoundingRect()
Updates the bounding rect of this item. Call this function before doing any changes related to annota...
Definition: qgslayoutitemmap.cpp:1877
QgsReadWriteContext
The class is used as a container of context for various read/write operations on other objects.
Definition: qgsreadwritecontext.h:34
QgsLayoutItemMapGrid::Latitude
@ Latitude
Coordinate is a latitude value.
Definition: qgslayoutitemmapgrid.h:272
QgsLayoutItemMapGrid::setOffsetY
void setOffsetY(double offset)
Sets the offset for grid lines in the y-direction.
Definition: qgslayoutitemmapgrid.cpp:2312
QgsGeometry::fromPolylineXY
static QgsGeometry fromPolylineXY(const QgsPolylineXY &polyline)
Creates a new LineString geometry from a list of QgsPointXY points.
Definition: qgsgeometry.cpp:186
QgsExpressionContextScope::addVariable
void addVariable(const QgsExpressionContextScope::StaticVariable &variable)
Adds a variable into the context scope.
Definition: qgsexpressioncontext.cpp:97
QgsLayoutItemMap::mapToItemCoords
QPointF mapToItemCoords(QPointF mapCoords) const
Transforms map coordinates to item coordinates (considering rotation and move offset)
Definition: qgslayoutitemmap.cpp:1826
qgstextrenderer.h
QgsUnitTypes::DistanceUnknownUnit
@ DistanceUnknownUnit
Unknown distance unit.
Definition: qgsunittypes.h:78
sortByDistance
bool sortByDistance(QPair< qreal, QgsLayoutItemMapGrid::BorderSide > a, QPair< qreal, QgsLayoutItemMapGrid::BorderSide > b)
Definition: qgslayoutitemmapgrid.cpp:2036
QgsLayoutItemMapGrid::OutsideMapFrame
@ OutsideMapFrame
Draw annotations outside the map frame.
Definition: qgslayoutitemmapgrid.h:186
QgsLayoutItemMapGrid::FrameLeft
@ FrameLeft
Left side of map.
Definition: qgslayoutitemmapgrid.h:259
QgsStyleSymbolEntity
A symbol entity for QgsStyle databases.
Definition: qgsstyle.h:1341
QgsLayout::renderContext
QgsLayoutRenderContext & renderContext()
Returns a reference to the layout's render context, which stores information relating to the current ...
Definition: qgslayout.cpp:359
QgsLayoutItemMapGrid::setFrameSideFlag
void setFrameSideFlag(QgsLayoutItemMapGrid::FrameSideFlag flag, bool on=true)
Sets whether the grid frame is drawn for a certain side of the map item.
Definition: qgslayoutitemmapgrid.cpp:2391
QgsLayoutItemMapGrid::setFramePenSize
void setFramePenSize(const double width)
Sets the width of the stroke drawn in the grid frame.
Definition: qgslayoutitemmapgrid.cpp:2457
QgsLayoutItemMapGrid::annotationDirection
AnnotationDirection annotationDirection(BorderSide border) const
Returns the direction for drawing frame annotations, on the specified side of the map.
Definition: qgslayoutitemmapgrid.cpp:2518
QgsLayoutItemMapItem::createExpressionContext
QgsExpressionContext createExpressionContext() const override
This method needs to be reimplemented in all classes which implement this interface and return an exp...
Definition: qgslayoutitemmapitem.cpp:124
qgsreadwritecontext.h
QgsLayoutItemMapGrid::lineSymbol
const QgsLineSymbol * lineSymbol() const
Returns the line symbol used for drawing grid lines.
Definition: qgslayoutitemmapgrid.cpp:2098
QgsLayoutItemMap::extentChanged
void extentChanged()
Emitted when the map's extent changes.
crs
const QgsCoordinateReferenceSystem & crs
Definition: qgswfsgetfeature.cpp:105
QgsLayoutItemMapGrid::ExteriorTicks
@ ExteriorTicks
Tick markers drawn outside map frame.
Definition: qgslayoutitemmapgrid.h:238
QgsLayoutItemMapGrid::ShowAll
@ ShowAll
Show both latitude and longitude annotations/divisions.
Definition: qgslayoutitemmapgrid.h:174
QgsPolylineXY
QVector< QgsPointXY > QgsPolylineXY
Polyline as represented as a vector of two-dimensional points.
Definition: qgsgeometry.h:52
QgsUnitTypes::RenderPoints
@ RenderPoints
Points (e.g., for font sizes)
Definition: qgsunittypes.h:173
QgsExpressionContext::lastScope
QgsExpressionContextScope * lastScope()
Returns the last scope added to the context.
Definition: qgsexpressioncontext.cpp:377
borderToNormal2D
QVector2D borderToNormal2D(QgsLayoutItemMapGrid::BorderSide border)
Definition: qgslayoutitemmapgrid.cpp:181
qgssymbollayerutils.h
QgsRectangle::yMinimum
double yMinimum() const SIP_HOLDGIL
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:198
QgsCoordinateTransform::transformBoundingBox
QgsRectangle transformBoundingBox(const QgsRectangle &rectangle, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward, bool handle180Crossover=false) const SIP_THROW(QgsCsException)
Transforms a rectangle from the source CRS to the destination CRS.
Definition: qgscoordinatetransform.cpp:560
MAX_GRID_LINES
#define MAX_GRID_LINES
Definition: qgslayoutitemmapgrid.cpp:49
QgsLayoutItemMapGrid::setMarkerSymbol
void setMarkerSymbol(QgsMarkerSymbol *symbol)
Sets the marker symbol used for drawing grid points.
Definition: qgslayoutitemmapgrid.cpp:2108
QgsLayoutObject::MapGridAnnotationDisplayLeft
@ MapGridAnnotationDisplayLeft
Map annotation display left.
Definition: qgslayoutobject.h:177
QgsLayoutItemMapGrid::setUnits
void setUnits(GridUnit unit)
Sets the unit to use for grid measurements such as the interval and offset for grid lines.
Definition: qgslayoutitemmapgrid.cpp:2269
QgsLayoutItemMapGrid::annotationFont
Q_DECL_DEPRECATED QFont annotationFont() const
Returns the font used for drawing grid annotations.
Definition: qgslayoutitemmapgrid.cpp:2138
qgspathresolver.h
QgsLayoutItemMapGrid::FrameSideFlag
FrameSideFlag
Flags for controlling which side of the map a frame is drawn on.
Definition: qgslayoutitemmapgrid.h:257
QgsLayoutObject::mDataDefinedProperties
QgsPropertyCollection mDataDefinedProperties
Definition: qgslayoutobject.h:365
QgsLayoutItemMapGrid::setStyle
void setStyle(GridStyle style)
Sets the grid style, which controls how the grid is drawn over the map's contents.
Definition: qgslayoutitemmapgrid.cpp:2345
QgsLayoutItemMapGrid::CustomFormat
@ CustomFormat
Custom expression-based format.
Definition: qgslayoutitemmapgrid.h:216
QgsLayoutItemMapGrid::GridStyle
GridStyle
Grid drawing style.
Definition: qgslayoutitemmapgrid.h:161
QgsRenderContext
Contains information about the context of a rendering operation.
Definition: qgsrendercontext.h:59
QgsLayoutItemMapItem
An item which is drawn inside a QgsLayoutItemMap, e.g., a grid or map overview.
Definition: qgslayoutitemmapitem.h:33
QgsStyleEntityVisitorInterface
An interface for classes which can visit style entity (e.g. symbol) nodes (using the visitor pattern)...
Definition: qgsstyleentityvisitor.h:33
QgsUnitTypes::RenderMillimeters
@ RenderMillimeters
Millimeters.
Definition: qgsunittypes.h:169
QgsLayoutItemMapItemStack::mMap
QgsLayoutItemMap * mMap
Definition: qgslayoutitemmapitem.h:355
QgsSettings
This class is a composition of two QSettings instances:
Definition: qgssettings.h:61
QgsPointXY::isEmpty
bool isEmpty() const SIP_HOLDGIL
Returns true if the geometry is empty.
Definition: qgspointxy.h:249
QgsLayoutItemMapItemStack
A collection of map items which are drawn above the map content in a QgsLayoutItemMap....
Definition: qgslayoutitemmapitem.h:230
QgsLayoutItemMapGrid::ZebraNautical
@ ZebraNautical
Black/white pattern, with nautical style diagonals on corners.
Definition: qgslayoutitemmapgrid.h:242
QgsLayoutItemMapGrid::setFrameSideFlags
void setFrameSideFlags(QgsLayoutItemMapGrid::FrameSideFlags flags)
Sets flags for grid frame sides.
Definition: qgslayoutitemmapgrid.cpp:2386
QgsLayoutItemMapGrid::DegreeMinutePadded
@ DegreeMinutePadded
Degree/minutes, with minutes using leading zeros where required.
Definition: qgslayoutitemmapgrid.h:213
QgsLayoutItemMapGrid::CM
@ CM
Grid units in centimeters.
Definition: qgslayoutitemmapgrid.h:154
FALLTHROUGH
#define FALLTHROUGH
Definition: qgis.h:2847
QgsLayoutItemMapItemStack::removeItems
void removeItems()
Clears the item stack and deletes all QgsLayoutItemMapItems contained by the stack.
Definition: qgslayoutitemmapitem.cpp:323
QgsDebugMsg
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
qgsmapsettings.h
qgsfontutils.h
QgsUnitTypes::DistanceUnit
DistanceUnit
Units of distance.
Definition: qgsunittypes.h:67
QgsLayoutItemMapGrid::DisplayMode
DisplayMode
Display settings for grid annotations and frames.
Definition: qgslayoutitemmapgrid.h:172
QgsCoordinateReferenceSystem::readXml
bool readXml(const QDomNode &node)
Restores state from the given DOM node.
Definition: qgscoordinatereferencesystem.cpp:1860
QgsLayoutItemMapGrid::createExpressionContext
QgsExpressionContext createExpressionContext() const override
This method needs to be reimplemented in all classes which implement this interface and return an exp...
Definition: qgslayoutitemmapgrid.cpp:2404
QgsSymbolLayerUtils::decodeColor
static QColor decodeColor(const QString &str)
Definition: qgssymbollayerutils.cpp:69
QgsLayoutItem::sizeWithUnits
QgsLayoutSize sizeWithUnits() const
Returns the item's current size, including units.
Definition: qgslayoutitem.h:673
QgsRectangle
A rectangle specified with double values.
Definition: qgsrectangle.h:41
QgsStyleEntityVisitorInterface::StyleLeaf
Contains information relating to the style entity currently being visited.
Definition: qgsstyleentityvisitor.h:60
QgsGeometry::asGeometryCollection
QVector< QgsGeometry > asGeometryCollection() const
Returns contents of the geometry as a list of geometries.
Definition: qgsgeometry.cpp:2753
QgsLineSymbol::createSimple
static QgsLineSymbol * createSimple(const QVariantMap &properties)
Create a line symbol with one symbol layer: SimpleLine with specified properties.
Definition: qgslinesymbol.cpp:22
qgsDoubleToString
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
Definition: qgis.h:2204
QgsLayoutObject::MapGridOffsetY
@ MapGridOffsetY
Map grid offset Y.
Definition: qgslayoutobject.h:171
QgsLayoutItemMapGrid::accept
bool accept(QgsStyleEntityVisitorInterface *visitor) const override
Accepts the specified style entity visitor, causing it to visit all style entities associated with th...
Definition: qgslayoutitemmapgrid.cpp:2414
QgsLayoutItemMapGrid::InteriorExteriorTicks
@ InteriorExteriorTicks
Tick markers drawn both inside and outside the map frame.
Definition: qgslayoutitemmapgrid.h:239
QgsGeometry::intersection
QgsGeometry intersection(const QgsGeometry &geometry) const
Returns a geometry representing the points shared by this geometry and other.
Definition: qgsgeometry.cpp:2616
QgsTextRenderer::textHeight
static double textHeight(const QgsRenderContext &context, const QgsTextFormat &format, const QStringList &textLines, DrawMode mode=Point, QFontMetricsF *fontMetrics=nullptr, Qgis::TextRendererFlags flags=Qgis::TextRendererFlags(), double maxLineWidth=0)
Returns the height of a text based on a given format.
Definition: qgstextrenderer.cpp:620
QgsLayoutItemMapGrid::Longitude
@ Longitude
Coordinate is a longitude value.
Definition: qgslayoutitemmapgrid.h:271
QgsLayoutItemMapGrid::LatitudeOnly
@ LatitudeOnly
Show latitude/y annotations/divisions only.
Definition: qgslayoutitemmapgrid.h:175
QgsLayoutItemMapGrid::FrameBottom
@ FrameBottom
Bottom side of map.
Definition: qgslayoutitemmapgrid.h:262
QgsLayoutItemMapGridStack::moveGridUp
void moveGridUp(const QString &gridId)
Moves a grid with matching gridId up the stack, causing it to be rendered above other grids.
Definition: qgslayoutitemmapgrid.cpp:67
QgsTextFormat::color
QColor color() const
Returns the color that text will be rendered in.
Definition: qgstextformat.cpp:297
QgsLayoutObject::MapGridFrameDivisionsTop
@ MapGridFrameDivisionsTop
Map frame division display top.
Definition: qgslayoutobject.h:183
QgsTextRenderer::textWidth
static double textWidth(const QgsRenderContext &context, const QgsTextFormat &format, const QStringList &textLines, QFontMetricsF *fontMetrics=nullptr)
Returns the width of a text based on a given format.
Definition: qgstextrenderer.cpp:545
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:521
QgsLayoutItemMapGrid::setAnnotationDisplay
void setAnnotationDisplay(DisplayMode display, BorderSide border)
Sets what types of grid annotations should be drawn for a specified side of the map frame,...
Definition: qgslayoutitemmapgrid.cpp:2153
QgsLayoutItemMapGridStack::QgsLayoutItemMapGridStack
QgsLayoutItemMapGridStack(QgsLayoutItemMap *map)
Constructor for QgsLayoutItemMapGridStack, attached to the specified map.
Definition: qgslayoutitemmapgrid.cpp:51
qgslayoututils.h
QgsLayoutItemMapGrid::QgsLayoutItemMapGrid
QgsLayoutItemMapGrid(const QString &name, QgsLayoutItemMap *map)
Constructor for QgsLayoutItemMapGrid.
Definition: qgslayoutitemmapgrid.cpp:188
QgsLayoutItemMapGrid::markerSymbol
const QgsMarkerSymbol * markerSymbol() const
Returns the marker symbol used for drawing grid points.
Definition: qgslayoutitemmapgrid.cpp:2113
QgsLayoutUtils::createRenderContextForLayout
static QgsRenderContext createRenderContextForLayout(QgsLayout *layout, QPainter *painter, double dpi=-1)
Creates a render context suitable for the specified layout and painter destination.
Definition: qgslayoututils.cpp:141
QgsCoordinateFormatter::FormatDegreesMinutes
@ FormatDegreesMinutes
Degrees and decimal minutes, eg 30degrees 45.55'.
Definition: qgscoordinateformatter.h:51
QgsRectangle::xMaximum
double xMaximum() const SIP_HOLDGIL
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:183
QgsUnitTypes::fromUnitToUnitFactor
static Q_INVOKABLE double fromUnitToUnitFactor(QgsUnitTypes::DistanceUnit fromUnit, QgsUnitTypes::DistanceUnit toUnit)
Returns the conversion factor between the specified distance units.
Definition: qgsunittypes.cpp:352
QgsLayoutItemMapGrid::FrameTop
@ FrameTop
Top side of map.
Definition: qgslayoutitemmapgrid.h:261
QgsDistanceArea::setEllipsoid
bool setEllipsoid(const QString &ellipsoid)
Sets the ellipsoid by its acronym.
Definition: qgsdistancearea.cpp:89
QgsTextFormat::setColor
void setColor(const QColor &color)
Sets the color that text will be rendered in.
Definition: qgstextformat.cpp:302
QgsLayoutObject::MapGridFrameMargin
@ MapGridFrameMargin
Map grid frame margin.
Definition: qgslayoutobject.h:173
QgsCoordinateReferenceSystem::isGeographic
bool isGeographic
Definition: qgscoordinatereferencesystem.h:216
qgsexpressioncontext.h
QgsCsException
Custom exception class for Coordinate Reference System related exceptions.
Definition: qgsexception.h:65
QgsLayoutUtils::calculatePrettySize
static double calculatePrettySize(double minimumSize, double maximumSize)
Calculates a "pretty" size which falls between the range [minimumSize, maximumSize].
Definition: qgslayoututils.cpp:458
QgsLayoutItemMapGridStack::operator[]
QgsLayoutItemMapGrid & operator[](int index)
Returns a reference to a grid at the specified index within the stack.
Definition: qgslayoutitemmapgrid.cpp:102
QgsLayoutObject::MapGridAnnotationDisplayBottom
@ MapGridAnnotationDisplayBottom
Map annotation display bottom.
Definition: qgslayoutobject.h:180
QgsCoordinateTransform::setBallparkTransformsAreAppropriate
void setBallparkTransformsAreAppropriate(bool appropriate)
Sets whether approximate "ballpark" results are appropriate for this coordinate transform.
Definition: qgscoordinatetransform.cpp:939
QgsCoordinateReferenceSystem::writeXml
bool writeXml(QDomNode &node, QDomDocument &doc) const
Stores state to the given Dom node in the given document.
Definition: qgscoordinatereferencesystem.cpp:1980
QgsLayoutItemMapGrid::crs
QgsCoordinateReferenceSystem crs() const
Retrieves the CRS for the grid.
Definition: qgslayoutitemmapgrid.h:297
QgsLayoutItemMapGridStack::removeGrid
void removeGrid(const QString &gridId)
Removes a grid with matching gridId from the stack and deletes the corresponding QgsLayoutItemMapGrid...
Definition: qgslayoutitemmapgrid.cpp:62
QgsLayoutItemMapItem::mMap
QgsLayoutItemMap * mMap
Associated map.
Definition: qgslayoutitemmapitem.h:207
QgsLayoutItemMapItemStack::removeItem
void removeItem(const QString &itemId)
Removes an item which matching itemId from the stack and deletes the corresponding QgsLayoutItemMapIt...
Definition: qgslayoutitemmapitem.cpp:162
QgsLayoutItemMapGrid::GridUnit
GridUnit
Unit for grid values.
Definition: qgslayoutitemmapgrid.h:150
QgsLayoutItemMapGrid::setMaximumIntervalWidth
void setMaximumIntervalWidth(double width)
Sets the maximum width (in millimeters) for grid segments.
Definition: qgslayoutitemmapgrid.cpp:2334
QgsMarkerSymbol
A marker symbol type, for rendering Point and MultiPoint geometries.
Definition: qgsmarkersymbol.h:30
QgsLayoutItemMapGrid::AnnotationDirection
AnnotationDirection
Direction of grid annotations.
Definition: qgslayoutitemmapgrid.h:192
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:2265
QgsLayoutItemMapGridStack::asList
QList< QgsLayoutItemMapGrid * > asList() const
Returns a list of QgsLayoutItemMapGrids contained by the stack.
Definition: qgslayoutitemmapgrid.cpp:89
QgsLayoutItemMapGrid::annotationDisplay
DisplayMode annotationDisplay(BorderSide border) const
Returns the display mode for the grid annotations on a specified side of the map frame.
Definition: qgslayoutitemmapgrid.cpp:2180
QgsRenderContext::setFlag
void setFlag(Qgis::RenderContextFlag flag, bool on=true)
Enable or disable a particular flag (other flags are not affected)
Definition: qgsrendercontext.cpp:216
QgsLayoutObject::MapGridIntervalX
@ MapGridIntervalX
Map grid interval X.
Definition: qgslayoutobject.h:168
QgsLayoutItemMapGridStack::maxGridExtension
double maxGridExtension() const
Calculates the maximum distance grids within the stack extend beyond the QgsLayoutItemMap's item rect...
Definition: qgslayoutitemmapgrid.cpp:126
Qgis::RenderContextFlag::ApplyScalingWorkaroundForTextRendering
@ ApplyScalingWorkaroundForTextRendering
Whether a scaling workaround designed to stablise the rendering of small font sizes (or for painters ...
QgsLayoutItemMapGrid::writeXml
bool writeXml(QDomElement &elem, QDomDocument &doc, const QgsReadWriteContext &context) const override
Stores map item state in a DOM element, where element is the DOM element corresponding to a 'LayoutMa...
Definition: qgslayoutitemmapgrid.cpp:251
QgsLayoutItemMapGrid::setFrameDivisions
void setFrameDivisions(DisplayMode divisions, BorderSide side)
Sets what type of grid divisions should be used for frames on a specified side of the map.
Definition: qgslayoutitemmapgrid.cpp:2539
qgsRound
double qgsRound(double number, int places)
Returns a double number, rounded (as close as possible) to the specified number of places.
Definition: qgis.h:2319
QgsException::what
QString what() const
Definition: qgsexception.h:48
QgsLayoutItemMapGrid::crsChanged
void crsChanged()
Emitted whenever the grid's CRS is changed.
QgsDistanceArea::measureLine
double measureLine(const QVector< QgsPointXY > &points) const
Measures the length of a line with multiple segments.
Definition: qgsdistancearea.cpp:298
QgsLayoutItemMapGrid::MapUnit
@ MapUnit
Grid units follow map units.
Definition: qgslayoutitemmapgrid.h:152
QgsLayoutItemMapGrid::calculateMaxExtension
void calculateMaxExtension(double &top, double &right, double &bottom, double &left) const
Calculates the maximum distance the grid extends beyond the QgsLayoutItemMap's item rect.
Definition: qgslayoutitemmapgrid.cpp:2206
QgsLayoutItemMapGrid::setIntervalY
void setIntervalY(double interval)
Sets the interval between grid lines in the y-direction.
Definition: qgslayoutitemmapgrid.cpp:2290
QgsLayoutObject::MapGridCrossSize
@ MapGridCrossSize
Map grid cross size.
Definition: qgslayoutobject.h:175
QgsDistanceArea::lengthUnits
QgsUnitTypes::DistanceUnit lengthUnits() const
Returns the units of distance for length calculations made by this object.
Definition: qgsdistancearea.cpp:790
QgsLayoutItemMapGrid::LineBorderNautical
@ LineBorderNautical
Simple solid line frame, with nautical style diagonals on corners.
Definition: qgslayoutitemmapgrid.h:241
qgsrendercontext.h
QgsLayoutItemMapGrid::DegreeMinuteSecondPadded
@ DegreeMinuteSecondPadded
Degree/minutes/seconds, with minutes using leading zeros where required.
Definition: qgslayoutitemmapgrid.h:215
QgsLineSymbol
A line symbol type, for rendering LineString and MultiLineString geometries.
Definition: qgslinesymbol.h:29
QgsLayoutItemMap::extent
QgsRectangle extent() const
Returns the current map extent.
Definition: qgslayoutitemmap.cpp:281
QgsTextRenderer::drawText
static void drawText(const QRectF &rect, double rotation, HAlignment alignment, const QStringList &textLines, QgsRenderContext &context, const QgsTextFormat &format, bool drawAsOutlines=true, VAlignment vAlignment=AlignTop, Qgis::TextRendererFlags flags=Qgis::TextRendererFlags())
Draws text within a rectangle using the specified settings.
Definition: qgstextrenderer.cpp:81
QgsLayoutItemMapGrid::Right
@ Right
Right border.
Definition: qgslayoutitemmapgrid.h:225
QgsLayoutItemMapGrid::setLineSymbol
void setLineSymbol(QgsLineSymbol *symbol)
Sets the line symbol used for drawing grid lines.
Definition: qgslayoutitemmapgrid.cpp:2093
QgsCoordinateReferenceSystem::isValid
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
Definition: qgscoordinatereferencesystem.cpp:977
QgsLayoutItemMapGrid::usesAdvancedEffects
bool usesAdvancedEffects() const override
Returns true if the item is drawn using advanced effects, such as blend modes.
Definition: qgslayoutitemmapgrid.cpp:458
QgsTextRenderer::AlignLeft
@ AlignLeft
Left align.
Definition: qgstextrenderer.h:60
QgsLayoutObject::MapGridOffsetX
@ MapGridOffsetX
Map grid offset X.
Definition: qgslayoutobject.h:170
QgsLayoutItemMapItem::readXml
virtual bool readXml(const QDomElement &element, const QDomDocument &doc, const QgsReadWriteContext &context)
Sets the map item state from a DOM document, where element is the DOM node corresponding to a 'Layout...
Definition: qgslayoutitemmapitem.cpp:55
QgsLayoutItemMapGrid::frameSideFlags
QgsLayoutItemMapGrid::FrameSideFlags frameSideFlags() const
Returns the flags which control which sides of the map item the grid frame is drawn on.
Definition: qgslayoutitemmapgrid.cpp:2399
QgsCoordinateFormatter::formatY
static QString formatY(double y, Format format, int precision=12, FormatFlags flags=FlagDegreesUseStringSuffix)
Formats a y coordinate value according to the specified parameters.
Definition: qgscoordinateformatter.cpp:43
QgsLayoutItemMapGrid::AnnotationPosition
AnnotationPosition
Position for grid annotations.
Definition: qgslayoutitemmapgrid.h:183
gridAnnotationDisplayModeFromDD
QgsLayoutItemMapGrid::DisplayMode gridAnnotationDisplayModeFromDD(QString ddValue, QgsLayoutItemMapGrid::DisplayMode defValue)
Definition: qgslayoutitemmapgrid.cpp:1932
QgsGeometry::isNull
bool isNull
Definition: qgsgeometry.h:127
QgsTextFormat::readXml
void readXml(const QDomElement &elem, const QgsReadWriteContext &context)
Read settings from a DOM element.
Definition: qgstextformat.cpp:488
QgsLayoutItemMapGrid::setCrs
void setCrs(const QgsCoordinateReferenceSystem &crs)
Sets the crs for the grid.
Definition: qgslayoutitemmapgrid.cpp:448
QgsRectangle::xMinimum
double xMinimum() const SIP_HOLDGIL
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:188
QgsTextFormat::toQFont
QFont toQFont() const
Returns a QFont matching the relevant settings from this text format.
Definition: qgstextformat.cpp:758
QgsDistanceArea::setSourceCrs
void setSourceCrs(const QgsCoordinateReferenceSystem &crs, const QgsCoordinateTransformContext &context)
Sets source spatial reference system crs.
Definition: qgsdistancearea.cpp:83
QgsLayoutItemMapGrid::setAnnotationFont
Q_DECL_DEPRECATED void setAnnotationFont(const QFont &font)
Sets the font used for drawing grid annotations.
Definition: qgslayoutitemmapgrid.cpp:2123
QgsScopedQPainterState
Scoped object for saving and restoring a QPainter object's state.
Definition: qgsrendercontext.h:1336
QgsLayoutItemMapGrid::BorderSide
BorderSide
Border sides for annotations.
Definition: qgslayoutitemmapgrid.h:222
qgslayout.h
QgsLayoutItemMapGrid::FrameAnnotationsOnly
@ FrameAnnotationsOnly
No grid lines over the map, only draw frame and annotations.
Definition: qgslayoutitemmapgrid.h:166
QgsLayoutItemMap::crs
QgsCoordinateReferenceSystem crs() const
Returns coordinate reference system used for rendering the map.
Definition: qgslayoutitemmap.cpp:308
QgsCoordinateReferenceSystem
This class represents a coordinate reference system (CRS).
Definition: qgscoordinatereferencesystem.h:211
QgsLayoutItemMapGrid::Solid
@ Solid
Definition: qgslayoutitemmapgrid.h:163
QgsExpressionContextScope
Single scope for storing variables and functions for use within a QgsExpressionContext....
Definition: qgsexpressioncontext.h:113
QgsLayoutItemMapGrid::Bottom
@ Bottom
Bottom border.
Definition: qgslayoutitemmapgrid.h:226
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
qgsclipper.h
QgsLayoutItemMapGridStack::moveGridDown
void moveGridDown(const QString &gridId)
Moves a grid with matching gridId down the stack, causing it to be rendered below other grids.
Definition: qgslayoutitemmapgrid.cpp:72
QgsLayoutItemMapGrid::~QgsLayoutItemMapGrid
~QgsLayoutItemMapGrid() override
QgsLayoutItemMapItemStack::moveItemDown
void moveItemDown(const QString &itemId)
Moves an item which matching itemId up the stack, causing it to be rendered above other items.
Definition: qgslayoutitemmapitem.cpp:194
QgsUnitTypes::RenderPixels
@ RenderPixels
Pixels.
Definition: qgsunittypes.h:171
QgsGeometry::vertexAt
QgsPoint vertexAt(int atVertex) const
Returns coordinates of a vertex.
Definition: qgsgeometry.cpp:683
QgsLayoutObject::MapGridEnabled
@ MapGridEnabled
Map grid enabled.
Definition: qgslayoutobject.h:167
QgsLayoutItemMapGrid::setFrameMargin
void setFrameMargin(const double margin)
Sets the grid frame margin (in layout units).
Definition: qgslayoutitemmapgrid.cpp:2451
QgsLayoutItemMapGrid::setEnabled
void setEnabled(bool enabled) override
Controls whether the item will be drawn.
Definition: qgslayoutitemmapgrid.cpp:2263
QgsExpressionContext::appendScope
void appendScope(QgsExpressionContextScope *scope)
Appends a scope to the end of the context.
Definition: qgsexpressioncontext.cpp:494
QgsLayoutItemMapGrid::annotationFontColor
Q_DECL_DEPRECATED QColor annotationFontColor() const
Returns the font color used for drawing grid annotations.
Definition: qgslayoutitemmapgrid.cpp:2148
QgsPointXY
A class to represent a 2D point.
Definition: qgspointxy.h:58
QgsLayoutItemMap::transformedMapPolygon
QPolygonF transformedMapPolygon() const
Returns extent that considers rotation and shift with mOffsetX / mOffsetY.
Definition: qgslayoutitemmap.cpp:1751
QgsRenderContext::convertToPainterUnits
double convertToPainterUnits(double size, QgsUnitTypes::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale(), Qgis::RenderSubcomponentProperty property=Qgis::RenderSubcomponentProperty::Generic) const
Converts a size from the specified units to painter units (pixels).
Definition: qgsrendercontext.cpp:367
QgsRenderContext::setForceVectorOutput
void setForceVectorOutput(bool force)
Sets whether rendering operations should use vector operations instead of any faster raster shortcuts...
Definition: qgsrendercontext.cpp:330
QgsLayoutItemMapGrid::Cross
@ Cross
Draw line crosses at intersections of grid lines.
Definition: qgslayoutitemmapgrid.h:164
QgsLayoutItemMap
Layout graphical items for displaying a map.
Definition: qgslayoutitemmap.h:317
QgsLayoutItemMap::crsChanged
void crsChanged()
Emitted when the map's coordinate reference system is changed.
QgsLayoutItemMapGrid::units
GridUnit units() const
Returns the units used for grid measurements such as the interval and offset for grid lines.
Definition: qgslayoutitemmapgrid.h:345
QgsSymbolLayerUtils::pointOnLineWithDistance
static QPointF pointOnLineWithDistance(QPointF startPoint, QPointF directionPoint, double distance)
Returns a point on the line from startPoint to directionPoint that is a certain distance away from th...
Definition: qgssymbollayerutils.cpp:4174
QgsLayoutItemMapItemStack::mItems
QList< QgsLayoutItemMapItem * > mItems
Definition: qgslayoutitemmapitem.h:353
QgsLayoutItemMapGrid::Horizontal
@ Horizontal
Draw annotations horizontally.
Definition: qgslayoutitemmapgrid.h:194
QgsCoordinateFormatter::FormatDegreesMinutesSeconds
@ FormatDegreesMinutesSeconds
Degrees, minutes and seconds, eg 30 degrees 45'30".
Definition: qgscoordinateformatter.h:50
QgsLayoutItemMapGridStack::addGrid
void addGrid(QgsLayoutItemMapGrid *grid)
Adds a new map grid to the stack and takes ownership of the grid.
Definition: qgslayoutitemmapgrid.cpp:57
QgsFontUtils::setFromXmlChildNode
static bool setFromXmlChildNode(QFont &font, const QDomElement &element, const QString &childNode)
Sets the properties of a font to match the properties stored in an XML child node.
Definition: qgsfontutils.cpp:400
QgsCoordinateFormatter::FlagDegreesUseStringSuffix
@ FlagDegreesUseStringSuffix
Include a direction suffix (eg 'N', 'E', 'S' or 'W'), otherwise a "-" prefix is used for west and sou...
Definition: qgscoordinateformatter.h:60
QgsLayoutItemMapGrid::setGridLineColor
void setGridLineColor(const QColor &color)
Sets the color of grid lines.
Definition: qgslayoutitemmapgrid.cpp:243
QgsCoordinateReferenceSystem::mapUnits
QgsUnitTypes::DistanceUnit mapUnits
Definition: qgscoordinatereferencesystem.h:215
QgsRectangle::yMaximum
double yMaximum() const SIP_HOLDGIL
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:193
qgsgeometry.h
QgsLayoutItemMapGrid::Vertical
@ Vertical
Draw annotations vertically, ascending.
Definition: qgslayoutitemmapgrid.h:195
QgsLayoutItemMapGrid::InsideMapFrame
@ InsideMapFrame
Draw annotations inside the map frame.
Definition: qgslayoutitemmapgrid.h:185
QgsLayoutObject::mLayout
QPointer< QgsLayout > mLayout
Definition: qgslayoutobject.h:363
c
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
Definition: porting_processing.dox:1
QgsGeometry
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:124
QgsAbstractPropertyCollection::valueAsBool
bool valueAsBool(int key, const QgsExpressionContext &context, bool defaultValue=false, bool *ok=nullptr) const
Calculates the current value of the property with the specified key and interprets it as an boolean.
Definition: qgspropertycollection.cpp:88
QgsLayoutItemMapGrid::DegreeMinute
@ DegreeMinute
Degree/minutes, use NSEW suffix.
Definition: qgslayoutitemmapgrid.h:209
QgsRectangle::width
double width() const SIP_HOLDGIL
Returns the width of the rectangle.
Definition: qgsrectangle.h:223
QgsLayoutItemMap::mapRotationChanged
void mapRotationChanged(double newRotation)
Emitted when the map's rotation changes.
QgsLayoutItemMapGrid::DecimalWithSuffix
@ DecimalWithSuffix
Decimal degrees, use NSEW suffix.
Definition: qgslayoutitemmapgrid.h:211
QgsLayoutItemMapGrid::DegreeMinuteNoSuffix
@ DegreeMinuteNoSuffix
Degree/minutes, use - for S/W coordinates.
Definition: qgslayoutitemmapgrid.h:212
QgsLayoutObject::MapGridLabelDistance
@ MapGridLabelDistance
Map grid label distance.
Definition: qgslayoutobject.h:174
QgsCoordinateFormatter::Format
Format
Available formats for displaying coordinates.
Definition: qgscoordinateformatter.h:47
qgsmarkersymbol.h
QgsLayoutItemMapItem::writeXml
virtual bool writeXml(QDomElement &element, QDomDocument &document, const QgsReadWriteContext &context) const
Stores map item state in a DOM element, where element is the DOM element corresponding to a 'LayoutMa...
Definition: qgslayoutitemmapitem.cpp:33
QgsPointXY::x
double x
Definition: qgspointxy.h:62
QgsGeometry::fromRect
static QgsGeometry fromRect(const QgsRectangle &rect) SIP_HOLDGIL
Creates a new geometry from a QgsRectangle.
Definition: qgsgeometry.cpp:241
qgssettings.h
QgsLayoutItemMapGrid::DegreeMinuteSecond
@ DegreeMinuteSecond
Degree/minutes/seconds, use NSEW suffix.
Definition: qgslayoutitemmapgrid.h:210
QgsLayoutItemMapGrid::NoFrame
@ NoFrame
Disable grid frame.
Definition: qgslayoutitemmapgrid.h:235
QgsLayoutItemMapGrid::setCrossLength
void setCrossLength(const double length)
Sets the length (in layout units) of the cross segments drawn for the grid.
Definition: qgslayoutitemmapgrid.cpp:2355
QgsLayoutItemMapGrid::Top
@ Top
Top border.
Definition: qgslayoutitemmapgrid.h:227
QgsLayoutItemMapGrid::refresh
void refresh() override
Refreshes the object, causing a recalculation of any property overrides.
Definition: qgslayoutitemmapgrid.cpp:2432
QgsLayoutItemMapGridStack::calculateMaxGridExtension
void calculateMaxGridExtension(double &top, double &right, double &bottom, double &left) const
Calculates the maximum distance grids within the stack extend beyond the QgsLayoutItemMap's item rect...
Definition: qgslayoutitemmapgrid.cpp:136
QgsLayoutItemMapGrid::AnnotationFormat
AnnotationFormat
Format for displaying grid annotations.
Definition: qgslayoutitemmapgrid.h:206
QgsLayoutObject::MapGridFrameDivisionsRight
@ MapGridFrameDivisionsRight
Map frame division display right.
Definition: qgslayoutobject.h:182
QgsStyleEntityVisitorInterface::visit
virtual bool visit(const QgsStyleEntityVisitorInterface::StyleLeaf &entity)
Called when the visitor will visit a style entity.
Definition: qgsstyleentityvisitor.h:153
QgsLayoutItemMapGrid::DegreeMinuteSecondNoSuffix
@ DegreeMinuteSecondNoSuffix
Degree/minutes/seconds, use - for S/W coordinates.
Definition: qgslayoutitemmapgrid.h:214
QgsExpressionContext::setHighlightedVariables
void setHighlightedVariables(const QStringList &variableNames)
Sets the list of variable names within the context intended to be highlighted to the user.
Definition: qgsexpressioncontext.cpp:328
QgsTextFormat::setSizeUnit
void setSizeUnit(QgsUnitTypes::RenderUnit unit)
Sets the units for the size of rendered text.
Definition: qgstextformat.cpp:269
QgsRenderContext::setExpressionContext
void setExpressionContext(const QgsExpressionContext &context)
Sets the expression context.
Definition: qgsrendercontext.h:617
QgsLayoutItemMapGrid::AboveTick
@ AboveTick
Draw annotations parallel to tick (above the line)
Definition: qgslayoutitemmapgrid.h:198
QgsLayoutObject::MapGridAnnotationDisplayRight
@ MapGridAnnotationDisplayRight
Map annotation display right.
Definition: qgslayoutobject.h:178
QgsLayoutItemMapGrid::readXml
bool readXml(const QDomElement &itemElem, const QDomDocument &doc, const QgsReadWriteContext &context) override
Sets the map item state from a DOM document, where element is the DOM node corresponding to a 'Layout...
Definition: qgslayoutitemmapgrid.cpp:329
QgsLayoutObject::MapGridIntervalY
@ MapGridIntervalY
Map grid interval Y.
Definition: qgslayoutobject.h:169
QgsLayoutItemMapItemStack::moveItemUp
void moveItemUp(const QString &itemId)
Moves an item which matching itemId up the stack, causing it to be rendered above other items.
Definition: qgslayoutitemmapitem.cpp:174
QgsDistanceArea
A general purpose distance and area calculator, capable of performing ellipsoid based calculations.
Definition: qgsdistancearea.h:52
QgsLayoutItemMapGrid::Decimal
@ Decimal
Decimal degrees, use - for S/W coordinates.
Definition: qgslayoutitemmapgrid.h:208
qgsexception.h
QgsCoordinateFormatter::FlagDegreesPadMinutesSeconds
@ FlagDegreesPadMinutesSeconds
Pad minute and second values with leading zeros, eg '05' instead of '5'.
Definition: qgscoordinateformatter.h:61
QgsLayoutItemMapGrid::setAnnotationDirection
void setAnnotationDirection(AnnotationDirection direction, BorderSide side)
Sets the direction for drawing frame annotations for the specified map side.
Definition: qgslayoutitemmapgrid.cpp:2361
QgsLayoutItemMapGrid::setGridLineWidth
void setGridLineWidth(double width)
Sets the width of grid lines (in layout units).
Definition: qgslayoutitemmapgrid.cpp:235
QgsLayoutItemMapGrid::setAnnotationFontColor
Q_DECL_DEPRECATED void setAnnotationFontColor(const QColor &color)
Sets the font color used for drawing grid annotations.
Definition: qgslayoutitemmapgrid.cpp:2143
QgsGeometry::fromQPolygonF
static QgsGeometry fromQPolygonF(const QPolygonF &polygon)
Construct geometry from a QPolygonF.
Definition: qgsgeometry.cpp:3408
QgsLayoutItemMapItemStack::item
QgsLayoutItemMapItem * item(int index) const
Returns a reference to the item at the specified index within the stack.
Definition: qgslayoutitemmapitem.cpp:227
QgsUnitTypes::LayoutMillimeters
@ LayoutMillimeters
Millimeters.
Definition: qgsunittypes.h:183
QgsLayoutItemMapGrid::setAnnotationPosition
void setAnnotationPosition(AnnotationPosition position, BorderSide side)
Sets the position for the grid annotations on a specified side of the map frame.
Definition: qgslayoutitemmapgrid.cpp:2471
QgsLayoutItemMapGrid::maxExtension
double maxExtension() const
Calculates the maximum distance the grid extends beyond the QgsLayoutItemMap's item rect (in layout u...
Definition: qgslayoutitemmapgrid.cpp:2196
QgsScopedRenderContextScaleToPixels
Scoped object for temporary scaling of a QgsRenderContext for pixel based rendering.
Definition: qgsrendercontext.h:1292
borderToVector2D
QVector2D borderToVector2D(QgsLayoutItemMapGrid::BorderSide border)
Definition: qgslayoutitemmapgrid.cpp:165
QgsLayoutItemMapGrid::frameDivisions
DisplayMode frameDivisions(BorderSide side) const
Returns the type of grid divisions which are used for frames on a specified side of the map.
Definition: qgslayoutitemmapgrid.cpp:2565
QgsLayoutItemMapGrid::testFrameSideFlag
bool testFrameSideFlag(FrameSideFlag flag) const
Tests whether the grid frame should be drawn on a specified side of the map item.
Definition: qgslayoutitemmapgrid.cpp:2440
QgsLayoutObject::MapGridFrameSize
@ MapGridFrameSize
Map grid frame size.
Definition: qgslayoutobject.h:172
QgsLayoutItemMapGrid::setIntervalX
void setIntervalX(double interval)
Sets the interval between grid lines in the x-direction.
Definition: qgslayoutitemmapgrid.cpp:2279
qgslogger.h
QgsRenderContext::painter
QPainter * painter()
Returns the destination QPainter for the render operation.
Definition: qgsrendercontext.h:112
QgsLayoutItemMapItemStack::addItem
void addItem(QgsLayoutItemMapItem *item)
Adds a new map item to the stack and takes ownership of the item.
Definition: qgslayoutitemmapitem.cpp:157
QgsLayoutItemMapGrid::OrthogonalTicks
@ OrthogonalTicks
Align ticks orthogonaly.
Definition: qgslayoutitemmapgrid.h:250
QgsCoordinateTransform::transform
QgsPointXY transform(const QgsPointXY &point, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward) const SIP_THROW(QgsCsException)
Transform the point from the source CRS to the destination CRS.
Definition: qgscoordinatetransform.cpp:272
QgsTextFormat::setSize
void setSize(double size)
Sets the size for rendered text.
Definition: qgstextformat.cpp:291
QgsCoordinateFormatter::formatX
static QString formatX(double x, Format format, int precision=12, FormatFlags flags=FlagDegreesUseStringSuffix)
Formats an x coordinate value according to the specified parameters.
Definition: qgscoordinateformatter.cpp:24
QgsExpressionContextScope::StaticVariable
Single variable definition for use within a QgsExpressionContextScope.
Definition: qgsexpressioncontext.h:120
QgsLayoutObject::MapGridFrameDivisionsBottom
@ MapGridFrameDivisionsBottom
Map frame division display bottom.
Definition: qgslayoutobject.h:184
QgsLayoutItemMapGrid::Markers
@ Markers
Draw markers at intersections of grid lines.
Definition: qgslayoutitemmapgrid.h:165
QgsLayoutItemMapGrid::setAnnotationFrameDistance
void setAnnotationFrameDistance(const double distance)
Sets the distance between the map frame and annotations.
Definition: qgslayoutitemmapgrid.cpp:2512
QgsExpression
Class for parsing and evaluation of expressions (formerly called "search strings")....
Definition: qgsexpression.h:102
qgscoordinateformatter.h
QgsLayoutRenderContext::FlagAntialiasing
@ FlagAntialiasing
Use antialiasing when drawing items.
Definition: qgslayoutrendercontext.h:48
QgsPropertyCollection::isActive
bool isActive(int key) const override
Returns true if the collection contains an active property with the specified key.
Definition: qgspropertycollection.cpp:268
QgsCoordinateTransform
Class for doing transforms between two map coordinate systems.
Definition: qgscoordinatetransform.h:57
QgsLayoutObject::MapGridFrameDivisionsLeft
@ MapGridFrameDivisionsLeft
Map frame division display left.
Definition: qgslayoutobject.h:181
QgsLayoutItemMapGrid::annotationPosition
AnnotationPosition annotationPosition(BorderSide side) const
Returns the position for the grid annotations on a specified side of the map frame.
Definition: qgslayoutitemmapgrid.cpp:2496
QgsMarkerSymbol::createSimple
static QgsMarkerSymbol * createSimple(const QVariantMap &properties)
Create a marker symbol with one symbol layer: SimpleMarker with specified properties.
Definition: qgsmarkersymbol.cpp:22
qgscoordinatereferencesystem.h
QgsLayoutItemMapGrid::LineBorder
@ LineBorder
Simple solid line frame.
Definition: qgslayoutitemmapgrid.h:240
QgsTextFormat::writeXml
QDomElement writeXml(QDomDocument &doc, const QgsReadWriteContext &context) const
Write settings into a DOM element.
Definition: qgstextformat.cpp:671
qgssymbol.h
QgsLayoutItemMapGrid::AnnotationCoordinate
AnnotationCoordinate
Annotation coordinate type.
Definition: qgslayoutitemmapgrid.h:269
QgsSymbolLayerUtils::saveSymbol
static QDomElement saveSymbol(const QString &symbolName, const QgsSymbol *symbol, QDomDocument &doc, const QgsReadWriteContext &context)
Writes a symbol definition to XML.
Definition: qgssymbollayerutils.cpp:1397
QgsLayoutItemMapGrid::UnderTick
@ UnderTick
Draw annotations parallel to tick (under the line)
Definition: qgslayoutitemmapgrid.h:200
QgsLayoutItemMapGrid::HideAll
@ HideAll
No annotations.
Definition: qgslayoutitemmapgrid.h:177
QgsLayoutItemMapItem::enabled
bool enabled() const
Returns whether the item will be drawn.
Definition: qgslayoutitemmapitem.cpp:104
QgsLayoutItemMapGrid::FrameStyle
FrameStyle
Style for grid frame.
Definition: qgslayoutitemmapgrid.h:233
qgsstyleentityvisitor.h
QgsSettings::Gui
@ Gui
Definition: qgssettings.h:71
QgsLayoutItemMapGrid::OnTick
@ OnTick
Draw annotations parallel to tick (on the line)
Definition: qgslayoutitemmapgrid.h:199
qgslinesymbol.h
qgslayoutitemmap.h
QgsLayoutItemMapGrid::Left
@ Left
Left border.
Definition: qgslayoutitemmapgrid.h:224
qgsmessagelog.h
QgsLayoutItemMapGrid::MM
@ MM
Grid units in millimeters.
Definition: qgslayoutitemmapgrid.h:153
QgsLayoutItemMapGrid::draw
void draw(QPainter *painter) override
Draws the item on to a destination painter.
Definition: qgslayoutitemmapgrid.cpp:598