QGIS API Documentation  3.23.0-Master (22c16f2067)
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  QgsProject *lProject = layout ? layout->project() : nullptr;
516  QVector< double > mapScales;
517  if ( lProject )
518  mapScales = lProject->viewSettings()->mapScales();
519 
520  bool hasProjectScales( lProject ? lProject->viewSettings()->useProjectScales() : false );
521  if ( !hasProjectScales || mapScales.isEmpty() )
522  {
523  // default to global map tool scales
524  QgsSettings settings;
525  QString scalesStr( settings.value( QStringLiteral( "Map/scales" ), Qgis::defaultProjectScales() ).toString() );
526  const QStringList scales = scalesStr.split( ',' );
527  for ( const QString &scale : scales )
528  {
529  QStringList parts( scale.split( ':' ) );
530  if ( parts.size() == 2 )
531  {
532  mapScales.push_back( parts[1].toDouble() );
533  }
534  }
535  }
536 
537  return mapScales;
538 }
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.
Qgis::TextRenderFormat textRenderFormat() const
Returns the text render format, which dictates how text is rendered (e.g.
Qgis::RenderContextFlags renderContextFlags() const
Returns the combination of render context flags matched to the layout context's settings.
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:73
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:101
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(Qgis::TextRenderFormat format)
Sets the text render format, which dictates how text is rendered (e.g.
void setFlags(Qgis::RenderContextFlags flags)
Set combination of flags that will be used for rendering.
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
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:1491
double prevNiceNumber(double a, double d=1)
#define M_DEG2RAD
double nextNiceNumber(double a, double d=1)