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