QGIS API Documentation  2.17.0-Master (8784312)
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 
1520 {
1521  if ( shapeIsFilled( mShape ) )
1522  {
1523  setFillColor( color );
1524  }
1525  else
1526  {
1527  setOutlineColor( color );
1528  }
1529 }
1530 
1532 {
1533  if ( shapeIsFilled( mShape ) )
1534  {
1535  return fillColor();
1536  }
1537  else
1538  {
1539  return outlineColor();
1540  }
1541 }
1542 
1543 
1544 
1545 
1546 //
1547 // QgsFilledMarkerSymbolLayer
1548 //
1549 
1551  : QgsSimpleMarkerSymbolLayerBase( shape, size, angle, scaleMethod )
1552 {
1553  mFill.reset( static_cast<QgsFillSymbolV2*>( QgsFillSymbolV2::createSimple( QgsStringMap() ) ) );
1554 }
1555 
1557 {
1562 
1563  if ( props.contains( "name" ) )
1564  name = props["name"];
1565  if ( props.contains( "size" ) )
1566  size = props["size"].toDouble();
1567  if ( props.contains( "angle" ) )
1568  angle = props["angle"].toDouble();
1569  if ( props.contains( "scale_method" ) )
1570  scaleMethod = QgsSymbolLayerV2Utils::decodeScaleMethod( props["scale_method"] );
1571 
1572  QgsFilledMarkerSymbolLayer* m = new QgsFilledMarkerSymbolLayer( decodeShape( name ), size, angle, scaleMethod );
1573  if ( props.contains( "offset" ) )
1574  m->setOffset( QgsSymbolLayerV2Utils::decodePoint( props["offset"] ) );
1575  if ( props.contains( "offset_unit" ) )
1576  m->setOffsetUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["offset_unit"] ) );
1577  if ( props.contains( "offset_map_unit_scale" ) )
1578  m->setOffsetMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["offset_map_unit_scale"] ) );
1579  if ( props.contains( "size_unit" ) )
1580  m->setSizeUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["size_unit"] ) );
1581  if ( props.contains( "size_map_unit_scale" ) )
1582  m->setSizeMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["size_map_unit_scale"] ) );
1583  if ( props.contains( "horizontal_anchor_point" ) )
1584  {
1585  m->setHorizontalAnchorPoint( QgsMarkerSymbolLayerV2::HorizontalAnchorPoint( props[ "horizontal_anchor_point" ].toInt() ) );
1586  }
1587  if ( props.contains( "vertical_anchor_point" ) )
1588  {
1589  m->setVerticalAnchorPoint( QgsMarkerSymbolLayerV2::VerticalAnchorPoint( props[ "vertical_anchor_point" ].toInt() ) );
1590  }
1591 
1593 
1594  m->restoreDataDefinedProperties( props );
1595 
1596  return m;
1597 }
1598 
1600 {
1601  return "FilledMarker";
1602 }
1603 
1605 {
1606  if ( mFill.data() )
1607  {
1608  mFill->startRender( context.renderContext(), context.fields() );
1609  }
1610 
1612 }
1613 
1615 {
1616  if ( mFill.data() )
1617  {
1618  mFill->stopRender( context.renderContext() );
1619  }
1620 }
1621 
1623 {
1624  QgsStringMap map;
1625  map["name"] = encodeShape( mShape );
1626  map["size"] = QString::number( mSize );
1627  map["size_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mSizeUnit );
1628  map["size_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mSizeMapUnitScale );
1629  map["angle"] = QString::number( mAngle );
1630  map["offset"] = QgsSymbolLayerV2Utils::encodePoint( mOffset );
1631  map["offset_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOffsetUnit );
1632  map["offset_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOffsetMapUnitScale );
1633  map["scale_method"] = QgsSymbolLayerV2Utils::encodeScaleMethod( mScaleMethod );
1634  map["horizontal_anchor_point"] = QString::number( mHorizontalAnchorPoint );
1635  map["vertical_anchor_point"] = QString::number( mVerticalAnchorPoint );
1636 
1637  if ( mFill.data() )
1638  {
1639  map["color"] = QgsSymbolLayerV2Utils::encodeColor( mFill->color() );
1640  }
1641 
1642  //data define properties
1644  return map;
1645 }
1646 
1648 {
1650  copyPaintEffect( m );
1651  m->setSubSymbol( mFill->clone() );
1652  return m;
1653 }
1654 
1656 {
1657  return mFill.data();
1658 }
1659 
1661 {
1662  if ( symbol && symbol->type() == QgsSymbolV2::Fill )
1663  {
1664  mFill.reset( static_cast<QgsFillSymbolV2*>( symbol ) );
1665  return true;
1666  }
1667  else
1668  {
1669  delete symbol;
1670  return false;
1671  }
1672 }
1673 
1675 {
1676  if ( mFill.data() )
1677  {
1679  }
1680  return 0;
1681 }
1682 
1684 {
1686  if ( mFill.data() )
1687  attr.unite( mFill->usedAttributes() );
1688  return attr;
1689 }
1690 
1692 {
1693  mColor = c;
1694  if ( mFill.data() )
1695  mFill->setColor( c );
1696 }
1697 
1699 {
1700  return mFill.data() ? mFill->color() : mColor;
1701 }
1702 
1703 void QgsFilledMarkerSymbolLayer::draw( QgsSymbolV2RenderContext &context, QgsSimpleMarkerSymbolLayerBase::Shape shape, const QPolygonF &polygon, const QPainterPath &path )
1704 {
1705  //making changes here? Don't forget to also update ::bounds if the changes affect the bounding box
1706  //of the rendered point!
1707 
1708  QPainter *p = context.renderContext().painter();
1709  if ( !p )
1710  {
1711  return;
1712  }
1713 
1714  if ( shapeIsFilled( shape ) )
1715  {
1716  p->setBrush( Qt::red );
1717  }
1718  else
1719  {
1720  p->setBrush( Qt::NoBrush );
1721  }
1722  p->setPen( Qt::black );
1723 
1724  if ( !polygon.isEmpty() )
1725  {
1726  mFill->renderPolygon( polygon, /* rings */ nullptr, context.feature(), context.renderContext() );
1727  }
1728  else
1729  {
1730  QPolygonF poly = path.toFillPolygon();
1731  mFill->renderPolygon( poly, /* rings */ nullptr, context.feature(), context.renderContext() );
1732  }
1733 
1734 
1735 }
1736 
1737 
1739 
1740 
1742 {
1744  mSize = size;
1745  mAngle = angle;
1746  mOffset = QPointF( 0, 0 );
1748  mOutlineWidth = 0.2;
1749  mOutlineWidthUnit = QgsSymbolV2::MM;
1750  mColor = QColor( Qt::black );
1751  mOutlineColor = QColor( Qt::black );
1752 }
1753 
1754 
1756 {
1758  double size = DEFAULT_SVGMARKER_SIZE;
1759  double angle = DEFAULT_SVGMARKER_ANGLE;
1761 
1762  if ( props.contains( "name" ) )
1763  name = props["name"];
1764  if ( props.contains( "size" ) )
1765  size = props["size"].toDouble();
1766  if ( props.contains( "angle" ) )
1767  angle = props["angle"].toDouble();
1768  if ( props.contains( "scale_method" ) )
1769  scaleMethod = QgsSymbolLayerV2Utils::decodeScaleMethod( props["scale_method"] );
1770 
1771  QgsSvgMarkerSymbolLayerV2* m = new QgsSvgMarkerSymbolLayerV2( name, size, angle, scaleMethod );
1772 
1773  //we only check the svg default parameters if necessary, since it could be expensive
1774  if ( !props.contains( "fill" ) && !props.contains( "color" ) && !props.contains( "outline" ) &&
1775  !props.contains( "outline_color" ) && !props.contains( "outline-width" ) && !props.contains( "outline_width" ) )
1776  {
1778  double fillOpacity = 1.0;
1779  double outlineOpacity = 1.0;
1780  double outlineWidth;
1781  bool hasFillParam = false, hasFillOpacityParam = false, hasOutlineParam = false, hasOutlineWidthParam = false, hasOutlineOpacityParam = false;
1782  bool hasDefaultFillColor = false, hasDefaultFillOpacity = false, hasDefaultOutlineColor = false, hasDefaultOutlineWidth = false, hasDefaultOutlineOpacity = false;
1783  QgsSvgCache::instance()->containsParams( name, hasFillParam, hasDefaultFillColor, fillColor,
1784  hasFillOpacityParam, hasDefaultFillOpacity, fillOpacity,
1785  hasOutlineParam, hasDefaultOutlineColor, outlineColor,
1786  hasOutlineWidthParam, hasDefaultOutlineWidth, outlineWidth,
1787  hasOutlineOpacityParam, hasDefaultOutlineOpacity, outlineOpacity );
1788  if ( hasDefaultFillColor )
1789  {
1790  m->setFillColor( fillColor );
1791  }
1792  if ( hasDefaultFillOpacity )
1793  {
1794  QColor c = m->fillColor();
1795  c.setAlphaF( fillOpacity );
1796  m->setFillColor( c );
1797  }
1798  if ( hasDefaultOutlineColor )
1799  {
1800  m->setOutlineColor( outlineColor );
1801  }
1802  if ( hasDefaultOutlineWidth )
1803  {
1804  m->setOutlineWidth( outlineWidth );
1805  }
1806  if ( hasDefaultOutlineOpacity )
1807  {
1808  QColor c = m->outlineColor();
1809  c.setAlphaF( outlineOpacity );
1810  m->setOutlineColor( c );
1811  }
1812  }
1813 
1814  if ( props.contains( "size_unit" ) )
1815  m->setSizeUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["size_unit"] ) );
1816  if ( props.contains( "size_map_unit_scale" ) )
1817  m->setSizeMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["size_map_unit_scale"] ) );
1818  if ( props.contains( "offset" ) )
1819  m->setOffset( QgsSymbolLayerV2Utils::decodePoint( props["offset"] ) );
1820  if ( props.contains( "offset_unit" ) )
1821  m->setOffsetUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["offset_unit"] ) );
1822  if ( props.contains( "offset_map_unit_scale" ) )
1823  m->setOffsetMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["offset_map_unit_scale"] ) );
1824  if ( props.contains( "fill" ) )
1825  {
1826  //pre 2.5 projects used "fill"
1827  m->setFillColor( QgsSymbolLayerV2Utils::decodeColor( props["fill"] ) );
1828  }
1829  else if ( props.contains( "color" ) )
1830  {
1831  m->setFillColor( QgsSymbolLayerV2Utils::decodeColor( props["color"] ) );
1832  }
1833  if ( props.contains( "outline" ) )
1834  {
1835  //pre 2.5 projects used "outline"
1836  m->setOutlineColor( QgsSymbolLayerV2Utils::decodeColor( props["outline"] ) );
1837  }
1838  else if ( props.contains( "outline_color" ) )
1839  {
1840  m->setOutlineColor( QgsSymbolLayerV2Utils::decodeColor( props["outline_color"] ) );
1841  }
1842  else if ( props.contains( "line_color" ) )
1843  {
1844  m->setOutlineColor( QgsSymbolLayerV2Utils::decodeColor( props["line_color"] ) );
1845  }
1846 
1847  if ( props.contains( "outline-width" ) )
1848  {
1849  //pre 2.5 projects used "outline-width"
1850  m->setOutlineWidth( props["outline-width"].toDouble() );
1851  }
1852  else if ( props.contains( "outline_width" ) )
1853  {
1854  m->setOutlineWidth( props["outline_width"].toDouble() );
1855  }
1856  else if ( props.contains( "line_width" ) )
1857  {
1858  m->setOutlineWidth( props["line_width"].toDouble() );
1859  }
1860 
1861  if ( props.contains( "outline_width_unit" ) )
1862  {
1863  m->setOutlineWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["outline_width_unit"] ) );
1864  }
1865  else if ( props.contains( "line_width_unit" ) )
1866  {
1867  m->setOutlineWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["line_width_unit"] ) );
1868  }
1869  if ( props.contains( "outline_width_map_unit_scale" ) )
1870  m->setOutlineWidthMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["outline_width_map_unit_scale"] ) );
1871 
1872  if ( props.contains( "horizontal_anchor_point" ) )
1873  {
1874  m->setHorizontalAnchorPoint( QgsMarkerSymbolLayerV2::HorizontalAnchorPoint( props[ "horizontal_anchor_point" ].toInt() ) );
1875  }
1876  if ( props.contains( "vertical_anchor_point" ) )
1877  {
1878  m->setVerticalAnchorPoint( QgsMarkerSymbolLayerV2::VerticalAnchorPoint( props[ "vertical_anchor_point" ].toInt() ) );
1879  }
1880 
1881  m->restoreDataDefinedProperties( props );
1882 
1883  return m;
1884 }
1885 
1887 {
1888  mPath = path;
1889  QColor defaultFillColor, defaultOutlineColor;
1890  double outlineWidth, fillOpacity, outlineOpacity;
1891  bool hasFillParam = false, hasFillOpacityParam = false, hasOutlineParam = false, hasOutlineWidthParam = false, hasOutlineOpacityParam = false;
1892  bool hasDefaultFillColor = false, hasDefaultFillOpacity = false, hasDefaultOutlineColor = false, hasDefaultOutlineWidth = false, hasDefaultOutlineOpacity = false;
1893  QgsSvgCache::instance()->containsParams( path, hasFillParam, hasDefaultFillColor, defaultFillColor,
1894  hasFillOpacityParam, hasDefaultFillOpacity, fillOpacity,
1895  hasOutlineParam, hasDefaultOutlineColor, defaultOutlineColor,
1896  hasOutlineWidthParam, hasDefaultOutlineWidth, outlineWidth,
1897  hasOutlineOpacityParam, hasDefaultOutlineOpacity, outlineOpacity );
1898 
1899  double newFillOpacity = hasFillOpacityParam ? fillColor().alphaF() : 1.0;
1900  double newOutlineOpacity = hasOutlineOpacityParam ? outlineColor().alphaF() : 1.0;
1901 
1902  if ( hasDefaultFillColor )
1903  {
1904  defaultFillColor.setAlphaF( newFillOpacity );
1905  setFillColor( defaultFillColor );
1906  }
1907  if ( hasDefaultFillOpacity )
1908  {
1909  QColor c = fillColor();
1910  c.setAlphaF( fillOpacity );
1911  setFillColor( c );
1912  }
1913  if ( hasDefaultOutlineColor )
1914  {
1915  defaultOutlineColor.setAlphaF( newOutlineOpacity );
1916  setOutlineColor( defaultOutlineColor );
1917  }
1918  if ( hasDefaultOutlineWidth )
1919  {
1920  setOutlineWidth( outlineWidth );
1921  }
1922  if ( hasDefaultOutlineOpacity )
1923  {
1924  QColor c = outlineColor();
1925  c.setAlphaF( outlineOpacity );
1926  setOutlineColor( c );
1927  }
1928 }
1929 
1930 
1932 {
1933  return "SvgMarker";
1934 }
1935 
1937 {
1938  QgsMarkerSymbolLayerV2::startRender( context ); // get anchor point expressions
1939  Q_UNUSED( context );
1940  prepareExpressions( context );
1941 }
1942 
1944 {
1945  Q_UNUSED( context );
1946 }
1947 
1949 {
1950  QPainter *p = context.renderContext().painter();
1951  if ( !p )
1952  return;
1953 
1954  bool hasDataDefinedSize = false;
1955  double scaledSize = calculateSize( context, hasDataDefinedSize );
1957 
1958  //don't render symbols with size below one or above 10,000 pixels
1959  if ( static_cast< int >( size ) < 1 || 10000.0 < size )
1960  {
1961  return;
1962  }
1963 
1964  p->save();
1965 
1966  QPointF outputOffset;
1967  double angle = 0.0;
1968  calculateOffsetAndRotation( context, scaledSize, outputOffset, angle );
1969 
1970  p->translate( point + outputOffset );
1971 
1972  bool rotated = !qgsDoubleNear( angle, 0 );
1973  if ( rotated )
1974  p->rotate( angle );
1975 
1976  QString path = mPath;
1978  {
1979  context.setOriginalValueVariable( mPath );
1981  }
1982 
1983  double outlineWidth = mOutlineWidth;
1985  {
1986  context.setOriginalValueVariable( mOutlineWidth );
1987  outlineWidth = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_OUTLINE_WIDTH, context, mOutlineWidth ).toDouble();
1988  }
1989  outlineWidth = QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), outlineWidth, mOutlineWidthUnit, mOutlineWidthMapUnitScale );
1990 
1992  bool ok = false;
1994  {
1997  if ( ok )
1998  fillColor = QgsSymbolLayerV2Utils::decodeColor( colorString );
1999  }
2000 
2001  QColor outlineColor = mOutlineColor;
2003  {
2006  if ( ok )
2007  outlineColor = QgsSymbolLayerV2Utils::decodeColor( colorString );
2008  }
2009 
2010  bool fitsInCache = true;
2011  bool usePict = true;
2012  double hwRatio = 1.0;
2013  if ( !context.renderContext().forceVectorOutput() && !rotated )
2014  {
2015  usePict = false;
2016  const QImage& img = QgsSvgCache::instance()->svgAsImage( path, size, fillColor, outlineColor, outlineWidth,
2017  context.renderContext().scaleFactor(), context.renderContext().rasterScaleFactor(), fitsInCache );
2018  if ( fitsInCache && img.width() > 1 )
2019  {
2020  //consider transparency
2021  if ( !qgsDoubleNear( context.alpha(), 1.0 ) )
2022  {
2023  QImage transparentImage = img.copy();
2024  QgsSymbolLayerV2Utils::multiplyImageOpacity( &transparentImage, context.alpha() );
2025  p->drawImage( -transparentImage.width() / 2.0, -transparentImage.height() / 2.0, transparentImage );
2026  hwRatio = static_cast< double >( transparentImage.height() ) / static_cast< double >( transparentImage.width() );
2027  }
2028  else
2029  {
2030  p->drawImage( -img.width() / 2.0, -img.height() / 2.0, img );
2031  hwRatio = static_cast< double >( img.height() ) / static_cast< double >( img.width() );
2032  }
2033  }
2034  }
2035 
2036  if ( usePict || !fitsInCache )
2037  {
2038  p->setOpacity( context.alpha() );
2039  const QPicture& pct = QgsSvgCache::instance()->svgAsPicture( path, size, fillColor, outlineColor, outlineWidth,
2041 
2042  if ( pct.width() > 1 )
2043  {
2044  p->save();
2045  _fixQPictureDPI( p );
2046  p->drawPicture( 0, 0, pct );
2047  p->restore();
2048  hwRatio = static_cast< double >( pct.height() ) / static_cast< double >( pct.width() );
2049  }
2050  }
2051 
2052  if ( context.selected() )
2053  {
2054  QPen pen( context.renderContext().selectionColor() );
2056  if ( penWidth > size / 20 )
2057  {
2058  // keep the pen width from covering symbol
2059  penWidth = size / 20;
2060  }
2061  double penOffset = penWidth / 2;
2062  pen.setWidth( penWidth );
2063  p->setPen( pen );
2064  p->setBrush( Qt::NoBrush );
2065  double wSize = size + penOffset;
2066  double hSize = size * hwRatio + penOffset;
2067  p->drawRect( QRectF( -wSize / 2.0, -hSize / 2.0, wSize, hSize ) );
2068  }
2069 
2070  p->restore();
2071 
2073  {
2074  // workaround issue with nested QPictures forgetting antialiasing flag - see http://hub.qgis.org/issues/14960
2075  p->setRenderHint( QPainter::Antialiasing );
2076  }
2077 
2078 }
2079 
2080 double QgsSvgMarkerSymbolLayerV2::calculateSize( QgsSymbolV2RenderContext& context, bool& hasDataDefinedSize ) const
2081 {
2082  double scaledSize = mSize;
2084 
2085  bool ok = true;
2087  {
2088  context.setOriginalValueVariable( mSize );
2089  scaledSize = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_SIZE, context, mSize, &ok ).toDouble();
2090  }
2091 
2092  if ( hasDataDefinedSize && ok )
2093  {
2094  switch ( mScaleMethod )
2095  {
2097  scaledSize = sqrt( scaledSize );
2098  break;
2100  break;
2101  }
2102  }
2103 
2104  return scaledSize;
2105 }
2106 
2107 void QgsSvgMarkerSymbolLayerV2::calculateOffsetAndRotation( QgsSymbolV2RenderContext& context, double scaledSize, QPointF& offset, double& angle ) const
2108 {
2109  //offset
2110  double offsetX = 0;
2111  double offsetY = 0;
2112  markerOffset( context, scaledSize, scaledSize, offsetX, offsetY );
2113  offset = QPointF( offsetX, offsetY );
2114 
2115  angle = mAngle + mLineAngle;
2117  {
2118  context.setOriginalValueVariable( mAngle );
2120  }
2121 
2123  if ( hasDataDefinedRotation )
2124  {
2125  // For non-point markers, "dataDefinedRotation" means following the
2126  // shape (shape-data defined). For them, "field-data defined" does
2127  // not work at all. TODO: if "field-data defined" ever gets implemented
2128  // we'll need a way to distinguish here between the two, possibly
2129  // using another flag in renderHints()
2130  const QgsFeature* f = context.feature();
2131  if ( f )
2132  {
2133  const QgsGeometry *g = f->constGeometry();
2134  if ( g && g->type() == QGis::Point )
2135  {
2136  const QgsMapToPixel& m2p = context.renderContext().mapToPixel();
2137  angle += m2p.mapRotation();
2138  }
2139  }
2140  }
2141 
2142  if ( angle )
2143  offset = _rotatedOffset( offset, angle );
2144 }
2145 
2146 
2148 {
2149  QgsStringMap map;
2151  map["size"] = QString::number( mSize );
2152  map["size_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mSizeUnit );
2153  map["size_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mSizeMapUnitScale );
2154  map["angle"] = QString::number( mAngle );
2155  map["offset"] = QgsSymbolLayerV2Utils::encodePoint( mOffset );
2156  map["offset_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOffsetUnit );
2157  map["offset_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOffsetMapUnitScale );
2158  map["scale_method"] = QgsSymbolLayerV2Utils::encodeScaleMethod( mScaleMethod );
2159  map["color"] = QgsSymbolLayerV2Utils::encodeColor( mColor );
2160  map["outline_color"] = QgsSymbolLayerV2Utils::encodeColor( mOutlineColor );
2161  map["outline_width"] = QString::number( mOutlineWidth );
2162  map["outline_width_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOutlineWidthUnit );
2163  map["outline_width_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOutlineWidthMapUnitScale );
2164  map["horizontal_anchor_point"] = QString::number( mHorizontalAnchorPoint );
2165  map["vertical_anchor_point"] = QString::number( mVerticalAnchorPoint );
2166 
2168  return map;
2169 }
2170 
2172 {
2174  m->setColor( mColor );
2175  m->setOutlineColor( mOutlineColor );
2176  m->setOutlineWidth( mOutlineWidth );
2177  m->setOutlineWidthUnit( mOutlineWidthUnit );
2178  m->setOutlineWidthMapUnitScale( mOutlineWidthMapUnitScale );
2179  m->setOffset( mOffset );
2180  m->setOffsetUnit( mOffsetUnit );
2182  m->setSizeUnit( mSizeUnit );
2187  copyPaintEffect( m );
2188  return m;
2189 }
2190 
2192 {
2194  mOutlineWidthUnit = unit;
2195 }
2196 
2198 {
2200  if ( unit != mOutlineWidthUnit )
2201  {
2202  return QgsSymbolV2::Mixed;
2203  }
2204  return unit;
2205 }
2206 
2208 {
2210  mOutlineWidthMapUnitScale = scale;
2211 }
2212 
2214 {
2215  if ( QgsMarkerSymbolLayerV2::mapUnitScale() == mOutlineWidthMapUnitScale )
2216  {
2217  return mOutlineWidthMapUnitScale;
2218  }
2219  return QgsMapUnitScale();
2220 }
2221 
2223 {
2224  // <Graphic>
2225  QDomElement graphicElem = doc.createElement( "se:Graphic" );
2226  element.appendChild( graphicElem );
2227 
2228  QgsSymbolLayerV2Utils::externalGraphicToSld( doc, graphicElem, mPath, "image/svg+xml", mColor, mSize );
2229 
2230  // <Rotation>
2231  QString angleFunc;
2232  bool ok;
2233  double angle = props.value( "angle", "0" ).toDouble( &ok );
2234  if ( !ok )
2235  {
2236  angleFunc = QString( "%1 + %2" ).arg( props.value( "angle", "0" ) ).arg( mAngle );
2237  }
2238  else if ( !qgsDoubleNear( angle + mAngle, 0.0 ) )
2239  {
2240  angleFunc = QString::number( angle + mAngle );
2241  }
2242 
2243  QgsSymbolLayerV2Utils::createRotationElement( doc, graphicElem, angleFunc );
2244 
2245  // <Displacement>
2247 }
2248 
2250 {
2251  QgsDebugMsg( "Entered." );
2252 
2253  QDomElement graphicElem = element.firstChildElement( "Graphic" );
2254  if ( graphicElem.isNull() )
2255  return nullptr;
2256 
2257  QString path, mimeType;
2258  QColor fillColor;
2259  double size;
2260 
2261  if ( !QgsSymbolLayerV2Utils::externalGraphicFromSld( graphicElem, path, mimeType, fillColor, size ) )
2262  return nullptr;
2263 
2264  if ( mimeType != "image/svg+xml" )
2265  return nullptr;
2266 
2267  double angle = 0.0;
2268  QString angleFunc;
2269  if ( QgsSymbolLayerV2Utils::rotationFromSldElement( graphicElem, angleFunc ) )
2270  {
2271  bool ok;
2272  double d = angleFunc.toDouble( &ok );
2273  if ( ok )
2274  angle = d;
2275  }
2276 
2277  QPointF offset;
2279 
2281  m->setFillColor( fillColor );
2282  //m->setOutlineColor( outlineColor );
2283  //m->setOutlineWidth( outlineWidth );
2284  m->setAngle( angle );
2285  m->setOffset( offset );
2286  return m;
2287 }
2288 
2289 bool QgsSvgMarkerSymbolLayerV2::writeDxf( QgsDxfExport& e, double mmMapUnitScaleFactor, const QString& layerName, QgsSymbolV2RenderContext &context, QPointF shift ) const
2290 {
2291  Q_UNUSED( layerName );
2292  Q_UNUSED( shift ); //todo...
2293 
2294  //size
2295  double size = mSize;
2296 
2298 
2299  bool ok = true;
2301  {
2302  context.setOriginalValueVariable( mSize );
2304  }
2305 
2306  if ( hasDataDefinedSize && ok )
2307  {
2308  switch ( mScaleMethod )
2309  {
2311  size = sqrt( size );
2312  break;
2314  break;
2315  }
2316  }
2317 
2318  if ( mSizeUnit == QgsSymbolV2::MM )
2319  {
2320  size *= mmMapUnitScaleFactor;
2321  }
2322 
2323  double halfSize = size / 2.0;
2324 
2325  //offset, angle
2326  QPointF offset = mOffset;
2327 
2329  {
2332  if ( ok )
2333  offset = QgsSymbolLayerV2Utils::decodePoint( offsetString );
2334  }
2335  double offsetX = offset.x();
2336  double offsetY = offset.y();
2337  if ( mSizeUnit == QgsSymbolV2::MM )
2338  {
2339  offsetX *= mmMapUnitScaleFactor;
2340  offsetY *= mmMapUnitScaleFactor;
2341  }
2342 
2343  QPointF outputOffset( offsetX, offsetY );
2344 
2345  double angle = mAngle + mLineAngle;
2347  {
2348  context.setOriginalValueVariable( mAngle );
2350  }
2351  //angle = -angle; //rotation in Qt is counterclockwise
2352  if ( angle )
2353  outputOffset = _rotatedOffset( outputOffset, angle );
2354 
2355  QString path = mPath;
2357  {
2358  context.setOriginalValueVariable( mPath );
2360  }
2361 
2362  double outlineWidth = mOutlineWidth;
2364  {
2365  context.setOriginalValueVariable( mOutlineWidth );
2366  outlineWidth = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_OUTLINE_WIDTH, context, mOutlineWidth ).toDouble();
2367  }
2368  outlineWidth = QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), outlineWidth, mOutlineWidthUnit, mOutlineWidthMapUnitScale );
2369 
2372  {
2375  if ( ok )
2376  fillColor = QgsSymbolLayerV2Utils::decodeColor( colorString );
2377  }
2378 
2379  QColor outlineColor = mOutlineColor;
2381  {
2384  if ( ok )
2385  outlineColor = QgsSymbolLayerV2Utils::decodeColor( colorString );
2386  }
2387 
2388  const QByteArray &svgContent = QgsSvgCache::instance()->svgContent( path, size, fillColor, outlineColor, outlineWidth,
2389  context.renderContext().scaleFactor(),
2390  context.renderContext().rasterScaleFactor() );
2391 
2392  //if current entry image is 0: cache image for entry
2393  // checks to see if image will fit into cache
2394  //update stats for memory usage
2395  QSvgRenderer r( svgContent );
2396  if ( !r.isValid() )
2397  {
2398  return false;
2399  }
2400 
2401  QgsDxfPaintDevice pd( &e );
2402  pd.setDrawingSize( QSizeF( r.defaultSize() ) );
2403 
2404  QPainter p;
2405  p.begin( &pd );
2406  if ( !qgsDoubleNear( angle, 0.0 ) )
2407  {
2408  p.translate( r.defaultSize().width() / 2.0, r.defaultSize().height() / 2.0 );
2409  p.rotate( angle );
2410  p.translate( -r.defaultSize().width() / 2.0, -r.defaultSize().height() / 2.0 );
2411  }
2412  pd.setShift( shift );
2413  pd.setOutputSize( QRectF( -halfSize, -halfSize, size, size ) );
2414  pd.setLayer( layerName );
2415  r.render( &p );
2416  p.end();
2417  return true;
2418 }
2419 
2421 {
2422  bool hasDataDefinedSize = false;
2423  double scaledSize = calculateSize( context, hasDataDefinedSize );
2425 
2426  //don't render symbols with size below one or above 10,000 pixels
2427  if ( static_cast< int >( scaledSize ) < 1 || 10000.0 < scaledSize )
2428  {
2429  return QRectF();
2430  }
2431 
2432  QPointF outputOffset;
2433  double angle = 0.0;
2434  calculateOffsetAndRotation( context, scaledSize, outputOffset, angle );
2435 
2436  QString path = mPath;
2438  {
2439  context.setOriginalValueVariable( mPath );
2441  }
2442 
2443  double outlineWidth = mOutlineWidth;
2445  {
2446  context.setOriginalValueVariable( mOutlineWidth );
2447  outlineWidth = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_OUTLINE_WIDTH, context, mOutlineWidth ).toDouble();
2448  }
2449  outlineWidth = QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), outlineWidth, mOutlineWidthUnit, mOutlineWidthMapUnitScale );
2450 
2451  //need to get colors to take advantage of cached SVGs
2453  bool ok = false;
2455  {
2458  if ( ok )
2459  fillColor = QgsSymbolLayerV2Utils::decodeColor( colorString );
2460  }
2461 
2462  QColor outlineColor = mOutlineColor;
2464  {
2467  if ( ok )
2468  outlineColor = QgsSymbolLayerV2Utils::decodeColor( colorString );
2469  }
2470 
2471  QSizeF svgViewbox = QgsSvgCache::instance()->svgViewboxSize( path, scaledSize, fillColor, outlineColor, outlineWidth,
2472  context.renderContext().scaleFactor(),
2473  context.renderContext().rasterScaleFactor() );
2474 
2475  double scaledHeight = svgViewbox.isValid() ? scaledSize * svgViewbox.height() / svgViewbox.width() : scaledSize;
2476  double pixelSize = 1.0 / context.renderContext().rasterScaleFactor();
2477 
2478  QMatrix transform;
2479 
2480  // move to the desired position
2481  transform.translate( point.x() + outputOffset.x(), point.y() + outputOffset.y() );
2482 
2483  if ( !qgsDoubleNear( angle, 0.0 ) )
2484  transform.rotate( angle );
2485 
2486  //antialiasing
2487  outlineWidth += pixelSize / 2.0;
2488 
2489  QRectF symbolBounds = transform.mapRect( QRectF( -scaledSize / 2.0,
2490  -scaledHeight / 2.0,
2491  scaledSize,
2492  scaledHeight ) );
2493 
2494  //extend bounds by pen width / 2.0
2495  symbolBounds.adjust( -outlineWidth / 2.0, -outlineWidth / 2.0,
2496  outlineWidth / 2.0, outlineWidth / 2.0 );
2497 
2498  return symbolBounds;
2499 
2500 }
2501 
2503 
2504 QgsFontMarkerSymbolLayerV2::QgsFontMarkerSymbolLayerV2( const QString& fontFamily, QChar chr, double pointSize, const QColor& color, double angle )
2505  : mFontMetrics( nullptr )
2506  , mChrWidth( 0 )
2507 {
2509  mChr = chr;
2510  mColor = color;
2511  mAngle = angle;
2512  mSize = pointSize;
2513  mOrigSize = pointSize;
2515  mOffset = QPointF( 0, 0 );
2517  mOutlineColor = DEFAULT_FONTMARKER_BORDERCOLOR;
2518  mOutlineWidth = 0.0;
2519  mOutlineWidthUnit = QgsSymbolV2::MM;
2520  mPenJoinStyle = DEFAULT_FONTMARKER_JOINSTYLE;
2521 }
2522 
2524 {
2525  delete mFontMetrics;
2526 }
2527 
2529 {
2532  double pointSize = DEFAULT_FONTMARKER_SIZE;
2535 
2536  if ( props.contains( "font" ) )
2537  fontFamily = props["font"];
2538  if ( props.contains( "chr" ) && props["chr"].length() > 0 )
2539  chr = props["chr"].at( 0 );
2540  if ( props.contains( "size" ) )
2541  pointSize = props["size"].toDouble();
2542  if ( props.contains( "color" ) )
2543  color = QgsSymbolLayerV2Utils::decodeColor( props["color"] );
2544  if ( props.contains( "angle" ) )
2545  angle = props["angle"].toDouble();
2546 
2547  QgsFontMarkerSymbolLayerV2* m = new QgsFontMarkerSymbolLayerV2( fontFamily, chr, pointSize, color, angle );
2548 
2549  if ( props.contains( "outline_color" ) )
2550  m->setOutlineColor( QgsSymbolLayerV2Utils::decodeColor( props["outline_color"] ) );
2551  if ( props.contains( "outline_width" ) )
2552  m->setOutlineWidth( props["outline_width"].toDouble() );
2553  if ( props.contains( "offset" ) )
2554  m->setOffset( QgsSymbolLayerV2Utils::decodePoint( props["offset"] ) );
2555  if ( props.contains( "offset_unit" ) )
2556  m->setOffsetUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["offset_unit" ] ) );
2557  if ( props.contains( "offset_map_unit_scale" ) )
2558  m->setOffsetMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["offset_map_unit_scale" ] ) );
2559  if ( props.contains( "size_unit" ) )
2560  m->setSizeUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["size_unit"] ) );
2561  if ( props.contains( "size_map_unit_scale" ) )
2562  m->setSizeMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["size_map_unit_scale"] ) );
2563  if ( props.contains( "outline_width_unit" ) )
2564  m->setOutlineWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["outline_width_unit"] ) );
2565  if ( props.contains( "outline_width_map_unit_scale" ) )
2566  m->setOutlineWidthMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["outline_width_map_unit_scale"] ) );
2567  if ( props.contains( "joinstyle" ) )
2568  m->setPenJoinStyle( QgsSymbolLayerV2Utils::decodePenJoinStyle( props["joinstyle"] ) );
2569  if ( props.contains( "horizontal_anchor_point" ) )
2570  m->setHorizontalAnchorPoint( QgsMarkerSymbolLayerV2::HorizontalAnchorPoint( props[ "horizontal_anchor_point" ].toInt() ) );
2571  if ( props.contains( "vertical_anchor_point" ) )
2572  m->setVerticalAnchorPoint( QgsMarkerSymbolLayerV2::VerticalAnchorPoint( props[ "vertical_anchor_point" ].toInt() ) );
2573 
2574  m->restoreDataDefinedProperties( props );
2575 
2576  return m;
2577 }
2578 
2580 {
2581  return "FontMarker";
2582 }
2583 
2585 {
2586  QColor brushColor = mColor;
2587  QColor penColor = mOutlineColor;
2588 
2589  brushColor.setAlphaF( mColor.alphaF() * context.alpha() );
2590  penColor.setAlphaF( mOutlineColor.alphaF() * context.alpha() );
2591 
2592  mBrush = QBrush( brushColor );
2593  mPen = QPen( penColor );
2594  mPen.setJoinStyle( mPenJoinStyle );
2595  mPen.setWidthF( QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), mOutlineWidth, mOutlineWidthUnit, mOutlineWidthMapUnitScale ) );
2596 
2597  mFont = QFont( mFontFamily );
2599  delete mFontMetrics;
2600  mFontMetrics = new QFontMetrics( mFont );
2602  mChrOffset = QPointF( mChrWidth / 2.0, -mFontMetrics->ascent() / 2.0 );
2603  mOrigSize = mSize; // save in case the size would be data defined
2604  prepareExpressions( context );
2605 }
2606 
2608 {
2609  Q_UNUSED( context );
2610 }
2611 
2612 QString QgsFontMarkerSymbolLayerV2::characterToRender( QgsSymbolV2RenderContext& context, QPointF& charOffset, double& charWidth )
2613 {
2614  charOffset = mChrOffset;
2615  QString charToRender = mChr;
2617  {
2618  context.setOriginalValueVariable( mChr );
2620  if ( charToRender != mChr )
2621  {
2622  charWidth = mFontMetrics->width( charToRender );
2623  charOffset = QPointF( charWidth / 2.0, -mFontMetrics->ascent() / 2.0 );
2624  }
2625  }
2626  return charToRender;
2627 }
2628 
2629 void QgsFontMarkerSymbolLayerV2::calculateOffsetAndRotation( QgsSymbolV2RenderContext& context,
2630  double scaledSize,
2631  bool& hasDataDefinedRotation,
2632  QPointF& offset,
2633  double& angle ) const
2634 {
2635  //offset
2636  double offsetX = 0;
2637  double offsetY = 0;
2638  markerOffset( context, scaledSize, scaledSize, offsetX, offsetY );
2639  offset = QPointF( offsetX, offsetY );
2640 
2641  //angle
2642  bool ok = true;
2643  angle = mAngle + mLineAngle;
2644  bool usingDataDefinedRotation = false;
2646  {
2647  context.setOriginalValueVariable( angle );
2649  usingDataDefinedRotation = ok;
2650  }
2651 
2652  hasDataDefinedRotation = context.renderHints() & QgsSymbolV2::DataDefinedRotation || usingDataDefinedRotation;
2653  if ( hasDataDefinedRotation )
2654  {
2655  // For non-point markers, "dataDefinedRotation" means following the
2656  // shape (shape-data defined). For them, "field-data defined" does
2657  // not work at all. TODO: if "field-data defined" ever gets implemented
2658  // we'll need a way to distinguish here between the two, possibly
2659  // using another flag in renderHints()
2660  const QgsFeature* f = context.feature();
2661  if ( f )
2662  {
2663  const QgsGeometry *g = f->constGeometry();
2664  if ( g && g->type() == QGis::Point )
2665  {
2666  const QgsMapToPixel& m2p = context.renderContext().mapToPixel();
2667  angle += m2p.mapRotation();
2668  }
2669  }
2670  }
2671 
2672  if ( angle )
2673  offset = _rotatedOffset( offset, angle );
2674 }
2675 
2676 double QgsFontMarkerSymbolLayerV2::calculateSize( QgsSymbolV2RenderContext& context )
2677 {
2678  double scaledSize = mSize;
2680 
2681  bool ok = true;
2683  {
2684  context.setOriginalValueVariable( mSize );
2685  scaledSize = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_SIZE, context, mSize, &ok ).toDouble();
2686  }
2687 
2688  if ( hasDataDefinedSize && ok )
2689  {
2690  switch ( mScaleMethod )
2691  {
2693  scaledSize = sqrt( scaledSize );
2694  break;
2696  break;
2697  }
2698  }
2699  return scaledSize;
2700 }
2701 
2703 {
2704  QPainter *p = context.renderContext().painter();
2705  if ( !p )
2706  return;
2707 
2708  QTransform transform;
2709 
2710  bool ok;
2711  QColor brushColor = mColor;
2713  {
2716  if ( ok )
2717  brushColor = QgsSymbolLayerV2Utils::decodeColor( colorString );
2718  }
2719  brushColor = context.selected() ? context.renderContext().selectionColor() : brushColor;
2720  brushColor.setAlphaF( brushColor.alphaF() * context.alpha() );
2721  mBrush.setColor( brushColor );
2722 
2723  QColor penColor = mOutlineColor;
2725  {
2728  if ( ok )
2729  penColor = QgsSymbolLayerV2Utils::decodeColor( colorString );
2730  }
2731  penColor.setAlphaF( penColor.alphaF() * context.alpha() );
2732 
2733  double penWidth = QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), mOutlineWidth, mOutlineWidthUnit, mOutlineWidthMapUnitScale );
2735  {
2736  context.setOriginalValueVariable( mOutlineWidth );
2738  if ( ok )
2739  {
2740  penWidth = QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), outlineWidth, mOutlineWidthUnit, mOutlineWidthMapUnitScale );
2741  }
2742  }
2743 
2745  {
2748  if ( ok )
2749  {
2751  }
2752  }
2753 
2754  p->setBrush( mBrush );
2755  if ( !qgsDoubleNear( penWidth, 0.0 ) )
2756  {
2757  mPen.setColor( penColor );
2758  mPen.setWidthF( penWidth );
2759  p->setPen( mPen );
2760  }
2761  else
2762  {
2763  p->setPen( Qt::NoPen );
2764  }
2765  p->save();
2766 
2767  QPointF chrOffset = mChrOffset;
2768  double chrWidth;
2769  QString charToRender = characterToRender( context, chrOffset, chrWidth );
2770 
2771  double sizeToRender = calculateSize( context );
2772 
2773  bool hasDataDefinedRotation = false;
2774  QPointF offset;
2775  double angle = 0;
2776  calculateOffsetAndRotation( context, sizeToRender, hasDataDefinedRotation, offset, angle );
2777 
2778  transform.translate( point.x() + offset.x(), point.y() + offset.y() );
2779 
2780  if ( !qgsDoubleNear( angle, 0.0 ) )
2781  transform.rotate( angle );
2782 
2783  if ( !qgsDoubleNear( sizeToRender, mOrigSize ) )
2784  {
2785  double s = sizeToRender / mOrigSize;
2786  transform.scale( s, s );
2787  }
2788 
2789  QPainterPath path;
2790  path.addText( -chrOffset.x(), -chrOffset.y(), mFont, charToRender );
2791  p->drawPath( transform.map( path ) );
2792  p->restore();
2793 }
2794 
2796 {
2797  QgsStringMap props;
2798  props["font"] = mFontFamily;
2799  props["chr"] = mChr;
2800  props["size"] = QString::number( mSize );
2801  props["size_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mSizeUnit );
2802  props["size_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mSizeMapUnitScale );
2803  props["color"] = QgsSymbolLayerV2Utils::encodeColor( mColor );
2804  props["outline_color"] = QgsSymbolLayerV2Utils::encodeColor( mOutlineColor );
2805  props["outline_width"] = QString::number( mOutlineWidth );
2806  props["outline_width_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOutlineWidthUnit );
2807  props["outline_width_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOutlineWidthMapUnitScale );
2808  props["joinstyle"] = QgsSymbolLayerV2Utils::encodePenJoinStyle( mPenJoinStyle );
2809  props["angle"] = QString::number( mAngle );
2810  props["offset"] = QgsSymbolLayerV2Utils::encodePoint( mOffset );
2811  props["offset_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOffsetUnit );
2812  props["offset_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOffsetMapUnitScale );
2813  props["horizontal_anchor_point"] = QString::number( mHorizontalAnchorPoint );
2814  props["vertical_anchor_point"] = QString::number( mVerticalAnchorPoint );
2815 
2816  //data define properties
2817  saveDataDefinedProperties( props );
2818 
2819  return props;
2820 }
2821 
2823 {
2825  m->setOutlineColor( mOutlineColor );
2826  m->setOutlineWidth( mOutlineWidth );
2827  m->setOutlineWidthUnit( mOutlineWidthUnit );
2828  m->setOutlineWidthMapUnitScale( mOutlineWidthMapUnitScale );
2829  m->setPenJoinStyle( mPenJoinStyle );
2830  m->setOffset( mOffset );
2831  m->setOffsetUnit( mOffsetUnit );
2833  m->setSizeUnit( mSizeUnit );
2838  copyPaintEffect( m );
2839  return m;
2840 }
2841 
2843 {
2844  // <Graphic>
2845  QDomElement graphicElem = doc.createElement( "se:Graphic" );
2846  element.appendChild( graphicElem );
2847 
2848  QString fontPath = QString( "ttf://%1" ).arg( mFontFamily );
2849  int markIndex = mChr.unicode();
2850  QgsSymbolLayerV2Utils::externalMarkerToSld( doc, graphicElem, fontPath, "ttf", &markIndex, mColor, mSize );
2851 
2852  // <Rotation>
2853  QString angleFunc;
2854  bool ok;
2855  double angle = props.value( "angle", "0" ).toDouble( &ok );
2856  if ( !ok )
2857  {
2858  angleFunc = QString( "%1 + %2" ).arg( props.value( "angle", "0" ) ).arg( mAngle );
2859  }
2860  else if ( !qgsDoubleNear( angle + mAngle, 0.0 ) )
2861  {
2862  angleFunc = QString::number( angle + mAngle );
2863  }
2864  QgsSymbolLayerV2Utils::createRotationElement( doc, graphicElem, angleFunc );
2865 
2866  // <Displacement>
2868 }
2869 
2871 {
2872  QPointF chrOffset = mChrOffset;
2873  double chrWidth = mChrWidth;
2874  //calculate width of rendered character
2875  ( void )characterToRender( context, chrOffset, chrWidth );
2876 
2877  if ( !mFontMetrics )
2878  mFontMetrics = new QFontMetrics( mFont );
2879 
2880  double scaledSize = calculateSize( context );
2881  if ( !qgsDoubleNear( scaledSize, mOrigSize ) )
2882  {
2883  chrWidth *= scaledSize / mOrigSize;
2884  }
2885 
2886  bool hasDataDefinedRotation = false;
2887  QPointF offset;
2888  double angle = 0;
2889  calculateOffsetAndRotation( context, scaledSize, hasDataDefinedRotation, offset, angle );
2891 
2892  QMatrix transform;
2893 
2894  // move to the desired position
2895  transform.translate( point.x() + offset.x(), point.y() + offset.y() );
2896 
2897  if ( !qgsDoubleNear( angle, 0.0 ) )
2898  transform.rotate( angle );
2899 
2900  QRectF symbolBounds = transform.mapRect( QRectF( -chrWidth / 2.0,
2901  -scaledSize / 2.0,
2902  chrWidth,
2903  scaledSize ) );
2904  return symbolBounds;
2905 }
2906 
2908 {
2909  QgsDebugMsg( "Entered." );
2910 
2911  QDomElement graphicElem = element.firstChildElement( "Graphic" );
2912  if ( graphicElem.isNull() )
2913  return nullptr;
2914 
2915  QString name, format;
2916  QColor color;
2917  double size;
2918  int chr;
2919 
2920  if ( !QgsSymbolLayerV2Utils::externalMarkerFromSld( graphicElem, name, format, chr, color, size ) )
2921  return nullptr;
2922 
2923  if ( !name.startsWith( "ttf://" ) || format != "ttf" )
2924  return nullptr;
2925 
2926  QString fontFamily = name.mid( 6 );
2927 
2928  double angle = 0.0;
2929  QString angleFunc;
2930  if ( QgsSymbolLayerV2Utils::rotationFromSldElement( graphicElem, angleFunc ) )
2931  {
2932  bool ok;
2933  double d = angleFunc.toDouble( &ok );
2934  if ( ok )
2935  angle = d;
2936  }
2937 
2938  QPointF offset;
2940 
2941  QgsMarkerSymbolLayerV2 *m = new QgsFontMarkerSymbolLayerV2( fontFamily, chr, size, color );
2942  m->setAngle( angle );
2943  m->setOffset( offset );
2944  return m;
2945 }
2946 
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:65
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:379
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:107
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:93
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.
void setFillColor(const QColor &color) override
Set fill color.
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:492
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:353
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:372
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:69
QTransform & translate(qreal dx, qreal dy)
The output shall be in millimeters.
Definition: qgssymbolv2.h:67
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
void setColor(const QColor &color) override
The fill color.
const QgsFeature * feature() const
Current feature being rendered - may be null.
Definition: qgssymbolv2.h:384
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
virtual QColor color() const override
The fill color.
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:90
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:355
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:83
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
QColor fillColor() const override
Get fill color.
const QgsFields * fields() const
Fields of the layer.
Definition: qgssymbolv2.h:390
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:376
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:92
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
QColor outlineColor() const override
Get outline color.
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.
void setOutlineColor(const QColor &color) override
Set outline color.