QGIS API Documentation  2.17.0-Master (00653d2)
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 
1128  QgsSymbolLayerV2Utils::wellKnownMarkerToSld( doc, graphicElem, encodeShape( mShape ), mColor, mBorderColor, mOutlineStyle, outlineWidth, size );
1129 
1130  // <Rotation>
1131  QString angleFunc;
1132  bool ok;
1133  double angle = props.value( "angle", "0" ).toDouble( &ok );
1134  if ( !ok )
1135  {
1136  angleFunc = QString( "%1 + %2" ).arg( props.value( "angle", "0" ) ).arg( mAngle );
1137  }
1138  else if ( !qgsDoubleNear( angle + mAngle, 0.0 ) )
1139  {
1140  angleFunc = QString::number( angle + mAngle );
1141  }
1142  QgsSymbolLayerV2Utils::createRotationElement( doc, graphicElem, angleFunc );
1143 
1144  // <Displacement>
1146  QgsSymbolLayerV2Utils::createDisplacementElement( doc, graphicElem, offset );
1147 }
1148 
1149 QString QgsSimpleMarkerSymbolLayerV2::ogrFeatureStyle( double mmScaleFactor, double mapUnitScaleFactor ) const
1150 {
1151  Q_UNUSED( mmScaleFactor );
1152  Q_UNUSED( mapUnitScaleFactor );
1153 #if 0
1154  QString ogrType = "3"; //default is circle
1155  if ( mName == "square" )
1156  {
1157  ogrType = "5";
1158  }
1159  else if ( mName == "triangle" )
1160  {
1161  ogrType = "7";
1162  }
1163  else if ( mName == "star" )
1164  {
1165  ogrType = "9";
1166  }
1167  else if ( mName == "circle" )
1168  {
1169  ogrType = "3";
1170  }
1171  else if ( mName == "cross" )
1172  {
1173  ogrType = "0";
1174  }
1175  else if ( mName == "x" || mName == "cross2" )
1176  {
1177  ogrType = "1";
1178  }
1179  else if ( mName == "line" )
1180  {
1181  ogrType = "10";
1182  }
1183 
1184  QString ogrString;
1185  ogrString.append( "SYMBOL(" );
1186  ogrString.append( "id:" );
1187  ogrString.append( '\"' );
1188  ogrString.append( "ogr-sym-" );
1189  ogrString.append( ogrType );
1190  ogrString.append( '\"' );
1191  ogrString.append( ",c:" );
1192  ogrString.append( mColor.name() );
1193  ogrString.append( ",o:" );
1194  ogrString.append( mBorderColor.name() );
1195  ogrString.append( QString( ",s:%1mm" ).arg( mSize ) );
1196  ogrString.append( ')' );
1197  return ogrString;
1198 #endif //0
1199 
1200  QString ogrString;
1201  ogrString.append( "PEN(" );
1202  ogrString.append( "c:" );
1203  ogrString.append( mColor.name() );
1204  ogrString.append( ",w:" );
1205  ogrString.append( QString::number( mSize ) );
1206  ogrString.append( "mm" );
1207  ogrString.append( ")" );
1208  return ogrString;
1209 }
1210 
1212 {
1213  QgsDebugMsg( "Entered." );
1214 
1215  QDomElement graphicElem = element.firstChildElement( "Graphic" );
1216  if ( graphicElem.isNull() )
1217  return nullptr;
1218 
1219  QString name = "square";
1221  double borderWidth, size;
1222  Qt::PenStyle borderStyle;
1223 
1224  if ( !QgsSymbolLayerV2Utils::wellKnownMarkerFromSld( graphicElem, name, color, borderColor, borderStyle, borderWidth, size ) )
1225  return nullptr;
1226 
1227  double angle = 0.0;
1228  QString angleFunc;
1229  if ( QgsSymbolLayerV2Utils::rotationFromSldElement( graphicElem, angleFunc ) )
1230  {
1231  bool ok;
1232  double d = angleFunc.toDouble( &ok );
1233  if ( ok )
1234  angle = d;
1235  }
1236 
1237  QPointF offset;
1239 
1240  Shape shape = decodeShape( name );
1241 
1243  m->setColor( color );
1244  m->setBorderColor( borderColor );
1245  m->setAngle( angle );
1246  m->setOffset( offset );
1247  m->setOutlineStyle( borderStyle );
1248  return m;
1249 }
1250 
1252 {
1253  Q_UNUSED( context );
1254 
1255  if ( mPolygon.count() != 0 )
1256  {
1257  p->drawPolygon( mPolygon );
1258  }
1259  else
1260  {
1261  p->drawPath( mPath );
1262  }
1263 }
1264 
1265 bool QgsSimpleMarkerSymbolLayerV2::writeDxf( QgsDxfExport& e, double mmMapUnitScaleFactor, const QString& layerName, QgsSymbolV2RenderContext &context, QPointF shift ) const
1266 {
1267  //data defined size?
1268  double size = mSize;
1269 
1271 
1272  //data defined size
1273  bool ok = true;
1274  if ( hasDataDefinedSize )
1275  {
1277  {
1278  context.setOriginalValueVariable( mSize );
1280  }
1281 
1282  if ( ok )
1283  {
1284  switch ( mScaleMethod )
1285  {
1287  size = sqrt( size );
1288  break;
1290  break;
1291  }
1292  }
1293 
1295  }
1296  if ( mSizeUnit == QgsSymbolV2::MM )
1297  {
1298  size *= mmMapUnitScaleFactor;
1299  }
1300  double halfSize = size / 2.0;
1301 
1302  //outlineWidth
1303  double outlineWidth = mOutlineWidth;
1304 
1306  {
1309  }
1310  if ( mSizeUnit == QgsSymbolV2::MM )
1311  {
1312  outlineWidth *= mmMapUnitScaleFactor;
1313  }
1314 
1315  //color
1316  QColor pc = mPen.color();
1317  QColor bc = mBrush.color();
1319  {
1322  if ( ok )
1323  bc = QgsSymbolLayerV2Utils::decodeColor( colorString );
1324  }
1326  {
1329  if ( ok )
1330  pc = QgsSymbolLayerV2Utils::decodeColor( colorString );
1331  }
1332 
1333  //offset
1334  double offsetX = 0;
1335  double offsetY = 0;
1336  markerOffset( context, offsetX, offsetY );
1337 
1338  QPointF off( offsetX, offsetY );
1339 
1340  //angle
1341  double angle = mAngle + mLineAngle;
1343  {
1344  context.setOriginalValueVariable( mAngle );
1346  }
1347 
1348  Shape shape = mShape;
1350  {
1351  context.setOriginalValueVariable( encodeShape( shape ) );
1353  if ( ok )
1354  {
1355  shape = decodeShape( shapeName, &ok );
1356  if ( !ok )
1357  shape = mShape;
1358  }
1359  }
1360 
1361  angle = -angle; //rotation in Qt is counterclockwise
1362  if ( angle )
1363  off = _rotatedOffset( off, angle );
1364 
1365  if ( mSizeUnit == QgsSymbolV2::MM )
1366  {
1367  off *= mmMapUnitScaleFactor;
1368  }
1369 
1370  QTransform t;
1371  t.translate( shift.x() + offsetX, shift.y() + offsetY );
1372 
1373  if ( !qgsDoubleNear( angle, 0.0 ) )
1374  t.rotate( angle );
1375 
1376  QPolygonF polygon;
1377  if ( shapeToPolygon( shape, polygon ) )
1378  {
1379  t.scale( halfSize, -halfSize );
1380 
1381  polygon = t.map( polygon );
1382 
1384  for ( int i = 0; i < polygon.size(); i++ )
1385  p << QgsPointV2( polygon[i] );
1386  p << p[0];
1387 
1388  if ( mBrush.style() != Qt::NoBrush )
1389  e.writePolygon( QgsRingSequenceV2() << p, layerName, "SOLID", bc );
1390  if ( mPen.style() != Qt::NoPen )
1391  e.writePolyline( p, layerName, "CONTINUOUS", pc, outlineWidth );
1392  }
1393  else if ( shape == Circle )
1394  {
1395  if ( mBrush.style() != Qt::NoBrush )
1396  e.writeFilledCircle( layerName, bc, QgsPointV2( shift ), halfSize );
1397  if ( mPen.style() != Qt::NoPen )
1398  e.writeCircle( layerName, pc, QgsPointV2( shift ), halfSize, "CONTINUOUS", outlineWidth );
1399  }
1400  else if ( shape == Line )
1401  {
1402  QPointF pt1 = t.map( QPointF( 0, -halfSize ) );
1403  QPointF pt2 = t.map( QPointF( 0, halfSize ) );
1404 
1405  if ( mPen.style() != Qt::NoPen )
1406  e.writeLine( QgsPointV2( pt1 ), QgsPointV2( pt2 ), layerName, "CONTINUOUS", pc, outlineWidth );
1407  }
1408  else if ( shape == Cross )
1409  {
1410  if ( mPen.style() != Qt::NoPen )
1411  {
1412  QPointF pt1 = t.map( QPointF( -halfSize, 0 ) );
1413  QPointF pt2 = t.map( QPointF( halfSize, 0 ) );
1414  QPointF pt3 = t.map( QPointF( 0, -halfSize ) );
1415  QPointF pt4 = t.map( QPointF( 0, halfSize ) );
1416 
1417  e.writeLine( QgsPointV2( pt1 ), QgsPointV2( pt2 ), layerName, "CONTINUOUS", pc, outlineWidth );
1418  e.writeLine( QgsPointV2( pt3 ), QgsPointV2( pt4 ), layerName, "CONTINUOUS", pc, outlineWidth );
1419  }
1420  }
1421  else if ( shape == Cross2 )
1422  {
1423  if ( mPen.style() != Qt::NoPen )
1424  {
1425  QPointF pt1 = t.map( QPointF( -halfSize, -halfSize ) );
1426  QPointF pt2 = t.map( QPointF( halfSize, halfSize ) );
1427  QPointF pt3 = t.map( QPointF( halfSize, -halfSize ) );
1428  QPointF pt4 = t.map( QPointF( -halfSize, halfSize ) );
1429 
1430  e.writeLine( QgsPointV2( pt1 ), QgsPointV2( pt2 ), layerName, "CONTINUOUS", pc, outlineWidth );
1431  e.writeLine( QgsPointV2( pt3 ), QgsPointV2( pt4 ), layerName, "CONTINUOUS", pc, outlineWidth );
1432  }
1433  }
1434  else if ( shape == ArrowHead )
1435  {
1436  if ( mPen.style() != Qt::NoPen )
1437  {
1438  QPointF pt1 = t.map( QPointF( -halfSize, halfSize ) );
1439  QPointF pt2 = t.map( QPointF( 0, 0 ) );
1440  QPointF pt3 = t.map( QPointF( -halfSize, -halfSize ) );
1441 
1442  e.writeLine( QgsPointV2( pt1 ), QgsPointV2( pt2 ), layerName, "CONTINUOUS", pc, outlineWidth );
1443  e.writeLine( QgsPointV2( pt3 ), QgsPointV2( pt2 ), layerName, "CONTINUOUS", pc, outlineWidth );
1444  }
1445  }
1446  else
1447  {
1448  QgsDebugMsg( QString( "Unsupported dxf marker name %1" ).arg( encodeShape( shape ) ) );
1449  return false;
1450  }
1451 
1452  return true;
1453 }
1454 
1455 
1457 {
1459  mOutlineWidthUnit = unit;
1460 }
1461 
1463 {
1465  {
1466  return mOutlineWidthUnit;
1467  }
1468  return QgsSymbolV2::Mixed;
1469 }
1470 
1472 {
1474  mOutlineWidthMapUnitScale = scale;
1475 }
1476 
1478 {
1480  {
1482  }
1483  return QgsMapUnitScale();
1484 }
1485 
1487 {
1488  QRectF symbolBounds = QgsSimpleMarkerSymbolLayerBase::bounds( point, context );
1489 
1490  // need to account for outline width
1491  double pixelSize = 1.0 / context.renderContext().rasterScaleFactor();
1492  double penWidth = 0.0;
1493  bool ok = true;
1495  {
1498  if ( ok )
1499  {
1501  }
1502  }
1504  {
1507  if ( ok && outlineStyle == "no" )
1508  {
1509  penWidth = 0.0;
1510  }
1511  }
1512  //antialiasing
1513  penWidth += pixelSize;
1514 
1515  //extend bounds by pen width / 2.0
1516  symbolBounds.adjust( -penWidth / 2.0, -penWidth / 2.0,
1517  penWidth / 2.0, penWidth / 2.0 );
1518 
1519  return symbolBounds;
1520 }
1521 
1523 {
1524  if ( shapeIsFilled( mShape ) )
1525  {
1526  setFillColor( color );
1527  }
1528  else
1529  {
1530  setOutlineColor( color );
1531  }
1532 }
1533 
1535 {
1536  if ( shapeIsFilled( mShape ) )
1537  {
1538  return fillColor();
1539  }
1540  else
1541  {
1542  return outlineColor();
1543  }
1544 }
1545 
1546 
1547 
1548 
1549 //
1550 // QgsFilledMarkerSymbolLayer
1551 //
1552 
1554  : QgsSimpleMarkerSymbolLayerBase( shape, size, angle, scaleMethod )
1555 {
1556  mFill.reset( static_cast<QgsFillSymbolV2*>( QgsFillSymbolV2::createSimple( QgsStringMap() ) ) );
1557 }
1558 
1560 {
1565 
1566  if ( props.contains( "name" ) )
1567  name = props["name"];
1568  if ( props.contains( "size" ) )
1569  size = props["size"].toDouble();
1570  if ( props.contains( "angle" ) )
1571  angle = props["angle"].toDouble();
1572  if ( props.contains( "scale_method" ) )
1573  scaleMethod = QgsSymbolLayerV2Utils::decodeScaleMethod( props["scale_method"] );
1574 
1575  QgsFilledMarkerSymbolLayer* m = new QgsFilledMarkerSymbolLayer( decodeShape( name ), size, angle, scaleMethod );
1576  if ( props.contains( "offset" ) )
1577  m->setOffset( QgsSymbolLayerV2Utils::decodePoint( props["offset"] ) );
1578  if ( props.contains( "offset_unit" ) )
1579  m->setOffsetUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["offset_unit"] ) );
1580  if ( props.contains( "offset_map_unit_scale" ) )
1581  m->setOffsetMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["offset_map_unit_scale"] ) );
1582  if ( props.contains( "size_unit" ) )
1583  m->setSizeUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["size_unit"] ) );
1584  if ( props.contains( "size_map_unit_scale" ) )
1585  m->setSizeMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["size_map_unit_scale"] ) );
1586  if ( props.contains( "horizontal_anchor_point" ) )
1587  {
1588  m->setHorizontalAnchorPoint( QgsMarkerSymbolLayerV2::HorizontalAnchorPoint( props[ "horizontal_anchor_point" ].toInt() ) );
1589  }
1590  if ( props.contains( "vertical_anchor_point" ) )
1591  {
1592  m->setVerticalAnchorPoint( QgsMarkerSymbolLayerV2::VerticalAnchorPoint( props[ "vertical_anchor_point" ].toInt() ) );
1593  }
1594 
1596 
1597  m->restoreDataDefinedProperties( props );
1598 
1599  return m;
1600 }
1601 
1603 {
1604  return "FilledMarker";
1605 }
1606 
1608 {
1609  if ( mFill.data() )
1610  {
1611  mFill->startRender( context.renderContext(), context.fields() );
1612  }
1613 
1615 }
1616 
1618 {
1619  if ( mFill.data() )
1620  {
1621  mFill->stopRender( context.renderContext() );
1622  }
1623 }
1624 
1626 {
1627  QgsStringMap map;
1628  map["name"] = encodeShape( mShape );
1629  map["size"] = QString::number( mSize );
1630  map["size_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mSizeUnit );
1631  map["size_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mSizeMapUnitScale );
1632  map["angle"] = QString::number( mAngle );
1633  map["offset"] = QgsSymbolLayerV2Utils::encodePoint( mOffset );
1634  map["offset_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOffsetUnit );
1635  map["offset_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOffsetMapUnitScale );
1636  map["scale_method"] = QgsSymbolLayerV2Utils::encodeScaleMethod( mScaleMethod );
1637  map["horizontal_anchor_point"] = QString::number( mHorizontalAnchorPoint );
1638  map["vertical_anchor_point"] = QString::number( mVerticalAnchorPoint );
1639 
1640  if ( mFill.data() )
1641  {
1642  map["color"] = QgsSymbolLayerV2Utils::encodeColor( mFill->color() );
1643  }
1644 
1645  //data define properties
1647  return map;
1648 }
1649 
1651 {
1653  copyPaintEffect( m );
1654  m->setSubSymbol( mFill->clone() );
1655  return m;
1656 }
1657 
1659 {
1660  return mFill.data();
1661 }
1662 
1664 {
1665  if ( symbol && symbol->type() == QgsSymbolV2::Fill )
1666  {
1667  mFill.reset( static_cast<QgsFillSymbolV2*>( symbol ) );
1668  return true;
1669  }
1670  else
1671  {
1672  delete symbol;
1673  return false;
1674  }
1675 }
1676 
1678 {
1679  if ( mFill.data() )
1680  {
1682  }
1683  return 0;
1684 }
1685 
1687 {
1689  if ( mFill.data() )
1690  attr.unite( mFill->usedAttributes() );
1691  return attr;
1692 }
1693 
1695 {
1696  mColor = c;
1697  if ( mFill.data() )
1698  mFill->setColor( c );
1699 }
1700 
1702 {
1703  return mFill.data() ? mFill->color() : mColor;
1704 }
1705 
1706 void QgsFilledMarkerSymbolLayer::draw( QgsSymbolV2RenderContext &context, QgsSimpleMarkerSymbolLayerBase::Shape shape, const QPolygonF &polygon, const QPainterPath &path )
1707 {
1708  //making changes here? Don't forget to also update ::bounds if the changes affect the bounding box
1709  //of the rendered point!
1710 
1711  QPainter *p = context.renderContext().painter();
1712  if ( !p )
1713  {
1714  return;
1715  }
1716 
1717  if ( shapeIsFilled( shape ) )
1718  {
1719  p->setBrush( Qt::red );
1720  }
1721  else
1722  {
1723  p->setBrush( Qt::NoBrush );
1724  }
1725  p->setPen( Qt::black );
1726 
1727  if ( !polygon.isEmpty() )
1728  {
1729  mFill->renderPolygon( polygon, /* rings */ nullptr, context.feature(), context.renderContext(), -1, context.selected() );
1730  }
1731  else
1732  {
1733  QPolygonF poly = path.toFillPolygon();
1734  mFill->renderPolygon( poly, /* rings */ nullptr, context.feature(), context.renderContext(), -1, context.selected() );
1735  }
1736 
1737 
1738 }
1739 
1740 
1742 
1743 
1745 {
1747  mSize = size;
1748  mAngle = angle;
1749  mOffset = QPointF( 0, 0 );
1751  mOutlineWidth = 0.2;
1752  mOutlineWidthUnit = QgsSymbolV2::MM;
1753  mColor = QColor( Qt::black );
1754  mOutlineColor = QColor( Qt::black );
1755 }
1756 
1757 
1759 {
1761  double size = DEFAULT_SVGMARKER_SIZE;
1762  double angle = DEFAULT_SVGMARKER_ANGLE;
1764 
1765  if ( props.contains( "name" ) )
1766  name = props["name"];
1767  if ( props.contains( "size" ) )
1768  size = props["size"].toDouble();
1769  if ( props.contains( "angle" ) )
1770  angle = props["angle"].toDouble();
1771  if ( props.contains( "scale_method" ) )
1772  scaleMethod = QgsSymbolLayerV2Utils::decodeScaleMethod( props["scale_method"] );
1773 
1774  QgsSvgMarkerSymbolLayerV2* m = new QgsSvgMarkerSymbolLayerV2( name, size, angle, scaleMethod );
1775 
1776  //we only check the svg default parameters if necessary, since it could be expensive
1777  if ( !props.contains( "fill" ) && !props.contains( "color" ) && !props.contains( "outline" ) &&
1778  !props.contains( "outline_color" ) && !props.contains( "outline-width" ) && !props.contains( "outline_width" ) )
1779  {
1781  double fillOpacity = 1.0;
1782  double outlineOpacity = 1.0;
1783  double outlineWidth;
1784  bool hasFillParam = false, hasFillOpacityParam = false, hasOutlineParam = false, hasOutlineWidthParam = false, hasOutlineOpacityParam = false;
1785  bool hasDefaultFillColor = false, hasDefaultFillOpacity = false, hasDefaultOutlineColor = false, hasDefaultOutlineWidth = false, hasDefaultOutlineOpacity = false;
1786  QgsSvgCache::instance()->containsParams( name, hasFillParam, hasDefaultFillColor, fillColor,
1787  hasFillOpacityParam, hasDefaultFillOpacity, fillOpacity,
1788  hasOutlineParam, hasDefaultOutlineColor, outlineColor,
1789  hasOutlineWidthParam, hasDefaultOutlineWidth, outlineWidth,
1790  hasOutlineOpacityParam, hasDefaultOutlineOpacity, outlineOpacity );
1791  if ( hasDefaultFillColor )
1792  {
1793  m->setFillColor( fillColor );
1794  }
1795  if ( hasDefaultFillOpacity )
1796  {
1797  QColor c = m->fillColor();
1798  c.setAlphaF( fillOpacity );
1799  m->setFillColor( c );
1800  }
1801  if ( hasDefaultOutlineColor )
1802  {
1803  m->setOutlineColor( outlineColor );
1804  }
1805  if ( hasDefaultOutlineWidth )
1806  {
1807  m->setOutlineWidth( outlineWidth );
1808  }
1809  if ( hasDefaultOutlineOpacity )
1810  {
1811  QColor c = m->outlineColor();
1812  c.setAlphaF( outlineOpacity );
1813  m->setOutlineColor( c );
1814  }
1815  }
1816 
1817  if ( props.contains( "size_unit" ) )
1818  m->setSizeUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["size_unit"] ) );
1819  if ( props.contains( "size_map_unit_scale" ) )
1820  m->setSizeMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["size_map_unit_scale"] ) );
1821  if ( props.contains( "offset" ) )
1822  m->setOffset( QgsSymbolLayerV2Utils::decodePoint( props["offset"] ) );
1823  if ( props.contains( "offset_unit" ) )
1824  m->setOffsetUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["offset_unit"] ) );
1825  if ( props.contains( "offset_map_unit_scale" ) )
1826  m->setOffsetMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["offset_map_unit_scale"] ) );
1827  if ( props.contains( "fill" ) )
1828  {
1829  //pre 2.5 projects used "fill"
1830  m->setFillColor( QgsSymbolLayerV2Utils::decodeColor( props["fill"] ) );
1831  }
1832  else if ( props.contains( "color" ) )
1833  {
1834  m->setFillColor( QgsSymbolLayerV2Utils::decodeColor( props["color"] ) );
1835  }
1836  if ( props.contains( "outline" ) )
1837  {
1838  //pre 2.5 projects used "outline"
1839  m->setOutlineColor( QgsSymbolLayerV2Utils::decodeColor( props["outline"] ) );
1840  }
1841  else if ( props.contains( "outline_color" ) )
1842  {
1843  m->setOutlineColor( QgsSymbolLayerV2Utils::decodeColor( props["outline_color"] ) );
1844  }
1845  else if ( props.contains( "line_color" ) )
1846  {
1847  m->setOutlineColor( QgsSymbolLayerV2Utils::decodeColor( props["line_color"] ) );
1848  }
1849 
1850  if ( props.contains( "outline-width" ) )
1851  {
1852  //pre 2.5 projects used "outline-width"
1853  m->setOutlineWidth( props["outline-width"].toDouble() );
1854  }
1855  else if ( props.contains( "outline_width" ) )
1856  {
1857  m->setOutlineWidth( props["outline_width"].toDouble() );
1858  }
1859  else if ( props.contains( "line_width" ) )
1860  {
1861  m->setOutlineWidth( props["line_width"].toDouble() );
1862  }
1863 
1864  if ( props.contains( "outline_width_unit" ) )
1865  {
1866  m->setOutlineWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["outline_width_unit"] ) );
1867  }
1868  else if ( props.contains( "line_width_unit" ) )
1869  {
1870  m->setOutlineWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["line_width_unit"] ) );
1871  }
1872  if ( props.contains( "outline_width_map_unit_scale" ) )
1873  m->setOutlineWidthMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["outline_width_map_unit_scale"] ) );
1874 
1875  if ( props.contains( "horizontal_anchor_point" ) )
1876  {
1877  m->setHorizontalAnchorPoint( QgsMarkerSymbolLayerV2::HorizontalAnchorPoint( props[ "horizontal_anchor_point" ].toInt() ) );
1878  }
1879  if ( props.contains( "vertical_anchor_point" ) )
1880  {
1881  m->setVerticalAnchorPoint( QgsMarkerSymbolLayerV2::VerticalAnchorPoint( props[ "vertical_anchor_point" ].toInt() ) );
1882  }
1883 
1884  m->restoreDataDefinedProperties( props );
1885 
1886  return m;
1887 }
1888 
1890 {
1891  mPath = path;
1892  QColor defaultFillColor, defaultOutlineColor;
1893  double outlineWidth, fillOpacity, outlineOpacity;
1894  bool hasFillParam = false, hasFillOpacityParam = false, hasOutlineParam = false, hasOutlineWidthParam = false, hasOutlineOpacityParam = false;
1895  bool hasDefaultFillColor = false, hasDefaultFillOpacity = false, hasDefaultOutlineColor = false, hasDefaultOutlineWidth = false, hasDefaultOutlineOpacity = false;
1896  QgsSvgCache::instance()->containsParams( path, hasFillParam, hasDefaultFillColor, defaultFillColor,
1897  hasFillOpacityParam, hasDefaultFillOpacity, fillOpacity,
1898  hasOutlineParam, hasDefaultOutlineColor, defaultOutlineColor,
1899  hasOutlineWidthParam, hasDefaultOutlineWidth, outlineWidth,
1900  hasOutlineOpacityParam, hasDefaultOutlineOpacity, outlineOpacity );
1901 
1902  double newFillOpacity = hasFillOpacityParam ? fillColor().alphaF() : 1.0;
1903  double newOutlineOpacity = hasOutlineOpacityParam ? outlineColor().alphaF() : 1.0;
1904 
1905  if ( hasDefaultFillColor )
1906  {
1907  defaultFillColor.setAlphaF( newFillOpacity );
1908  setFillColor( defaultFillColor );
1909  }
1910  if ( hasDefaultFillOpacity )
1911  {
1912  QColor c = fillColor();
1913  c.setAlphaF( fillOpacity );
1914  setFillColor( c );
1915  }
1916  if ( hasDefaultOutlineColor )
1917  {
1918  defaultOutlineColor.setAlphaF( newOutlineOpacity );
1919  setOutlineColor( defaultOutlineColor );
1920  }
1921  if ( hasDefaultOutlineWidth )
1922  {
1923  setOutlineWidth( outlineWidth );
1924  }
1925  if ( hasDefaultOutlineOpacity )
1926  {
1927  QColor c = outlineColor();
1928  c.setAlphaF( outlineOpacity );
1929  setOutlineColor( c );
1930  }
1931 }
1932 
1933 
1935 {
1936  return "SvgMarker";
1937 }
1938 
1940 {
1941  QgsMarkerSymbolLayerV2::startRender( context ); // get anchor point expressions
1942  Q_UNUSED( context );
1943  prepareExpressions( context );
1944 }
1945 
1947 {
1948  Q_UNUSED( context );
1949 }
1950 
1952 {
1953  QPainter *p = context.renderContext().painter();
1954  if ( !p )
1955  return;
1956 
1957  bool hasDataDefinedSize = false;
1958  double scaledSize = calculateSize( context, hasDataDefinedSize );
1960 
1961  //don't render symbols with size below one or above 10,000 pixels
1962  if ( static_cast< int >( size ) < 1 || 10000.0 < size )
1963  {
1964  return;
1965  }
1966 
1967  p->save();
1968 
1969  QPointF outputOffset;
1970  double angle = 0.0;
1971  calculateOffsetAndRotation( context, scaledSize, outputOffset, angle );
1972 
1973  p->translate( point + outputOffset );
1974 
1975  bool rotated = !qgsDoubleNear( angle, 0 );
1976  if ( rotated )
1977  p->rotate( angle );
1978 
1979  QString path = mPath;
1981  {
1982  context.setOriginalValueVariable( mPath );
1984  }
1985 
1986  double outlineWidth = mOutlineWidth;
1988  {
1989  context.setOriginalValueVariable( mOutlineWidth );
1990  outlineWidth = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_OUTLINE_WIDTH, context, mOutlineWidth ).toDouble();
1991  }
1992  outlineWidth = QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), outlineWidth, mOutlineWidthUnit, mOutlineWidthMapUnitScale );
1993 
1995  bool ok = false;
1997  {
2000  if ( ok )
2001  fillColor = QgsSymbolLayerV2Utils::decodeColor( colorString );
2002  }
2003 
2004  QColor outlineColor = mOutlineColor;
2006  {
2009  if ( ok )
2010  outlineColor = QgsSymbolLayerV2Utils::decodeColor( colorString );
2011  }
2012 
2013  bool fitsInCache = true;
2014  bool usePict = true;
2015  double hwRatio = 1.0;
2016  if ( !context.renderContext().forceVectorOutput() && !rotated )
2017  {
2018  usePict = false;
2019  const QImage& img = QgsSvgCache::instance()->svgAsImage( path, size, fillColor, outlineColor, outlineWidth,
2020  context.renderContext().scaleFactor(), context.renderContext().rasterScaleFactor(), fitsInCache );
2021  if ( fitsInCache && img.width() > 1 )
2022  {
2023  //consider transparency
2024  if ( !qgsDoubleNear( context.alpha(), 1.0 ) )
2025  {
2026  QImage transparentImage = img.copy();
2027  QgsSymbolLayerV2Utils::multiplyImageOpacity( &transparentImage, context.alpha() );
2028  p->drawImage( -transparentImage.width() / 2.0, -transparentImage.height() / 2.0, transparentImage );
2029  hwRatio = static_cast< double >( transparentImage.height() ) / static_cast< double >( transparentImage.width() );
2030  }
2031  else
2032  {
2033  p->drawImage( -img.width() / 2.0, -img.height() / 2.0, img );
2034  hwRatio = static_cast< double >( img.height() ) / static_cast< double >( img.width() );
2035  }
2036  }
2037  }
2038 
2039  if ( usePict || !fitsInCache )
2040  {
2041  p->setOpacity( context.alpha() );
2042  const QPicture& pct = QgsSvgCache::instance()->svgAsPicture( path, size, fillColor, outlineColor, outlineWidth,
2044 
2045  if ( pct.width() > 1 )
2046  {
2047  p->save();
2048  _fixQPictureDPI( p );
2049  p->drawPicture( 0, 0, pct );
2050  p->restore();
2051  hwRatio = static_cast< double >( pct.height() ) / static_cast< double >( pct.width() );
2052  }
2053  }
2054 
2055  if ( context.selected() )
2056  {
2057  QPen pen( context.renderContext().selectionColor() );
2059  if ( penWidth > size / 20 )
2060  {
2061  // keep the pen width from covering symbol
2062  penWidth = size / 20;
2063  }
2064  double penOffset = penWidth / 2;
2065  pen.setWidth( penWidth );
2066  p->setPen( pen );
2067  p->setBrush( Qt::NoBrush );
2068  double wSize = size + penOffset;
2069  double hSize = size * hwRatio + penOffset;
2070  p->drawRect( QRectF( -wSize / 2.0, -hSize / 2.0, wSize, hSize ) );
2071  }
2072 
2073  p->restore();
2074 
2076  {
2077  // workaround issue with nested QPictures forgetting antialiasing flag - see http://hub.qgis.org/issues/14960
2078  p->setRenderHint( QPainter::Antialiasing );
2079  }
2080 
2081 }
2082 
2083 double QgsSvgMarkerSymbolLayerV2::calculateSize( QgsSymbolV2RenderContext& context, bool& hasDataDefinedSize ) const
2084 {
2085  double scaledSize = mSize;
2087 
2088  bool ok = true;
2090  {
2091  context.setOriginalValueVariable( mSize );
2092  scaledSize = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_SIZE, context, mSize, &ok ).toDouble();
2093  }
2094 
2095  if ( hasDataDefinedSize && ok )
2096  {
2097  switch ( mScaleMethod )
2098  {
2100  scaledSize = sqrt( scaledSize );
2101  break;
2103  break;
2104  }
2105  }
2106 
2107  return scaledSize;
2108 }
2109 
2110 void QgsSvgMarkerSymbolLayerV2::calculateOffsetAndRotation( QgsSymbolV2RenderContext& context, double scaledSize, QPointF& offset, double& angle ) const
2111 {
2112  //offset
2113  double offsetX = 0;
2114  double offsetY = 0;
2115  markerOffset( context, scaledSize, scaledSize, offsetX, offsetY );
2116  offset = QPointF( offsetX, offsetY );
2117 
2118  angle = mAngle + mLineAngle;
2120  {
2121  context.setOriginalValueVariable( mAngle );
2123  }
2124 
2126  if ( hasDataDefinedRotation )
2127  {
2128  // For non-point markers, "dataDefinedRotation" means following the
2129  // shape (shape-data defined). For them, "field-data defined" does
2130  // not work at all. TODO: if "field-data defined" ever gets implemented
2131  // we'll need a way to distinguish here between the two, possibly
2132  // using another flag in renderHints()
2133  const QgsFeature* f = context.feature();
2134  if ( f )
2135  {
2136  const QgsGeometry *g = f->constGeometry();
2137  if ( g && g->type() == QGis::Point )
2138  {
2139  const QgsMapToPixel& m2p = context.renderContext().mapToPixel();
2140  angle += m2p.mapRotation();
2141  }
2142  }
2143  }
2144 
2145  if ( angle )
2146  offset = _rotatedOffset( offset, angle );
2147 }
2148 
2149 
2151 {
2152  QgsStringMap map;
2154  map["size"] = QString::number( mSize );
2155  map["size_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mSizeUnit );
2156  map["size_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mSizeMapUnitScale );
2157  map["angle"] = QString::number( mAngle );
2158  map["offset"] = QgsSymbolLayerV2Utils::encodePoint( mOffset );
2159  map["offset_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOffsetUnit );
2160  map["offset_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOffsetMapUnitScale );
2161  map["scale_method"] = QgsSymbolLayerV2Utils::encodeScaleMethod( mScaleMethod );
2162  map["color"] = QgsSymbolLayerV2Utils::encodeColor( mColor );
2163  map["outline_color"] = QgsSymbolLayerV2Utils::encodeColor( mOutlineColor );
2164  map["outline_width"] = QString::number( mOutlineWidth );
2165  map["outline_width_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOutlineWidthUnit );
2166  map["outline_width_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOutlineWidthMapUnitScale );
2167  map["horizontal_anchor_point"] = QString::number( mHorizontalAnchorPoint );
2168  map["vertical_anchor_point"] = QString::number( mVerticalAnchorPoint );
2169 
2171  return map;
2172 }
2173 
2175 {
2177  m->setColor( mColor );
2178  m->setOutlineColor( mOutlineColor );
2179  m->setOutlineWidth( mOutlineWidth );
2180  m->setOutlineWidthUnit( mOutlineWidthUnit );
2181  m->setOutlineWidthMapUnitScale( mOutlineWidthMapUnitScale );
2182  m->setOffset( mOffset );
2183  m->setOffsetUnit( mOffsetUnit );
2185  m->setSizeUnit( mSizeUnit );
2190  copyPaintEffect( m );
2191  return m;
2192 }
2193 
2195 {
2197  mOutlineWidthUnit = unit;
2198 }
2199 
2201 {
2203  if ( unit != mOutlineWidthUnit )
2204  {
2205  return QgsSymbolV2::Mixed;
2206  }
2207  return unit;
2208 }
2209 
2211 {
2213  mOutlineWidthMapUnitScale = scale;
2214 }
2215 
2217 {
2218  if ( QgsMarkerSymbolLayerV2::mapUnitScale() == mOutlineWidthMapUnitScale )
2219  {
2220  return mOutlineWidthMapUnitScale;
2221  }
2222  return QgsMapUnitScale();
2223 }
2224 
2226 {
2227  // <Graphic>
2228  QDomElement graphicElem = doc.createElement( "se:Graphic" );
2229  element.appendChild( graphicElem );
2230 
2232  QgsSymbolLayerV2Utils::externalGraphicToSld( doc, graphicElem, mPath, "image/svg+xml", mColor, size );
2233 
2234  // <Rotation>
2235  QString angleFunc;
2236  bool ok;
2237  double angle = props.value( "angle", "0" ).toDouble( &ok );
2238  if ( !ok )
2239  {
2240  angleFunc = QString( "%1 + %2" ).arg( props.value( "angle", "0" ) ).arg( mAngle );
2241  }
2242  else if ( !qgsDoubleNear( angle + mAngle, 0.0 ) )
2243  {
2244  angleFunc = QString::number( angle + mAngle );
2245  }
2246 
2247  QgsSymbolLayerV2Utils::createRotationElement( doc, graphicElem, angleFunc );
2248 
2249  // <Displacement>
2251  QgsSymbolLayerV2Utils::createDisplacementElement( doc, graphicElem, offset );
2252 }
2253 
2255 {
2256  QgsDebugMsg( "Entered." );
2257 
2258  QDomElement graphicElem = element.firstChildElement( "Graphic" );
2259  if ( graphicElem.isNull() )
2260  return nullptr;
2261 
2262  QString path, mimeType;
2263  QColor fillColor;
2264  double size;
2265 
2266  if ( !QgsSymbolLayerV2Utils::externalGraphicFromSld( graphicElem, path, mimeType, fillColor, size ) )
2267  return nullptr;
2268 
2269  if ( mimeType != "image/svg+xml" )
2270  return nullptr;
2271 
2272  double angle = 0.0;
2273  QString angleFunc;
2274  if ( QgsSymbolLayerV2Utils::rotationFromSldElement( graphicElem, angleFunc ) )
2275  {
2276  bool ok;
2277  double d = angleFunc.toDouble( &ok );
2278  if ( ok )
2279  angle = d;
2280  }
2281 
2282  QPointF offset;
2284 
2286  m->setFillColor( fillColor );
2287  //m->setOutlineColor( outlineColor );
2288  //m->setOutlineWidth( outlineWidth );
2289  m->setAngle( angle );
2290  m->setOffset( offset );
2291  return m;
2292 }
2293 
2294 bool QgsSvgMarkerSymbolLayerV2::writeDxf( QgsDxfExport& e, double mmMapUnitScaleFactor, const QString& layerName, QgsSymbolV2RenderContext &context, QPointF shift ) const
2295 {
2296  Q_UNUSED( layerName );
2297  Q_UNUSED( shift ); //todo...
2298 
2299  //size
2300  double size = mSize;
2301 
2303 
2304  bool ok = true;
2306  {
2307  context.setOriginalValueVariable( mSize );
2309  }
2310 
2311  if ( hasDataDefinedSize && ok )
2312  {
2313  switch ( mScaleMethod )
2314  {
2316  size = sqrt( size );
2317  break;
2319  break;
2320  }
2321  }
2322 
2323  if ( mSizeUnit == QgsSymbolV2::MM )
2324  {
2325  size *= mmMapUnitScaleFactor;
2326  }
2327 
2328  double halfSize = size / 2.0;
2329 
2330  //offset, angle
2331  QPointF offset = mOffset;
2332 
2334  {
2337  if ( ok )
2338  offset = QgsSymbolLayerV2Utils::decodePoint( offsetString );
2339  }
2340  double offsetX = offset.x();
2341  double offsetY = offset.y();
2342  if ( mSizeUnit == QgsSymbolV2::MM )
2343  {
2344  offsetX *= mmMapUnitScaleFactor;
2345  offsetY *= mmMapUnitScaleFactor;
2346  }
2347 
2348  QPointF outputOffset( offsetX, offsetY );
2349 
2350  double angle = mAngle + mLineAngle;
2352  {
2353  context.setOriginalValueVariable( mAngle );
2355  }
2356  //angle = -angle; //rotation in Qt is counterclockwise
2357  if ( angle )
2358  outputOffset = _rotatedOffset( outputOffset, angle );
2359 
2360  QString path = mPath;
2362  {
2363  context.setOriginalValueVariable( mPath );
2365  }
2366 
2367  double outlineWidth = mOutlineWidth;
2369  {
2370  context.setOriginalValueVariable( mOutlineWidth );
2371  outlineWidth = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_OUTLINE_WIDTH, context, mOutlineWidth ).toDouble();
2372  }
2373  outlineWidth = QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), outlineWidth, mOutlineWidthUnit, mOutlineWidthMapUnitScale );
2374 
2377  {
2380  if ( ok )
2381  fillColor = QgsSymbolLayerV2Utils::decodeColor( colorString );
2382  }
2383 
2384  QColor outlineColor = mOutlineColor;
2386  {
2389  if ( ok )
2390  outlineColor = QgsSymbolLayerV2Utils::decodeColor( colorString );
2391  }
2392 
2393  const QByteArray &svgContent = QgsSvgCache::instance()->svgContent( path, size, fillColor, outlineColor, outlineWidth,
2394  context.renderContext().scaleFactor(),
2395  context.renderContext().rasterScaleFactor() );
2396 
2397  //if current entry image is 0: cache image for entry
2398  // checks to see if image will fit into cache
2399  //update stats for memory usage
2400  QSvgRenderer r( svgContent );
2401  if ( !r.isValid() )
2402  {
2403  return false;
2404  }
2405 
2406  QgsDxfPaintDevice pd( &e );
2407  pd.setDrawingSize( QSizeF( r.defaultSize() ) );
2408 
2409  QPainter p;
2410  p.begin( &pd );
2411  if ( !qgsDoubleNear( angle, 0.0 ) )
2412  {
2413  p.translate( r.defaultSize().width() / 2.0, r.defaultSize().height() / 2.0 );
2414  p.rotate( angle );
2415  p.translate( -r.defaultSize().width() / 2.0, -r.defaultSize().height() / 2.0 );
2416  }
2417  pd.setShift( shift );
2418  pd.setOutputSize( QRectF( -halfSize, -halfSize, size, size ) );
2419  pd.setLayer( layerName );
2420  r.render( &p );
2421  p.end();
2422  return true;
2423 }
2424 
2426 {
2427  bool hasDataDefinedSize = false;
2428  double scaledSize = calculateSize( context, hasDataDefinedSize );
2430 
2431  //don't render symbols with size below one or above 10,000 pixels
2432  if ( static_cast< int >( scaledSize ) < 1 || 10000.0 < scaledSize )
2433  {
2434  return QRectF();
2435  }
2436 
2437  QPointF outputOffset;
2438  double angle = 0.0;
2439  calculateOffsetAndRotation( context, scaledSize, outputOffset, angle );
2440 
2441  QString path = mPath;
2443  {
2444  context.setOriginalValueVariable( mPath );
2446  }
2447 
2448  double outlineWidth = mOutlineWidth;
2450  {
2451  context.setOriginalValueVariable( mOutlineWidth );
2452  outlineWidth = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_OUTLINE_WIDTH, context, mOutlineWidth ).toDouble();
2453  }
2454  outlineWidth = QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), outlineWidth, mOutlineWidthUnit, mOutlineWidthMapUnitScale );
2455 
2456  //need to get colors to take advantage of cached SVGs
2458  bool ok = false;
2460  {
2463  if ( ok )
2464  fillColor = QgsSymbolLayerV2Utils::decodeColor( colorString );
2465  }
2466 
2467  QColor outlineColor = mOutlineColor;
2469  {
2472  if ( ok )
2473  outlineColor = QgsSymbolLayerV2Utils::decodeColor( colorString );
2474  }
2475 
2476  QSizeF svgViewbox = QgsSvgCache::instance()->svgViewboxSize( path, scaledSize, fillColor, outlineColor, outlineWidth,
2477  context.renderContext().scaleFactor(),
2478  context.renderContext().rasterScaleFactor() );
2479 
2480  double scaledHeight = svgViewbox.isValid() ? scaledSize * svgViewbox.height() / svgViewbox.width() : scaledSize;
2481  double pixelSize = 1.0 / context.renderContext().rasterScaleFactor();
2482 
2483  QMatrix transform;
2484 
2485  // move to the desired position
2486  transform.translate( point.x() + outputOffset.x(), point.y() + outputOffset.y() );
2487 
2488  if ( !qgsDoubleNear( angle, 0.0 ) )
2489  transform.rotate( angle );
2490 
2491  //antialiasing
2492  outlineWidth += pixelSize / 2.0;
2493 
2494  QRectF symbolBounds = transform.mapRect( QRectF( -scaledSize / 2.0,
2495  -scaledHeight / 2.0,
2496  scaledSize,
2497  scaledHeight ) );
2498 
2499  //extend bounds by pen width / 2.0
2500  symbolBounds.adjust( -outlineWidth / 2.0, -outlineWidth / 2.0,
2501  outlineWidth / 2.0, outlineWidth / 2.0 );
2502 
2503  return symbolBounds;
2504 
2505 }
2506 
2508 
2509 QgsFontMarkerSymbolLayerV2::QgsFontMarkerSymbolLayerV2( const QString& fontFamily, QChar chr, double pointSize, const QColor& color, double angle )
2510  : mFontMetrics( nullptr )
2511  , mChrWidth( 0 )
2512 {
2514  mChr = chr;
2515  mColor = color;
2516  mAngle = angle;
2517  mSize = pointSize;
2518  mOrigSize = pointSize;
2520  mOffset = QPointF( 0, 0 );
2522  mOutlineColor = DEFAULT_FONTMARKER_BORDERCOLOR;
2523  mOutlineWidth = 0.0;
2524  mOutlineWidthUnit = QgsSymbolV2::MM;
2525  mPenJoinStyle = DEFAULT_FONTMARKER_JOINSTYLE;
2526 }
2527 
2529 {
2530  delete mFontMetrics;
2531 }
2532 
2534 {
2537  double pointSize = DEFAULT_FONTMARKER_SIZE;
2540 
2541  if ( props.contains( "font" ) )
2542  fontFamily = props["font"];
2543  if ( props.contains( "chr" ) && props["chr"].length() > 0 )
2544  chr = props["chr"].at( 0 );
2545  if ( props.contains( "size" ) )
2546  pointSize = props["size"].toDouble();
2547  if ( props.contains( "color" ) )
2548  color = QgsSymbolLayerV2Utils::decodeColor( props["color"] );
2549  if ( props.contains( "angle" ) )
2550  angle = props["angle"].toDouble();
2551 
2552  QgsFontMarkerSymbolLayerV2* m = new QgsFontMarkerSymbolLayerV2( fontFamily, chr, pointSize, color, angle );
2553 
2554  if ( props.contains( "outline_color" ) )
2555  m->setOutlineColor( QgsSymbolLayerV2Utils::decodeColor( props["outline_color"] ) );
2556  if ( props.contains( "outline_width" ) )
2557  m->setOutlineWidth( props["outline_width"].toDouble() );
2558  if ( props.contains( "offset" ) )
2559  m->setOffset( QgsSymbolLayerV2Utils::decodePoint( props["offset"] ) );
2560  if ( props.contains( "offset_unit" ) )
2561  m->setOffsetUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["offset_unit" ] ) );
2562  if ( props.contains( "offset_map_unit_scale" ) )
2563  m->setOffsetMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["offset_map_unit_scale" ] ) );
2564  if ( props.contains( "size_unit" ) )
2565  m->setSizeUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["size_unit"] ) );
2566  if ( props.contains( "size_map_unit_scale" ) )
2567  m->setSizeMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["size_map_unit_scale"] ) );
2568  if ( props.contains( "outline_width_unit" ) )
2569  m->setOutlineWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["outline_width_unit"] ) );
2570  if ( props.contains( "outline_width_map_unit_scale" ) )
2571  m->setOutlineWidthMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["outline_width_map_unit_scale"] ) );
2572  if ( props.contains( "joinstyle" ) )
2573  m->setPenJoinStyle( QgsSymbolLayerV2Utils::decodePenJoinStyle( props["joinstyle"] ) );
2574  if ( props.contains( "horizontal_anchor_point" ) )
2575  m->setHorizontalAnchorPoint( QgsMarkerSymbolLayerV2::HorizontalAnchorPoint( props[ "horizontal_anchor_point" ].toInt() ) );
2576  if ( props.contains( "vertical_anchor_point" ) )
2577  m->setVerticalAnchorPoint( QgsMarkerSymbolLayerV2::VerticalAnchorPoint( props[ "vertical_anchor_point" ].toInt() ) );
2578 
2579  m->restoreDataDefinedProperties( props );
2580 
2581  return m;
2582 }
2583 
2585 {
2586  return "FontMarker";
2587 }
2588 
2590 {
2591  QColor brushColor = mColor;
2592  QColor penColor = mOutlineColor;
2593 
2594  brushColor.setAlphaF( mColor.alphaF() * context.alpha() );
2595  penColor.setAlphaF( mOutlineColor.alphaF() * context.alpha() );
2596 
2597  mBrush = QBrush( brushColor );
2598  mPen = QPen( penColor );
2599  mPen.setJoinStyle( mPenJoinStyle );
2600  mPen.setWidthF( QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), mOutlineWidth, mOutlineWidthUnit, mOutlineWidthMapUnitScale ) );
2601 
2602  mFont = QFont( mFontFamily );
2604  delete mFontMetrics;
2605  mFontMetrics = new QFontMetrics( mFont );
2607  mChrOffset = QPointF( mChrWidth / 2.0, -mFontMetrics->ascent() / 2.0 );
2608  mOrigSize = mSize; // save in case the size would be data defined
2609  prepareExpressions( context );
2610 }
2611 
2613 {
2614  Q_UNUSED( context );
2615 }
2616 
2617 QString QgsFontMarkerSymbolLayerV2::characterToRender( QgsSymbolV2RenderContext& context, QPointF& charOffset, double& charWidth )
2618 {
2619  charOffset = mChrOffset;
2620  QString charToRender = mChr;
2622  {
2623  context.setOriginalValueVariable( mChr );
2625  if ( charToRender != mChr )
2626  {
2627  charWidth = mFontMetrics->width( charToRender );
2628  charOffset = QPointF( charWidth / 2.0, -mFontMetrics->ascent() / 2.0 );
2629  }
2630  }
2631  return charToRender;
2632 }
2633 
2634 void QgsFontMarkerSymbolLayerV2::calculateOffsetAndRotation( QgsSymbolV2RenderContext& context,
2635  double scaledSize,
2636  bool& hasDataDefinedRotation,
2637  QPointF& offset,
2638  double& angle ) const
2639 {
2640  //offset
2641  double offsetX = 0;
2642  double offsetY = 0;
2643  markerOffset( context, scaledSize, scaledSize, offsetX, offsetY );
2644  offset = QPointF( offsetX, offsetY );
2645 
2646  //angle
2647  bool ok = true;
2648  angle = mAngle + mLineAngle;
2649  bool usingDataDefinedRotation = false;
2651  {
2652  context.setOriginalValueVariable( angle );
2654  usingDataDefinedRotation = ok;
2655  }
2656 
2657  hasDataDefinedRotation = context.renderHints() & QgsSymbolV2::DataDefinedRotation || usingDataDefinedRotation;
2658  if ( hasDataDefinedRotation )
2659  {
2660  // For non-point markers, "dataDefinedRotation" means following the
2661  // shape (shape-data defined). For them, "field-data defined" does
2662  // not work at all. TODO: if "field-data defined" ever gets implemented
2663  // we'll need a way to distinguish here between the two, possibly
2664  // using another flag in renderHints()
2665  const QgsFeature* f = context.feature();
2666  if ( f )
2667  {
2668  const QgsGeometry *g = f->constGeometry();
2669  if ( g && g->type() == QGis::Point )
2670  {
2671  const QgsMapToPixel& m2p = context.renderContext().mapToPixel();
2672  angle += m2p.mapRotation();
2673  }
2674  }
2675  }
2676 
2677  if ( angle )
2678  offset = _rotatedOffset( offset, angle );
2679 }
2680 
2681 double QgsFontMarkerSymbolLayerV2::calculateSize( QgsSymbolV2RenderContext& context )
2682 {
2683  double scaledSize = mSize;
2685 
2686  bool ok = true;
2688  {
2689  context.setOriginalValueVariable( mSize );
2690  scaledSize = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_SIZE, context, mSize, &ok ).toDouble();
2691  }
2692 
2693  if ( hasDataDefinedSize && ok )
2694  {
2695  switch ( mScaleMethod )
2696  {
2698  scaledSize = sqrt( scaledSize );
2699  break;
2701  break;
2702  }
2703  }
2704  return scaledSize;
2705 }
2706 
2708 {
2709  QPainter *p = context.renderContext().painter();
2710  if ( !p )
2711  return;
2712 
2713  QTransform transform;
2714 
2715  bool ok;
2716  QColor brushColor = mColor;
2718  {
2721  if ( ok )
2722  brushColor = QgsSymbolLayerV2Utils::decodeColor( colorString );
2723  }
2724  brushColor = context.selected() ? context.renderContext().selectionColor() : brushColor;
2725  brushColor.setAlphaF( brushColor.alphaF() * context.alpha() );
2726  mBrush.setColor( brushColor );
2727 
2728  QColor penColor = mOutlineColor;
2730  {
2733  if ( ok )
2734  penColor = QgsSymbolLayerV2Utils::decodeColor( colorString );
2735  }
2736  penColor.setAlphaF( penColor.alphaF() * context.alpha() );
2737 
2738  double penWidth = QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), mOutlineWidth, mOutlineWidthUnit, mOutlineWidthMapUnitScale );
2740  {
2741  context.setOriginalValueVariable( mOutlineWidth );
2743  if ( ok )
2744  {
2745  penWidth = QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), outlineWidth, mOutlineWidthUnit, mOutlineWidthMapUnitScale );
2746  }
2747  }
2748 
2750  {
2753  if ( ok )
2754  {
2756  }
2757  }
2758 
2759  p->setBrush( mBrush );
2760  if ( !qgsDoubleNear( penWidth, 0.0 ) )
2761  {
2762  mPen.setColor( penColor );
2763  mPen.setWidthF( penWidth );
2764  p->setPen( mPen );
2765  }
2766  else
2767  {
2768  p->setPen( Qt::NoPen );
2769  }
2770  p->save();
2771 
2772  QPointF chrOffset = mChrOffset;
2773  double chrWidth;
2774  QString charToRender = characterToRender( context, chrOffset, chrWidth );
2775 
2776  double sizeToRender = calculateSize( context );
2777 
2778  bool hasDataDefinedRotation = false;
2779  QPointF offset;
2780  double angle = 0;
2781  calculateOffsetAndRotation( context, sizeToRender, hasDataDefinedRotation, offset, angle );
2782 
2783  transform.translate( point.x() + offset.x(), point.y() + offset.y() );
2784 
2785  if ( !qgsDoubleNear( angle, 0.0 ) )
2786  transform.rotate( angle );
2787 
2788  if ( !qgsDoubleNear( sizeToRender, mOrigSize ) )
2789  {
2790  double s = sizeToRender / mOrigSize;
2791  transform.scale( s, s );
2792  }
2793 
2794  QPainterPath path;
2795  path.addText( -chrOffset.x(), -chrOffset.y(), mFont, charToRender );
2796  p->drawPath( transform.map( path ) );
2797  p->restore();
2798 }
2799 
2801 {
2802  QgsStringMap props;
2803  props["font"] = mFontFamily;
2804  props["chr"] = mChr;
2805  props["size"] = QString::number( mSize );
2806  props["size_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mSizeUnit );
2807  props["size_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mSizeMapUnitScale );
2808  props["color"] = QgsSymbolLayerV2Utils::encodeColor( mColor );
2809  props["outline_color"] = QgsSymbolLayerV2Utils::encodeColor( mOutlineColor );
2810  props["outline_width"] = QString::number( mOutlineWidth );
2811  props["outline_width_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOutlineWidthUnit );
2812  props["outline_width_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOutlineWidthMapUnitScale );
2813  props["joinstyle"] = QgsSymbolLayerV2Utils::encodePenJoinStyle( mPenJoinStyle );
2814  props["angle"] = QString::number( mAngle );
2815  props["offset"] = QgsSymbolLayerV2Utils::encodePoint( mOffset );
2816  props["offset_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOffsetUnit );
2817  props["offset_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOffsetMapUnitScale );
2818  props["horizontal_anchor_point"] = QString::number( mHorizontalAnchorPoint );
2819  props["vertical_anchor_point"] = QString::number( mVerticalAnchorPoint );
2820 
2821  //data define properties
2822  saveDataDefinedProperties( props );
2823 
2824  return props;
2825 }
2826 
2828 {
2830  m->setOutlineColor( mOutlineColor );
2831  m->setOutlineWidth( mOutlineWidth );
2832  m->setOutlineWidthUnit( mOutlineWidthUnit );
2833  m->setOutlineWidthMapUnitScale( mOutlineWidthMapUnitScale );
2834  m->setPenJoinStyle( mPenJoinStyle );
2835  m->setOffset( mOffset );
2836  m->setOffsetUnit( mOffsetUnit );
2838  m->setSizeUnit( mSizeUnit );
2843  copyPaintEffect( m );
2844  return m;
2845 }
2846 
2848 {
2849  // <Graphic>
2850  QDomElement graphicElem = doc.createElement( "se:Graphic" );
2851  element.appendChild( graphicElem );
2852 
2853  QString fontPath = QString( "ttf://%1" ).arg( mFontFamily );
2854  int markIndex = mChr.unicode();
2856  QgsSymbolLayerV2Utils::externalMarkerToSld( doc, graphicElem, fontPath, "ttf", &markIndex, mColor, size );
2857 
2858  // <Rotation>
2859  QString angleFunc;
2860  bool ok;
2861  double angle = props.value( "angle", "0" ).toDouble( &ok );
2862  if ( !ok )
2863  {
2864  angleFunc = QString( "%1 + %2" ).arg( props.value( "angle", "0" ) ).arg( mAngle );
2865  }
2866  else if ( !qgsDoubleNear( angle + mAngle, 0.0 ) )
2867  {
2868  angleFunc = QString::number( angle + mAngle );
2869  }
2870  QgsSymbolLayerV2Utils::createRotationElement( doc, graphicElem, angleFunc );
2871 
2872  // <Displacement>
2874  QgsSymbolLayerV2Utils::createDisplacementElement( doc, graphicElem, offset );
2875 }
2876 
2878 {
2879  QPointF chrOffset = mChrOffset;
2880  double chrWidth = mChrWidth;
2881  //calculate width of rendered character
2882  ( void )characterToRender( context, chrOffset, chrWidth );
2883 
2884  if ( !mFontMetrics )
2885  mFontMetrics = new QFontMetrics( mFont );
2886 
2887  double scaledSize = calculateSize( context );
2888  if ( !qgsDoubleNear( scaledSize, mOrigSize ) )
2889  {
2890  chrWidth *= scaledSize / mOrigSize;
2891  }
2892 
2893  bool hasDataDefinedRotation = false;
2894  QPointF offset;
2895  double angle = 0;
2896  calculateOffsetAndRotation( context, scaledSize, hasDataDefinedRotation, offset, angle );
2898 
2899  QMatrix transform;
2900 
2901  // move to the desired position
2902  transform.translate( point.x() + offset.x(), point.y() + offset.y() );
2903 
2904  if ( !qgsDoubleNear( angle, 0.0 ) )
2905  transform.rotate( angle );
2906 
2907  QRectF symbolBounds = transform.mapRect( QRectF( -chrWidth / 2.0,
2908  -scaledSize / 2.0,
2909  chrWidth,
2910  scaledSize ) );
2911  return symbolBounds;
2912 }
2913 
2915 {
2916  QgsDebugMsg( "Entered." );
2917 
2918  QDomElement graphicElem = element.firstChildElement( "Graphic" );
2919  if ( graphicElem.isNull() )
2920  return nullptr;
2921 
2922  QString name, format;
2923  QColor color;
2924  double size;
2925  int chr;
2926 
2927  if ( !QgsSymbolLayerV2Utils::externalMarkerFromSld( graphicElem, name, format, chr, color, size ) )
2928  return nullptr;
2929 
2930  if ( !name.startsWith( "ttf://" ) || format != "ttf" )
2931  return nullptr;
2932 
2933  QString fontFamily = name.mid( 6 );
2934 
2935  double angle = 0.0;
2936  QString angleFunc;
2937  if ( QgsSymbolLayerV2Utils::rotationFromSldElement( graphicElem, angleFunc ) )
2938  {
2939  bool ok;
2940  double d = angleFunc.toDouble( &ok );
2941  if ( ok )
2942  angle = d;
2943  }
2944 
2945  QPointF offset;
2947 
2948  QgsMarkerSymbolLayerV2 *m = new QgsFontMarkerSymbolLayerV2( fontFamily, chr, size, color );
2949  m->setAngle( angle );
2950  m->setOffset( offset );
2951  return m;
2952 }
2953 
void addEllipse(const QRectF &boundingRectangle)
QgsSymbolV2::OutputUnit outputUnit() const override
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 markerOffset(QgsSymbolV2RenderContext &context, double &offsetX, double &offsetY) const
Calculates the required marker offset, including both the symbol offset and any displacement required...
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
const QgsFields * fields() const
Fields of the layer.
Definition: qgssymbolv2.h:391
void setStyle(Qt::PenStyle style)
QString & append(QChar ch)
static QPointF _rotatedOffset(QPointF offset, double angle)
Adjusts a marker offset to account for rotation.
QPointF offset() const
Returns the marker&#39;s offset, which is the horizontal and vertical displacement which the rendered mar...
static void multiplyImageOpacity(QImage *image, qreal alpha)
Multiplies opacity of image pixel values with a (global) transparency value.
int ascent() const
OutputUnit
The unit of the output.
Definition: qgssymbolv2.h:65
Q_DECL_DEPRECATED void writeLine(const QgsPoint &pt1, const QgsPoint &pt2, const QString &layer, const QString &lineStyleName, const QColor &color, double width=-1)
Write line (as a polyline)
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.
Qt::PenStyle outlineStyle() const
Returns the marker&#39;s outline style (eg solid, dashed, etc)
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)
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)
static double rescaleUom(double size, QgsSymbolV2::OutputUnit unit, const QgsStringMap &props)
Rescales the given size based on the uomScale found in the props, if any is found, otherwise returns the value un-modified.
Use antialiasing while drawing.
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
Abstract base class for simple marker symbol layers.
virtual QSet< QString > usedAttributes() const
Returns the set of attributes referenced by the layer.
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
double size() const
Returns the symbol size.
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
virtual QColor outlineColor() const
Get outline color.
void renderPoint(QPointF point, QgsSymbolV2RenderContext &context) override
Renders a marker at the specified point.
void calculateOffsetAndRotation(QgsSymbolV2RenderContext &context, double scaledSize, bool &hasDataDefinedRotation, QPointF &offset, double &angle) const
Calculates the marker offset and rotation.
static void externalGraphicToSld(QDomDocument &doc, QDomElement &element, const QString &path, const QString &mime, const QColor &color, double size=-1)
void scale(qreal sx, qreal sy)
void setDrawingSize(QSizeF size)
#define DEFAULT_FONTMARKER_CHR
static QgsFillSymbolV2 * createSimple(const QgsStringMap &properties)
Create a fill symbol with one symbol layer: SimpleFill with specified properties. ...
static QgsSymbolV2::ScaleMethod decodeScaleMethod(const QString &str)
Calculate scale by the diameter.
Definition: qgssymbolv2.h:93
bool isValid() const
void setOffset(QPointF offset)
Sets the marker&#39;s offset, which is the horizontal and vertical displacement which the rendered marker...
QString ogrFeatureStyle(double mmScaleFactor, double mapUnitScaleFactor) const override
void setHorizontalAnchorPoint(HorizontalAnchorPoint h)
Sets the horizontal anchor point for positioning the symbol.
bool isValid() const
#define DEG2RAD(x)
void setOutlineWidth(double w)
Sets the width of the marker&#39;s outline.
#define DEFAULT_SIMPLEMARKER_COLOR
void save()
QImage mCache
Cached image of marker, if using cached version.
void setOriginalValueVariable(const QVariant &value)
Sets the original value variable value for data defined symbology.
void writeSldMarker(QDomDocument &doc, QDomElement &element, const QgsStringMap &props) const override
Writes the symbol layer definition as a SLD XML element.
void drawPolygon(const QPointF *points, int pointCount, Qt::FillRule fillRule)
void setVerticalAnchorPoint(VerticalAnchorPoint v)
Sets the vertical anchor point for positioning the symbol.
void setFillColor(const QColor &color) override
Set fill color.
bool mUsingCache
True if using cached images of markers for drawing.
static bool externalGraphicFromSld(QDomElement &element, QString &path, QString &mime, QColor &color, double &size)
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:76
static Shape decodeShape(const QString &name, bool *ok=nullptr)
Attempts to decode a string representation of a shape name to the corresponding shape.
void setJoinStyle(Qt::PenJoinStyle style)
void moveTo(const QPointF &point)
void renderPoint(QPointF point, QgsSymbolV2RenderContext &context) override
Renders a marker at the specified point.
SymbolType type() const
Definition: qgssymbolv2.h:107
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)
Flags flags() const
Return combination of flags used for rendering.
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.
const QgsGeometry * constGeometry() const
Gets a const pointer to the geometry object associated with this feature.
Definition: qgsfeature.cpp:82
void stopRender(QgsSymbolV2RenderContext &context) override
void stopRender(QgsSymbolV2RenderContext &context) override
const QgsFeature * feature() const
Current feature being rendered - may be null.
Definition: qgssymbolv2.h:385
static QString encodeMapUnitScale(const QgsMapUnitScale &mapUnitScale)
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
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
static QgsSymbolLayerV2 * create(const QgsStringMap &properties=QgsStringMap())
Creates a new QgsSimpleMarkerSymbolLayerV2.
QMap< QString, QString > QgsStringMap
Definition: qgis.h:492
void adjust(qreal dx1, qreal dy1, qreal dx2, qreal dy2)
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
Compare two doubles (but allow some difference)
Definition: qgis.h:353
static const QString EXPR_OFFSET
void setMapUnitScale(const QgsMapUnitScale &scale) override
static QgsSymbolLayerV2 * createFromSld(QDomElement &element)
Creates a new QgsSimpleMarkerSymbolLayerV2 from an SLD XML element.
#define DEFAULT_FONTMARKER_JOINSTYLE
QSize defaultSize() const
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_SVGMARKER_ANGLE
static QList< Shape > availableShapes()
Returns a list of all available shape types.
static const QString EXPR_SIZE
double mapRotation() const
Return current map rotation in degrees.
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
static QgsSymbolV2::OutputUnit decodeOutputUnit(const QString &str)
static bool displacementFromSldElement(QDomElement &element, QPointF &offset)
int width() const
void drawMarker(QPainter *p, QgsSymbolV2RenderContext &context)
Draws the marker shape in the specified painter.
const QColor & color() const
static QgsSvgCache * instance()
Definition: qgssvgcache.cpp:97
static QString encodePenStyle(Qt::PenStyle style)
void setOutlineWidthUnit(QgsSymbolV2::OutputUnit unit)
const QImage & svgAsImage(const QString &file, double size, const QColor &fill, const QColor &outline, double outlineWidth, double widthScaleFactor, double rasterScaleFactor, bool &fitsInCache)
Get SVG as QImage.
void drawRect(const QRectF &rectangle)
Perform transforms between map coordinates and device coordinates.
Definition: qgsmaptopixel.h:34
void setPixelSize(int pixelSize)
static QString symbolPathToName(QString path)
Get symbols&#39;s name from its path.
QColor color() const
void clear()
Mixed units in symbol layers.
Definition: qgssymbolv2.h:69
QTransform & translate(qreal dx, qreal dy)
The output shall be in millimeters.
Definition: qgssymbolv2.h:67
void setMapUnitScale(const QgsMapUnitScale &scale) override
QString number(int n, int base)
void setOutlineWidthUnit(QgsSymbolV2::OutputUnit u)
Sets the unit for the width of the marker&#39;s outline.
Q_DECL_DEPRECATED QString name() const
qreal x() const
qreal y() const
void setColor(const QColor &color) override
The fill color.
bool shapeToPolygon(Shape shape, QPolygonF &polygon) const
Creates a polygon representing the specified shape.
virtual QColor fillColor() const
Get fill color.
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)
qreal alpha() const
Get alpha transparency 1 for opaque, 0 for invisible.
Definition: qgssymbolv2.h:373
#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)
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
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
QColor selectionColor() 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)
QColor borderColor() const
Returns the marker&#39;s border color.
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
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.
QGis::GeometryType type() const
Returns type of the geometry as a QGis::GeometryType.
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.
virtual QColor color() const
The fill color.
void setOutlineWidthMapUnitScale(const QgsMapUnitScale &scale)
double mAngle
Marker rotation angle, in degrees clockwise from north.
static Qt::PenStyle decodePenStyle(const QString &str)
double mLineAngle
Line rotation angle (see setLineAngle() for details)
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)
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
void copyDataDefinedProperties(QgsSymbolLayerV2 *destLayer) const
Copies all data defined properties of this layer to another symbol layer.
QString toLower() const
void saveDataDefinedProperties(QgsStringMap &stringMap) const
Saves all data defined properties to a string map.
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
double outlineWidth() const
Get outline width.
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
bool forceVectorOutput() const
virtual QColor color() const override
The fill color.
void restore()
void startRender(QgsSymbolV2RenderContext &context) override
static const QString EXPR_OUTLINE_WIDTH
QTransform & rotate(qreal angle, Qt::Axis axis)
#define DEFAULT_FONTMARKER_FONT
void copyPaintEffect(QgsSymbolLayerV2 *destLayer) const
Copies paint effect of this layer to another symbol layer.
#define DEFAULT_SVGMARKER_NAME
QMatrix & rotate(qreal degrees)
void setBorderColor(const QColor &color)
Sets the marker&#39;s border 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.
QgsSymbolV2::ScaleMethod scaleMethod() const
Returns the method to use for scaling the marker&#39;s size.
Shape shape() const
Returns the shape for the rendered marker symbol.
void drawImage(const QRectF &target, const QImage &image, const QRectF &source, QFlags< Qt::ImageConversionFlag > flags)
QPainter * painter()
const QgsMapToPixel & mapToPixel() const
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)
static QgsSymbolLayerV2 * create(const QgsStringMap &properties=QgsStringMap())
void setOutputUnit(QgsSymbolV2::OutputUnit unit) override
ScaleMethod
Scale method.
Definition: qgssymbolv2.h:90
Struct for storing maximum and minimum scales for measurements in map units.
QgsMapUnitScale mapUnitScale() const override
#define DEFAULT_FONTMARKER_BORDERCOLOR
virtual bool hasDataDefinedProperty(const QString &property) const
Checks whether the layer has a matching data defined property and if that property is currently activ...
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:356
QDomElement firstChildElement(const QString &tagName) const
Q_DECL_DEPRECATED bool preparePath(QString name=QString())
QPen mSelPen
QPen to use as outline of selected symbols.
QPen mPen
QPen corresponding to marker&#39;s outline style.
QSet< QString > usedAttributes() const override
Returns the set of attributes referenced by the layer.
int height() const
int count(const T &value) const
Fill symbol.
Definition: qgssymbolv2.h:83
static const QString EXPR_COLOR_BORDER
double outlineWidth() const
Returns the width of the marker&#39;s outline.
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)
double angle() const
Returns the rotation angle for the marker, in degrees clockwise from north.
QColor fillColor() const override
Get fill color.
QgsSymbolV2::OutputUnit mOffsetUnit
Offset units.
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)
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)
Qt::PenJoinStyle penJoinStyle() const
Returns the marker&#39;s outline join style (eg miter, bevel, etc).
void startRender(QgsSymbolV2RenderContext &context) override
Abstract base class for marker symbol layers.
VerticalAnchorPoint mVerticalAnchorPoint
Vertical anchor point.
QgsSymbolV2::OutputUnit mSizeUnit
Marker size unit.
void setOutlineWidthUnit(QgsSymbolV2::OutputUnit unit)
Set outline width unit.
Calculate scale by the area.
Definition: qgssymbolv2.h:92
QgsMapUnitScale mOffsetMapUnitScale
Offset map unit scale.
void drawPicture(const QPointF &point, const QPicture &picture)
static const QString EXPR_OUTLINE
QRectF bounds(QPointF point, QgsSymbolV2RenderContext &context) override
Returns the approximate bounding box of the marker symbol layer, taking into account any data defined...
HorizontalAnchorPoint
Symbol horizontal anchor points.
void restoreDataDefinedProperties(const QgsStringMap &stringMap)
Restores all data defined properties from string map.
static QgsMapUnitScale decodeMapUnitScale(const QString &str)
Qt::PenJoinStyle mPenJoinStyle
Outline pen join style.
double rasterScaleFactor() const
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.
double scaleFactor() const
bool begin(QPaintDevice *device)
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
QPointF mOffset
Marker offset.
void setSizeMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale for the symbol&#39;s size.
QColor outlineColor() const override
Get outline color.
QPolygonF mPolygon
Polygon of points in shape. If polygon is empty then shape is using mPath.
QgsFilledMarkerSymbolLayer * clone() const override
Shall be reimplemented by subclasses to create a deep copy of the instance.
QgsSimpleMarkerSymbolLayerV2 * clone() const override
Shall be reimplemented by subclasses to create a deep copy of the instance.
void setOutputUnit(QgsSymbolV2::OutputUnit unit) override
QRect mapRect(const QRect &rectangle) const
qreal width() const
QColor outlineColor() const override
Get outline color.
static bool shapeIsFilled(Shape shape)
Returns true if a symbol shape has a fill.
bool prepareCache(QgsSymbolV2RenderContext &context)
Prepares cache image.
Simple marker symbol layer, consisting of a rendered shape with solid fill color and an outline...
double calculateSize(QgsSymbolV2RenderContext &context, bool &hasDataDefinedSize) const
Calculates the desired size of the marker, considering data defined size overrides.
bool prepareMarkerPath(Shape symbol)
Prepares the layer for drawing the specified shape (QPainterPath version)
static const int mMaximumCacheWidth
Maximum width/height of cache image.
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)
#define DEFAULT_SIMPLEMARKER_BORDERCOLOR
QBrush mSelBrush
QBrush to use as fill of selected symbols.
void setOutlineColor(const QColor &color) override
Set outline color.