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