LCOV - code coverage report
Current view: top level - core/layout - qgslayoututils.cpp (source / functions) Hit Total Coverage
Test: coverage.info.cleaned Lines: 0 278 0.0 %
Date: 2021-03-26 12:19:53 Functions: 0 0 -
Branches: 0 0 -

           Branch data     Line data    Source code
       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                 :          0 : void QgsLayoutUtils::rotate( double angle, double &x, double &y )
      34                 :            : {
      35                 :          0 :   double rotToRad = angle * M_PI / 180.0;
      36                 :            :   double xRot, yRot;
      37                 :          0 :   xRot = x * std::cos( rotToRad ) - y * std::sin( rotToRad );
      38                 :          0 :   yRot = x * std::sin( rotToRad ) + y * std::cos( rotToRad );
      39                 :          0 :   x = xRot;
      40                 :          0 :   y = yRot;
      41                 :          0 : }
      42                 :            : 
      43                 :          0 : double QgsLayoutUtils::normalizedAngle( const double angle, const bool allowNegative )
      44                 :            : {
      45                 :          0 :   double clippedAngle = angle;
      46                 :          0 :   if ( clippedAngle >= 360.0 || clippedAngle <= -360.0 )
      47                 :            :   {
      48                 :          0 :     clippedAngle = std::fmod( clippedAngle, 360.0 );
      49                 :          0 :   }
      50                 :          0 :   if ( !allowNegative && clippedAngle < 0.0 )
      51                 :            :   {
      52                 :          0 :     clippedAngle += 360.0;
      53                 :          0 :   }
      54                 :          0 :   return clippedAngle;
      55                 :            : }
      56                 :            : 
      57                 :          0 : double QgsLayoutUtils::snappedAngle( double angle )
      58                 :            : {
      59                 :            :   //normalize angle to 0-360 degrees
      60                 :          0 :   double clippedAngle = normalizedAngle( angle );
      61                 :            : 
      62                 :            :   //snap angle to 45 degree
      63                 :          0 :   if ( clippedAngle >= 22.5 && clippedAngle < 67.5 )
      64                 :            :   {
      65                 :          0 :     return 45.0;
      66                 :            :   }
      67                 :          0 :   else if ( clippedAngle >= 67.5 && clippedAngle < 112.5 )
      68                 :            :   {
      69                 :          0 :     return 90.0;
      70                 :            :   }
      71                 :          0 :   else if ( clippedAngle >= 112.5 && clippedAngle < 157.5 )
      72                 :            :   {
      73                 :          0 :     return 135.0;
      74                 :            :   }
      75                 :          0 :   else if ( clippedAngle >= 157.5 && clippedAngle < 202.5 )
      76                 :            :   {
      77                 :          0 :     return 180.0;
      78                 :            :   }
      79                 :          0 :   else if ( clippedAngle >= 202.5 && clippedAngle < 247.5 )
      80                 :            :   {
      81                 :          0 :     return 225.0;
      82                 :            :   }
      83                 :          0 :   else if ( clippedAngle >= 247.5 && clippedAngle < 292.5 )
      84                 :            :   {
      85                 :          0 :     return 270.0;
      86                 :            :   }
      87                 :          0 :   else if ( clippedAngle >= 292.5 && clippedAngle < 337.5 )
      88                 :            :   {
      89                 :          0 :     return 315.0;
      90                 :            :   }
      91                 :            :   else
      92                 :            :   {
      93                 :          0 :     return 0.0;
      94                 :            :   }
      95                 :          0 : }
      96                 :            : 
      97                 :          0 : QgsRenderContext QgsLayoutUtils::createRenderContextForMap( QgsLayoutItemMap *map, QPainter *painter, double dpi )
      98                 :            : {
      99                 :          0 :   if ( !map )
     100                 :            :   {
     101                 :          0 :     QgsRenderContext context;
     102                 :          0 :     context.setPainter( painter );
     103                 :          0 :     if ( dpi < 0 && painter && painter->device() )
     104                 :            :     {
     105                 :          0 :       context.setScaleFactor( painter->device()->logicalDpiX() / 25.4 );
     106                 :          0 :     }
     107                 :          0 :     else if ( dpi > 0 )
     108                 :            :     {
     109                 :          0 :       context.setScaleFactor( dpi / 25.4 );
     110                 :          0 :     }
     111                 :            :     else
     112                 :            :     {
     113                 :          0 :       context.setScaleFactor( 3.465 ); //assume 88 dpi as standard value
     114                 :            :     }
     115                 :          0 :     return context;
     116                 :          0 :   }
     117                 :            :   else
     118                 :            :   {
     119                 :            :     // default to 88 dpi if no painter specified
     120                 :          0 :     if ( dpi < 0 )
     121                 :            :     {
     122                 :          0 :       dpi = ( painter && painter->device() ) ? painter->device()->logicalDpiX() : 88;
     123                 :          0 :     }
     124                 :          0 :     double dotsPerMM = dpi / 25.4;
     125                 :            : 
     126                 :            :     // get map settings from reference map
     127                 :          0 :     QgsRectangle extent = map->extent();
     128                 :          0 :     QSizeF mapSizeLayoutUnits = map->rect().size();
     129                 :          0 :     QSizeF mapSizeMM = map->layout()->convertFromLayoutUnits( mapSizeLayoutUnits, QgsUnitTypes::LayoutMillimeters ).toQSizeF();
     130                 :          0 :     QgsMapSettings ms = map->mapSettings( extent, mapSizeMM * dotsPerMM, dpi, false );
     131                 :          0 :     QgsRenderContext context = QgsRenderContext::fromMapSettings( ms );
     132                 :          0 :     if ( painter )
     133                 :          0 :       context.setPainter( painter );
     134                 :            : 
     135                 :          0 :     context.setFlags( map->layout()->renderContext().renderContextFlags() );
     136                 :          0 :     context.setTextRenderFormat( map->layout()->renderContext().textRenderFormat() );
     137                 :          0 :     return context;
     138                 :          0 :   }
     139                 :          0 : }
     140                 :            : 
     141                 :          0 : QgsRenderContext QgsLayoutUtils::createRenderContextForLayout( QgsLayout *layout, QPainter *painter, double dpi )
     142                 :            : {
     143                 :          0 :   QgsLayoutItemMap *referenceMap = layout ? layout->referenceMap() : nullptr;
     144                 :          0 :   QgsRenderContext context = createRenderContextForMap( referenceMap, painter, dpi );
     145                 :          0 :   if ( layout )
     146                 :            :   {
     147                 :          0 :     context.setFlags( layout->renderContext().renderContextFlags() );
     148                 :          0 :     context.setTextRenderFormat( layout->renderContext().textRenderFormat() );
     149                 :          0 :   }
     150                 :            : 
     151                 :          0 :   return context;
     152                 :          0 : }
     153                 :            : 
     154                 :          0 : 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                 :          0 :   double left = relativePosition( rectToResize.left(), boundsBefore.left(), boundsBefore.right(), boundsAfter.left(), boundsAfter.right() );
     158                 :          0 :   double right = relativePosition( rectToResize.right(), boundsBefore.left(), boundsBefore.right(), boundsAfter.left(), boundsAfter.right() );
     159                 :          0 :   double top = relativePosition( rectToResize.top(), boundsBefore.top(), boundsBefore.bottom(), boundsAfter.top(), boundsAfter.bottom() );
     160                 :          0 :   double bottom = relativePosition( rectToResize.bottom(), boundsBefore.top(), boundsBefore.bottom(), boundsAfter.top(), boundsAfter.bottom() );
     161                 :            : 
     162                 :          0 :   rectToResize.setRect( left, top, right - left, bottom - top );
     163                 :          0 : }
     164                 :            : 
     165                 :          0 : 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                 :          0 :   double m = ( afterMax - afterMin ) / ( beforeMax - beforeMin );
     169                 :          0 :   double c = afterMin - ( beforeMin * m );
     170                 :            : 
     171                 :            :   //return linearly scaled position
     172                 :          0 :   return m * position + c;
     173                 :            : }
     174                 :          0 : 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                 :          0 :   QFont scaledFont = font;
     179                 :          0 :   double pixelSize = pointsToMM( scaledFont.pointSizeF() ) * FONT_WORKAROUND_SCALE + 0.5;
     180                 :          0 :   scaledFont.setPixelSize( pixelSize );
     181                 :          0 :   return scaledFont;
     182                 :          0 : }
     183                 :            : 
     184                 :          0 : 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                 :          0 :   QFont metricsFont = scaledFontPixelSize( font );
     189                 :          0 :   QFontMetricsF fontMetrics( metricsFont );
     190                 :          0 :   return ( fontMetrics.ascent() / FONT_WORKAROUND_SCALE );
     191                 :          0 : }
     192                 :            : 
     193                 :          0 : 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                 :          0 :   QFont metricsFont = scaledFontPixelSize( font );
     198                 :          0 :   QFontMetricsF fontMetrics( metricsFont );
     199                 :          0 :   return ( fontMetrics.descent() / FONT_WORKAROUND_SCALE );
     200                 :            : 
     201                 :          0 : }
     202                 :            : 
     203                 :          0 : 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                 :          0 :   QFont metricsFont = scaledFontPixelSize( font );
     208                 :          0 :   QFontMetricsF fontMetrics( metricsFont );
     209                 :          0 :   return ( fontMetrics.height() / FONT_WORKAROUND_SCALE );
     210                 :            : 
     211                 :          0 : }
     212                 :            : 
     213                 :          0 : 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                 :          0 :   QFont metricsFont = scaledFontPixelSize( font );
     218                 :          0 :   QFontMetricsF fontMetrics( metricsFont );
     219                 :          0 :   return ( fontMetrics.boundingRect( character ).height() / FONT_WORKAROUND_SCALE );
     220                 :          0 : }
     221                 :            : 
     222                 :          0 : 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                 :          0 :   const QStringList multiLineSplit = text.split( '\n' );
     228                 :          0 :   QFont metricsFont = scaledFontPixelSize( font );
     229                 :          0 :   QFontMetricsF fontMetrics( metricsFont );
     230                 :            : 
     231                 :          0 :   double maxWidth = 0;
     232                 :          0 :   for ( const QString &line : multiLineSplit )
     233                 :            :   {
     234                 :          0 :     maxWidth = std::max( maxWidth, ( fontMetrics.horizontalAdvance( line ) / FONT_WORKAROUND_SCALE ) );
     235                 :            :   }
     236                 :          0 :   return maxWidth;
     237                 :          0 : }
     238                 :            : 
     239                 :          0 : double QgsLayoutUtils::textHeightMM( const QFont &font, const QString &text, double multiLineHeight )
     240                 :            : {
     241                 :          0 :   QStringList multiLineSplit = text.split( '\n' );
     242                 :          0 :   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                 :          0 :   QFont metricsFont = scaledFontPixelSize( font );
     247                 :          0 :   QFontMetricsF fontMetrics( metricsFont );
     248                 :            : 
     249                 :          0 :   double fontHeight = fontMetrics.ascent() + fontMetrics.descent(); // ignore +1 for baseline
     250                 :          0 :   double textHeight = fontMetrics.ascent() + static_cast< double >( ( lines - 1 ) * fontHeight * multiLineHeight );
     251                 :            : 
     252                 :          0 :   return textHeight / FONT_WORKAROUND_SCALE;
     253                 :          0 : }
     254                 :            : 
     255                 :          0 : void QgsLayoutUtils::drawText( QPainter *painter, QPointF position, const QString &text, const QFont &font, const QColor &color )
     256                 :            : {
     257                 :          0 :   if ( !painter )
     258                 :            :   {
     259                 :          0 :     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                 :          0 :   QFont textFont = scaledFontPixelSize( font );
     265                 :            : 
     266                 :          0 :   QgsScopedQPainterState painterState( painter );
     267                 :          0 :   painter->setFont( textFont );
     268                 :          0 :   if ( color.isValid() )
     269                 :            :   {
     270                 :          0 :     painter->setPen( color );
     271                 :          0 :   }
     272                 :          0 :   double scaleFactor = 1.0 / FONT_WORKAROUND_SCALE;
     273                 :          0 :   painter->scale( scaleFactor, scaleFactor );
     274                 :          0 :   painter->drawText( position * FONT_WORKAROUND_SCALE, text );
     275                 :          0 : }
     276                 :            : 
     277                 :          0 : 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                 :          0 :   if ( !painter )
     280                 :            :   {
     281                 :          0 :     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                 :          0 :   QFont textFont = scaledFontPixelSize( font );
     287                 :            : 
     288                 :          0 :   QRectF scaledRect( rect.x() * FONT_WORKAROUND_SCALE, rect.y() * FONT_WORKAROUND_SCALE,
     289                 :          0 :                      rect.width() * FONT_WORKAROUND_SCALE, rect.height() * FONT_WORKAROUND_SCALE );
     290                 :            : 
     291                 :          0 :   QgsScopedQPainterState painterState( painter );
     292                 :          0 :   painter->setFont( textFont );
     293                 :          0 :   if ( color.isValid() )
     294                 :            :   {
     295                 :          0 :     painter->setPen( color );
     296                 :          0 :   }
     297                 :          0 :   double scaleFactor = 1.0 / FONT_WORKAROUND_SCALE;
     298                 :          0 :   painter->scale( scaleFactor, scaleFactor );
     299                 :          0 :   painter->drawText( scaledRect, halignment | valignment | flags, text );
     300                 :          0 : }
     301                 :            : 
     302                 :          0 : QRectF QgsLayoutUtils::largestRotatedRectWithinBounds( const QRectF &originalRect, const QRectF &boundsRect, const double rotation )
     303                 :            : {
     304                 :          0 :   double originalWidth = originalRect.width();
     305                 :          0 :   double originalHeight = originalRect.height();
     306                 :          0 :   double boundsWidth = boundsRect.width();
     307                 :          0 :   double boundsHeight = boundsRect.height();
     308                 :          0 :   double ratioBoundsRect = boundsWidth / boundsHeight;
     309                 :            : 
     310                 :          0 :   double clippedRotation = normalizedAngle( rotation );
     311                 :            : 
     312                 :            :   //shortcut for some rotation values
     313                 :          0 :   if ( qgsDoubleNear( clippedRotation, 0.0 ) || qgsDoubleNear( clippedRotation, 90.0 ) || qgsDoubleNear( clippedRotation, 180.0 ) || qgsDoubleNear( clippedRotation, 270.0 ) )
     314                 :            :   {
     315                 :            :     double rectScale;
     316                 :          0 :     if ( qgsDoubleNear( clippedRotation, 0.0 ) || qgsDoubleNear( clippedRotation, 180.0 ) )
     317                 :            :     {
     318                 :          0 :       rectScale = ( ( originalWidth / originalHeight ) > ratioBoundsRect ) ? boundsWidth / originalWidth : boundsHeight / originalHeight;
     319                 :          0 :     }
     320                 :            :     else
     321                 :            :     {
     322                 :          0 :       rectScale = ( ( originalHeight / originalWidth ) > ratioBoundsRect ) ? boundsWidth / originalHeight : boundsHeight / originalWidth;
     323                 :            :     }
     324                 :          0 :     double rectScaledWidth = rectScale * originalWidth;
     325                 :          0 :     double rectScaledHeight = rectScale * originalHeight;
     326                 :            : 
     327                 :          0 :     if ( qgsDoubleNear( clippedRotation, 0.0 ) || qgsDoubleNear( clippedRotation, 180.0 ) )
     328                 :            :     {
     329                 :          0 :       return QRectF( ( boundsWidth - rectScaledWidth ) / 2.0, ( boundsHeight - rectScaledHeight ) / 2.0, rectScaledWidth, rectScaledHeight );
     330                 :            :     }
     331                 :            :     else
     332                 :            :     {
     333                 :          0 :       return QRectF( ( boundsWidth - rectScaledHeight ) / 2.0, ( boundsHeight - rectScaledWidth ) / 2.0, rectScaledWidth, rectScaledHeight );
     334                 :            :     }
     335                 :            :   }
     336                 :            : 
     337                 :            :   //convert angle to radians and flip
     338                 :          0 :   double angleRad = -clippedRotation * M_DEG2RAD;
     339                 :          0 :   double cosAngle = std::cos( angleRad );
     340                 :          0 :   double sinAngle = std::sin( angleRad );
     341                 :            : 
     342                 :            :   //calculate size of bounds of rotated rectangle
     343                 :          0 :   double widthBoundsRotatedRect = originalWidth * std::fabs( cosAngle ) + originalHeight * std::fabs( sinAngle );
     344                 :          0 :   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                 :          0 :   double ratioBoundsRotatedRect = widthBoundsRotatedRect / heightBoundsRotatedRect;
     349                 :          0 :   double rectScale = ratioBoundsRotatedRect > ratioBoundsRect ? boundsWidth / widthBoundsRotatedRect : boundsHeight / heightBoundsRotatedRect;
     350                 :          0 :   double rectScaledWidth = rectScale * originalWidth;
     351                 :          0 :   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                 :          0 :   double currentCornerX = 0;
     356                 :          0 :   double minX = 0;
     357                 :          0 :   currentCornerX += rectScaledWidth * cosAngle;
     358                 :          0 :   minX = minX < currentCornerX ? minX : currentCornerX;
     359                 :          0 :   currentCornerX += rectScaledHeight * sinAngle;
     360                 :          0 :   minX = minX < currentCornerX ? minX : currentCornerX;
     361                 :          0 :   currentCornerX -= rectScaledWidth * cosAngle;
     362                 :          0 :   minX = minX < currentCornerX ? minX : currentCornerX;
     363                 :            : 
     364                 :          0 :   double currentCornerY = 0;
     365                 :          0 :   double minY = 0;
     366                 :          0 :   currentCornerY -= rectScaledWidth * sinAngle;
     367                 :          0 :   minY = minY < currentCornerY ? minY : currentCornerY;
     368                 :          0 :   currentCornerY += rectScaledHeight * cosAngle;
     369                 :          0 :   minY = minY < currentCornerY ? minY : currentCornerY;
     370                 :          0 :   currentCornerY += rectScaledWidth * sinAngle;
     371                 :          0 :   minY = minY < currentCornerY ? minY : currentCornerY;
     372                 :            : 
     373                 :            :   //now calculate offset position of rotated rectangle
     374                 :          0 :   double offsetX = ratioBoundsRotatedRect > ratioBoundsRect ? 0 : ( boundsWidth - rectScale * widthBoundsRotatedRect ) / 2.0;
     375                 :          0 :   offsetX += std::fabs( minX );
     376                 :          0 :   double offsetY = ratioBoundsRotatedRect > ratioBoundsRect ? ( boundsHeight - rectScale * heightBoundsRotatedRect ) / 2.0 : 0;
     377                 :          0 :   offsetY += std::fabs( minY );
     378                 :            : 
     379                 :          0 :   return QRectF( offsetX, offsetY, rectScaledWidth, rectScaledHeight );
     380                 :          0 : }
     381                 :            : 
     382                 :          0 : QgsLayoutItemPage::Orientation QgsLayoutUtils::decodePaperOrientation( const QString &string, bool &ok )
     383                 :            : {
     384                 :          0 :   QString s = string.trimmed();
     385                 :          0 :   if ( s.compare( QLatin1String( "Portrait" ), Qt::CaseInsensitive ) == 0 )
     386                 :            :   {
     387                 :          0 :     ok = true;
     388                 :          0 :     return QgsLayoutItemPage::Portrait;
     389                 :            :   }
     390                 :          0 :   else if ( s.compare( QLatin1String( "Landscape" ), Qt::CaseInsensitive ) == 0 )
     391                 :            :   {
     392                 :          0 :     ok = true;
     393                 :          0 :     return QgsLayoutItemPage::Landscape;
     394                 :            :   }
     395                 :          0 :   ok = false;
     396                 :          0 :   return QgsLayoutItemPage::Landscape; // default to landscape
     397                 :          0 : }
     398                 :            : 
     399                 :          0 : double QgsLayoutUtils::scaleFactorFromItemStyle( const QStyleOptionGraphicsItem *style )
     400                 :            : {
     401                 :            :   // workaround Qt bug 66185
     402                 :            : 
     403                 :            :   // Refs #18027 - if a QGraphicsItem is rotated by 90 or 270 degrees, then the item
     404                 :            :   // style given to QGraphicsItem::paint incorrectly uses the shear parameter of the matrix (m12)
     405                 :            :   // to store the current view scale, instead of the horizontal scale parameter (m11) which
     406                 :            :   // is used in all other cases
     407                 :            : 
     408                 :            :   // TODO - ifdef this out if Qt fixes upstream
     409                 :          0 :   return !qgsDoubleNear( style->matrix.m11(), 0.0 ) ? style->matrix.m11() : style->matrix.m12();
     410                 :            : }
     411                 :            : 
     412                 :          0 : QgsMapLayer *QgsLayoutUtils::mapLayerFromString( const QString &string, QgsProject *project )
     413                 :            : {
     414                 :            :   // Maybe it's a layer id?
     415                 :          0 :   if ( QgsMapLayer *ml = project->mapLayer( string ) )
     416                 :          0 :     return ml;
     417                 :            : 
     418                 :            :   // Still nothing? Check for layer name
     419                 :          0 :   if ( QgsMapLayer *ml = project->mapLayersByName( string ).value( 0 ) )
     420                 :          0 :     return ml;
     421                 :            : 
     422                 :            :   // Still nothing? Check for layer name, case-insensitive
     423                 :          0 :   const auto layers = project->mapLayers();
     424                 :          0 :   for ( auto it = layers.constBegin(); it != layers.constEnd(); ++it )
     425                 :            :   {
     426                 :          0 :     if ( it.value()->name().compare( string, Qt::CaseInsensitive ) == 0 )
     427                 :          0 :       return it.value();
     428                 :          0 :   }
     429                 :            : 
     430                 :          0 :   return nullptr;
     431                 :          0 : }
     432                 :            : 
     433                 :            : // nextNiceNumber(4573.23, d) = 5000 (d=1) -> 4600 (d=10) -> 4580 (d=100) -> 4574 (d=1000) -> etc
     434                 :          0 : inline double nextNiceNumber( double a, double d = 1 )
     435                 :            : {
     436                 :          0 :   double s = std::pow( 10.0, std::floor( std::log10( a ) ) ) / d;
     437                 :          0 :   return std::ceil( a / s ) * s;
     438                 :            : }
     439                 :            : 
     440                 :            : // prevNiceNumber(4573.23, d) = 4000 (d=1) -> 4500 (d=10) -> 4570 (d=100) -> 4573 (d=1000) -> etc
     441                 :          0 : inline double prevNiceNumber( double a, double d = 1 )
     442                 :            : {
     443                 :          0 :   double s = std::pow( 10.0, std::floor( std::log10( a ) ) ) / d;
     444                 :          0 :   return std::floor( a / s ) * s;
     445                 :            : }
     446                 :            : 
     447                 :          0 : double QgsLayoutUtils::calculatePrettySize( const double minimumSize, const double maximumSize )
     448                 :            : {
     449                 :          0 :   if ( maximumSize < minimumSize )
     450                 :            :   {
     451                 :          0 :     return 0;
     452                 :            :   }
     453                 :            :   else
     454                 :            :   {
     455                 :            :     // Start with coarsest "nice" number closest to minimumSize resp
     456                 :            :     // maximumSize, then proceed to finer numbers as long as neither
     457                 :            :     // lowerNiceUnitsPerSeg nor upperNiceUnitsPerSeg are in
     458                 :            :     // [minimumSize, maximumSize]
     459                 :          0 :     double lowerNiceUnitsPerSeg = nextNiceNumber( minimumSize );
     460                 :          0 :     double upperNiceUnitsPerSeg = prevNiceNumber( maximumSize );
     461                 :            : 
     462                 :          0 :     double d = 1;
     463                 :          0 :     while ( lowerNiceUnitsPerSeg > maximumSize && upperNiceUnitsPerSeg < minimumSize )
     464                 :            :     {
     465                 :          0 :       d *= 10;
     466                 :          0 :       lowerNiceUnitsPerSeg = nextNiceNumber( minimumSize, d );
     467                 :          0 :       upperNiceUnitsPerSeg = prevNiceNumber( maximumSize, d );
     468                 :            :     }
     469                 :            : 
     470                 :            :     // Pick size from {lowerNiceUnitsPerSeg, upperNiceUnitsPerSeg}, use the larger if possible
     471                 :          0 :     return upperNiceUnitsPerSeg < minimumSize ? lowerNiceUnitsPerSeg : upperNiceUnitsPerSeg;
     472                 :            :   }
     473                 :          0 : }
     474                 :            : 
     475                 :          0 : bool QgsLayoutUtils::itemIsAClippingSource( const QgsLayoutItem *item )
     476                 :            : {
     477                 :          0 :   if ( !( item->itemFlags() & QgsLayoutItem::FlagProvidesClipPath ) )
     478                 :          0 :     return false; // not a clipping provider, so shortcut out
     479                 :            : 
     480                 :            :   // current only maps can be clipped
     481                 :          0 :   QList< QgsLayoutItemMap * > maps;
     482                 :          0 :   item->layout()->layoutItems( maps );
     483                 :          0 :   for ( QgsLayoutItemMap *map : std::as_const( maps ) )
     484                 :            :   {
     485                 :          0 :     if ( map->itemClippingSettings()->isActive() && map->itemClippingSettings()->sourceItem() == item )
     486                 :          0 :       return true;
     487                 :            :   }
     488                 :          0 :   return false;
     489                 :          0 : }
     490                 :            : 
     491                 :          0 : double QgsLayoutUtils::pointsToMM( const double pointSize )
     492                 :            : {
     493                 :            :   //conversion to mm based on 1 point = 1/72 inch
     494                 :          0 :   return ( pointSize * 0.3527 );
     495                 :            : }
     496                 :            : 
     497                 :          0 : double QgsLayoutUtils::mmToPoints( const double mmSize )
     498                 :            : {
     499                 :            :   //conversion to points based on 1 point = 1/72 inch
     500                 :          0 :   return ( mmSize / 0.3527 );
     501                 :            : }
     502                 :            : 
     503                 :          0 : QVector< double > QgsLayoutUtils::predefinedScales( const QgsLayout *layout )
     504                 :            : {
     505                 :          0 :   QVector< double > mapScales;
     506                 :          0 :   if ( layout->project() )
     507                 :          0 :     mapScales = layout->project()->viewSettings()->mapScales();
     508                 :            : 
     509                 :          0 :   bool hasProjectScales( layout->project()->viewSettings()->useProjectScales() );
     510                 :          0 :   if ( !hasProjectScales || mapScales.isEmpty() )
     511                 :            :   {
     512                 :            :     // default to global map tool scales
     513                 :          0 :     QgsSettings settings;
     514                 :          0 :     QString scalesStr( settings.value( QStringLiteral( "Map/scales" ), Qgis::defaultProjectScales() ).toString() );
     515                 :          0 :     const QStringList scales = scalesStr.split( ',' );
     516                 :          0 :     for ( const QString &scale : scales )
     517                 :            :     {
     518                 :          0 :       QStringList parts( scale.split( ':' ) );
     519                 :          0 :       if ( parts.size() == 2 )
     520                 :            :       {
     521                 :          0 :         mapScales.push_back( parts[1].toDouble() );
     522                 :          0 :       }
     523                 :          0 :     }
     524                 :          0 :   }
     525                 :            : 
     526                 :          0 :   return mapScales;
     527                 :          0 : }

Generated by: LCOV version 1.14