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