QGIS API Documentation  2.18.21-Las Palmas (9fba24a)
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 
1242  QString uom = element.attribute( QString( "uom" ), "" );
1244  offset.setX( QgsSymbolLayerV2Utils::sizeInPixelsFromSldUom( uom, offset.x() ) );
1245  offset.setY( QgsSymbolLayerV2Utils::sizeInPixelsFromSldUom( uom, offset.y() ) );
1246 
1249  m->setColor( color );
1250  m->setBorderColor( borderColor );
1251  m->setAngle( angle );
1252  m->setOffset( offset );
1253  m->setOutlineStyle( borderStyle );
1254  return m;
1255 }
1256 
1258 {
1259  Q_UNUSED( context );
1260 
1261  if ( mPolygon.count() != 0 )
1262  {
1263  p->drawPolygon( mPolygon );
1264  }
1265  else
1266  {
1267  p->drawPath( mPath );
1268  }
1269 }
1270 
1271 bool QgsSimpleMarkerSymbolLayerV2::writeDxf( QgsDxfExport& e, double mmMapUnitScaleFactor, const QString& layerName, QgsSymbolV2RenderContext &context, QPointF shift ) const
1272 {
1273  Q_UNUSED( mmMapUnitScaleFactor );
1274 
1275  //data defined size?
1276  double size = mSize;
1277 
1279 
1280  //data defined size
1281  bool ok = true;
1282  if ( hasDataDefinedSize )
1283  {
1285  {
1286  context.setOriginalValueVariable( mSize );
1288  }
1289 
1290  if ( ok )
1291  {
1292  switch ( mScaleMethod )
1293  {
1295  size = sqrt( size );
1296  break;
1298  break;
1299  }
1300  }
1301  }
1302 
1305  {
1307  }
1308  double halfSize = size / 2.0;
1309 
1310  //outlineWidth
1311  double outlineWidth = mOutlineWidth;
1312 
1314  {
1317  }
1320  {
1322  }
1323 
1324  //color
1325  QColor pc = mPen.color();
1326  QColor bc = mBrush.color();
1328  {
1331  if ( ok )
1332  bc = QgsSymbolLayerV2Utils::decodeColor( colorString );
1333  }
1335  {
1338  if ( ok )
1339  pc = QgsSymbolLayerV2Utils::decodeColor( colorString );
1340  }
1341 
1342  //offset
1343  double offsetX = 0;
1344  double offsetY = 0;
1345  markerOffset( context, offsetX, offsetY );
1346  offsetX *= context.renderContext().mapToPixel().mapUnitsPerPixel();
1347  offsetY *= context.renderContext().mapToPixel().mapUnitsPerPixel();
1348 
1349  QPointF off( offsetX, offsetY );
1350 
1351  //angle
1352  double angle = mAngle + mLineAngle;
1354  {
1355  context.setOriginalValueVariable( mAngle );
1357  }
1358 
1359  Shape shape = mShape;
1361  {
1362  context.setOriginalValueVariable( encodeShape( shape ) );
1364  if ( ok )
1365  {
1366  shape = decodeShape( shapeName, &ok );
1367  if ( !ok )
1368  shape = mShape;
1369  }
1370  }
1371 
1372  if ( angle )
1373  off = _rotatedOffset( off, angle );
1374 
1376 
1377  QTransform t;
1378  t.translate( shift.x() + off.x(), shift.y() - off.y() );
1379 
1380  if ( !qgsDoubleNear( angle, 0.0 ) )
1381  t.rotate( angle );
1382 
1383  QPolygonF polygon;
1384  if ( shapeToPolygon( shape, polygon ) )
1385  {
1386  t.scale( halfSize, -halfSize );
1387 
1388  polygon = t.map( polygon );
1389 
1391  for ( int i = 0; i < polygon.size(); i++ )
1392  {
1393  p << QgsPointV2( polygon[i] );
1394  }
1395 
1396  if ( mBrush.style() != Qt::NoBrush )
1397  e.writePolygon( QgsRingSequenceV2() << p, layerName, "SOLID", bc );
1398  if ( mPen.style() != Qt::NoPen )
1399  e.writePolyline( p, layerName, "CONTINUOUS", pc, outlineWidth );
1400  }
1401  else if ( shape == Circle )
1402  {
1403  shift += QPointF( off.x(), -off.y() );
1404  if ( mBrush.style() != Qt::NoBrush )
1405  e.writeFilledCircle( layerName, bc, QgsPointV2( shift ), halfSize );
1406  if ( mPen.style() != Qt::NoPen )
1407  e.writeCircle( layerName, pc, QgsPointV2( shift ), halfSize, "CONTINUOUS", outlineWidth );
1408  }
1409  else if ( shape == Line )
1410  {
1411  QPointF pt1 = t.map( QPointF( 0, -halfSize ) );
1412  QPointF pt2 = t.map( QPointF( 0, halfSize ) );
1413 
1414  if ( mPen.style() != Qt::NoPen )
1415  e.writeLine( QgsPointV2( pt1 ), QgsPointV2( pt2 ), layerName, "CONTINUOUS", pc, outlineWidth );
1416  }
1417  else if ( shape == Cross )
1418  {
1419  if ( mPen.style() != Qt::NoPen )
1420  {
1421  QPointF pt1 = t.map( QPointF( -halfSize, 0 ) );
1422  QPointF pt2 = t.map( QPointF( halfSize, 0 ) );
1423  QPointF pt3 = t.map( QPointF( 0, -halfSize ) );
1424  QPointF pt4 = t.map( QPointF( 0, halfSize ) );
1425 
1426  e.writeLine( QgsPointV2( pt1 ), QgsPointV2( pt2 ), layerName, "CONTINUOUS", pc, outlineWidth );
1427  e.writeLine( QgsPointV2( pt3 ), QgsPointV2( pt4 ), layerName, "CONTINUOUS", pc, outlineWidth );
1428  }
1429  }
1430  else if ( shape == Cross2 )
1431  {
1432  if ( mPen.style() != Qt::NoPen )
1433  {
1434  QPointF pt1 = t.map( QPointF( -halfSize, -halfSize ) );
1435  QPointF pt2 = t.map( QPointF( halfSize, halfSize ) );
1436  QPointF pt3 = t.map( QPointF( halfSize, -halfSize ) );
1437  QPointF pt4 = t.map( QPointF( -halfSize, halfSize ) );
1438 
1439  e.writeLine( QgsPointV2( pt1 ), QgsPointV2( pt2 ), layerName, "CONTINUOUS", pc, outlineWidth );
1440  e.writeLine( QgsPointV2( pt3 ), QgsPointV2( pt4 ), layerName, "CONTINUOUS", pc, outlineWidth );
1441  }
1442  }
1443  else if ( shape == ArrowHead )
1444  {
1445  if ( mPen.style() != Qt::NoPen )
1446  {
1447  QPointF pt1 = t.map( QPointF( -halfSize, halfSize ) );
1448  QPointF pt2 = t.map( QPointF( 0, 0 ) );
1449  QPointF pt3 = t.map( QPointF( -halfSize, -halfSize ) );
1450 
1451  e.writeLine( QgsPointV2( pt1 ), QgsPointV2( pt2 ), layerName, "CONTINUOUS", pc, outlineWidth );
1452  e.writeLine( QgsPointV2( pt3 ), QgsPointV2( pt2 ), layerName, "CONTINUOUS", pc, outlineWidth );
1453  }
1454  }
1455  else
1456  {
1457  QgsDebugMsg( QString( "Unsupported dxf marker name %1" ).arg( encodeShape( shape ) ) );
1458  return false;
1459  }
1460 
1461  return true;
1462 }
1463 
1464 
1466 {
1468  mOutlineWidthUnit = unit;
1469 }
1470 
1472 {
1474  {
1475  return mOutlineWidthUnit;
1476  }
1477  return QgsSymbolV2::Mixed;
1478 }
1479 
1481 {
1483  mOutlineWidthMapUnitScale = scale;
1484 }
1485 
1487 {
1489  {
1491  }
1492  return QgsMapUnitScale();
1493 }
1494 
1496 {
1497  QRectF symbolBounds = QgsSimpleMarkerSymbolLayerBase::bounds( point, context );
1498 
1499  // need to account for outline width
1500  double pixelSize = 1.0 / context.renderContext().rasterScaleFactor();
1501  double penWidth = 0.0;
1502  bool ok = true;
1504  {
1507  if ( ok )
1508  {
1510  }
1511  }
1513  {
1516  if ( ok && outlineStyle == "no" )
1517  {
1518  penWidth = 0.0;
1519  }
1520  }
1521  //antialiasing
1522  penWidth += pixelSize;
1523 
1524  //extend bounds by pen width / 2.0
1525  symbolBounds.adjust( -penWidth / 2.0, -penWidth / 2.0,
1526  penWidth / 2.0, penWidth / 2.0 );
1527 
1528  return symbolBounds;
1529 }
1530 
1532 {
1533  if ( shapeIsFilled( mShape ) )
1534  {
1535  setFillColor( color );
1536  }
1537  else
1538  {
1539  setOutlineColor( color );
1540  }
1541 }
1542 
1544 {
1545  if ( shapeIsFilled( mShape ) )
1546  {
1547  return fillColor();
1548  }
1549  else
1550  {
1551  return outlineColor();
1552  }
1553 }
1554 
1555 
1556 
1557 
1558 //
1559 // QgsFilledMarkerSymbolLayer
1560 //
1561 
1563  : QgsSimpleMarkerSymbolLayerBase( shape, size, angle, scaleMethod )
1564 {
1565  mFill.reset( static_cast<QgsFillSymbolV2*>( QgsFillSymbolV2::createSimple( QgsStringMap() ) ) );
1566 }
1567 
1569 {
1574 
1575  if ( props.contains( "name" ) )
1576  name = props["name"];
1577  if ( props.contains( "size" ) )
1578  size = props["size"].toDouble();
1579  if ( props.contains( "angle" ) )
1580  angle = props["angle"].toDouble();
1581  if ( props.contains( "scale_method" ) )
1582  scaleMethod = QgsSymbolLayerV2Utils::decodeScaleMethod( props["scale_method"] );
1583 
1584  QgsFilledMarkerSymbolLayer* m = new QgsFilledMarkerSymbolLayer( decodeShape( name ), size, angle, scaleMethod );
1585  if ( props.contains( "offset" ) )
1586  m->setOffset( QgsSymbolLayerV2Utils::decodePoint( props["offset"] ) );
1587  if ( props.contains( "offset_unit" ) )
1588  m->setOffsetUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["offset_unit"] ) );
1589  if ( props.contains( "offset_map_unit_scale" ) )
1590  m->setOffsetMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["offset_map_unit_scale"] ) );
1591  if ( props.contains( "size_unit" ) )
1592  m->setSizeUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["size_unit"] ) );
1593  if ( props.contains( "size_map_unit_scale" ) )
1594  m->setSizeMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["size_map_unit_scale"] ) );
1595  if ( props.contains( "horizontal_anchor_point" ) )
1596  {
1597  m->setHorizontalAnchorPoint( QgsMarkerSymbolLayerV2::HorizontalAnchorPoint( props[ "horizontal_anchor_point" ].toInt() ) );
1598  }
1599  if ( props.contains( "vertical_anchor_point" ) )
1600  {
1601  m->setVerticalAnchorPoint( QgsMarkerSymbolLayerV2::VerticalAnchorPoint( props[ "vertical_anchor_point" ].toInt() ) );
1602  }
1603 
1605 
1606  m->restoreDataDefinedProperties( props );
1607 
1608  return m;
1609 }
1610 
1612 {
1613  return "FilledMarker";
1614 }
1615 
1617 {
1618  if ( mFill.data() )
1619  {
1620  mFill->startRender( context.renderContext(), context.fields() );
1621  }
1622 
1624 }
1625 
1627 {
1628  if ( mFill.data() )
1629  {
1630  mFill->stopRender( context.renderContext() );
1631  }
1632 }
1633 
1635 {
1636  QgsStringMap map;
1637  map["name"] = encodeShape( mShape );
1638  map["size"] = QString::number( mSize );
1639  map["size_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mSizeUnit );
1640  map["size_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mSizeMapUnitScale );
1641  map["angle"] = QString::number( mAngle );
1642  map["offset"] = QgsSymbolLayerV2Utils::encodePoint( mOffset );
1643  map["offset_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOffsetUnit );
1644  map["offset_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOffsetMapUnitScale );
1645  map["scale_method"] = QgsSymbolLayerV2Utils::encodeScaleMethod( mScaleMethod );
1646  map["horizontal_anchor_point"] = QString::number( mHorizontalAnchorPoint );
1647  map["vertical_anchor_point"] = QString::number( mVerticalAnchorPoint );
1648 
1649  if ( mFill.data() )
1650  {
1651  map["color"] = QgsSymbolLayerV2Utils::encodeColor( mFill->color() );
1652  }
1653 
1654  //data define properties
1656  return map;
1657 }
1658 
1660 {
1662  copyPaintEffect( m );
1663  m->setSubSymbol( mFill->clone() );
1664  return m;
1665 }
1666 
1668 {
1669  return mFill.data();
1670 }
1671 
1673 {
1674  if ( symbol && symbol->type() == QgsSymbolV2::Fill )
1675  {
1676  mFill.reset( static_cast<QgsFillSymbolV2*>( symbol ) );
1677  return true;
1678  }
1679  else
1680  {
1681  delete symbol;
1682  return false;
1683  }
1684 }
1685 
1687 {
1688  if ( mFill.data() )
1689  {
1691  }
1692  return 0;
1693 }
1694 
1696 {
1698  if ( mFill.data() )
1699  attr.unite( mFill->usedAttributes() );
1700  return attr;
1701 }
1702 
1704 {
1705  mColor = c;
1706  if ( mFill.data() )
1707  mFill->setColor( c );
1708 }
1709 
1711 {
1712  return mFill.data() ? mFill->color() : mColor;
1713 }
1714 
1715 void QgsFilledMarkerSymbolLayer::draw( QgsSymbolV2RenderContext &context, QgsSimpleMarkerSymbolLayerBase::Shape shape, const QPolygonF &polygon, const QPainterPath &path )
1716 {
1717  //making changes here? Don't forget to also update ::bounds if the changes affect the bounding box
1718  //of the rendered point!
1719 
1720  QPainter *p = context.renderContext().painter();
1721  if ( !p )
1722  {
1723  return;
1724  }
1725 
1726  if ( shapeIsFilled( shape ) )
1727  {
1728  p->setBrush( Qt::red );
1729  }
1730  else
1731  {
1732  p->setBrush( Qt::NoBrush );
1733  }
1734  p->setPen( Qt::black );
1735 
1736  if ( !polygon.isEmpty() )
1737  {
1738  mFill->renderPolygon( polygon, /* rings */ nullptr, context.feature(), context.renderContext(), -1, context.selected() );
1739  }
1740  else
1741  {
1742  QPolygonF poly = path.toFillPolygon();
1743  mFill->renderPolygon( poly, /* rings */ nullptr, context.feature(), context.renderContext(), -1, context.selected() );
1744  }
1745 
1746 
1747 }
1748 
1749 
1751 
1752 
1754 {
1756  mSize = size;
1757  mAngle = angle;
1758  mOffset = QPointF( 0, 0 );
1760  mOutlineWidth = 0.2;
1761  mOutlineWidthUnit = QgsSymbolV2::MM;
1762  mColor = QColor( Qt::black );
1763  mOutlineColor = QColor( Qt::black );
1764 }
1765 
1766 
1768 {
1770  double size = DEFAULT_SVGMARKER_SIZE;
1771  double angle = DEFAULT_SVGMARKER_ANGLE;
1773 
1774  if ( props.contains( "name" ) )
1775  name = props["name"];
1776  if ( props.contains( "size" ) )
1777  size = props["size"].toDouble();
1778  if ( props.contains( "angle" ) )
1779  angle = props["angle"].toDouble();
1780  if ( props.contains( "scale_method" ) )
1781  scaleMethod = QgsSymbolLayerV2Utils::decodeScaleMethod( props["scale_method"] );
1782 
1783  QgsSvgMarkerSymbolLayerV2* m = new QgsSvgMarkerSymbolLayerV2( name, size, angle, scaleMethod );
1784 
1785  //we only check the svg default parameters if necessary, since it could be expensive
1786  if ( !props.contains( "fill" ) && !props.contains( "color" ) && !props.contains( "outline" ) &&
1787  !props.contains( "outline_color" ) && !props.contains( "outline-width" ) && !props.contains( "outline_width" ) )
1788  {
1790  double fillOpacity = 1.0;
1791  double outlineOpacity = 1.0;
1792  double outlineWidth;
1793  bool hasFillParam = false, hasFillOpacityParam = false, hasOutlineParam = false, hasOutlineWidthParam = false, hasOutlineOpacityParam = false;
1794  bool hasDefaultFillColor = false, hasDefaultFillOpacity = false, hasDefaultOutlineColor = false, hasDefaultOutlineWidth = false, hasDefaultOutlineOpacity = false;
1795  QgsSvgCache::instance()->containsParams( name, hasFillParam, hasDefaultFillColor, fillColor,
1796  hasFillOpacityParam, hasDefaultFillOpacity, fillOpacity,
1797  hasOutlineParam, hasDefaultOutlineColor, outlineColor,
1798  hasOutlineWidthParam, hasDefaultOutlineWidth, outlineWidth,
1799  hasOutlineOpacityParam, hasDefaultOutlineOpacity, outlineOpacity );
1800  if ( hasDefaultFillColor )
1801  {
1802  m->setFillColor( fillColor );
1803  }
1804  if ( hasDefaultFillOpacity )
1805  {
1806  QColor c = m->fillColor();
1807  c.setAlphaF( fillOpacity );
1808  m->setFillColor( c );
1809  }
1810  if ( hasDefaultOutlineColor )
1811  {
1812  m->setOutlineColor( outlineColor );
1813  }
1814  if ( hasDefaultOutlineWidth )
1815  {
1816  m->setOutlineWidth( outlineWidth );
1817  }
1818  if ( hasDefaultOutlineOpacity )
1819  {
1820  QColor c = m->outlineColor();
1821  c.setAlphaF( outlineOpacity );
1822  m->setOutlineColor( c );
1823  }
1824  }
1825 
1826  if ( props.contains( "size_unit" ) )
1827  m->setSizeUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["size_unit"] ) );
1828  if ( props.contains( "size_map_unit_scale" ) )
1829  m->setSizeMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["size_map_unit_scale"] ) );
1830  if ( props.contains( "offset" ) )
1831  m->setOffset( QgsSymbolLayerV2Utils::decodePoint( props["offset"] ) );
1832  if ( props.contains( "offset_unit" ) )
1833  m->setOffsetUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["offset_unit"] ) );
1834  if ( props.contains( "offset_map_unit_scale" ) )
1835  m->setOffsetMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["offset_map_unit_scale"] ) );
1836  if ( props.contains( "fill" ) )
1837  {
1838  //pre 2.5 projects used "fill"
1839  m->setFillColor( QgsSymbolLayerV2Utils::decodeColor( props["fill"] ) );
1840  }
1841  else if ( props.contains( "color" ) )
1842  {
1843  m->setFillColor( QgsSymbolLayerV2Utils::decodeColor( props["color"] ) );
1844  }
1845  if ( props.contains( "outline" ) )
1846  {
1847  //pre 2.5 projects used "outline"
1848  m->setOutlineColor( QgsSymbolLayerV2Utils::decodeColor( props["outline"] ) );
1849  }
1850  else if ( props.contains( "outline_color" ) )
1851  {
1852  m->setOutlineColor( QgsSymbolLayerV2Utils::decodeColor( props["outline_color"] ) );
1853  }
1854  else if ( props.contains( "line_color" ) )
1855  {
1856  m->setOutlineColor( QgsSymbolLayerV2Utils::decodeColor( props["line_color"] ) );
1857  }
1858 
1859  if ( props.contains( "outline-width" ) )
1860  {
1861  //pre 2.5 projects used "outline-width"
1862  m->setOutlineWidth( props["outline-width"].toDouble() );
1863  }
1864  else if ( props.contains( "outline_width" ) )
1865  {
1866  m->setOutlineWidth( props["outline_width"].toDouble() );
1867  }
1868  else if ( props.contains( "line_width" ) )
1869  {
1870  m->setOutlineWidth( props["line_width"].toDouble() );
1871  }
1872 
1873  if ( props.contains( "outline_width_unit" ) )
1874  {
1875  m->setOutlineWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["outline_width_unit"] ) );
1876  }
1877  else if ( props.contains( "line_width_unit" ) )
1878  {
1879  m->setOutlineWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["line_width_unit"] ) );
1880  }
1881  if ( props.contains( "outline_width_map_unit_scale" ) )
1882  m->setOutlineWidthMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["outline_width_map_unit_scale"] ) );
1883 
1884  if ( props.contains( "horizontal_anchor_point" ) )
1885  {
1886  m->setHorizontalAnchorPoint( QgsMarkerSymbolLayerV2::HorizontalAnchorPoint( props[ "horizontal_anchor_point" ].toInt() ) );
1887  }
1888  if ( props.contains( "vertical_anchor_point" ) )
1889  {
1890  m->setVerticalAnchorPoint( QgsMarkerSymbolLayerV2::VerticalAnchorPoint( props[ "vertical_anchor_point" ].toInt() ) );
1891  }
1892 
1893  m->restoreDataDefinedProperties( props );
1894 
1895  return m;
1896 }
1897 
1899 {
1900  mPath = path;
1901  QColor defaultFillColor, defaultOutlineColor;
1902  double outlineWidth, fillOpacity, outlineOpacity;
1903  bool hasFillParam = false, hasFillOpacityParam = false, hasOutlineParam = false, hasOutlineWidthParam = false, hasOutlineOpacityParam = false;
1904  bool hasDefaultFillColor = false, hasDefaultFillOpacity = false, hasDefaultOutlineColor = false, hasDefaultOutlineWidth = false, hasDefaultOutlineOpacity = false;
1905  QgsSvgCache::instance()->containsParams( path, hasFillParam, hasDefaultFillColor, defaultFillColor,
1906  hasFillOpacityParam, hasDefaultFillOpacity, fillOpacity,
1907  hasOutlineParam, hasDefaultOutlineColor, defaultOutlineColor,
1908  hasOutlineWidthParam, hasDefaultOutlineWidth, outlineWidth,
1909  hasOutlineOpacityParam, hasDefaultOutlineOpacity, outlineOpacity );
1910 
1911  double newFillOpacity = hasFillOpacityParam ? fillColor().alphaF() : 1.0;
1912  double newOutlineOpacity = hasOutlineOpacityParam ? outlineColor().alphaF() : 1.0;
1913 
1914  if ( hasDefaultFillColor )
1915  {
1916  defaultFillColor.setAlphaF( newFillOpacity );
1917  setFillColor( defaultFillColor );
1918  }
1919  if ( hasDefaultFillOpacity )
1920  {
1921  QColor c = fillColor();
1922  c.setAlphaF( fillOpacity );
1923  setFillColor( c );
1924  }
1925  if ( hasDefaultOutlineColor )
1926  {
1927  defaultOutlineColor.setAlphaF( newOutlineOpacity );
1928  setOutlineColor( defaultOutlineColor );
1929  }
1930  if ( hasDefaultOutlineWidth )
1931  {
1932  setOutlineWidth( outlineWidth );
1933  }
1934  if ( hasDefaultOutlineOpacity )
1935  {
1936  QColor c = outlineColor();
1937  c.setAlphaF( outlineOpacity );
1938  setOutlineColor( c );
1939  }
1940 }
1941 
1942 
1944 {
1945  return "SvgMarker";
1946 }
1947 
1949 {
1950  QgsMarkerSymbolLayerV2::startRender( context ); // get anchor point expressions
1951  Q_UNUSED( context );
1952  prepareExpressions( context );
1953 }
1954 
1956 {
1957  Q_UNUSED( context );
1958 }
1959 
1961 {
1962  QPainter *p = context.renderContext().painter();
1963  if ( !p )
1964  return;
1965 
1966  bool hasDataDefinedSize = false;
1967  double scaledSize = calculateSize( context, hasDataDefinedSize );
1969 
1970  //don't render symbols with size below one or above 10,000 pixels
1971  if ( static_cast< int >( size ) < 1 || 10000.0 < size )
1972  {
1973  return;
1974  }
1975 
1976  p->save();
1977 
1978  QPointF outputOffset;
1979  double angle = 0.0;
1980  calculateOffsetAndRotation( context, scaledSize, outputOffset, angle );
1981 
1982  p->translate( point + outputOffset );
1983 
1984  bool rotated = !qgsDoubleNear( angle, 0 );
1985  if ( rotated )
1986  p->rotate( angle );
1987 
1988  QString path = mPath;
1990  {
1991  context.setOriginalValueVariable( mPath );
1993  }
1994 
1995  double outlineWidth = mOutlineWidth;
1997  {
1998  context.setOriginalValueVariable( mOutlineWidth );
1999  outlineWidth = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_OUTLINE_WIDTH, context, mOutlineWidth ).toDouble();
2000  }
2001  outlineWidth = QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), outlineWidth, mOutlineWidthUnit, mOutlineWidthMapUnitScale );
2002 
2004  bool ok = false;
2006  {
2009  if ( ok )
2010  fillColor = QgsSymbolLayerV2Utils::decodeColor( colorString );
2011  }
2012 
2013  QColor outlineColor = mOutlineColor;
2015  {
2018  if ( ok )
2019  outlineColor = QgsSymbolLayerV2Utils::decodeColor( colorString );
2020  }
2021 
2022  bool fitsInCache = true;
2023  bool usePict = true;
2024  double hwRatio = 1.0;
2025  if ( !context.renderContext().forceVectorOutput() && !rotated )
2026  {
2027  usePict = false;
2028  const QImage& img = QgsSvgCache::instance()->svgAsImage( path, size, fillColor, outlineColor, outlineWidth,
2029  context.renderContext().scaleFactor(), context.renderContext().rasterScaleFactor(), fitsInCache );
2030  if ( fitsInCache && img.width() > 1 )
2031  {
2032  //consider transparency
2033  if ( !qgsDoubleNear( context.alpha(), 1.0 ) )
2034  {
2035  QImage transparentImage = img.copy();
2036  QgsSymbolLayerV2Utils::multiplyImageOpacity( &transparentImage, context.alpha() );
2037  p->drawImage( -transparentImage.width() / 2.0, -transparentImage.height() / 2.0, transparentImage );
2038  hwRatio = static_cast< double >( transparentImage.height() ) / static_cast< double >( transparentImage.width() );
2039  }
2040  else
2041  {
2042  p->drawImage( -img.width() / 2.0, -img.height() / 2.0, img );
2043  hwRatio = static_cast< double >( img.height() ) / static_cast< double >( img.width() );
2044  }
2045  }
2046  }
2047 
2048  if ( usePict || !fitsInCache )
2049  {
2050  p->setOpacity( context.alpha() );
2051  const QPicture& pct = QgsSvgCache::instance()->svgAsPicture( path, size, fillColor, outlineColor, outlineWidth,
2053 
2054  if ( pct.width() > 1 )
2055  {
2056  p->save();
2057  _fixQPictureDPI( p );
2058  p->drawPicture( 0, 0, pct );
2059  p->restore();
2060  hwRatio = static_cast< double >( pct.height() ) / static_cast< double >( pct.width() );
2061  }
2062  }
2063 
2064  if ( context.selected() )
2065  {
2066  QPen pen( context.renderContext().selectionColor() );
2068  if ( penWidth > size / 20 )
2069  {
2070  // keep the pen width from covering symbol
2071  penWidth = size / 20;
2072  }
2073  double penOffset = penWidth / 2;
2074  pen.setWidth( penWidth );
2075  p->setPen( pen );
2076  p->setBrush( Qt::NoBrush );
2077  double wSize = size + penOffset;
2078  double hSize = size * hwRatio + penOffset;
2079  p->drawRect( QRectF( -wSize / 2.0, -hSize / 2.0, wSize, hSize ) );
2080  }
2081 
2082  p->restore();
2083 
2085  {
2086  // workaround issue with nested QPictures forgetting antialiasing flag - see http://hub.qgis.org/issues/14960
2087  p->setRenderHint( QPainter::Antialiasing );
2088  }
2089 
2090 }
2091 
2092 double QgsSvgMarkerSymbolLayerV2::calculateSize( QgsSymbolV2RenderContext& context, bool& hasDataDefinedSize ) const
2093 {
2094  double scaledSize = mSize;
2096 
2097  bool ok = true;
2099  {
2100  context.setOriginalValueVariable( mSize );
2101  scaledSize = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_SIZE, context, mSize, &ok ).toDouble();
2102  }
2103 
2104  if ( hasDataDefinedSize && ok )
2105  {
2106  switch ( mScaleMethod )
2107  {
2109  scaledSize = sqrt( scaledSize );
2110  break;
2112  break;
2113  }
2114  }
2115 
2116  return scaledSize;
2117 }
2118 
2119 void QgsSvgMarkerSymbolLayerV2::calculateOffsetAndRotation( QgsSymbolV2RenderContext& context, double scaledSize, QPointF& offset, double& angle ) const
2120 {
2121  //offset
2122  double offsetX = 0;
2123  double offsetY = 0;
2124  markerOffset( context, scaledSize, scaledSize, offsetX, offsetY );
2125  offset = QPointF( offsetX, offsetY );
2126 
2127  angle = mAngle + mLineAngle;
2129  {
2130  context.setOriginalValueVariable( mAngle );
2132  }
2133 
2135  if ( hasDataDefinedRotation )
2136  {
2137  // For non-point markers, "dataDefinedRotation" means following the
2138  // shape (shape-data defined). For them, "field-data defined" does
2139  // not work at all. TODO: if "field-data defined" ever gets implemented
2140  // we'll need a way to distinguish here between the two, possibly
2141  // using another flag in renderHints()
2142  const QgsFeature* f = context.feature();
2143  if ( f )
2144  {
2145  const QgsGeometry *g = f->constGeometry();
2146  if ( g && g->type() == QGis::Point )
2147  {
2148  const QgsMapToPixel& m2p = context.renderContext().mapToPixel();
2149  angle += m2p.mapRotation();
2150  }
2151  }
2152  }
2153 
2154  if ( angle )
2155  offset = _rotatedOffset( offset, angle );
2156 }
2157 
2158 
2160 {
2161  QgsStringMap map;
2163  map["size"] = QString::number( mSize );
2164  map["size_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mSizeUnit );
2165  map["size_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mSizeMapUnitScale );
2166  map["angle"] = QString::number( mAngle );
2167  map["offset"] = QgsSymbolLayerV2Utils::encodePoint( mOffset );
2168  map["offset_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOffsetUnit );
2169  map["offset_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOffsetMapUnitScale );
2170  map["scale_method"] = QgsSymbolLayerV2Utils::encodeScaleMethod( mScaleMethod );
2171  map["color"] = QgsSymbolLayerV2Utils::encodeColor( mColor );
2172  map["outline_color"] = QgsSymbolLayerV2Utils::encodeColor( mOutlineColor );
2173  map["outline_width"] = QString::number( mOutlineWidth );
2174  map["outline_width_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOutlineWidthUnit );
2175  map["outline_width_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOutlineWidthMapUnitScale );
2176  map["horizontal_anchor_point"] = QString::number( mHorizontalAnchorPoint );
2177  map["vertical_anchor_point"] = QString::number( mVerticalAnchorPoint );
2178 
2180  return map;
2181 }
2182 
2184 {
2186  m->setColor( mColor );
2187  m->setOutlineColor( mOutlineColor );
2188  m->setOutlineWidth( mOutlineWidth );
2189  m->setOutlineWidthUnit( mOutlineWidthUnit );
2190  m->setOutlineWidthMapUnitScale( mOutlineWidthMapUnitScale );
2191  m->setOffset( mOffset );
2192  m->setOffsetUnit( mOffsetUnit );
2194  m->setSizeUnit( mSizeUnit );
2199  copyPaintEffect( m );
2200  return m;
2201 }
2202 
2204 {
2206  mOutlineWidthUnit = unit;
2207 }
2208 
2210 {
2212  if ( unit != mOutlineWidthUnit )
2213  {
2214  return QgsSymbolV2::Mixed;
2215  }
2216  return unit;
2217 }
2218 
2220 {
2222  mOutlineWidthMapUnitScale = scale;
2223 }
2224 
2226 {
2227  if ( QgsMarkerSymbolLayerV2::mapUnitScale() == mOutlineWidthMapUnitScale )
2228  {
2229  return mOutlineWidthMapUnitScale;
2230  }
2231  return QgsMapUnitScale();
2232 }
2233 
2235 {
2236  // <Graphic>
2237  QDomElement graphicElem = doc.createElement( "se:Graphic" );
2238  element.appendChild( graphicElem );
2239 
2241  QgsSymbolLayerV2Utils::externalGraphicToSld( doc, graphicElem, mPath, "image/svg+xml", mColor, size );
2242 
2243  // <Rotation>
2244  QString angleFunc;
2245  bool ok;
2246  double angle = props.value( "angle", "0" ).toDouble( &ok );
2247  if ( !ok )
2248  {
2249  angleFunc = QString( "%1 + %2" ).arg( props.value( "angle", "0" ) ).arg( mAngle );
2250  }
2251  else if ( !qgsDoubleNear( angle + mAngle, 0.0 ) )
2252  {
2253  angleFunc = QString::number( angle + mAngle );
2254  }
2255 
2256  QgsSymbolLayerV2Utils::createRotationElement( doc, graphicElem, angleFunc );
2257 
2258  // <Displacement>
2260  QgsSymbolLayerV2Utils::createDisplacementElement( doc, graphicElem, offset );
2261 }
2262 
2264 {
2265  QgsDebugMsg( "Entered." );
2266 
2267  QDomElement graphicElem = element.firstChildElement( "Graphic" );
2268  if ( graphicElem.isNull() )
2269  return nullptr;
2270 
2271  QString path, mimeType;
2272  QColor fillColor;
2273  double size;
2274 
2275  if ( !QgsSymbolLayerV2Utils::externalGraphicFromSld( graphicElem, path, mimeType, fillColor, size ) )
2276  return nullptr;
2277 
2278  QString uom = element.attribute( QString( "uom" ), "" );
2280 
2281  if ( mimeType != "image/svg+xml" )
2282  return nullptr;
2283 
2284  double angle = 0.0;
2285  QString angleFunc;
2286  if ( QgsSymbolLayerV2Utils::rotationFromSldElement( graphicElem, angleFunc ) )
2287  {
2288  bool ok;
2289  double d = angleFunc.toDouble( &ok );
2290  if ( ok )
2291  angle = d;
2292  }
2293 
2294  QPointF offset;
2296 
2299  m->setFillColor( fillColor );
2300  //m->setOutlineColor( outlineColor );
2301  //m->setOutlineWidth( outlineWidth );
2302  m->setAngle( angle );
2303  m->setOffset( offset );
2304  return m;
2305 }
2306 
2307 bool QgsSvgMarkerSymbolLayerV2::writeDxf( QgsDxfExport& e, double mmMapUnitScaleFactor, const QString& layerName, QgsSymbolV2RenderContext &context, QPointF shift ) const
2308 {
2309  Q_UNUSED( layerName );
2310  Q_UNUSED( shift ); //todo...
2311 
2312  //size
2313  double size = mSize;
2314 
2316 
2317  bool ok = true;
2319  {
2320  context.setOriginalValueVariable( mSize );
2322  }
2323 
2324  if ( hasDataDefinedSize && ok )
2325  {
2326  switch ( mScaleMethod )
2327  {
2329  size = sqrt( size );
2330  break;
2332  break;
2333  }
2334  }
2335 
2336  if ( mSizeUnit == QgsSymbolV2::MM )
2337  {
2338  size *= mmMapUnitScaleFactor;
2339  }
2340 
2341  double halfSize = size / 2.0;
2342 
2343  //offset, angle
2344  QPointF offset = mOffset;
2345 
2347  {
2350  if ( ok )
2351  offset = QgsSymbolLayerV2Utils::decodePoint( offsetString );
2352  }
2353  double offsetX = offset.x();
2354  double offsetY = offset.y();
2355 
2356  QPointF outputOffset( offsetX, offsetY );
2357 
2358  double angle = mAngle + mLineAngle;
2360  {
2361  context.setOriginalValueVariable( mAngle );
2363  }
2364  //angle = -angle; //rotation in Qt is counterclockwise
2365  if ( angle )
2366  outputOffset = _rotatedOffset( outputOffset, angle );
2367 
2369 
2370  QString path = mPath;
2372  {
2373  context.setOriginalValueVariable( mPath );
2375  }
2376 
2377  double outlineWidth = mOutlineWidth;
2379  {
2380  context.setOriginalValueVariable( mOutlineWidth );
2381  outlineWidth = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_OUTLINE_WIDTH, context, mOutlineWidth ).toDouble();
2382  }
2383  outlineWidth *= e.mapUnitScaleFactor( e.symbologyScaleDenominator(), mOutlineWidthUnit, e.mapUnits(), context.renderContext().mapToPixel().mapUnitsPerPixel() );
2384 
2387  {
2390  if ( ok )
2391  fillColor = QgsSymbolLayerV2Utils::decodeColor( colorString );
2392  }
2393 
2394  QColor outlineColor = mOutlineColor;
2396  {
2399  if ( ok )
2400  outlineColor = QgsSymbolLayerV2Utils::decodeColor( colorString );
2401  }
2402 
2403  const QByteArray &svgContent = QgsSvgCache::instance()->svgContent( path, size, fillColor, outlineColor, outlineWidth,
2404  context.renderContext().scaleFactor(),
2405  context.renderContext().rasterScaleFactor() );
2406 
2407  //if current entry image is 0: cache image for entry
2408  // checks to see if image will fit into cache
2409  //update stats for memory usage
2410  QSvgRenderer r( svgContent );
2411  if ( !r.isValid() )
2412  {
2413  return false;
2414  }
2415 
2416  QgsDxfPaintDevice pd( &e );
2417  pd.setDrawingSize( QSizeF( r.defaultSize() ) );
2418 
2419  QPainter p;
2420  p.begin( &pd );
2421  if ( !qgsDoubleNear( angle, 0.0 ) )
2422  {
2423  p.translate( r.defaultSize().width() / 2.0, r.defaultSize().height() / 2.0 );
2424  p.rotate( angle );
2425  p.translate( -r.defaultSize().width() / 2.0, -r.defaultSize().height() / 2.0 );
2426  }
2427  pd.setShift( shift + QPointF( outputOffset.x(), -outputOffset.y() ) );
2428  pd.setOutputSize( QRectF( -halfSize, -halfSize, size, size ) );
2429  pd.setLayer( layerName );
2430  r.render( &p );
2431  p.end();
2432  return true;
2433 }
2434 
2436 {
2437  bool hasDataDefinedSize = false;
2438  double scaledSize = calculateSize( context, hasDataDefinedSize );
2440 
2441  //don't render symbols with size below one or above 10,000 pixels
2442  if ( static_cast< int >( scaledSize ) < 1 || 10000.0 < scaledSize )
2443  {
2444  return QRectF();
2445  }
2446 
2447  QPointF outputOffset;
2448  double angle = 0.0;
2449  calculateOffsetAndRotation( context, scaledSize, outputOffset, angle );
2450 
2451  QString path = mPath;
2453  {
2454  context.setOriginalValueVariable( mPath );
2456  }
2457 
2458  double outlineWidth = mOutlineWidth;
2460  {
2461  context.setOriginalValueVariable( mOutlineWidth );
2462  outlineWidth = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_OUTLINE_WIDTH, context, mOutlineWidth ).toDouble();
2463  }
2464  outlineWidth = QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), outlineWidth, mOutlineWidthUnit, mOutlineWidthMapUnitScale );
2465 
2466  //need to get colors to take advantage of cached SVGs
2468  bool ok = false;
2470  {
2473  if ( ok )
2474  fillColor = QgsSymbolLayerV2Utils::decodeColor( colorString );
2475  }
2476 
2477  QColor outlineColor = mOutlineColor;
2479  {
2482  if ( ok )
2483  outlineColor = QgsSymbolLayerV2Utils::decodeColor( colorString );
2484  }
2485 
2486  QSizeF svgViewbox = QgsSvgCache::instance()->svgViewboxSize( path, scaledSize, fillColor, outlineColor, outlineWidth,
2487  context.renderContext().scaleFactor(),
2488  context.renderContext().rasterScaleFactor() );
2489 
2490  double scaledHeight = svgViewbox.isValid() ? scaledSize * svgViewbox.height() / svgViewbox.width() : scaledSize;
2491  double pixelSize = 1.0 / context.renderContext().rasterScaleFactor();
2492 
2493  QMatrix transform;
2494 
2495  // move to the desired position
2496  transform.translate( point.x() + outputOffset.x(), point.y() + outputOffset.y() );
2497 
2498  if ( !qgsDoubleNear( angle, 0.0 ) )
2499  transform.rotate( angle );
2500 
2501  //antialiasing
2502  outlineWidth += pixelSize / 2.0;
2503 
2504  QRectF symbolBounds = transform.mapRect( QRectF( -scaledSize / 2.0,
2505  -scaledHeight / 2.0,
2506  scaledSize,
2507  scaledHeight ) );
2508 
2509  //extend bounds by pen width / 2.0
2510  symbolBounds.adjust( -outlineWidth / 2.0, -outlineWidth / 2.0,
2511  outlineWidth / 2.0, outlineWidth / 2.0 );
2512 
2513  return symbolBounds;
2514 
2515 }
2516 
2518 
2519 QgsFontMarkerSymbolLayerV2::QgsFontMarkerSymbolLayerV2( const QString& fontFamily, QChar chr, double pointSize, const QColor& color, double angle )
2520  : mFontMetrics( nullptr )
2521  , mChrWidth( 0 )
2522 {
2524  mChr = chr;
2525  mColor = color;
2526  mAngle = angle;
2527  mSize = pointSize;
2528  mOrigSize = pointSize;
2530  mOffset = QPointF( 0, 0 );
2532  mOutlineColor = DEFAULT_FONTMARKER_BORDERCOLOR;
2533  mOutlineWidth = 0.0;
2534  mOutlineWidthUnit = QgsSymbolV2::MM;
2535  mPenJoinStyle = DEFAULT_FONTMARKER_JOINSTYLE;
2536 }
2537 
2539 {
2540  delete mFontMetrics;
2541 }
2542 
2544 {
2547  double pointSize = DEFAULT_FONTMARKER_SIZE;
2550 
2551  if ( props.contains( "font" ) )
2552  fontFamily = props["font"];
2553  if ( props.contains( "chr" ) && props["chr"].length() > 0 )
2554  chr = props["chr"].at( 0 );
2555  if ( props.contains( "size" ) )
2556  pointSize = props["size"].toDouble();
2557  if ( props.contains( "color" ) )
2558  color = QgsSymbolLayerV2Utils::decodeColor( props["color"] );
2559  if ( props.contains( "angle" ) )
2560  angle = props["angle"].toDouble();
2561 
2562  QgsFontMarkerSymbolLayerV2* m = new QgsFontMarkerSymbolLayerV2( fontFamily, chr, pointSize, color, angle );
2563 
2564  if ( props.contains( "outline_color" ) )
2565  m->setOutlineColor( QgsSymbolLayerV2Utils::decodeColor( props["outline_color"] ) );
2566  if ( props.contains( "outline_width" ) )
2567  m->setOutlineWidth( props["outline_width"].toDouble() );
2568  if ( props.contains( "offset" ) )
2569  m->setOffset( QgsSymbolLayerV2Utils::decodePoint( props["offset"] ) );
2570  if ( props.contains( "offset_unit" ) )
2571  m->setOffsetUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["offset_unit" ] ) );
2572  if ( props.contains( "offset_map_unit_scale" ) )
2573  m->setOffsetMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["offset_map_unit_scale" ] ) );
2574  if ( props.contains( "size_unit" ) )
2575  m->setSizeUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["size_unit"] ) );
2576  if ( props.contains( "size_map_unit_scale" ) )
2577  m->setSizeMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["size_map_unit_scale"] ) );
2578  if ( props.contains( "outline_width_unit" ) )
2579  m->setOutlineWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["outline_width_unit"] ) );
2580  if ( props.contains( "outline_width_map_unit_scale" ) )
2581  m->setOutlineWidthMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["outline_width_map_unit_scale"] ) );
2582  if ( props.contains( "joinstyle" ) )
2583  m->setPenJoinStyle( QgsSymbolLayerV2Utils::decodePenJoinStyle( props["joinstyle"] ) );
2584  if ( props.contains( "horizontal_anchor_point" ) )
2585  m->setHorizontalAnchorPoint( QgsMarkerSymbolLayerV2::HorizontalAnchorPoint( props[ "horizontal_anchor_point" ].toInt() ) );
2586  if ( props.contains( "vertical_anchor_point" ) )
2587  m->setVerticalAnchorPoint( QgsMarkerSymbolLayerV2::VerticalAnchorPoint( props[ "vertical_anchor_point" ].toInt() ) );
2588 
2589  m->restoreDataDefinedProperties( props );
2590 
2591  return m;
2592 }
2593 
2595 {
2596  return "FontMarker";
2597 }
2598 
2600 {
2601  QColor brushColor = mColor;
2602  QColor penColor = mOutlineColor;
2603 
2604  brushColor.setAlphaF( mColor.alphaF() * context.alpha() );
2605  penColor.setAlphaF( mOutlineColor.alphaF() * context.alpha() );
2606 
2607  mBrush = QBrush( brushColor );
2608  mPen = QPen( penColor );
2609  mPen.setJoinStyle( mPenJoinStyle );
2610  mPen.setWidthF( QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), mOutlineWidth, mOutlineWidthUnit, mOutlineWidthMapUnitScale ) );
2611 
2612  mFont = QFont( mFontFamily );
2614  delete mFontMetrics;
2615  mFontMetrics = new QFontMetrics( mFont );
2617  mChrOffset = QPointF( mChrWidth / 2.0, -mFontMetrics->ascent() / 2.0 );
2618  mOrigSize = mSize; // save in case the size would be data defined
2619  prepareExpressions( context );
2620 }
2621 
2623 {
2624  Q_UNUSED( context );
2625 }
2626 
2627 QString QgsFontMarkerSymbolLayerV2::characterToRender( QgsSymbolV2RenderContext& context, QPointF& charOffset, double& charWidth )
2628 {
2629  charOffset = mChrOffset;
2630  QString charToRender = mChr;
2632  {
2633  context.setOriginalValueVariable( mChr );
2635  if ( charToRender != mChr )
2636  {
2637  charWidth = mFontMetrics->width( charToRender );
2638  charOffset = QPointF( charWidth / 2.0, -mFontMetrics->ascent() / 2.0 );
2639  }
2640  }
2641  return charToRender;
2642 }
2643 
2644 void QgsFontMarkerSymbolLayerV2::calculateOffsetAndRotation( QgsSymbolV2RenderContext& context,
2645  double scaledSize,
2646  bool& hasDataDefinedRotation,
2647  QPointF& offset,
2648  double& angle ) const
2649 {
2650  //offset
2651  double offsetX = 0;
2652  double offsetY = 0;
2653  markerOffset( context, scaledSize, scaledSize, offsetX, offsetY );
2654  offset = QPointF( offsetX, offsetY );
2655 
2656  //angle
2657  bool ok = true;
2658  angle = mAngle + mLineAngle;
2659  bool usingDataDefinedRotation = false;
2661  {
2662  context.setOriginalValueVariable( angle );
2664  usingDataDefinedRotation = ok;
2665  }
2666 
2667  hasDataDefinedRotation = context.renderHints() & QgsSymbolV2::DataDefinedRotation || usingDataDefinedRotation;
2668  if ( hasDataDefinedRotation )
2669  {
2670  // For non-point markers, "dataDefinedRotation" means following the
2671  // shape (shape-data defined). For them, "field-data defined" does
2672  // not work at all. TODO: if "field-data defined" ever gets implemented
2673  // we'll need a way to distinguish here between the two, possibly
2674  // using another flag in renderHints()
2675  const QgsFeature* f = context.feature();
2676  if ( f )
2677  {
2678  const QgsGeometry *g = f->constGeometry();
2679  if ( g && g->type() == QGis::Point )
2680  {
2681  const QgsMapToPixel& m2p = context.renderContext().mapToPixel();
2682  angle += m2p.mapRotation();
2683  }
2684  }
2685  }
2686 
2687  if ( angle )
2688  offset = _rotatedOffset( offset, angle );
2689 }
2690 
2691 double QgsFontMarkerSymbolLayerV2::calculateSize( QgsSymbolV2RenderContext& context )
2692 {
2693  double scaledSize = mSize;
2695 
2696  bool ok = true;
2698  {
2699  context.setOriginalValueVariable( mSize );
2700  scaledSize = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_SIZE, context, mSize, &ok ).toDouble();
2701  }
2702 
2703  if ( hasDataDefinedSize && ok )
2704  {
2705  switch ( mScaleMethod )
2706  {
2708  scaledSize = sqrt( scaledSize );
2709  break;
2711  break;
2712  }
2713  }
2714  return scaledSize;
2715 }
2716 
2718 {
2719  QPainter *p = context.renderContext().painter();
2720  if ( !p )
2721  return;
2722 
2723  QTransform transform;
2724 
2725  bool ok;
2726  QColor brushColor = mColor;
2728  {
2731  if ( ok )
2732  brushColor = QgsSymbolLayerV2Utils::decodeColor( colorString );
2733  }
2734  brushColor = context.selected() ? context.renderContext().selectionColor() : brushColor;
2735  brushColor.setAlphaF( brushColor.alphaF() * context.alpha() );
2736  mBrush.setColor( brushColor );
2737 
2738  QColor penColor = mOutlineColor;
2740  {
2743  if ( ok )
2744  penColor = QgsSymbolLayerV2Utils::decodeColor( colorString );
2745  }
2746  penColor.setAlphaF( penColor.alphaF() * context.alpha() );
2747 
2748  double penWidth = QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), mOutlineWidth, mOutlineWidthUnit, mOutlineWidthMapUnitScale );
2750  {
2751  context.setOriginalValueVariable( mOutlineWidth );
2753  if ( ok )
2754  {
2755  penWidth = QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), outlineWidth, mOutlineWidthUnit, mOutlineWidthMapUnitScale );
2756  }
2757  }
2758 
2760  {
2763  if ( ok )
2764  {
2766  }
2767  }
2768 
2769  p->setBrush( mBrush );
2770  if ( !qgsDoubleNear( penWidth, 0.0 ) )
2771  {
2772  mPen.setColor( penColor );
2773  mPen.setWidthF( penWidth );
2774  p->setPen( mPen );
2775  }
2776  else
2777  {
2778  p->setPen( Qt::NoPen );
2779  }
2780  p->save();
2781 
2782  QPointF chrOffset = mChrOffset;
2783  double chrWidth;
2784  QString charToRender = characterToRender( context, chrOffset, chrWidth );
2785 
2786  double sizeToRender = calculateSize( context );
2787 
2788  bool hasDataDefinedRotation = false;
2789  QPointF offset;
2790  double angle = 0;
2791  calculateOffsetAndRotation( context, sizeToRender, hasDataDefinedRotation, offset, angle );
2792 
2793  transform.translate( point.x() + offset.x(), point.y() + offset.y() );
2794 
2795  if ( !qgsDoubleNear( angle, 0.0 ) )
2796  transform.rotate( angle );
2797 
2798  if ( !qgsDoubleNear( sizeToRender, mOrigSize ) )
2799  {
2800  double s = sizeToRender / mOrigSize;
2801  transform.scale( s, s );
2802  }
2803 
2804  QPainterPath path;
2805  path.addText( -chrOffset.x(), -chrOffset.y(), mFont, charToRender );
2806  p->drawPath( transform.map( path ) );
2807  p->restore();
2808 }
2809 
2811 {
2812  QgsStringMap props;
2813  props["font"] = mFontFamily;
2814  props["chr"] = mChr;
2815  props["size"] = QString::number( mSize );
2816  props["size_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mSizeUnit );
2817  props["size_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mSizeMapUnitScale );
2818  props["color"] = QgsSymbolLayerV2Utils::encodeColor( mColor );
2819  props["outline_color"] = QgsSymbolLayerV2Utils::encodeColor( mOutlineColor );
2820  props["outline_width"] = QString::number( mOutlineWidth );
2821  props["outline_width_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOutlineWidthUnit );
2822  props["outline_width_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOutlineWidthMapUnitScale );
2823  props["joinstyle"] = QgsSymbolLayerV2Utils::encodePenJoinStyle( mPenJoinStyle );
2824  props["angle"] = QString::number( mAngle );
2825  props["offset"] = QgsSymbolLayerV2Utils::encodePoint( mOffset );
2826  props["offset_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOffsetUnit );
2827  props["offset_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOffsetMapUnitScale );
2828  props["horizontal_anchor_point"] = QString::number( mHorizontalAnchorPoint );
2829  props["vertical_anchor_point"] = QString::number( mVerticalAnchorPoint );
2830 
2831  //data define properties
2832  saveDataDefinedProperties( props );
2833 
2834  return props;
2835 }
2836 
2838 {
2840  m->setOutlineColor( mOutlineColor );
2841  m->setOutlineWidth( mOutlineWidth );
2842  m->setOutlineWidthUnit( mOutlineWidthUnit );
2843  m->setOutlineWidthMapUnitScale( mOutlineWidthMapUnitScale );
2844  m->setPenJoinStyle( mPenJoinStyle );
2845  m->setOffset( mOffset );
2846  m->setOffsetUnit( mOffsetUnit );
2848  m->setSizeUnit( mSizeUnit );
2853  copyPaintEffect( m );
2854  return m;
2855 }
2856 
2858 {
2859  // <Graphic>
2860  QDomElement graphicElem = doc.createElement( "se:Graphic" );
2861  element.appendChild( graphicElem );
2862 
2863  QString fontPath = QString( "ttf://%1" ).arg( mFontFamily );
2864  int markIndex = mChr.unicode();
2866  QgsSymbolLayerV2Utils::externalMarkerToSld( doc, graphicElem, fontPath, "ttf", &markIndex, mColor, size );
2867 
2868  // <Rotation>
2869  QString angleFunc;
2870  bool ok;
2871  double angle = props.value( "angle", "0" ).toDouble( &ok );
2872  if ( !ok )
2873  {
2874  angleFunc = QString( "%1 + %2" ).arg( props.value( "angle", "0" ) ).arg( mAngle );
2875  }
2876  else if ( !qgsDoubleNear( angle + mAngle, 0.0 ) )
2877  {
2878  angleFunc = QString::number( angle + mAngle );
2879  }
2880  QgsSymbolLayerV2Utils::createRotationElement( doc, graphicElem, angleFunc );
2881 
2882  // <Displacement>
2884  QgsSymbolLayerV2Utils::createDisplacementElement( doc, graphicElem, offset );
2885 }
2886 
2888 {
2889  QPointF chrOffset = mChrOffset;
2890  double chrWidth = mChrWidth;
2891  //calculate width of rendered character
2892  ( void )characterToRender( context, chrOffset, chrWidth );
2893 
2894  if ( !mFontMetrics )
2895  mFontMetrics = new QFontMetrics( mFont );
2896 
2897  double scaledSize = calculateSize( context );
2898  if ( !qgsDoubleNear( scaledSize, mOrigSize ) )
2899  {
2900  chrWidth *= scaledSize / mOrigSize;
2901  }
2902 
2903  bool hasDataDefinedRotation = false;
2904  QPointF offset;
2905  double angle = 0;
2906  calculateOffsetAndRotation( context, scaledSize, hasDataDefinedRotation, offset, angle );
2908 
2909  QMatrix transform;
2910 
2911  // move to the desired position
2912  transform.translate( point.x() + offset.x(), point.y() + offset.y() );
2913 
2914  if ( !qgsDoubleNear( angle, 0.0 ) )
2915  transform.rotate( angle );
2916 
2917  QRectF symbolBounds = transform.mapRect( QRectF( -chrWidth / 2.0,
2918  -scaledSize / 2.0,
2919  chrWidth,
2920  scaledSize ) );
2921  return symbolBounds;
2922 }
2923 
2925 {
2926  QgsDebugMsg( "Entered." );
2927 
2928  QDomElement graphicElem = element.firstChildElement( "Graphic" );
2929  if ( graphicElem.isNull() )
2930  return nullptr;
2931 
2932  QString name, format;
2933  QColor color;
2934  double size;
2935  int chr;
2936 
2937  if ( !QgsSymbolLayerV2Utils::externalMarkerFromSld( graphicElem, name, format, chr, color, size ) )
2938  return nullptr;
2939 
2940  if ( !name.startsWith( "ttf://" ) || format != "ttf" )
2941  return nullptr;
2942 
2943  QString fontFamily = name.mid( 6 );
2944 
2945  double angle = 0.0;
2946  QString angleFunc;
2947  if ( QgsSymbolLayerV2Utils::rotationFromSldElement( graphicElem, angleFunc ) )
2948  {
2949  bool ok;
2950  double d = angleFunc.toDouble( &ok );
2951  if ( ok )
2952  angle = d;
2953  }
2954 
2955  QPointF offset;
2957 
2958  QString uom = element.attribute( QString( "uom" ), "" );
2959  offset.setX( QgsSymbolLayerV2Utils::sizeInPixelsFromSldUom( uom, offset.x() ) );
2960  offset.setY( QgsSymbolLayerV2Utils::sizeInPixelsFromSldUom( uom, offset.y() ) );
2962 
2963  QgsMarkerSymbolLayerV2 *m = new QgsFontMarkerSymbolLayerV2( fontFamily, chr, size, color );
2965  m->setAngle( angle );
2966  m->setOffset( offset );
2967  return m;
2968 }
2969 
void addEllipse(const QRectF &boundingRectangle)
QgsSymbolV2::OutputUnit outputUnit() const override
static QString encodeOutputUnit(QgsSymbolV2::OutputUnit unit)
static double mapUnitScaleFactor(double scaleDenominator, QgsSymbolV2::OutputUnit symbolUnits, QGis::UnitType mapUnits, double mapUnitsPerPixel=1.0)
Returns scale factor for conversion to map units.
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:394
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)
void clipValueToMapUnitScale(double &value, const QgsMapUnitScale &scale, double pixelToMMFactor) const
Clips value to scale minimum/maximum.
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
QString attribute(const QString &name, const QString &defValue) 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.
static double sizeInPixelsFromSldUom(const QString &uom, double size)
Returns the size scaled in pixels according to the uom attribute.
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)
The output shall be in pixels.
Definition: qgssymbolv2.h:70
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:388
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.
QGis::UnitType mapUnits() const
Retrieve map units.
Definition: qgsdxfexport.h:122
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)
double symbologyScaleDenominator() const
Retrieve reference scale for output.
Definition: qgsdxfexport.h:109
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:376
#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
The output shall be in map unitx.
Definition: qgssymbolv2.h:68
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.
double mapUnitsPerPixel() const
Return current map units per pixel.
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:359
void setX(qreal x)
void setY(qreal y)
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.