QGIS API Documentation  3.20.0-Odense (decaadbb31)
qgslayoututils.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgslayoututils.cpp
3  ------------------
4  begin : July 2017
5  copyright : (C) 2017 by Nyall Dawson
6  email : nyall dot dawson at gmail dot com
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
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 "qgslayoututils.h"
19 #include "qgslayout.h"
20 #include "qgslayoutitemmap.h"
21 #include "qgsprojectviewsettings.h"
22 #include "qgsrendercontext.h"
23 #include "qgssettings.h"
24 
25 #include <QStyleOptionGraphicsItem>
26 #include <QPainter>
27 #include <cmath>
28 
29 #ifndef M_DEG2RAD
30 #define M_DEG2RAD 0.0174532925
31 #endif
32 
33 void QgsLayoutUtils::rotate( double angle, double &x, double &y )
34 {
35  double rotToRad = angle * M_PI / 180.0;
36  double xRot, yRot;
37  xRot = x * std::cos( rotToRad ) - y * std::sin( rotToRad );
38  yRot = x * std::sin( rotToRad ) + y * std::cos( rotToRad );
39  x = xRot;
40  y = yRot;
41 }
42 
43 double QgsLayoutUtils::normalizedAngle( const double angle, const bool allowNegative )
44 {
45  double clippedAngle = angle;
46  if ( clippedAngle >= 360.0 || clippedAngle <= -360.0 )
47  {
48  clippedAngle = std::fmod( clippedAngle, 360.0 );
49  }
50  if ( !allowNegative && clippedAngle < 0.0 )
51  {
52  clippedAngle += 360.0;
53  }
54  return clippedAngle;
55 }
56 
58 {
59  //normalize angle to 0-360 degrees
60  double clippedAngle = normalizedAngle( angle );
61 
62  //snap angle to 45 degree
63  if ( clippedAngle >= 22.5 && clippedAngle < 67.5 )
64  {
65  return 45.0;
66  }
67  else if ( clippedAngle >= 67.5 && clippedAngle < 112.5 )
68  {
69  return 90.0;
70  }
71  else if ( clippedAngle >= 112.5 && clippedAngle < 157.5 )
72  {
73  return 135.0;
74  }
75  else if ( clippedAngle >= 157.5 && clippedAngle < 202.5 )
76  {
77  return 180.0;
78  }
79  else if ( clippedAngle >= 202.5 && clippedAngle < 247.5 )
80  {
81  return 225.0;
82  }
83  else if ( clippedAngle >= 247.5 && clippedAngle < 292.5 )
84  {
85  return 270.0;
86  }
87  else if ( clippedAngle >= 292.5 && clippedAngle < 337.5 )
88  {
89  return 315.0;
90  }
91  else
92  {
93  return 0.0;
94  }
95 }
96 
98 {
99  if ( !map )
100  {
101  QgsRenderContext context;
102  context.setPainter( painter );
103  if ( dpi < 0 && painter && painter->device() )
104  {
105  context.setScaleFactor( painter->device()->logicalDpiX() / 25.4 );
106  }
107  else if ( dpi > 0 )
108  {
109  context.setScaleFactor( dpi / 25.4 );
110  }
111  else
112  {
113  context.setScaleFactor( 3.465 ); //assume 88 dpi as standard value
114  }
115  return context;
116  }
117  else
118  {
119  // default to 88 dpi if no painter specified
120  if ( dpi < 0 )
121  {
122  dpi = ( painter && painter->device() ) ? painter->device()->logicalDpiX() : 88;
123  }
124  double dotsPerMM = dpi / 25.4;
125 
126  // get map settings from reference map
127  QgsRectangle extent = map->extent();
128  QSizeF mapSizeLayoutUnits = map->rect().size();
129  QSizeF mapSizeMM = map->layout()->convertFromLayoutUnits( mapSizeLayoutUnits, QgsUnitTypes::LayoutMillimeters ).toQSizeF();
130  QgsMapSettings ms = map->mapSettings( extent, mapSizeMM * dotsPerMM, dpi, false );
132  if ( painter )
133  context.setPainter( painter );
134 
135  context.setFlags( map->layout()->renderContext().renderContextFlags() );
137  return context;
138  }
139 }
140 
142 {
143  QgsLayoutItemMap *referenceMap = layout ? layout->referenceMap() : nullptr;
144  QgsRenderContext context = createRenderContextForMap( referenceMap, painter, dpi );
145  if ( layout )
146  {
147  context.setFlags( layout->renderContext().renderContextFlags() );
148  context.setTextRenderFormat( layout->renderContext().textRenderFormat() );
149  }
150 
151  return context;
152 }
153 
154 void QgsLayoutUtils::relativeResizeRect( QRectF &rectToResize, const QRectF &boundsBefore, const QRectF &boundsAfter )
155 {
156  //linearly scale rectToResize relative to the scaling from boundsBefore to boundsAfter
157  double left = relativePosition( rectToResize.left(), boundsBefore.left(), boundsBefore.right(), boundsAfter.left(), boundsAfter.right() );
158  double right = relativePosition( rectToResize.right(), boundsBefore.left(), boundsBefore.right(), boundsAfter.left(), boundsAfter.right() );
159  double top = relativePosition( rectToResize.top(), boundsBefore.top(), boundsBefore.bottom(), boundsAfter.top(), boundsAfter.bottom() );
160  double bottom = relativePosition( rectToResize.bottom(), boundsBefore.top(), boundsBefore.bottom(), boundsAfter.top(), boundsAfter.bottom() );
161 
162  rectToResize.setRect( left, top, right - left, bottom - top );
163 }
164 
165 double QgsLayoutUtils::relativePosition( const double position, const double beforeMin, const double beforeMax, const double afterMin, const double afterMax )
166 {
167  //calculate parameters for linear scale between before and after ranges
168  double m = ( afterMax - afterMin ) / ( beforeMax - beforeMin );
169  double c = afterMin - ( beforeMin * m );
170 
171  //return linearly scaled position
172  return m * position + c;
173 }
174 QFont QgsLayoutUtils::scaledFontPixelSize( const QFont &font )
175 {
176  //upscale using FONT_WORKAROUND_SCALE
177  //ref: http://osgeo-org.1560.x6.nabble.com/Multi-line-labels-and-font-bug-td4157152.html
178  QFont scaledFont = font;
179  double pixelSize = pointsToMM( scaledFont.pointSizeF() ) * FONT_WORKAROUND_SCALE + 0.5;
180  scaledFont.setPixelSize( pixelSize );
181  return scaledFont;
182 }
183 
184 double QgsLayoutUtils::fontAscentMM( const QFont &font )
185 {
186  //upscale using FONT_WORKAROUND_SCALE
187  //ref: http://osgeo-org.1560.x6.nabble.com/Multi-line-labels-and-font-bug-td4157152.html
188  QFont metricsFont = scaledFontPixelSize( font );
189  QFontMetricsF fontMetrics( metricsFont );
190  return ( fontMetrics.ascent() / FONT_WORKAROUND_SCALE );
191 }
192 
193 double QgsLayoutUtils::fontDescentMM( const QFont &font )
194 {
195  //upscale using FONT_WORKAROUND_SCALE
196  //ref: http://osgeo-org.1560.x6.nabble.com/Multi-line-labels-and-font-bug-td4157152.html
197  QFont metricsFont = scaledFontPixelSize( font );
198  QFontMetricsF fontMetrics( metricsFont );
199  return ( fontMetrics.descent() / FONT_WORKAROUND_SCALE );
200 
201 }
202 
203 double QgsLayoutUtils::fontHeightMM( const QFont &font )
204 {
205  //upscale using FONT_WORKAROUND_SCALE
206  //ref: http://osgeo-org.1560.x6.nabble.com/Multi-line-labels-and-font-bug-td4157152.html
207  QFont metricsFont = scaledFontPixelSize( font );
208  QFontMetricsF fontMetrics( metricsFont );
209  return ( fontMetrics.height() / FONT_WORKAROUND_SCALE );
210 
211 }
212 
213 double QgsLayoutUtils::fontHeightCharacterMM( const QFont &font, QChar character )
214 {
215  //upscale using FONT_WORKAROUND_SCALE
216  //ref: http://osgeo-org.1560.x6.nabble.com/Multi-line-labels-and-font-bug-td4157152.html
217  QFont metricsFont = scaledFontPixelSize( font );
218  QFontMetricsF fontMetrics( metricsFont );
219  return ( fontMetrics.boundingRect( character ).height() / FONT_WORKAROUND_SCALE );
220 }
221 
222 double QgsLayoutUtils::textWidthMM( const QFont &font, const QString &text )
223 {
224  //upscale using FONT_WORKAROUND_SCALE
225  //ref: http://osgeo-org.1560.x6.nabble.com/Multi-line-labels-and-font-bug-td4157152.html
226 
227  const QStringList multiLineSplit = text.split( '\n' );
228  QFont metricsFont = scaledFontPixelSize( font );
229  QFontMetricsF fontMetrics( metricsFont );
230 
231  double maxWidth = 0;
232  for ( const QString &line : multiLineSplit )
233  {
234  maxWidth = std::max( maxWidth, ( fontMetrics.horizontalAdvance( line ) / FONT_WORKAROUND_SCALE ) );
235  }
236  return maxWidth;
237 }
238 
239 double QgsLayoutUtils::textHeightMM( const QFont &font, const QString &text, double multiLineHeight )
240 {
241  QStringList multiLineSplit = text.split( '\n' );
242  int lines = multiLineSplit.size();
243 
244  //upscale using FONT_WORKAROUND_SCALE
245  //ref: http://osgeo-org.1560.x6.nabble.com/Multi-line-labels-and-font-bug-td4157152.html
246  QFont metricsFont = scaledFontPixelSize( font );
247  QFontMetricsF fontMetrics( metricsFont );
248 
249  double fontHeight = fontMetrics.ascent() + fontMetrics.descent(); // ignore +1 for baseline
250  double textHeight = fontMetrics.ascent() + static_cast< double >( ( lines - 1 ) * fontHeight * multiLineHeight );
251 
252  return textHeight / FONT_WORKAROUND_SCALE;
253 }
254 
255 void QgsLayoutUtils::drawText( QPainter *painter, QPointF position, const QString &text, const QFont &font, const QColor &color )
256 {
257  if ( !painter )
258  {
259  return;
260  }
261 
262  //upscale using FONT_WORKAROUND_SCALE
263  //ref: http://osgeo-org.1560.x6.nabble.com/Multi-line-labels-and-font-bug-td4157152.html
264  QFont textFont = scaledFontPixelSize( font );
265 
266  QgsScopedQPainterState painterState( painter );
267  painter->setFont( textFont );
268  if ( color.isValid() )
269  {
270  painter->setPen( color );
271  }
272  double scaleFactor = 1.0 / FONT_WORKAROUND_SCALE;
273  painter->scale( scaleFactor, scaleFactor );
274  painter->drawText( position * FONT_WORKAROUND_SCALE, text );
275 }
276 
277 void QgsLayoutUtils::drawText( QPainter *painter, const QRectF &rect, const QString &text, const QFont &font, const QColor &color, const Qt::AlignmentFlag halignment, const Qt::AlignmentFlag valignment, const int flags )
278 {
279  if ( !painter )
280  {
281  return;
282  }
283 
284  //upscale using FONT_WORKAROUND_SCALE
285  //ref: http://osgeo-org.1560.x6.nabble.com/Multi-line-labels-and-font-bug-td4157152.html
286  QFont textFont = scaledFontPixelSize( font );
287 
288  QRectF scaledRect( rect.x() * FONT_WORKAROUND_SCALE, rect.y() * FONT_WORKAROUND_SCALE,
289  rect.width() * FONT_WORKAROUND_SCALE, rect.height() * FONT_WORKAROUND_SCALE );
290 
291  QgsScopedQPainterState painterState( painter );
292  painter->setFont( textFont );
293  if ( color.isValid() )
294  {
295  painter->setPen( color );
296  }
297  double scaleFactor = 1.0 / FONT_WORKAROUND_SCALE;
298  painter->scale( scaleFactor, scaleFactor );
299  painter->drawText( scaledRect, halignment | valignment | flags, text );
300 }
301 
302 QRectF QgsLayoutUtils::largestRotatedRectWithinBounds( const QRectF &originalRect, const QRectF &boundsRect, const double rotation )
303 {
304  double originalWidth = originalRect.width();
305  double originalHeight = originalRect.height();
306  double boundsWidth = boundsRect.width();
307  double boundsHeight = boundsRect.height();
308  double ratioBoundsRect = boundsWidth / boundsHeight;
309 
310  double clippedRotation = normalizedAngle( rotation );
311 
312  //shortcut for some rotation values
313  if ( qgsDoubleNear( clippedRotation, 0.0 ) || qgsDoubleNear( clippedRotation, 90.0 ) || qgsDoubleNear( clippedRotation, 180.0 ) || qgsDoubleNear( clippedRotation, 270.0 ) )
314  {
315  double rectScale;
316  if ( qgsDoubleNear( clippedRotation, 0.0 ) || qgsDoubleNear( clippedRotation, 180.0 ) )
317  {
318  rectScale = ( ( originalWidth / originalHeight ) > ratioBoundsRect ) ? boundsWidth / originalWidth : boundsHeight / originalHeight;
319  }
320  else
321  {
322  rectScale = ( ( originalHeight / originalWidth ) > ratioBoundsRect ) ? boundsWidth / originalHeight : boundsHeight / originalWidth;
323  }
324  double rectScaledWidth = rectScale * originalWidth;
325  double rectScaledHeight = rectScale * originalHeight;
326 
327  if ( qgsDoubleNear( clippedRotation, 0.0 ) || qgsDoubleNear( clippedRotation, 180.0 ) )
328  {
329  return QRectF( ( boundsWidth - rectScaledWidth ) / 2.0, ( boundsHeight - rectScaledHeight ) / 2.0, rectScaledWidth, rectScaledHeight );
330  }
331  else
332  {
333  return QRectF( ( boundsWidth - rectScaledHeight ) / 2.0, ( boundsHeight - rectScaledWidth ) / 2.0, rectScaledWidth, rectScaledHeight );
334  }
335  }
336 
337  //convert angle to radians and flip
338  double angleRad = -clippedRotation * M_DEG2RAD;
339  double cosAngle = std::cos( angleRad );
340  double sinAngle = std::sin( angleRad );
341 
342  //calculate size of bounds of rotated rectangle
343  double widthBoundsRotatedRect = originalWidth * std::fabs( cosAngle ) + originalHeight * std::fabs( sinAngle );
344  double heightBoundsRotatedRect = originalHeight * std::fabs( cosAngle ) + originalWidth * std::fabs( sinAngle );
345 
346  //compare ratio of rotated rect with bounds rect and calculate scaling of rotated
347  //rect to fit within bounds
348  double ratioBoundsRotatedRect = widthBoundsRotatedRect / heightBoundsRotatedRect;
349  double rectScale = ratioBoundsRotatedRect > ratioBoundsRect ? boundsWidth / widthBoundsRotatedRect : boundsHeight / heightBoundsRotatedRect;
350  double rectScaledWidth = rectScale * originalWidth;
351  double rectScaledHeight = rectScale * originalHeight;
352 
353  //now calculate offset so that rotated rectangle is centered within bounds
354  //first calculate min x and y coordinates
355  double currentCornerX = 0;
356  double minX = 0;
357  currentCornerX += rectScaledWidth * cosAngle;
358  minX = minX < currentCornerX ? minX : currentCornerX;
359  currentCornerX += rectScaledHeight * sinAngle;
360  minX = minX < currentCornerX ? minX : currentCornerX;
361  currentCornerX -= rectScaledWidth * cosAngle;
362  minX = minX < currentCornerX ? minX : currentCornerX;
363 
364  double currentCornerY = 0;
365  double minY = 0;
366  currentCornerY -= rectScaledWidth * sinAngle;
367  minY = minY < currentCornerY ? minY : currentCornerY;
368  currentCornerY += rectScaledHeight * cosAngle;
369  minY = minY < currentCornerY ? minY : currentCornerY;
370  currentCornerY += rectScaledWidth * sinAngle;
371  minY = minY < currentCornerY ? minY : currentCornerY;
372 
373  //now calculate offset position of rotated rectangle
374  double offsetX = ratioBoundsRotatedRect > ratioBoundsRect ? 0 : ( boundsWidth - rectScale * widthBoundsRotatedRect ) / 2.0;
375  offsetX += std::fabs( minX );
376  double offsetY = ratioBoundsRotatedRect > ratioBoundsRect ? ( boundsHeight - rectScale * heightBoundsRotatedRect ) / 2.0 : 0;
377  offsetY += std::fabs( minY );
378 
379  return QRectF( offsetX, offsetY, rectScaledWidth, rectScaledHeight );
380 }
381 
383 {
384  QString s = string.trimmed();
385  if ( s.compare( QLatin1String( "Portrait" ), Qt::CaseInsensitive ) == 0 )
386  {
387  ok = true;
389  }
390  else if ( s.compare( QLatin1String( "Landscape" ), Qt::CaseInsensitive ) == 0 )
391  {
392  ok = true;
394  }
395  ok = false;
396  return QgsLayoutItemPage::Landscape; // default to landscape
397 }
398 
399 double QgsLayoutUtils::scaleFactorFromItemStyle( const QStyleOptionGraphicsItem *style )
400 {
401 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
402  // workaround Qt bug 66185
403 
404  // Refs #18027 - if a QGraphicsItem is rotated by 90 or 270 degrees, then the item
405  // style given to QGraphicsItem::paint incorrectly uses the shear parameter of the matrix (m12)
406  // to store the current view scale, instead of the horizontal scale parameter (m11) which
407  // is used in all other cases
408 
409  // TODO - ifdef this out if Qt fixes upstream
410  return !qgsDoubleNear( style->matrix.m11(), 0.0 ) ? style->matrix.m11() : style->matrix.m12();
411 #else
412  Q_UNUSED( style )
413  return 1;
414 #endif
415 }
416 
417 double QgsLayoutUtils::scaleFactorFromItemStyle( const QStyleOptionGraphicsItem *style, QPainter *painter )
418 {
419  return style->levelOfDetailFromTransform( painter->worldTransform() );
420 }
421 
422 QgsMapLayer *QgsLayoutUtils::mapLayerFromString( const QString &string, QgsProject *project )
423 {
424  // Maybe it's a layer id?
425  if ( QgsMapLayer *ml = project->mapLayer( string ) )
426  return ml;
427 
428  // Still nothing? Check for layer name
429  if ( QgsMapLayer *ml = project->mapLayersByName( string ).value( 0 ) )
430  return ml;
431 
432  // Still nothing? Check for layer name, case-insensitive
433  const auto layers = project->mapLayers();
434  for ( auto it = layers.constBegin(); it != layers.constEnd(); ++it )
435  {
436  if ( it.value()->name().compare( string, Qt::CaseInsensitive ) == 0 )
437  return it.value();
438  }
439 
440  return nullptr;
441 }
442 
443 // nextNiceNumber(4573.23, d) = 5000 (d=1) -> 4600 (d=10) -> 4580 (d=100) -> 4574 (d=1000) -> etc
444 inline double nextNiceNumber( double a, double d = 1 )
445 {
446  double s = std::pow( 10.0, std::floor( std::log10( a ) ) ) / d;
447  return std::ceil( a / s ) * s;
448 }
449 
450 // prevNiceNumber(4573.23, d) = 4000 (d=1) -> 4500 (d=10) -> 4570 (d=100) -> 4573 (d=1000) -> etc
451 inline double prevNiceNumber( double a, double d = 1 )
452 {
453  double s = std::pow( 10.0, std::floor( std::log10( a ) ) ) / d;
454  return std::floor( a / s ) * s;
455 }
456 
457 double QgsLayoutUtils::calculatePrettySize( const double minimumSize, const double maximumSize )
458 {
459  if ( maximumSize < minimumSize )
460  {
461  return 0;
462  }
463  else
464  {
465  // Start with coarsest "nice" number closest to minimumSize resp
466  // maximumSize, then proceed to finer numbers as long as neither
467  // lowerNiceUnitsPerSeg nor upperNiceUnitsPerSeg are in
468  // [minimumSize, maximumSize]
469  double lowerNiceUnitsPerSeg = nextNiceNumber( minimumSize );
470  double upperNiceUnitsPerSeg = prevNiceNumber( maximumSize );
471 
472  double d = 1;
473  while ( lowerNiceUnitsPerSeg > maximumSize && upperNiceUnitsPerSeg < minimumSize )
474  {
475  d *= 10;
476  lowerNiceUnitsPerSeg = nextNiceNumber( minimumSize, d );
477  upperNiceUnitsPerSeg = prevNiceNumber( maximumSize, d );
478  }
479 
480  // Pick size from {lowerNiceUnitsPerSeg, upperNiceUnitsPerSeg}, use the larger if possible
481  return upperNiceUnitsPerSeg < minimumSize ? lowerNiceUnitsPerSeg : upperNiceUnitsPerSeg;
482  }
483 }
484 
486 {
487  if ( !( item->itemFlags() & QgsLayoutItem::FlagProvidesClipPath ) )
488  return false; // not a clipping provider, so shortcut out
489 
490  // current only maps can be clipped
491  QList< QgsLayoutItemMap * > maps;
492  item->layout()->layoutItems( maps );
493  for ( QgsLayoutItemMap *map : std::as_const( maps ) )
494  {
495  if ( map->itemClippingSettings()->isActive() && map->itemClippingSettings()->sourceItem() == item )
496  return true;
497  }
498  return false;
499 }
500 
501 double QgsLayoutUtils::pointsToMM( const double pointSize )
502 {
503  //conversion to mm based on 1 point = 1/72 inch
504  return ( pointSize * 0.3527 );
505 }
506 
507 double QgsLayoutUtils::mmToPoints( const double mmSize )
508 {
509  //conversion to points based on 1 point = 1/72 inch
510  return ( mmSize / 0.3527 );
511 }
512 
513 QVector< double > QgsLayoutUtils::predefinedScales( const QgsLayout *layout )
514 {
515  QVector< double > mapScales;
516  if ( layout->project() )
517  mapScales = layout->project()->viewSettings()->mapScales();
518 
519  bool hasProjectScales( layout->project()->viewSettings()->useProjectScales() );
520  if ( !hasProjectScales || mapScales.isEmpty() )
521  {
522  // default to global map tool scales
523  QgsSettings settings;
524  QString scalesStr( settings.value( QStringLiteral( "Map/scales" ), Qgis::defaultProjectScales() ).toString() );
525  const QStringList scales = scalesStr.split( ',' );
526  for ( const QString &scale : scales )
527  {
528  QStringList parts( scale.split( ':' ) );
529  if ( parts.size() == 2 )
530  {
531  mapScales.push_back( parts[1].toDouble() );
532  }
533  }
534  }
535 
536  return mapScales;
537 }
static QString defaultProjectScales()
A string with default project scales.
Definition: qgis.cpp:279
Layout graphical items for displaying a map.
QgsMapSettings mapSettings(const QgsRectangle &extent, QSizeF size, double dpi, bool includeLayerSettings) const
Returns map settings that will be used for drawing of the map.
QgsRectangle extent() const
Returns the current map extent.
Orientation
Page orientation.
@ Landscape
Landscape orientation.
@ Portrait
Portrait orientation.
Base class for graphical items within a QgsLayout.
@ FlagProvidesClipPath
Item can act as a clipping path provider (see clipPath())
virtual Flags itemFlags() const
Returns the item's flags, which indicate how the item behaves.
const QgsLayout * layout() const
Returns the layout the object is attached to.
QgsRenderContext::Flags renderContextFlags() const
Returns the combination of render context flags matched to the layout context's settings.
QgsRenderContext::TextRenderFormat textRenderFormat() const
Returns the text render format, which dictates how text is rendered (e.g.
static QgsRenderContext createRenderContextForLayout(QgsLayout *layout, QPainter *painter, double dpi=-1)
Creates a render context suitable for the specified layout and painter destination.
static QVector< double > predefinedScales(const QgsLayout *layout)
Returns a list of predefined scales associated with a layout.
static double fontHeightMM(const QFont &font)
Calculate a font height in millimeters, including workarounds for QT font rendering issues.
static double relativePosition(double position, double beforeMin, double beforeMax, double afterMin, double afterMax)
Returns a scaled position given a before and after range.
static double fontDescentMM(const QFont &font)
Calculate a font descent in millimeters, including workarounds for QT font rendering issues.
static double fontAscentMM(const QFont &font)
Calculates a font ascent in millimeters, including workarounds for QT font rendering issues.
static QRectF largestRotatedRectWithinBounds(const QRectF &originalRect, const QRectF &boundsRect, double rotation)
Calculates the largest scaled version of originalRect which fits within boundsRect,...
static QFont scaledFontPixelSize(const QFont &font)
Returns a font where size is set in points and the size has been upscaled with FONT_WORKAROUND_SCALE ...
static QgsRenderContext createRenderContextForMap(QgsLayoutItemMap *map, QPainter *painter, double dpi=-1)
Creates a render context suitable for the specified layout map and painter destination.
static bool itemIsAClippingSource(const QgsLayoutItem *item)
Returns true if an item is a clipping item for another layout item.
static double snappedAngle(double angle)
Snaps an angle (in degrees) to its closest 45 degree angle.
static double textHeightMM(const QFont &font, const QString &text, double multiLineHeight=1.0)
Calculate a font height in millimeters for a text string, including workarounds for QT font rendering...
static QgsLayoutItemPage::Orientation decodePaperOrientation(const QString &string, bool &ok)
Decodes a string representing a paper orientation and returns the decoded orientation.
static void rotate(double angle, double &x, double &y)
Rotates a point / vector around the origin.
static double fontHeightCharacterMM(const QFont &font, QChar character)
Calculate a font height in millimeters of a single character, including workarounds for QT font rende...
static double normalizedAngle(double angle, bool allowNegative=false)
Ensures that an angle (in degrees) is in the range 0 <= angle < 360.
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...
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 ...
static double calculatePrettySize(double minimumSize, double maximumSize)
Calculates a "pretty" size which falls between the range [minimumSize, maximumSize].
static QgsMapLayer * mapLayerFromString(const QString &string, QgsProject *project)
Resolves a string into a map layer from a given project.
static Q_DECL_DEPRECATED double scaleFactorFromItemStyle(const QStyleOptionGraphicsItem *style)
Extracts the scale factor from an item style.
static void relativeResizeRect(QRectF &rectToResize, const QRectF &boundsBefore, const QRectF &boundsAfter)
Resizes a QRectF relative to a resized bounding rectangle.
Base class for layouts, which can contain items such as maps, labels, scalebars, etc.
Definition: qgslayout.h:51
QgsLayoutRenderContext & renderContext()
Returns a reference to the layout's render context, which stores information relating to the current ...
Definition: qgslayout.cpp:359
void layoutItems(QList< T * > &itemList) const
Returns a list of layout items of a specific type.
Definition: qgslayout.h:122
QgsLayoutItemMap * referenceMap() const
Returns the map item which will be used to generate corresponding world files when the layout is expo...
Definition: qgslayout.cpp:430
QgsLayoutMeasurement convertFromLayoutUnits(double length, QgsUnitTypes::LayoutUnit unit) const
Converts a length measurement from the layout's native units to a specified target unit.
Definition: qgslayout.cpp:344
QgsProject * project() const
The project associated with the layout.
Definition: qgslayout.cpp:132
Base class for all map layer types.
Definition: qgsmaplayer.h:70
The QgsMapSettings class contains configuration for rendering of the map.
bool useProjectScales() const
Returns true if project mapScales() are enabled.
QVector< double > mapScales() const
Returns the list of custom project map scales.
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
Definition: qgsproject.h:99
Q_INVOKABLE QgsMapLayer * mapLayer(const QString &layerId) const
Retrieve a pointer to a registered layer by layer ID.
QList< QgsMapLayer * > mapLayersByName(const QString &layerName) const
Retrieve a list of matching registered layers by layer name.
const QgsProjectViewSettings * viewSettings() const
Returns the project's view settings, which contains settings and properties relating to how a QgsProj...
QMap< QString, QgsMapLayer * > mapLayers(const bool validOnly=false) const
Returns a map of all registered layers by layer ID.
A rectangle specified with double values.
Definition: qgsrectangle.h:42
Contains information about the context of a rendering operation.
void setScaleFactor(double factor)
Sets the scaling factor for the render to convert painter units to physical sizes.
void setTextRenderFormat(TextRenderFormat format)
Sets the text render format, which dictates how text is rendered (e.g.
void setPainter(QPainter *p)
Sets the destination QPainter for the render operation.
static QgsRenderContext fromMapSettings(const QgsMapSettings &mapSettings)
create initialized QgsRenderContext instance from given QgsMapSettings
void setFlags(QgsRenderContext::Flags flags)
Set combination of flags that will be used for rendering.
Scoped object for saving and restoring a QPainter object's state.
@ LayoutMillimeters
Millimeters.
Definition: qgsunittypes.h:183
double ANALYSIS_EXPORT angle(QgsPoint *p1, QgsPoint *p2, QgsPoint *p3, QgsPoint *p4)
Calculates the angle between two segments (in 2 dimension, z-values are ignored)
Definition: MathUtils.cpp:786
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
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:598
double prevNiceNumber(double a, double d=1)
#define M_DEG2RAD
double nextNiceNumber(double a, double d=1)