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

           Branch data     Line data    Source code
       1                 :            : /***************************************************************************
       2                 :            :                          qgslayoutitempolyline.cpp
       3                 :            :     begin                : March 2016
       4                 :            :     copyright            : (C) 2016 Paul Blottiere, Oslandia
       5                 :            :      email                : paul dot blottiere at oslandia dot com
       6                 :            :  ***************************************************************************/
       7                 :            : 
       8                 :            : /***************************************************************************
       9                 :            :  *                                                                         *
      10                 :            :  *   This program is free software; you can redistribute it and/or modify  *
      11                 :            :  *   it under the terms of the GNU General Public License as published by  *
      12                 :            :  *   the Free Software Foundation; either version 2 of the License, or     *
      13                 :            :  *   (at your option) any later version.                                   *
      14                 :            :  *                                                                         *
      15                 :            :  ***************************************************************************/
      16                 :            : 
      17                 :            : #include "qgslayoutitempolyline.h"
      18                 :            : #include "qgslayoutitemregistry.h"
      19                 :            : #include "qgssymbollayerutils.h"
      20                 :            : #include "qgssymbol.h"
      21                 :            : #include "qgslayout.h"
      22                 :            : #include "qgsmapsettings.h"
      23                 :            : #include "qgslayoututils.h"
      24                 :            : #include "qgsreadwritecontext.h"
      25                 :            : #include "qgssvgcache.h"
      26                 :            : #include "qgsstyleentityvisitor.h"
      27                 :            : #include <QSvgRenderer>
      28                 :            : #include <limits>
      29                 :            : #include <QGraphicsPathItem>
      30                 :            : #include <QVector2D>
      31                 :            : 
      32                 :          0 : QgsLayoutItemPolyline::QgsLayoutItemPolyline( QgsLayout *layout )
      33                 :          0 :   : QgsLayoutNodesItem( layout )
      34                 :          0 : {
      35                 :          0 :   createDefaultPolylineStyleSymbol();
      36                 :          0 : }
      37                 :            : 
      38                 :          0 : QgsLayoutItemPolyline::QgsLayoutItemPolyline( const QPolygonF &polyline, QgsLayout *layout )
      39                 :          0 :   : QgsLayoutNodesItem( polyline, layout )
      40                 :          0 : {
      41                 :          0 :   createDefaultPolylineStyleSymbol();
      42                 :          0 : }
      43                 :            : 
      44                 :          0 : QgsLayoutItemPolyline *QgsLayoutItemPolyline::create( QgsLayout *layout )
      45                 :            : {
      46                 :          0 :   return new QgsLayoutItemPolyline( layout );
      47                 :          0 : }
      48                 :            : 
      49                 :          0 : int QgsLayoutItemPolyline::type() const
      50                 :            : {
      51                 :          0 :   return QgsLayoutItemRegistry::LayoutPolyline;
      52                 :            : }
      53                 :            : 
      54                 :          0 : QIcon QgsLayoutItemPolyline::icon() const
      55                 :            : {
      56                 :          0 :   return QgsApplication::getThemeIcon( QStringLiteral( "/mLayoutItemPolyline.svg" ) );
      57                 :          0 : }
      58                 :            : 
      59                 :          0 : bool QgsLayoutItemPolyline::_addNode( const int indexPoint,
      60                 :            :                                       QPointF newPoint,
      61                 :            :                                       const double radius )
      62                 :            : {
      63                 :          0 :   const double distStart = computeDistance( newPoint, mPolygon[0] );
      64                 :          0 :   const double distEnd = computeDistance( newPoint, mPolygon[mPolygon.size() - 1] );
      65                 :            : 
      66                 :          0 :   if ( indexPoint == ( mPolygon.size() - 1 ) )
      67                 :            :   {
      68                 :          0 :     if ( distEnd < radius )
      69                 :          0 :       mPolygon.append( newPoint );
      70                 :          0 :     else if ( distStart < radius )
      71                 :          0 :       mPolygon.insert( 0, newPoint );
      72                 :          0 :   }
      73                 :            :   else
      74                 :          0 :     mPolygon.insert( indexPoint + 1, newPoint );
      75                 :            : 
      76                 :          0 :   return true;
      77                 :            : }
      78                 :            : 
      79                 :          0 : bool QgsLayoutItemPolyline::_removeNode( const int index )
      80                 :            : {
      81                 :          0 :   if ( index < 0 || index >= mPolygon.size() )
      82                 :          0 :     return false;
      83                 :            : 
      84                 :          0 :   mPolygon.remove( index );
      85                 :            : 
      86                 :          0 :   if ( mPolygon.size() < 2 )
      87                 :          0 :     mPolygon.clear();
      88                 :            :   else
      89                 :            :   {
      90                 :          0 :     int newSelectNode = index;
      91                 :          0 :     if ( index >= mPolygon.size() )
      92                 :          0 :       newSelectNode = mPolygon.size() - 1;
      93                 :          0 :     setSelectedNode( newSelectNode );
      94                 :            :   }
      95                 :            : 
      96                 :          0 :   return true;
      97                 :          0 : }
      98                 :            : 
      99                 :          0 : void QgsLayoutItemPolyline::createDefaultPolylineStyleSymbol()
     100                 :            : {
     101                 :          0 :   QVariantMap properties;
     102                 :          0 :   properties.insert( QStringLiteral( "color" ), QStringLiteral( "0,0,0,255" ) );
     103                 :          0 :   properties.insert( QStringLiteral( "width" ), QStringLiteral( "0.3" ) );
     104                 :          0 :   properties.insert( QStringLiteral( "capstyle" ), QStringLiteral( "square" ) );
     105                 :            : 
     106                 :          0 :   mPolylineStyleSymbol.reset( QgsLineSymbol::createSimple( properties ) );
     107                 :          0 :   refreshSymbol();
     108                 :          0 : }
     109                 :            : 
     110                 :          0 : void QgsLayoutItemPolyline::refreshSymbol()
     111                 :            : {
     112                 :          0 :   if ( auto *lLayout = layout() )
     113                 :            :   {
     114                 :          0 :     QgsRenderContext rc = QgsLayoutUtils::createRenderContextForLayout( lLayout, nullptr, lLayout->renderContext().dpi() );
     115                 :          0 :     mMaxSymbolBleed = ( 25.4 / lLayout->renderContext().dpi() ) * QgsSymbolLayerUtils::estimateMaxSymbolBleed( mPolylineStyleSymbol.get(), rc );
     116                 :          0 :   }
     117                 :            : 
     118                 :          0 :   updateSceneRect();
     119                 :            : 
     120                 :          0 :   emit frameChanged();
     121                 :          0 : }
     122                 :            : 
     123                 :          0 : void QgsLayoutItemPolyline::drawStartMarker( QPainter *painter )
     124                 :            : {
     125                 :          0 :   if ( mPolygon.size() < 2 )
     126                 :          0 :     return;
     127                 :            : 
     128                 :          0 :   switch ( mStartMarker )
     129                 :            :   {
     130                 :            :     case MarkerMode::NoMarker:
     131                 :          0 :       break;
     132                 :            : 
     133                 :            :     case MarkerMode::ArrowHead:
     134                 :            :     {
     135                 :            :       // calculate angle at start of line
     136                 :          0 :       QLineF startLine( mPolygon.at( 0 ), mPolygon.at( 1 ) );
     137                 :          0 :       double angle = startLine.angle();
     138                 :          0 :       drawArrow( painter, mPolygon.at( 0 ), angle );
     139                 :          0 :       break;
     140                 :            :     }
     141                 :            : 
     142                 :            :     case MarkerMode::SvgMarker:
     143                 :            :     {
     144                 :            :       // calculate angle at start of line
     145                 :          0 :       QLineF startLine( mPolygon.at( 0 ), mPolygon.at( 1 ) );
     146                 :          0 :       double angle = startLine.angle();
     147                 :          0 :       drawSvgMarker( painter, mPolygon.at( 0 ), angle, mStartMarkerFile, mStartArrowHeadHeight );
     148                 :          0 :       break;
     149                 :            :     }
     150                 :            :   }
     151                 :            : 
     152                 :          0 : }
     153                 :            : 
     154                 :          0 : void QgsLayoutItemPolyline::drawEndMarker( QPainter *painter )
     155                 :            : {
     156                 :          0 :   if ( mPolygon.size() < 2 )
     157                 :          0 :     return;
     158                 :            : 
     159                 :          0 :   switch ( mEndMarker )
     160                 :            :   {
     161                 :            :     case MarkerMode::NoMarker:
     162                 :          0 :       break;
     163                 :            : 
     164                 :            :     case MarkerMode::ArrowHead:
     165                 :            :     {
     166                 :            :       // calculate angle at end of line
     167                 :          0 :       QLineF endLine( mPolygon.at( mPolygon.count() - 2 ), mPolygon.at( mPolygon.count() - 1 ) );
     168                 :          0 :       double angle = endLine.angle();
     169                 :            : 
     170                 :            :       //move end point depending on arrow width
     171                 :          0 :       QVector2D dir = QVector2D( endLine.dx(), endLine.dy() ).normalized();
     172                 :          0 :       QPointF endPoint = endLine.p2();
     173                 :          0 :       endPoint += ( dir * 0.5 * mArrowHeadWidth ).toPointF();
     174                 :            : 
     175                 :          0 :       drawArrow( painter, endPoint, angle );
     176                 :          0 :       break;
     177                 :            :     }
     178                 :            :     case MarkerMode::SvgMarker:
     179                 :            :     {
     180                 :            :       // calculate angle at end of line
     181                 :          0 :       QLineF endLine( mPolygon.at( mPolygon.count() - 2 ), mPolygon.at( mPolygon.count() - 1 ) );
     182                 :          0 :       double angle = endLine.angle();
     183                 :          0 :       drawSvgMarker( painter, endLine.p2(), angle, mEndMarkerFile, mEndArrowHeadHeight );
     184                 :          0 :       break;
     185                 :            :     }
     186                 :            :   }
     187                 :          0 : }
     188                 :            : 
     189                 :          0 : void QgsLayoutItemPolyline::drawArrow( QPainter *painter, QPointF center, double angle )
     190                 :            : {
     191                 :            :   // translate angle from ccw from axis to cw from north
     192                 :          0 :   angle = 90 - angle;
     193                 :          0 :   QPen p;
     194                 :          0 :   p.setColor( mArrowHeadStrokeColor );
     195                 :          0 :   p.setWidthF( mArrowHeadStrokeWidth );
     196                 :          0 :   painter->setPen( p );
     197                 :          0 :   QBrush b;
     198                 :          0 :   b.setColor( mArrowHeadFillColor );
     199                 :          0 :   painter->setBrush( b );
     200                 :            : 
     201                 :          0 :   drawArrowHead( painter, center.x(), center.y(), angle, mArrowHeadWidth );
     202                 :          0 : }
     203                 :            : 
     204                 :          0 : void QgsLayoutItemPolyline::updateMarkerSvgSizes()
     205                 :            : {
     206                 :          0 :   setStartSvgMarkerPath( mStartMarkerFile );
     207                 :          0 :   setEndSvgMarkerPath( mEndMarkerFile );
     208                 :          0 : }
     209                 :            : 
     210                 :          0 : void QgsLayoutItemPolyline::drawArrowHead( QPainter *p, const double x, const double y, const double angle, const double arrowHeadWidth )
     211                 :            : {
     212                 :          0 :   if ( !p )
     213                 :          0 :     return;
     214                 :          0 : 
     215                 :          0 :   double angleRad = angle / 180.0 * M_PI;
     216                 :          0 :   QPointF middlePoint( x, y );
     217                 :            : 
     218                 :            :   //rotate both arrow points
     219                 :          0 :   QPointF p1 = QPointF( -arrowHeadWidth / 2.0, arrowHeadWidth );
     220                 :          0 :   QPointF p2 = QPointF( arrowHeadWidth / 2.0, arrowHeadWidth );
     221                 :            : 
     222                 :          0 :   QPointF p1Rotated, p2Rotated;
     223                 :          0 :   p1Rotated.setX( p1.x() * std::cos( angleRad ) + p1.y() * -std::sin( angleRad ) );
     224                 :          0 :   p1Rotated.setY( p1.x() * std::sin( angleRad ) + p1.y() * std::cos( angleRad ) );
     225                 :          0 :   p2Rotated.setX( p2.x() * std::cos( angleRad ) + p2.y() * -std::sin( angleRad ) );
     226                 :          0 :   p2Rotated.setY( p2.x() * std::sin( angleRad ) + p2.y() * std::cos( angleRad ) );
     227                 :            : 
     228                 :          0 :   QPolygonF arrowHeadPoly;
     229                 :          0 :   arrowHeadPoly << middlePoint;
     230                 :          0 :   arrowHeadPoly << QPointF( middlePoint.x() + p1Rotated.x(), middlePoint.y() + p1Rotated.y() );
     231                 :          0 :   arrowHeadPoly << QPointF( middlePoint.x() + p2Rotated.x(), middlePoint.y() + p2Rotated.y() );
     232                 :          0 :   QPen arrowPen = p->pen();
     233                 :          0 :   arrowPen.setJoinStyle( Qt::RoundJoin );
     234                 :          0 :   QBrush arrowBrush = p->brush();
     235                 :          0 :   arrowBrush.setStyle( Qt::SolidPattern );
     236                 :          0 :   p->setPen( arrowPen );
     237                 :          0 :   p->setBrush( arrowBrush );
     238                 :          0 :   arrowBrush.setStyle( Qt::SolidPattern );
     239                 :          0 :   p->drawPolygon( arrowHeadPoly );
     240                 :          0 : }
     241                 :            : 
     242                 :          0 : void QgsLayoutItemPolyline::drawSvgMarker( QPainter *p, QPointF point, double angle, const QString &markerPath, double height ) const
     243                 :            : {
     244                 :            :   // translate angle from ccw from axis to cw from north
     245                 :          0 :   angle = 90 - angle;
     246                 :            : 
     247                 :          0 :   if ( mArrowHeadWidth <= 0 || height <= 0 )
     248                 :            :   {
     249                 :            :     //bad image size
     250                 :          0 :     return;
     251                 :            :   }
     252                 :            : 
     253                 :          0 :   if ( markerPath.isEmpty() )
     254                 :          0 :     return;
     255                 :            : 
     256                 :          0 :   QSvgRenderer r;
     257                 :          0 :   const QByteArray &svgContent = QgsApplication::svgCache()->svgContent( markerPath, mArrowHeadWidth, mArrowHeadFillColor, mArrowHeadStrokeColor, mArrowHeadStrokeWidth,
     258                 :            :                                  1.0 );
     259                 :          0 :   r.load( svgContent );
     260                 :            : 
     261                 :          0 :   QgsScopedQPainterState painterState( p );
     262                 :          0 :   p->translate( point.x(), point.y() );
     263                 :          0 :   p->rotate( angle );
     264                 :          0 :   p->translate( -mArrowHeadWidth / 2.0, -height / 2.0 );
     265                 :          0 :   r.render( p, QRectF( 0, 0, mArrowHeadWidth, height ) );
     266                 :          0 : }
     267                 :            : 
     268                 :          0 : QString QgsLayoutItemPolyline::displayName() const
     269                 :            : {
     270                 :          0 :   if ( !id().isEmpty() )
     271                 :          0 :     return id();
     272                 :            : 
     273                 :          0 :   return tr( "<Polyline>" );
     274                 :          0 : }
     275                 :            : 
     276                 :          0 : void QgsLayoutItemPolyline::_draw( QgsLayoutItemRenderContext &context, const QStyleOptionGraphicsItem * )
     277                 :            : {
     278                 :          0 :   QgsScopedQPainterState painterState( context.renderContext().painter() );
     279                 :            :   //setup painter scaling to dots so that raster symbology is drawn to scale
     280                 :          0 :   double scale = context.renderContext().convertToPainterUnits( 1, QgsUnitTypes::RenderMillimeters );
     281                 :          0 :   QTransform t = QTransform::fromScale( scale, scale );
     282                 :            : 
     283                 :          0 :   mPolylineStyleSymbol->startRender( context.renderContext() );
     284                 :          0 :   mPolylineStyleSymbol->renderPolyline( t.map( mPolygon ), nullptr, context.renderContext() );
     285                 :          0 :   mPolylineStyleSymbol->stopRender( context.renderContext() );
     286                 :            : 
     287                 :            :   // painter is scaled to dots, so scale back to layout units
     288                 :          0 :   context.renderContext().painter()->scale( context.renderContext().scaleFactor(), context.renderContext().scaleFactor() );
     289                 :            : 
     290                 :          0 :   drawStartMarker( context.renderContext().painter() );
     291                 :          0 :   drawEndMarker( context.renderContext().painter() );
     292                 :          0 : }
     293                 :            : 
     294                 :          0 : void QgsLayoutItemPolyline::_readXmlStyle( const QDomElement &elmt, const QgsReadWriteContext &context )
     295                 :            : {
     296                 :          0 :   mPolylineStyleSymbol.reset( QgsSymbolLayerUtils::loadSymbol<QgsLineSymbol>( elmt, context ) );
     297                 :          0 : }
     298                 :            : 
     299                 :          0 : void QgsLayoutItemPolyline::setSymbol( QgsLineSymbol *symbol )
     300                 :            : {
     301                 :          0 :   mPolylineStyleSymbol.reset( static_cast<QgsLineSymbol *>( symbol->clone() ) );
     302                 :          0 :   refreshSymbol();
     303                 :          0 : }
     304                 :            : 
     305                 :          0 : void QgsLayoutItemPolyline::setStartMarker( QgsLayoutItemPolyline::MarkerMode mode )
     306                 :            : {
     307                 :          0 :   mStartMarker = mode;
     308                 :          0 :   update();
     309                 :          0 : }
     310                 :            : 
     311                 :          0 : void QgsLayoutItemPolyline::setEndMarker( QgsLayoutItemPolyline::MarkerMode mode )
     312                 :            : {
     313                 :          0 :   mEndMarker = mode;
     314                 :          0 :   update();
     315                 :          0 : }
     316                 :            : 
     317                 :          0 : void QgsLayoutItemPolyline::setArrowHeadWidth( double width )
     318                 :            : {
     319                 :          0 :   mArrowHeadWidth = width;
     320                 :          0 :   updateMarkerSvgSizes();
     321                 :          0 :   update();
     322                 :          0 : }
     323                 :            : 
     324                 :          0 : QPainterPath QgsLayoutItemPolyline::shape() const
     325                 :            : {
     326                 :          0 :   QPainterPath path;
     327                 :          0 :   path.addPolygon( mPolygon );
     328                 :            : 
     329                 :          0 :   QPainterPathStroker ps;
     330                 :            : 
     331                 :          0 :   ps.setWidth( 2 * mMaxSymbolBleed );
     332                 :          0 :   QPainterPath strokedOutline = ps.createStroke( path );
     333                 :            : 
     334                 :          0 :   return strokedOutline;
     335                 :          0 : }
     336                 :            : 
     337                 :          0 : void QgsLayoutItemPolyline::setStartSvgMarkerPath( const QString &path )
     338                 :            : {
     339                 :          0 :   QSvgRenderer r;
     340                 :          0 :   mStartMarkerFile = path;
     341                 :          0 :   if ( path.isEmpty() || !r.load( path ) )
     342                 :            :   {
     343                 :          0 :     mStartArrowHeadHeight = 0;
     344                 :          0 :   }
     345                 :            :   else
     346                 :            :   {
     347                 :            :     //calculate mArrowHeadHeight from svg file and mArrowHeadWidth
     348                 :          0 :     QRect viewBox = r.viewBox();
     349                 :          0 :     mStartArrowHeadHeight = mArrowHeadWidth / viewBox.width() * viewBox.height();
     350                 :            :   }
     351                 :          0 :   updateBoundingRect();
     352                 :          0 : }
     353                 :            : 
     354                 :          0 : void QgsLayoutItemPolyline::setEndSvgMarkerPath( const QString &path )
     355                 :            : {
     356                 :          0 :   QSvgRenderer r;
     357                 :          0 :   mEndMarkerFile = path;
     358                 :          0 :   if ( path.isEmpty() || !r.load( path ) )
     359                 :            :   {
     360                 :          0 :     mEndArrowHeadHeight = 0;
     361                 :          0 :   }
     362                 :            :   else
     363                 :            :   {
     364                 :            :     //calculate mArrowHeadHeight from svg file and mArrowHeadWidth
     365                 :          0 :     QRect viewBox = r.viewBox();
     366                 :          0 :     mEndArrowHeadHeight = mArrowHeadWidth / viewBox.width() * viewBox.height();
     367                 :            :   }
     368                 :          0 :   updateBoundingRect();
     369                 :          0 : }
     370                 :            : 
     371                 :          0 : void QgsLayoutItemPolyline::setArrowHeadStrokeColor( const QColor &color )
     372                 :            : {
     373                 :          0 :   mArrowHeadStrokeColor = color;
     374                 :          0 :   update();
     375                 :          0 : }
     376                 :            : 
     377                 :          0 : void QgsLayoutItemPolyline::setArrowHeadFillColor( const QColor &color )
     378                 :            : {
     379                 :          0 :   mArrowHeadFillColor = color;
     380                 :          0 :   update();
     381                 :          0 : }
     382                 :            : 
     383                 :          0 : void QgsLayoutItemPolyline::setArrowHeadStrokeWidth( double width )
     384                 :            : {
     385                 :          0 :   mArrowHeadStrokeWidth = width;
     386                 :          0 :   updateBoundingRect();
     387                 :          0 :   update();
     388                 :          0 : }
     389                 :            : 
     390                 :          0 : bool QgsLayoutItemPolyline::accept( QgsStyleEntityVisitorInterface *visitor ) const
     391                 :            : {
     392                 :          0 :   if ( mPolylineStyleSymbol )
     393                 :            :   {
     394                 :          0 :     QgsStyleSymbolEntity entity( mPolylineStyleSymbol.get() );
     395                 :          0 :     if ( !visitor->visit( QgsStyleEntityVisitorInterface::StyleLeaf( &entity, uuid(), displayName() ) ) )
     396                 :          0 :       return false;
     397                 :          0 :   }
     398                 :            : 
     399                 :          0 :   return true;
     400                 :          0 : }
     401                 :            : 
     402                 :          0 : void QgsLayoutItemPolyline::_writeXmlStyle( QDomDocument &doc, QDomElement &elmt, const QgsReadWriteContext &context ) const
     403                 :            : {
     404                 :          0 :   const QDomElement pe = QgsSymbolLayerUtils::saveSymbol( QString(),
     405                 :          0 :                          mPolylineStyleSymbol.get(),
     406                 :          0 :                          doc,
     407                 :          0 :                          context );
     408                 :          0 :   elmt.appendChild( pe );
     409                 :          0 : }
     410                 :            : 
     411                 :          0 : bool QgsLayoutItemPolyline::writePropertiesToElement( QDomElement &elmt, QDomDocument &doc, const QgsReadWriteContext &context ) const
     412                 :            : {
     413                 :          0 :   QgsLayoutNodesItem::writePropertiesToElement( elmt, doc, context );
     414                 :            : 
     415                 :            :   // absolute paths to relative
     416                 :          0 :   QString startMarkerPath = QgsSymbolLayerUtils::svgSymbolPathToName( mStartMarkerFile, context.pathResolver() );
     417                 :          0 :   QString endMarkerPath = QgsSymbolLayerUtils::svgSymbolPathToName( mEndMarkerFile, context.pathResolver() );
     418                 :            : 
     419                 :          0 :   elmt.setAttribute( QStringLiteral( "arrowHeadWidth" ), QString::number( mArrowHeadWidth ) );
     420                 :          0 :   elmt.setAttribute( QStringLiteral( "arrowHeadFillColor" ), QgsSymbolLayerUtils::encodeColor( mArrowHeadFillColor ) );
     421                 :          0 :   elmt.setAttribute( QStringLiteral( "arrowHeadOutlineColor" ), QgsSymbolLayerUtils::encodeColor( mArrowHeadStrokeColor ) );
     422                 :          0 :   elmt.setAttribute( QStringLiteral( "outlineWidth" ), QString::number( mArrowHeadStrokeWidth ) );
     423                 :          0 :   elmt.setAttribute( QStringLiteral( "markerMode" ), mEndMarker );
     424                 :          0 :   elmt.setAttribute( QStringLiteral( "startMarkerMode" ), mStartMarker );
     425                 :          0 :   elmt.setAttribute( QStringLiteral( "startMarkerFile" ), startMarkerPath );
     426                 :          0 :   elmt.setAttribute( QStringLiteral( "endMarkerFile" ), endMarkerPath );
     427                 :            : 
     428                 :            :   return true;
     429                 :          0 : }
     430                 :            : 
     431                 :          0 : bool QgsLayoutItemPolyline::readPropertiesFromElement( const QDomElement &elmt, const QDomDocument &doc, const QgsReadWriteContext &context )
     432                 :            : {
     433                 :          0 :   mArrowHeadWidth = elmt.attribute( QStringLiteral( "arrowHeadWidth" ), QStringLiteral( "2.0" ) ).toDouble();
     434                 :          0 :   mArrowHeadFillColor = QgsSymbolLayerUtils::decodeColor( elmt.attribute( QStringLiteral( "arrowHeadFillColor" ), QStringLiteral( "0,0,0,255" ) ) );
     435                 :          0 :   mArrowHeadStrokeColor = QgsSymbolLayerUtils::decodeColor( elmt.attribute( QStringLiteral( "arrowHeadOutlineColor" ), QStringLiteral( "0,0,0,255" ) ) );
     436                 :          0 :   mArrowHeadStrokeWidth = elmt.attribute( QStringLiteral( "outlineWidth" ), QStringLiteral( "1.0" ) ).toDouble();
     437                 :            :   // relative paths to absolute
     438                 :          0 :   QString startMarkerPath = elmt.attribute( QStringLiteral( "startMarkerFile" ), QString() );
     439                 :          0 :   QString endMarkerPath = elmt.attribute( QStringLiteral( "endMarkerFile" ), QString() );
     440                 :          0 :   setStartSvgMarkerPath( QgsSymbolLayerUtils::svgSymbolNameToPath( startMarkerPath, context.pathResolver() ) );
     441                 :          0 :   setEndSvgMarkerPath( QgsSymbolLayerUtils::svgSymbolNameToPath( endMarkerPath, context.pathResolver() ) );
     442                 :          0 :   mEndMarker = static_cast< QgsLayoutItemPolyline::MarkerMode >( elmt.attribute( QStringLiteral( "markerMode" ), QStringLiteral( "0" ) ).toInt() );
     443                 :          0 :   mStartMarker = static_cast< QgsLayoutItemPolyline::MarkerMode >( elmt.attribute( QStringLiteral( "startMarkerMode" ), QStringLiteral( "0" ) ).toInt() );
     444                 :            : 
     445                 :          0 :   QgsLayoutNodesItem::readPropertiesFromElement( elmt, doc, context );
     446                 :            : 
     447                 :          0 :   updateBoundingRect();
     448                 :            :   return true;
     449                 :          0 : }
     450                 :            : 
     451                 :          0 : void QgsLayoutItemPolyline::updateBoundingRect()
     452                 :            : {
     453                 :          0 :   QRectF br = rect();
     454                 :            : 
     455                 :          0 :   double margin = std::max( mMaxSymbolBleed, computeMarkerMargin() );
     456                 :          0 :   if ( mEndMarker == ArrowHead )
     457                 :            :   {
     458                 :          0 :     margin += 0.5 * mArrowHeadWidth;
     459                 :          0 :   }
     460                 :          0 :   br.adjust( -margin, -margin, margin, margin );
     461                 :          0 :   mCurrentRectangle = br;
     462                 :            : 
     463                 :            :   // update
     464                 :          0 :   prepareGeometryChange();
     465                 :          0 :   update();
     466                 :          0 : }
     467                 :            : 
     468                 :            : 
     469                 :          0 : double QgsLayoutItemPolyline::computeMarkerMargin() const
     470                 :            : {
     471                 :          0 :   double margin = 0;
     472                 :            : 
     473                 :          0 :   if ( mStartMarker == ArrowHead || mEndMarker == ArrowHead )
     474                 :            :   {
     475                 :          0 :     margin = mArrowHeadStrokeWidth / 2.0 + mArrowHeadWidth * M_SQRT2;
     476                 :          0 :   }
     477                 :            : 
     478                 :          0 :   if ( mStartMarker == SvgMarker )
     479                 :            :   {
     480                 :          0 :     double startMarkerMargin = std::sqrt( 0.25 * ( mStartArrowHeadHeight * mStartArrowHeadHeight + mArrowHeadWidth * mArrowHeadWidth ) );
     481                 :          0 :     margin = std::max( startMarkerMargin, margin );
     482                 :          0 :   }
     483                 :            : 
     484                 :          0 :   if ( mEndMarker == SvgMarker )
     485                 :            :   {
     486                 :          0 :     double endMarkerMargin = std::sqrt( 0.25 * ( mEndArrowHeadHeight * mEndArrowHeadHeight + mArrowHeadWidth * mArrowHeadWidth ) );
     487                 :          0 :     margin = std::max( endMarkerMargin, margin );
     488                 :          0 :   }
     489                 :            : 
     490                 :          0 :   return margin;
     491                 :            : }

Generated by: LCOV version 1.14