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