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

           Branch data     Line data    Source code
       1                 :            : /***************************************************************************
       2                 :            :  qgsmarkersymbollayer.cpp
       3                 :            :  ---------------------
       4                 :            :  begin                : November 2009
       5                 :            :  copyright            : (C) 2009 by Martin Dobias
       6                 :            :  email                : wonder dot sk at gmail dot com
       7                 :            :  ***************************************************************************
       8                 :            :  *                                                                         *
       9                 :            :  *   This program is free software; you can redistribute it and/or modify  *
      10                 :            :  *   it under the terms of the GNU General Public License as published by  *
      11                 :            :  *   the Free Software Foundation; either version 2 of the License, or     *
      12                 :            :  *   (at your option) any later version.                                   *
      13                 :            :  *                                                                         *
      14                 :            :  ***************************************************************************/
      15                 :            : 
      16                 :            : #include "qgsmarkersymbollayer.h"
      17                 :            : #include "qgssymbollayerutils.h"
      18                 :            : 
      19                 :            : #include "qgsdxfexport.h"
      20                 :            : #include "qgsdxfpaintdevice.h"
      21                 :            : #include "qgsexpression.h"
      22                 :            : #include "qgsfontutils.h"
      23                 :            : #include "qgsimagecache.h"
      24                 :            : #include "qgsimageoperation.h"
      25                 :            : #include "qgsrendercontext.h"
      26                 :            : #include "qgslogger.h"
      27                 :            : #include "qgssvgcache.h"
      28                 :            : #include "qgsunittypes.h"
      29                 :            : 
      30                 :            : #include <QPainter>
      31                 :            : #include <QSvgRenderer>
      32                 :            : #include <QFileInfo>
      33                 :            : #include <QDir>
      34                 :            : #include <QDomDocument>
      35                 :            : #include <QDomElement>
      36                 :            : 
      37                 :            : #include <cmath>
      38                 :            : 
      39                 :            : Q_GUI_EXPORT extern int qt_defaultDpiX();
      40                 :            : Q_GUI_EXPORT extern int qt_defaultDpiY();
      41                 :            : 
      42                 :          0 : static void _fixQPictureDPI( QPainter *p )
      43                 :            : {
      44                 :            :   // QPicture makes an assumption that we drawing to it with system DPI.
      45                 :            :   // Then when being drawn, it scales the painter. The following call
      46                 :            :   // negates the effect. There is no way of setting QPicture's DPI.
      47                 :            :   // See QTBUG-20361
      48                 :          0 :   p->scale( static_cast< double >( qt_defaultDpiX() ) / p->device()->logicalDpiX(),
      49                 :          0 :             static_cast< double >( qt_defaultDpiY() ) / p->device()->logicalDpiY() );
      50                 :          0 : }
      51                 :            : 
      52                 :            : 
      53                 :            : //////
      54                 :            : 
      55                 :            : 
      56                 :            : //
      57                 :            : // QgsSimpleMarkerSymbolLayerBase
      58                 :            : //
      59                 :            : 
      60                 :          0 : QList<QgsSimpleMarkerSymbolLayerBase::Shape> QgsSimpleMarkerSymbolLayerBase::availableShapes()
      61                 :            : {
      62                 :          0 :   QList< Shape > shapes;
      63                 :          0 :   shapes << Square
      64                 :          0 :          << Diamond
      65                 :          0 :          << Pentagon
      66                 :          0 :          << Hexagon
      67                 :          0 :          << Octagon
      68                 :          0 :          << SquareWithCorners
      69                 :          0 :          << Triangle
      70                 :          0 :          << EquilateralTriangle
      71                 :          0 :          << Star
      72                 :          0 :          << Arrow
      73                 :          0 :          << Circle
      74                 :          0 :          << Cross
      75                 :          0 :          << CrossFill
      76                 :          0 :          << Cross2
      77                 :          0 :          << Line
      78                 :          0 :          << HalfArc
      79                 :          0 :          << ThirdArc
      80                 :          0 :          << QuarterArc
      81                 :          0 :          << ArrowHead
      82                 :          0 :          << ArrowHeadFilled
      83                 :          0 :          << SemiCircle
      84                 :          0 :          << ThirdCircle
      85                 :          0 :          << QuarterCircle
      86                 :          0 :          << QuarterSquare
      87                 :          0 :          << HalfSquare
      88                 :          0 :          << DiagonalHalfSquare
      89                 :          0 :          << RightHalfTriangle
      90                 :          0 :          << LeftHalfTriangle
      91                 :          0 :          << AsteriskFill;
      92                 :            : 
      93                 :          0 :   return shapes;
      94                 :          0 : }
      95                 :            : 
      96                 :        332 : QgsSimpleMarkerSymbolLayerBase::QgsSimpleMarkerSymbolLayerBase( QgsSimpleMarkerSymbolLayerBase::Shape shape, double size, double angle, QgsSymbol::ScaleMethod scaleMethod )
      97                 :        332 :   : mShape( shape )
      98                 :        664 : {
      99                 :        332 :   mSize = size;
     100                 :        332 :   mAngle = angle;
     101                 :        332 :   mOffset = QPointF( 0, 0 );
     102                 :        332 :   mScaleMethod = scaleMethod;
     103                 :        332 :   mSizeUnit = QgsUnitTypes::RenderMillimeters;
     104                 :        332 :   mOffsetUnit = QgsUnitTypes::RenderMillimeters;
     105                 :        332 : }
     106                 :            : 
     107                 :        102 : bool QgsSimpleMarkerSymbolLayerBase::shapeIsFilled( QgsSimpleMarkerSymbolLayerBase::Shape shape )
     108                 :            : {
     109                 :        102 :   switch ( shape )
     110                 :            :   {
     111                 :            :     case Square:
     112                 :            :     case Diamond:
     113                 :            :     case Pentagon:
     114                 :            :     case Hexagon:
     115                 :            :     case Octagon:
     116                 :            :     case SquareWithCorners:
     117                 :            :     case Triangle:
     118                 :            :     case EquilateralTriangle:
     119                 :            :     case Star:
     120                 :            :     case Arrow:
     121                 :            :     case Circle:
     122                 :            :     case CrossFill:
     123                 :            :     case ArrowHeadFilled:
     124                 :            :     case SemiCircle:
     125                 :            :     case ThirdCircle:
     126                 :            :     case QuarterCircle:
     127                 :            :     case QuarterSquare:
     128                 :            :     case HalfSquare:
     129                 :            :     case DiagonalHalfSquare:
     130                 :            :     case RightHalfTriangle:
     131                 :            :     case LeftHalfTriangle:
     132                 :            :     case AsteriskFill:
     133                 :         92 :       return true;
     134                 :            : 
     135                 :            :     case Cross:
     136                 :            :     case Cross2:
     137                 :            :     case Line:
     138                 :            :     case ArrowHead:
     139                 :            :     case HalfArc:
     140                 :            :     case ThirdArc:
     141                 :            :     case QuarterArc:
     142                 :         10 :       return false;
     143                 :            :   }
     144                 :          0 :   return true;
     145                 :        102 : }
     146                 :            : 
     147                 :          0 : void QgsSimpleMarkerSymbolLayerBase::startRender( QgsSymbolRenderContext &context )
     148                 :            : {
     149                 :          0 :   bool hasDataDefinedRotation = context.renderHints() & QgsSymbol::DynamicRotation
     150                 :          0 :                                 || mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyAngle );
     151                 :          0 :   bool hasDataDefinedSize = mDataDefinedProperties.isActive( QgsSymbolLayer::PropertySize );
     152                 :            : 
     153                 :            :   // use either QPolygonF or QPainterPath for drawing
     154                 :          0 :   if ( !prepareMarkerShape( mShape ) ) // drawing as a polygon
     155                 :            :   {
     156                 :          0 :     prepareMarkerPath( mShape ); // drawing as a painter path
     157                 :          0 :   }
     158                 :            : 
     159                 :          0 :   QTransform transform;
     160                 :            : 
     161                 :            :   // scale the shape (if the size is not going to be modified)
     162                 :          0 :   if ( !hasDataDefinedSize )
     163                 :            :   {
     164                 :          0 :     double scaledSize = context.renderContext().convertToPainterUnits( mSize, mSizeUnit, mSizeMapUnitScale );
     165                 :          0 :     if ( mSizeUnit == QgsUnitTypes::RenderMetersInMapUnits && context.renderContext().flags() & QgsRenderContext::RenderSymbolPreview )
     166                 :            :     {
     167                 :            :       // rendering for symbol previews -- an size in meters in map units can't be calculated, so treat the size as millimeters
     168                 :            :       // and clamp it to a reasonable range. It's the best we can do in this situation!
     169                 :          0 :       scaledSize = std::min( std::max( context.renderContext().convertToPainterUnits( mSize, QgsUnitTypes::RenderMillimeters ), 3.0 ), 100.0 );
     170                 :          0 :     }
     171                 :            : 
     172                 :          0 :     double half = scaledSize / 2.0;
     173                 :          0 :     transform.scale( half, half );
     174                 :          0 :   }
     175                 :            : 
     176                 :            :   // rotate if the rotation is not going to be changed during the rendering
     177                 :          0 :   if ( !hasDataDefinedRotation && !qgsDoubleNear( mAngle, 0.0 ) )
     178                 :            :   {
     179                 :          0 :     transform.rotate( mAngle );
     180                 :          0 :   }
     181                 :            : 
     182                 :          0 :   if ( !mPolygon.isEmpty() )
     183                 :          0 :     mPolygon = transform.map( mPolygon );
     184                 :            :   else
     185                 :          0 :     mPath = transform.map( mPath );
     186                 :            : 
     187                 :          0 :   QgsMarkerSymbolLayer::startRender( context );
     188                 :          0 : }
     189                 :            : 
     190                 :          0 : void QgsSimpleMarkerSymbolLayerBase::stopRender( QgsSymbolRenderContext &context )
     191                 :            : {
     192                 :          0 :   Q_UNUSED( context )
     193                 :          0 : }
     194                 :            : 
     195                 :          0 : void QgsSimpleMarkerSymbolLayerBase::renderPoint( QPointF point, QgsSymbolRenderContext &context )
     196                 :            : {
     197                 :            :   //making changes here? Don't forget to also update ::bounds if the changes affect the bounding box
     198                 :            :   //of the rendered point!
     199                 :            : 
     200                 :          0 :   QPainter *p = context.renderContext().painter();
     201                 :          0 :   if ( !p )
     202                 :            :   {
     203                 :          0 :     return;
     204                 :            :   }
     205                 :            : 
     206                 :          0 :   bool hasDataDefinedSize = false;
     207                 :          0 :   double scaledSize = calculateSize( context, hasDataDefinedSize );
     208                 :            : 
     209                 :          0 :   bool hasDataDefinedRotation = false;
     210                 :          0 :   QPointF offset;
     211                 :          0 :   double angle = 0;
     212                 :          0 :   calculateOffsetAndRotation( context, scaledSize, hasDataDefinedRotation, offset, angle );
     213                 :            : 
     214                 :            :   //data defined shape?
     215                 :          0 :   bool createdNewPath = false;
     216                 :          0 :   bool ok = true;
     217                 :          0 :   Shape symbol = mShape;
     218                 :          0 :   if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyName ) )
     219                 :            :   {
     220                 :          0 :     context.setOriginalValueVariable( encodeShape( symbol ) );
     221                 :          0 :     QVariant exprVal = mDataDefinedProperties.value( QgsSymbolLayer::PropertyName, context.renderContext().expressionContext() );
     222                 :          0 :     if ( exprVal.isValid() )
     223                 :            :     {
     224                 :          0 :       Shape decoded = decodeShape( exprVal.toString(), &ok );
     225                 :          0 :       if ( ok )
     226                 :            :       {
     227                 :          0 :         symbol = decoded;
     228                 :            : 
     229                 :          0 :         if ( !prepareMarkerShape( symbol ) ) // drawing as a polygon
     230                 :            :         {
     231                 :          0 :           prepareMarkerPath( symbol ); // drawing as a painter path
     232                 :          0 :         }
     233                 :          0 :         createdNewPath = true;
     234                 :          0 :       }
     235                 :          0 :     }
     236                 :            :     else
     237                 :            :     {
     238                 :          0 :       symbol = mShape;
     239                 :            :     }
     240                 :          0 :   }
     241                 :            : 
     242                 :          0 :   QTransform transform;
     243                 :            : 
     244                 :            :   // move to the desired position
     245                 :          0 :   transform.translate( point.x() + offset.x(), point.y() + offset.y() );
     246                 :            : 
     247                 :            :   // resize if necessary
     248                 :          0 :   if ( hasDataDefinedSize || createdNewPath )
     249                 :            :   {
     250                 :          0 :     double s = context.renderContext().convertToPainterUnits( scaledSize, mSizeUnit, mSizeMapUnitScale );
     251                 :          0 :     if ( mSizeUnit == QgsUnitTypes::RenderMetersInMapUnits && context.renderContext().flags() & QgsRenderContext::RenderSymbolPreview )
     252                 :            :     {
     253                 :            :       // rendering for symbol previews -- a size in meters in map units can't be calculated, so treat the size as millimeters
     254                 :            :       // and clamp it to a reasonable range. It's the best we can do in this situation!
     255                 :          0 :       s = std::min( std::max( context.renderContext().convertToPainterUnits( mSize, QgsUnitTypes::RenderMillimeters ), 3.0 ), 100.0 );
     256                 :          0 :     }
     257                 :          0 :     double half = s / 2.0;
     258                 :          0 :     transform.scale( half, half );
     259                 :          0 :   }
     260                 :            : 
     261                 :          0 :   if ( !qgsDoubleNear( angle, 0.0 ) && ( hasDataDefinedRotation || createdNewPath ) )
     262                 :            :   {
     263                 :          0 :     transform.rotate( angle );
     264                 :          0 :   }
     265                 :            : 
     266                 :            :   //need to pass: symbol, polygon, path
     267                 :            : 
     268                 :          0 :   QPolygonF polygon;
     269                 :          0 :   QPainterPath path;
     270                 :          0 :   if ( !mPolygon.isEmpty() )
     271                 :            :   {
     272                 :          0 :     polygon = transform.map( mPolygon );
     273                 :          0 :   }
     274                 :            :   else
     275                 :            :   {
     276                 :          0 :     path = transform.map( mPath );
     277                 :            :   }
     278                 :          0 :   draw( context, symbol, polygon, path );
     279                 :          0 : }
     280                 :            : 
     281                 :          0 : QRectF QgsSimpleMarkerSymbolLayerBase::bounds( QPointF point, QgsSymbolRenderContext &context )
     282                 :            : {
     283                 :          0 :   bool hasDataDefinedSize = false;
     284                 :          0 :   double scaledSize = calculateSize( context, hasDataDefinedSize );
     285                 :            : 
     286                 :          0 :   bool hasDataDefinedRotation = false;
     287                 :          0 :   QPointF offset;
     288                 :          0 :   double angle = 0;
     289                 :          0 :   calculateOffsetAndRotation( context, scaledSize, hasDataDefinedRotation, offset, angle );
     290                 :            : 
     291                 :          0 :   scaledSize = context.renderContext().convertToPainterUnits( scaledSize, mSizeUnit, mSizeMapUnitScale );
     292                 :            : 
     293                 :          0 :   QTransform transform;
     294                 :            : 
     295                 :            :   // move to the desired position
     296                 :          0 :   transform.translate( point.x() + offset.x(), point.y() + offset.y() );
     297                 :            : 
     298                 :          0 :   if ( !qgsDoubleNear( angle, 0.0 ) )
     299                 :          0 :     transform.rotate( angle );
     300                 :            : 
     301                 :          0 :   return transform.mapRect( QRectF( -scaledSize / 2.0,
     302                 :          0 :                                     -scaledSize / 2.0,
     303                 :          0 :                                     scaledSize,
     304                 :          0 :                                     scaledSize ) );
     305                 :            : }
     306                 :            : 
     307                 :        230 : QgsSimpleMarkerSymbolLayerBase::Shape QgsSimpleMarkerSymbolLayerBase::decodeShape( const QString &name, bool *ok )
     308                 :            : {
     309                 :        230 :   if ( ok )
     310                 :          0 :     *ok = true;
     311                 :        230 :   QString cleaned = name.toLower().trimmed();
     312                 :            : 
     313                 :        230 :   if ( cleaned == QLatin1String( "square" ) || cleaned == QLatin1String( "rectangle" ) )
     314                 :          5 :     return Square;
     315                 :        225 :   else if ( cleaned == QLatin1String( "square_with_corners" ) )
     316                 :          0 :     return SquareWithCorners;
     317                 :        225 :   else if ( cleaned == QLatin1String( "diamond" ) )
     318                 :         15 :     return Diamond;
     319                 :        210 :   else if ( cleaned == QLatin1String( "pentagon" ) )
     320                 :          0 :     return Pentagon;
     321                 :        210 :   else if ( cleaned == QLatin1String( "hexagon" ) )
     322                 :         10 :     return Hexagon;
     323                 :        200 :   else if ( cleaned == QLatin1String( "octagon" ) )
     324                 :          0 :     return Octagon;
     325                 :        200 :   else if ( cleaned == QLatin1String( "triangle" ) )
     326                 :         25 :     return Triangle;
     327                 :        175 :   else if ( cleaned == QLatin1String( "equilateral_triangle" ) )
     328                 :          0 :     return EquilateralTriangle;
     329                 :        175 :   else if ( cleaned == QLatin1String( "star" ) || cleaned == QLatin1String( "regular_star" ) )
     330                 :         10 :     return Star;
     331                 :        165 :   else if ( cleaned == QLatin1String( "arrow" ) )
     332                 :          0 :     return Arrow;
     333                 :        165 :   else if ( cleaned == QLatin1String( "circle" ) )
     334                 :        135 :     return Circle;
     335                 :         30 :   else if ( cleaned == QLatin1String( "cross" ) )
     336                 :          0 :     return Cross;
     337                 :         30 :   else if ( cleaned == QLatin1String( "cross_fill" ) )
     338                 :          5 :     return CrossFill;
     339                 :         25 :   else if ( cleaned == QLatin1String( "cross2" ) || cleaned == QLatin1String( "x" ) )
     340                 :          0 :     return Cross2;
     341                 :         25 :   else if ( cleaned == QLatin1String( "line" ) )
     342                 :         25 :     return Line;
     343                 :          0 :   else if ( cleaned == QLatin1String( "arrowhead" ) )
     344                 :          0 :     return ArrowHead;
     345                 :          0 :   else if ( cleaned == QLatin1String( "filled_arrowhead" ) )
     346                 :          0 :     return ArrowHeadFilled;
     347                 :          0 :   else if ( cleaned == QLatin1String( "semi_circle" ) )
     348                 :          0 :     return SemiCircle;
     349                 :          0 :   else if ( cleaned == QLatin1String( "third_circle" ) )
     350                 :          0 :     return ThirdCircle;
     351                 :          0 :   else if ( cleaned == QLatin1String( "quarter_circle" ) )
     352                 :          0 :     return QuarterCircle;
     353                 :          0 :   else if ( cleaned == QLatin1String( "quarter_square" ) )
     354                 :          0 :     return QuarterSquare;
     355                 :          0 :   else if ( cleaned == QLatin1String( "half_square" ) )
     356                 :          0 :     return HalfSquare;
     357                 :          0 :   else if ( cleaned == QLatin1String( "diagonal_half_square" ) )
     358                 :          0 :     return DiagonalHalfSquare;
     359                 :          0 :   else if ( cleaned == QLatin1String( "right_half_triangle" ) )
     360                 :          0 :     return RightHalfTriangle;
     361                 :          0 :   else if ( cleaned == QLatin1String( "left_half_triangle" ) )
     362                 :          0 :     return LeftHalfTriangle;
     363                 :          0 :   else if ( cleaned == QLatin1String( "asterisk_fill" ) )
     364                 :          0 :     return AsteriskFill;
     365                 :          0 :   else if ( cleaned == QLatin1String( "half_arc" ) )
     366                 :          0 :     return HalfArc;
     367                 :          0 :   else if ( cleaned == QLatin1String( "third_arc" ) )
     368                 :          0 :     return ThirdArc;
     369                 :          0 :   else if ( cleaned == QLatin1String( "quarter_arc" ) )
     370                 :          0 :     return QuarterArc;
     371                 :            : 
     372                 :          0 :   if ( ok )
     373                 :          0 :     *ok = false;
     374                 :          0 :   return Circle;
     375                 :        230 : }
     376                 :            : 
     377                 :          0 : QString QgsSimpleMarkerSymbolLayerBase::encodeShape( QgsSimpleMarkerSymbolLayerBase::Shape shape )
     378                 :            : {
     379                 :          0 :   switch ( shape )
     380                 :            :   {
     381                 :            :     case Square:
     382                 :          0 :       return QStringLiteral( "square" );
     383                 :            :     case QuarterSquare:
     384                 :          0 :       return QStringLiteral( "quarter_square" );
     385                 :            :     case HalfSquare:
     386                 :          0 :       return QStringLiteral( "half_square" );
     387                 :            :     case DiagonalHalfSquare:
     388                 :          0 :       return QStringLiteral( "diagonal_half_square" );
     389                 :            :     case Diamond:
     390                 :          0 :       return QStringLiteral( "diamond" );
     391                 :            :     case Pentagon:
     392                 :          0 :       return QStringLiteral( "pentagon" );
     393                 :            :     case Hexagon:
     394                 :          0 :       return QStringLiteral( "hexagon" );
     395                 :            :     case Octagon:
     396                 :          0 :       return QStringLiteral( "octagon" );
     397                 :            :     case SquareWithCorners:
     398                 :          0 :       return QStringLiteral( "square_with_corners" );
     399                 :            :     case Triangle:
     400                 :          0 :       return QStringLiteral( "triangle" );
     401                 :            :     case EquilateralTriangle:
     402                 :          0 :       return QStringLiteral( "equilateral_triangle" );
     403                 :            :     case LeftHalfTriangle:
     404                 :          0 :       return QStringLiteral( "left_half_triangle" );
     405                 :            :     case RightHalfTriangle:
     406                 :          0 :       return QStringLiteral( "right_half_triangle" );
     407                 :            :     case Star:
     408                 :          0 :       return QStringLiteral( "star" );
     409                 :            :     case Arrow:
     410                 :          0 :       return QStringLiteral( "arrow" );
     411                 :            :     case ArrowHeadFilled:
     412                 :          0 :       return QStringLiteral( "filled_arrowhead" );
     413                 :        332 :     case CrossFill:
     414                 :          0 :       return QStringLiteral( "cross_fill" );
     415                 :        332 :     case Circle:
     416                 :          0 :       return QStringLiteral( "circle" );
     417                 :        332 :     case Cross:
     418                 :          0 :       return QStringLiteral( "cross" );
     419                 :            :     case Cross2:
     420                 :          0 :       return QStringLiteral( "cross2" );
     421                 :            :     case Line:
     422                 :          0 :       return QStringLiteral( "line" );
     423                 :        332 :     case ArrowHead:
     424                 :          0 :       return QStringLiteral( "arrowhead" );
     425                 :            :     case SemiCircle:
     426                 :          0 :       return QStringLiteral( "semi_circle" );
     427                 :            :     case ThirdCircle:
     428                 :          0 :       return QStringLiteral( "third_circle" );
     429                 :            :     case QuarterCircle:
     430                 :          0 :       return QStringLiteral( "quarter_circle" );
     431                 :            :     case AsteriskFill:
     432                 :          0 :       return QStringLiteral( "asterisk_fill" );
     433                 :            :     case HalfArc:
     434                 :          0 :       return QStringLiteral( "half_arc" );
     435                 :            :     case ThirdArc:
     436                 :          0 :       return QStringLiteral( "third_arc" );
     437                 :            :     case QuarterArc:
     438                 :          0 :       return QStringLiteral( "quarter_arc" );
     439                 :            :   }
     440                 :          0 :   return QString();
     441                 :          0 : }
     442                 :        332 : 
     443                 :          0 : bool QgsSimpleMarkerSymbolLayerBase::prepareMarkerShape( QgsSimpleMarkerSymbolLayerBase::Shape shape )
     444                 :            : {
     445                 :          0 :   return shapeToPolygon( shape, mPolygon );
     446                 :            : }
     447                 :            : 
     448                 :          0 : bool QgsSimpleMarkerSymbolLayerBase::shapeToPolygon( QgsSimpleMarkerSymbolLayerBase::Shape shape, QPolygonF &polygon ) const
     449                 :            : {
     450                 :          0 :   polygon.clear();
     451                 :        332 : 
     452                 :          0 :   switch ( shape )
     453                 :            :   {
     454                 :            :     case Square:
     455                 :          0 :       polygon = QPolygonF( QRectF( QPointF( -1, -1 ), QPointF( 1, 1 ) ) );
     456                 :          0 :       return true;
     457                 :            : 
     458                 :            :     case SquareWithCorners:
     459                 :            :     {
     460                 :            :       static constexpr double VERTEX_OFFSET_FROM_ORIGIN = 0.6072;
     461                 :            : 
     462                 :          0 :       polygon << QPointF( - VERTEX_OFFSET_FROM_ORIGIN, 1 )
     463                 :          0 :               << QPointF( VERTEX_OFFSET_FROM_ORIGIN, 1 )
     464                 :          0 :               << QPointF( 1, VERTEX_OFFSET_FROM_ORIGIN )
     465                 :          0 :               << QPointF( 1, -VERTEX_OFFSET_FROM_ORIGIN )
     466                 :          0 :               << QPointF( VERTEX_OFFSET_FROM_ORIGIN, -1 )
     467                 :          0 :               << QPointF( -VERTEX_OFFSET_FROM_ORIGIN, -1 )
     468                 :          0 :               << QPointF( -1, -VERTEX_OFFSET_FROM_ORIGIN )
     469                 :          0 :               << QPointF( -1, VERTEX_OFFSET_FROM_ORIGIN )
     470                 :          0 :               << QPointF( -VERTEX_OFFSET_FROM_ORIGIN, 1 );
     471                 :          0 :       return true;
     472                 :            :     }
     473                 :            : 
     474                 :            :     case QuarterSquare:
     475                 :          0 :       polygon = QPolygonF( QRectF( QPointF( -1, -1 ), QPointF( 0, 0 ) ) );
     476                 :          0 :       return true;
     477                 :            : 
     478                 :            :     case HalfSquare:
     479                 :          0 :       polygon = QPolygonF( QRectF( QPointF( -1, -1 ), QPointF( 0, 1 ) ) );
     480                 :          0 :       return true;
     481                 :            : 
     482                 :            :     case DiagonalHalfSquare:
     483                 :          0 :       polygon << QPointF( -1, -1 ) << QPointF( 1, 1 ) << QPointF( -1, 1 ) << QPointF( -1, -1 );
     484                 :          0 :       return true;
     485                 :            : 
     486                 :            :     case Diamond:
     487                 :          0 :       polygon << QPointF( -1, 0 ) << QPointF( 0, 1 )
     488                 :          0 :               << QPointF( 1, 0 ) << QPointF( 0, -1 ) << QPointF( -1, 0 );
     489                 :          0 :       return true;
     490                 :            : 
     491                 :            :     case Pentagon:
     492                 :            :       /* angular-representation of hardcoded values used
     493                 :            :       polygon << QPointF( std::sin( DEG2RAD( 288.0 ) ), - std::cos( DEG2RAD( 288.0 ) ) )
     494                 :            :       << QPointF( std::sin( DEG2RAD( 216.0 ) ), - std::cos( DEG2RAD( 216.0 ) ) )
     495                 :            :       << QPointF( std::sin( DEG2RAD( 144.0 ) ), - std::cos( DEG2RAD( 144.0 ) ) )
     496                 :            :       << QPointF( std::sin( DEG2RAD( 72.0 ) ), - std::cos( DEG2RAD( 72.0 ) ) )
     497                 :            :       << QPointF( 0, -1 ); */
     498                 :          0 :       polygon << QPointF( -0.9511, -0.3090 )
     499                 :          0 :               << QPointF( -0.5878, 0.8090 )
     500                 :          0 :               << QPointF( 0.5878, 0.8090 )
     501                 :          0 :               << QPointF( 0.9511, -0.3090 )
     502                 :          0 :               << QPointF( 0, -1 )
     503                 :          0 :               << QPointF( -0.9511, -0.3090 );
     504                 :          0 :       return true;
     505                 :            : 
     506                 :            :     case Hexagon:
     507                 :            :       /* angular-representation of hardcoded values used
     508                 :            :       polygon << QPointF( std::sin( DEG2RAD( 300.0 ) ), - std::cos( DEG2RAD( 300.0 ) ) )
     509                 :            :       << QPointF( std::sin( DEG2RAD( 240.0 ) ), - std::cos( DEG2RAD( 240.0 ) ) )
     510                 :            :       << QPointF( std::sin( DEG2RAD( 180.0 ) ), - std::cos( DEG2RAD( 180.0 ) ) )
     511                 :            :       << QPointF( std::sin( DEG2RAD( 120.0 ) ), - std::cos( DEG2RAD( 120.0 ) ) )
     512                 :            :       << QPointF( std::sin( DEG2RAD( 60.0 ) ), - std::cos( DEG2RAD( 60.0 ) ) )
     513                 :            :       << QPointF( 0, -1 ); */
     514                 :          0 :       polygon << QPointF( -0.8660, -0.5 )
     515                 :          0 :               << QPointF( -0.8660, 0.5 )
     516                 :          0 :               << QPointF( 0, 1 )
     517                 :          0 :               << QPointF( 0.8660, 0.5 )
     518                 :          0 :               << QPointF( 0.8660, -0.5 )
     519                 :          0 :               << QPointF( 0, -1 )
     520                 :          0 :               << QPointF( -0.8660, -0.5 );
     521                 :          0 :       return true;
     522                 :            : 
     523                 :            :     case Octagon:
     524                 :            :     {
     525                 :            :       static constexpr double VERTEX_OFFSET_FROM_ORIGIN = 1.0 / ( 1 + M_SQRT2 );
     526                 :            : 
     527                 :          0 :       polygon << QPointF( - VERTEX_OFFSET_FROM_ORIGIN, 1 )
     528                 :          0 :               << QPointF( VERTEX_OFFSET_FROM_ORIGIN, 1 )
     529                 :          0 :               << QPointF( 1, VERTEX_OFFSET_FROM_ORIGIN )
     530                 :          0 :               << QPointF( 1, -VERTEX_OFFSET_FROM_ORIGIN )
     531                 :          0 :               << QPointF( VERTEX_OFFSET_FROM_ORIGIN, -1 )
     532                 :          0 :               << QPointF( -VERTEX_OFFSET_FROM_ORIGIN, -1 )
     533                 :          0 :               << QPointF( -1, -VERTEX_OFFSET_FROM_ORIGIN )
     534                 :          0 :               << QPointF( -1, VERTEX_OFFSET_FROM_ORIGIN )
     535                 :          0 :               << QPointF( -VERTEX_OFFSET_FROM_ORIGIN, 1 );
     536                 :          0 :       return true;
     537                 :            :     }
     538                 :            : 
     539                 :            :     case Triangle:
     540                 :          0 :       polygon << QPointF( -1, 1 ) << QPointF( 1, 1 ) << QPointF( 0, -1 ) << QPointF( -1, 1 );
     541                 :          0 :       return true;
     542                 :            : 
     543                 :            :     case EquilateralTriangle:
     544                 :            :       /* angular-representation of hardcoded values used
     545                 :            :       polygon << QPointF( std::sin( DEG2RAD( 240.0 ) ), - std::cos( DEG2RAD( 240.0 ) ) )
     546                 :            :       << QPointF( std::sin( DEG2RAD( 120.0 ) ), - std::cos( DEG2RAD( 120.0 ) ) )
     547                 :            :       << QPointF( 0, -1 ); */
     548                 :          0 :       polygon << QPointF( -0.8660, 0.5 )
     549                 :          0 :               << QPointF( 0.8660, 0.5 )
     550                 :          0 :               << QPointF( 0, -1 )
     551                 :          0 :               << QPointF( -0.8660, 0.5 );
     552                 :          0 :       return true;
     553                 :            : 
     554                 :            :     case LeftHalfTriangle:
     555                 :          0 :       polygon << QPointF( 0, 1 ) << QPointF( 1, 1 ) << QPointF( 0, -1 ) << QPointF( 0, 1 );
     556                 :          0 :       return true;
     557                 :            : 
     558                 :            :     case RightHalfTriangle:
     559                 :          0 :       polygon << QPointF( -1, 1 ) << QPointF( 0, 1 ) << QPointF( 0, -1 ) << QPointF( -1, 1 );
     560                 :          0 :       return true;
     561                 :            : 
     562                 :            :     case Star:
     563                 :            :     {
     564                 :          0 :       double inner_r = std::cos( DEG2RAD( 72.0 ) ) / std::cos( DEG2RAD( 36.0 ) );
     565                 :            : 
     566                 :          0 :       polygon << QPointF( inner_r * std::sin( DEG2RAD( 324.0 ) ), - inner_r * std::cos( DEG2RAD( 324.0 ) ) )  // 324
     567                 :          0 :               << QPointF( std::sin( DEG2RAD( 288.0 ) ), - std::cos( DEG2RAD( 288 ) ) )    // 288
     568                 :          0 :               << QPointF( inner_r * std::sin( DEG2RAD( 252.0 ) ), - inner_r * std::cos( DEG2RAD( 252.0 ) ) )   // 252
     569                 :          0 :               << QPointF( std::sin( DEG2RAD( 216.0 ) ), - std::cos( DEG2RAD( 216.0 ) ) )   // 216
     570                 :          0 :               << QPointF( 0, inner_r )         // 180
     571                 :          0 :               << QPointF( std::sin( DEG2RAD( 144.0 ) ), - std::cos( DEG2RAD( 144.0 ) ) )   // 144
     572                 :          0 :               << QPointF( inner_r * std::sin( DEG2RAD( 108.0 ) ), - inner_r * std::cos( DEG2RAD( 108.0 ) ) )   // 108
     573                 :          0 :               << QPointF( std::sin( DEG2RAD( 72.0 ) ), - std::cos( DEG2RAD( 72.0 ) ) )    //  72
     574                 :          0 :               << QPointF( inner_r * std::sin( DEG2RAD( 36.0 ) ), - inner_r * std::cos( DEG2RAD( 36.0 ) ) )   //  36
     575                 :          0 :               << QPointF( 0, -1 )
     576                 :          0 :               << QPointF( inner_r * std::sin( DEG2RAD( 324.0 ) ), - inner_r * std::cos( DEG2RAD( 324.0 ) ) );  // 324;          //   0
     577                 :          0 :       return true;
     578                 :            :     }
     579                 :            : 
     580                 :            :     case Arrow:
     581                 :          0 :       polygon << QPointF( 0, -1 )
     582                 :          0 :               << QPointF( 0.5,  -0.5 )
     583                 :          0 :               << QPointF( 0.25, -0.5 )
     584                 :          0 :               << QPointF( 0.25,  1 )
     585                 :          0 :               << QPointF( -0.25,  1 )
     586                 :          0 :               << QPointF( -0.25, -0.5 )
     587                 :          0 :               << QPointF( -0.5,  -0.5 )
     588                 :          0 :               << QPointF( 0, -1 );
     589                 :          0 :       return true;
     590                 :            : 
     591                 :            :     case ArrowHeadFilled:
     592                 :          0 :       polygon << QPointF( 0, 0 ) << QPointF( -1, 1 ) << QPointF( -1, -1 ) << QPointF( 0, 0 );
     593                 :          0 :       return true;
     594                 :            : 
     595                 :            :     case CrossFill:
     596                 :          0 :       polygon << QPointF( -1, -0.2 )
     597                 :          0 :               << QPointF( -1, -0.2 )
     598                 :          0 :               << QPointF( -1, 0.2 )
     599                 :          0 :               << QPointF( -0.2, 0.2 )
     600                 :          0 :               << QPointF( -0.2, 1 )
     601                 :          0 :               << QPointF( 0.2, 1 )
     602                 :          0 :               << QPointF( 0.2, 0.2 )
     603                 :          0 :               << QPointF( 1, 0.2 )
     604                 :          0 :               << QPointF( 1, -0.2 )
     605                 :          0 :               << QPointF( 0.2, -0.2 )
     606                 :          0 :               << QPointF( 0.2, -1 )
     607                 :          0 :               << QPointF( -0.2, -1 )
     608                 :          0 :               << QPointF( -0.2, -0.2 )
     609                 :          0 :               << QPointF( -1, -0.2 );
     610                 :          0 :       return true;
     611                 :            : 
     612                 :            :     case AsteriskFill:
     613                 :            :     {
     614                 :            :       static constexpr double THICKNESS = 0.3;
     615                 :            :       static constexpr double HALF_THICKNESS = THICKNESS / 2.0;
     616                 :            :       static constexpr double INTERSECTION_POINT = THICKNESS / M_SQRT2;
     617                 :            :       static constexpr double DIAGONAL1 = M_SQRT1_2 - INTERSECTION_POINT * 0.5;
     618                 :            :       static constexpr double DIAGONAL2 = M_SQRT1_2 + INTERSECTION_POINT * 0.5;
     619                 :            : 
     620                 :          0 :       polygon << QPointF( -HALF_THICKNESS, -1 )
     621                 :          0 :               << QPointF( HALF_THICKNESS, -1 )
     622                 :          0 :               << QPointF( HALF_THICKNESS, -HALF_THICKNESS - INTERSECTION_POINT )
     623                 :          0 :               << QPointF( DIAGONAL1, -DIAGONAL2 )
     624                 :          0 :               << QPointF( DIAGONAL2, -DIAGONAL1 )
     625                 :          0 :               << QPointF( HALF_THICKNESS + INTERSECTION_POINT, -HALF_THICKNESS )
     626                 :          0 :               << QPointF( 1, -HALF_THICKNESS )
     627                 :          0 :               << QPointF( 1, HALF_THICKNESS )
     628                 :          0 :               << QPointF( HALF_THICKNESS + INTERSECTION_POINT, HALF_THICKNESS )
     629                 :          0 :               << QPointF( DIAGONAL2, DIAGONAL1 )
     630                 :          0 :               << QPointF( DIAGONAL1, DIAGONAL2 )
     631                 :          0 :               << QPointF( HALF_THICKNESS, HALF_THICKNESS + INTERSECTION_POINT )
     632                 :          0 :               << QPointF( HALF_THICKNESS, 1 )
     633                 :          0 :               << QPointF( -HALF_THICKNESS, 1 )
     634                 :          0 :               << QPointF( -HALF_THICKNESS, HALF_THICKNESS + INTERSECTION_POINT )
     635                 :          0 :               << QPointF( -DIAGONAL1, DIAGONAL2 )
     636                 :          0 :               << QPointF( -DIAGONAL2, DIAGONAL1 )
     637                 :          0 :               << QPointF( -HALF_THICKNESS - INTERSECTION_POINT, HALF_THICKNESS )
     638                 :          0 :               << QPointF( -1, HALF_THICKNESS )
     639                 :          0 :               << QPointF( -1, -HALF_THICKNESS )
     640                 :          0 :               << QPointF( -HALF_THICKNESS - INTERSECTION_POINT, -HALF_THICKNESS )
     641                 :          0 :               << QPointF( -DIAGONAL2, -DIAGONAL1 )
     642                 :          0 :               << QPointF( -DIAGONAL1, -DIAGONAL2 )
     643                 :          0 :               << QPointF( -HALF_THICKNESS, -HALF_THICKNESS - INTERSECTION_POINT )
     644                 :          0 :               << QPointF( -HALF_THICKNESS, -1 );
     645                 :          0 :       return true;
     646                 :            :     }
     647                 :            : 
     648                 :            :     case Circle:
     649                 :            :     case Cross:
     650                 :            :     case Cross2:
     651                 :            :     case Line:
     652                 :            :     case ArrowHead:
     653                 :            :     case SemiCircle:
     654                 :            :     case ThirdCircle:
     655                 :            :     case QuarterCircle:
     656                 :            :     case HalfArc:
     657                 :            :     case ThirdArc:
     658                 :            :     case QuarterArc:
     659                 :          0 :       return false;
     660                 :            :   }
     661                 :            : 
     662                 :          0 :   return false;
     663                 :          0 : }
     664                 :            : 
     665                 :          0 : bool QgsSimpleMarkerSymbolLayerBase::prepareMarkerPath( QgsSimpleMarkerSymbolLayerBase::Shape symbol )
     666                 :            : {
     667                 :          0 :   mPath = QPainterPath();
     668                 :            : 
     669                 :          0 :   switch ( symbol )
     670                 :            :   {
     671                 :            :     case Circle:
     672                 :            : 
     673                 :          0 :       mPath.addEllipse( QRectF( -1, -1, 2, 2 ) ); // x,y,w,h
     674                 :          0 :       return true;
     675                 :            : 
     676                 :            :     case SemiCircle:
     677                 :          0 :       mPath.arcTo( -1, -1, 2, 2, 0, 180 );
     678                 :         40 :       mPath.lineTo( 0, 0 );
     679                 :          0 :       return true;
     680                 :         40 : 
     681                 :            :     case ThirdCircle:
     682                 :          0 :       mPath.arcTo( -1, -1, 2, 2, 90, 120 );
     683                 :         40 :       mPath.lineTo( 0, 0 );
     684                 :          0 :       return true;
     685                 :            : 
     686                 :            :     case QuarterCircle:
     687                 :          0 :       mPath.arcTo( -1, -1, 2, 2, 90, 90 );
     688                 :          0 :       mPath.lineTo( 0, 0 );
     689                 :          0 :       return true;
     690                 :            : 
     691                 :            :     case HalfArc:
     692                 :          0 :       mPath.moveTo( 1, 0 );
     693                 :          0 :       mPath.arcTo( -1, -1, 2, 2, 0, 180 );
     694                 :          0 :       return true;
     695                 :            : 
     696                 :            :     case ThirdArc:
     697                 :          0 :       mPath.moveTo( 0, -1 );
     698                 :          0 :       mPath.arcTo( -1, -1, 2, 2, 90, 120 );
     699                 :          0 :       return true;
     700                 :            : 
     701                 :            :     case QuarterArc:
     702                 :          0 :       mPath.moveTo( 0, -1 );
     703                 :          0 :       mPath.arcTo( -1, -1, 2, 2, 90, 90 );
     704                 :          0 :       return true;
     705                 :            : 
     706                 :            :     case Cross:
     707                 :          0 :       mPath.moveTo( -1, 0 );
     708                 :          0 :       mPath.lineTo( 1, 0 ); // horizontal
     709                 :          0 :       mPath.moveTo( 0, -1 );
     710                 :          0 :       mPath.lineTo( 0, 1 ); // vertical
     711                 :          0 :       return true;
     712                 :            : 
     713                 :            :     case Cross2:
     714                 :          0 :       mPath.moveTo( -1, -1 );
     715                 :          0 :       mPath.lineTo( 1, 1 );
     716                 :          0 :       mPath.moveTo( 1, -1 );
     717                 :          0 :       mPath.lineTo( -1, 1 );
     718                 :          0 :       return true;
     719                 :            : 
     720                 :            :     case Line:
     721                 :          0 :       mPath.moveTo( 0, -1 );
     722                 :          0 :       mPath.lineTo( 0, 1 ); // vertical line
     723                 :          0 :       return true;
     724                 :            : 
     725                 :            :     case ArrowHead:
     726                 :          0 :       mPath.moveTo( -1, -1 );
     727                 :          0 :       mPath.lineTo( 0, 0 );
     728                 :          0 :       mPath.lineTo( -1, 1 );
     729                 :          0 :       return true;
     730                 :            : 
     731                 :            :     case Square:
     732                 :            :     case SquareWithCorners:
     733                 :            :     case QuarterSquare:
     734                 :            :     case HalfSquare:
     735                 :            :     case DiagonalHalfSquare:
     736                 :            :     case Diamond:
     737                 :            :     case Pentagon:
     738                 :            :     case Hexagon:
     739                 :            :     case Octagon:
     740                 :            :     case Triangle:
     741                 :            :     case EquilateralTriangle:
     742                 :            :     case LeftHalfTriangle:
     743                 :            :     case RightHalfTriangle:
     744                 :            :     case Star:
     745                 :            :     case Arrow:
     746                 :            :     case ArrowHeadFilled:
     747                 :            :     case CrossFill:
     748                 :            :     case AsteriskFill:
     749                 :          0 :       return false;
     750                 :            :   }
     751                 :          0 :   return false;
     752                 :          0 : }
     753                 :            : 
     754                 :          0 : double QgsSimpleMarkerSymbolLayerBase::calculateSize( QgsSymbolRenderContext &context, bool &hasDataDefinedSize ) const
     755                 :            : {
     756                 :          0 :   double scaledSize = mSize;
     757                 :            : 
     758                 :          0 :   hasDataDefinedSize = mDataDefinedProperties.isActive( QgsSymbolLayer::PropertySize );
     759                 :          0 :   bool ok = true;
     760                 :          0 :   if ( hasDataDefinedSize )
     761                 :            :   {
     762                 :          0 :     context.setOriginalValueVariable( mSize );
     763                 :          0 :     scaledSize = mDataDefinedProperties.valueAsDouble( QgsSymbolLayer::PropertySize, context.renderContext().expressionContext(),
     764                 :          0 :                  mSize, &ok );
     765                 :          0 :   }
     766                 :            : 
     767                 :          0 :   if ( hasDataDefinedSize && ok )
     768                 :            :   {
     769                 :          0 :     switch ( mScaleMethod )
     770                 :            :     {
     771                 :            :       case QgsSymbol::ScaleArea:
     772                 :          0 :         scaledSize = std::sqrt( scaledSize );
     773                 :          0 :         break;
     774                 :            :       case QgsSymbol::ScaleDiameter:
     775                 :          0 :         break;
     776                 :            :     }
     777                 :          0 :   }
     778                 :            : 
     779                 :          0 :   return scaledSize;
     780                 :          0 : }
     781                 :            : 
     782                 :          0 : void QgsSimpleMarkerSymbolLayerBase::calculateOffsetAndRotation( QgsSymbolRenderContext &context, double scaledSize, bool &hasDataDefinedRotation, QPointF &offset, double &angle ) const
     783                 :            : {
     784                 :            :   //offset
     785                 :          0 :   double offsetX = 0;
     786                 :          0 :   double offsetY = 0;
     787                 :          0 :   markerOffset( context, scaledSize, scaledSize, offsetX, offsetY );
     788                 :          0 :   offset = QPointF( offsetX, offsetY );
     789                 :            : 
     790                 :          0 :   hasDataDefinedRotation = false;
     791                 :            :   //angle
     792                 :          0 :   bool ok = true;
     793                 :          0 :   angle = mAngle + mLineAngle;
     794                 :          0 :   if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyAngle ) )
     795                 :            :   {
     796                 :          0 :     context.setOriginalValueVariable( angle );
     797                 :          0 :     angle = mDataDefinedProperties.valueAsDouble( QgsSymbolLayer::PropertyAngle, context.renderContext().expressionContext(), 0, &ok ) + mLineAngle;
     798                 :            : 
     799                 :            :     // If the expression evaluation was not successful, fallback to static value
     800                 :          0 :     if ( !ok )
     801                 :          0 :       angle = mAngle + mLineAngle;
     802                 :            : 
     803                 :          0 :     hasDataDefinedRotation = true;
     804                 :          0 :   }
     805                 :            : 
     806                 :          0 :   hasDataDefinedRotation = context.renderHints() & QgsSymbol::DynamicRotation || hasDataDefinedRotation;
     807                 :            : 
     808                 :          0 :   if ( hasDataDefinedRotation )
     809                 :            :   {
     810                 :            :     // For non-point markers, "dataDefinedRotation" means following the
     811                 :            :     // shape (shape-data defined). For them, "field-data defined" does
     812                 :            :     // not work at all. TODO: if "field-data defined" ever gets implemented
     813                 :            :     // we'll need a way to distinguish here between the two, possibly
     814                 :            :     // using another flag in renderHints()
     815                 :          0 :     const QgsFeature *f = context.feature();
     816                 :          0 :     if ( f )
     817                 :            :     {
     818                 :          0 :       if ( f->hasGeometry() && f->geometry().type() == QgsWkbTypes::PointGeometry )
     819                 :            :       {
     820                 :          0 :         const QgsMapToPixel &m2p = context.renderContext().mapToPixel();
     821                 :          0 :         angle += m2p.mapRotation();
     822                 :          0 :       }
     823                 :          0 :     }
     824                 :          0 :   }
     825                 :            : 
     826                 :          0 :   if ( angle )
     827                 :          0 :     offset = _rotatedOffset( offset, angle );
     828                 :          0 : }
     829                 :            : 
     830                 :          0 : 
     831                 :            : //
     832                 :          0 : // QgsSimpleMarkerSymbolLayer
     833                 :            : //
     834                 :          0 : 
     835                 :        332 : QgsSimpleMarkerSymbolLayer::QgsSimpleMarkerSymbolLayer( QgsSimpleMarkerSymbolLayerBase::Shape shape, double size, double angle, QgsSymbol::ScaleMethod scaleMethod, const QColor &color, const QColor &strokeColor, Qt::PenJoinStyle penJoinStyle )
     836                 :        332 :   : QgsSimpleMarkerSymbolLayerBase( shape, size, angle, scaleMethod )
     837                 :        332 :   , mStrokeColor( strokeColor )
     838                 :        332 :   , mPenJoinStyle( penJoinStyle )
     839                 :        664 : {
     840                 :        332 :   mColor = color;
     841                 :        332 : }
     842                 :            : 
     843                 :        230 : QgsSymbolLayer *QgsSimpleMarkerSymbolLayer::create( const QVariantMap &props )
     844                 :            : {
     845                 :        230 :   Shape shape = Circle;
     846                 :        230 :   QColor color = DEFAULT_SIMPLEMARKER_COLOR;
     847                 :        230 :   QColor strokeColor = DEFAULT_SIMPLEMARKER_BORDERCOLOR;
     848                 :        230 :   Qt::PenJoinStyle penJoinStyle = DEFAULT_SIMPLEMARKER_JOINSTYLE;
     849                 :        230 :   double size = DEFAULT_SIMPLEMARKER_SIZE;
     850                 :        230 :   double angle = DEFAULT_SIMPLEMARKER_ANGLE;
     851                 :        230 :   QgsSymbol::ScaleMethod scaleMethod = DEFAULT_SCALE_METHOD;
     852                 :            : 
     853                 :        460 :   if ( props.contains( QStringLiteral( "name" ) ) )
     854                 :            :   {
     855                 :        460 :     shape = decodeShape( props[QStringLiteral( "name" )].toString() );
     856                 :        230 :   }
     857                 :        460 :   if ( props.contains( QStringLiteral( "color" ) ) )
     858                 :        460 :     color = QgsSymbolLayerUtils::decodeColor( props[QStringLiteral( "color" )].toString() );
     859                 :        460 :   if ( props.contains( QStringLiteral( "color_border" ) ) )
     860                 :            :   {
     861                 :            :     //pre 2.5 projects use "color_border"
     862                 :          0 :     strokeColor = QgsSymbolLayerUtils::decodeColor( props[QStringLiteral( "color_border" )].toString() );
     863                 :          0 :   }
     864                 :        460 :   else if ( props.contains( QStringLiteral( "outline_color" ) ) )
     865                 :            :   {
     866                 :        460 :     strokeColor = QgsSymbolLayerUtils::decodeColor( props[QStringLiteral( "outline_color" )].toString() );
     867                 :        230 :   }
     868                 :          0 :   else if ( props.contains( QStringLiteral( "line_color" ) ) )
     869                 :            :   {
     870                 :          0 :     strokeColor = QgsSymbolLayerUtils::decodeColor( props[QStringLiteral( "line_color" )].toString() );
     871                 :          0 :   }
     872                 :        460 :   if ( props.contains( QStringLiteral( "joinstyle" ) ) )
     873                 :            :   {
     874                 :        460 :     penJoinStyle = QgsSymbolLayerUtils::decodePenJoinStyle( props[QStringLiteral( "joinstyle" )].toString() );
     875                 :        230 :   }
     876                 :        460 :   if ( props.contains( QStringLiteral( "size" ) ) )
     877                 :        460 :     size = props[QStringLiteral( "size" )].toDouble();
     878                 :        460 :   if ( props.contains( QStringLiteral( "angle" ) ) )
     879                 :        460 :     angle = props[QStringLiteral( "angle" )].toDouble();
     880                 :        460 :   if ( props.contains( QStringLiteral( "scale_method" ) ) )
     881                 :        460 :     scaleMethod = QgsSymbolLayerUtils::decodeScaleMethod( props[QStringLiteral( "scale_method" )].toString() );
     882                 :            : 
     883                 :        230 :   QgsSimpleMarkerSymbolLayer *m = new QgsSimpleMarkerSymbolLayer( shape, size, angle, scaleMethod, color, strokeColor, penJoinStyle );
     884                 :        460 :   if ( props.contains( QStringLiteral( "offset" ) ) )
     885                 :        460 :     m->setOffset( QgsSymbolLayerUtils::decodePoint( props[QStringLiteral( "offset" )].toString() ) );
     886                 :        460 :   if ( props.contains( QStringLiteral( "offset_unit" ) ) )
     887                 :        460 :     m->setOffsetUnit( QgsUnitTypes::decodeRenderUnit( props[QStringLiteral( "offset_unit" )].toString() ) );
     888                 :        460 :   if ( props.contains( QStringLiteral( "offset_map_unit_scale" ) ) )
     889                 :        460 :     m->setOffsetMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( props[QStringLiteral( "offset_map_unit_scale" )].toString() ) );
     890                 :        460 :   if ( props.contains( QStringLiteral( "size_unit" ) ) )
     891                 :        460 :     m->setSizeUnit( QgsUnitTypes::decodeRenderUnit( props[QStringLiteral( "size_unit" )].toString() ) );
     892                 :        460 :   if ( props.contains( QStringLiteral( "size_map_unit_scale" ) ) )
     893                 :        460 :     m->setSizeMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( props[QStringLiteral( "size_map_unit_scale" )].toString() ) );
     894                 :            : 
     895                 :        460 :   if ( props.contains( QStringLiteral( "outline_style" ) ) )
     896                 :            :   {
     897                 :        460 :     m->setStrokeStyle( QgsSymbolLayerUtils::decodePenStyle( props[QStringLiteral( "outline_style" )].toString() ) );
     898                 :        230 :   }
     899                 :          0 :   else if ( props.contains( QStringLiteral( "line_style" ) ) )
     900                 :            :   {
     901                 :          0 :     m->setStrokeStyle( QgsSymbolLayerUtils::decodePenStyle( props[QStringLiteral( "line_style" )].toString() ) );
     902                 :          0 :   }
     903                 :        460 :   if ( props.contains( QStringLiteral( "outline_width" ) ) )
     904                 :            :   {
     905                 :        460 :     m->setStrokeWidth( props[QStringLiteral( "outline_width" )].toDouble() );
     906                 :        230 :   }
     907                 :          0 :   else if ( props.contains( QStringLiteral( "line_width" ) ) )
     908                 :            :   {
     909                 :          0 :     m->setStrokeWidth( props[QStringLiteral( "line_width" )].toDouble() );
     910                 :          0 :   }
     911                 :        460 :   if ( props.contains( QStringLiteral( "outline_width_unit" ) ) )
     912                 :            :   {
     913                 :        460 :     m->setStrokeWidthUnit( QgsUnitTypes::decodeRenderUnit( props[QStringLiteral( "outline_width_unit" )].toString() ) );
     914                 :        230 :   }
     915                 :        460 :   if ( props.contains( QStringLiteral( "line_width_unit" ) ) )
     916                 :            :   {
     917                 :          0 :     m->setStrokeWidthUnit( QgsUnitTypes::decodeRenderUnit( props[QStringLiteral( "line_width_unit" )].toString() ) );
     918                 :          0 :   }
     919                 :        460 :   if ( props.contains( QStringLiteral( "outline_width_map_unit_scale" ) ) )
     920                 :            :   {
     921                 :        460 :     m->setStrokeWidthMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( props[QStringLiteral( "outline_width_map_unit_scale" )].toString() ) );
     922                 :        230 :   }
     923                 :            : 
     924                 :        460 :   if ( props.contains( QStringLiteral( "horizontal_anchor_point" ) ) )
     925                 :            :   {
     926                 :        460 :     m->setHorizontalAnchorPoint( QgsMarkerSymbolLayer::HorizontalAnchorPoint( props[ QStringLiteral( "horizontal_anchor_point" )].toInt() ) );
     927                 :        230 :   }
     928                 :        460 :   if ( props.contains( QStringLiteral( "vertical_anchor_point" ) ) )
     929                 :            :   {
     930                 :        460 :     m->setVerticalAnchorPoint( QgsMarkerSymbolLayer::VerticalAnchorPoint( props[ QStringLiteral( "vertical_anchor_point" )].toInt() ) );
     931                 :        230 :   }
     932                 :            : 
     933                 :        460 :   if ( props.contains( QStringLiteral( "cap_style" ) ) )
     934                 :            :   {
     935                 :        276 :     m->setPenCapStyle( QgsSymbolLayerUtils::decodePenCapStyle( props[QStringLiteral( "cap_style" )].toString() ) );
     936                 :        138 :   }
     937                 :            : 
     938                 :        230 :   m->restoreOldDataDefinedProperties( props );
     939                 :            : 
     940                 :        230 :   return m;
     941                 :          0 : }
     942                 :            : 
     943                 :            : 
     944                 :          0 : QString QgsSimpleMarkerSymbolLayer::layerType() const
     945                 :            : {
     946                 :          0 :   return QStringLiteral( "SimpleMarker" );
     947                 :            : }
     948                 :            : 
     949                 :          0 : void QgsSimpleMarkerSymbolLayer::startRender( QgsSymbolRenderContext &context )
     950                 :            : {
     951                 :          0 :   QgsSimpleMarkerSymbolLayerBase::startRender( context );
     952                 :            : 
     953                 :          0 :   QColor brushColor = mColor;
     954                 :          0 :   QColor penColor = mStrokeColor;
     955                 :            : 
     956                 :          0 :   brushColor.setAlphaF( mColor.alphaF() * context.opacity() );
     957                 :          0 :   penColor.setAlphaF( mStrokeColor.alphaF() * context.opacity() );
     958                 :            : 
     959                 :          0 :   mBrush = QBrush( brushColor );
     960                 :          0 :   mPen = QPen( penColor );
     961                 :          0 :   mPen.setStyle( mStrokeStyle );
     962                 :          0 :   mPen.setCapStyle( mPenCapStyle );
     963                 :          0 :   mPen.setJoinStyle( mPenJoinStyle );
     964                 :          0 :   mPen.setWidthF( context.renderContext().convertToPainterUnits( mStrokeWidth, mStrokeWidthUnit, mStrokeWidthMapUnitScale ) );
     965                 :            : 
     966                 :          0 :   QColor selBrushColor = context.renderContext().selectionColor();
     967                 :          0 :   QColor selPenColor = selBrushColor == mColor ? selBrushColor : mStrokeColor;
     968                 :          0 :   if ( context.opacity() < 1  && !SELECTION_IS_OPAQUE )
     969                 :            :   {
     970                 :          0 :     selBrushColor.setAlphaF( context.opacity() );
     971                 :          0 :     selPenColor.setAlphaF( context.opacity() );
     972                 :          0 :   }
     973                 :          0 :   mSelBrush = QBrush( selBrushColor );
     974                 :          0 :   mSelPen = QPen( selPenColor );
     975                 :          0 :   mSelPen.setStyle( mStrokeStyle );
     976                 :          0 :   mSelPen.setWidthF( context.renderContext().convertToPainterUnits( mStrokeWidth, mStrokeWidthUnit, mStrokeWidthMapUnitScale ) );
     977                 :            : 
     978                 :          0 :   bool hasDataDefinedRotation = context.renderHints() & QgsSymbol::DynamicRotation || mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyAngle );
     979                 :          0 :   bool hasDataDefinedSize = mDataDefinedProperties.isActive( QgsSymbolLayer::PropertySize );
     980                 :            : 
     981                 :            :   // use caching only when:
     982                 :            :   // - size, rotation, shape, color, stroke color is not data-defined
     983                 :            :   // - drawing to screen (not printer)
     984                 :          0 :   mUsingCache = !hasDataDefinedRotation && !hasDataDefinedSize && !context.renderContext().forceVectorOutput()
     985                 :          0 :                 && !mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyName ) && !mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyFillColor ) && !mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyStrokeColor )
     986                 :          0 :                 && !mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyStrokeWidth ) && !mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyStrokeStyle )
     987                 :          0 :                 && !mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyJoinStyle );
     988                 :            : 
     989                 :          0 :   if ( mUsingCache )
     990                 :          0 :     mCachedOpacity = context.opacity();
     991                 :            : 
     992                 :          0 :   if ( !shapeIsFilled( mShape ) )
     993                 :            :   {
     994                 :            :     // some markers can't be drawn as a polygon (circle, cross)
     995                 :            :     // For these set the selected stroke color to the selected color
     996                 :          0 :     mSelPen.setColor( selBrushColor );
     997                 :          0 :   }
     998                 :            : 
     999                 :            : 
    1000                 :          0 :   if ( mUsingCache )
    1001                 :            :   {
    1002                 :          0 :     if ( !prepareCache( context ) )
    1003                 :            :     {
    1004                 :          0 :       mUsingCache = false;
    1005                 :          0 :     }
    1006                 :          0 :   }
    1007                 :            :   else
    1008                 :            :   {
    1009                 :          0 :     mCache = QImage();
    1010                 :          0 :     mSelCache = QImage();
    1011                 :            :   }
    1012                 :          0 : }
    1013                 :            : 
    1014                 :            : 
    1015                 :          0 : bool QgsSimpleMarkerSymbolLayer::prepareCache( QgsSymbolRenderContext &context )
    1016                 :            : {
    1017                 :          0 :   double scaledSize = context.renderContext().convertToPainterUnits( mSize, mSizeUnit, mSizeMapUnitScale );
    1018                 :          0 :   if ( mSizeUnit == QgsUnitTypes::RenderMetersInMapUnits && context.renderContext().flags() & QgsRenderContext::RenderSymbolPreview )
    1019                 :            :   {
    1020                 :            :     // rendering for symbol previews -- a size in meters in map units can't be calculated, so treat the size as millimeters
    1021                 :            :     // and clamp it to a reasonable range. It's the best we can do in this situation!
    1022                 :          0 :     scaledSize = std::min( std::max( context.renderContext().convertToPainterUnits( mSize, QgsUnitTypes::RenderMillimeters ), 3.0 ), 100.0 );
    1023                 :          0 :   }
    1024                 :            : 
    1025                 :            :   // take into account angle (which is not data-defined otherwise cache wouldn't be used)
    1026                 :          0 :   if ( !qgsDoubleNear( mAngle, 0.0 ) )
    1027                 :            :   {
    1028                 :          0 :     scaledSize = ( std::abs( std::sin( mAngle * M_PI / 180 ) ) + std::abs( std::cos( mAngle * M_PI / 180 ) ) ) * scaledSize;
    1029                 :          0 :   }
    1030                 :            :   // calculate necessary image size for the cache
    1031                 :          0 :   double pw = static_cast< int >( std::round( ( ( qgsDoubleNear( mPen.widthF(), 0.0 ) ? 1 : mPen.widthF() * 4 ) + 1 ) ) ) / 2 * 2; // make even (round up); handle cosmetic pen
    1032                 :          0 :   int imageSize = ( static_cast< int >( scaledSize ) + pw ) / 2 * 2 + 1; //  make image width, height odd; account for pen width
    1033                 :          0 :   double center = imageSize / 2.0;
    1034                 :          0 :   if ( imageSize > MAXIMUM_CACHE_WIDTH )
    1035                 :            :   {
    1036                 :          0 :     return false;
    1037                 :            :   }
    1038                 :            : 
    1039                 :          0 :   mCache = QImage( QSize( imageSize, imageSize ), QImage::Format_ARGB32_Premultiplied );
    1040                 :          0 :   mCache.fill( 0 );
    1041                 :            : 
    1042                 :          0 :   bool needsBrush = shapeIsFilled( mShape );
    1043                 :          0 : 
    1044                 :          0 :   QPainter p;
    1045                 :          0 :   p.begin( &mCache );
    1046                 :          0 :   p.setRenderHint( QPainter::Antialiasing );
    1047                 :          0 :   p.setBrush( needsBrush ? mBrush : Qt::NoBrush );
    1048                 :          0 :   p.setPen( mPen );
    1049                 :          0 :   p.translate( QPointF( center, center ) );
    1050                 :          0 :   drawMarker( &p, context );
    1051                 :          0 :   p.end();
    1052                 :            : 
    1053                 :            :   // Construct the selected version of the Cache
    1054                 :            : 
    1055                 :          0 :   QColor selColor = context.renderContext().selectionColor();
    1056                 :          0 : 
    1057                 :          0 :   mSelCache = QImage( QSize( imageSize, imageSize ), QImage::Format_ARGB32_Premultiplied );
    1058                 :          0 :   mSelCache.fill( 0 );
    1059                 :            : 
    1060                 :          0 :   p.begin( &mSelCache );
    1061                 :          0 :   p.setRenderHint( QPainter::Antialiasing );
    1062                 :          0 :   p.setBrush( needsBrush ? mSelBrush : Qt::NoBrush );
    1063                 :          0 :   p.setPen( mSelPen );
    1064                 :          0 :   p.translate( QPointF( center, center ) );
    1065                 :          0 :   drawMarker( &p, context );
    1066                 :          0 :   p.end();
    1067                 :            : 
    1068                 :            :   // Check that the selected version is different.  If not, then re-render,
    1069                 :            :   // filling the background with the selection color and using the normal
    1070                 :            :   // colors for the symbol .. could be ugly!
    1071                 :            : 
    1072                 :          0 :   if ( mSelCache == mCache )
    1073                 :            :   {
    1074                 :          0 :     p.begin( &mSelCache );
    1075                 :          0 :     p.setRenderHint( QPainter::Antialiasing );
    1076                 :          0 :     p.fillRect( 0, 0, imageSize, imageSize, selColor );
    1077                 :          0 :     p.setBrush( needsBrush ? mBrush : Qt::NoBrush );
    1078                 :          0 :     p.setPen( mPen );
    1079                 :          0 :     p.translate( QPointF( center, center ) );
    1080                 :          0 :     drawMarker( &p, context );
    1081                 :          0 :     p.end();
    1082                 :          0 :   }
    1083                 :            : 
    1084                 :          0 :   return true;
    1085                 :          0 : }
    1086                 :            : 
    1087                 :          0 : void QgsSimpleMarkerSymbolLayer::draw( QgsSymbolRenderContext &context, QgsSimpleMarkerSymbolLayerBase::Shape shape, const QPolygonF &polygon, const QPainterPath &path )
    1088                 :            : {
    1089                 :            :   //making changes here? Don't forget to also update ::bounds if the changes affect the bounding box
    1090                 :            :   //of the rendered point!
    1091                 :            : 
    1092                 :          0 :   QPainter *p = context.renderContext().painter();
    1093                 :          0 :   if ( !p )
    1094                 :            :   {
    1095                 :          0 :     return;
    1096                 :            :   }
    1097                 :            : 
    1098                 :          0 :   QColor brushColor = mColor;
    1099                 :          0 :   brushColor.setAlphaF( brushColor.alphaF() * context.opacity() );
    1100                 :          0 :   mBrush.setColor( brushColor );
    1101                 :            : 
    1102                 :          0 :   QColor penColor = mStrokeColor;
    1103                 :          0 :   penColor.setAlphaF( penColor.alphaF() * context.opacity() );
    1104                 :          0 :   mPen.setColor( penColor );
    1105                 :            : 
    1106                 :          0 :   bool ok = true;
    1107                 :          0 :   if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyFillColor ) )
    1108                 :            :   {
    1109                 :          0 :     context.setOriginalValueVariable( QgsSymbolLayerUtils::encodeColor( mColor ) );
    1110                 :          0 :     QColor c = mDataDefinedProperties.valueAsColor( QgsSymbolLayer::PropertyFillColor, context.renderContext().expressionContext(), mColor, &ok );
    1111                 :          0 :     if ( ok )
    1112                 :            :     {
    1113                 :          0 :       c.setAlphaF( c.alphaF() * context.opacity() );
    1114                 :          0 :       mBrush.setColor( c );
    1115                 :          0 :     }
    1116                 :          0 :   }
    1117                 :          0 :   if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyStrokeColor ) )
    1118                 :            :   {
    1119                 :          0 :     context.setOriginalValueVariable( QgsSymbolLayerUtils::encodeColor( mStrokeColor ) );
    1120                 :          0 :     QColor c = mDataDefinedProperties.valueAsColor( QgsSymbolLayer::PropertyStrokeColor, context.renderContext().expressionContext(), mStrokeColor, &ok );
    1121                 :          0 :     if ( ok )
    1122                 :            :     {
    1123                 :          0 :       c.setAlphaF( c.alphaF() * context.opacity() );
    1124                 :          0 :       mPen.setColor( c );
    1125                 :          0 :       mSelPen.setColor( c );
    1126                 :          0 :     }
    1127                 :          0 :   }
    1128                 :          0 :   if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyStrokeWidth ) )
    1129                 :            :   {
    1130                 :          0 :     context.setOriginalValueVariable( mStrokeWidth );
    1131                 :          0 :     double strokeWidth = mDataDefinedProperties.valueAsDouble( QgsSymbolLayer::PropertyStrokeWidth, context.renderContext().expressionContext(), 0, &ok );
    1132                 :          0 :     if ( ok )
    1133                 :            :     {
    1134                 :          0 :       mPen.setWidthF( context.renderContext().convertToPainterUnits( strokeWidth, mStrokeWidthUnit, mStrokeWidthMapUnitScale ) );
    1135                 :          0 :       mSelPen.setWidthF( context.renderContext().convertToPainterUnits( strokeWidth, mStrokeWidthUnit, mStrokeWidthMapUnitScale ) );
    1136                 :          0 :     }
    1137                 :          0 :   }
    1138                 :          0 :   if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyStrokeStyle ) )
    1139                 :            :   {
    1140                 :          0 :     context.setOriginalValueVariable( QgsSymbolLayerUtils::encodePenStyle( mStrokeStyle ) );
    1141                 :          0 :     QString strokeStyle = mDataDefinedProperties.valueAsString( QgsSymbolLayer::PropertyStrokeStyle, context.renderContext().expressionContext(), QString(), &ok );
    1142                 :          0 :     if ( ok )
    1143                 :            :     {
    1144                 :          0 :       mPen.setStyle( QgsSymbolLayerUtils::decodePenStyle( strokeStyle ) );
    1145                 :          0 :       mSelPen.setStyle( QgsSymbolLayerUtils::decodePenStyle( strokeStyle ) );
    1146                 :          0 :     }
    1147                 :          0 :   }
    1148                 :          0 :   if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyJoinStyle ) )
    1149                 :            :   {
    1150                 :          0 :     context.setOriginalValueVariable( QgsSymbolLayerUtils::encodePenJoinStyle( mPenJoinStyle ) );
    1151                 :          0 :     QString style = mDataDefinedProperties.valueAsString( QgsSymbolLayer::PropertyJoinStyle, context.renderContext().expressionContext(), QString(), &ok );
    1152                 :          0 :     if ( ok )
    1153                 :            :     {
    1154                 :          0 :       mPen.setJoinStyle( QgsSymbolLayerUtils::decodePenJoinStyle( style ) );
    1155                 :          0 :       mSelPen.setJoinStyle( QgsSymbolLayerUtils::decodePenJoinStyle( style ) );
    1156                 :          0 :     }
    1157                 :          0 :   }
    1158                 :          0 :   if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyCapStyle ) )
    1159                 :            :   {
    1160                 :          0 :     context.setOriginalValueVariable( QgsSymbolLayerUtils::encodePenCapStyle( mPenCapStyle ) );
    1161                 :          0 :     QString style = mDataDefinedProperties.valueAsString( QgsSymbolLayer::PropertyCapStyle, context.renderContext().expressionContext(), QString(), &ok );
    1162                 :          0 :     if ( ok )
    1163                 :            :     {
    1164                 :          0 :       mPen.setCapStyle( QgsSymbolLayerUtils::decodePenCapStyle( style ) );
    1165                 :          0 :       mSelPen.setCapStyle( QgsSymbolLayerUtils::decodePenCapStyle( style ) );
    1166                 :          0 :     }
    1167                 :          0 :   }
    1168                 :            : 
    1169                 :          0 :   if ( shapeIsFilled( shape ) )
    1170                 :            :   {
    1171                 :          0 :     p->setBrush( context.selected() ? mSelBrush : mBrush );
    1172                 :          0 :   }
    1173                 :            :   else
    1174                 :            :   {
    1175                 :          0 :     p->setBrush( Qt::NoBrush );
    1176                 :            :   }
    1177                 :          0 :   p->setPen( context.selected() ? mSelPen : mPen );
    1178                 :            : 
    1179                 :          0 :   if ( !polygon.isEmpty() )
    1180                 :          0 :     p->drawPolygon( polygon );
    1181                 :            :   else
    1182                 :          0 :     p->drawPath( path );
    1183                 :          0 : }
    1184                 :            : 
    1185                 :          0 : void QgsSimpleMarkerSymbolLayer::renderPoint( QPointF point, QgsSymbolRenderContext &context )
    1186                 :            : {
    1187                 :            :   //making changes here? Don't forget to also update ::bounds if the changes affect the bounding box
    1188                 :            :   //of the rendered point!
    1189                 :            : 
    1190                 :          0 :   QPainter *p = context.renderContext().painter();
    1191                 :          0 :   if ( !p )
    1192                 :            :   {
    1193                 :          0 :     return;
    1194                 :            :   }
    1195                 :            : 
    1196                 :          0 :   if ( mUsingCache && qgsDoubleNear( mCachedOpacity, context.opacity() ) )
    1197                 :            :   {
    1198                 :          0 :     QImage &img = context.selected() ? mSelCache : mCache;
    1199                 :          0 :     double s = img.width();
    1200                 :            : 
    1201                 :          0 :     bool hasDataDefinedSize = false;
    1202                 :          0 :     double scaledSize = calculateSize( context, hasDataDefinedSize );
    1203                 :            : 
    1204                 :          0 :     bool hasDataDefinedRotation = false;
    1205                 :          0 :     QPointF offset;
    1206                 :          0 :     double angle = 0;
    1207                 :          0 :     calculateOffsetAndRotation( context, scaledSize, hasDataDefinedRotation, offset, angle );
    1208                 :            : 
    1209                 :          0 :     p->drawImage( QRectF( point.x() - s / 2.0 + offset.x(),
    1210                 :          0 :                           point.y() - s / 2.0 + offset.y(),
    1211                 :          0 :                           s, s ), img );
    1212                 :          0 :   }
    1213                 :            :   else
    1214                 :            :   {
    1215                 :          0 :     QgsSimpleMarkerSymbolLayerBase::renderPoint( point, context );
    1216                 :            :   }
    1217                 :          0 : }
    1218                 :            : 
    1219                 :          0 : QVariantMap QgsSimpleMarkerSymbolLayer::properties() const
    1220                 :            : {
    1221                 :          0 :   QVariantMap map;
    1222                 :          0 :   map[QStringLiteral( "name" )] = encodeShape( mShape );
    1223                 :          0 :   map[QStringLiteral( "color" )] = QgsSymbolLayerUtils::encodeColor( mColor );
    1224                 :          0 :   map[QStringLiteral( "outline_color" )] = QgsSymbolLayerUtils::encodeColor( mStrokeColor );
    1225                 :          0 :   map[QStringLiteral( "size" )] = QString::number( mSize );
    1226                 :          0 :   map[QStringLiteral( "size_unit" )] = QgsUnitTypes::encodeUnit( mSizeUnit );
    1227                 :          0 :   map[QStringLiteral( "size_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mSizeMapUnitScale );
    1228                 :          0 :   map[QStringLiteral( "angle" )] = QString::number( mAngle );
    1229                 :          0 :   map[QStringLiteral( "offset" )] = QgsSymbolLayerUtils::encodePoint( mOffset );
    1230                 :          0 :   map[QStringLiteral( "offset_unit" )] = QgsUnitTypes::encodeUnit( mOffsetUnit );
    1231                 :          0 :   map[QStringLiteral( "offset_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mOffsetMapUnitScale );
    1232                 :          0 :   map[QStringLiteral( "scale_method" )] = QgsSymbolLayerUtils::encodeScaleMethod( mScaleMethod );
    1233                 :          0 :   map[QStringLiteral( "outline_style" )] = QgsSymbolLayerUtils::encodePenStyle( mStrokeStyle );
    1234                 :          0 :   map[QStringLiteral( "outline_width" )] = QString::number( mStrokeWidth );
    1235                 :          0 :   map[QStringLiteral( "outline_width_unit" )] = QgsUnitTypes::encodeUnit( mStrokeWidthUnit );
    1236                 :          0 :   map[QStringLiteral( "outline_width_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mStrokeWidthMapUnitScale );
    1237                 :          0 :   map[QStringLiteral( "joinstyle" )] = QgsSymbolLayerUtils::encodePenJoinStyle( mPenJoinStyle );
    1238                 :          0 :   map[QStringLiteral( "cap_style" )] = QgsSymbolLayerUtils::encodePenCapStyle( mPenCapStyle );
    1239                 :          0 :   map[QStringLiteral( "horizontal_anchor_point" )] = QString::number( mHorizontalAnchorPoint );
    1240                 :          0 :   map[QStringLiteral( "vertical_anchor_point" )] = QString::number( mVerticalAnchorPoint );
    1241                 :          0 :   return map;
    1242                 :          0 : }
    1243                 :            : 
    1244                 :          0 : QgsSimpleMarkerSymbolLayer *QgsSimpleMarkerSymbolLayer::clone() const
    1245                 :            : {
    1246                 :          0 :   QgsSimpleMarkerSymbolLayer *m = new QgsSimpleMarkerSymbolLayer( mShape, mSize, mAngle, mScaleMethod, mColor, mStrokeColor, mPenJoinStyle );
    1247                 :          0 :   m->setOffset( mOffset );
    1248                 :          0 :   m->setSizeUnit( mSizeUnit );
    1249                 :          0 :   m->setSizeMapUnitScale( mSizeMapUnitScale );
    1250                 :          0 :   m->setOffsetUnit( mOffsetUnit );
    1251                 :          0 :   m->setOffsetMapUnitScale( mOffsetMapUnitScale );
    1252                 :          0 :   m->setStrokeStyle( mStrokeStyle );
    1253                 :          0 :   m->setStrokeWidth( mStrokeWidth );
    1254                 :          0 :   m->setStrokeWidthUnit( mStrokeWidthUnit );
    1255                 :          0 :   m->setStrokeWidthMapUnitScale( mStrokeWidthMapUnitScale );
    1256                 :          0 :   m->setHorizontalAnchorPoint( mHorizontalAnchorPoint );
    1257                 :          0 :   m->setVerticalAnchorPoint( mVerticalAnchorPoint );
    1258                 :          0 :   m->setPenCapStyle( mPenCapStyle );
    1259                 :          0 :   copyDataDefinedProperties( m );
    1260                 :          0 :   copyPaintEffect( m );
    1261                 :          0 :   return m;
    1262                 :          0 : }
    1263                 :            : 
    1264                 :          0 : void QgsSimpleMarkerSymbolLayer::writeSldMarker( QDomDocument &doc, QDomElement &element, const QVariantMap &props ) const
    1265                 :            : {
    1266                 :            :   // <Graphic>
    1267                 :          0 :   QDomElement graphicElem = doc.createElement( QStringLiteral( "se:Graphic" ) );
    1268                 :          0 :   element.appendChild( graphicElem );
    1269                 :            : 
    1270                 :          0 :   double strokeWidth = QgsSymbolLayerUtils::rescaleUom( mStrokeWidth, mStrokeWidthUnit, props );
    1271                 :          0 :   double size = QgsSymbolLayerUtils::rescaleUom( mSize, mSizeUnit, props );
    1272                 :          0 :   QgsSymbolLayerUtils::wellKnownMarkerToSld( doc, graphicElem, encodeShape( mShape ), mColor, mStrokeColor, mStrokeStyle, strokeWidth, size );
    1273                 :            : 
    1274                 :            :   // <Rotation>
    1275                 :          0 :   QString angleFunc;
    1276                 :            :   bool ok;
    1277                 :          0 :   double angle = props.value( QStringLiteral( "angle" ), QStringLiteral( "0" ) ).toDouble( &ok );
    1278                 :          0 :   if ( !ok )
    1279                 :            :   {
    1280                 :          0 :     angleFunc = QStringLiteral( "%1 + %2" ).arg( props.value( QStringLiteral( "angle" ), QStringLiteral( "0" ) ).toString() ).arg( mAngle );
    1281                 :          0 :   }
    1282                 :          0 :   else if ( !qgsDoubleNear( angle + mAngle, 0.0 ) )
    1283                 :            :   {
    1284                 :          0 :     angleFunc = QString::number( angle + mAngle );
    1285                 :          0 :   }
    1286                 :          0 :   QgsSymbolLayerUtils::createRotationElement( doc, graphicElem, angleFunc );
    1287                 :            : 
    1288                 :            :   // <Displacement>
    1289                 :          0 :   QPointF offset = QgsSymbolLayerUtils::rescaleUom( mOffset, mOffsetUnit, props );
    1290                 :          0 :   QgsSymbolLayerUtils::createDisplacementElement( doc, graphicElem, offset );
    1291                 :          0 : }
    1292                 :            : 
    1293                 :          0 : QString QgsSimpleMarkerSymbolLayer::ogrFeatureStyle( double mmScaleFactor, double mapUnitScaleFactor ) const
    1294                 :            : {
    1295                 :            :   Q_UNUSED( mmScaleFactor )
    1296                 :            :   Q_UNUSED( mapUnitScaleFactor )
    1297                 :            : #if 0
    1298                 :            :   QString ogrType = "3"; //default is circle
    1299                 :            :   if ( mName == "square" )
    1300                 :            :   {
    1301                 :            :     ogrType = "5";
    1302                 :            :   }
    1303                 :            :   else if ( mName == "triangle" )
    1304                 :            :   {
    1305                 :            :     ogrType = "7";
    1306                 :            :   }
    1307                 :            :   else if ( mName == "star" )
    1308                 :            :   {
    1309                 :            :     ogrType = "9";
    1310                 :            :   }
    1311                 :            :   else if ( mName == "circle" )
    1312                 :            :   {
    1313                 :            :     ogrType = "3";
    1314                 :            :   }
    1315                 :            :   else if ( mName == "cross" )
    1316                 :            :   {
    1317                 :            :     ogrType = "0";
    1318                 :            :   }
    1319                 :            :   else if ( mName == "x" || mName == "cross2" )
    1320                 :            :   {
    1321                 :            :     ogrType = "1";
    1322                 :            :   }
    1323                 :            :   else if ( mName == "line" )
    1324                 :            :   {
    1325                 :            :     ogrType = "10";
    1326                 :            :   }
    1327                 :            : 
    1328                 :            :   QString ogrString;
    1329                 :            :   ogrString.append( "SYMBOL(" );
    1330                 :            :   ogrString.append( "id:" );
    1331                 :            :   ogrString.append( '\"' );
    1332                 :            :   ogrString.append( "ogr-sym-" );
    1333                 :            :   ogrString.append( ogrType );
    1334                 :            :   ogrString.append( '\"' );
    1335                 :            :   ogrString.append( ",c:" );
    1336                 :            :   ogrString.append( mColor.name() );
    1337                 :            :   ogrString.append( ",o:" );
    1338                 :            :   ogrString.append( mStrokeColor.name() );
    1339                 :            :   ogrString.append( QString( ",s:%1mm" ).arg( mSize ) );
    1340                 :            :   ogrString.append( ')' );
    1341                 :            :   return ogrString;
    1342                 :            : #endif //0
    1343                 :            : 
    1344                 :          0 :   QString ogrString;
    1345                 :          0 :   ogrString.append( "PEN(" );
    1346                 :          0 :   ogrString.append( "c:" );
    1347                 :          0 :   ogrString.append( mColor.name() );
    1348                 :          0 :   ogrString.append( ",w:" );
    1349                 :          0 :   ogrString.append( QString::number( mSize ) );
    1350                 :          0 :   ogrString.append( "mm" );
    1351                 :          0 :   ogrString.append( ")" );
    1352                 :          0 :   return ogrString;
    1353                 :          0 : }
    1354                 :            : 
    1355                 :          0 : QgsSymbolLayer *QgsSimpleMarkerSymbolLayer::createFromSld( QDomElement &element )
    1356                 :            : {
    1357                 :          0 :   QgsDebugMsgLevel( QStringLiteral( "Entered." ), 4 );
    1358                 :            : 
    1359                 :          0 :   QDomElement graphicElem = element.firstChildElement( QStringLiteral( "Graphic" ) );
    1360                 :          0 :   if ( graphicElem.isNull() )
    1361                 :          0 :     return nullptr;
    1362                 :            : 
    1363                 :          0 :   QString name = QStringLiteral( "square" );
    1364                 :          0 :   QColor color, strokeColor;
    1365                 :            :   double strokeWidth, size;
    1366                 :            :   Qt::PenStyle strokeStyle;
    1367                 :            : 
    1368                 :          0 :   if ( !QgsSymbolLayerUtils::wellKnownMarkerFromSld( graphicElem, name, color, strokeColor, strokeStyle, strokeWidth, size ) )
    1369                 :          0 :     return nullptr;
    1370                 :            : 
    1371                 :          0 :   double angle = 0.0;
    1372                 :          0 :   QString angleFunc;
    1373                 :          0 :   if ( QgsSymbolLayerUtils::rotationFromSldElement( graphicElem, angleFunc ) )
    1374                 :            :   {
    1375                 :            :     bool ok;
    1376                 :          0 :     double d = angleFunc.toDouble( &ok );
    1377                 :          0 :     if ( ok )
    1378                 :          0 :       angle = d;
    1379                 :          0 :   }
    1380                 :            : 
    1381                 :          0 :   QPointF offset;
    1382                 :          0 :   QgsSymbolLayerUtils::displacementFromSldElement( graphicElem, offset );
    1383                 :            : 
    1384                 :          0 :   Shape shape = decodeShape( name );
    1385                 :            : 
    1386                 :          0 :   QString uom = element.attribute( QStringLiteral( "uom" ) );
    1387                 :          0 :   size = QgsSymbolLayerUtils::sizeInPixelsFromSldUom( uom, size );
    1388                 :          0 :   offset.setX( QgsSymbolLayerUtils::sizeInPixelsFromSldUom( uom, offset.x() ) );
    1389                 :          0 :   offset.setY( QgsSymbolLayerUtils::sizeInPixelsFromSldUom( uom, offset.y() ) );
    1390                 :            : 
    1391                 :          0 :   QgsSimpleMarkerSymbolLayer *m = new QgsSimpleMarkerSymbolLayer( shape, size );
    1392                 :          0 :   m->setOutputUnit( QgsUnitTypes::RenderUnit::RenderPixels );
    1393                 :          0 :   m->setColor( color );
    1394                 :          0 :   m->setStrokeColor( strokeColor );
    1395                 :          0 :   m->setAngle( angle );
    1396                 :          0 :   m->setOffset( offset );
    1397                 :          0 :   m->setStrokeStyle( strokeStyle );
    1398                 :          0 :   m->setStrokeWidth( strokeWidth );
    1399                 :          0 :   return m;
    1400                 :          0 : }
    1401                 :            : 
    1402                 :          0 : void QgsSimpleMarkerSymbolLayer::drawMarker( QPainter *p, QgsSymbolRenderContext &context )
    1403                 :            : {
    1404                 :          0 :   Q_UNUSED( context )
    1405                 :            : 
    1406                 :          0 :   if ( mPolygon.count() != 0 )
    1407                 :            :   {
    1408                 :          0 :     p->drawPolygon( mPolygon );
    1409                 :          0 :   }
    1410                 :            :   else
    1411                 :            :   {
    1412                 :          0 :     p->drawPath( mPath );
    1413                 :            :   }
    1414                 :          0 : }
    1415                 :            : 
    1416                 :          0 : bool QgsSimpleMarkerSymbolLayer::writeDxf( QgsDxfExport &e, double mmMapUnitScaleFactor, const QString &layerName, QgsSymbolRenderContext &context, QPointF shift ) const
    1417                 :            : {
    1418                 :            :   //data defined size?
    1419                 :          0 :   double size = mSize;
    1420                 :            : 
    1421                 :          0 :   bool hasDataDefinedSize = mDataDefinedProperties.isActive( QgsSymbolLayer::PropertySize );
    1422                 :            : 
    1423                 :            :   //data defined size
    1424                 :          0 :   bool ok = true;
    1425                 :          0 :   if ( hasDataDefinedSize )
    1426                 :            :   {
    1427                 :          0 :     size = mDataDefinedProperties.valueAsDouble( QgsSymbolLayer::PropertySize, context.renderContext().expressionContext(), mSize, &ok );
    1428                 :            : 
    1429                 :          0 :     if ( ok )
    1430                 :            :     {
    1431                 :          0 :       switch ( mScaleMethod )
    1432                 :            :       {
    1433                 :            :         case QgsSymbol::ScaleArea:
    1434                 :          0 :           size = std::sqrt( size );
    1435                 :          0 :           break;
    1436                 :            :         case QgsSymbol::ScaleDiameter:
    1437                 :          0 :           break;
    1438                 :            :       }
    1439                 :          0 :     }
    1440                 :            : 
    1441                 :          0 :     size *= e.mapUnitScaleFactor( e.symbologyScale(), mSizeUnit, e.mapUnits(), context.renderContext().mapToPixel().mapUnitsPerPixel() );
    1442                 :          0 :   }
    1443                 :            : 
    1444                 :          0 :   if ( mSizeUnit == QgsUnitTypes::RenderMillimeters )
    1445                 :            :   {
    1446                 :          0 :     size *= mmMapUnitScaleFactor;
    1447                 :          0 :   }
    1448                 :            : 
    1449                 :          0 :   if ( mSizeUnit == QgsUnitTypes::RenderMapUnits )
    1450                 :            :   {
    1451                 :          0 :     e.clipValueToMapUnitScale( size, mSizeMapUnitScale, context.renderContext().scaleFactor() );
    1452                 :          0 :   }
    1453                 :          0 :   double halfSize = size / 2.0;
    1454                 :            : 
    1455                 :            :   //strokeWidth
    1456                 :          0 :   double strokeWidth = mStrokeWidth;
    1457                 :            : 
    1458                 :          0 :   if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyStrokeWidth ) )
    1459                 :            :   {
    1460                 :          0 :     context.setOriginalValueVariable( mStrokeWidth );
    1461                 :          0 :     strokeWidth = mDataDefinedProperties.valueAsDouble( QgsSymbolLayer::PropertyStrokeWidth, context.renderContext().expressionContext(), mStrokeWidth );
    1462                 :          0 :   }
    1463                 :          0 :   strokeWidth *= e.mapUnitScaleFactor( e.symbologyScale(), mStrokeWidthUnit, e.mapUnits(), context.renderContext().mapToPixel().mapUnitsPerPixel() );
    1464                 :          0 :   if ( mSizeUnit == QgsUnitTypes::RenderMapUnits )
    1465                 :            :   {
    1466                 :          0 :     e.clipValueToMapUnitScale( strokeWidth, mStrokeWidthMapUnitScale, context.renderContext().scaleFactor() );
    1467                 :          0 :   }
    1468                 :            : 
    1469                 :            :   //color
    1470                 :          0 :   QColor pc = mPen.color();
    1471                 :          0 :   QColor bc = mBrush.color();
    1472                 :          0 :   if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyFillColor ) )
    1473                 :            :   {
    1474                 :          0 :     context.setOriginalValueVariable( QgsSymbolLayerUtils::encodeColor( mColor ) );
    1475                 :          0 :     bc = mDataDefinedProperties.valueAsColor( QgsSymbolLayer::PropertyFillColor, context.renderContext().expressionContext(), bc );
    1476                 :          0 :   }
    1477                 :          0 :   if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyStrokeColor ) )
    1478                 :            :   {
    1479                 :          0 :     context.setOriginalValueVariable( QgsSymbolLayerUtils::encodeColor( mStrokeColor ) );
    1480                 :          0 :     pc = mDataDefinedProperties.valueAsColor( QgsSymbolLayer::PropertyStrokeColor, context.renderContext().expressionContext(), pc );
    1481                 :          0 :   }
    1482                 :            : 
    1483                 :            :   //offset
    1484                 :          0 :   double offsetX = 0;
    1485                 :          0 :   double offsetY = 0;
    1486                 :          0 :   markerOffset( context, offsetX, offsetY );
    1487                 :          0 :   offsetX *= context.renderContext().mapToPixel().mapUnitsPerPixel();
    1488                 :          0 :   offsetY *= context.renderContext().mapToPixel().mapUnitsPerPixel();
    1489                 :            : 
    1490                 :            : 
    1491                 :          0 :   QPointF off( offsetX, offsetY );
    1492                 :            : 
    1493                 :            :   //angle
    1494                 :          0 :   double angle = mAngle + mLineAngle;
    1495                 :          0 :   if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyAngle ) )
    1496                 :            :   {
    1497                 :          0 :     context.setOriginalValueVariable( mAngle );
    1498                 :          0 :     angle = mDataDefinedProperties.valueAsDouble( QgsSymbolLayer::PropertyAngle, context.renderContext().expressionContext(), mAngle ) + mLineAngle;
    1499                 :          0 :   }
    1500                 :            : 
    1501                 :          0 :   Shape shape = mShape;
    1502                 :          0 :   if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyName ) )
    1503                 :            :   {
    1504                 :          0 :     context.setOriginalValueVariable( encodeShape( shape ) );
    1505                 :          0 :     QString shapeName = mDataDefinedProperties.valueAsString( QgsSymbolLayer::PropertyName, context.renderContext().expressionContext(), QString(), &ok );
    1506                 :          0 :     if ( ok )
    1507                 :            :     {
    1508                 :          0 :       shape = decodeShape( shapeName, &ok );
    1509                 :          0 :       if ( !ok )
    1510                 :          0 :         shape = mShape;
    1511                 :          0 :     }
    1512                 :          0 :   }
    1513                 :            : 
    1514                 :          0 :   if ( angle )
    1515                 :          0 :     off = _rotatedOffset( off, angle );
    1516                 :            : 
    1517                 :          0 :   off *= e.mapUnitScaleFactor( e.symbologyScale(), mSizeUnit, e.mapUnits(), context.renderContext().mapToPixel().mapUnitsPerPixel() );
    1518                 :            : 
    1519                 :          0 :   QTransform t;
    1520                 :          0 :   t.translate( shift.x() + off.x(), shift.y() - off.y() );
    1521                 :            : 
    1522                 :          0 :   if ( !qgsDoubleNear( angle, 0.0 ) )
    1523                 :          0 :     t.rotate( angle );
    1524                 :            : 
    1525                 :          0 :   QPolygonF polygon;
    1526                 :          0 :   if ( shapeToPolygon( shape, polygon ) )
    1527                 :            :   {
    1528                 :          0 :     t.scale( halfSize, -halfSize );
    1529                 :            : 
    1530                 :          0 :     polygon = t.map( polygon );
    1531                 :            : 
    1532                 :          0 :     QgsPointSequence p;
    1533                 :          0 :     p.reserve( polygon.size() );
    1534                 :          0 :     for ( int i = 0; i < polygon.size(); i++ )
    1535                 :            :     {
    1536                 :          0 :       p << QgsPoint( polygon[i] );
    1537                 :          0 :     }
    1538                 :            : 
    1539                 :          0 :     if ( mBrush.style() != Qt::NoBrush )
    1540                 :          0 :       e.writePolygon( QgsRingSequence() << p, layerName, QStringLiteral( "SOLID" ), bc );
    1541                 :          0 :     if ( mPen.style() != Qt::NoPen )
    1542                 :          0 :       e.writePolyline( p, layerName, QStringLiteral( "CONTINUOUS" ), pc, strokeWidth );
    1543                 :          0 :   }
    1544                 :          0 :   else if ( shape == Circle )
    1545                 :            :   {
    1546                 :          0 :     shift += QPointF( off.x(), -off.y() );
    1547                 :          0 :     if ( mBrush.style() != Qt::NoBrush )
    1548                 :          0 :       e.writeFilledCircle( layerName, bc, QgsPoint( shift ), halfSize );
    1549                 :          0 :     if ( mPen.style() != Qt::NoPen )
    1550                 :          0 :       e.writeCircle( layerName, pc, QgsPoint( shift ), halfSize, QStringLiteral( "CONTINUOUS" ), strokeWidth );
    1551                 :          0 :   }
    1552                 :          0 :   else if ( shape == Line )
    1553                 :            :   {
    1554                 :          0 :     QPointF pt1 = t.map( QPointF( 0, -halfSize ) );
    1555                 :          0 :     QPointF pt2 = t.map( QPointF( 0, halfSize ) );
    1556                 :            : 
    1557                 :          0 :     if ( mPen.style() != Qt::NoPen )
    1558                 :          0 :       e.writeLine( QgsPoint( pt1 ), QgsPoint( pt2 ), layerName, QStringLiteral( "CONTINUOUS" ), pc, strokeWidth );
    1559                 :          0 :   }
    1560                 :          0 :   else if ( shape == Cross )
    1561                 :            :   {
    1562                 :          0 :     if ( mPen.style() != Qt::NoPen )
    1563                 :            :     {
    1564                 :          0 :       QPointF pt1 = t.map( QPointF( -halfSize, 0 ) );
    1565                 :          0 :       QPointF pt2 = t.map( QPointF( halfSize, 0 ) );
    1566                 :          0 :       QPointF pt3 = t.map( QPointF( 0, -halfSize ) );
    1567                 :          0 :       QPointF pt4 = t.map( QPointF( 0, halfSize ) );
    1568                 :            : 
    1569                 :          0 :       e.writeLine( QgsPoint( pt1 ), QgsPoint( pt2 ), layerName, QStringLiteral( "CONTINUOUS" ), pc, strokeWidth );
    1570                 :          0 :       e.writeLine( QgsPoint( pt3 ), QgsPoint( pt4 ), layerName, QStringLiteral( "CONTINUOUS" ), pc, strokeWidth );
    1571                 :          0 :     }
    1572                 :          0 :   }
    1573                 :          0 :   else if ( shape == Cross2 )
    1574                 :            :   {
    1575                 :          0 :     if ( mPen.style() != Qt::NoPen )
    1576                 :            :     {
    1577                 :          0 :       QPointF pt1 = t.map( QPointF( -halfSize, -halfSize ) );
    1578                 :          0 :       QPointF pt2 = t.map( QPointF( halfSize, halfSize ) );
    1579                 :          0 :       QPointF pt3 = t.map( QPointF( halfSize, -halfSize ) );
    1580                 :          0 :       QPointF pt4 = t.map( QPointF( -halfSize, halfSize ) );
    1581                 :            : 
    1582                 :          0 :       e.writeLine( QgsPoint( pt1 ), QgsPoint( pt2 ), layerName, QStringLiteral( "CONTINUOUS" ), pc, strokeWidth );
    1583                 :          0 :       e.writeLine( QgsPoint( pt3 ), QgsPoint( pt4 ), layerName, QStringLiteral( "CONTINUOUS" ), pc, strokeWidth );
    1584                 :          0 :     }
    1585                 :          0 :   }
    1586                 :          0 :   else if ( shape == ArrowHead )
    1587                 :            :   {
    1588                 :          0 :     if ( mPen.style() != Qt::NoPen )
    1589                 :            :     {
    1590                 :          0 :       QPointF pt1 = t.map( QPointF( -halfSize, halfSize ) );
    1591                 :          0 :       QPointF pt2 = t.map( QPointF( 0, 0 ) );
    1592                 :          0 :       QPointF pt3 = t.map( QPointF( -halfSize, -halfSize ) );
    1593                 :            : 
    1594                 :          0 :       e.writeLine( QgsPoint( pt1 ), QgsPoint( pt2 ), layerName, QStringLiteral( "CONTINUOUS" ), pc, strokeWidth );
    1595                 :          0 :       e.writeLine( QgsPoint( pt3 ), QgsPoint( pt2 ), layerName, QStringLiteral( "CONTINUOUS" ), pc, strokeWidth );
    1596                 :          0 :     }
    1597                 :          0 :   }
    1598                 :            :   else
    1599                 :            :   {
    1600                 :          0 :     QgsDebugMsg( QStringLiteral( "Unsupported dxf marker name %1" ).arg( encodeShape( shape ) ) );
    1601                 :          0 :     return false;
    1602                 :            :   }
    1603                 :            : 
    1604                 :          0 :   return true;
    1605                 :          0 : }
    1606                 :            : 
    1607                 :            : 
    1608                 :          0 : void QgsSimpleMarkerSymbolLayer::setOutputUnit( QgsUnitTypes::RenderUnit unit )
    1609                 :            : {
    1610                 :          0 :   QgsMarkerSymbolLayer::setOutputUnit( unit );
    1611                 :          0 :   mStrokeWidthUnit = unit;
    1612                 :          0 : }
    1613                 :            : 
    1614                 :          0 : QgsUnitTypes::RenderUnit QgsSimpleMarkerSymbolLayer::outputUnit() const
    1615                 :            : {
    1616                 :          0 :   if ( QgsMarkerSymbolLayer::outputUnit() == mStrokeWidthUnit )
    1617                 :            :   {
    1618                 :          0 :     return mStrokeWidthUnit;
    1619                 :            :   }
    1620                 :          0 :   return QgsUnitTypes::RenderUnknownUnit;
    1621                 :          0 : }
    1622                 :            : 
    1623                 :          0 : void QgsSimpleMarkerSymbolLayer::setMapUnitScale( const QgsMapUnitScale &scale )
    1624                 :            : {
    1625                 :          0 :   QgsMarkerSymbolLayer::setMapUnitScale( scale );
    1626                 :          0 :   mStrokeWidthMapUnitScale = scale;
    1627                 :          0 : }
    1628                 :            : 
    1629                 :          0 : QgsMapUnitScale QgsSimpleMarkerSymbolLayer::mapUnitScale() const
    1630                 :            : {
    1631                 :          0 :   if ( QgsMarkerSymbolLayer::mapUnitScale() == mStrokeWidthMapUnitScale )
    1632                 :            :   {
    1633                 :          0 :     return mStrokeWidthMapUnitScale;
    1634                 :            :   }
    1635                 :          0 :   return QgsMapUnitScale();
    1636                 :          0 : }
    1637                 :            : 
    1638                 :          0 : bool QgsSimpleMarkerSymbolLayer::usesMapUnits() const
    1639                 :            : {
    1640                 :          0 :   return mSizeUnit == QgsUnitTypes::RenderMapUnits || mSizeUnit == QgsUnitTypes::RenderMetersInMapUnits
    1641                 :          0 :          || mOffsetUnit == QgsUnitTypes::RenderMapUnits || mOffsetUnit == QgsUnitTypes::RenderMetersInMapUnits
    1642                 :          0 :          || mStrokeWidthUnit == QgsUnitTypes::RenderMapUnits || mStrokeWidthUnit == QgsUnitTypes::RenderMetersInMapUnits;
    1643                 :            : }
    1644                 :            : 
    1645                 :          0 : QRectF QgsSimpleMarkerSymbolLayer::bounds( QPointF point, QgsSymbolRenderContext &context )
    1646                 :            : {
    1647                 :          0 :   QRectF symbolBounds = QgsSimpleMarkerSymbolLayerBase::bounds( point, context );
    1648                 :            : 
    1649                 :            :   // need to account for stroke width
    1650                 :          0 :   double penWidth = mStrokeWidth;
    1651                 :          0 :   bool ok = true;
    1652                 :          0 :   if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyStrokeWidth ) )
    1653                 :            :   {
    1654                 :          0 :     context.setOriginalValueVariable( mStrokeWidth );
    1655                 :          0 :     double strokeWidth = mDataDefinedProperties.valueAsDouble( QgsSymbolLayer::PropertyStrokeWidth, context.renderContext().expressionContext(), mStrokeWidth, &ok );
    1656                 :          0 :     if ( ok )
    1657                 :            :     {
    1658                 :          0 :       penWidth = strokeWidth;
    1659                 :          0 :     }
    1660                 :          0 :   }
    1661                 :          0 :   penWidth = context.renderContext().convertToPainterUnits( penWidth, mStrokeWidthUnit, mStrokeWidthMapUnitScale );
    1662                 :          0 :   if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyStrokeStyle ) )
    1663                 :            :   {
    1664                 :          0 :     context.setOriginalValueVariable( QgsSymbolLayerUtils::encodePenStyle( mStrokeStyle ) );
    1665                 :          0 :     QString strokeStyle = mDataDefinedProperties.valueAsString( QgsSymbolLayer::PropertyStrokeStyle, context.renderContext().expressionContext(), QString(), &ok );
    1666                 :          0 :     if ( ok && strokeStyle == QLatin1String( "no" ) )
    1667                 :            :     {
    1668                 :          0 :       penWidth = 0.0;
    1669                 :          0 :     }
    1670                 :          0 :   }
    1671                 :          0 :   else if ( mStrokeStyle == Qt::NoPen )
    1672                 :          0 :     penWidth = 0;
    1673                 :            : 
    1674                 :            :   //antialiasing, add 1 pixel
    1675                 :          0 :   penWidth += 1;
    1676                 :            : 
    1677                 :            :   //extend bounds by pen width / 2.0
    1678                 :          0 :   symbolBounds.adjust( -penWidth / 2.0, -penWidth / 2.0,
    1679                 :          0 :                        penWidth / 2.0, penWidth / 2.0 );
    1680                 :            : 
    1681                 :          0 :   return symbolBounds;
    1682                 :          0 : }
    1683                 :            : 
    1684                 :         22 : void QgsSimpleMarkerSymbolLayer::setColor( const QColor &color )
    1685                 :            : {
    1686                 :         22 :   if ( shapeIsFilled( mShape ) )
    1687                 :            :   {
    1688                 :         22 :     setFillColor( color );
    1689                 :         22 :   }
    1690                 :            :   else
    1691                 :            :   {
    1692                 :          0 :     setStrokeColor( color );
    1693                 :            :   }
    1694                 :         22 : }
    1695                 :            : 
    1696                 :         80 : QColor QgsSimpleMarkerSymbolLayer::color() const
    1697                 :            : {
    1698                 :         80 :   if ( shapeIsFilled( mShape ) )
    1699                 :            :   {
    1700                 :         70 :     return fillColor();
    1701                 :            :   }
    1702                 :            :   else
    1703                 :            :   {
    1704                 :         10 :     return strokeColor();
    1705                 :            :   }
    1706                 :         80 : }
    1707                 :            : 
    1708                 :            : 
    1709                 :            : 
    1710                 :            : 
    1711                 :            : //
    1712                 :            : // QgsFilledMarkerSymbolLayer
    1713                 :            : //
    1714                 :            : 
    1715                 :          0 : QgsFilledMarkerSymbolLayer::QgsFilledMarkerSymbolLayer( QgsSimpleMarkerSymbolLayerBase::Shape shape, double size, double angle, QgsSymbol::ScaleMethod scaleMethod )
    1716                 :          0 :   : QgsSimpleMarkerSymbolLayerBase( shape, size, angle, scaleMethod )
    1717                 :          0 : {
    1718                 :          0 :   mFill.reset( static_cast<QgsFillSymbol *>( QgsFillSymbol::createSimple( QVariantMap() ) ) );
    1719                 :          0 : }
    1720                 :            : 
    1721                 :          0 : QgsSymbolLayer *QgsFilledMarkerSymbolLayer::create( const QVariantMap &props )
    1722                 :            : {
    1723                 :          0 :   QString name = DEFAULT_SIMPLEMARKER_NAME;
    1724                 :          0 :   double size = DEFAULT_SIMPLEMARKER_SIZE;
    1725                 :          0 :   double angle = DEFAULT_SIMPLEMARKER_ANGLE;
    1726                 :          0 :   QgsSymbol::ScaleMethod scaleMethod = DEFAULT_SCALE_METHOD;
    1727                 :            : 
    1728                 :          0 :   if ( props.contains( QStringLiteral( "name" ) ) )
    1729                 :          0 :     name = props[QStringLiteral( "name" )].toString();
    1730                 :          0 :   if ( props.contains( QStringLiteral( "size" ) ) )
    1731                 :          0 :     size = props[QStringLiteral( "size" )].toDouble();
    1732                 :          0 :   if ( props.contains( QStringLiteral( "angle" ) ) )
    1733                 :          0 :     angle = props[QStringLiteral( "angle" )].toDouble();
    1734                 :          0 :   if ( props.contains( QStringLiteral( "scale_method" ) ) )
    1735                 :          0 :     scaleMethod = QgsSymbolLayerUtils::decodeScaleMethod( props[QStringLiteral( "scale_method" )].toString() );
    1736                 :            : 
    1737                 :          0 :   QgsFilledMarkerSymbolLayer *m = new QgsFilledMarkerSymbolLayer( decodeShape( name ), size, angle, scaleMethod );
    1738                 :          0 :   if ( props.contains( QStringLiteral( "offset" ) ) )
    1739                 :          0 :     m->setOffset( QgsSymbolLayerUtils::decodePoint( props[QStringLiteral( "offset" )].toString() ) );
    1740                 :          0 :   if ( props.contains( QStringLiteral( "offset_unit" ) ) )
    1741                 :          0 :     m->setOffsetUnit( QgsUnitTypes::decodeRenderUnit( props[QStringLiteral( "offset_unit" )].toString() ) );
    1742                 :          0 :   if ( props.contains( QStringLiteral( "offset_map_unit_scale" ) ) )
    1743                 :          0 :     m->setOffsetMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( props[QStringLiteral( "offset_map_unit_scale" )].toString() ) );
    1744                 :          0 :   if ( props.contains( QStringLiteral( "size_unit" ) ) )
    1745                 :          0 :     m->setSizeUnit( QgsUnitTypes::decodeRenderUnit( props[QStringLiteral( "size_unit" )].toString() ) );
    1746                 :          0 :   if ( props.contains( QStringLiteral( "size_map_unit_scale" ) ) )
    1747                 :          0 :     m->setSizeMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( props[QStringLiteral( "size_map_unit_scale" )].toString() ) );
    1748                 :          0 :   if ( props.contains( QStringLiteral( "horizontal_anchor_point" ) ) )
    1749                 :            :   {
    1750                 :          0 :     m->setHorizontalAnchorPoint( QgsMarkerSymbolLayer::HorizontalAnchorPoint( props[ QStringLiteral( "horizontal_anchor_point" )].toInt() ) );
    1751                 :          0 :   }
    1752                 :          0 :   if ( props.contains( QStringLiteral( "vertical_anchor_point" ) ) )
    1753                 :            :   {
    1754                 :          0 :     m->setVerticalAnchorPoint( QgsMarkerSymbolLayer::VerticalAnchorPoint( props[ QStringLiteral( "vertical_anchor_point" )].toInt() ) );
    1755                 :          0 :   }
    1756                 :            : 
    1757                 :          0 :   m->setSubSymbol( QgsFillSymbol::createSimple( props ) );
    1758                 :            : 
    1759                 :          0 :   m->restoreOldDataDefinedProperties( props );
    1760                 :            : 
    1761                 :          0 :   return m;
    1762                 :          0 : }
    1763                 :            : 
    1764                 :          0 : QString QgsFilledMarkerSymbolLayer::layerType() const
    1765                 :            : {
    1766                 :          0 :   return QStringLiteral( "FilledMarker" );
    1767                 :            : }
    1768                 :            : 
    1769                 :          0 : void QgsFilledMarkerSymbolLayer::startRender( QgsSymbolRenderContext &context )
    1770                 :            : {
    1771                 :          0 :   if ( mFill )
    1772                 :            :   {
    1773                 :          0 :     mFill->startRender( context.renderContext(), context.fields() );
    1774                 :          0 :   }
    1775                 :            : 
    1776                 :          0 :   QgsSimpleMarkerSymbolLayerBase::startRender( context );
    1777                 :          0 : }
    1778                 :            : 
    1779                 :          0 : void QgsFilledMarkerSymbolLayer::stopRender( QgsSymbolRenderContext &context )
    1780                 :            : {
    1781                 :          0 :   if ( mFill )
    1782                 :            :   {
    1783                 :          0 :     mFill->stopRender( context.renderContext() );
    1784                 :          0 :   }
    1785                 :          0 : }
    1786                 :            : 
    1787                 :          0 : QVariantMap QgsFilledMarkerSymbolLayer::properties() const
    1788                 :            : {
    1789                 :          0 :   QVariantMap map;
    1790                 :          0 :   map[QStringLiteral( "name" )] = encodeShape( mShape );
    1791                 :          0 :   map[QStringLiteral( "size" )] = QString::number( mSize );
    1792                 :          0 :   map[QStringLiteral( "size_unit" )] = QgsUnitTypes::encodeUnit( mSizeUnit );
    1793                 :          0 :   map[QStringLiteral( "size_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mSizeMapUnitScale );
    1794                 :          0 :   map[QStringLiteral( "angle" )] = QString::number( mAngle );
    1795                 :          0 :   map[QStringLiteral( "offset" )] = QgsSymbolLayerUtils::encodePoint( mOffset );
    1796                 :          0 :   map[QStringLiteral( "offset_unit" )] = QgsUnitTypes::encodeUnit( mOffsetUnit );
    1797                 :          0 :   map[QStringLiteral( "offset_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mOffsetMapUnitScale );
    1798                 :          0 :   map[QStringLiteral( "scale_method" )] = QgsSymbolLayerUtils::encodeScaleMethod( mScaleMethod );
    1799                 :          0 :   map[QStringLiteral( "horizontal_anchor_point" )] = QString::number( mHorizontalAnchorPoint );
    1800                 :          0 :   map[QStringLiteral( "vertical_anchor_point" )] = QString::number( mVerticalAnchorPoint );
    1801                 :            : 
    1802                 :          0 :   if ( mFill )
    1803                 :            :   {
    1804                 :          0 :     map[QStringLiteral( "color" )] = QgsSymbolLayerUtils::encodeColor( mFill->color() );
    1805                 :          0 :   }
    1806                 :          0 :   return map;
    1807                 :          0 : }
    1808                 :            : 
    1809                 :          0 : QgsFilledMarkerSymbolLayer *QgsFilledMarkerSymbolLayer::clone() const
    1810                 :            : {
    1811                 :          0 :   QgsFilledMarkerSymbolLayer *m = static_cast< QgsFilledMarkerSymbolLayer * >( QgsFilledMarkerSymbolLayer::create( properties() ) );
    1812                 :          0 :   copyPaintEffect( m );
    1813                 :          0 :   copyDataDefinedProperties( m );
    1814                 :          0 :   m->setSubSymbol( mFill->clone() );
    1815                 :          0 :   return m;
    1816                 :          0 : }
    1817                 :            : 
    1818                 :          0 : QgsSymbol *QgsFilledMarkerSymbolLayer::subSymbol()
    1819                 :            : {
    1820                 :          0 :   return mFill.get();
    1821                 :            : }
    1822                 :            : 
    1823                 :          0 : bool QgsFilledMarkerSymbolLayer::setSubSymbol( QgsSymbol *symbol )
    1824                 :            : {
    1825                 :          0 :   if ( symbol && symbol->type() == QgsSymbol::Fill )
    1826                 :            :   {
    1827                 :          0 :     mFill.reset( static_cast<QgsFillSymbol *>( symbol ) );
    1828                 :          0 :     return true;
    1829                 :            :   }
    1830                 :            :   else
    1831                 :            :   {
    1832                 :          0 :     delete symbol;
    1833                 :          0 :     return false;
    1834                 :            :   }
    1835                 :          0 : }
    1836                 :            : 
    1837                 :          0 : double QgsFilledMarkerSymbolLayer::estimateMaxBleed( const QgsRenderContext &context ) const
    1838                 :            : {
    1839                 :          0 :   if ( mFill )
    1840                 :            :   {
    1841                 :          0 :     return QgsSymbolLayerUtils::estimateMaxSymbolBleed( mFill.get(), context );
    1842                 :            :   }
    1843                 :          0 :   return 0;
    1844                 :          0 : }
    1845                 :            : 
    1846                 :          0 : QSet<QString> QgsFilledMarkerSymbolLayer::usedAttributes( const QgsRenderContext &context ) const
    1847                 :            : {
    1848                 :          0 :   QSet<QString> attr = QgsSimpleMarkerSymbolLayerBase::usedAttributes( context );
    1849                 :          0 :   if ( mFill )
    1850                 :          0 :     attr.unite( mFill->usedAttributes( context ) );
    1851                 :          0 :   return attr;
    1852                 :          0 : }
    1853                 :            : 
    1854                 :          0 : bool QgsFilledMarkerSymbolLayer::hasDataDefinedProperties() const
    1855                 :            : {
    1856                 :          0 :   if ( QgsSymbolLayer::hasDataDefinedProperties() )
    1857                 :          0 :     return true;
    1858                 :          0 :   if ( mFill && mFill->hasDataDefinedProperties() )
    1859                 :          0 :     return true;
    1860                 :          0 :   return false;
    1861                 :          0 : }
    1862                 :            : 
    1863                 :          0 : void QgsFilledMarkerSymbolLayer::setColor( const QColor &c )
    1864                 :            : {
    1865                 :          0 :   mColor = c;
    1866                 :          0 :   if ( mFill )
    1867                 :          0 :     mFill->setColor( c );
    1868                 :          0 : }
    1869                 :            : 
    1870                 :          0 : QColor QgsFilledMarkerSymbolLayer::color() const
    1871                 :            : {
    1872                 :          0 :   return mFill ?  mFill->color() : mColor;
    1873                 :            : }
    1874                 :            : 
    1875                 :          0 : bool QgsFilledMarkerSymbolLayer::usesMapUnits() const
    1876                 :            : {
    1877                 :          0 :   return mSizeUnit == QgsUnitTypes::RenderMapUnits || mSizeUnit == QgsUnitTypes::RenderMetersInMapUnits
    1878                 :          0 :          || mOffsetUnit == QgsUnitTypes::RenderMapUnits || mOffsetUnit == QgsUnitTypes::RenderMetersInMapUnits
    1879                 :          0 :          || ( mFill && mFill->usesMapUnits() );
    1880                 :            : }
    1881                 :            : 
    1882                 :          0 : void QgsFilledMarkerSymbolLayer::draw( QgsSymbolRenderContext &context, QgsSimpleMarkerSymbolLayerBase::Shape shape, const QPolygonF &polygon, const QPainterPath &path )
    1883                 :            : {
    1884                 :            :   //making changes here? Don't forget to also update ::bounds if the changes affect the bounding box
    1885                 :            :   //of the rendered point!
    1886                 :            : 
    1887                 :          0 :   QPainter *p = context.renderContext().painter();
    1888                 :          0 :   if ( !p )
    1889                 :            :   {
    1890                 :          0 :     return;
    1891                 :            :   }
    1892                 :            : 
    1893                 :          0 :   const double prevOpacity = mFill->opacity();
    1894                 :          0 :   mFill->setOpacity( mFill->opacity() * context.opacity() );
    1895                 :            : 
    1896                 :          0 :   if ( shapeIsFilled( shape ) )
    1897                 :            :   {
    1898                 :          0 :     p->setBrush( Qt::red );
    1899                 :          0 :   }
    1900                 :            :   else
    1901                 :            :   {
    1902                 :          0 :     p->setBrush( Qt::NoBrush );
    1903                 :            :   }
    1904                 :          0 :   p->setPen( Qt::black );
    1905                 :            : 
    1906                 :          0 :   if ( !polygon.isEmpty() )
    1907                 :            :   {
    1908                 :          0 :     mFill->renderPolygon( polygon, /* rings */ nullptr, context.feature(), context.renderContext(), -1, context.selected() );
    1909                 :          0 :   }
    1910                 :            :   else
    1911                 :            :   {
    1912                 :          0 :     QPolygonF poly = path.toFillPolygon();
    1913                 :          0 :     mFill->renderPolygon( poly, /* rings */ nullptr, context.feature(), context.renderContext(), -1, context.selected() );
    1914                 :          0 :   }
    1915                 :            : 
    1916                 :          0 :   mFill->setOpacity( prevOpacity );
    1917                 :          0 : }
    1918                 :            : 
    1919                 :            : 
    1920                 :            : //////////
    1921                 :            : 
    1922                 :            : 
    1923                 :         40 : QgsSvgMarkerSymbolLayer::QgsSvgMarkerSymbolLayer( const QString &path, double size, double angle, QgsSymbol::ScaleMethod scaleMethod )
    1924                 :         80 : {
    1925                 :         40 :   mSize = size;
    1926                 :         40 :   mAngle = angle;
    1927                 :         40 :   mOffset = QPointF( 0, 0 );
    1928                 :         40 :   mScaleMethod = scaleMethod;
    1929                 :         40 :   mStrokeWidth = 0.2;
    1930                 :         40 :   mStrokeWidthUnit = QgsUnitTypes::RenderMillimeters;
    1931                 :         40 :   mColor = QColor( 35, 35, 35 );
    1932                 :         40 :   mStrokeColor = QColor( 35, 35, 35 );
    1933                 :         40 :   setPath( path );
    1934                 :         40 : }
    1935                 :            : 
    1936                 :            : 
    1937                 :         40 : QgsSymbolLayer *QgsSvgMarkerSymbolLayer::create( const QVariantMap &props )
    1938                 :            : {
    1939                 :         40 :   QString name;
    1940                 :         40 :   double size = DEFAULT_SVGMARKER_SIZE;
    1941                 :         40 :   double angle = DEFAULT_SVGMARKER_ANGLE;
    1942                 :         40 :   QgsSymbol::ScaleMethod scaleMethod = DEFAULT_SCALE_METHOD;
    1943                 :            : 
    1944                 :         80 :   if ( props.contains( QStringLiteral( "name" ) ) )
    1945                 :         80 :     name = props[QStringLiteral( "name" )].toString();
    1946                 :         80 :   if ( props.contains( QStringLiteral( "size" ) ) )
    1947                 :         80 :     size = props[QStringLiteral( "size" )].toDouble();
    1948                 :         80 :   if ( props.contains( QStringLiteral( "angle" ) ) )
    1949                 :         80 :     angle = props[QStringLiteral( "angle" )].toDouble();
    1950                 :         80 :   if ( props.contains( QStringLiteral( "scale_method" ) ) )
    1951                 :         80 :     scaleMethod = QgsSymbolLayerUtils::decodeScaleMethod( props[QStringLiteral( "scale_method" )].toString() );
    1952                 :            : 
    1953                 :         40 :   QgsSvgMarkerSymbolLayer *m = new QgsSvgMarkerSymbolLayer( name, size, angle, scaleMethod );
    1954                 :            : 
    1955                 :         80 :   if ( props.contains( QStringLiteral( "size_unit" ) ) )
    1956                 :         80 :     m->setSizeUnit( QgsUnitTypes::decodeRenderUnit( props[QStringLiteral( "size_unit" )].toString() ) );
    1957                 :         80 :   if ( props.contains( QStringLiteral( "size_map_unit_scale" ) ) )
    1958                 :         80 :     m->setSizeMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( props[QStringLiteral( "size_map_unit_scale" )].toString() ) );
    1959                 :         80 :   if ( props.contains( QStringLiteral( "fixedAspectRatio" ) ) )
    1960                 :         80 :     m->setFixedAspectRatio( props[QStringLiteral( "fixedAspectRatio" )].toDouble() );
    1961                 :         80 :   if ( props.contains( QStringLiteral( "offset" ) ) )
    1962                 :         80 :     m->setOffset( QgsSymbolLayerUtils::decodePoint( props[QStringLiteral( "offset" )].toString() ) );
    1963                 :         80 :   if ( props.contains( QStringLiteral( "offset_unit" ) ) )
    1964                 :         80 :     m->setOffsetUnit( QgsUnitTypes::decodeRenderUnit( props[QStringLiteral( "offset_unit" )].toString() ) );
    1965                 :         80 :   if ( props.contains( QStringLiteral( "offset_map_unit_scale" ) ) )
    1966                 :         80 :     m->setOffsetMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( props[QStringLiteral( "offset_map_unit_scale" )].toString() ) );
    1967                 :         80 :   if ( props.contains( QStringLiteral( "fill" ) ) )
    1968                 :            :   {
    1969                 :            :     //pre 2.5 projects used "fill"
    1970                 :          0 :     m->setFillColor( QgsSymbolLayerUtils::decodeColor( props[QStringLiteral( "fill" )].toString() ) );
    1971                 :          0 :   }
    1972                 :         80 :   else if ( props.contains( QStringLiteral( "color" ) ) )
    1973                 :            :   {
    1974                 :         80 :     m->setFillColor( QgsSymbolLayerUtils::decodeColor( props[QStringLiteral( "color" )].toString() ) );
    1975                 :         40 :   }
    1976                 :         80 :   if ( props.contains( QStringLiteral( "outline" ) ) )
    1977                 :            :   {
    1978                 :            :     //pre 2.5 projects used "outline"
    1979                 :          0 :     m->setStrokeColor( QgsSymbolLayerUtils::decodeColor( props[QStringLiteral( "outline" )].toString() ) );
    1980                 :          0 :   }
    1981                 :         80 :   else if ( props.contains( QStringLiteral( "outline_color" ) ) )
    1982                 :            :   {
    1983                 :         80 :     m->setStrokeColor( QgsSymbolLayerUtils::decodeColor( props[QStringLiteral( "outline_color" )].toString() ) );
    1984                 :         40 :   }
    1985                 :          0 :   else if ( props.contains( QStringLiteral( "line_color" ) ) )
    1986                 :            :   {
    1987                 :          0 :     m->setStrokeColor( QgsSymbolLayerUtils::decodeColor( props[QStringLiteral( "line_color" )].toString() ) );
    1988                 :          0 :   }
    1989                 :            : 
    1990                 :         80 :   if ( props.contains( QStringLiteral( "outline-width" ) ) )
    1991                 :            :   {
    1992                 :            :     //pre 2.5 projects used "outline-width"
    1993                 :          0 :     m->setStrokeWidth( props[QStringLiteral( "outline-width" )].toDouble() );
    1994                 :          0 :   }
    1995                 :         80 :   else if ( props.contains( QStringLiteral( "outline_width" ) ) )
    1996                 :            :   {
    1997                 :         80 :     m->setStrokeWidth( props[QStringLiteral( "outline_width" )].toDouble() );
    1998                 :         40 :   }
    1999                 :          0 :   else if ( props.contains( QStringLiteral( "line_width" ) ) )
    2000                 :            :   {
    2001                 :          0 :     m->setStrokeWidth( props[QStringLiteral( "line_width" )].toDouble() );
    2002                 :          0 :   }
    2003                 :            : 
    2004                 :         80 :   if ( props.contains( QStringLiteral( "outline_width_unit" ) ) )
    2005                 :            :   {
    2006                 :         80 :     m->setStrokeWidthUnit( QgsUnitTypes::decodeRenderUnit( props[QStringLiteral( "outline_width_unit" )].toString() ) );
    2007                 :         40 :   }
    2008                 :          0 :   else if ( props.contains( QStringLiteral( "line_width_unit" ) ) )
    2009                 :            :   {
    2010                 :          0 :     m->setStrokeWidthUnit( QgsUnitTypes::decodeRenderUnit( props[QStringLiteral( "line_width_unit" )].toString() ) );
    2011                 :          0 :   }
    2012                 :         80 :   if ( props.contains( QStringLiteral( "outline_width_map_unit_scale" ) ) )
    2013                 :         80 :     m->setStrokeWidthMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( props[QStringLiteral( "outline_width_map_unit_scale" )].toString() ) );
    2014                 :            : 
    2015                 :         80 :   if ( props.contains( QStringLiteral( "horizontal_anchor_point" ) ) )
    2016                 :            :   {
    2017                 :         80 :     m->setHorizontalAnchorPoint( QgsMarkerSymbolLayer::HorizontalAnchorPoint( props[ QStringLiteral( "horizontal_anchor_point" )].toInt() ) );
    2018                 :         40 :   }
    2019                 :         80 :   if ( props.contains( QStringLiteral( "vertical_anchor_point" ) ) )
    2020                 :            :   {
    2021                 :         80 :     m->setVerticalAnchorPoint( QgsMarkerSymbolLayer::VerticalAnchorPoint( props[ QStringLiteral( "vertical_anchor_point" )].toInt() ) );
    2022                 :         40 :   }
    2023                 :            : 
    2024                 :         40 :   m->restoreOldDataDefinedProperties( props );
    2025                 :            : 
    2026                 :         40 :   m->updateDefaultAspectRatio();
    2027                 :            : 
    2028                 :         80 :   if ( props.contains( QStringLiteral( "parameters" ) ) )
    2029                 :            :   {
    2030                 :         48 :     const QVariantMap parameters = props[QStringLiteral( "parameters" )].toMap();
    2031                 :         24 :     QMap<QString, QgsProperty> parametersProperties;
    2032                 :         24 :     QVariantMap::const_iterator it = parameters.constBegin();
    2033                 :         24 :     for ( ; it != parameters.constEnd(); ++it )
    2034                 :            :     {
    2035                 :          0 :       QgsProperty property;
    2036                 :          0 :       if ( property.loadVariant( it.value() ) )
    2037                 :          0 :         parametersProperties.insert( it.key(), property );
    2038                 :          0 :     }
    2039                 :            : 
    2040                 :         24 :     m->setParameters( parametersProperties );
    2041                 :         24 :   }
    2042                 :            : 
    2043                 :         40 :   return m;
    2044                 :         40 : }
    2045                 :            : 
    2046                 :         40 : void QgsSvgMarkerSymbolLayer::resolvePaths( QVariantMap &properties, const QgsPathResolver &pathResolver, bool saving )
    2047                 :            : {
    2048                 :         80 :   QVariantMap::iterator it = properties.find( QStringLiteral( "name" ) );
    2049                 :         40 :   if ( it != properties.end() )
    2050                 :            :   {
    2051                 :         40 :     if ( saving )
    2052                 :            :     {
    2053                 :          0 :       it.value() = QgsSymbolLayerUtils::svgSymbolPathToName( it.value().toString(), pathResolver );
    2054                 :          0 :     }
    2055                 :            :     else
    2056                 :            :     {
    2057                 :         40 :       it.value() = QgsSymbolLayerUtils::svgSymbolNameToPath( it.value().toString(), pathResolver );
    2058                 :            :     }
    2059                 :         40 :   }
    2060                 :         40 : }
    2061                 :            : 
    2062                 :         40 : void QgsSvgMarkerSymbolLayer::setPath( const QString &path )
    2063                 :            : {
    2064                 :         40 :   mDefaultAspectRatio = 0;
    2065                 :         40 :   mHasFillParam = false;
    2066                 :         40 :   mPath = path;
    2067                 :         40 :   QColor defaultFillColor, defaultStrokeColor;
    2068                 :            :   double strokeWidth, fillOpacity, strokeOpacity;
    2069                 :         40 :   bool hasFillOpacityParam = false, hasStrokeParam = false, hasStrokeWidthParam = false, hasStrokeOpacityParam = false;
    2070                 :         40 :   bool hasDefaultFillColor = false, hasDefaultFillOpacity = false, hasDefaultStrokeColor = false, hasDefaultStrokeWidth = false, hasDefaultStrokeOpacity = false;
    2071                 :         40 :   QgsApplication::svgCache()->containsParams( path, mHasFillParam, hasDefaultFillColor, defaultFillColor,
    2072                 :            :       hasFillOpacityParam, hasDefaultFillOpacity, fillOpacity,
    2073                 :            :       hasStrokeParam, hasDefaultStrokeColor, defaultStrokeColor,
    2074                 :            :       hasStrokeWidthParam, hasDefaultStrokeWidth, strokeWidth,
    2075                 :            :       hasStrokeOpacityParam, hasDefaultStrokeOpacity, strokeOpacity );
    2076                 :            : 
    2077                 :         40 :   double newFillOpacity = hasFillOpacityParam ? fillColor().alphaF() : 1.0;
    2078                 :         40 :   double newStrokeOpacity = hasStrokeOpacityParam ? strokeColor().alphaF() : 1.0;
    2079                 :            : 
    2080                 :         40 :   if ( hasDefaultFillColor )
    2081                 :            :   {
    2082                 :          0 :     defaultFillColor.setAlphaF( newFillOpacity );
    2083                 :          0 :     setFillColor( defaultFillColor );
    2084                 :          0 :   }
    2085                 :         40 :   if ( hasDefaultFillOpacity )
    2086                 :            :   {
    2087                 :          0 :     QColor c = fillColor();
    2088                 :          0 :     c.setAlphaF( fillOpacity );
    2089                 :          0 :     setFillColor( c );
    2090                 :          0 :   }
    2091                 :         40 :   if ( hasDefaultStrokeColor )
    2092                 :            :   {
    2093                 :          0 :     defaultStrokeColor.setAlphaF( newStrokeOpacity );
    2094                 :          0 :     setStrokeColor( defaultStrokeColor );
    2095                 :          0 :   }
    2096                 :         40 :   if ( hasDefaultStrokeWidth )
    2097                 :            :   {
    2098                 :          0 :     setStrokeWidth( strokeWidth );
    2099                 :          0 :   }
    2100                 :         40 :   if ( hasDefaultStrokeOpacity )
    2101                 :            :   {
    2102                 :          0 :     QColor c = strokeColor();
    2103                 :          0 :     c.setAlphaF( strokeOpacity );
    2104                 :          0 :     setStrokeColor( c );
    2105                 :          0 :   }
    2106                 :            : 
    2107                 :         40 :   updateDefaultAspectRatio();
    2108                 :         40 : }
    2109                 :            : 
    2110                 :         80 : double QgsSvgMarkerSymbolLayer::updateDefaultAspectRatio()
    2111                 :            : {
    2112                 :         80 :   if ( mDefaultAspectRatio == 0.0 )
    2113                 :            :   {
    2114                 :            :     //size
    2115                 :         40 :     double size = mSize;
    2116                 :            :     //assume 88 dpi as standard value
    2117                 :         40 :     double widthScaleFactor = 3.465;
    2118                 :         40 :     QSizeF svgViewbox = QgsApplication::svgCache()->svgViewboxSize( mPath, size, mColor, mStrokeColor, mStrokeWidth, widthScaleFactor );
    2119                 :            :     // set default aspect ratio
    2120                 :         40 :     mDefaultAspectRatio = svgViewbox.isValid() ? svgViewbox.height() / svgViewbox.width() : 0.0;
    2121                 :         40 :   }
    2122                 :         80 :   return mDefaultAspectRatio;
    2123                 :          0 : }
    2124                 :            : 
    2125                 :          0 : bool QgsSvgMarkerSymbolLayer::setPreservedAspectRatio( bool par )
    2126                 :            : {
    2127                 :          0 :   bool aPreservedAspectRatio = preservedAspectRatio();
    2128                 :          0 :   if ( aPreservedAspectRatio && !par )
    2129                 :            :   {
    2130                 :          0 :     mFixedAspectRatio = mDefaultAspectRatio;
    2131                 :          0 :   }
    2132                 :          0 :   else if ( !aPreservedAspectRatio && par )
    2133                 :            :   {
    2134                 :          0 :     mFixedAspectRatio = 0.0;
    2135                 :          0 :   }
    2136                 :          0 :   return preservedAspectRatio();
    2137                 :            : }
    2138                 :            : 
    2139                 :         24 : void QgsSvgMarkerSymbolLayer::setParameters( const QMap<QString, QgsProperty> &parameters )
    2140                 :            : {
    2141                 :         24 :   mParameters = parameters;
    2142                 :         24 : }
    2143                 :            : 
    2144                 :            : 
    2145                 :          0 : QString QgsSvgMarkerSymbolLayer::layerType() const
    2146                 :            : {
    2147                 :          0 :   return QStringLiteral( "SvgMarker" );
    2148                 :            : }
    2149                 :            : 
    2150                 :          0 : void QgsSvgMarkerSymbolLayer::startRender( QgsSymbolRenderContext &context )
    2151                 :            : {
    2152                 :          0 :   QgsMarkerSymbolLayer::startRender( context ); // get anchor point expressions
    2153                 :          0 :   Q_UNUSED( context )
    2154                 :          0 : }
    2155                 :            : 
    2156                 :          0 : void QgsSvgMarkerSymbolLayer::stopRender( QgsSymbolRenderContext &context )
    2157                 :            : {
    2158                 :          0 :   Q_UNUSED( context )
    2159                 :          0 : }
    2160                 :            : 
    2161                 :          0 : void QgsSvgMarkerSymbolLayer::renderPoint( QPointF point, QgsSymbolRenderContext &context )
    2162                 :            : {
    2163                 :          0 :   QPainter *p = context.renderContext().painter();
    2164                 :          0 :   if ( !p )
    2165                 :          0 :     return;
    2166                 :            : 
    2167                 :          0 :   bool hasDataDefinedSize = false;
    2168                 :          0 :   double scaledWidth = calculateSize( context, hasDataDefinedSize );
    2169                 :          0 :   double width = context.renderContext().convertToPainterUnits( scaledWidth, mSizeUnit, mSizeMapUnitScale );
    2170                 :            : 
    2171                 :            :   //don't render symbols with a width below one or above 10,000 pixels
    2172                 :          0 :   if ( static_cast< int >( width ) < 1 || 10000.0 < width )
    2173                 :            :   {
    2174                 :          0 :     return;
    2175                 :            :   }
    2176                 :            : 
    2177                 :          0 :   QgsScopedQPainterState painterState( p );
    2178                 :            : 
    2179                 :          0 :   bool hasDataDefinedAspectRatio = false;
    2180                 :          0 :   double aspectRatio = calculateAspectRatio( context, scaledWidth, hasDataDefinedAspectRatio );
    2181                 :          0 :   double scaledHeight = scaledWidth * ( !qgsDoubleNear( aspectRatio, 0.0 ) ? aspectRatio : mDefaultAspectRatio );
    2182                 :            : 
    2183                 :          0 :   QgsStringMap evaluatedParameters = QgsSymbolLayerUtils::evaluatePropertiesMap( mParameters, context.renderContext().expressionContext() );
    2184                 :            : 
    2185                 :          0 :   double strokeWidth = mStrokeWidth;
    2186                 :          0 :   if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyStrokeWidth ) )
    2187                 :            :   {
    2188                 :          0 :     context.setOriginalValueVariable( mStrokeWidth );
    2189                 :          0 :     strokeWidth = mDataDefinedProperties.valueAsDouble( QgsSymbolLayer::PropertyStrokeWidth, context.renderContext().expressionContext(), mStrokeWidth );
    2190                 :          0 :   }
    2191                 :          0 :   strokeWidth = context.renderContext().convertToPainterUnits( strokeWidth, mStrokeWidthUnit, mStrokeWidthMapUnitScale );
    2192                 :            : 
    2193                 :          0 :   QColor fillColor = mColor;
    2194                 :          0 :   if ( context.selected() && mHasFillParam )
    2195                 :            :   {
    2196                 :          0 :     fillColor = context.renderContext().selectionColor();
    2197                 :          0 :   }
    2198                 :          0 :   else if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyFillColor ) )
    2199                 :            :   {
    2200                 :          0 :     context.setOriginalValueVariable( QgsSymbolLayerUtils::encodeColor( mColor ) );
    2201                 :          0 :     fillColor = mDataDefinedProperties.valueAsColor( QgsSymbolLayer::PropertyFillColor, context.renderContext().expressionContext(), mColor );
    2202                 :          0 :   }
    2203                 :            : 
    2204                 :          0 :   QColor strokeColor = mStrokeColor;
    2205                 :          0 :   if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyStrokeColor ) )
    2206                 :            :   {
    2207                 :          0 :     context.setOriginalValueVariable( QgsSymbolLayerUtils::encodeColor( mStrokeColor ) );
    2208                 :          0 :     strokeColor = mDataDefinedProperties.valueAsColor( QgsSymbolLayer::PropertyStrokeColor, context.renderContext().expressionContext(), mStrokeColor );
    2209                 :          0 :   }
    2210                 :            : 
    2211                 :          0 :   QString path = mPath;
    2212                 :          0 :   if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyName ) )
    2213                 :            :   {
    2214                 :          0 :     context.setOriginalValueVariable( mPath );
    2215                 :          0 :     path = QgsSymbolLayerUtils::svgSymbolNameToPath( mDataDefinedProperties.valueAsString( QgsSymbolLayer::PropertyName, context.renderContext().expressionContext(), mPath ),
    2216                 :          0 :            context.renderContext().pathResolver() );
    2217                 :          0 :     if ( path != mPath && qgsDoubleNear( aspectRatio, 0.0 ) && !mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyHeight ) )
    2218                 :            :     {
    2219                 :            :       // adjust height of data defined path
    2220                 :          0 :       QSizeF svgViewbox = QgsApplication::svgCache()->svgViewboxSize( path, scaledWidth, fillColor, strokeColor, strokeWidth,
    2221                 :          0 :                           context.renderContext().scaleFactor(), aspectRatio,
    2222                 :          0 :                           ( context.renderContext().flags() & QgsRenderContext::RenderBlocking ), evaluatedParameters );
    2223                 :          0 :       scaledHeight = svgViewbox.isValid() ? scaledWidth * svgViewbox.height() / svgViewbox.width() : scaledWidth;
    2224                 :          0 :     }
    2225                 :          0 :   }
    2226                 :            : 
    2227                 :          0 :   QPointF outputOffset;
    2228                 :          0 :   double angle = 0.0;
    2229                 :          0 :   calculateOffsetAndRotation( context, scaledWidth, scaledHeight, outputOffset, angle );
    2230                 :            : 
    2231                 :          0 :   p->translate( point + outputOffset );
    2232                 :            : 
    2233                 :          0 :   bool rotated = !qgsDoubleNear( angle, 0 );
    2234                 :          0 :   if ( rotated )
    2235                 :          0 :     p->rotate( angle );
    2236                 :            : 
    2237                 :          0 :   bool fitsInCache = true;
    2238                 :          0 :   bool usePict = true;
    2239                 :          0 :   bool rasterizeSelected = !mHasFillParam || mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyName );
    2240                 :          0 :   if ( ( !context.renderContext().forceVectorOutput() && !rotated ) || ( context.selected() && rasterizeSelected ) )
    2241                 :            :   {
    2242                 :          0 :     QImage img = QgsApplication::svgCache()->svgAsImage( path, width, fillColor, strokeColor, strokeWidth,
    2243                 :          0 :                  context.renderContext().scaleFactor(), fitsInCache, aspectRatio,
    2244                 :          0 :                  ( context.renderContext().flags() & QgsRenderContext::RenderBlocking ), evaluatedParameters );
    2245                 :          0 :     if ( fitsInCache && img.width() > 1 )
    2246                 :            :     {
    2247                 :          0 :       usePict = false;
    2248                 :            : 
    2249                 :          0 :       if ( context.selected() )
    2250                 :          0 :         QgsImageOperation::adjustHueSaturation( img, 1.0, context.renderContext().selectionColor(), 1.0 );
    2251                 :            : 
    2252                 :            :       //consider transparency
    2253                 :          0 :       if ( !qgsDoubleNear( context.opacity(), 1.0 ) )
    2254                 :            :       {
    2255                 :          0 :         QImage transparentImage = img.copy();
    2256                 :          0 :         QgsSymbolLayerUtils::multiplyImageOpacity( &transparentImage, context.opacity() );
    2257                 :          0 :         p->drawImage( -transparentImage.width() / 2.0, -transparentImage.height() / 2.0, transparentImage );
    2258                 :          0 :       }
    2259                 :            :       else
    2260                 :            :       {
    2261                 :          0 :         p->drawImage( -img.width() / 2.0, -img.height() / 2.0, img );
    2262                 :            :       }
    2263                 :          0 :     }
    2264                 :          0 :   }
    2265                 :            : 
    2266                 :          0 :   if ( usePict || !fitsInCache )
    2267                 :            :   {
    2268                 :          0 :     p->setOpacity( context.opacity() );
    2269                 :          0 :     QPicture pct = QgsApplication::svgCache()->svgAsPicture( path, width, fillColor, strokeColor, strokeWidth,
    2270                 :          0 :                    context.renderContext().scaleFactor(), context.renderContext().forceVectorOutput(), aspectRatio,
    2271                 :          0 :                    ( context.renderContext().flags() & QgsRenderContext::RenderBlocking ), evaluatedParameters );
    2272                 :          0 :     if ( pct.width() > 1 )
    2273                 :            :     {
    2274                 :          0 :       QgsScopedQPainterState painterPictureState( p );
    2275                 :          0 :       _fixQPictureDPI( p );
    2276                 :          0 :       p->drawPicture( 0, 0, pct );
    2277                 :          0 :     }
    2278                 :          0 :   }
    2279                 :            : 
    2280                 :            :   // workaround issue with nested QPictures forgetting antialiasing flag - see https://github.com/qgis/QGIS/issues/22909
    2281                 :          0 :   context.renderContext().setPainterFlagsUsingContext( p );
    2282                 :          0 : }
    2283                 :            : 
    2284                 :          0 : double QgsSvgMarkerSymbolLayer::calculateSize( QgsSymbolRenderContext &context, bool &hasDataDefinedSize ) const
    2285                 :            : {
    2286                 :          0 :   double scaledSize = mSize;
    2287                 :          0 :   hasDataDefinedSize = mDataDefinedProperties.isActive( QgsSymbolLayer::PropertySize );
    2288                 :            : 
    2289                 :          0 :   bool ok = true;
    2290                 :          0 :   if ( hasDataDefinedSize )
    2291                 :            :   {
    2292                 :          0 :     context.setOriginalValueVariable( mSize );
    2293                 :          0 :     scaledSize = mDataDefinedProperties.valueAsDouble( QgsSymbolLayer::PropertySize, context.renderContext().expressionContext(), mSize, &ok );
    2294                 :          0 :   }
    2295                 :            :   else
    2296                 :            :   {
    2297                 :          0 :     hasDataDefinedSize = mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyWidth );
    2298                 :          0 :     if ( hasDataDefinedSize )
    2299                 :            :     {
    2300                 :          0 :       context.setOriginalValueVariable( mSize );
    2301                 :          0 :       scaledSize = mDataDefinedProperties.valueAsDouble( QgsSymbolLayer::PropertyWidth, context.renderContext().expressionContext(), mSize, &ok );
    2302                 :          0 :     }
    2303                 :            :   }
    2304                 :            : 
    2305                 :          0 :   if ( hasDataDefinedSize && ok )
    2306                 :            :   {
    2307                 :          0 :     switch ( mScaleMethod )
    2308                 :            :     {
    2309                 :            :       case QgsSymbol::ScaleArea:
    2310                 :          0 :         scaledSize = std::sqrt( scaledSize );
    2311                 :          0 :         break;
    2312                 :            :       case QgsSymbol::ScaleDiameter:
    2313                 :          0 :         break;
    2314                 :            :     }
    2315                 :          0 :   }
    2316                 :            : 
    2317                 :          0 :   return scaledSize;
    2318                 :          0 : }
    2319                 :            : 
    2320                 :          0 : double QgsSvgMarkerSymbolLayer::calculateAspectRatio( QgsSymbolRenderContext &context, double scaledSize, bool &hasDataDefinedAspectRatio ) const
    2321                 :            : {
    2322                 :          0 :   hasDataDefinedAspectRatio = mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyWidth ) || mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyHeight );
    2323                 :          0 :   if ( !hasDataDefinedAspectRatio )
    2324                 :          0 :     return mFixedAspectRatio;
    2325                 :            : 
    2326                 :          0 :   if ( !mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyHeight ) && mFixedAspectRatio <= 0.0 )
    2327                 :          0 :     return 0.0;
    2328                 :            : 
    2329                 :          0 :   double scaledAspectRatio = mDefaultAspectRatio;
    2330                 :          0 :   if ( mFixedAspectRatio > 0.0 )
    2331                 :          0 :     scaledAspectRatio = mFixedAspectRatio;
    2332                 :            : 
    2333                 :          0 :   double defaultHeight = mSize * scaledAspectRatio;
    2334                 :          0 :   scaledAspectRatio = defaultHeight / scaledSize;
    2335                 :            : 
    2336                 :          0 :   bool ok = true;
    2337                 :          0 :   double scaledHeight = scaledSize * scaledAspectRatio;
    2338                 :          0 :   if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyHeight ) )
    2339                 :            :   {
    2340                 :          0 :     context.setOriginalValueVariable( defaultHeight );
    2341                 :          0 :     scaledHeight = mDataDefinedProperties.valueAsDouble( QgsSymbolLayer::PropertyHeight, context.renderContext().expressionContext(), defaultHeight, &ok );
    2342                 :          0 :   }
    2343                 :            : 
    2344                 :          0 :   if ( hasDataDefinedAspectRatio && ok )
    2345                 :            :   {
    2346                 :          0 :     switch ( mScaleMethod )
    2347                 :            :     {
    2348                 :            :       case QgsSymbol::ScaleArea:
    2349                 :          0 :         scaledHeight = sqrt( scaledHeight );
    2350                 :          0 :         break;
    2351                 :            :       case QgsSymbol::ScaleDiameter:
    2352                 :          0 :         break;
    2353                 :            :     }
    2354                 :          0 :   }
    2355                 :            : 
    2356                 :          0 :   scaledAspectRatio = scaledHeight / scaledSize;
    2357                 :            : 
    2358                 :          0 :   return scaledAspectRatio;
    2359                 :          0 : }
    2360                 :            : 
    2361                 :          0 : void QgsSvgMarkerSymbolLayer::calculateOffsetAndRotation( QgsSymbolRenderContext &context, double scaledWidth, double scaledHeight, QPointF &offset, double &angle ) const
    2362                 :            : {
    2363                 :            :   //offset
    2364                 :          0 :   double offsetX = 0;
    2365                 :          0 :   double offsetY = 0;
    2366                 :          0 :   markerOffset( context, scaledWidth, scaledHeight, offsetX, offsetY );
    2367                 :          0 :   offset = QPointF( offsetX, offsetY );
    2368                 :            : 
    2369                 :          0 :   angle = mAngle + mLineAngle;
    2370                 :          0 :   if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyAngle ) )
    2371                 :            :   {
    2372                 :          0 :     context.setOriginalValueVariable( mAngle );
    2373                 :          0 :     angle = mDataDefinedProperties.valueAsDouble( QgsSymbolLayer::PropertyAngle, context.renderContext().expressionContext(), mAngle ) + mLineAngle;
    2374                 :          0 :   }
    2375                 :            : 
    2376                 :          0 :   bool hasDataDefinedRotation = context.renderHints() & QgsSymbol::DynamicRotation || mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyAngle );
    2377                 :          0 :   if ( hasDataDefinedRotation )
    2378                 :            :   {
    2379                 :            :     // For non-point markers, "dataDefinedRotation" means following the
    2380                 :            :     // shape (shape-data defined). For them, "field-data defined" does
    2381                 :            :     // not work at all. TODO: if "field-data defined" ever gets implemented
    2382                 :            :     // we'll need a way to distinguish here between the two, possibly
    2383                 :            :     // using another flag in renderHints()
    2384                 :          0 :     const QgsFeature *f = context.feature();
    2385                 :          0 :     if ( f )
    2386                 :            :     {
    2387                 :          0 :       if ( f->hasGeometry() && f->geometry().type() == QgsWkbTypes::PointGeometry )
    2388                 :            :       {
    2389                 :          0 :         const QgsMapToPixel &m2p = context.renderContext().mapToPixel();
    2390                 :          0 :         angle += m2p.mapRotation();
    2391                 :          0 :       }
    2392                 :          0 :     }
    2393                 :          0 :   }
    2394                 :            : 
    2395                 :          0 :   if ( angle )
    2396                 :          0 :     offset = _rotatedOffset( offset, angle );
    2397                 :          0 : }
    2398                 :            : 
    2399                 :            : 
    2400                 :          0 : QVariantMap QgsSvgMarkerSymbolLayer::properties() const
    2401                 :            : {
    2402                 :          0 :   QVariantMap map;
    2403                 :          0 :   map[QStringLiteral( "name" )] = mPath;
    2404                 :          0 :   map[QStringLiteral( "size" )] = QString::number( mSize );
    2405                 :          0 :   map[QStringLiteral( "size_unit" )] = QgsUnitTypes::encodeUnit( mSizeUnit );
    2406                 :          0 :   map[QStringLiteral( "size_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mSizeMapUnitScale );
    2407                 :          0 :   map[QStringLiteral( "fixedAspectRatio" )] = QString::number( mFixedAspectRatio );
    2408                 :          0 :   map[QStringLiteral( "angle" )] = QString::number( mAngle );
    2409                 :          0 :   map[QStringLiteral( "offset" )] = QgsSymbolLayerUtils::encodePoint( mOffset );
    2410                 :          0 :   map[QStringLiteral( "offset_unit" )] = QgsUnitTypes::encodeUnit( mOffsetUnit );
    2411                 :          0 :   map[QStringLiteral( "offset_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mOffsetMapUnitScale );
    2412                 :          0 :   map[QStringLiteral( "scale_method" )] = QgsSymbolLayerUtils::encodeScaleMethod( mScaleMethod );
    2413                 :          0 :   map[QStringLiteral( "color" )] = QgsSymbolLayerUtils::encodeColor( mColor );
    2414                 :          0 :   map[QStringLiteral( "outline_color" )] = QgsSymbolLayerUtils::encodeColor( mStrokeColor );
    2415                 :          0 :   map[QStringLiteral( "outline_width" )] = QString::number( mStrokeWidth );
    2416                 :          0 :   map[QStringLiteral( "outline_width_unit" )] = QgsUnitTypes::encodeUnit( mStrokeWidthUnit );
    2417                 :          0 :   map[QStringLiteral( "outline_width_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mStrokeWidthMapUnitScale );
    2418                 :          0 :   map[QStringLiteral( "horizontal_anchor_point" )] = QString::number( mHorizontalAnchorPoint );
    2419                 :          0 :   map[QStringLiteral( "vertical_anchor_point" )] = QString::number( mVerticalAnchorPoint );
    2420                 :            : 
    2421                 :          0 :   QVariantMap parameters;
    2422                 :          0 :   QMap<QString, QgsProperty>::const_iterator it = mParameters.constBegin();
    2423                 :          0 :   for ( ; it != mParameters.constEnd(); ++it )
    2424                 :          0 :     parameters.insert( it.key(), it.value().toVariant() );
    2425                 :          0 :   map[QStringLiteral( "parameters" )] = parameters;
    2426                 :            : 
    2427                 :          0 :   return map;
    2428                 :          0 : }
    2429                 :            : 
    2430                 :          0 : bool QgsSvgMarkerSymbolLayer::usesMapUnits() const
    2431                 :            : {
    2432                 :          0 :   return mSizeUnit == QgsUnitTypes::RenderMapUnits || mSizeUnit == QgsUnitTypes::RenderMetersInMapUnits
    2433                 :          0 :          || mOffsetUnit == QgsUnitTypes::RenderMapUnits || mOffsetUnit == QgsUnitTypes::RenderMetersInMapUnits
    2434                 :          0 :          || mStrokeWidthUnit == QgsUnitTypes::RenderMapUnits || mStrokeWidthUnit == QgsUnitTypes::RenderMetersInMapUnits;
    2435                 :            : }
    2436                 :            : 
    2437                 :          0 : QgsSvgMarkerSymbolLayer *QgsSvgMarkerSymbolLayer::clone() const
    2438                 :            : {
    2439                 :          0 :   QgsSvgMarkerSymbolLayer *m = new QgsSvgMarkerSymbolLayer( mPath, mSize, mAngle );
    2440                 :          0 :   m->setFixedAspectRatio( mFixedAspectRatio );
    2441                 :          0 :   m->setColor( mColor );
    2442                 :          0 :   m->setStrokeColor( mStrokeColor );
    2443                 :          0 :   m->setStrokeWidth( mStrokeWidth );
    2444                 :          0 :   m->setStrokeWidthUnit( mStrokeWidthUnit );
    2445                 :          0 :   m->setStrokeWidthMapUnitScale( mStrokeWidthMapUnitScale );
    2446                 :          0 :   m->setOffset( mOffset );
    2447                 :          0 :   m->setOffsetUnit( mOffsetUnit );
    2448                 :          0 :   m->setOffsetMapUnitScale( mOffsetMapUnitScale );
    2449                 :          0 :   m->setSizeUnit( mSizeUnit );
    2450                 :          0 :   m->setSizeMapUnitScale( mSizeMapUnitScale );
    2451                 :          0 :   m->setHorizontalAnchorPoint( mHorizontalAnchorPoint );
    2452                 :          0 :   m->setVerticalAnchorPoint( mVerticalAnchorPoint );
    2453                 :          0 :   m->setParameters( mParameters );
    2454                 :            : 
    2455                 :          0 :   copyDataDefinedProperties( m );
    2456                 :          0 :   copyPaintEffect( m );
    2457                 :          0 :   return m;
    2458                 :          0 : }
    2459                 :            : 
    2460                 :          0 : void QgsSvgMarkerSymbolLayer::setOutputUnit( QgsUnitTypes::RenderUnit unit )
    2461                 :            : {
    2462                 :          0 :   QgsMarkerSymbolLayer::setOutputUnit( unit );
    2463                 :          0 :   mStrokeWidthUnit = unit;
    2464                 :          0 : }
    2465                 :            : 
    2466                 :          0 : QgsUnitTypes::RenderUnit QgsSvgMarkerSymbolLayer::outputUnit() const
    2467                 :            : {
    2468                 :          0 :   QgsUnitTypes::RenderUnit unit = QgsMarkerSymbolLayer::outputUnit();
    2469                 :          0 :   if ( unit != mStrokeWidthUnit )
    2470                 :            :   {
    2471                 :          0 :     return QgsUnitTypes::RenderUnknownUnit;
    2472                 :            :   }
    2473                 :          0 :   return unit;
    2474                 :          0 : }
    2475                 :            : 
    2476                 :          0 : void QgsSvgMarkerSymbolLayer::setMapUnitScale( const QgsMapUnitScale &scale )
    2477                 :            : {
    2478                 :          0 :   QgsMarkerSymbolLayer::setMapUnitScale( scale );
    2479                 :          0 :   mStrokeWidthMapUnitScale = scale;
    2480                 :          0 : }
    2481                 :            : 
    2482                 :          0 : QgsMapUnitScale QgsSvgMarkerSymbolLayer::mapUnitScale() const
    2483                 :            : {
    2484                 :          0 :   if ( QgsMarkerSymbolLayer::mapUnitScale() == mStrokeWidthMapUnitScale )
    2485                 :            :   {
    2486                 :          0 :     return mStrokeWidthMapUnitScale;
    2487                 :            :   }
    2488                 :          0 :   return QgsMapUnitScale();
    2489                 :          0 : }
    2490                 :            : 
    2491                 :          0 : void QgsSvgMarkerSymbolLayer::writeSldMarker( QDomDocument &doc, QDomElement &element, const QVariantMap &props ) const
    2492                 :            : {
    2493                 :            :   // <Graphic>
    2494                 :          0 :   QDomElement graphicElem = doc.createElement( QStringLiteral( "se:Graphic" ) );
    2495                 :          0 :   element.appendChild( graphicElem );
    2496                 :            : 
    2497                 :            :   // encode a parametric SVG reference
    2498                 :          0 :   double size = QgsSymbolLayerUtils::rescaleUom( mSize, mSizeUnit, props );
    2499                 :          0 :   double strokeWidth = QgsSymbolLayerUtils::rescaleUom( mStrokeWidth, mStrokeWidthUnit, props );
    2500                 :          0 :   QgsSymbolLayerUtils::parametricSvgToSld( doc, graphicElem, mPath, mColor, size, mStrokeColor, strokeWidth );
    2501                 :            : 
    2502                 :            :   // <Rotation>
    2503                 :          0 :   QString angleFunc;
    2504                 :            :   bool ok;
    2505                 :          0 :   double angle = props.value( QStringLiteral( "angle" ), QStringLiteral( "0" ) ).toDouble( &ok );
    2506                 :          0 :   if ( !ok )
    2507                 :            :   {
    2508                 :          0 :     angleFunc = QStringLiteral( "%1 + %2" ).arg( props.value( QStringLiteral( "angle" ), QStringLiteral( "0" ) ).toString() ).arg( mAngle );
    2509                 :          0 :   }
    2510                 :          0 :   else if ( !qgsDoubleNear( angle + mAngle, 0.0 ) )
    2511                 :            :   {
    2512                 :          0 :     angleFunc = QString::number( angle + mAngle );
    2513                 :          0 :   }
    2514                 :            : 
    2515                 :          0 :   QgsSymbolLayerUtils::createRotationElement( doc, graphicElem, angleFunc );
    2516                 :            : 
    2517                 :            :   // <Displacement>
    2518                 :          0 :   QPointF offset = QgsSymbolLayerUtils::rescaleUom( mOffset, mOffsetUnit, props );
    2519                 :          0 :   QgsSymbolLayerUtils::createDisplacementElement( doc, graphicElem, offset );
    2520                 :          0 : }
    2521                 :            : 
    2522                 :          0 : QgsSymbolLayer *QgsSvgMarkerSymbolLayer::createFromSld( QDomElement &element )
    2523                 :            : {
    2524                 :          0 :   QgsDebugMsgLevel( QStringLiteral( "Entered." ), 4 );
    2525                 :            : 
    2526                 :          0 :   QDomElement graphicElem = element.firstChildElement( QStringLiteral( "Graphic" ) );
    2527                 :          0 :   if ( graphicElem.isNull() )
    2528                 :          0 :     return nullptr;
    2529                 :            : 
    2530                 :          0 :   QString path, mimeType;
    2531                 :          0 :   QColor fillColor;
    2532                 :            :   double size;
    2533                 :            : 
    2534                 :          0 :   if ( !QgsSymbolLayerUtils::externalGraphicFromSld( graphicElem, path, mimeType, fillColor, size ) )
    2535                 :          0 :     return nullptr;
    2536                 :            : 
    2537                 :          0 :   QString uom = element.attribute( QStringLiteral( "uom" ) );
    2538                 :          0 :   size = QgsSymbolLayerUtils::sizeInPixelsFromSldUom( uom, size );
    2539                 :            : 
    2540                 :          0 :   if ( mimeType != QLatin1String( "image/svg+xml" ) )
    2541                 :          0 :     return nullptr;
    2542                 :            : 
    2543                 :          0 :   double angle = 0.0;
    2544                 :          0 :   QString angleFunc;
    2545                 :          0 :   if ( QgsSymbolLayerUtils::rotationFromSldElement( graphicElem, angleFunc ) )
    2546                 :            :   {
    2547                 :            :     bool ok;
    2548                 :          0 :     double d = angleFunc.toDouble( &ok );
    2549                 :          0 :     if ( ok )
    2550                 :          0 :       angle = d;
    2551                 :          0 :   }
    2552                 :            : 
    2553                 :          0 :   QPointF offset;
    2554                 :          0 :   QgsSymbolLayerUtils::displacementFromSldElement( graphicElem, offset );
    2555                 :            : 
    2556                 :          0 :   QgsSvgMarkerSymbolLayer *m = new QgsSvgMarkerSymbolLayer( path, size );
    2557                 :          0 :   m->setOutputUnit( QgsUnitTypes::RenderUnit::RenderPixels );
    2558                 :          0 :   m->setFillColor( fillColor );
    2559                 :            :   //m->setStrokeColor( strokeColor );
    2560                 :            :   //m->setStrokeWidth( strokeWidth );
    2561                 :          0 :   m->setAngle( angle );
    2562                 :          0 :   m->setOffset( offset );
    2563                 :          0 :   return m;
    2564                 :          0 : }
    2565                 :            : 
    2566                 :          0 : bool QgsSvgMarkerSymbolLayer::writeDxf( QgsDxfExport &e, double mmMapUnitScaleFactor, const QString &layerName, QgsSymbolRenderContext &context, QPointF shift ) const
    2567                 :            : {
    2568                 :            :   //size
    2569                 :          0 :   double size = mSize;
    2570                 :            : 
    2571                 :          0 :   bool hasDataDefinedSize = mDataDefinedProperties.isActive( QgsSymbolLayer::PropertySize );
    2572                 :            : 
    2573                 :          0 :   bool ok = true;
    2574                 :          0 :   if ( hasDataDefinedSize )
    2575                 :            :   {
    2576                 :          0 :     context.setOriginalValueVariable( mSize );
    2577                 :          0 :     size = mDataDefinedProperties.valueAsDouble( QgsSymbolLayer::PropertySize, context.renderContext().expressionContext(), mSize, &ok );
    2578                 :          0 :   }
    2579                 :            : 
    2580                 :          0 :   if ( hasDataDefinedSize && ok )
    2581                 :            :   {
    2582                 :          0 :     switch ( mScaleMethod )
    2583                 :            :     {
    2584                 :            :       case QgsSymbol::ScaleArea:
    2585                 :          0 :         size = std::sqrt( size );
    2586                 :          0 :         break;
    2587                 :            :       case QgsSymbol::ScaleDiameter:
    2588                 :          0 :         break;
    2589                 :            :     }
    2590                 :          0 :   }
    2591                 :            : 
    2592                 :          0 :   if ( mSizeUnit == QgsUnitTypes::RenderMillimeters )
    2593                 :            :   {
    2594                 :          0 :     size *= mmMapUnitScaleFactor;
    2595                 :          0 :   }
    2596                 :            : 
    2597                 :            :   //offset, angle
    2598                 :          0 :   QPointF offset = mOffset;
    2599                 :            : 
    2600                 :          0 :   if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyOffset ) )
    2601                 :            :   {
    2602                 :          0 :     context.setOriginalValueVariable( QgsSymbolLayerUtils::encodePoint( mOffset ) );
    2603                 :          0 :     const QVariant val = mDataDefinedProperties.value( QgsSymbolLayer::PropertyOffset, context.renderContext().expressionContext(), QString() );
    2604                 :          0 :     const QPointF res = QgsSymbolLayerUtils::toPoint( val, &ok );
    2605                 :          0 :     if ( ok )
    2606                 :          0 :       offset = res;
    2607                 :          0 :   }
    2608                 :          0 :   double offsetX = offset.x();
    2609                 :          0 :   double offsetY = offset.y();
    2610                 :            : 
    2611                 :          0 :   QPointF outputOffset( offsetX, offsetY );
    2612                 :            : 
    2613                 :          0 :   double angle = mAngle + mLineAngle;
    2614                 :          0 :   if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyAngle ) )
    2615                 :            :   {
    2616                 :          0 :     context.setOriginalValueVariable( mAngle );
    2617                 :          0 :     angle = mDataDefinedProperties.valueAsDouble( QgsSymbolLayer::PropertyAngle, context.renderContext().expressionContext(), mAngle ) + mLineAngle;
    2618                 :          0 :   }
    2619                 :            : 
    2620                 :          0 :   if ( angle )
    2621                 :          0 :     outputOffset = _rotatedOffset( outputOffset, angle );
    2622                 :            : 
    2623                 :          0 :   outputOffset *= e.mapUnitScaleFactor( e.symbologyScale(), mOffsetUnit, e.mapUnits(), context.renderContext().mapToPixel().mapUnitsPerPixel() );
    2624                 :            : 
    2625                 :          0 :   QString path = mPath;
    2626                 :          0 :   if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyName ) )
    2627                 :            :   {
    2628                 :          0 :     context.setOriginalValueVariable( mPath );
    2629                 :          0 :     path = QgsSymbolLayerUtils::svgSymbolNameToPath( mDataDefinedProperties.valueAsString( QgsSymbolLayer::PropertyName, context.renderContext().expressionContext(), mPath ),
    2630                 :          0 :            context.renderContext().pathResolver() );
    2631                 :          0 :   }
    2632                 :            : 
    2633                 :          0 :   double strokeWidth = mStrokeWidth;
    2634                 :          0 :   if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyStrokeWidth ) )
    2635                 :            :   {
    2636                 :          0 :     context.setOriginalValueVariable( mStrokeWidth );
    2637                 :          0 :     strokeWidth = mDataDefinedProperties.valueAsDouble( QgsSymbolLayer::PropertyStrokeWidth, context.renderContext().expressionContext(), mStrokeWidth );
    2638                 :          0 :   }
    2639                 :          0 :   strokeWidth  *= e.mapUnitScaleFactor( e.symbologyScale(), mStrokeWidthUnit, e.mapUnits(), context.renderContext().mapToPixel().mapUnitsPerPixel() );
    2640                 :            : 
    2641                 :          0 :   QColor fillColor = mColor;
    2642                 :          0 :   if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyFillColor ) )
    2643                 :            :   {
    2644                 :          0 :     context.setOriginalValueVariable( QgsSymbolLayerUtils::encodeColor( mColor ) );
    2645                 :          0 :     fillColor = mDataDefinedProperties.valueAsColor( QgsSymbolLayer::PropertyFillColor, context.renderContext().expressionContext(), mColor );
    2646                 :          0 :   }
    2647                 :            : 
    2648                 :          0 :   QColor strokeColor = mStrokeColor;
    2649                 :          0 :   if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyStrokeColor ) )
    2650                 :            :   {
    2651                 :          0 :     context.setOriginalValueVariable( QgsSymbolLayerUtils::encodeColor( mStrokeColor ) );
    2652                 :          0 :     strokeColor = mDataDefinedProperties.valueAsColor( QgsSymbolLayer::PropertyStrokeColor, context.renderContext().expressionContext(), mStrokeColor );
    2653                 :          0 :   }
    2654                 :            : 
    2655                 :          0 :   QgsStringMap evaluatedParameters = QgsSymbolLayerUtils::evaluatePropertiesMap( mParameters, context.renderContext().expressionContext() );
    2656                 :            : 
    2657                 :          0 :   const QByteArray &svgContent = QgsApplication::svgCache()->svgContent( path, size, fillColor, strokeColor, strokeWidth,
    2658                 :          0 :                                  context.renderContext().scaleFactor(), mFixedAspectRatio,
    2659                 :          0 :                                  ( context.renderContext().flags() & QgsRenderContext::RenderBlocking ), evaluatedParameters );
    2660                 :            : 
    2661                 :          0 :   QSvgRenderer r( svgContent );
    2662                 :          0 :   if ( !r.isValid() )
    2663                 :          0 :     return false;
    2664                 :            : 
    2665                 :          0 :   QgsDxfPaintDevice pd( &e );
    2666                 :          0 :   pd.setDrawingSize( QSizeF( r.defaultSize() ) );
    2667                 :            : 
    2668                 :          0 :   QSizeF outSize( r.defaultSize() );
    2669                 :          0 :   outSize.scale( size, size, Qt::KeepAspectRatio );
    2670                 :            : 
    2671                 :          0 :   QPainter p;
    2672                 :          0 :   p.begin( &pd );
    2673                 :          0 :   if ( !qgsDoubleNear( angle, 0.0 ) )
    2674                 :            :   {
    2675                 :          0 :     p.translate( r.defaultSize().width() / 2.0, r.defaultSize().height() / 2.0 );
    2676                 :          0 :     p.rotate( angle );
    2677                 :          0 :     p.translate( -r.defaultSize().width() / 2.0, -r.defaultSize().height() / 2.0 );
    2678                 :          0 :   }
    2679                 :          0 :   pd.setShift( shift + QPointF( outputOffset.x(), -outputOffset.y() ) );
    2680                 :          0 :   pd.setOutputSize( QRectF( -outSize.width() / 2.0, -outSize.height() / 2.0, outSize.width(), outSize.height() ) );
    2681                 :          0 :   pd.setLayer( layerName );
    2682                 :          0 :   r.render( &p );
    2683                 :          0 :   p.end();
    2684                 :          0 :   return true;
    2685                 :          0 : }
    2686                 :            : 
    2687                 :          0 : QRectF QgsSvgMarkerSymbolLayer::bounds( QPointF point, QgsSymbolRenderContext &context )
    2688                 :            : {
    2689                 :          0 :   bool hasDataDefinedSize = false;
    2690                 :          0 :   double scaledWidth = calculateSize( context, hasDataDefinedSize );
    2691                 :            : 
    2692                 :          0 :   bool hasDataDefinedAspectRatio = false;
    2693                 :          0 :   double aspectRatio = calculateAspectRatio( context, scaledWidth, hasDataDefinedAspectRatio );
    2694                 :          0 :   double scaledHeight = scaledWidth * ( !qgsDoubleNear( aspectRatio, 0.0 ) ? aspectRatio : mDefaultAspectRatio );
    2695                 :            : 
    2696                 :          0 :   scaledWidth = context.renderContext().convertToPainterUnits( scaledWidth, mSizeUnit, mSizeMapUnitScale );
    2697                 :          0 :   scaledHeight = context.renderContext().convertToPainterUnits( scaledHeight, mSizeUnit, mSizeMapUnitScale );
    2698                 :            : 
    2699                 :            :   //don't render symbols with size below one or above 10,000 pixels
    2700                 :          0 :   if ( static_cast< int >( scaledWidth ) < 1 || 10000.0 < scaledWidth )
    2701                 :            :   {
    2702                 :          0 :     return QRectF();
    2703                 :            :   }
    2704                 :            : 
    2705                 :          0 :   QPointF outputOffset;
    2706                 :          0 :   double angle = 0.0;
    2707                 :          0 :   calculateOffsetAndRotation( context, scaledWidth, scaledHeight, outputOffset, angle );
    2708                 :            : 
    2709                 :          0 :   double strokeWidth = mStrokeWidth;
    2710                 :          0 :   if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyStrokeWidth ) )
    2711                 :            :   {
    2712                 :          0 :     context.setOriginalValueVariable( mStrokeWidth );
    2713                 :          0 :     strokeWidth = mDataDefinedProperties.valueAsDouble( QgsSymbolLayer::PropertyStrokeWidth, context.renderContext().expressionContext(), mStrokeWidth );
    2714                 :          0 :   }
    2715                 :          0 :   strokeWidth = context.renderContext().convertToPainterUnits( strokeWidth, mStrokeWidthUnit, mStrokeWidthMapUnitScale );
    2716                 :            : 
    2717                 :          0 :   QString path = mPath;
    2718                 :          0 :   if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyName ) )
    2719                 :            :   {
    2720                 :          0 :     context.setOriginalValueVariable( mPath );
    2721                 :          0 :     path = QgsSymbolLayerUtils::svgSymbolNameToPath( mDataDefinedProperties.valueAsString( QgsSymbolLayer::PropertyName, context.renderContext().expressionContext(), mPath ),
    2722                 :          0 :            context.renderContext().pathResolver() );
    2723                 :          0 :     if ( path != mPath && qgsDoubleNear( aspectRatio, 0.0 ) && !mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyHeight ) )
    2724                 :            :     {
    2725                 :            :       // need to get colors to take advantage of cached SVGs
    2726                 :          0 :       QColor fillColor = mColor;
    2727                 :          0 :       if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyFillColor ) )
    2728                 :            :       {
    2729                 :          0 :         context.setOriginalValueVariable( QgsSymbolLayerUtils::encodeColor( mColor ) );
    2730                 :          0 :         fillColor = mDataDefinedProperties.valueAsColor( QgsSymbolLayer::PropertyFillColor, context.renderContext().expressionContext(), mColor );
    2731                 :          0 :       }
    2732                 :            : 
    2733                 :          0 :       QColor strokeColor = mStrokeColor;
    2734                 :          0 :       if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyStrokeColor ) )
    2735                 :            :       {
    2736                 :          0 :         context.setOriginalValueVariable( QgsSymbolLayerUtils::encodeColor( mStrokeColor ) );
    2737                 :          0 :         fillColor = mDataDefinedProperties.valueAsColor( QgsSymbolLayer::PropertyStrokeColor, context.renderContext().expressionContext(), mStrokeColor );
    2738                 :          0 :       }
    2739                 :            : 
    2740                 :          0 :       QgsStringMap evaluatedParameters = QgsSymbolLayerUtils::evaluatePropertiesMap( mParameters, context.renderContext().expressionContext() );
    2741                 :            : 
    2742                 :            :       // adjust height of data defined path
    2743                 :          0 :       QSizeF svgViewbox = QgsApplication::svgCache()->svgViewboxSize( path, scaledWidth, fillColor, strokeColor, strokeWidth,
    2744                 :          0 :                           context.renderContext().scaleFactor(), aspectRatio,
    2745                 :          0 :                           ( context.renderContext().flags() & QgsRenderContext::RenderBlocking ), evaluatedParameters );
    2746                 :          0 :       scaledHeight = svgViewbox.isValid() ? scaledWidth * svgViewbox.height() / svgViewbox.width() : scaledWidth;
    2747                 :          0 :     }
    2748                 :          0 :   }
    2749                 :            : 
    2750                 :          0 :   QMatrix transform;
    2751                 :            :   // move to the desired position
    2752                 :          0 :   transform.translate( point.x() + outputOffset.x(), point.y() + outputOffset.y() );
    2753                 :            : 
    2754                 :          0 :   if ( !qgsDoubleNear( angle, 0.0 ) )
    2755                 :          0 :     transform.rotate( angle );
    2756                 :            : 
    2757                 :            :   //antialiasing
    2758                 :          0 :   strokeWidth += 1.0 / 2.0;
    2759                 :            : 
    2760                 :          0 :   QRectF symbolBounds = transform.mapRect( QRectF( -scaledWidth / 2.0,
    2761                 :          0 :                         -scaledHeight / 2.0,
    2762                 :          0 :                         scaledWidth,
    2763                 :          0 :                         scaledHeight ) );
    2764                 :            : 
    2765                 :            :   //extend bounds by pen width / 2.0
    2766                 :          0 :   symbolBounds.adjust( -strokeWidth / 2.0, -strokeWidth / 2.0,
    2767                 :          0 :                        strokeWidth / 2.0, strokeWidth / 2.0 );
    2768                 :            : 
    2769                 :          0 :   return symbolBounds;
    2770                 :          0 : }
    2771                 :            : 
    2772                 :            : //////////
    2773                 :            : 
    2774                 :          0 : QgsRasterMarkerSymbolLayer::QgsRasterMarkerSymbolLayer( const QString &path, double size, double angle, QgsSymbol::ScaleMethod scaleMethod )
    2775                 :          0 :   : mPath( path )
    2776                 :          0 : {
    2777                 :          0 :   mSize = size;
    2778                 :          0 :   mAngle = angle;
    2779                 :          0 :   mOffset = QPointF( 0, 0 );
    2780                 :          0 :   mScaleMethod = scaleMethod;
    2781                 :          0 :   updateDefaultAspectRatio();
    2782                 :          0 : }
    2783                 :            : 
    2784                 :            : 
    2785                 :          0 : QgsSymbolLayer *QgsRasterMarkerSymbolLayer::create( const QVariantMap &props )
    2786                 :            : {
    2787                 :          0 :   QString path;
    2788                 :          0 :   double size = DEFAULT_RASTERMARKER_SIZE;
    2789                 :          0 :   double angle = DEFAULT_RASTERMARKER_ANGLE;
    2790                 :          0 :   QgsSymbol::ScaleMethod scaleMethod = DEFAULT_SCALE_METHOD;
    2791                 :            : 
    2792                 :          0 :   if ( props.contains( QStringLiteral( "imageFile" ) ) )
    2793                 :          0 :     path = props[QStringLiteral( "imageFile" )].toString();
    2794                 :          0 :   if ( props.contains( QStringLiteral( "size" ) ) )
    2795                 :          0 :     size = props[QStringLiteral( "size" )].toDouble();
    2796                 :          0 :   if ( props.contains( QStringLiteral( "angle" ) ) )
    2797                 :          0 :     angle = props[QStringLiteral( "angle" )].toDouble();
    2798                 :          0 :   if ( props.contains( QStringLiteral( "scale_method" ) ) )
    2799                 :          0 :     scaleMethod = QgsSymbolLayerUtils::decodeScaleMethod( props[QStringLiteral( "scale_method" )].toString() );
    2800                 :            : 
    2801                 :          0 :   QgsRasterMarkerSymbolLayer *m = new QgsRasterMarkerSymbolLayer( path, size, angle, scaleMethod );
    2802                 :            : 
    2803                 :          0 :   if ( props.contains( QStringLiteral( "alpha" ) ) )
    2804                 :            :   {
    2805                 :          0 :     m->setOpacity( props[QStringLiteral( "alpha" )].toDouble() );
    2806                 :          0 :   }
    2807                 :            : 
    2808                 :          0 :   if ( props.contains( QStringLiteral( "size_unit" ) ) )
    2809                 :          0 :     m->setSizeUnit( QgsUnitTypes::decodeRenderUnit( props[QStringLiteral( "size_unit" )].toString() ) );
    2810                 :          0 :   if ( props.contains( QStringLiteral( "size_map_unit_scale" ) ) )
    2811                 :          0 :     m->setSizeMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( props[QStringLiteral( "size_map_unit_scale" )].toString() ) );
    2812                 :          0 :   if ( props.contains( QStringLiteral( "fixedAspectRatio" ) ) )
    2813                 :          0 :     m->setFixedAspectRatio( props[QStringLiteral( "fixedAspectRatio" )].toDouble() );
    2814                 :            : 
    2815                 :          0 :   if ( props.contains( QStringLiteral( "offset" ) ) )
    2816                 :          0 :     m->setOffset( QgsSymbolLayerUtils::decodePoint( props[QStringLiteral( "offset" )].toString() ) );
    2817                 :          0 :   if ( props.contains( QStringLiteral( "offset_unit" ) ) )
    2818                 :          0 :     m->setOffsetUnit( QgsUnitTypes::decodeRenderUnit( props[QStringLiteral( "offset_unit" )].toString() ) );
    2819                 :          0 :   if ( props.contains( QStringLiteral( "offset_map_unit_scale" ) ) )
    2820                 :          0 :     m->setOffsetMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( props[QStringLiteral( "offset_map_unit_scale" )].toString() ) );
    2821                 :            : 
    2822                 :          0 :   if ( props.contains( QStringLiteral( "horizontal_anchor_point" ) ) )
    2823                 :            :   {
    2824                 :          0 :     m->setHorizontalAnchorPoint( QgsMarkerSymbolLayer::HorizontalAnchorPoint( props[ QStringLiteral( "horizontal_anchor_point" )].toInt() ) );
    2825                 :          0 :   }
    2826                 :          0 :   if ( props.contains( QStringLiteral( "vertical_anchor_point" ) ) )
    2827                 :            :   {
    2828                 :          0 :     m->setVerticalAnchorPoint( QgsMarkerSymbolLayer::VerticalAnchorPoint( props[ QStringLiteral( "vertical_anchor_point" )].toInt() ) );
    2829                 :          0 :   }
    2830                 :            : 
    2831                 :          0 :   m->restoreOldDataDefinedProperties( props );
    2832                 :          0 :   m->updateDefaultAspectRatio();
    2833                 :            : 
    2834                 :          0 :   return m;
    2835                 :          0 : }
    2836                 :            : 
    2837                 :          0 : void QgsRasterMarkerSymbolLayer::resolvePaths( QVariantMap &properties, const QgsPathResolver &pathResolver, bool saving )
    2838                 :            : {
    2839                 :          0 :   QVariantMap::iterator it = properties.find( QStringLiteral( "name" ) );
    2840                 :          0 :   if ( it != properties.end() && it.value().type() == QVariant::String )
    2841                 :            :   {
    2842                 :          0 :     if ( saving )
    2843                 :          0 :       it.value() = QgsSymbolLayerUtils::svgSymbolPathToName( it.value().toString(), pathResolver );
    2844                 :            :     else
    2845                 :          0 :       it.value() =  QgsSymbolLayerUtils::svgSymbolNameToPath( it.value().toString(), pathResolver );
    2846                 :          0 :   }
    2847                 :          0 : }
    2848                 :            : 
    2849                 :          0 : void QgsRasterMarkerSymbolLayer::setPath( const QString &path )
    2850                 :            : {
    2851                 :          0 :   mPath = path;
    2852                 :          0 :   updateDefaultAspectRatio();
    2853                 :          0 : }
    2854                 :            : 
    2855                 :          0 : bool QgsRasterMarkerSymbolLayer::setPreservedAspectRatio( bool par )
    2856                 :            : {
    2857                 :          0 :   bool aPreservedAspectRatio = preservedAspectRatio();
    2858                 :          0 :   if ( aPreservedAspectRatio && !par )
    2859                 :            :   {
    2860                 :          0 :     mFixedAspectRatio = mDefaultAspectRatio;
    2861                 :          0 :   }
    2862                 :          0 :   else if ( !aPreservedAspectRatio && par )
    2863                 :            :   {
    2864                 :          0 :     mFixedAspectRatio = 0.0;
    2865                 :          0 :   }
    2866                 :          0 :   return preservedAspectRatio();
    2867                 :            : }
    2868                 :            : 
    2869                 :          0 : double QgsRasterMarkerSymbolLayer::updateDefaultAspectRatio()
    2870                 :            : {
    2871                 :          0 :   if ( mDefaultAspectRatio == 0.0 )
    2872                 :            :   {
    2873                 :          0 :     QSize size = QgsApplication::imageCache()->originalSize( mPath );
    2874                 :          0 :     mDefaultAspectRatio = ( !size.isNull() && size.isValid() && size.width() > 0 ) ? static_cast< double >( size.height() ) / static_cast< double >( size.width() ) : 0.0;
    2875                 :          0 :   }
    2876                 :          0 :   return mDefaultAspectRatio;
    2877                 :            : }
    2878                 :            : 
    2879                 :          0 : QString QgsRasterMarkerSymbolLayer::layerType() const
    2880                 :            : {
    2881                 :          0 :   return QStringLiteral( "RasterMarker" );
    2882                 :            : }
    2883                 :            : 
    2884                 :          0 : void QgsRasterMarkerSymbolLayer::renderPoint( QPointF point, QgsSymbolRenderContext &context )
    2885                 :            : {
    2886                 :          0 :   QPainter *p = context.renderContext().painter();
    2887                 :          0 :   if ( !p )
    2888                 :          0 :     return;
    2889                 :            : 
    2890                 :          0 :   QString path = mPath;
    2891                 :          0 :   if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyName ) )
    2892                 :            :   {
    2893                 :          0 :     context.setOriginalValueVariable( mPath );
    2894                 :          0 :     path = mDataDefinedProperties.valueAsString( QgsSymbolLayer::PropertyName, context.renderContext().expressionContext(), mPath );
    2895                 :          0 :   }
    2896                 :            : 
    2897                 :          0 :   if ( path.isEmpty() )
    2898                 :          0 :     return;
    2899                 :            : 
    2900                 :          0 :   double width = 0.0;
    2901                 :          0 :   double height = 0.0;
    2902                 :            : 
    2903                 :          0 :   bool hasDataDefinedSize = false;
    2904                 :          0 :   double scaledSize = calculateSize( context, hasDataDefinedSize );
    2905                 :            : 
    2906                 :          0 :   bool hasDataDefinedAspectRatio = false;
    2907                 :          0 :   double aspectRatio = calculateAspectRatio( context, scaledSize, hasDataDefinedAspectRatio );
    2908                 :            : 
    2909                 :          0 :   QPointF outputOffset;
    2910                 :          0 :   double angle = 0.0;
    2911                 :            : 
    2912                 :            :   // RenderPercentage Unit Type takes original image size
    2913                 :          0 :   if ( mSizeUnit == QgsUnitTypes::RenderPercentage )
    2914                 :            :   {
    2915                 :          0 :     QSize size = QgsApplication::imageCache()->originalSize( path );
    2916                 :          0 :     if ( size.isEmpty() )
    2917                 :          0 :       return;
    2918                 :            : 
    2919                 :          0 :     width = ( scaledSize * static_cast< double >( size.width() ) ) / 100.0;
    2920                 :          0 :     height = ( scaledSize * static_cast< double >( size.height() ) ) / 100.0;
    2921                 :            : 
    2922                 :            :     // don't render symbols with size below one or above 10,000 pixels
    2923                 :          0 :     if ( static_cast< int >( width ) < 1 || 10000.0 < width || static_cast< int >( height ) < 1 || 10000.0 < height )
    2924                 :          0 :       return;
    2925                 :            : 
    2926                 :          0 :     calculateOffsetAndRotation( context, width, height, outputOffset, angle );
    2927                 :          0 :   }
    2928                 :            :   else
    2929                 :            :   {
    2930                 :          0 :     width = context.renderContext().convertToPainterUnits( scaledSize, mSizeUnit, mSizeMapUnitScale );
    2931                 :          0 :     height = width * ( preservedAspectRatio() ? defaultAspectRatio() : aspectRatio );
    2932                 :            : 
    2933                 :          0 :     if ( preservedAspectRatio() && path != mPath )
    2934                 :            :     {
    2935                 :          0 :       QSize size = QgsApplication::imageCache()->originalSize( path );
    2936                 :          0 :       if ( !size.isNull() && size.isValid() && size.width() > 0 )
    2937                 :            :       {
    2938                 :          0 :         height = width * ( static_cast< double >( size.height() ) / static_cast< double >( size.width() ) );
    2939                 :          0 :       }
    2940                 :          0 :     }
    2941                 :            : 
    2942                 :            :     // don't render symbols with size below one or above 10,000 pixels
    2943                 :          0 :     if ( static_cast< int >( width ) < 1 || 10000.0 < width )
    2944                 :          0 :       return;
    2945                 :            : 
    2946                 :          0 :     calculateOffsetAndRotation( context, scaledSize, scaledSize * ( height / width ), outputOffset, angle );
    2947                 :            :   }
    2948                 :            : 
    2949                 :          0 :   QgsScopedQPainterState painterState( p );
    2950                 :          0 :   p->translate( point + outputOffset );
    2951                 :            : 
    2952                 :          0 :   bool rotated = !qgsDoubleNear( angle, 0 );
    2953                 :          0 :   if ( rotated )
    2954                 :          0 :     p->rotate( angle );
    2955                 :            : 
    2956                 :          0 :   double opacity = mOpacity;
    2957                 :          0 :   if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyOpacity ) )
    2958                 :            :   {
    2959                 :          0 :     context.setOriginalValueVariable( mOpacity );
    2960                 :          0 :     opacity = mDataDefinedProperties.valueAsDouble( QgsSymbolLayer::PropertyOpacity, context.renderContext().expressionContext(), opacity * 100 ) / 100.0;
    2961                 :          0 :   }
    2962                 :          0 :   opacity *= context.opacity();
    2963                 :            : 
    2964                 :            :   bool cached;
    2965                 :          0 :   QImage img = QgsApplication::imageCache()->pathAsImage( path, QSize( width, preservedAspectRatio() ? 0 : width * aspectRatio ), preservedAspectRatio(), opacity, cached, ( context.renderContext().flags() & QgsRenderContext::RenderBlocking ) );
    2966                 :          0 :   if ( !img.isNull() )
    2967                 :            :   {
    2968                 :          0 :     if ( context.selected() )
    2969                 :          0 :       QgsImageOperation::adjustHueSaturation( img, 1.0, context.renderContext().selectionColor(), 1.0 );
    2970                 :            : 
    2971                 :          0 :     p->drawImage( -img.width() / 2.0, -img.height() / 2.0, img );
    2972                 :          0 :   }
    2973                 :          0 : }
    2974                 :            : 
    2975                 :          0 : double QgsRasterMarkerSymbolLayer::calculateSize( QgsSymbolRenderContext &context, bool &hasDataDefinedSize ) const
    2976                 :            : {
    2977                 :          0 :   double scaledSize = mSize;
    2978                 :          0 :   hasDataDefinedSize = mDataDefinedProperties.isActive( QgsSymbolLayer::PropertySize );
    2979                 :            : 
    2980                 :          0 :   bool ok = true;
    2981                 :          0 :   if ( hasDataDefinedSize )
    2982                 :            :   {
    2983                 :          0 :     context.setOriginalValueVariable( mSize );
    2984                 :          0 :     scaledSize = mDataDefinedProperties.valueAsDouble( QgsSymbolLayer::PropertySize, context.renderContext().expressionContext(), mSize, &ok );
    2985                 :          0 :   }
    2986                 :            :   else
    2987                 :            :   {
    2988                 :          0 :     hasDataDefinedSize = mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyWidth );
    2989                 :          0 :     if ( hasDataDefinedSize )
    2990                 :            :     {
    2991                 :          0 :       context.setOriginalValueVariable( mSize );
    2992                 :          0 :       scaledSize = mDataDefinedProperties.valueAsDouble( QgsSymbolLayer::PropertyWidth, context.renderContext().expressionContext(), mSize, &ok );
    2993                 :          0 :     }
    2994                 :            :   }
    2995                 :            : 
    2996                 :          0 :   if ( hasDataDefinedSize && ok )
    2997                 :            :   {
    2998                 :          0 :     switch ( mScaleMethod )
    2999                 :            :     {
    3000                 :            :       case QgsSymbol::ScaleArea:
    3001                 :          0 :         scaledSize = std::sqrt( scaledSize );
    3002                 :          0 :         break;
    3003                 :            :       case QgsSymbol::ScaleDiameter:
    3004                 :          0 :         break;
    3005                 :            :     }
    3006                 :          0 :   }
    3007                 :            : 
    3008                 :          0 :   return scaledSize;
    3009                 :          0 : }
    3010                 :            : 
    3011                 :          0 : double QgsRasterMarkerSymbolLayer::calculateAspectRatio( QgsSymbolRenderContext &context, double scaledSize, bool &hasDataDefinedAspectRatio ) const
    3012                 :            : {
    3013                 :          0 :   hasDataDefinedAspectRatio = mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyWidth ) || mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyHeight );
    3014                 :          0 :   if ( !hasDataDefinedAspectRatio )
    3015                 :          0 :     return mFixedAspectRatio;
    3016                 :            : 
    3017                 :          0 :   if ( !mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyHeight ) && mFixedAspectRatio <= 0.0 )
    3018                 :          0 :     return 0.0;
    3019                 :            : 
    3020                 :          0 :   double scaledAspectRatio = mDefaultAspectRatio;
    3021                 :          0 :   if ( mFixedAspectRatio > 0.0 )
    3022                 :          0 :     scaledAspectRatio = mFixedAspectRatio;
    3023                 :            : 
    3024                 :          0 :   double defaultHeight = mSize * scaledAspectRatio;
    3025                 :          0 :   scaledAspectRatio = defaultHeight / scaledSize;
    3026                 :            : 
    3027                 :          0 :   bool ok = true;
    3028                 :          0 :   double scaledHeight = scaledSize * scaledAspectRatio;
    3029                 :          0 :   if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyHeight ) )
    3030                 :            :   {
    3031                 :          0 :     context.setOriginalValueVariable( defaultHeight );
    3032                 :          0 :     scaledHeight = mDataDefinedProperties.valueAsDouble( QgsSymbolLayer::PropertyHeight, context.renderContext().expressionContext(), defaultHeight, &ok );
    3033                 :          0 :   }
    3034                 :            : 
    3035                 :          0 :   if ( hasDataDefinedAspectRatio && ok )
    3036                 :            :   {
    3037                 :          0 :     switch ( mScaleMethod )
    3038                 :            :     {
    3039                 :            :       case QgsSymbol::ScaleArea:
    3040                 :          0 :         scaledHeight = sqrt( scaledHeight );
    3041                 :          0 :         break;
    3042                 :            :       case QgsSymbol::ScaleDiameter:
    3043                 :          0 :         break;
    3044                 :            :     }
    3045                 :          0 :   }
    3046                 :            : 
    3047                 :          0 :   scaledAspectRatio = scaledHeight / scaledSize;
    3048                 :            : 
    3049                 :          0 :   return scaledAspectRatio;
    3050                 :          0 : }
    3051                 :            : 
    3052                 :          0 : void QgsRasterMarkerSymbolLayer::calculateOffsetAndRotation( QgsSymbolRenderContext &context, double scaledWidth, double scaledHeight, QPointF &offset, double &angle ) const
    3053                 :            : {
    3054                 :            :   //offset
    3055                 :          0 :   double offsetX = 0;
    3056                 :          0 :   double offsetY = 0;
    3057                 :          0 :   markerOffset( context, scaledWidth, scaledHeight, offsetX, offsetY );
    3058                 :          0 :   offset = QPointF( offsetX, offsetY );
    3059                 :            : 
    3060                 :          0 :   angle = mAngle + mLineAngle;
    3061                 :          0 :   if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyAngle ) )
    3062                 :            :   {
    3063                 :          0 :     context.setOriginalValueVariable( mAngle );
    3064                 :          0 :     angle = mDataDefinedProperties.valueAsDouble( QgsSymbolLayer::PropertyAngle, context.renderContext().expressionContext(), mAngle ) + mLineAngle;
    3065                 :          0 :   }
    3066                 :            : 
    3067                 :          0 :   bool hasDataDefinedRotation = context.renderHints() & QgsSymbol::DynamicRotation || mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyAngle );
    3068                 :          0 :   if ( hasDataDefinedRotation )
    3069                 :            :   {
    3070                 :          0 :     const QgsFeature *f = context.feature();
    3071                 :          0 :     if ( f )
    3072                 :            :     {
    3073                 :          0 :       if ( f->hasGeometry() && f->geometry().type() == QgsWkbTypes::PointGeometry )
    3074                 :            :       {
    3075                 :          0 :         const QgsMapToPixel &m2p = context.renderContext().mapToPixel();
    3076                 :          0 :         angle += m2p.mapRotation();
    3077                 :          0 :       }
    3078                 :          0 :     }
    3079                 :          0 :   }
    3080                 :            : 
    3081                 :          0 :   if ( angle )
    3082                 :          0 :     offset = _rotatedOffset( offset, angle );
    3083                 :          0 : }
    3084                 :            : 
    3085                 :            : 
    3086                 :          0 : QVariantMap QgsRasterMarkerSymbolLayer::properties() const
    3087                 :            : {
    3088                 :          0 :   QVariantMap map;
    3089                 :          0 :   map[QStringLiteral( "imageFile" )] = mPath;
    3090                 :          0 :   map[QStringLiteral( "size" )] = QString::number( mSize );
    3091                 :          0 :   map[QStringLiteral( "size_unit" )] = QgsUnitTypes::encodeUnit( mSizeUnit );
    3092                 :          0 :   map[QStringLiteral( "size_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mSizeMapUnitScale );
    3093                 :          0 :   map[QStringLiteral( "fixedAspectRatio" )] = QString::number( mFixedAspectRatio );
    3094                 :          0 :   map[QStringLiteral( "angle" )] = QString::number( mAngle );
    3095                 :          0 :   map[QStringLiteral( "alpha" )] = QString::number( mOpacity );
    3096                 :          0 :   map[QStringLiteral( "offset" )] = QgsSymbolLayerUtils::encodePoint( mOffset );
    3097                 :          0 :   map[QStringLiteral( "offset_unit" )] = QgsUnitTypes::encodeUnit( mOffsetUnit );
    3098                 :          0 :   map[QStringLiteral( "offset_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mOffsetMapUnitScale );
    3099                 :          0 :   map[QStringLiteral( "scale_method" )] = QgsSymbolLayerUtils::encodeScaleMethod( mScaleMethod );
    3100                 :          0 :   map[QStringLiteral( "horizontal_anchor_point" )] = QString::number( mHorizontalAnchorPoint );
    3101                 :          0 :   map[QStringLiteral( "vertical_anchor_point" )] = QString::number( mVerticalAnchorPoint );
    3102                 :          0 :   return map;
    3103                 :          0 : }
    3104                 :            : 
    3105                 :          0 : QgsRasterMarkerSymbolLayer *QgsRasterMarkerSymbolLayer::clone() const
    3106                 :            : {
    3107                 :          0 :   QgsRasterMarkerSymbolLayer *m = new QgsRasterMarkerSymbolLayer( mPath, mSize, mAngle );
    3108                 :          0 :   m->setFixedAspectRatio( mFixedAspectRatio );
    3109                 :          0 :   m->setOpacity( mOpacity );
    3110                 :          0 :   m->setOffset( mOffset );
    3111                 :          0 :   m->setOffsetUnit( mOffsetUnit );
    3112                 :          0 :   m->setOffsetMapUnitScale( mOffsetMapUnitScale );
    3113                 :          0 :   m->setSizeUnit( mSizeUnit );
    3114                 :          0 :   m->setSizeMapUnitScale( mSizeMapUnitScale );
    3115                 :          0 :   m->setHorizontalAnchorPoint( mHorizontalAnchorPoint );
    3116                 :          0 :   m->setVerticalAnchorPoint( mVerticalAnchorPoint );
    3117                 :          0 :   copyDataDefinedProperties( m );
    3118                 :          0 :   copyPaintEffect( m );
    3119                 :          0 :   return m;
    3120                 :          0 : }
    3121                 :            : 
    3122                 :          0 : bool QgsRasterMarkerSymbolLayer::usesMapUnits() const
    3123                 :            : {
    3124                 :          0 :   return mSizeUnit == QgsUnitTypes::RenderMapUnits || mSizeUnit == QgsUnitTypes::RenderMetersInMapUnits
    3125                 :          0 :          || mOffsetUnit == QgsUnitTypes::RenderMapUnits || mOffsetUnit == QgsUnitTypes::RenderMetersInMapUnits;
    3126                 :            : }
    3127                 :            : 
    3128                 :          0 : void QgsRasterMarkerSymbolLayer::setMapUnitScale( const QgsMapUnitScale &scale )
    3129                 :            : {
    3130                 :          0 :   QgsMarkerSymbolLayer::setMapUnitScale( scale );
    3131                 :          0 : }
    3132                 :            : 
    3133                 :          0 : QgsMapUnitScale QgsRasterMarkerSymbolLayer::mapUnitScale() const
    3134                 :            : {
    3135                 :          0 :   return QgsMarkerSymbolLayer::mapUnitScale();
    3136                 :            : }
    3137                 :            : 
    3138                 :          0 : QRectF QgsRasterMarkerSymbolLayer::bounds( QPointF point, QgsSymbolRenderContext &context )
    3139                 :            : {
    3140                 :          0 :   bool hasDataDefinedSize = false;
    3141                 :          0 :   double scaledSize = calculateSize( context, hasDataDefinedSize );
    3142                 :          0 :   double width = context.renderContext().convertToPainterUnits( scaledSize, mSizeUnit, mSizeMapUnitScale );
    3143                 :          0 :   bool hasDataDefinedAspectRatio = false;
    3144                 :          0 :   double aspectRatio = calculateAspectRatio( context, scaledSize, hasDataDefinedAspectRatio );
    3145                 :          0 :   double height = width * ( preservedAspectRatio() ? defaultAspectRatio() : aspectRatio );
    3146                 :            : 
    3147                 :            :   //don't render symbols with size below one or above 10,000 pixels
    3148                 :          0 :   if ( static_cast< int >( scaledSize ) < 1 || 10000.0 < scaledSize )
    3149                 :            :   {
    3150                 :          0 :     return QRectF();
    3151                 :            :   }
    3152                 :            : 
    3153                 :          0 :   QPointF outputOffset;
    3154                 :          0 :   double angle = 0.0;
    3155                 :          0 :   calculateOffsetAndRotation( context, scaledSize, scaledSize * ( height / width ), outputOffset, angle );
    3156                 :            : 
    3157                 :          0 :   QMatrix transform;
    3158                 :            : 
    3159                 :            :   // move to the desired position
    3160                 :          0 :   transform.translate( point.x() + outputOffset.x(), point.y() + outputOffset.y() );
    3161                 :            : 
    3162                 :          0 :   if ( !qgsDoubleNear( angle, 0.0 ) )
    3163                 :          0 :     transform.rotate( angle );
    3164                 :            : 
    3165                 :          0 :   QRectF symbolBounds = transform.mapRect( QRectF( -width / 2.0,
    3166                 :          0 :                         -height / 2.0,
    3167                 :          0 :                         width,
    3168                 :          0 :                         height ) );
    3169                 :            : 
    3170                 :          0 :   return symbolBounds;
    3171                 :          0 : }
    3172                 :            : 
    3173                 :            : //////////
    3174                 :            : 
    3175                 :          0 : QgsFontMarkerSymbolLayer::QgsFontMarkerSymbolLayer( const QString &fontFamily, QString chr, double pointSize, const QColor &color, double angle )
    3176                 :          0 : {
    3177                 :          0 :   mFontFamily = fontFamily;
    3178                 :          0 :   mString = chr;
    3179                 :          0 :   mColor = color;
    3180                 :          0 :   mAngle = angle;
    3181                 :          0 :   mSize = pointSize;
    3182                 :          0 :   mOrigSize = pointSize;
    3183                 :          0 :   mSizeUnit = QgsUnitTypes::RenderMillimeters;
    3184                 :          0 :   mOffset = QPointF( 0, 0 );
    3185                 :          0 :   mOffsetUnit = QgsUnitTypes::RenderMillimeters;
    3186                 :          0 :   mStrokeColor = DEFAULT_FONTMARKER_BORDERCOLOR;
    3187                 :          0 :   mStrokeWidth = 0.0;
    3188                 :          0 :   mStrokeWidthUnit = QgsUnitTypes::RenderMillimeters;
    3189                 :          0 :   mPenJoinStyle = DEFAULT_FONTMARKER_JOINSTYLE;
    3190                 :          0 : }
    3191                 :            : 
    3192                 :          0 : QgsSymbolLayer *QgsFontMarkerSymbolLayer::create( const QVariantMap &props )
    3193                 :            : {
    3194                 :          0 :   QString fontFamily = DEFAULT_FONTMARKER_FONT;
    3195                 :          0 :   QString fontStyle = DEFAULT_FONTMARKER_FONT;
    3196                 :          0 :   QString string = DEFAULT_FONTMARKER_CHR;
    3197                 :          0 :   double pointSize = DEFAULT_FONTMARKER_SIZE;
    3198                 :          0 :   QColor color = DEFAULT_FONTMARKER_COLOR;
    3199                 :          0 :   double angle = DEFAULT_FONTMARKER_ANGLE;
    3200                 :            : 
    3201                 :          0 :   if ( props.contains( QStringLiteral( "font" ) ) )
    3202                 :          0 :     fontFamily = props[QStringLiteral( "font" )].toString();
    3203                 :          0 :   if ( props.contains( QStringLiteral( "chr" ) ) && props[QStringLiteral( "chr" )].toString().length() > 0 )
    3204                 :          0 :     string = props[QStringLiteral( "chr" )].toString();
    3205                 :          0 :   if ( props.contains( QStringLiteral( "size" ) ) )
    3206                 :          0 :     pointSize = props[QStringLiteral( "size" )].toDouble();
    3207                 :          0 :   if ( props.contains( QStringLiteral( "color" ) ) )
    3208                 :          0 :     color = QgsSymbolLayerUtils::decodeColor( props[QStringLiteral( "color" )].toString() );
    3209                 :          0 :   if ( props.contains( QStringLiteral( "angle" ) ) )
    3210                 :          0 :     angle = props[QStringLiteral( "angle" )].toDouble();
    3211                 :            : 
    3212                 :          0 :   QgsFontMarkerSymbolLayer *m = new QgsFontMarkerSymbolLayer( fontFamily, string, pointSize, color, angle );
    3213                 :            : 
    3214                 :          0 :   if ( props.contains( QStringLiteral( "font_style" ) ) )
    3215                 :          0 :     m->setFontStyle( props[QStringLiteral( "font_style" )].toString() );
    3216                 :          0 :   if ( props.contains( QStringLiteral( "outline_color" ) ) )
    3217                 :          0 :     m->setStrokeColor( QgsSymbolLayerUtils::decodeColor( props[QStringLiteral( "outline_color" )].toString() ) );
    3218                 :          0 :   if ( props.contains( QStringLiteral( "outline_width" ) ) )
    3219                 :          0 :     m->setStrokeWidth( props[QStringLiteral( "outline_width" )].toDouble() );
    3220                 :          0 :   if ( props.contains( QStringLiteral( "offset" ) ) )
    3221                 :          0 :     m->setOffset( QgsSymbolLayerUtils::decodePoint( props[QStringLiteral( "offset" )].toString() ) );
    3222                 :          0 :   if ( props.contains( QStringLiteral( "offset_unit" ) ) )
    3223                 :          0 :     m->setOffsetUnit( QgsUnitTypes::decodeRenderUnit( props[QStringLiteral( "offset_unit" )].toString() ) );
    3224                 :          0 :   if ( props.contains( QStringLiteral( "offset_map_unit_scale" ) ) )
    3225                 :          0 :     m->setOffsetMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( props[QStringLiteral( "offset_map_unit_scale" )].toString() ) );
    3226                 :          0 :   if ( props.contains( QStringLiteral( "size_unit" ) ) )
    3227                 :          0 :     m->setSizeUnit( QgsUnitTypes::decodeRenderUnit( props[QStringLiteral( "size_unit" )].toString() ) );
    3228                 :          0 :   if ( props.contains( QStringLiteral( "size_map_unit_scale" ) ) )
    3229                 :          0 :     m->setSizeMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( props[QStringLiteral( "size_map_unit_scale" )].toString() ) );
    3230                 :          0 :   if ( props.contains( QStringLiteral( "outline_width_unit" ) ) )
    3231                 :          0 :     m->setStrokeWidthUnit( QgsUnitTypes::decodeRenderUnit( props[QStringLiteral( "outline_width_unit" )].toString() ) );
    3232                 :          0 :   if ( props.contains( QStringLiteral( "outline_width_map_unit_scale" ) ) )
    3233                 :          0 :     m->setStrokeWidthMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( props[QStringLiteral( "outline_width_map_unit_scale" )].toString() ) );
    3234                 :          0 :   if ( props.contains( QStringLiteral( "joinstyle" ) ) )
    3235                 :          0 :     m->setPenJoinStyle( QgsSymbolLayerUtils::decodePenJoinStyle( props[QStringLiteral( "joinstyle" )].toString() ) );
    3236                 :          0 :   if ( props.contains( QStringLiteral( "horizontal_anchor_point" ) ) )
    3237                 :          0 :     m->setHorizontalAnchorPoint( QgsMarkerSymbolLayer::HorizontalAnchorPoint( props[ QStringLiteral( "horizontal_anchor_point" )].toInt() ) );
    3238                 :          0 :   if ( props.contains( QStringLiteral( "vertical_anchor_point" ) ) )
    3239                 :          0 :     m->setVerticalAnchorPoint( QgsMarkerSymbolLayer::VerticalAnchorPoint( props[ QStringLiteral( "vertical_anchor_point" )].toInt() ) );
    3240                 :            : 
    3241                 :          0 :   m->restoreOldDataDefinedProperties( props );
    3242                 :            : 
    3243                 :          0 :   return m;
    3244                 :          0 : }
    3245                 :            : 
    3246                 :          0 : QString QgsFontMarkerSymbolLayer::layerType() const
    3247                 :            : {
    3248                 :          0 :   return QStringLiteral( "FontMarker" );
    3249                 :            : }
    3250                 :            : 
    3251                 :          0 : void QgsFontMarkerSymbolLayer::startRender( QgsSymbolRenderContext &context )
    3252                 :            : {
    3253                 :          0 :   QColor brushColor = mColor;
    3254                 :          0 :   QColor penColor = mStrokeColor;
    3255                 :            : 
    3256                 :          0 :   brushColor.setAlphaF( mColor.alphaF() * context.opacity() );
    3257                 :          0 :   penColor.setAlphaF( mStrokeColor.alphaF() * context.opacity() );
    3258                 :            : 
    3259                 :          0 :   mBrush = QBrush( brushColor );
    3260                 :          0 :   mPen = QPen( penColor );
    3261                 :          0 :   mPen.setJoinStyle( mPenJoinStyle );
    3262                 :          0 :   mPen.setWidthF( context.renderContext().convertToPainterUnits( mStrokeWidth, mStrokeWidthUnit, mStrokeWidthMapUnitScale ) );
    3263                 :            : 
    3264                 :          0 :   mFont = QFont( mFontFamily );
    3265                 :          0 :   if ( !mFontStyle.isEmpty() )
    3266                 :            :   {
    3267                 :          0 :     mFont.setStyleName( QgsFontUtils::translateNamedStyle( mFontStyle ) );
    3268                 :          0 :   }
    3269                 :            : 
    3270                 :          0 :   const double sizePixels = context.renderContext().convertToPainterUnits( mSize, mSizeUnit, mSizeMapUnitScale );
    3271                 :          0 :   mNonZeroFontSize = !qgsDoubleNear( sizePixels, 0.0 );
    3272                 :            :   // if a non zero, but small pixel size results, round up to 2 pixels so that a "dot" is at least visible
    3273                 :            :   // (if we set a <=1 pixel size here Qt will reset the font to a default size, leading to much too large symbols)
    3274                 :          0 :   mFont.setPixelSize( std::max( 2, static_cast< int >( std::round( sizePixels ) ) ) );
    3275                 :          0 :   mFontMetrics.reset( new QFontMetrics( mFont ) );
    3276                 :          0 :   mChrWidth = mFontMetrics->horizontalAdvance( mString );
    3277                 :          0 :   mChrOffset = QPointF( mChrWidth / 2.0, -mFontMetrics->ascent() / 2.0 );
    3278                 :          0 :   mOrigSize = mSize; // save in case the size would be data defined
    3279                 :            : 
    3280                 :            :   // use caching only when not using a data defined character
    3281                 :          0 :   mUseCachedPath = !mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyFontFamily ) &&
    3282                 :          0 :                    !mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyFontStyle ) &&
    3283                 :          0 :                    !mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyCharacter );
    3284                 :          0 :   if ( mUseCachedPath )
    3285                 :            :   {
    3286                 :          0 :     QPointF chrOffset = mChrOffset;
    3287                 :            :     double chrWidth;
    3288                 :          0 :     QString charToRender = characterToRender( context, chrOffset, chrWidth );
    3289                 :          0 :     mCachedPath = QPainterPath();
    3290                 :          0 :     mCachedPath.addText( -chrOffset.x(), -chrOffset.y(), mFont, charToRender );
    3291                 :          0 :   }
    3292                 :          0 : }
    3293                 :            : 
    3294                 :          0 : void QgsFontMarkerSymbolLayer::stopRender( QgsSymbolRenderContext &context )
    3295                 :            : {
    3296                 :          0 :   Q_UNUSED( context )
    3297                 :          0 : }
    3298                 :            : 
    3299                 :          0 : QString QgsFontMarkerSymbolLayer::characterToRender( QgsSymbolRenderContext &context, QPointF &charOffset, double &charWidth )
    3300                 :            : {
    3301                 :          0 :   charOffset = mChrOffset;
    3302                 :          0 :   QString stringToRender = mString;
    3303                 :          0 :   if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyCharacter ) )
    3304                 :            :   {
    3305                 :          0 :     context.setOriginalValueVariable( mString );
    3306                 :          0 :     stringToRender = mDataDefinedProperties.valueAsString( QgsSymbolLayer::PropertyCharacter, context.renderContext().expressionContext(), mString );
    3307                 :          0 :     if ( stringToRender != mString )
    3308                 :            :     {
    3309                 :          0 :       charWidth = mFontMetrics->horizontalAdvance( stringToRender );
    3310                 :          0 :       charOffset = QPointF( charWidth / 2.0, -mFontMetrics->ascent() / 2.0 );
    3311                 :          0 :     }
    3312                 :          0 :   }
    3313                 :          0 :   return stringToRender;
    3314                 :          0 : }
    3315                 :            : 
    3316                 :          0 : void QgsFontMarkerSymbolLayer::calculateOffsetAndRotation( QgsSymbolRenderContext &context,
    3317                 :            :     double scaledSize,
    3318                 :            :     bool &hasDataDefinedRotation,
    3319                 :            :     QPointF &offset,
    3320                 :            :     double &angle ) const
    3321                 :            : {
    3322                 :            :   //offset
    3323                 :          0 :   double offsetX = 0;
    3324                 :          0 :   double offsetY = 0;
    3325                 :          0 :   markerOffset( context, scaledSize, scaledSize, offsetX, offsetY );
    3326                 :          0 :   offset = QPointF( offsetX, offsetY );
    3327                 :            : 
    3328                 :            :   //angle
    3329                 :          0 :   bool ok = true;
    3330                 :          0 :   angle = mAngle + mLineAngle;
    3331                 :          0 :   if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyAngle ) )
    3332                 :            :   {
    3333                 :          0 :     context.setOriginalValueVariable( angle );
    3334                 :          0 :     angle = mDataDefinedProperties.valueAsDouble( QgsSymbolLayer::PropertyAngle, context.renderContext().expressionContext(), mAngle, &ok ) + mLineAngle;
    3335                 :            : 
    3336                 :            :     // If the expression evaluation was not successful, fallback to static value
    3337                 :          0 :     if ( !ok )
    3338                 :          0 :       angle = mAngle + mLineAngle;
    3339                 :          0 :   }
    3340                 :            : 
    3341                 :          0 :   hasDataDefinedRotation = context.renderHints() & QgsSymbol::DynamicRotation;
    3342                 :          0 :   if ( hasDataDefinedRotation )
    3343                 :            :   {
    3344                 :            :     // For non-point markers, "dataDefinedRotation" means following the
    3345                 :            :     // shape (shape-data defined). For them, "field-data defined" does
    3346                 :            :     // not work at all. TODO: if "field-data defined" ever gets implemented
    3347                 :            :     // we'll need a way to distinguish here between the two, possibly
    3348                 :            :     // using another flag in renderHints()
    3349                 :          0 :     const QgsFeature *f = context.feature();
    3350                 :          0 :     if ( f )
    3351                 :            :     {
    3352                 :          0 :       if ( f->hasGeometry() && f->geometry().type() == QgsWkbTypes::PointGeometry )
    3353                 :            :       {
    3354                 :          0 :         const QgsMapToPixel &m2p = context.renderContext().mapToPixel();
    3355                 :          0 :         angle += m2p.mapRotation();
    3356                 :          0 :       }
    3357                 :          0 :     }
    3358                 :          0 :   }
    3359                 :            : 
    3360                 :          0 :   if ( angle )
    3361                 :          0 :     offset = _rotatedOffset( offset, angle );
    3362                 :          0 : }
    3363                 :            : 
    3364                 :          0 : double QgsFontMarkerSymbolLayer::calculateSize( QgsSymbolRenderContext &context )
    3365                 :            : {
    3366                 :          0 :   double scaledSize = mSize;
    3367                 :          0 :   bool hasDataDefinedSize = mDataDefinedProperties.isActive( QgsSymbolLayer::PropertySize );
    3368                 :            : 
    3369                 :          0 :   bool ok = true;
    3370                 :          0 :   if ( hasDataDefinedSize )
    3371                 :            :   {
    3372                 :          0 :     context.setOriginalValueVariable( mSize );
    3373                 :          0 :     scaledSize = mDataDefinedProperties.valueAsDouble( QgsSymbolLayer::PropertySize, context.renderContext().expressionContext(), mSize, &ok );
    3374                 :          0 :   }
    3375                 :            : 
    3376                 :          0 :   if ( hasDataDefinedSize && ok )
    3377                 :            :   {
    3378                 :          0 :     switch ( mScaleMethod )
    3379                 :            :     {
    3380                 :            :       case QgsSymbol::ScaleArea:
    3381                 :          0 :         scaledSize = std::sqrt( scaledSize );
    3382                 :          0 :         break;
    3383                 :            :       case QgsSymbol::ScaleDiameter:
    3384                 :          0 :         break;
    3385                 :            :     }
    3386                 :          0 :   }
    3387                 :          0 :   return scaledSize;
    3388                 :          0 : }
    3389                 :            : 
    3390                 :          0 : void QgsFontMarkerSymbolLayer::renderPoint( QPointF point, QgsSymbolRenderContext &context )
    3391                 :            : {
    3392                 :          0 :   QPainter *p = context.renderContext().painter();
    3393                 :          0 :   if ( !p || !mNonZeroFontSize )
    3394                 :          0 :     return;
    3395                 :            : 
    3396                 :          0 :   QTransform transform;
    3397                 :            : 
    3398                 :            :   bool ok;
    3399                 :          0 :   QColor brushColor = mColor;
    3400                 :          0 :   if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyFillColor ) )
    3401                 :            :   {
    3402                 :          0 :     context.setOriginalValueVariable( QgsSymbolLayerUtils::encodeColor( mColor ) );
    3403                 :          0 :     brushColor = mDataDefinedProperties.valueAsColor( QgsSymbolLayer::PropertyFillColor, context.renderContext().expressionContext(), brushColor );
    3404                 :          0 :   }
    3405                 :          0 :   brushColor = context.selected() ? context.renderContext().selectionColor() : brushColor;
    3406                 :          0 :   if ( !context.selected() || !SELECTION_IS_OPAQUE )
    3407                 :            :   {
    3408                 :          0 :     brushColor.setAlphaF( brushColor.alphaF() * context.opacity() );
    3409                 :          0 :   }
    3410                 :          0 :   mBrush.setColor( brushColor );
    3411                 :            : 
    3412                 :          0 :   QColor penColor = mStrokeColor;
    3413                 :          0 :   if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyStrokeColor ) )
    3414                 :            :   {
    3415                 :          0 :     context.setOriginalValueVariable( QgsSymbolLayerUtils::encodeColor( mStrokeColor ) );
    3416                 :          0 :     penColor = mDataDefinedProperties.valueAsColor( QgsSymbolLayer::PropertyStrokeColor, context.renderContext().expressionContext(), penColor );
    3417                 :          0 :   }
    3418                 :          0 :   penColor.setAlphaF( penColor.alphaF() * context.opacity() );
    3419                 :            : 
    3420                 :          0 :   double penWidth = context.renderContext().convertToPainterUnits( mStrokeWidth, mStrokeWidthUnit, mStrokeWidthMapUnitScale );
    3421                 :          0 :   if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyStrokeWidth ) )
    3422                 :            :   {
    3423                 :          0 :     context.setOriginalValueVariable( mStrokeWidth );
    3424                 :          0 :     double strokeWidth = mDataDefinedProperties.valueAsDouble( QgsSymbolLayer::PropertyStrokeWidth, context.renderContext().expressionContext(), mStrokeWidth, &ok );
    3425                 :          0 :     if ( ok )
    3426                 :            :     {
    3427                 :          0 :       penWidth = context.renderContext().convertToPainterUnits( strokeWidth, mStrokeWidthUnit, mStrokeWidthMapUnitScale );
    3428                 :          0 :     }
    3429                 :          0 :   }
    3430                 :            : 
    3431                 :          0 :   if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyJoinStyle ) )
    3432                 :            :   {
    3433                 :          0 :     context.setOriginalValueVariable( QgsSymbolLayerUtils::encodePenJoinStyle( mPenJoinStyle ) );
    3434                 :          0 :     QString style = mDataDefinedProperties.valueAsString( QgsSymbolLayer::PropertyJoinStyle, context.renderContext().expressionContext(), QString(), &ok );
    3435                 :          0 :     if ( ok )
    3436                 :            :     {
    3437                 :          0 :       mPen.setJoinStyle( QgsSymbolLayerUtils::decodePenJoinStyle( style ) );
    3438                 :          0 :     }
    3439                 :          0 :   }
    3440                 :            : 
    3441                 :          0 :   QgsScopedQPainterState painterState( p );
    3442                 :          0 :   p->setBrush( mBrush );
    3443                 :          0 :   if ( !qgsDoubleNear( penWidth, 0.0 ) )
    3444                 :            :   {
    3445                 :          0 :     mPen.setColor( penColor );
    3446                 :          0 :     mPen.setWidthF( penWidth );
    3447                 :          0 :     p->setPen( mPen );
    3448                 :          0 :   }
    3449                 :            :   else
    3450                 :            :   {
    3451                 :          0 :     p->setPen( Qt::NoPen );
    3452                 :            :   }
    3453                 :            : 
    3454                 :          0 :   if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyFontFamily ) )
    3455                 :            :   {
    3456                 :          0 :     context.setOriginalValueVariable( mFontFamily );
    3457                 :          0 :     QString fontFamily = mDataDefinedProperties.valueAsString( QgsSymbolLayer::PropertyFontFamily, context.renderContext().expressionContext(), mFontFamily, &ok );
    3458                 :          0 :     mFont.setFamily( ok ? fontFamily : mFontFamily );
    3459                 :          0 :   }
    3460                 :          0 :   if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyFontStyle ) )
    3461                 :            :   {
    3462                 :          0 :     context.setOriginalValueVariable( mFontStyle );
    3463                 :          0 :     QString fontStyle = mDataDefinedProperties.valueAsString( QgsSymbolLayer::PropertyFontStyle, context.renderContext().expressionContext(), mFontStyle, &ok );
    3464                 :          0 :     QgsFontUtils::updateFontViaStyle( mFont, QgsFontUtils::translateNamedStyle( ok ? fontStyle : mFontStyle ) );
    3465                 :          0 :   }
    3466                 :          0 :   if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyFontFamily ) || mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyFontStyle ) )
    3467                 :            :   {
    3468                 :          0 :     mFontMetrics.reset( new QFontMetrics( mFont ) );
    3469                 :          0 :   }
    3470                 :            : 
    3471                 :          0 :   QPointF chrOffset = mChrOffset;
    3472                 :            :   double chrWidth;
    3473                 :          0 :   QString charToRender = characterToRender( context, chrOffset, chrWidth );
    3474                 :            : 
    3475                 :          0 :   double sizeToRender = calculateSize( context );
    3476                 :            : 
    3477                 :          0 :   bool hasDataDefinedRotation = false;
    3478                 :          0 :   QPointF offset;
    3479                 :          0 :   double angle = 0;
    3480                 :          0 :   calculateOffsetAndRotation( context, sizeToRender, hasDataDefinedRotation, offset, angle );
    3481                 :            : 
    3482                 :          0 :   p->translate( point.x() + offset.x(), point.y() + offset.y() );
    3483                 :            : 
    3484                 :          0 :   if ( !qgsDoubleNear( angle, 0.0 ) )
    3485                 :          0 :     transform.rotate( angle );
    3486                 :            : 
    3487                 :          0 :   if ( !qgsDoubleNear( sizeToRender, mOrigSize ) )
    3488                 :            :   {
    3489                 :          0 :     double s = sizeToRender / mOrigSize;
    3490                 :          0 :     transform.scale( s, s );
    3491                 :          0 :   }
    3492                 :            : 
    3493                 :          0 :   if ( mUseCachedPath )
    3494                 :            :   {
    3495                 :          0 :     p->drawPath( transform.map( mCachedPath ) );
    3496                 :          0 :   }
    3497                 :            :   else
    3498                 :            :   {
    3499                 :          0 :     QPainterPath path;
    3500                 :          0 :     path.addText( -chrOffset.x(), -chrOffset.y(), mFont, charToRender );
    3501                 :          0 :     p->drawPath( transform.map( path ) );
    3502                 :          0 :   }
    3503                 :          0 : }
    3504                 :            : 
    3505                 :          0 : QVariantMap QgsFontMarkerSymbolLayer::properties() const
    3506                 :            : {
    3507                 :          0 :   QVariantMap props;
    3508                 :          0 :   props[QStringLiteral( "font" )] = mFontFamily;
    3509                 :          0 :   props[QStringLiteral( "font_style" )] = mFontStyle;
    3510                 :          0 :   props[QStringLiteral( "chr" )] = mString;
    3511                 :          0 :   props[QStringLiteral( "size" )] = QString::number( mSize );
    3512                 :          0 :   props[QStringLiteral( "size_unit" )] = QgsUnitTypes::encodeUnit( mSizeUnit );
    3513                 :          0 :   props[QStringLiteral( "size_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mSizeMapUnitScale );
    3514                 :          0 :   props[QStringLiteral( "color" )] = QgsSymbolLayerUtils::encodeColor( mColor );
    3515                 :          0 :   props[QStringLiteral( "outline_color" )] = QgsSymbolLayerUtils::encodeColor( mStrokeColor );
    3516                 :          0 :   props[QStringLiteral( "outline_width" )] = QString::number( mStrokeWidth );
    3517                 :          0 :   props[QStringLiteral( "outline_width_unit" )] = QgsUnitTypes::encodeUnit( mStrokeWidthUnit );
    3518                 :          0 :   props[QStringLiteral( "outline_width_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mStrokeWidthMapUnitScale );
    3519                 :          0 :   props[QStringLiteral( "joinstyle" )] = QgsSymbolLayerUtils::encodePenJoinStyle( mPenJoinStyle );
    3520                 :          0 :   props[QStringLiteral( "angle" )] = QString::number( mAngle );
    3521                 :          0 :   props[QStringLiteral( "offset" )] = QgsSymbolLayerUtils::encodePoint( mOffset );
    3522                 :          0 :   props[QStringLiteral( "offset_unit" )] = QgsUnitTypes::encodeUnit( mOffsetUnit );
    3523                 :          0 :   props[QStringLiteral( "offset_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mOffsetMapUnitScale );
    3524                 :          0 :   props[QStringLiteral( "horizontal_anchor_point" )] = QString::number( mHorizontalAnchorPoint );
    3525                 :          0 :   props[QStringLiteral( "vertical_anchor_point" )] = QString::number( mVerticalAnchorPoint );
    3526                 :          0 :   return props;
    3527                 :          0 : }
    3528                 :            : 
    3529                 :          0 : QgsFontMarkerSymbolLayer *QgsFontMarkerSymbolLayer::clone() const
    3530                 :            : {
    3531                 :          0 :   QgsFontMarkerSymbolLayer *m = new QgsFontMarkerSymbolLayer( mFontFamily, mString, mSize, mColor, mAngle );
    3532                 :          0 :   m->setFontStyle( mFontStyle );
    3533                 :          0 :   m->setStrokeColor( mStrokeColor );
    3534                 :          0 :   m->setStrokeWidth( mStrokeWidth );
    3535                 :          0 :   m->setStrokeWidthUnit( mStrokeWidthUnit );
    3536                 :          0 :   m->setStrokeWidthMapUnitScale( mStrokeWidthMapUnitScale );
    3537                 :          0 :   m->setPenJoinStyle( mPenJoinStyle );
    3538                 :          0 :   m->setOffset( mOffset );
    3539                 :          0 :   m->setOffsetUnit( mOffsetUnit );
    3540                 :          0 :   m->setOffsetMapUnitScale( mOffsetMapUnitScale );
    3541                 :          0 :   m->setSizeUnit( mSizeUnit );
    3542                 :          0 :   m->setSizeMapUnitScale( mSizeMapUnitScale );
    3543                 :          0 :   m->setHorizontalAnchorPoint( mHorizontalAnchorPoint );
    3544                 :          0 :   m->setVerticalAnchorPoint( mVerticalAnchorPoint );
    3545                 :          0 :   copyDataDefinedProperties( m );
    3546                 :          0 :   copyPaintEffect( m );
    3547                 :          0 :   return m;
    3548                 :          0 : }
    3549                 :            : 
    3550                 :          0 : void QgsFontMarkerSymbolLayer::writeSldMarker( QDomDocument &doc, QDomElement &element, const QVariantMap &props ) const
    3551                 :            : {
    3552                 :            :   // <Graphic>
    3553                 :          0 :   QDomElement graphicElem = doc.createElement( QStringLiteral( "se:Graphic" ) );
    3554                 :          0 :   element.appendChild( graphicElem );
    3555                 :            : 
    3556                 :          0 :   QString fontPath = QStringLiteral( "ttf://%1" ).arg( mFontFamily );
    3557                 :          0 :   int markIndex = !mString.isEmpty() ? mString.at( 0 ).unicode() : 0;
    3558                 :          0 :   double size = QgsSymbolLayerUtils::rescaleUom( mSize, mSizeUnit, props );
    3559                 :          0 :   QgsSymbolLayerUtils::externalMarkerToSld( doc, graphicElem, fontPath, QStringLiteral( "ttf" ), &markIndex, mColor, size );
    3560                 :            : 
    3561                 :            :   // <Rotation>
    3562                 :          0 :   QString angleFunc;
    3563                 :            :   bool ok;
    3564                 :          0 :   double angle = props.value( QStringLiteral( "angle" ), QStringLiteral( "0" ) ).toDouble( &ok );
    3565                 :          0 :   if ( !ok )
    3566                 :            :   {
    3567                 :          0 :     angleFunc = QStringLiteral( "%1 + %2" ).arg( props.value( QStringLiteral( "angle" ), QStringLiteral( "0" ) ).toString() ).arg( mAngle );
    3568                 :          0 :   }
    3569                 :          0 :   else if ( !qgsDoubleNear( angle + mAngle, 0.0 ) )
    3570                 :            :   {
    3571                 :          0 :     angleFunc = QString::number( angle + mAngle );
    3572                 :          0 :   }
    3573                 :          0 :   QgsSymbolLayerUtils::createRotationElement( doc, graphicElem, angleFunc );
    3574                 :            : 
    3575                 :            :   // <Displacement>
    3576                 :          0 :   QPointF offset = QgsSymbolLayerUtils::rescaleUom( mOffset, mOffsetUnit, props );
    3577                 :          0 :   QgsSymbolLayerUtils::createDisplacementElement( doc, graphicElem, offset );
    3578                 :          0 : }
    3579                 :            : 
    3580                 :          0 : bool QgsFontMarkerSymbolLayer::usesMapUnits() const
    3581                 :            : {
    3582                 :          0 :   return mSizeUnit == QgsUnitTypes::RenderMapUnits || mSizeUnit == QgsUnitTypes::RenderMetersInMapUnits
    3583                 :          0 :          || mStrokeWidthUnit == QgsUnitTypes::RenderMapUnits || mStrokeWidthUnit == QgsUnitTypes::RenderMetersInMapUnits
    3584                 :          0 :          || mOffsetUnit == QgsUnitTypes::RenderMapUnits || mOffsetUnit == QgsUnitTypes::RenderMetersInMapUnits;
    3585                 :            : }
    3586                 :            : 
    3587                 :          0 : QRectF QgsFontMarkerSymbolLayer::bounds( QPointF point, QgsSymbolRenderContext &context )
    3588                 :            : {
    3589                 :          0 :   QPointF chrOffset = mChrOffset;
    3590                 :          0 :   double chrWidth = mChrWidth;
    3591                 :            :   //calculate width of rendered character
    3592                 :          0 :   ( void )characterToRender( context, chrOffset, chrWidth );
    3593                 :            : 
    3594                 :          0 :   if ( !mFontMetrics )
    3595                 :          0 :     mFontMetrics.reset( new QFontMetrics( mFont ) );
    3596                 :            : 
    3597                 :          0 :   double scaledSize = calculateSize( context );
    3598                 :          0 :   if ( !qgsDoubleNear( scaledSize, mOrigSize ) )
    3599                 :            :   {
    3600                 :          0 :     chrWidth *= scaledSize / mOrigSize;
    3601                 :          0 :   }
    3602                 :            : 
    3603                 :          0 :   bool hasDataDefinedRotation = false;
    3604                 :          0 :   QPointF offset;
    3605                 :          0 :   double angle = 0;
    3606                 :          0 :   calculateOffsetAndRotation( context, scaledSize, hasDataDefinedRotation, offset, angle );
    3607                 :          0 :   scaledSize = context.renderContext().convertToPainterUnits( scaledSize, mSizeUnit, mSizeMapUnitScale );
    3608                 :            : 
    3609                 :          0 :   QMatrix transform;
    3610                 :            : 
    3611                 :            :   // move to the desired position
    3612                 :          0 :   transform.translate( point.x() + offset.x(), point.y() + offset.y() );
    3613                 :            : 
    3614                 :          0 :   if ( !qgsDoubleNear( angle, 0.0 ) )
    3615                 :          0 :     transform.rotate( angle );
    3616                 :            : 
    3617                 :          0 :   QRectF symbolBounds = transform.mapRect( QRectF( -chrWidth / 2.0,
    3618                 :          0 :                         -scaledSize / 2.0,
    3619                 :          0 :                         chrWidth,
    3620                 :          0 :                         scaledSize ) );
    3621                 :          0 :   return symbolBounds;
    3622                 :          0 : }
    3623                 :            : 
    3624                 :          0 : QgsSymbolLayer *QgsFontMarkerSymbolLayer::createFromSld( QDomElement &element )
    3625                 :            : {
    3626                 :          0 :   QgsDebugMsgLevel( QStringLiteral( "Entered." ), 4 );
    3627                 :            : 
    3628                 :          0 :   QDomElement graphicElem = element.firstChildElement( QStringLiteral( "Graphic" ) );
    3629                 :          0 :   if ( graphicElem.isNull() )
    3630                 :          0 :     return nullptr;
    3631                 :            : 
    3632                 :          0 :   QString name, format;
    3633                 :          0 :   QColor color;
    3634                 :            :   double size;
    3635                 :            :   int chr;
    3636                 :            : 
    3637                 :          0 :   if ( !QgsSymbolLayerUtils::externalMarkerFromSld( graphicElem, name, format, chr, color, size ) )
    3638                 :          0 :     return nullptr;
    3639                 :            : 
    3640                 :          0 :   if ( !name.startsWith( QLatin1String( "ttf://" ) ) || format != QLatin1String( "ttf" ) )
    3641                 :          0 :     return nullptr;
    3642                 :            : 
    3643                 :          0 :   QString fontFamily = name.mid( 6 );
    3644                 :            : 
    3645                 :          0 :   double angle = 0.0;
    3646                 :          0 :   QString angleFunc;
    3647                 :          0 :   if ( QgsSymbolLayerUtils::rotationFromSldElement( graphicElem, angleFunc ) )
    3648                 :            :   {
    3649                 :            :     bool ok;
    3650                 :          0 :     double d = angleFunc.toDouble( &ok );
    3651                 :          0 :     if ( ok )
    3652                 :          0 :       angle = d;
    3653                 :          0 :   }
    3654                 :            : 
    3655                 :          0 :   QPointF offset;
    3656                 :          0 :   QgsSymbolLayerUtils::displacementFromSldElement( graphicElem, offset );
    3657                 :            : 
    3658                 :          0 :   QString uom = element.attribute( QStringLiteral( "uom" ) );
    3659                 :          0 :   offset.setX( QgsSymbolLayerUtils::sizeInPixelsFromSldUom( uom, offset.x() ) );
    3660                 :          0 :   offset.setY( QgsSymbolLayerUtils::sizeInPixelsFromSldUom( uom, offset.y() ) );
    3661                 :          0 :   size = QgsSymbolLayerUtils::sizeInPixelsFromSldUom( uom, size );
    3662                 :            : 
    3663                 :          0 :   QgsMarkerSymbolLayer *m = new QgsFontMarkerSymbolLayer( fontFamily, QChar( chr ), size, color );
    3664                 :          0 :   m->setOutputUnit( QgsUnitTypes::RenderUnit::RenderPixels );
    3665                 :          0 :   m->setAngle( angle );
    3666                 :          0 :   m->setOffset( offset );
    3667                 :          0 :   return m;
    3668                 :          0 : }
    3669                 :            : 
    3670                 :            : 
    3671                 :          0 : void QgsSvgMarkerSymbolLayer::prepareExpressions( const QgsSymbolRenderContext &context )
    3672                 :            : {
    3673                 :          0 :   QMap<QString, QgsProperty>::iterator it = mParameters.begin();
    3674                 :          0 :   for ( ; it != mParameters.end(); ++it )
    3675                 :          0 :     it.value().prepare( context.renderContext().expressionContext() );
    3676                 :            : 
    3677                 :          0 :   QgsMarkerSymbolLayer::prepareExpressions( context );
    3678                 :          0 : }
    3679                 :            : 
    3680                 :            : 
    3681                 :          0 : QSet<QString> QgsSvgMarkerSymbolLayer::usedAttributes( const QgsRenderContext &context ) const
    3682                 :            : {
    3683                 :          0 :   QSet<QString> attrs = QgsMarkerSymbolLayer::usedAttributes( context );
    3684                 :            : 
    3685                 :          0 :   QMap<QString, QgsProperty>::const_iterator it = mParameters.constBegin();
    3686                 :          0 :   for ( ; it != mParameters.constEnd(); ++it )
    3687                 :            :   {
    3688                 :          0 :     attrs.unite( it.value().referencedFields( context.expressionContext(), true ) );
    3689                 :          0 :   }
    3690                 :            : 
    3691                 :          0 :   return attrs;
    3692                 :          0 : }

Generated by: LCOV version 1.14