QGIS API Documentation  2.15.0-Master (972fc9f)
qgsmarkersymbollayerv2.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsmarkersymbollayerv2.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 "qgsmarkersymbollayerv2.h"
17 #include "qgssymbollayerv2utils.h"
18 
19 #include "qgsdxfexport.h"
20 #include "qgsdxfpaintdevice.h"
21 #include "qgsexpression.h"
22 #include "qgsrendercontext.h"
23 #include "qgslogger.h"
24 #include "qgssvgcache.h"
25 #include "qgsunittypes.h"
26 
27 #include <QPainter>
28 #include <QSvgRenderer>
29 #include <QFileInfo>
30 #include <QDir>
31 #include <QDomDocument>
32 #include <QDomElement>
33 
34 #include <cmath>
35 
36 Q_GUI_EXPORT extern int qt_defaultDpiX();
37 Q_GUI_EXPORT extern int qt_defaultDpiY();
38 
39 static void _fixQPictureDPI( QPainter* p )
40 {
41  // QPicture makes an assumption that we drawing to it with system DPI.
42  // Then when being drawn, it scales the painter. The following call
43  // negates the effect. There is no way of setting QPicture's DPI.
44  // See QTBUG-20361
45  p->scale( static_cast< double >( qt_defaultDpiX() ) / p->device()->logicalDpiX(),
46  static_cast< double >( qt_defaultDpiY() ) / p->device()->logicalDpiY() );
47 }
48 
49 
51 
52 
53 //
54 // QgsSimpleMarkerSymbolLayerBase
55 //
56 
58 {
59  QList< Shape > shapes;
60  shapes << Square
61  << Diamond
62  << Pentagon
63  << Hexagon
64  << Triangle
66  << Star
67  << Arrow
68  << Circle
69  << Cross
70  << CrossFill
71  << Cross2
72  << Line
73  << ArrowHead
75  << SemiCircle
76  << ThirdCircle
77  << QuarterCircle
78  << QuarterSquare
79  << HalfSquare
83  return shapes;
84 }
85 
87  : mShape( shape )
88 {
89  mSize = size;
90  mAngle = angle;
91  mOffset = QPointF( 0, 0 );
95 }
96 
98 {
99  switch ( shape )
100  {
101  case Square:
102  case Diamond:
103  case Pentagon:
104  case Hexagon:
105  case Triangle:
106  case EquilateralTriangle:
107  case Star:
108  case Arrow:
109  case Circle:
110  case CrossFill:
111  case ArrowHeadFilled:
112  case SemiCircle:
113  case ThirdCircle:
114  case QuarterCircle:
115  case QuarterSquare:
116  case HalfSquare:
117  case DiagonalHalfSquare:
118  case RightHalfTriangle:
119  case LeftHalfTriangle:
120  return true;
121 
122  case Cross:
123  case Cross2:
124  case Line:
125  case ArrowHead:
126  return false;
127  }
128  return true;
129 }
130 
132 {
135 
136  // use either QPolygonF or QPainterPath for drawing
137  if ( !prepareMarkerShape( mShape ) ) // drawing as a polygon
138  {
139  prepareMarkerPath( mShape ); // drawing as a painter path
140  }
141 
142  QTransform transform;
143 
144  // scale the shape (if the size is not going to be modified)
145  if ( !hasDataDefinedSize )
146  {
148  double half = scaledSize / 2.0;
149  transform.scale( half, half );
150  }
151 
152  // rotate if the rotation is not going to be changed during the rendering
153  if ( !hasDataDefinedRotation && !qgsDoubleNear( mAngle, 0.0 ) )
154  {
155  transform.rotate( mAngle );
156  }
157 
158  if ( !mPolygon.isEmpty() )
159  mPolygon = transform.map( mPolygon );
160  else
161  mPath = transform.map( mPath );
162 
163  prepareExpressions( context );
164 
166 }
167 
169 {
170  Q_UNUSED( context );
171 }
172 
174 {
175  //making changes here? Don't forget to also update ::bounds if the changes affect the bounding box
176  //of the rendered point!
177 
178  QPainter *p = context.renderContext().painter();
179  if ( !p )
180  {
181  return;
182  }
183 
184  bool hasDataDefinedSize = false;
185  double scaledSize = calculateSize( context, hasDataDefinedSize );
186 
187  bool hasDataDefinedRotation = false;
188  QPointF offset;
189  double angle = 0;
190  calculateOffsetAndRotation( context, scaledSize, hasDataDefinedRotation, offset, angle );
191 
192  //data defined shape?
193  bool createdNewPath = false;
194  bool ok = true;
195  Shape symbol = mShape;
197  {
198  context.setOriginalValueVariable( encodeShape( symbol ) );
200  if ( ok )
201  {
202  Shape decoded = decodeShape( name, &ok );
203  if ( ok )
204  {
205  symbol = decoded;
206 
207  if ( !prepareMarkerShape( symbol ) ) // drawing as a polygon
208  {
209  prepareMarkerPath( symbol ); // drawing as a painter path
210  }
211  createdNewPath = true;
212  }
213  }
214  else
215  {
216  symbol = mShape;
217  }
218  }
219 
220  QTransform transform;
221 
222  // move to the desired position
223  transform.translate( point.x() + offset.x(), point.y() + offset.y() );
224 
225  // resize if necessary
226  if ( hasDataDefinedSize || createdNewPath )
227  {
229  double half = s / 2.0;
230  transform.scale( half, half );
231  }
232 
233  if ( !qgsDoubleNear( angle, 0.0 ) && ( hasDataDefinedRotation || createdNewPath ) )
234  transform.rotate( angle );
235 
236  //need to pass: symbol, polygon, path
237 
238  QPolygonF polygon;
239  QPainterPath path;
240  if ( !mPolygon.isEmpty() )
241  {
242  polygon = transform.map( mPolygon );
243  }
244  else
245  {
246  path = transform.map( mPath );
247  }
248  draw( context, symbol, polygon, path );
249 }
250 
252 {
253  bool hasDataDefinedSize = false;
254  double scaledSize = calculateSize( context, hasDataDefinedSize );
255 
256  bool hasDataDefinedRotation = false;
257  QPointF offset;
258  double angle = 0;
259  calculateOffsetAndRotation( context, scaledSize, hasDataDefinedRotation, offset, angle );
260 
262 
263  QTransform transform;
264 
265  // move to the desired position
266  transform.translate( point.x() + offset.x(), point.y() + offset.y() );
267 
268  if ( !qgsDoubleNear( angle, 0.0 ) )
269  transform.rotate( angle );
270 
271  return transform.mapRect( QRectF( -scaledSize / 2.0,
272  -scaledSize / 2.0,
273  scaledSize,
274  scaledSize ) );
275 }
276 
278 {
279  if ( ok )
280  *ok = true;
281  QString cleaned = name.toLower().trimmed();
282 
283  if ( cleaned == "square" || cleaned == "rectangle" )
284  return Square;
285  else if ( cleaned == "diamond" )
286  return Diamond;
287  else if ( cleaned == "pentagon" )
288  return Pentagon;
289  else if ( cleaned == "hexagon" )
290  return Hexagon;
291  else if ( cleaned == "triangle" )
292  return Triangle;
293  else if ( cleaned == "equilateral_triangle" )
294  return EquilateralTriangle;
295  else if ( cleaned == "star" || cleaned == "regular_star" )
296  return Star;
297  else if ( cleaned == "arrow" )
298  return Arrow;
299  else if ( cleaned == "circle" )
300  return Circle;
301  else if ( cleaned == "cross" )
302  return Cross;
303  else if ( cleaned == "cross_fill" )
304  return CrossFill;
305  else if ( cleaned == "cross2" || cleaned == "x" )
306  return Cross2;
307  else if ( cleaned == "line" )
308  return Line;
309  else if ( cleaned == "arrowhead" )
310  return ArrowHead;
311  else if ( cleaned == "filled_arrowhead" )
312  return ArrowHeadFilled;
313  else if ( cleaned == "semi_circle" )
314  return SemiCircle;
315  else if ( cleaned == "third_circle" )
316  return ThirdCircle;
317  else if ( cleaned == "quarter_circle" )
318  return QuarterCircle;
319  else if ( cleaned == "quarter_square" )
320  return QuarterSquare;
321  else if ( cleaned == "half_square" )
322  return HalfSquare;
323  else if ( cleaned == "diagonal_half_square" )
324  return DiagonalHalfSquare;
325  else if ( cleaned == "right_half_triangle" )
326  return RightHalfTriangle;
327  else if ( cleaned == "left_half_triangle" )
328  return LeftHalfTriangle;
329 
330  if ( ok )
331  *ok = false;
332  return Circle;
333 }
334 
336 {
337  switch ( shape )
338  {
339  case Square:
340  return "square";
341  case QuarterSquare:
342  return "quarter_square";
343  case HalfSquare:
344  return "half_square";
345  case DiagonalHalfSquare:
346  return "diagonal_half_square";
347  case Diamond:
348  return "diamond";
349  case Pentagon:
350  return "pentagon";
351  case Hexagon:
352  return "hexagon";
353  case Triangle:
354  return "triangle";
355  case EquilateralTriangle:
356  return "equilateral_triangle";
357  case LeftHalfTriangle:
358  return "left_half_triangle";
359  case RightHalfTriangle:
360  return "right_half_triangle";
361  case Star:
362  return "star";
363  case Arrow:
364  return "arrow";
365  case ArrowHeadFilled:
366  return "filled_arrowhead";
367  case CrossFill:
368  return "cross_fill";
369  case Circle:
370  return "circle";
371  case Cross:
372  return "cross";
373  case Cross2:
374  return "cross2";
375  case Line:
376  return "line";
377  case ArrowHead:
378  return "arrowhead";
379  case SemiCircle:
380  return "semi_circle";
381  case ThirdCircle:
382  return "third_circle";
383  case QuarterCircle:
384  return "quarter_circle";
385  }
386  return QString();
387 }
388 
390 {
391  return shapeToPolygon( shape, mPolygon );
392 }
393 
395 {
396  polygon.clear();
397 
398  switch ( shape )
399  {
400  case Square:
401  polygon = QPolygonF( QRectF( QPointF( -1, -1 ), QPointF( 1, 1 ) ) );
402  return true;
403 
404  case QuarterSquare:
405  polygon = QPolygonF( QRectF( QPointF( -1, -1 ), QPointF( 0, 0 ) ) );
406  return true;
407 
408  case HalfSquare:
409  polygon = QPolygonF( QRectF( QPointF( -1, -1 ), QPointF( 0, 1 ) ) );
410  return true;
411 
412  case DiagonalHalfSquare:
413  polygon << QPointF( -1, -1 ) << QPointF( 1, 1 ) << QPointF( -1, 1 ) << QPointF( -1, -1 );
414  return true;
415 
416  case Diamond:
417  polygon << QPointF( -1, 0 ) << QPointF( 0, 1 )
418  << QPointF( 1, 0 ) << QPointF( 0, -1 ) << QPointF( -1, 0 );
419  return true;
420 
421  case Pentagon:
422  /* angular-representation of hardcoded values used
423  polygon << QPointF( sin( DEG2RAD( 288.0 ) ), - cos( DEG2RAD( 288.0 ) ) )
424  << QPointF( sin( DEG2RAD( 216.0 ) ), - cos( DEG2RAD( 216.0 ) ) )
425  << QPointF( sin( DEG2RAD( 144.0 ) ), - cos( DEG2RAD( 144.0 ) ) )
426  << QPointF( sin( DEG2RAD( 72.0 ) ), - cos( DEG2RAD( 72.0 ) ) )
427  << QPointF( 0, -1 ); */
428  polygon << QPointF( -0.9511, -0.3090 )
429  << QPointF( -0.5878, 0.8090 )
430  << QPointF( 0.5878, 0.8090 )
431  << QPointF( 0.9511, -0.3090 )
432  << QPointF( 0, -1 )
433  << QPointF( -0.9511, -0.3090 );
434  return true;
435 
436  case Hexagon:
437  /* angular-representation of hardcoded values used
438  polygon << QPointF( sin( DEG2RAD( 300.0 ) ), - cos( DEG2RAD( 300.0 ) ) )
439  << QPointF( sin( DEG2RAD( 240.0 ) ), - cos( DEG2RAD( 240.0 ) ) )
440  << QPointF( sin( DEG2RAD( 180.0 ) ), - cos( DEG2RAD( 180.0 ) ) )
441  << QPointF( sin( DEG2RAD( 120.0 ) ), - cos( DEG2RAD( 120.0 ) ) )
442  << QPointF( sin( DEG2RAD( 60.0 ) ), - cos( DEG2RAD( 60.0 ) ) )
443  << QPointF( 0, -1 ); */
444  polygon << QPointF( -0.8660, -0.5 )
445  << QPointF( -0.8660, 0.5 )
446  << QPointF( 0, 1 )
447  << QPointF( 0.8660, 0.5 )
448  << QPointF( 0.8660, -0.5 )
449  << QPointF( 0, -1 )
450  << QPointF( -0.8660, -0.5 );
451  return true;
452 
453  case Triangle:
454  polygon << QPointF( -1, 1 ) << QPointF( 1, 1 ) << QPointF( 0, -1 ) << QPointF( -1, 1 );
455  return true;
456 
457  case EquilateralTriangle:
458  /* angular-representation of hardcoded values used
459  polygon << QPointF( sin( DEG2RAD( 240.0 ) ), - cos( DEG2RAD( 240.0 ) ) )
460  << QPointF( sin( DEG2RAD( 120.0 ) ), - cos( DEG2RAD( 120.0 ) ) )
461  << QPointF( 0, -1 ); */
462  polygon << QPointF( -0.8660, 0.5 )
463  << QPointF( 0.8660, 0.5 )
464  << QPointF( 0, -1 )
465  << QPointF( -0.8660, 0.5 );
466  return true;
467 
468  case LeftHalfTriangle:
469  polygon << QPointF( 0, 1 ) << QPointF( 1, 1 ) << QPointF( 0, -1 ) << QPointF( 0, 1 );
470  return true;
471 
472  case RightHalfTriangle:
473  polygon << QPointF( -1, 1 ) << QPointF( 0, 1 ) << QPointF( 0, -1 ) << QPointF( -1, 1 );
474  return true;
475 
476  case Star:
477  {
478  double inner_r = cos( DEG2RAD( 72.0 ) ) / cos( DEG2RAD( 36.0 ) );
479 
480  polygon << QPointF( inner_r * sin( DEG2RAD( 324.0 ) ), - inner_r * cos( DEG2RAD( 324.0 ) ) ) // 324
481  << QPointF( sin( DEG2RAD( 288.0 ) ), - cos( DEG2RAD( 288 ) ) ) // 288
482  << QPointF( inner_r * sin( DEG2RAD( 252.0 ) ), - inner_r * cos( DEG2RAD( 252.0 ) ) ) // 252
483  << QPointF( sin( DEG2RAD( 216.0 ) ), - cos( DEG2RAD( 216.0 ) ) ) // 216
484  << QPointF( 0, inner_r ) // 180
485  << QPointF( sin( DEG2RAD( 144.0 ) ), - cos( DEG2RAD( 144.0 ) ) ) // 144
486  << QPointF( inner_r * sin( DEG2RAD( 108.0 ) ), - inner_r * cos( DEG2RAD( 108.0 ) ) ) // 108
487  << QPointF( sin( DEG2RAD( 72.0 ) ), - cos( DEG2RAD( 72.0 ) ) ) // 72
488  << QPointF( inner_r * sin( DEG2RAD( 36.0 ) ), - inner_r * cos( DEG2RAD( 36.0 ) ) ) // 36
489  << QPointF( 0, -1 )
490  << QPointF( inner_r * sin( DEG2RAD( 324.0 ) ), - inner_r * cos( DEG2RAD( 324.0 ) ) ); // 324; // 0
491  return true;
492  }
493 
494  case Arrow:
495  polygon << QPointF( 0, -1 )
496  << QPointF( 0.5, -0.5 )
497  << QPointF( 0.25, -0.5 )
498  << QPointF( 0.25, 1 )
499  << QPointF( -0.25, 1 )
500  << QPointF( -0.25, -0.5 )
501  << QPointF( -0.5, -0.5 )
502  << QPointF( 0, -1 );
503  return true;
504 
505  case ArrowHeadFilled:
506  polygon << QPointF( 0, 0 ) << QPointF( -1, 1 ) << QPointF( -1, -1 ) << QPointF( 0, 0 );
507  return true;
508 
509  case CrossFill:
510  polygon << QPointF( -1, -0.2 )
511  << QPointF( -1, -0.2 )
512  << QPointF( -1, 0.2 )
513  << QPointF( -0.2, 0.2 )
514  << QPointF( -0.2, 1 )
515  << QPointF( 0.2, 1 )
516  << QPointF( 0.2, 0.2 )
517  << QPointF( 1, 0.2 )
518  << QPointF( 1, -0.2 )
519  << QPointF( 0.2, -0.2 )
520  << QPointF( 0.2, -1 )
521  << QPointF( -0.2, -1 )
522  << QPointF( -0.2, -0.2 )
523  << QPointF( -1, -0.2 );
524  return true;
525 
526  case Circle:
527  case Cross:
528  case Cross2:
529  case Line:
530  case ArrowHead:
531  case SemiCircle:
532  case ThirdCircle:
533  case QuarterCircle:
534  return false;
535  }
536 
537  return false;
538 }
539 
541 {
542  mPath = QPainterPath();
543 
544  switch ( symbol )
545  {
546  case Circle:
547 
548  mPath.addEllipse( QRectF( -1, -1, 2, 2 ) ); // x,y,w,h
549  return true;
550 
551  case SemiCircle:
552  mPath.arcTo( -1, -1, 2, 2, 0, 180 );
553  mPath.lineTo( 0, 0 );
554  return true;
555 
556  case ThirdCircle:
557  mPath.arcTo( -1, -1, 2, 2, 90, 120 );
558  mPath.lineTo( 0, 0 );
559  return true;
560 
561  case QuarterCircle:
562  mPath.arcTo( -1, -1, 2, 2, 90, 90 );
563  mPath.lineTo( 0, 0 );
564  return true;
565 
566  case Cross:
567  mPath.moveTo( -1, 0 );
568  mPath.lineTo( 1, 0 ); // horizontal
569  mPath.moveTo( 0, -1 );
570  mPath.lineTo( 0, 1 ); // vertical
571  return true;
572 
573  case Cross2:
574  mPath.moveTo( -1, -1 );
575  mPath.lineTo( 1, 1 );
576  mPath.moveTo( 1, -1 );
577  mPath.lineTo( -1, 1 );
578  return true;
579 
580  case Line:
581  mPath.moveTo( 0, -1 );
582  mPath.lineTo( 0, 1 ); // vertical line
583  return true;
584 
585  case ArrowHead:
586  mPath.moveTo( -1, -1 );
587  mPath.lineTo( 0, 0 );
588  mPath.lineTo( -1, 1 );
589  return true;
590 
591  case Square:
592  case QuarterSquare:
593  case HalfSquare:
594  case DiagonalHalfSquare:
595  case Diamond:
596  case Pentagon:
597  case Hexagon:
598  case Triangle:
599  case EquilateralTriangle:
600  case LeftHalfTriangle:
601  case RightHalfTriangle:
602  case Star:
603  case Arrow:
604  case ArrowHeadFilled:
605  case CrossFill:
606  return false;
607  }
608  return false;
609 }
610 
611 double QgsSimpleMarkerSymbolLayerBase::calculateSize( QgsSymbolV2RenderContext &context, bool &hasDataDefinedSize ) const
612 {
613  double scaledSize = mSize;
614 
616  bool ok = true;
618  {
619  context.setOriginalValueVariable( mSize );
621  }
622 
623  if ( hasDataDefinedSize && ok )
624  {
625  switch ( mScaleMethod )
626  {
628  scaledSize = sqrt( scaledSize );
629  break;
631  break;
632  }
633  }
634 
635  return scaledSize;
636 }
637 
638 void QgsSimpleMarkerSymbolLayerBase::calculateOffsetAndRotation( QgsSymbolV2RenderContext &context, double scaledSize, bool &hasDataDefinedRotation, QPointF &offset, double &angle ) const
639 {
640  //offset
641  double offsetX = 0;
642  double offsetY = 0;
643  markerOffset( context, scaledSize, scaledSize, offsetX, offsetY );
644  offset = QPointF( offsetX, offsetY );
645 
646  //angle
647  bool ok = true;
648  angle = mAngle + mLineAngle;
649  bool usingDataDefinedRotation = false;
651  {
652  context.setOriginalValueVariable( angle );
654  usingDataDefinedRotation = ok;
655  }
656 
657  hasDataDefinedRotation = context.renderHints() & QgsSymbolV2::DataDefinedRotation || usingDataDefinedRotation;
658  if ( hasDataDefinedRotation )
659  {
660  // For non-point markers, "dataDefinedRotation" means following the
661  // shape (shape-data defined). For them, "field-data defined" does
662  // not work at all. TODO: if "field-data defined" ever gets implemented
663  // we'll need a way to distinguish here between the two, possibly
664  // using another flag in renderHints()
665  const QgsFeature* f = context.feature();
666  if ( f )
667  {
668  const QgsGeometry *g = f->constGeometry();
669  if ( g && g->type() == QGis::Point )
670  {
671  const QgsMapToPixel& m2p = context.renderContext().mapToPixel();
672  angle += m2p.mapRotation();
673  }
674  }
675  }
676 
677  if ( angle )
678  offset = _rotatedOffset( offset, angle );
679 }
680 
681 
682 //
683 // QgsSimpleMarkerSymbolLayerV2
684 //
685 
687  Qt::PenJoinStyle penJoinStyle )
688  : QgsSimpleMarkerSymbolLayerBase( decodeShape( name ), size, angle, scaleMethod )
689  , mBorderColor( borderColor )
690  , mOutlineStyle( Qt::SolidLine )
691  , mOutlineWidth( 0 )
692  , mOutlineWidthUnit( QgsSymbolV2::MM )
693  , mPenJoinStyle( penJoinStyle )
694  , mName( name )
695  , mUsingCache( false )
696 {
697  mColor = color;
698 }
699 
701  : QgsSimpleMarkerSymbolLayerBase( shape, size, angle, scaleMethod )
702  , mBorderColor( borderColor )
703  , mOutlineStyle( Qt::SolidLine )
704  , mOutlineWidth( 0 )
706  , mPenJoinStyle( penJoinStyle )
707  , mName( encodeShape( shape ) )
708  , mUsingCache( false )
709 {
710  mColor = color;
711 }
712 
714 {
715  Shape shape = Circle;
718  Qt::PenJoinStyle penJoinStyle = DEFAULT_SIMPLEMARKER_JOINSTYLE;
722 
723  if ( props.contains( "name" ) )
724  {
725  shape = decodeShape( props["name"] );
726  }
727  if ( props.contains( "color" ) )
728  color = QgsSymbolLayerV2Utils::decodeColor( props["color"] );
729  if ( props.contains( "color_border" ) )
730  {
731  //pre 2.5 projects use "color_border"
732  borderColor = QgsSymbolLayerV2Utils::decodeColor( props["color_border"] );
733  }
734  else if ( props.contains( "outline_color" ) )
735  {
736  borderColor = QgsSymbolLayerV2Utils::decodeColor( props["outline_color"] );
737  }
738  else if ( props.contains( "line_color" ) )
739  {
740  borderColor = QgsSymbolLayerV2Utils::decodeColor( props["line_color"] );
741  }
742  if ( props.contains( "joinstyle" ) )
743  {
744  penJoinStyle = QgsSymbolLayerV2Utils::decodePenJoinStyle( props["joinstyle"] );
745  }
746  if ( props.contains( "size" ) )
747  size = props["size"].toDouble();
748  if ( props.contains( "angle" ) )
749  angle = props["angle"].toDouble();
750  if ( props.contains( "scale_method" ) )
751  scaleMethod = QgsSymbolLayerV2Utils::decodeScaleMethod( props["scale_method"] );
752 
753  QgsSimpleMarkerSymbolLayerV2* m = new QgsSimpleMarkerSymbolLayerV2( shape, size, angle, scaleMethod, color, borderColor, penJoinStyle );
754  if ( props.contains( "offset" ) )
755  m->setOffset( QgsSymbolLayerV2Utils::decodePoint( props["offset"] ) );
756  if ( props.contains( "offset_unit" ) )
757  m->setOffsetUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["offset_unit"] ) );
758  if ( props.contains( "offset_map_unit_scale" ) )
759  m->setOffsetMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["offset_map_unit_scale"] ) );
760  if ( props.contains( "size_unit" ) )
761  m->setSizeUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["size_unit"] ) );
762  if ( props.contains( "size_map_unit_scale" ) )
763  m->setSizeMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["size_map_unit_scale"] ) );
764 
765  if ( props.contains( "outline_style" ) )
766  {
767  m->setOutlineStyle( QgsSymbolLayerV2Utils::decodePenStyle( props["outline_style"] ) );
768  }
769  else if ( props.contains( "line_style" ) )
770  {
771  m->setOutlineStyle( QgsSymbolLayerV2Utils::decodePenStyle( props["line_style"] ) );
772  }
773  if ( props.contains( "outline_width" ) )
774  {
775  m->setOutlineWidth( props["outline_width"].toDouble() );
776  }
777  else if ( props.contains( "line_width" ) )
778  {
779  m->setOutlineWidth( props["line_width"].toDouble() );
780  }
781  if ( props.contains( "outline_width_unit" ) )
782  {
783  m->setOutlineWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["outline_width_unit"] ) );
784  }
785  if ( props.contains( "line_width_unit" ) )
786  {
787  m->setOutlineWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["line_width_unit"] ) );
788  }
789  if ( props.contains( "outline_width_map_unit_scale" ) )
790  {
791  m->setOutlineWidthMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["outline_width_map_unit_scale"] ) );
792  }
793 
794  if ( props.contains( "horizontal_anchor_point" ) )
795  {
796  m->setHorizontalAnchorPoint( QgsMarkerSymbolLayerV2::HorizontalAnchorPoint( props[ "horizontal_anchor_point" ].toInt() ) );
797  }
798  if ( props.contains( "vertical_anchor_point" ) )
799  {
800  m->setVerticalAnchorPoint( QgsMarkerSymbolLayerV2::VerticalAnchorPoint( props[ "vertical_anchor_point" ].toInt() ) );
801  }
802 
803  m->restoreDataDefinedProperties( props );
804 
805  return m;
806 }
807 
808 
810 {
811  return "SimpleMarker";
812 }
813 
815 {
817 
818  QColor brushColor = mColor;
819  QColor penColor = mBorderColor;
820 
821  brushColor.setAlphaF( mColor.alphaF() * context.alpha() );
822  penColor.setAlphaF( mBorderColor.alphaF() * context.alpha() );
823 
824  mBrush = QBrush( brushColor );
825  mPen = QPen( penColor );
829 
830  QColor selBrushColor = context.renderContext().selectionColor();
831  QColor selPenColor = selBrushColor == mColor ? selBrushColor : mBorderColor;
832  if ( context.alpha() < 1 )
833  {
834  selBrushColor.setAlphaF( context.alpha() );
835  selPenColor.setAlphaF( context.alpha() );
836  }
837  mSelBrush = QBrush( selBrushColor );
838  mSelPen = QPen( selPenColor );
841 
844 
845  // use caching only when:
846  // - size, rotation, shape, color, border color is not data-defined
847  // - drawing to screen (not printer)
848  mUsingCache = !hasDataDefinedRotation && !hasDataDefinedSize && !context.renderContext().forceVectorOutput()
852 
853  if ( !shapeIsFilled( mShape ) )
854  {
855  // some markers can't be drawn as a polygon (circle, cross)
856  // For these set the selected border color to the selected color
857  mSelPen.setColor( selBrushColor );
858  }
859 
860 
861  if ( mUsingCache )
862  {
863  if ( !qgsDoubleNear( context.renderContext().rasterScaleFactor(), 1.0 ) )
864  {
865  QTransform transform;
866  transform.scale( context.renderContext().rasterScaleFactor(), context.renderContext().rasterScaleFactor() );
867  if ( !mPolygon.isEmpty() )
868  mPolygon = transform.map( mPolygon );
869  else
870  mPath = transform.map( mPath );
871  }
872 
873  if ( !prepareCache( context ) )
874  {
875  mUsingCache = false;
876  }
877  }
878  else
879  {
880  mCache = QImage();
881  mSelCache = QImage();
882  }
883 }
884 
885 
887 {
889 
890  // calculate necessary image size for the cache
891  double pw = qRound((( qgsDoubleNear( mPen.widthF(), 0.0 ) ? 1 : mPen.widthF() * 4 ) + 1 ) ) / 2 * 2; // make even (round up); handle cosmetic pen
892  int imageSize = ( static_cast< int >( scaledSize ) + pw ) / 2 * 2 + 1; // make image width, height odd; account for pen width
893  double center = imageSize / 2.0;
894 
895  if ( imageSize > mMaximumCacheWidth )
896  {
897  return false;
898  }
899 
900  mCache = QImage( QSize( imageSize, imageSize ), QImage::Format_ARGB32_Premultiplied );
901  mCache.fill( 0 );
902 
903  bool needsBrush = shapeIsFilled( mShape );
904 
905  QPainter p;
906  p.begin( &mCache );
907  p.setRenderHint( QPainter::Antialiasing );
908  p.setBrush( needsBrush ? mBrush : Qt::NoBrush );
909  p.setPen( mPen );
910  p.translate( QPointF( center, center ) );
911  drawMarker( &p, context );
912  p.end();
913 
914  // Construct the selected version of the Cache
915 
916  QColor selColor = context.renderContext().selectionColor();
917 
918  mSelCache = QImage( QSize( imageSize, imageSize ), QImage::Format_ARGB32_Premultiplied );
919  mSelCache.fill( 0 );
920 
921  p.begin( &mSelCache );
922  p.setRenderHint( QPainter::Antialiasing );
923  p.setBrush( needsBrush ? mSelBrush : Qt::NoBrush );
924  p.setPen( mSelPen );
925  p.translate( QPointF( center, center ) );
926  drawMarker( &p, context );
927  p.end();
928 
929  // Check that the selected version is different. If not, then re-render,
930  // filling the background with the selection color and using the normal
931  // colors for the symbol .. could be ugly!
932 
933  if ( mSelCache == mCache )
934  {
935  p.begin( &mSelCache );
936  p.setRenderHint( QPainter::Antialiasing );
937  p.fillRect( 0, 0, imageSize, imageSize, selColor );
938  p.setBrush( needsBrush ? mBrush : Qt::NoBrush );
939  p.setPen( mPen );
940  p.translate( QPointF( center, center ) );
941  drawMarker( &p, context );
942  p.end();
943  }
944 
945  return true;
946 }
947 
949 {
950  return shapeToPolygon( name.isNull() ? mShape : decodeShape( name ), mPolygon );
951 }
952 
954 {
955  return shapeToPolygon( decodeShape( name ), polygon );
956 }
957 
959 {
960  return prepareMarkerPath( decodeShape( name ) );
961 }
962 
963 void QgsSimpleMarkerSymbolLayerV2::draw( QgsSymbolV2RenderContext &context, QgsSimpleMarkerSymbolLayerBase::Shape shape, const QPolygonF &polygon, const QPainterPath &path )
964 {
965  //making changes here? Don't forget to also update ::bounds if the changes affect the bounding box
966  //of the rendered point!
967 
968  QPainter *p = context.renderContext().painter();
969  if ( !p )
970  {
971  return;
972  }
973 
974  bool ok = true;
976  {
979  if ( ok )
981  }
983  {
986  if ( ok )
987  {
990  }
991  }
993  {
996  if ( ok )
997  {
1000  }
1001  }
1003  {
1006  if ( ok )
1007  {
1010  }
1011  }
1013  {
1016  if ( ok )
1017  {
1020  }
1021  }
1022 
1023  if ( shapeIsFilled( shape ) )
1024  {
1025  p->setBrush( context.selected() ? mSelBrush : mBrush );
1026  }
1027  else
1028  {
1029  p->setBrush( Qt::NoBrush );
1030  }
1031  p->setPen( context.selected() ? mSelPen : mPen );
1032 
1033  if ( !polygon.isEmpty() )
1034  p->drawPolygon( polygon );
1035  else
1036  p->drawPath( path );
1037 }
1038 
1040 {
1041  //making changes here? Don't forget to also update ::bounds if the changes affect the bounding box
1042  //of the rendered point!
1043 
1044  QPainter *p = context.renderContext().painter();
1045  if ( !p )
1046  {
1047  return;
1048  }
1049 
1050  if ( mUsingCache )
1051  {
1052  QImage &img = context.selected() ? mSelCache : mCache;
1053  double s = img.width() / context.renderContext().rasterScaleFactor();
1054 
1055  bool hasDataDefinedSize = false;
1056  double scaledSize = calculateSize( context, hasDataDefinedSize );
1057 
1058  bool hasDataDefinedRotation = false;
1059  QPointF offset;
1060  double angle = 0;
1061  calculateOffsetAndRotation( context, scaledSize, hasDataDefinedRotation, offset, angle );
1062 
1063  p->drawImage( QRectF( point.x() - s / 2.0 + offset.x(),
1064  point.y() - s / 2.0 + offset.y(),
1065  s, s ), img );
1066  }
1067  else
1068  {
1070  }
1071 }
1072 
1074 {
1075  QgsStringMap map;
1076  map["name"] = encodeShape( mShape );
1077  map["color"] = QgsSymbolLayerV2Utils::encodeColor( mColor );
1078  map["outline_color"] = QgsSymbolLayerV2Utils::encodeColor( mBorderColor );
1079  map["size"] = QString::number( mSize );
1080  map["size_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mSizeUnit );
1081  map["size_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mSizeMapUnitScale );
1082  map["angle"] = QString::number( mAngle );
1083  map["offset"] = QgsSymbolLayerV2Utils::encodePoint( mOffset );
1084  map["offset_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOffsetUnit );
1085  map["offset_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOffsetMapUnitScale );
1086  map["scale_method"] = QgsSymbolLayerV2Utils::encodeScaleMethod( mScaleMethod );
1087  map["outline_style"] = QgsSymbolLayerV2Utils::encodePenStyle( mOutlineStyle );
1088  map["outline_width"] = QString::number( mOutlineWidth );
1089  map["outline_width_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOutlineWidthUnit );
1090  map["outline_width_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOutlineWidthMapUnitScale );
1092  map["horizontal_anchor_point"] = QString::number( mHorizontalAnchorPoint );
1093  map["vertical_anchor_point"] = QString::number( mVerticalAnchorPoint );
1094 
1095 
1096  //data define properties
1098  return map;
1099 }
1100 
1102 {
1104  m->setOffset( mOffset );
1105  m->setSizeUnit( mSizeUnit );
1107  m->setOffsetUnit( mOffsetUnit );
1116  copyPaintEffect( m );
1117  return m;
1118 }
1119 
1121 {
1122  // <Graphic>
1123  QDomElement graphicElem = doc.createElement( "se:Graphic" );
1124  element.appendChild( graphicElem );
1125 
1127 
1128  // <Rotation>
1129  QString angleFunc;
1130  bool ok;
1131  double angle = props.value( "angle", "0" ).toDouble( &ok );
1132  if ( !ok )
1133  {
1134  angleFunc = QString( "%1 + %2" ).arg( props.value( "angle", "0" ) ).arg( mAngle );
1135  }
1136  else if ( !qgsDoubleNear( angle + mAngle, 0.0 ) )
1137  {
1138  angleFunc = QString::number( angle + mAngle );
1139  }
1140  QgsSymbolLayerV2Utils::createRotationElement( doc, graphicElem, angleFunc );
1141 
1142  // <Displacement>
1144 }
1145 
1146 QString QgsSimpleMarkerSymbolLayerV2::ogrFeatureStyle( double mmScaleFactor, double mapUnitScaleFactor ) const
1147 {
1148  Q_UNUSED( mmScaleFactor );
1149  Q_UNUSED( mapUnitScaleFactor );
1150 #if 0
1151  QString ogrType = "3"; //default is circle
1152  if ( mName == "square" )
1153  {
1154  ogrType = "5";
1155  }
1156  else if ( mName == "triangle" )
1157  {
1158  ogrType = "7";
1159  }
1160  else if ( mName == "star" )
1161  {
1162  ogrType = "9";
1163  }
1164  else if ( mName == "circle" )
1165  {
1166  ogrType = "3";
1167  }
1168  else if ( mName == "cross" )
1169  {
1170  ogrType = "0";
1171  }
1172  else if ( mName == "x" || mName == "cross2" )
1173  {
1174  ogrType = "1";
1175  }
1176  else if ( mName == "line" )
1177  {
1178  ogrType = "10";
1179  }
1180 
1181  QString ogrString;
1182  ogrString.append( "SYMBOL(" );
1183  ogrString.append( "id:" );
1184  ogrString.append( '\"' );
1185  ogrString.append( "ogr-sym-" );
1186  ogrString.append( ogrType );
1187  ogrString.append( '\"' );
1188  ogrString.append( ",c:" );
1189  ogrString.append( mColor.name() );
1190  ogrString.append( ",o:" );
1191  ogrString.append( mBorderColor.name() );
1192  ogrString.append( QString( ",s:%1mm" ).arg( mSize ) );
1193  ogrString.append( ')' );
1194  return ogrString;
1195 #endif //0
1196 
1197  QString ogrString;
1198  ogrString.append( "PEN(" );
1199  ogrString.append( "c:" );
1200  ogrString.append( mColor.name() );
1201  ogrString.append( ",w:" );
1202  ogrString.append( QString::number( mSize ) );
1203  ogrString.append( "mm" );
1204  ogrString.append( ")" );
1205  return ogrString;
1206 }
1207 
1209 {
1210  QgsDebugMsg( "Entered." );
1211 
1212  QDomElement graphicElem = element.firstChildElement( "Graphic" );
1213  if ( graphicElem.isNull() )
1214  return nullptr;
1215 
1216  QString name = "square";
1218  double borderWidth, size;
1219  Qt::PenStyle borderStyle;
1220 
1221  if ( !QgsSymbolLayerV2Utils::wellKnownMarkerFromSld( graphicElem, name, color, borderColor, borderStyle, borderWidth, size ) )
1222  return nullptr;
1223 
1224  double angle = 0.0;
1225  QString angleFunc;
1226  if ( QgsSymbolLayerV2Utils::rotationFromSldElement( graphicElem, angleFunc ) )
1227  {
1228  bool ok;
1229  double d = angleFunc.toDouble( &ok );
1230  if ( ok )
1231  angle = d;
1232  }
1233 
1234  QPointF offset;
1236 
1237  Shape shape = decodeShape( name );
1238 
1240  m->setColor( color );
1241  m->setBorderColor( borderColor );
1242  m->setAngle( angle );
1243  m->setOffset( offset );
1244  m->setOutlineStyle( borderStyle );
1245  return m;
1246 }
1247 
1249 {
1250  Q_UNUSED( context );
1251 
1252  if ( mPolygon.count() != 0 )
1253  {
1254  p->drawPolygon( mPolygon );
1255  }
1256  else
1257  {
1258  p->drawPath( mPath );
1259  }
1260 }
1261 
1262 bool QgsSimpleMarkerSymbolLayerV2::writeDxf( QgsDxfExport& e, double mmMapUnitScaleFactor, const QString& layerName, QgsSymbolV2RenderContext &context, QPointF shift ) const
1263 {
1264  //data defined size?
1265  double size = mSize;
1266 
1268 
1269  //data defined size
1270  bool ok = true;
1271  if ( hasDataDefinedSize )
1272  {
1274  {
1275  context.setOriginalValueVariable( mSize );
1277  }
1278 
1279  if ( ok )
1280  {
1281  switch ( mScaleMethod )
1282  {
1284  size = sqrt( size );
1285  break;
1287  break;
1288  }
1289  }
1290 
1292  }
1293  if ( mSizeUnit == QgsSymbolV2::MM )
1294  {
1295  size *= mmMapUnitScaleFactor;
1296  }
1297  double halfSize = size / 2.0;
1298 
1299  //outlineWidth
1300  double outlineWidth = mOutlineWidth;
1301 
1303  {
1306  }
1307  if ( mSizeUnit == QgsSymbolV2::MM )
1308  {
1309  outlineWidth *= mmMapUnitScaleFactor;
1310  }
1311 
1312  //color
1313  QColor pc = mPen.color();
1314  QColor bc = mBrush.color();
1316  {
1319  if ( ok )
1320  bc = QgsSymbolLayerV2Utils::decodeColor( colorString );
1321  }
1323  {
1326  if ( ok )
1327  pc = QgsSymbolLayerV2Utils::decodeColor( colorString );
1328  }
1329 
1330  //offset
1331  double offsetX = 0;
1332  double offsetY = 0;
1333  markerOffset( context, offsetX, offsetY );
1334 
1335  QPointF off( offsetX, offsetY );
1336 
1337  //angle
1338  double angle = mAngle + mLineAngle;
1340  {
1341  context.setOriginalValueVariable( mAngle );
1343  }
1344 
1345  Shape shape = mShape;
1347  {
1348  context.setOriginalValueVariable( encodeShape( shape ) );
1350  if ( ok )
1351  {
1352  shape = decodeShape( shapeName, &ok );
1353  if ( !ok )
1354  shape = mShape;
1355  }
1356  }
1357 
1358  angle = -angle; //rotation in Qt is counterclockwise
1359  if ( angle )
1360  off = _rotatedOffset( off, angle );
1361 
1362  if ( mSizeUnit == QgsSymbolV2::MM )
1363  {
1364  off *= mmMapUnitScaleFactor;
1365  }
1366 
1367  QTransform t;
1368  t.translate( shift.x() + offsetX, shift.y() + offsetY );
1369 
1370  if ( !qgsDoubleNear( angle, 0.0 ) )
1371  t.rotate( angle );
1372 
1373  QPolygonF polygon;
1374  if ( shapeToPolygon( shape, polygon ) )
1375  {
1376  t.scale( halfSize, -halfSize );
1377 
1378  polygon = t.map( polygon );
1379 
1381  for ( int i = 0; i < polygon.size(); i++ )
1382  p << QgsPointV2( polygon[i] );
1383  p << p[0];
1384 
1385  if ( mBrush.style() != Qt::NoBrush )
1386  e.writePolygon( QgsRingSequenceV2() << p, layerName, "SOLID", bc );
1387  if ( mPen.style() != Qt::NoPen )
1388  e.writePolyline( p, layerName, "CONTINUOUS", pc, outlineWidth );
1389  }
1390  else if ( shape == Circle )
1391  {
1392  if ( mBrush.style() != Qt::NoBrush )
1393  e.writeFilledCircle( layerName, bc, QgsPointV2( shift ), halfSize );
1394  if ( mPen.style() != Qt::NoPen )
1395  e.writeCircle( layerName, pc, QgsPointV2( shift ), halfSize, "CONTINUOUS", outlineWidth );
1396  }
1397  else if ( shape == Line )
1398  {
1399  QPointF pt1 = t.map( QPointF( 0, -halfSize ) );
1400  QPointF pt2 = t.map( QPointF( 0, halfSize ) );
1401 
1402  if ( mPen.style() != Qt::NoPen )
1403  e.writeLine( QgsPointV2( pt1 ), QgsPointV2( pt2 ), layerName, "CONTINUOUS", pc, outlineWidth );
1404  }
1405  else if ( shape == Cross )
1406  {
1407  if ( mPen.style() != Qt::NoPen )
1408  {
1409  QPointF pt1 = t.map( QPointF( -halfSize, 0 ) );
1410  QPointF pt2 = t.map( QPointF( halfSize, 0 ) );
1411  QPointF pt3 = t.map( QPointF( 0, -halfSize ) );
1412  QPointF pt4 = t.map( QPointF( 0, halfSize ) );
1413 
1414  e.writeLine( QgsPointV2( pt1 ), QgsPointV2( pt2 ), layerName, "CONTINUOUS", pc, outlineWidth );
1415  e.writeLine( QgsPointV2( pt3 ), QgsPointV2( pt4 ), layerName, "CONTINUOUS", pc, outlineWidth );
1416  }
1417  }
1418  else if ( shape == Cross2 )
1419  {
1420  if ( mPen.style() != Qt::NoPen )
1421  {
1422  QPointF pt1 = t.map( QPointF( -halfSize, -halfSize ) );
1423  QPointF pt2 = t.map( QPointF( halfSize, halfSize ) );
1424  QPointF pt3 = t.map( QPointF( halfSize, -halfSize ) );
1425  QPointF pt4 = t.map( QPointF( -halfSize, halfSize ) );
1426 
1427  e.writeLine( QgsPointV2( pt1 ), QgsPointV2( pt2 ), layerName, "CONTINUOUS", pc, outlineWidth );
1428  e.writeLine( QgsPointV2( pt3 ), QgsPointV2( pt4 ), layerName, "CONTINUOUS", pc, outlineWidth );
1429  }
1430  }
1431  else if ( shape == ArrowHead )
1432  {
1433  if ( mPen.style() != Qt::NoPen )
1434  {
1435  QPointF pt1 = t.map( QPointF( -halfSize, halfSize ) );
1436  QPointF pt2 = t.map( QPointF( 0, 0 ) );
1437  QPointF pt3 = t.map( QPointF( -halfSize, -halfSize ) );
1438 
1439  e.writeLine( QgsPointV2( pt1 ), QgsPointV2( pt2 ), layerName, "CONTINUOUS", pc, outlineWidth );
1440  e.writeLine( QgsPointV2( pt3 ), QgsPointV2( pt2 ), layerName, "CONTINUOUS", pc, outlineWidth );
1441  }
1442  }
1443  else
1444  {
1445  QgsDebugMsg( QString( "Unsupported dxf marker name %1" ).arg( encodeShape( shape ) ) );
1446  return false;
1447  }
1448 
1449  return true;
1450 }
1451 
1452 
1454 {
1456  mOutlineWidthUnit = unit;
1457 }
1458 
1460 {
1462  {
1463  return mOutlineWidthUnit;
1464  }
1465  return QgsSymbolV2::Mixed;
1466 }
1467 
1469 {
1471  mOutlineWidthMapUnitScale = scale;
1472 }
1473 
1475 {
1477  {
1479  }
1480  return QgsMapUnitScale();
1481 }
1482 
1484 {
1485  QRectF symbolBounds = QgsSimpleMarkerSymbolLayerBase::bounds( point, context );
1486 
1487  // need to account for outline width
1488  double pixelSize = 1.0 / context.renderContext().rasterScaleFactor();
1489  double penWidth = 0.0;
1490  bool ok = true;
1492  {
1495  if ( ok )
1496  {
1498  }
1499  }
1501  {
1504  if ( ok && outlineStyle == "no" )
1505  {
1506  penWidth = 0.0;
1507  }
1508  }
1509  //antialiasing
1510  penWidth += pixelSize;
1511 
1512  //extend bounds by pen width / 2.0
1513  symbolBounds.adjust( -penWidth / 2.0, -penWidth / 2.0,
1514  penWidth / 2.0, penWidth / 2.0 );
1515 
1516  return symbolBounds;
1517 }
1518 
1519 
1520 //
1521 // QgsFilledMarkerSymbolLayer
1522 //
1523 
1525  : QgsSimpleMarkerSymbolLayerBase( shape, size, angle, scaleMethod )
1526 {
1527  mFill.reset( static_cast<QgsFillSymbolV2*>( QgsFillSymbolV2::createSimple( QgsStringMap() ) ) );
1528 }
1529 
1531 {
1536 
1537  if ( props.contains( "name" ) )
1538  name = props["name"];
1539  if ( props.contains( "size" ) )
1540  size = props["size"].toDouble();
1541  if ( props.contains( "angle" ) )
1542  angle = props["angle"].toDouble();
1543  if ( props.contains( "scale_method" ) )
1544  scaleMethod = QgsSymbolLayerV2Utils::decodeScaleMethod( props["scale_method"] );
1545 
1546  QgsFilledMarkerSymbolLayer* m = new QgsFilledMarkerSymbolLayer( decodeShape( name ), size, angle, scaleMethod );
1547  if ( props.contains( "offset" ) )
1548  m->setOffset( QgsSymbolLayerV2Utils::decodePoint( props["offset"] ) );
1549  if ( props.contains( "offset_unit" ) )
1550  m->setOffsetUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["offset_unit"] ) );
1551  if ( props.contains( "offset_map_unit_scale" ) )
1552  m->setOffsetMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["offset_map_unit_scale"] ) );
1553  if ( props.contains( "size_unit" ) )
1554  m->setSizeUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["size_unit"] ) );
1555  if ( props.contains( "size_map_unit_scale" ) )
1556  m->setSizeMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["size_map_unit_scale"] ) );
1557  if ( props.contains( "horizontal_anchor_point" ) )
1558  {
1559  m->setHorizontalAnchorPoint( QgsMarkerSymbolLayerV2::HorizontalAnchorPoint( props[ "horizontal_anchor_point" ].toInt() ) );
1560  }
1561  if ( props.contains( "vertical_anchor_point" ) )
1562  {
1563  m->setVerticalAnchorPoint( QgsMarkerSymbolLayerV2::VerticalAnchorPoint( props[ "vertical_anchor_point" ].toInt() ) );
1564  }
1565 
1567 
1568  m->restoreDataDefinedProperties( props );
1569 
1570  return m;
1571 }
1572 
1574 {
1575  return "FilledMarker";
1576 }
1577 
1579 {
1580  if ( mFill.data() )
1581  {
1582  mFill->startRender( context.renderContext(), context.fields() );
1583  }
1584 
1586 }
1587 
1589 {
1590  if ( mFill.data() )
1591  {
1592  mFill->stopRender( context.renderContext() );
1593  }
1594 }
1595 
1597 {
1598  QgsStringMap map;
1599  map["name"] = encodeShape( mShape );
1600  map["size"] = QString::number( mSize );
1601  map["size_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mSizeUnit );
1602  map["size_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mSizeMapUnitScale );
1603  map["angle"] = QString::number( mAngle );
1604  map["offset"] = QgsSymbolLayerV2Utils::encodePoint( mOffset );
1605  map["offset_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOffsetUnit );
1606  map["offset_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOffsetMapUnitScale );
1607  map["scale_method"] = QgsSymbolLayerV2Utils::encodeScaleMethod( mScaleMethod );
1608  map["horizontal_anchor_point"] = QString::number( mHorizontalAnchorPoint );
1609  map["vertical_anchor_point"] = QString::number( mVerticalAnchorPoint );
1610 
1611  if ( mFill.data() )
1612  {
1613  map["color"] = QgsSymbolLayerV2Utils::encodeColor( mFill->color() );
1614  }
1615 
1616  //data define properties
1618  return map;
1619 }
1620 
1622 {
1624  copyPaintEffect( m );
1625  m->setSubSymbol( mFill->clone() );
1626  return m;
1627 }
1628 
1630 {
1631  return mFill.data();
1632 }
1633 
1635 {
1636  if ( symbol && symbol->type() == QgsSymbolV2::Fill )
1637  {
1638  mFill.reset( static_cast<QgsFillSymbolV2*>( symbol ) );
1639  return true;
1640  }
1641  else
1642  {
1643  delete symbol;
1644  return false;
1645  }
1646 }
1647 
1649 {
1650  if ( mFill.data() )
1651  {
1653  }
1654  return 0;
1655 }
1656 
1658 {
1660  if ( mFill.data() )
1661  attr.unite( mFill->usedAttributes() );
1662  return attr;
1663 }
1664 
1666 {
1667  mColor = c;
1668  if ( mFill.data() )
1669  mFill->setColor( c );
1670 }
1671 
1673 {
1674  return mFill.data() ? mFill->color() : mColor;
1675 }
1676 
1677 void QgsFilledMarkerSymbolLayer::draw( QgsSymbolV2RenderContext &context, QgsSimpleMarkerSymbolLayerBase::Shape shape, const QPolygonF &polygon, const QPainterPath &path )
1678 {
1679  //making changes here? Don't forget to also update ::bounds if the changes affect the bounding box
1680  //of the rendered point!
1681 
1682  QPainter *p = context.renderContext().painter();
1683  if ( !p )
1684  {
1685  return;
1686  }
1687 
1688  if ( shapeIsFilled( shape ) )
1689  {
1690  p->setBrush( Qt::red );
1691  }
1692  else
1693  {
1694  p->setBrush( Qt::NoBrush );
1695  }
1696  p->setPen( Qt::black );
1697 
1698  if ( !polygon.isEmpty() )
1699  {
1700  mFill->renderPolygon( polygon, /* rings */ nullptr, context.feature(), context.renderContext() );
1701  }
1702  else
1703  {
1704  QPolygonF poly = path.toFillPolygon();
1705  mFill->renderPolygon( poly, /* rings */ nullptr, context.feature(), context.renderContext() );
1706  }
1707 
1708 
1709 }
1710 
1711 
1713 
1714 
1716 {
1718  mSize = size;
1719  mAngle = angle;
1720  mOffset = QPointF( 0, 0 );
1722  mOutlineWidth = 0.2;
1723  mOutlineWidthUnit = QgsSymbolV2::MM;
1724  mColor = QColor( Qt::black );
1725  mOutlineColor = QColor( Qt::black );
1726 }
1727 
1728 
1730 {
1732  double size = DEFAULT_SVGMARKER_SIZE;
1733  double angle = DEFAULT_SVGMARKER_ANGLE;
1735 
1736  if ( props.contains( "name" ) )
1737  name = props["name"];
1738  if ( props.contains( "size" ) )
1739  size = props["size"].toDouble();
1740  if ( props.contains( "angle" ) )
1741  angle = props["angle"].toDouble();
1742  if ( props.contains( "scale_method" ) )
1743  scaleMethod = QgsSymbolLayerV2Utils::decodeScaleMethod( props["scale_method"] );
1744 
1745  QgsSvgMarkerSymbolLayerV2* m = new QgsSvgMarkerSymbolLayerV2( name, size, angle, scaleMethod );
1746 
1747  //we only check the svg default parameters if necessary, since it could be expensive
1748  if ( !props.contains( "fill" ) && !props.contains( "color" ) && !props.contains( "outline" ) &&
1749  !props.contains( "outline_color" ) && !props.contains( "outline-width" ) && !props.contains( "outline_width" ) )
1750  {
1752  double fillOpacity = 1.0;
1753  double outlineOpacity = 1.0;
1754  double outlineWidth;
1755  bool hasFillParam = false, hasFillOpacityParam = false, hasOutlineParam = false, hasOutlineWidthParam = false, hasOutlineOpacityParam = false;
1756  bool hasDefaultFillColor = false, hasDefaultFillOpacity = false, hasDefaultOutlineColor = false, hasDefaultOutlineWidth = false, hasDefaultOutlineOpacity = false;
1757  QgsSvgCache::instance()->containsParams( name, hasFillParam, hasDefaultFillColor, fillColor,
1758  hasFillOpacityParam, hasDefaultFillOpacity, fillOpacity,
1759  hasOutlineParam, hasDefaultOutlineColor, outlineColor,
1760  hasOutlineWidthParam, hasDefaultOutlineWidth, outlineWidth,
1761  hasOutlineOpacityParam, hasDefaultOutlineOpacity, outlineOpacity );
1762  if ( hasDefaultFillColor )
1763  {
1764  m->setFillColor( fillColor );
1765  }
1766  if ( hasDefaultFillOpacity )
1767  {
1768  QColor c = m->fillColor();
1769  c.setAlphaF( fillOpacity );
1770  m->setFillColor( c );
1771  }
1772  if ( hasDefaultOutlineColor )
1773  {
1774  m->setOutlineColor( outlineColor );
1775  }
1776  if ( hasDefaultOutlineWidth )
1777  {
1778  m->setOutlineWidth( outlineWidth );
1779  }
1780  if ( hasDefaultOutlineOpacity )
1781  {
1782  QColor c = m->outlineColor();
1783  c.setAlphaF( outlineOpacity );
1784  m->setOutlineColor( c );
1785  }
1786  }
1787 
1788  if ( props.contains( "size_unit" ) )
1789  m->setSizeUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["size_unit"] ) );
1790  if ( props.contains( "size_map_unit_scale" ) )
1791  m->setSizeMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["size_map_unit_scale"] ) );
1792  if ( props.contains( "offset" ) )
1793  m->setOffset( QgsSymbolLayerV2Utils::decodePoint( props["offset"] ) );
1794  if ( props.contains( "offset_unit" ) )
1795  m->setOffsetUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["offset_unit"] ) );
1796  if ( props.contains( "offset_map_unit_scale" ) )
1797  m->setOffsetMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["offset_map_unit_scale"] ) );
1798  if ( props.contains( "fill" ) )
1799  {
1800  //pre 2.5 projects used "fill"
1801  m->setFillColor( QgsSymbolLayerV2Utils::decodeColor( props["fill"] ) );
1802  }
1803  else if ( props.contains( "color" ) )
1804  {
1805  m->setFillColor( QgsSymbolLayerV2Utils::decodeColor( props["color"] ) );
1806  }
1807  if ( props.contains( "outline" ) )
1808  {
1809  //pre 2.5 projects used "outline"
1810  m->setOutlineColor( QgsSymbolLayerV2Utils::decodeColor( props["outline"] ) );
1811  }
1812  else if ( props.contains( "outline_color" ) )
1813  {
1814  m->setOutlineColor( QgsSymbolLayerV2Utils::decodeColor( props["outline_color"] ) );
1815  }
1816  else if ( props.contains( "line_color" ) )
1817  {
1818  m->setOutlineColor( QgsSymbolLayerV2Utils::decodeColor( props["line_color"] ) );
1819  }
1820 
1821  if ( props.contains( "outline-width" ) )
1822  {
1823  //pre 2.5 projects used "outline-width"
1824  m->setOutlineWidth( props["outline-width"].toDouble() );
1825  }
1826  else if ( props.contains( "outline_width" ) )
1827  {
1828  m->setOutlineWidth( props["outline_width"].toDouble() );
1829  }
1830  else if ( props.contains( "line_width" ) )
1831  {
1832  m->setOutlineWidth( props["line_width"].toDouble() );
1833  }
1834 
1835  if ( props.contains( "outline_width_unit" ) )
1836  {
1837  m->setOutlineWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["outline_width_unit"] ) );
1838  }
1839  else if ( props.contains( "line_width_unit" ) )
1840  {
1841  m->setOutlineWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["line_width_unit"] ) );
1842  }
1843  if ( props.contains( "outline_width_map_unit_scale" ) )
1844  m->setOutlineWidthMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["outline_width_map_unit_scale"] ) );
1845 
1846  if ( props.contains( "horizontal_anchor_point" ) )
1847  {
1848  m->setHorizontalAnchorPoint( QgsMarkerSymbolLayerV2::HorizontalAnchorPoint( props[ "horizontal_anchor_point" ].toInt() ) );
1849  }
1850  if ( props.contains( "vertical_anchor_point" ) )
1851  {
1852  m->setVerticalAnchorPoint( QgsMarkerSymbolLayerV2::VerticalAnchorPoint( props[ "vertical_anchor_point" ].toInt() ) );
1853  }
1854 
1855  m->restoreDataDefinedProperties( props );
1856 
1857  return m;
1858 }
1859 
1861 {
1862  mPath = path;
1863  QColor defaultFillColor, defaultOutlineColor;
1864  double outlineWidth, fillOpacity, outlineOpacity;
1865  bool hasFillParam = false, hasFillOpacityParam = false, hasOutlineParam = false, hasOutlineWidthParam = false, hasOutlineOpacityParam = false;
1866  bool hasDefaultFillColor = false, hasDefaultFillOpacity = false, hasDefaultOutlineColor = false, hasDefaultOutlineWidth = false, hasDefaultOutlineOpacity = false;
1867  QgsSvgCache::instance()->containsParams( path, hasFillParam, hasDefaultFillColor, defaultFillColor,
1868  hasFillOpacityParam, hasDefaultFillOpacity, fillOpacity,
1869  hasOutlineParam, hasDefaultOutlineColor, defaultOutlineColor,
1870  hasOutlineWidthParam, hasDefaultOutlineWidth, outlineWidth,
1871  hasOutlineOpacityParam, hasDefaultOutlineOpacity, outlineOpacity );
1872 
1873  double newFillOpacity = hasFillOpacityParam ? fillColor().alphaF() : 1.0;
1874  double newOutlineOpacity = hasOutlineOpacityParam ? outlineColor().alphaF() : 1.0;
1875 
1876  if ( hasDefaultFillColor )
1877  {
1878  defaultFillColor.setAlphaF( newFillOpacity );
1879  setFillColor( defaultFillColor );
1880  }
1881  if ( hasDefaultFillOpacity )
1882  {
1883  QColor c = fillColor();
1884  c.setAlphaF( fillOpacity );
1885  setFillColor( c );
1886  }
1887  if ( hasDefaultOutlineColor )
1888  {
1889  defaultOutlineColor.setAlphaF( newOutlineOpacity );
1890  setOutlineColor( defaultOutlineColor );
1891  }
1892  if ( hasDefaultOutlineWidth )
1893  {
1894  setOutlineWidth( outlineWidth );
1895  }
1896  if ( hasDefaultOutlineOpacity )
1897  {
1898  QColor c = outlineColor();
1899  c.setAlphaF( outlineOpacity );
1900  setOutlineColor( c );
1901  }
1902 }
1903 
1904 
1906 {
1907  return "SvgMarker";
1908 }
1909 
1911 {
1912  QgsMarkerSymbolLayerV2::startRender( context ); // get anchor point expressions
1913  Q_UNUSED( context );
1914  prepareExpressions( context );
1915 }
1916 
1918 {
1919  Q_UNUSED( context );
1920 }
1921 
1923 {
1924  QPainter *p = context.renderContext().painter();
1925  if ( !p )
1926  return;
1927 
1928  bool hasDataDefinedSize = false;
1929  double scaledSize = calculateSize( context, hasDataDefinedSize );
1931 
1932  //don't render symbols with size below one or above 10,000 pixels
1933  if ( static_cast< int >( size ) < 1 || 10000.0 < size )
1934  {
1935  return;
1936  }
1937 
1938  p->save();
1939 
1940  QPointF outputOffset;
1941  double angle = 0.0;
1942  calculateOffsetAndRotation( context, scaledSize, outputOffset, angle );
1943 
1944  p->translate( point + outputOffset );
1945 
1946  bool rotated = !qgsDoubleNear( angle, 0 );
1947  if ( rotated )
1948  p->rotate( angle );
1949 
1950  QString path = mPath;
1952  {
1953  context.setOriginalValueVariable( mPath );
1955  }
1956 
1957  double outlineWidth = mOutlineWidth;
1959  {
1960  context.setOriginalValueVariable( mOutlineWidth );
1961  outlineWidth = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_OUTLINE_WIDTH, context, mOutlineWidth ).toDouble();
1962  }
1963  outlineWidth = QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), outlineWidth, mOutlineWidthUnit, mOutlineWidthMapUnitScale );
1964 
1966  bool ok = false;
1968  {
1971  if ( ok )
1972  fillColor = QgsSymbolLayerV2Utils::decodeColor( colorString );
1973  }
1974 
1975  QColor outlineColor = mOutlineColor;
1977  {
1980  if ( ok )
1981  outlineColor = QgsSymbolLayerV2Utils::decodeColor( colorString );
1982  }
1983 
1984  bool fitsInCache = true;
1985  bool usePict = true;
1986  double hwRatio = 1.0;
1987  if ( !context.renderContext().forceVectorOutput() && !rotated )
1988  {
1989  usePict = false;
1990  const QImage& img = QgsSvgCache::instance()->svgAsImage( path, size, fillColor, outlineColor, outlineWidth,
1991  context.renderContext().scaleFactor(), context.renderContext().rasterScaleFactor(), fitsInCache );
1992  if ( fitsInCache && img.width() > 1 )
1993  {
1994  //consider transparency
1995  if ( !qgsDoubleNear( context.alpha(), 1.0 ) )
1996  {
1997  QImage transparentImage = img.copy();
1998  QgsSymbolLayerV2Utils::multiplyImageOpacity( &transparentImage, context.alpha() );
1999  p->drawImage( -transparentImage.width() / 2.0, -transparentImage.height() / 2.0, transparentImage );
2000  hwRatio = static_cast< double >( transparentImage.height() ) / static_cast< double >( transparentImage.width() );
2001  }
2002  else
2003  {
2004  p->drawImage( -img.width() / 2.0, -img.height() / 2.0, img );
2005  hwRatio = static_cast< double >( img.height() ) / static_cast< double >( img.width() );
2006  }
2007  }
2008  }
2009 
2010  if ( usePict || !fitsInCache )
2011  {
2012  p->setOpacity( context.alpha() );
2013  const QPicture& pct = QgsSvgCache::instance()->svgAsPicture( path, size, fillColor, outlineColor, outlineWidth,
2015 
2016  if ( pct.width() > 1 )
2017  {
2018  p->save();
2019  _fixQPictureDPI( p );
2020  p->drawPicture( 0, 0, pct );
2021  p->restore();
2022  hwRatio = static_cast< double >( pct.height() ) / static_cast< double >( pct.width() );
2023  }
2024  }
2025 
2026  if ( context.selected() )
2027  {
2028  QPen pen( context.renderContext().selectionColor() );
2030  if ( penWidth > size / 20 )
2031  {
2032  // keep the pen width from covering symbol
2033  penWidth = size / 20;
2034  }
2035  double penOffset = penWidth / 2;
2036  pen.setWidth( penWidth );
2037  p->setPen( pen );
2038  p->setBrush( Qt::NoBrush );
2039  double wSize = size + penOffset;
2040  double hSize = size * hwRatio + penOffset;
2041  p->drawRect( QRectF( -wSize / 2.0, -hSize / 2.0, wSize, hSize ) );
2042  }
2043 
2044  p->restore();
2045 
2047  {
2048  // workaround issue with nested QPictures forgetting antialiasing flag - see http://hub.qgis.org/issues/14960
2049  p->setRenderHint( QPainter::Antialiasing );
2050  }
2051 
2052 }
2053 
2054 double QgsSvgMarkerSymbolLayerV2::calculateSize( QgsSymbolV2RenderContext& context, bool& hasDataDefinedSize ) const
2055 {
2056  double scaledSize = mSize;
2058 
2059  bool ok = true;
2061  {
2062  context.setOriginalValueVariable( mSize );
2063  scaledSize = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_SIZE, context, mSize, &ok ).toDouble();
2064  }
2065 
2066  if ( hasDataDefinedSize && ok )
2067  {
2068  switch ( mScaleMethod )
2069  {
2071  scaledSize = sqrt( scaledSize );
2072  break;
2074  break;
2075  }
2076  }
2077 
2078  return scaledSize;
2079 }
2080 
2081 void QgsSvgMarkerSymbolLayerV2::calculateOffsetAndRotation( QgsSymbolV2RenderContext& context, double scaledSize, QPointF& offset, double& angle ) const
2082 {
2083  //offset
2084  double offsetX = 0;
2085  double offsetY = 0;
2086  markerOffset( context, scaledSize, scaledSize, offsetX, offsetY );
2087  offset = QPointF( offsetX, offsetY );
2088 
2089  angle = mAngle + mLineAngle;
2091  {
2092  context.setOriginalValueVariable( mAngle );
2094  }
2095 
2097  if ( hasDataDefinedRotation )
2098  {
2099  // For non-point markers, "dataDefinedRotation" means following the
2100  // shape (shape-data defined). For them, "field-data defined" does
2101  // not work at all. TODO: if "field-data defined" ever gets implemented
2102  // we'll need a way to distinguish here between the two, possibly
2103  // using another flag in renderHints()
2104  const QgsFeature* f = context.feature();
2105  if ( f )
2106  {
2107  const QgsGeometry *g = f->constGeometry();
2108  if ( g && g->type() == QGis::Point )
2109  {
2110  const QgsMapToPixel& m2p = context.renderContext().mapToPixel();
2111  angle += m2p.mapRotation();
2112  }
2113  }
2114  }
2115 
2116  if ( angle )
2117  offset = _rotatedOffset( offset, angle );
2118 }
2119 
2120 
2122 {
2123  QgsStringMap map;
2125  map["size"] = QString::number( mSize );
2126  map["size_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mSizeUnit );
2127  map["size_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mSizeMapUnitScale );
2128  map["angle"] = QString::number( mAngle );
2129  map["offset"] = QgsSymbolLayerV2Utils::encodePoint( mOffset );
2130  map["offset_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOffsetUnit );
2131  map["offset_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOffsetMapUnitScale );
2132  map["scale_method"] = QgsSymbolLayerV2Utils::encodeScaleMethod( mScaleMethod );
2133  map["color"] = QgsSymbolLayerV2Utils::encodeColor( mColor );
2134  map["outline_color"] = QgsSymbolLayerV2Utils::encodeColor( mOutlineColor );
2135  map["outline_width"] = QString::number( mOutlineWidth );
2136  map["outline_width_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOutlineWidthUnit );
2137  map["outline_width_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOutlineWidthMapUnitScale );
2138  map["horizontal_anchor_point"] = QString::number( mHorizontalAnchorPoint );
2139  map["vertical_anchor_point"] = QString::number( mVerticalAnchorPoint );
2140 
2142  return map;
2143 }
2144 
2146 {
2148  m->setColor( mColor );
2149  m->setOutlineColor( mOutlineColor );
2150  m->setOutlineWidth( mOutlineWidth );
2151  m->setOutlineWidthUnit( mOutlineWidthUnit );
2152  m->setOutlineWidthMapUnitScale( mOutlineWidthMapUnitScale );
2153  m->setOffset( mOffset );
2154  m->setOffsetUnit( mOffsetUnit );
2156  m->setSizeUnit( mSizeUnit );
2161  copyPaintEffect( m );
2162  return m;
2163 }
2164 
2166 {
2168  mOutlineWidthUnit = unit;
2169 }
2170 
2172 {
2174  if ( unit != mOutlineWidthUnit )
2175  {
2176  return QgsSymbolV2::Mixed;
2177  }
2178  return unit;
2179 }
2180 
2182 {
2184  mOutlineWidthMapUnitScale = scale;
2185 }
2186 
2188 {
2189  if ( QgsMarkerSymbolLayerV2::mapUnitScale() == mOutlineWidthMapUnitScale )
2190  {
2191  return mOutlineWidthMapUnitScale;
2192  }
2193  return QgsMapUnitScale();
2194 }
2195 
2197 {
2198  // <Graphic>
2199  QDomElement graphicElem = doc.createElement( "se:Graphic" );
2200  element.appendChild( graphicElem );
2201 
2202  QgsSymbolLayerV2Utils::externalGraphicToSld( doc, graphicElem, mPath, "image/svg+xml", mColor, mSize );
2203 
2204  // <Rotation>
2205  QString angleFunc;
2206  bool ok;
2207  double angle = props.value( "angle", "0" ).toDouble( &ok );
2208  if ( !ok )
2209  {
2210  angleFunc = QString( "%1 + %2" ).arg( props.value( "angle", "0" ) ).arg( mAngle );
2211  }
2212  else if ( !qgsDoubleNear( angle + mAngle, 0.0 ) )
2213  {
2214  angleFunc = QString::number( angle + mAngle );
2215  }
2216 
2217  QgsSymbolLayerV2Utils::createRotationElement( doc, graphicElem, angleFunc );
2218 
2219  // <Displacement>
2221 }
2222 
2224 {
2225  QgsDebugMsg( "Entered." );
2226 
2227  QDomElement graphicElem = element.firstChildElement( "Graphic" );
2228  if ( graphicElem.isNull() )
2229  return nullptr;
2230 
2231  QString path, mimeType;
2232  QColor fillColor;
2233  double size;
2234 
2235  if ( !QgsSymbolLayerV2Utils::externalGraphicFromSld( graphicElem, path, mimeType, fillColor, size ) )
2236  return nullptr;
2237 
2238  if ( mimeType != "image/svg+xml" )
2239  return nullptr;
2240 
2241  double angle = 0.0;
2242  QString angleFunc;
2243  if ( QgsSymbolLayerV2Utils::rotationFromSldElement( graphicElem, angleFunc ) )
2244  {
2245  bool ok;
2246  double d = angleFunc.toDouble( &ok );
2247  if ( ok )
2248  angle = d;
2249  }
2250 
2251  QPointF offset;
2253 
2255  m->setFillColor( fillColor );
2256  //m->setOutlineColor( outlineColor );
2257  //m->setOutlineWidth( outlineWidth );
2258  m->setAngle( angle );
2259  m->setOffset( offset );
2260  return m;
2261 }
2262 
2263 bool QgsSvgMarkerSymbolLayerV2::writeDxf( QgsDxfExport& e, double mmMapUnitScaleFactor, const QString& layerName, QgsSymbolV2RenderContext &context, QPointF shift ) const
2264 {
2265  Q_UNUSED( layerName );
2266  Q_UNUSED( shift ); //todo...
2267 
2268  //size
2269  double size = mSize;
2270 
2272 
2273  bool ok = true;
2275  {
2276  context.setOriginalValueVariable( mSize );
2278  }
2279 
2280  if ( hasDataDefinedSize && ok )
2281  {
2282  switch ( mScaleMethod )
2283  {
2285  size = sqrt( size );
2286  break;
2288  break;
2289  }
2290  }
2291 
2292  if ( mSizeUnit == QgsSymbolV2::MM )
2293  {
2294  size *= mmMapUnitScaleFactor;
2295  }
2296 
2297  double halfSize = size / 2.0;
2298 
2299  //offset, angle
2300  QPointF offset = mOffset;
2301 
2303  {
2306  if ( ok )
2307  offset = QgsSymbolLayerV2Utils::decodePoint( offsetString );
2308  }
2309  double offsetX = offset.x();
2310  double offsetY = offset.y();
2311  if ( mSizeUnit == QgsSymbolV2::MM )
2312  {
2313  offsetX *= mmMapUnitScaleFactor;
2314  offsetY *= mmMapUnitScaleFactor;
2315  }
2316 
2317  QPointF outputOffset( offsetX, offsetY );
2318 
2319  double angle = mAngle + mLineAngle;
2321  {
2322  context.setOriginalValueVariable( mAngle );
2324  }
2325  //angle = -angle; //rotation in Qt is counterclockwise
2326  if ( angle )
2327  outputOffset = _rotatedOffset( outputOffset, angle );
2328 
2329  QString path = mPath;
2331  {
2332  context.setOriginalValueVariable( mPath );
2334  }
2335 
2336  double outlineWidth = mOutlineWidth;
2338  {
2339  context.setOriginalValueVariable( mOutlineWidth );
2340  outlineWidth = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_OUTLINE_WIDTH, context, mOutlineWidth ).toDouble();
2341  }
2342  outlineWidth = QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), outlineWidth, mOutlineWidthUnit, mOutlineWidthMapUnitScale );
2343 
2346  {
2349  if ( ok )
2350  fillColor = QgsSymbolLayerV2Utils::decodeColor( colorString );
2351  }
2352 
2353  QColor outlineColor = mOutlineColor;
2355  {
2358  if ( ok )
2359  outlineColor = QgsSymbolLayerV2Utils::decodeColor( colorString );
2360  }
2361 
2362  const QByteArray &svgContent = QgsSvgCache::instance()->svgContent( path, size, fillColor, outlineColor, outlineWidth,
2363  context.renderContext().scaleFactor(),
2364  context.renderContext().rasterScaleFactor() );
2365 
2366  //if current entry image is 0: cache image for entry
2367  // checks to see if image will fit into cache
2368  //update stats for memory usage
2369  QSvgRenderer r( svgContent );
2370  if ( !r.isValid() )
2371  {
2372  return false;
2373  }
2374 
2375  QgsDxfPaintDevice pd( &e );
2376  pd.setDrawingSize( QSizeF( r.defaultSize() ) );
2377 
2378  QPainter p;
2379  p.begin( &pd );
2380  if ( !qgsDoubleNear( angle, 0.0 ) )
2381  {
2382  p.translate( r.defaultSize().width() / 2.0, r.defaultSize().height() / 2.0 );
2383  p.rotate( angle );
2384  p.translate( -r.defaultSize().width() / 2.0, -r.defaultSize().height() / 2.0 );
2385  }
2386  pd.setShift( shift );
2387  pd.setOutputSize( QRectF( -halfSize, -halfSize, size, size ) );
2388  pd.setLayer( layerName );
2389  r.render( &p );
2390  p.end();
2391  return true;
2392 }
2393 
2395 {
2396  bool hasDataDefinedSize = false;
2397  double scaledSize = calculateSize( context, hasDataDefinedSize );
2399 
2400  //don't render symbols with size below one or above 10,000 pixels
2401  if ( static_cast< int >( scaledSize ) < 1 || 10000.0 < scaledSize )
2402  {
2403  return QRectF();
2404  }
2405 
2406  QPointF outputOffset;
2407  double angle = 0.0;
2408  calculateOffsetAndRotation( context, scaledSize, outputOffset, angle );
2409 
2410  QString path = mPath;
2412  {
2413  context.setOriginalValueVariable( mPath );
2415  }
2416 
2417  double outlineWidth = mOutlineWidth;
2419  {
2420  context.setOriginalValueVariable( mOutlineWidth );
2421  outlineWidth = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_OUTLINE_WIDTH, context, mOutlineWidth ).toDouble();
2422  }
2423  outlineWidth = QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), outlineWidth, mOutlineWidthUnit, mOutlineWidthMapUnitScale );
2424 
2425  //need to get colors to take advantage of cached SVGs
2427  bool ok = false;
2429  {
2432  if ( ok )
2433  fillColor = QgsSymbolLayerV2Utils::decodeColor( colorString );
2434  }
2435 
2436  QColor outlineColor = mOutlineColor;
2438  {
2441  if ( ok )
2442  outlineColor = QgsSymbolLayerV2Utils::decodeColor( colorString );
2443  }
2444 
2445  QSizeF svgViewbox = QgsSvgCache::instance()->svgViewboxSize( path, scaledSize, fillColor, outlineColor, outlineWidth,
2446  context.renderContext().scaleFactor(),
2447  context.renderContext().rasterScaleFactor() );
2448 
2449  double scaledHeight = svgViewbox.isValid() ? scaledSize * svgViewbox.height() / svgViewbox.width() : scaledSize;
2450  double pixelSize = 1.0 / context.renderContext().rasterScaleFactor();
2451 
2452  QMatrix transform;
2453 
2454  // move to the desired position
2455  transform.translate( point.x() + outputOffset.x(), point.y() + outputOffset.y() );
2456 
2457  if ( !qgsDoubleNear( angle, 0.0 ) )
2458  transform.rotate( angle );
2459 
2460  //antialiasing
2461  outlineWidth += pixelSize / 2.0;
2462 
2463  QRectF symbolBounds = transform.mapRect( QRectF( -scaledSize / 2.0,
2464  -scaledHeight / 2.0,
2465  scaledSize,
2466  scaledHeight ) );
2467 
2468  //extend bounds by pen width / 2.0
2469  symbolBounds.adjust( -outlineWidth / 2.0, -outlineWidth / 2.0,
2470  outlineWidth / 2.0, outlineWidth / 2.0 );
2471 
2472  return symbolBounds;
2473 
2474 }
2475 
2477 
2478 QgsFontMarkerSymbolLayerV2::QgsFontMarkerSymbolLayerV2( const QString& fontFamily, QChar chr, double pointSize, const QColor& color, double angle )
2479  : mFontMetrics( nullptr )
2480  , mChrWidth( 0 )
2481 {
2483  mChr = chr;
2484  mColor = color;
2485  mAngle = angle;
2486  mSize = pointSize;
2487  mOrigSize = pointSize;
2489  mOffset = QPointF( 0, 0 );
2491  mOutlineColor = DEFAULT_FONTMARKER_BORDERCOLOR;
2492  mOutlineWidth = 0.0;
2493  mOutlineWidthUnit = QgsSymbolV2::MM;
2494  mPenJoinStyle = DEFAULT_FONTMARKER_JOINSTYLE;
2495 }
2496 
2498 {
2499  delete mFontMetrics;
2500 }
2501 
2503 {
2506  double pointSize = DEFAULT_FONTMARKER_SIZE;
2509 
2510  if ( props.contains( "font" ) )
2511  fontFamily = props["font"];
2512  if ( props.contains( "chr" ) && props["chr"].length() > 0 )
2513  chr = props["chr"].at( 0 );
2514  if ( props.contains( "size" ) )
2515  pointSize = props["size"].toDouble();
2516  if ( props.contains( "color" ) )
2517  color = QgsSymbolLayerV2Utils::decodeColor( props["color"] );
2518  if ( props.contains( "angle" ) )
2519  angle = props["angle"].toDouble();
2520 
2521  QgsFontMarkerSymbolLayerV2* m = new QgsFontMarkerSymbolLayerV2( fontFamily, chr, pointSize, color, angle );
2522 
2523  if ( props.contains( "outline_color" ) )
2524  m->setOutlineColor( QgsSymbolLayerV2Utils::decodeColor( props["outline_color"] ) );
2525  if ( props.contains( "outline_width" ) )
2526  m->setOutlineWidth( props["outline_width"].toDouble() );
2527  if ( props.contains( "offset" ) )
2528  m->setOffset( QgsSymbolLayerV2Utils::decodePoint( props["offset"] ) );
2529  if ( props.contains( "offset_unit" ) )
2530  m->setOffsetUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["offset_unit" ] ) );
2531  if ( props.contains( "offset_map_unit_scale" ) )
2532  m->setOffsetMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["offset_map_unit_scale" ] ) );
2533  if ( props.contains( "size_unit" ) )
2534  m->setSizeUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["size_unit"] ) );
2535  if ( props.contains( "size_map_unit_scale" ) )
2536  m->setSizeMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["size_map_unit_scale"] ) );
2537  if ( props.contains( "outline_width_unit" ) )
2538  m->setOutlineWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["outline_width_unit"] ) );
2539  if ( props.contains( "outline_width_map_unit_scale" ) )
2540  m->setOutlineWidthMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["outline_width_map_unit_scale"] ) );
2541  if ( props.contains( "joinstyle" ) )
2542  m->setPenJoinStyle( QgsSymbolLayerV2Utils::decodePenJoinStyle( props["joinstyle"] ) );
2543  if ( props.contains( "horizontal_anchor_point" ) )
2544  m->setHorizontalAnchorPoint( QgsMarkerSymbolLayerV2::HorizontalAnchorPoint( props[ "horizontal_anchor_point" ].toInt() ) );
2545  if ( props.contains( "vertical_anchor_point" ) )
2546  m->setVerticalAnchorPoint( QgsMarkerSymbolLayerV2::VerticalAnchorPoint( props[ "vertical_anchor_point" ].toInt() ) );
2547 
2548  m->restoreDataDefinedProperties( props );
2549 
2550  return m;
2551 }
2552 
2554 {
2555  return "FontMarker";
2556 }
2557 
2559 {
2560  QColor brushColor = mColor;
2561  QColor penColor = mOutlineColor;
2562 
2563  brushColor.setAlphaF( mColor.alphaF() * context.alpha() );
2564  penColor.setAlphaF( mOutlineColor.alphaF() * context.alpha() );
2565 
2566  mBrush = QBrush( brushColor );
2567  mPen = QPen( penColor );
2568  mPen.setJoinStyle( mPenJoinStyle );
2569  mPen.setWidthF( QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), mOutlineWidth, mOutlineWidthUnit, mOutlineWidthMapUnitScale ) );
2570 
2571  mFont = QFont( mFontFamily );
2573  delete mFontMetrics;
2574  mFontMetrics = new QFontMetrics( mFont );
2576  mChrOffset = QPointF( mChrWidth / 2.0, -mFontMetrics->ascent() / 2.0 );
2577  mOrigSize = mSize; // save in case the size would be data defined
2578  prepareExpressions( context );
2579 }
2580 
2582 {
2583  Q_UNUSED( context );
2584 }
2585 
2586 QString QgsFontMarkerSymbolLayerV2::characterToRender( QgsSymbolV2RenderContext& context, QPointF& charOffset, double& charWidth )
2587 {
2588  charOffset = mChrOffset;
2589  QString charToRender = mChr;
2591  {
2592  context.setOriginalValueVariable( mChr );
2594  if ( charToRender != mChr )
2595  {
2596  charWidth = mFontMetrics->width( charToRender );
2597  charOffset = QPointF( charWidth / 2.0, -mFontMetrics->ascent() / 2.0 );
2598  }
2599  }
2600  return charToRender;
2601 }
2602 
2603 void QgsFontMarkerSymbolLayerV2::calculateOffsetAndRotation( QgsSymbolV2RenderContext& context,
2604  double scaledSize,
2605  bool& hasDataDefinedRotation,
2606  QPointF& offset,
2607  double& angle ) const
2608 {
2609  //offset
2610  double offsetX = 0;
2611  double offsetY = 0;
2612  markerOffset( context, scaledSize, scaledSize, offsetX, offsetY );
2613  offset = QPointF( offsetX, offsetY );
2614 
2615  //angle
2616  bool ok = true;
2617  angle = mAngle + mLineAngle;
2618  bool usingDataDefinedRotation = false;
2620  {
2621  context.setOriginalValueVariable( angle );
2623  usingDataDefinedRotation = ok;
2624  }
2625 
2626  hasDataDefinedRotation = context.renderHints() & QgsSymbolV2::DataDefinedRotation || usingDataDefinedRotation;
2627  if ( hasDataDefinedRotation )
2628  {
2629  // For non-point markers, "dataDefinedRotation" means following the
2630  // shape (shape-data defined). For them, "field-data defined" does
2631  // not work at all. TODO: if "field-data defined" ever gets implemented
2632  // we'll need a way to distinguish here between the two, possibly
2633  // using another flag in renderHints()
2634  const QgsFeature* f = context.feature();
2635  if ( f )
2636  {
2637  const QgsGeometry *g = f->constGeometry();
2638  if ( g && g->type() == QGis::Point )
2639  {
2640  const QgsMapToPixel& m2p = context.renderContext().mapToPixel();
2641  angle += m2p.mapRotation();
2642  }
2643  }
2644  }
2645 
2646  if ( angle )
2647  offset = _rotatedOffset( offset, angle );
2648 }
2649 
2650 double QgsFontMarkerSymbolLayerV2::calculateSize( QgsSymbolV2RenderContext& context )
2651 {
2652  double scaledSize = mSize;
2654 
2655  bool ok = true;
2657  {
2658  context.setOriginalValueVariable( mSize );
2659  scaledSize = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_SIZE, context, mSize, &ok ).toDouble();
2660  }
2661 
2662  if ( hasDataDefinedSize && ok )
2663  {
2664  switch ( mScaleMethod )
2665  {
2667  scaledSize = sqrt( scaledSize );
2668  break;
2670  break;
2671  }
2672  }
2673  return scaledSize;
2674 }
2675 
2677 {
2678  QPainter *p = context.renderContext().painter();
2679  if ( !p )
2680  return;
2681 
2682  QTransform transform;
2683 
2684  bool ok;
2685  QColor brushColor = mColor;
2687  {
2690  if ( ok )
2691  brushColor = QgsSymbolLayerV2Utils::decodeColor( colorString );
2692  }
2693  brushColor = context.selected() ? context.renderContext().selectionColor() : brushColor;
2694  brushColor.setAlphaF( brushColor.alphaF() * context.alpha() );
2695  mBrush.setColor( brushColor );
2696 
2697  QColor penColor = mOutlineColor;
2699  {
2702  if ( ok )
2703  penColor = QgsSymbolLayerV2Utils::decodeColor( colorString );
2704  }
2705  penColor.setAlphaF( penColor.alphaF() * context.alpha() );
2706 
2707  double penWidth = QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), mOutlineWidth, mOutlineWidthUnit, mOutlineWidthMapUnitScale );
2709  {
2710  context.setOriginalValueVariable( mOutlineWidth );
2712  if ( ok )
2713  {
2714  penWidth = QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), outlineWidth, mOutlineWidthUnit, mOutlineWidthMapUnitScale );
2715  }
2716  }
2717 
2719  {
2722  if ( ok )
2723  {
2725  }
2726  }
2727 
2728  p->setBrush( mBrush );
2729  if ( !qgsDoubleNear( penWidth, 0.0 ) )
2730  {
2731  mPen.setColor( penColor );
2732  mPen.setWidthF( penWidth );
2733  p->setPen( mPen );
2734  }
2735  else
2736  {
2737  p->setPen( Qt::NoPen );
2738  }
2739  p->save();
2740 
2741  QPointF chrOffset = mChrOffset;
2742  double chrWidth;
2743  QString charToRender = characterToRender( context, chrOffset, chrWidth );
2744 
2745  double sizeToRender = calculateSize( context );
2746 
2747  bool hasDataDefinedRotation = false;
2748  QPointF offset;
2749  double angle = 0;
2750  calculateOffsetAndRotation( context, sizeToRender, hasDataDefinedRotation, offset, angle );
2751 
2752  transform.translate( point.x() + offset.x(), point.y() + offset.y() );
2753 
2754  if ( !qgsDoubleNear( angle, 0.0 ) )
2755  transform.rotate( angle );
2756 
2757  if ( !qgsDoubleNear( sizeToRender, mOrigSize ) )
2758  {
2759  double s = sizeToRender / mOrigSize;
2760  transform.scale( s, s );
2761  }
2762 
2763  QPainterPath path;
2764  path.addText( -chrOffset.x(), -chrOffset.y(), mFont, charToRender );
2765  p->drawPath( transform.map( path ) );
2766  p->restore();
2767 }
2768 
2770 {
2771  QgsStringMap props;
2772  props["font"] = mFontFamily;
2773  props["chr"] = mChr;
2774  props["size"] = QString::number( mSize );
2775  props["size_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mSizeUnit );
2776  props["size_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mSizeMapUnitScale );
2777  props["color"] = QgsSymbolLayerV2Utils::encodeColor( mColor );
2778  props["outline_color"] = QgsSymbolLayerV2Utils::encodeColor( mOutlineColor );
2779  props["outline_width"] = QString::number( mOutlineWidth );
2780  props["outline_width_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOutlineWidthUnit );
2781  props["outline_width_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOutlineWidthMapUnitScale );
2782  props["joinstyle"] = QgsSymbolLayerV2Utils::encodePenJoinStyle( mPenJoinStyle );
2783  props["angle"] = QString::number( mAngle );
2784  props["offset"] = QgsSymbolLayerV2Utils::encodePoint( mOffset );
2785  props["offset_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOffsetUnit );
2786  props["offset_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOffsetMapUnitScale );
2787  props["horizontal_anchor_point"] = QString::number( mHorizontalAnchorPoint );
2788  props["vertical_anchor_point"] = QString::number( mVerticalAnchorPoint );
2789 
2790  //data define properties
2791  saveDataDefinedProperties( props );
2792 
2793  return props;
2794 }
2795 
2797 {
2799  m->setOutlineColor( mOutlineColor );
2800  m->setOutlineWidth( mOutlineWidth );
2801  m->setOutlineWidthUnit( mOutlineWidthUnit );
2802  m->setOutlineWidthMapUnitScale( mOutlineWidthMapUnitScale );
2803  m->setPenJoinStyle( mPenJoinStyle );
2804  m->setOffset( mOffset );
2805  m->setOffsetUnit( mOffsetUnit );
2807  m->setSizeUnit( mSizeUnit );
2812  copyPaintEffect( m );
2813  return m;
2814 }
2815 
2817 {
2818  // <Graphic>
2819  QDomElement graphicElem = doc.createElement( "se:Graphic" );
2820  element.appendChild( graphicElem );
2821 
2822  QString fontPath = QString( "ttf://%1" ).arg( mFontFamily );
2823  int markIndex = mChr.unicode();
2824  QgsSymbolLayerV2Utils::externalMarkerToSld( doc, graphicElem, fontPath, "ttf", &markIndex, mColor, mSize );
2825 
2826  // <Rotation>
2827  QString angleFunc;
2828  bool ok;
2829  double angle = props.value( "angle", "0" ).toDouble( &ok );
2830  if ( !ok )
2831  {
2832  angleFunc = QString( "%1 + %2" ).arg( props.value( "angle", "0" ) ).arg( mAngle );
2833  }
2834  else if ( !qgsDoubleNear( angle + mAngle, 0.0 ) )
2835  {
2836  angleFunc = QString::number( angle + mAngle );
2837  }
2838  QgsSymbolLayerV2Utils::createRotationElement( doc, graphicElem, angleFunc );
2839 
2840  // <Displacement>
2842 }
2843 
2845 {
2846  QPointF chrOffset = mChrOffset;
2847  double chrWidth = mChrWidth;
2848  //calculate width of rendered character
2849  ( void )characterToRender( context, chrOffset, chrWidth );
2850 
2851  if ( !mFontMetrics )
2852  mFontMetrics = new QFontMetrics( mFont );
2853 
2854  double scaledSize = calculateSize( context );
2855  if ( !qgsDoubleNear( scaledSize, mOrigSize ) )
2856  {
2857  chrWidth *= scaledSize / mOrigSize;
2858  }
2859 
2860  bool hasDataDefinedRotation = false;
2861  QPointF offset;
2862  double angle = 0;
2863  calculateOffsetAndRotation( context, scaledSize, hasDataDefinedRotation, offset, angle );
2865 
2866  QMatrix transform;
2867 
2868  // move to the desired position
2869  transform.translate( point.x() + offset.x(), point.y() + offset.y() );
2870 
2871  if ( !qgsDoubleNear( angle, 0.0 ) )
2872  transform.rotate( angle );
2873 
2874  QRectF symbolBounds = transform.mapRect( QRectF( -chrWidth / 2.0,
2875  -scaledSize / 2.0,
2876  chrWidth,
2877  scaledSize ) );
2878  return symbolBounds;
2879 }
2880 
2882 {
2883  QgsDebugMsg( "Entered." );
2884 
2885  QDomElement graphicElem = element.firstChildElement( "Graphic" );
2886  if ( graphicElem.isNull() )
2887  return nullptr;
2888 
2889  QString name, format;
2890  QColor color;
2891  double size;
2892  int chr;
2893 
2894  if ( !QgsSymbolLayerV2Utils::externalMarkerFromSld( graphicElem, name, format, chr, color, size ) )
2895  return nullptr;
2896 
2897  if ( !name.startsWith( "ttf://" ) || format != "ttf" )
2898  return nullptr;
2899 
2900  QString fontFamily = name.mid( 6 );
2901 
2902  double angle = 0.0;
2903  QString angleFunc;
2904  if ( QgsSymbolLayerV2Utils::rotationFromSldElement( graphicElem, angleFunc ) )
2905  {
2906  bool ok;
2907  double d = angleFunc.toDouble( &ok );
2908  if ( ok )
2909  angle = d;
2910  }
2911 
2912  QPointF offset;
2914 
2915  QgsMarkerSymbolLayerV2 *m = new QgsFontMarkerSymbolLayerV2( fontFamily, chr, size, color );
2916  m->setAngle( angle );
2917  m->setOffset( offset );
2918  return m;
2919 }
2920 
virtual QSet< QString > usedAttributes() const
Returns the set of attributes referenced by the layer.
void addEllipse(const QRectF &boundingRectangle)
double angle() const
Returns the rotation angle for the marker, in degrees clockwise from north.
QgsSymbolV2::OutputUnit outputUnit() const override
QColor borderColor() const
Returns the marker&#39;s border color.
static QString encodeOutputUnit(QgsSymbolV2::OutputUnit unit)
Q_GUI_EXPORT int qt_defaultDpiX()
QRectF bounds(QPointF point, QgsSymbolV2RenderContext &context) override
Returns the approximate bounding box of the marker symbol layer, taking into account any data defined...
static const QString EXPR_CHAR
void setOutlineStyle(Qt::PenStyle outlineStyle)
Sets the marker&#39;s outline style (eg solid, dashed, etc)
static void createRotationElement(QDomDocument &doc, QDomElement &element, const QString &rotationFunc)
void setOutlineColor(const QColor &color) override
Set outline color.
void setOpacity(qreal opacity)
Qt::PenStyle style() const
void setPenJoinStyle(Qt::PenJoinStyle style)
Set outline join style.
static void externalMarkerToSld(QDomDocument &doc, QDomElement &element, const QString &path, const QString &format, int *markIndex=nullptr, const QColor &color=QColor(), double size=-1)
QgsSymbolV2::OutputUnit outputUnit() const override
void setStyle(Qt::PenStyle style)
QString & append(QChar ch)
static QPointF _rotatedOffset(QPointF offset, double angle)
Adjusts a marker offset to account for rotation.
static void multiplyImageOpacity(QImage *image, qreal alpha)
Multiplies opacity of image pixel values with a (global) transparency value.
int ascent() const
OutputUnit
The unit of the output.
Definition: qgssymbolv2.h:62
Q_DECL_DEPRECATED 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)
int renderHints() const
Definition: qgssymbolv2.h:373
QgsMapUnitScale mSizeMapUnitScale
Marker size map unit scale.
QgsMapUnitScale mOutlineWidthMapUnitScale
Outline width map unit scale.
Q_GUI_EXPORT int qt_defaultDpiY()
int width() const
void startRender(QgsSymbolV2RenderContext &context) override
void setColor(const QColor &c) override
The fill color.
QString layerType() const override
Returns a string that represents this layer type.
bool end()
bool contains(const Key &key) const
QgsStringMap properties() const override
Should be reimplemented by subclasses to return a string map that contains the configuration informat...
static Q_DECL_DEPRECATED bool wellKnownMarkerFromSld(QDomElement &element, QString &name, QColor &color, QColor &borderColor, double &borderWidth, double &size)
void fillRect(const QRectF &rectangle, const QBrush &brush)
double calculateSize(QgsSymbolV2RenderContext &context, bool &hasDataDefinedSize) const
Calculates the desired size of the marker, considering data defined size overrides.
qreal alphaF() const
QRectF bounds(QPointF point, QgsSymbolV2RenderContext &context) override
Returns the approximate bounding box of the marker symbol layer, taking into account any data defined...
A paint device for drawing into dxf files.
void setRenderHint(RenderHint hint, bool on)
QString layerType() const override
Returns a string that represents this layer type.
virtual void setOutlineColor(const QColor &color)
Set outline color.
QDomNode appendChild(const QDomNode &newChild)
#define DEFAULT_FONTMARKER_COLOR
void render(QPainter *painter)
Use antialiasing while drawing.
SymbolType type() const
Definition: qgssymbolv2.h:104
void renderPoint(QPointF point, QgsSymbolV2RenderContext &context) override
Renders a marker at the specified point.
QString name() const
const QPicture & svgAsPicture(const QString &file, double size, const QColor &fill, const QColor &outline, double outlineWidth, double widthScaleFactor, double rasterScaleFactor, bool forceVectorOutput=false)
Get SVG as QPicture&.
QSizeF svgViewboxSize(const QString &file, double size, const QColor &fill, const QColor &outline, double outlineWidth, double widthScaleFactor, double rasterScaleFactor)
Calculates the viewbox size of a (possibly cached) SVG file.
Qt::BrushStyle style() const
QColor selectionColor() const
Abstract base class for simple marker symbol layers.
void setOutlineColor(const QColor &c) override
Set outline color.
QString layerType() const override
Returns a string that represents this layer type.
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
QPoint map(const QPoint &point) const
void setOutlineWidthMapUnitScale(const QgsMapUnitScale &scale)
Set outline width map unit scale.
static QString encodeColor(const QColor &color)
#define DEFAULT_SIMPLEMARKER_ANGLE
void renderPoint(QPointF point, QgsSymbolV2RenderContext &context) override
Renders a marker at the specified point.
static void externalGraphicToSld(QDomDocument &doc, QDomElement &element, const QString &path, const QString &mime, const QColor &color, double size=-1)
void scale(qreal sx, qreal sy)
void setDrawingSize(QSizeF size)
#define DEFAULT_FONTMARKER_CHR
static QgsFillSymbolV2 * createSimple(const QgsStringMap &properties)
Create a fill symbol with one symbol layer: SimpleFill with specified properties. ...
static QgsSymbolV2::ScaleMethod decodeScaleMethod(const QString &str)
Calculate scale by the diameter.
Definition: qgssymbolv2.h:90
bool isValid() const
void setOffset(QPointF offset)
Sets the marker&#39;s offset, which is the horizontal and vertical displacement which the rendered marker...
QString ogrFeatureStyle(double mmScaleFactor, double mapUnitScaleFactor) const override
void setHorizontalAnchorPoint(HorizontalAnchorPoint h)
Sets the horizontal anchor point for positioning the symbol.
bool isValid() const
#define DEG2RAD(x)
Q_DECL_DEPRECATED QString name() const
void setOutlineWidth(double w)
Sets the width of the marker&#39;s outline.
QGis::GeometryType type() const
Returns type of the geometry as a QGis::GeometryType.
#define DEFAULT_SIMPLEMARKER_COLOR
void save()
QImage mCache
Cached image of marker, if using cached version.
void setOriginalValueVariable(const QVariant &value)
Sets the original value variable value for data defined symbology.
void writeSldMarker(QDomDocument &doc, QDomElement &element, const QgsStringMap &props) const override
Writes the symbol layer definition as a SLD XML element.
void drawPolygon(const QPointF *points, int pointCount, Qt::FillRule fillRule)
void setVerticalAnchorPoint(VerticalAnchorPoint v)
Sets the vertical anchor point for positioning the symbol.
bool mUsingCache
True if using cached images of markers for drawing.
static bool externalGraphicFromSld(QDomElement &element, QString &path, QString &mime, QColor &color, double &size)
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:76
static Shape decodeShape(const QString &name, bool *ok=nullptr)
Attempts to decode a string representation of a shape name to the corresponding shape.
void setJoinStyle(Qt::PenJoinStyle style)
void moveTo(const QPointF &point)
void renderPoint(QPointF point, QgsSymbolV2RenderContext &context) override
Renders a marker at the specified point.
bool writeDxf(QgsDxfExport &e, double mmMapUnitScaleFactor, const QString &layerName, QgsSymbolV2RenderContext &context, QPointF shift=QPointF(0.0, 0.0)) const override
write as DXF
static QPointF decodePoint(const QString &str)
static Qt::PenJoinStyle decodePenJoinStyle(const QString &str)
void copyPaintEffect(QgsSymbolLayerV2 *destLayer) const
Copies paint effect of this layer to another symbol layer.
void stopRender(QgsSymbolV2RenderContext &context) override
void stopRender(QgsSymbolV2RenderContext &context) override
void calculateOffsetAndRotation(QgsSymbolV2RenderContext &context, double scaledSize, bool &hasDataDefinedRotation, QPointF &offset, double &angle) const
Calculates the marker offset and rotation.
static QString encodeMapUnitScale(const QgsMapUnitScale &mapUnitScale)
virtual bool hasDataDefinedProperty(const QString &property) const
Checks whether the layer has a matching data defined property and if that property is currently activ...
void writeSldMarker(QDomDocument &doc, QDomElement &element, const QgsStringMap &props) const override
Writes the symbol layer definition as a SLD XML element.
QPolygonF toFillPolygon(const QMatrix &matrix) const
bool writeDxf(QgsDxfExport &e, double mmMapUnitScaleFactor, const QString &layerName, QgsSymbolV2RenderContext &context, QPointF shift=QPointF(0.0, 0.0)) const override
write as DXF
double scaleFactor() const
QColor fillColor() const override
Get fill color.
void rotate(qreal angle)
static QgsSymbolLayerV2 * create(const QgsStringMap &properties=QgsStringMap())
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:187
static void _fixQPictureDPI(QPainter *p)
void addText(const QPointF &point, const QFont &font, const QString &text)
void setOffsetMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale for the symbol&#39;s offset.
QImage copy(const QRect &rectangle) const
static void createDisplacementElement(QDomDocument &doc, QDomElement &element, QPointF offset)
QgsFilledMarkerSymbolLayer(Shape shape=Circle, double size=DEFAULT_SIMPLEMARKER_SIZE, double angle=DEFAULT_SIMPLEMARKER_ANGLE, QgsSymbolV2::ScaleMethod scaleMethod=DEFAULT_SCALE_METHOD)
Constructor for QgsFilledMarkerSymbolLayer.
double toDouble(bool *ok) const
virtual QColor fillColor() const
Get fill color.
static QgsSymbolLayerV2 * create(const QgsStringMap &properties=QgsStringMap())
Creates a new QgsSimpleMarkerSymbolLayerV2.
QMap< QString, QString > QgsStringMap
Definition: qgis.h:491
double mapRotation() const
Return current map rotation in degrees.
void adjust(qreal dx1, qreal dy1, qreal dx2, qreal dy2)
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
Compare two doubles (but allow some difference)
Definition: qgis.h:352
static const QString EXPR_OFFSET
void setMapUnitScale(const QgsMapUnitScale &scale) override
static QgsSymbolLayerV2 * createFromSld(QDomElement &element)
Creates a new QgsSimpleMarkerSymbolLayerV2 from an SLD XML element.
#define DEFAULT_FONTMARKER_JOINSTYLE
QSize defaultSize() const
#define DEFAULT_SVGMARKER_ANGLE
static QList< Shape > availableShapes()
Returns a list of all available shape types.
static const QString EXPR_SIZE
void setOffsetUnit(QgsSymbolV2::OutputUnit unit)
Sets the units for the symbol&#39;s offset.
bool isNull() const
void reset(T *other)
QPainterPath mPath
Painter path representing shape. If mPolygon is empty then the shape is stored in mPath...
virtual QgsSymbolV2 * subSymbol() override
#define DEFAULT_SIMPLEMARKER_NAME
static const QString EXPR_JOIN_STYLE
void containsParams(const QString &path, bool &hasFillParam, QColor &defaultFillColor, bool &hasOutlineParam, QColor &defaultOutlineColor, bool &hasOutlineWidthParam, double &defaultOutlineWidth) const
Tests if an svg file contains parameters for fill, outline color, outline width.
static QgsSymbolV2::OutputUnit decodeOutputUnit(const QString &str)
static bool displacementFromSldElement(QDomElement &element, QPointF &offset)
int width() const
qreal alpha() const
Get alpha transparency 1 for opaque, 0 for invisible.
Definition: qgssymbolv2.h:366
void drawMarker(QPainter *p, QgsSymbolV2RenderContext &context)
Draws the marker shape in the specified painter.
const QColor & color() const
static QgsSvgCache * instance()
Definition: qgssvgcache.cpp:97
static QString encodePenStyle(Qt::PenStyle style)
void setOutlineWidthUnit(QgsSymbolV2::OutputUnit unit)
const QImage & svgAsImage(const QString &file, double size, const QColor &fill, const QColor &outline, double outlineWidth, double widthScaleFactor, double rasterScaleFactor, bool &fitsInCache)
Get SVG as QImage.
void drawRect(const QRectF &rectangle)
Perform transforms between map coordinates and device coordinates.
Definition: qgsmaptopixel.h:34
void setPixelSize(int pixelSize)
static QString symbolPathToName(QString path)
Get symbols&#39;s name from its path.
QColor color() const
void clear()
Mixed units in symbol layers.
Definition: qgssymbolv2.h:66
QTransform & translate(qreal dx, qreal dy)
The output shall be in millimeters.
Definition: qgssymbolv2.h:64
void setMapUnitScale(const QgsMapUnitScale &scale) override
QString number(int n, int base)
void setOutlineWidthUnit(QgsSymbolV2::OutputUnit u)
Sets the unit for the width of the marker&#39;s outline.
void markerOffset(QgsSymbolV2RenderContext &context, double &offsetX, double &offsetY) const
Calculates the required marker offset, including both the symbol offset and any displacement required...
qreal x() const
qreal y() const
const QgsFeature * feature() const
Current feature being rendered - may be null.
Definition: qgssymbolv2.h:378
QTransform & scale(qreal sx, qreal sy)
QRectF bounds(QPointF point, QgsSymbolV2RenderContext &context) override
Returns the approximate bounding box of the marker symbol layer, taking into account any data defined...
void fill(uint pixelValue)
static QString encodePoint(QPointF point)
static double convertToPainterUnits(const QgsRenderContext &c, double size, QgsSymbolV2::OutputUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale())
Converts a size from the specied units to painter units.
QgsStringMap properties() const override
Should be reimplemented by subclasses to return a string map that contains the configuration informat...
void setPath(const QString &path)
void setPen(const QColor &color)
int width() const
void lineTo(const QPointF &endPoint)
#define DEFAULT_SCALE_METHOD
void setOutputUnit(QgsSymbolV2::OutputUnit unit) override
Qt::PenStyle mOutlineStyle
Outline style.
QMatrix & translate(qreal dx, qreal dy)
void startRender(QgsSymbolV2RenderContext &context) override
Point geometry type, with support for z-dimension and m-values.
Definition: qgspointv2.h:34
void setMapUnitScale(const QgsMapUnitScale &scale) override
void setFillColor(const QColor &color) override
Set fill color.
QString trimmed() const
QgsFontMarkerSymbolLayerV2(const QString &fontFamily=DEFAULT_FONTMARKER_FONT, QChar chr=DEFAULT_FONTMARKER_CHR, double pointSize=DEFAULT_FONTMARKER_SIZE, const QColor &color=DEFAULT_FONTMARKER_COLOR, double angle=DEFAULT_FONTMARKER_ANGLE)
static QString encodePenJoinStyle(Qt::PenJoinStyle style)
double outlineWidth() const
Returns the width of the marker&#39;s outline.
Q_DECL_DEPRECATED bool prepareShape(const QString &name=QString())
QgsSymbolV2::ScaleMethod mScaleMethod
Marker size scaling method.
static QString symbolNameToPath(QString name)
Get symbol&#39;s path from its name.
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const
bool forceVectorOutput() const
void setLayer(const QString &layer)
void setSizeUnit(QgsSymbolV2::OutputUnit unit)
Sets the units for the symbol&#39;s size.
virtual QColor color() const override
The fill color.
static bool externalMarkerFromSld(QDomElement &element, QString &path, QString &format, int &markIndex, QColor &color, double &size)
QPaintDevice * device() const
QgsMapUnitScale mapUnitScale() const override
void setWidthF(qreal width)
QgsStringMap properties() const override
Should be reimplemented by subclasses to return a string map that contains the configuration informat...
void stopRender(QgsSymbolV2RenderContext &context) override
void setBrush(const QBrush &brush)
double rasterScaleFactor() const
QgsStringMap properties() const override
Should be reimplemented by subclasses to return a string map that contains the configuration informat...
Q_DECL_DEPRECATED void writeFilledCircle(const QString &layer, const QColor &color, const QgsPoint &pt, double radius)
Write filled circle (as hatch)
static QString encodeShape(Shape shape)
Encodes a shape to its string representation.
#define DEFAULT_FONTMARKER_ANGLE
QgsSymbolV2::OutputUnit outputUnit() const override
static const QString EXPR_FILL
virtual QColor color() const
The fill color.
const QByteArray & svgContent(const QString &file, double size, const QColor &fill, const QColor &outline, double outlineWidth, double widthScaleFactor, double rasterScaleFactor)
Get SVG content.
static QgsSymbolLayerV2 * createFromSld(QDomElement &element)
HorizontalAnchorPoint mHorizontalAnchorPoint
Horizontal anchor point.
ushort unicode() const
QgsSvgMarkerSymbolLayerV2 * clone() const override
Shall be reimplemented by subclasses to create a deep copy of the instance.
static double estimateMaxSymbolBleed(QgsSymbolV2 *symbol)
Returns the maximum estimated bleed for the symbol.
void setColor(const QColor &color)
virtual Q_DECL_DEPRECATED void prepareExpressions(const QgsFields *fields, double scale=-1.0)
Prepares all data defined property expressions for evaluation.
virtual double estimateMaxBleed() const override
Returns the estimated maximum distance which the layer style will bleed outside the drawn shape...
void renderPoint(QPointF point, QgsSymbolV2RenderContext &context) override
Renders a marker at the specified point.
void setOutlineWidthMapUnitScale(const QgsMapUnitScale &scale)
double mAngle
Marker rotation angle, in degrees clockwise from north.
bool shapeToPolygon(Shape shape, QPolygonF &polygon) const
Creates a polygon representing the specified shape.
static Qt::PenStyle decodePenStyle(const QString &str)
double mLineAngle
Line rotation angle (see setLineAngle() for details)
QgsSymbolV2::ScaleMethod scaleMethod() const
Returns the method to use for scaling the marker&#39;s size.
static const QString EXPR_OUTLINE_STYLE
Q_DECL_DEPRECATED void writePolyline(const QgsPolyline &line, const QString &layer, const QString &lineStyleName, const QColor &color, double width=-1)
Draw dxf primitives (LWPOLYLINE)
double size() const
Returns the symbol size.
int logicalDpiX() const
int logicalDpiY() const
virtual void setFillColor(const QColor &color)
Set fill color.
QgsSymbolV2::OutputUnit mOutlineWidthUnit
Outline width units.
T * data() const
#define DEFAULT_SVGMARKER_SIZE
QString toLower() const
void setOutlineWidth(double width)
Set outline width.
static const QString EXPR_COLOR
QBrush mBrush
QBrush corresponding to marker&#39;s fill style.
static const QString EXPR_ANGLE
static QgsSymbolLayerV2 * create(const QgsStringMap &properties=QgsStringMap())
Creates a new QgsFilledMarkerSymbolLayer.
QgsSimpleMarkerSymbolLayerBase(Shape shape=Circle, double size=DEFAULT_SIMPLEMARKER_SIZE, double angle=DEFAULT_SIMPLEMARKER_ANGLE, QgsSymbolV2::ScaleMethod scaleMethod=DEFAULT_SCALE_METHOD)
Constructor for QgsSimpleMarkerSymbolLayerBase.
QRect mapRect(const QRect &rectangle) const
int width(const QString &text, int len) const
void setOutlineWidthMapUnitScale(const QgsMapUnitScale &scale)
Sets the map scale for the width of the marker&#39;s outline.
QgsMapUnitScale mapUnitScale() const override
void startRender(QgsSymbolV2RenderContext &context) override
#define DEFAULT_FONTMARKER_SIZE
bool isNull() const
void restore()
void startRender(QgsSymbolV2RenderContext &context) override
static const QString EXPR_OUTLINE_WIDTH
QTransform & rotate(qreal angle, Qt::Axis axis)
#define DEFAULT_FONTMARKER_FONT
#define DEFAULT_SVGMARKER_NAME
QMatrix & rotate(qreal degrees)
void setBorderColor(const QColor &color)
Sets the marker&#39;s border color.
virtual QColor outlineColor() const
Get outline color.
#define DEFAULT_SIMPLEMARKER_SIZE
Q_DECL_DEPRECATED void writeCircle(const QString &layer, const QColor &color, const QgsPoint &pt, double radius, const QString &lineStyleName, double width)
Write circle (as polyline)
void setShift(QPointF shift)
VerticalAnchorPoint
Symbol vertical anchor points.
void drawImage(const QRectF &target, const QImage &image, const QRectF &source, QFlags< Qt::ImageConversionFlag > flags)
QPainter * painter()
QString mid(int position, int n) const
void drawPath(const QPainterPath &path)
static double lineWidthScaleFactor(const QgsRenderContext &c, QgsSymbolV2::OutputUnit u, const QgsMapUnitScale &scale=QgsMapUnitScale())
Returns the line width scale factor depending on the unit and the paint device.
QSet< T > & unite(const QSet< T > &other)
Qt::PenJoinStyle penJoinStyle() const
Returns the marker&#39;s outline join style (eg miter, bevel, etc).
static QgsSymbolLayerV2 * create(const QgsStringMap &properties=QgsStringMap())
void setOutputUnit(QgsSymbolV2::OutputUnit unit) override
ScaleMethod
Scale method.
Definition: qgssymbolv2.h:87
Struct for storing maximum and minimum scales for measurements in map units.
QgsMapUnitScale mapUnitScale() const override
#define DEFAULT_FONTMARKER_BORDERCOLOR
Qt::PenStyle outlineStyle() const
Returns the marker&#39;s outline style (eg solid, dashed, etc)
QImage mSelCache
Cached image of selected marker, if using cached version.
static const QString EXPR_NAME
QgsSvgMarkerSymbolLayerV2(const QString &name=DEFAULT_SVGMARKER_NAME, double size=DEFAULT_SVGMARKER_SIZE, double angle=DEFAULT_SVGMARKER_ANGLE, QgsSymbolV2::ScaleMethod scaleMethod=DEFAULT_SCALE_METHOD)
bool isEmpty() const
void writeSldMarker(QDomDocument &doc, QDomElement &element, const QgsStringMap &props) const override
Writes the symbol layer definition as a SLD XML element.
static QString encodeScaleMethod(QgsSymbolV2::ScaleMethod scaleMethod)
QgsRenderContext & renderContext()
Definition: qgssymbolv2.h:349
QDomElement firstChildElement(const QString &tagName) const
Q_DECL_DEPRECATED bool preparePath(QString name=QString())
QPen mSelPen
QPen to use as outline of selected symbols.
QPen mPen
QPen corresponding to marker&#39;s outline style.
QSet< QString > usedAttributes() const override
Returns the set of attributes referenced by the layer.
int height() const
int count(const T &value) const
Fill symbol.
Definition: qgssymbolv2.h:80
static const QString EXPR_COLOR_BORDER
const QgsGeometry * constGeometry() const
Gets a const pointer to the geometry object associated with this feature.
Definition: qgsfeature.cpp:82
Q_DECL_DEPRECATED void writePolygon(const QgsPolygon &polygon, const QString &layer, const QString &hatchPattern, const QColor &color)
Draw dxf filled polygon (HATCH)
Flags flags() const
Return combination of flags used for rendering.
qreal widthF() const
void translate(const QPointF &offset)
const QgsMapToPixel & mapToPixel() const
const QgsFields * fields() const
Fields of the layer.
Definition: qgssymbolv2.h:384
QgsSymbolV2::OutputUnit mOffsetUnit
Offset units.
double outlineWidth() const
Get outline width.
void setAlphaF(qreal alpha)
virtual void setColor(const QColor &color)
The fill color.
void startRender(QgsSymbolV2RenderContext &context) override
static bool rotationFromSldElement(QDomElement &element, QString &rotationFunc)
bool selected() const
Definition: qgssymbolv2.h:370
int height() const
QString layerType() const override
Returns a string that represents this layer type.
double toDouble(bool *ok) const
static QColor decodeColor(const QString &str)
void startRender(QgsSymbolV2RenderContext &context) override
Abstract base class for marker symbol layers.
VerticalAnchorPoint mVerticalAnchorPoint
Vertical anchor point.
QgsSymbolV2::OutputUnit mSizeUnit
Marker size unit.
void setOutlineWidthUnit(QgsSymbolV2::OutputUnit unit)
Set outline width unit.
Calculate scale by the area.
Definition: qgssymbolv2.h:89
QgsMapUnitScale mOffsetMapUnitScale
Offset map unit scale.
void drawPicture(const QPointF &point, const QPicture &picture)
static const QString EXPR_OUTLINE
QRectF bounds(QPointF point, QgsSymbolV2RenderContext &context) override
Returns the approximate bounding box of the marker symbol layer, taking into account any data defined...
HorizontalAnchorPoint
Symbol horizontal anchor points.
void restoreDataDefinedProperties(const QgsStringMap &stringMap)
Restores all data defined properties from string map.
static QgsMapUnitScale decodeMapUnitScale(const QString &str)
Qt::PenJoinStyle mPenJoinStyle
Outline pen join style.
int height() const
double mSize
Marker size.
QDomElement createElement(const QString &tagName)
bool prepareMarkerShape(Shape shape)
Prepares the layer for drawing the specified shape (QPolygonF version)
qreal height() const
#define DEFAULT_SIMPLEMARKER_JOINSTYLE
Q_DECL_DEPRECATED QgsSimpleMarkerSymbolLayerV2(const QString &name, const QColor &color=DEFAULT_SIMPLEMARKER_COLOR, const QColor &borderColor=DEFAULT_SIMPLEMARKER_BORDERCOLOR, double size=DEFAULT_SIMPLEMARKER_SIZE, double angle=DEFAULT_SIMPLEMARKER_ANGLE, QgsSymbolV2::ScaleMethod scaleMethod=DEFAULT_SCALE_METHOD, Qt::PenJoinStyle penJoinStyle=DEFAULT_SIMPLEMARKER_JOINSTYLE)
Constructor for QgsSimpleMarkerSymbolLayerV2.
Filled marker symbol layer, consisting of a shape which is rendered using a QgsFillSymbolV2.
int size() const
void setAngle(double angle)
Sets the rotation angle for the marker.
bool begin(QPaintDevice *device)
QPointF offset() const
Returns the marker&#39;s offset, which is the horizontal and vertical displacement which the rendered mar...
static QgsSymbolLayerV2 * createFromSld(QDomElement &element)
void arcTo(const QRectF &rectangle, qreal startAngle, qreal sweepLength)
void setColor(const QColor &color)
void stopRender(QgsSymbolV2RenderContext &context) override
QgsFontMarkerSymbolLayerV2 * clone() const override
Shall be reimplemented by subclasses to create a deep copy of the instance.
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
QString toString() const
void saveDataDefinedProperties(QgsStringMap &stringMap) const
Saves all data defined properties to a string map.
QPointF mOffset
Marker offset.
void setSizeMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale for the symbol&#39;s size.
QColor outlineColor() const override
Get outline color.
QPolygonF mPolygon
Polygon of points in shape. If polygon is empty then shape is using mPath.
QgsFilledMarkerSymbolLayer * clone() const override
Shall be reimplemented by subclasses to create a deep copy of the instance.
QgsSimpleMarkerSymbolLayerV2 * clone() const override
Shall be reimplemented by subclasses to create a deep copy of the instance.
void setOutputUnit(QgsSymbolV2::OutputUnit unit) override
QRect mapRect(const QRect &rectangle) const
qreal width() const
static bool shapeIsFilled(Shape shape)
Returns true if a symbol shape has a fill.
bool prepareCache(QgsSymbolV2RenderContext &context)
Prepares cache image.
Simple marker symbol layer, consisting of a rendered shape with solid fill color and an outline...
bool prepareMarkerPath(Shape symbol)
Prepares the layer for drawing the specified shape (QPainterPath version)
static const int mMaximumCacheWidth
Maximum width/height of cache image.
Shape shape() const
Returns the shape for the rendered marker symbol.
void copyDataDefinedProperties(QgsSymbolLayerV2 *destLayer) const
Copies all data defined properties of this layer to another symbol layer.
void setOutputSize(const QRectF &r)
const T value(const Key &key) const
virtual bool setSubSymbol(QgsSymbolV2 *symbol) override
set layer&#39;s subsymbol. takes ownership of the passed symbol
static Q_DECL_DEPRECATED void wellKnownMarkerToSld(QDomDocument &doc, QDomElement &element, const QString &name, const QColor &color, const QColor &borderColor=QColor(), double borderWidth=-1, double size=-1)
virtual Q_DECL_DEPRECATED QVariant evaluateDataDefinedProperty(const QString &property, const QgsFeature *feature, const QVariant &defaultVal=QVariant(), bool *ok=nullptr) const
Evaluates the matching data defined property and returns the calculated value.
#define DEFAULT_SIMPLEMARKER_BORDERCOLOR
QBrush mSelBrush
QBrush to use as fill of selected symbols.