QGIS API Documentation
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 
50 
51 QgsSimpleMarkerSymbolLayerV2::QgsSimpleMarkerSymbolLayerV2( const QString& name, const QColor& color, const QColor& borderColor, double size, double angle, QgsSymbolV2::ScaleMethod scaleMethod,
52  Qt::PenJoinStyle penJoinStyle )
53  : mOutlineStyle( Qt::SolidLine )
54  , mOutlineWidth( 0 )
55  , mOutlineWidthUnit( QgsSymbolV2::MM )
56  , mPenJoinStyle( penJoinStyle )
57 {
58  mName = name;
59  mColor = color;
61  mSize = size;
62  mAngle = angle;
63  mOffset = QPointF( 0, 0 );
67  mUsingCache = false;
68 }
69 
71 {
79 
80  if ( props.contains( "name" ) )
81  name = props["name"];
82  if ( props.contains( "color" ) )
83  color = QgsSymbolLayerV2Utils::decodeColor( props["color"] );
84  if ( props.contains( "color_border" ) )
85  {
86  //pre 2.5 projects use "color_border"
87  borderColor = QgsSymbolLayerV2Utils::decodeColor( props["color_border"] );
88  }
89  else if ( props.contains( "outline_color" ) )
90  {
91  borderColor = QgsSymbolLayerV2Utils::decodeColor( props["outline_color"] );
92  }
93  else if ( props.contains( "line_color" ) )
94  {
95  borderColor = QgsSymbolLayerV2Utils::decodeColor( props["line_color"] );
96  }
97  if ( props.contains( "joinstyle" ) )
98  {
99  penJoinStyle = QgsSymbolLayerV2Utils::decodePenJoinStyle( props["joinstyle"] );
100  }
101  if ( props.contains( "size" ) )
102  size = props["size"].toDouble();
103  if ( props.contains( "angle" ) )
104  angle = props["angle"].toDouble();
105  if ( props.contains( "scale_method" ) )
106  scaleMethod = QgsSymbolLayerV2Utils::decodeScaleMethod( props["scale_method"] );
107 
108  QgsSimpleMarkerSymbolLayerV2* m = new QgsSimpleMarkerSymbolLayerV2( name, color, borderColor, size, angle, scaleMethod, penJoinStyle );
109  if ( props.contains( "offset" ) )
110  m->setOffset( QgsSymbolLayerV2Utils::decodePoint( props["offset"] ) );
111  if ( props.contains( "offset_unit" ) )
112  m->setOffsetUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["offset_unit"] ) );
113  if ( props.contains( "offset_map_unit_scale" ) )
114  m->setOffsetMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["offset_map_unit_scale"] ) );
115  if ( props.contains( "size_unit" ) )
116  m->setSizeUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["size_unit"] ) );
117  if ( props.contains( "size_map_unit_scale" ) )
118  m->setSizeMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["size_map_unit_scale"] ) );
119 
120  if ( props.contains( "outline_style" ) )
121  {
122  m->setOutlineStyle( QgsSymbolLayerV2Utils::decodePenStyle( props["outline_style"] ) );
123  }
124  else if ( props.contains( "line_style" ) )
125  {
126  m->setOutlineStyle( QgsSymbolLayerV2Utils::decodePenStyle( props["line_style"] ) );
127  }
128  if ( props.contains( "outline_width" ) )
129  {
130  m->setOutlineWidth( props["outline_width"].toDouble() );
131  }
132  else if ( props.contains( "line_width" ) )
133  {
134  m->setOutlineWidth( props["line_width"].toDouble() );
135  }
136  if ( props.contains( "outline_width_unit" ) )
137  {
138  m->setOutlineWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["outline_width_unit"] ) );
139  }
140  if ( props.contains( "line_width_unit" ) )
141  {
142  m->setOutlineWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["line_width_unit"] ) );
143  }
144  if ( props.contains( "outline_width_map_unit_scale" ) )
145  {
146  m->setOutlineWidthMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["outline_width_map_unit_scale"] ) );
147  }
148 
149  if ( props.contains( "horizontal_anchor_point" ) )
150  {
151  m->setHorizontalAnchorPoint( QgsMarkerSymbolLayerV2::HorizontalAnchorPoint( props[ "horizontal_anchor_point" ].toInt() ) );
152  }
153  if ( props.contains( "vertical_anchor_point" ) )
154  {
155  m->setVerticalAnchorPoint( QgsMarkerSymbolLayerV2::VerticalAnchorPoint( props[ "vertical_anchor_point" ].toInt() ) );
156  }
157 
158  m->restoreDataDefinedProperties( props );
159 
160  return m;
161 }
162 
163 
165 {
166  return "SimpleMarker";
167 }
168 
170 {
171  QColor brushColor = mColor;
172  QColor penColor = mBorderColor;
173 
174  brushColor.setAlphaF( mColor.alphaF() * context.alpha() );
175  penColor.setAlphaF( mBorderColor.alphaF() * context.alpha() );
176 
177  mBrush = QBrush( brushColor );
178  mPen = QPen( penColor );
182 
183  QColor selBrushColor = context.renderContext().selectionColor();
184  QColor selPenColor = selBrushColor == mColor ? selBrushColor : mBorderColor;
185  if ( context.alpha() < 1 )
186  {
187  selBrushColor.setAlphaF( context.alpha() );
188  selPenColor.setAlphaF( context.alpha() );
189  }
190  mSelBrush = QBrush( selBrushColor );
191  mSelPen = QPen( selPenColor );
194 
197 
198  // use caching only when:
199  // - size, rotation, shape, color, border color is not data-defined
200  // - drawing to screen (not printer)
201  mUsingCache = !hasDataDefinedRotation && !hasDataDefinedSize && !context.renderContext().forceVectorOutput()
205 
206  // use either QPolygonF or QPainterPath for drawing
207  // TODO: find out whether drawing directly doesn't bring overhead - if not, use it for all shapes
208  if ( !prepareShape() ) // drawing as a polygon
209  {
210  if ( preparePath() ) // drawing as a painter path
211  {
212  // some markers can't be drawn as a polygon (circle, cross)
213  // For these set the selected border color to the selected color
214 
215  if ( mName != "circle" )
216  mSelPen.setColor( selBrushColor );
217  }
218  else
219  {
220  QgsDebugMsg( "unknown symbol" );
221  return;
222  }
223  }
224 
225  QMatrix transform;
226 
227  // scale the shape (if the size is not going to be modified)
228  if ( !hasDataDefinedSize )
229  {
231  if ( mUsingCache )
232  scaledSize *= context.renderContext().rasterScaleFactor();
233  double half = scaledSize / 2.0;
234  transform.scale( half, half );
235  }
236 
237  // rotate if the rotation is not going to be changed during the rendering
238  if ( !hasDataDefinedRotation && !qgsDoubleNear( mAngle, 0.0 ) )
239  {
240  transform.rotate( mAngle );
241  }
242 
243  if ( !mPolygon.isEmpty() )
244  mPolygon = transform.map( mPolygon );
245  else
246  mPath = transform.map( mPath );
247 
248  if ( mUsingCache )
249  {
250  if ( !prepareCache( context ) )
251  {
252  mUsingCache = false;
253  }
254  }
255  else
256  {
257  mCache = QImage();
258  mSelCache = QImage();
259  }
260 
261  prepareExpressions( context );
262 
264 }
265 
266 
268 {
270 
271  // calculate necessary image size for the cache
272  double pw = qRound((( qgsDoubleNear( mPen.widthF(), 0.0 ) ? 1 : mPen.widthF() * 4 ) + 1 ) ) / 2 * 2; // make even (round up); handle cosmetic pen
273  int imageSize = ( static_cast< int >( scaledSize ) + pw ) / 2 * 2 + 1; // make image width, height odd; account for pen width
274  double center = imageSize / 2.0;
275 
276  if ( imageSize > mMaximumCacheWidth )
277  {
278  return false;
279  }
280 
281  mCache = QImage( QSize( imageSize, imageSize ), QImage::Format_ARGB32_Premultiplied );
282  mCache.fill( 0 );
283 
284  bool needsBrush = symbolNeedsBrush( mName );
285 
286  QPainter p;
287  p.begin( &mCache );
288  p.setRenderHint( QPainter::Antialiasing );
289  p.setBrush( needsBrush ? mBrush : Qt::NoBrush );
290  p.setPen( mPen );
291  p.translate( QPointF( center, center ) );
292  drawMarker( &p, context );
293  p.end();
294 
295  // Construct the selected version of the Cache
296 
297  QColor selColor = context.renderContext().selectionColor();
298 
299  mSelCache = QImage( QSize( imageSize, imageSize ), QImage::Format_ARGB32_Premultiplied );
300  mSelCache.fill( 0 );
301 
302  p.begin( &mSelCache );
303  p.setRenderHint( QPainter::Antialiasing );
304  p.setBrush( needsBrush ? mSelBrush : Qt::NoBrush );
305  p.setPen( mSelPen );
306  p.translate( QPointF( center, center ) );
307  drawMarker( &p, context );
308  p.end();
309 
310  // Check that the selected version is different. If not, then re-render,
311  // filling the background with the selection color and using the normal
312  // colors for the symbol .. could be ugly!
313 
314  if ( mSelCache == mCache )
315  {
316  p.begin( &mSelCache );
317  p.setRenderHint( QPainter::Antialiasing );
318  p.fillRect( 0, 0, imageSize, imageSize, selColor );
319  p.setBrush( needsBrush ? mBrush : Qt::NoBrush );
320  p.setPen( mPen );
321  p.translate( QPointF( center, center ) );
322  drawMarker( &p, context );
323  p.end();
324  }
325 
326  return true;
327 }
328 
330 {
331  Q_UNUSED( context );
332 }
333 
335 {
336  return prepareShape( name.isNull() ? mName : name, mPolygon );
337 }
338 
340 {
341  polygon.clear();
342 
343  if ( name == "square" || name == "rectangle" )
344  {
345  polygon = QPolygonF( QRectF( QPointF( -1, -1 ), QPointF( 1, 1 ) ) );
346  return true;
347  }
348  else if ( name == "quarter_square" )
349  {
350  polygon = QPolygonF( QRectF( QPointF( -1, -1 ), QPointF( 0, 0 ) ) );
351  return true;
352  }
353  else if ( name == "half_square" )
354  {
355  polygon = QPolygonF( QRectF( QPointF( -1, -1 ), QPointF( 0, 1 ) ) );
356  return true;
357  }
358  else if ( name == "diagonal_half_square" )
359  {
360  polygon << QPointF( -1, -1 ) << QPointF( 1, 1 ) << QPointF( -1, 1 );
361  return true;
362  }
363  else if ( name == "diamond" )
364  {
365  polygon << QPointF( -1, 0 ) << QPointF( 0, 1 )
366  << QPointF( 1, 0 ) << QPointF( 0, -1 );
367  return true;
368  }
369  else if ( name == "pentagon" )
370  {
371  /* angular-representation of hardcoded values used
372  polygon << QPointF( sin( DEG2RAD( 288.0 ) ), - cos( DEG2RAD( 288.0 ) ) )
373  << QPointF( sin( DEG2RAD( 216.0 ) ), - cos( DEG2RAD( 216.0 ) ) )
374  << QPointF( sin( DEG2RAD( 144.0 ) ), - cos( DEG2RAD( 144.0 ) ) )
375  << QPointF( sin( DEG2RAD( 72.0 ) ), - cos( DEG2RAD( 72.0 ) ) )
376  << QPointF( 0, -1 ); */
377  polygon << QPointF( -0.9511, -0.3090 )
378  << QPointF( -0.5878, 0.8090 )
379  << QPointF( 0.5878, 0.8090 )
380  << QPointF( 0.9511, -0.3090 )
381  << QPointF( 0, -1 );
382  return true;
383  }
384  else if ( name == "hexagon" )
385  {
386  /* angular-representation of hardcoded values used
387  polygon << QPointF( sin( DEG2RAD( 300.0 ) ), - cos( DEG2RAD( 300.0 ) ) )
388  << QPointF( sin( DEG2RAD( 240.0 ) ), - cos( DEG2RAD( 240.0 ) ) )
389  << QPointF( sin( DEG2RAD( 180.0 ) ), - cos( DEG2RAD( 180.0 ) ) )
390  << QPointF( sin( DEG2RAD( 120.0 ) ), - cos( DEG2RAD( 120.0 ) ) )
391  << QPointF( sin( DEG2RAD( 60.0 ) ), - cos( DEG2RAD( 60.0 ) ) )
392  << QPointF( 0, -1 ); */
393  polygon << QPointF( -0.8660, -0.5 )
394  << QPointF( -0.8660, 0.5 )
395  << QPointF( 0, 1 )
396  << QPointF( 0.8660, 0.5 )
397  << QPointF( 0.8660, -0.5 )
398  << QPointF( 0, -1 );
399  return true;
400  }
401  else if ( name == "triangle" )
402  {
403  polygon << QPointF( -1, 1 ) << QPointF( 1, 1 ) << QPointF( 0, -1 );
404  return true;
405  }
406  else if ( name == "equilateral_triangle" )
407  {
408  /* angular-representation of hardcoded values used
409  polygon << QPointF( sin( DEG2RAD( 240.0 ) ), - cos( DEG2RAD( 240.0 ) ) )
410  << QPointF( sin( DEG2RAD( 120.0 ) ), - cos( DEG2RAD( 120.0 ) ) )
411  << QPointF( 0, -1 ); */
412  polygon << QPointF( -0.8660, 0.5 )
413  << QPointF( 0.8660, 0.5 )
414  << QPointF( 0, -1 );
415  return true;
416  }
417  else if ( name == "left_half_triangle" )
418  {
419  polygon << QPointF( 0, 1 ) << QPointF( 1, 1 ) << QPointF( 0, -1 );
420  return true;
421  }
422  else if ( name == "right_half_triangle" )
423  {
424  polygon << QPointF( -1, 1 ) << QPointF( 0, 1 ) << QPointF( 0, -1 );
425  return true;
426  }
427  else if ( name == "star" || name == "regular_star" )
428  {
429  double inner_r = cos( DEG2RAD( 72.0 ) ) / cos( DEG2RAD( 36.0 ) );
430 
431  polygon << QPointF( inner_r * sin( DEG2RAD( 324.0 ) ), - inner_r * cos( DEG2RAD( 324.0 ) ) ) // 324
432  << QPointF( sin( DEG2RAD( 288.0 ) ), - cos( DEG2RAD( 288 ) ) ) // 288
433  << QPointF( inner_r * sin( DEG2RAD( 252.0 ) ), - inner_r * cos( DEG2RAD( 252.0 ) ) ) // 252
434  << QPointF( sin( DEG2RAD( 216.0 ) ), - cos( DEG2RAD( 216.0 ) ) ) // 216
435  << QPointF( 0, inner_r ) // 180
436  << QPointF( sin( DEG2RAD( 144.0 ) ), - cos( DEG2RAD( 144.0 ) ) ) // 144
437  << QPointF( inner_r * sin( DEG2RAD( 108.0 ) ), - inner_r * cos( DEG2RAD( 108.0 ) ) ) // 108
438  << QPointF( sin( DEG2RAD( 72.0 ) ), - cos( DEG2RAD( 72.0 ) ) ) // 72
439  << QPointF( inner_r * sin( DEG2RAD( 36.0 ) ), - inner_r * cos( DEG2RAD( 36.0 ) ) ) // 36
440  << QPointF( 0, -1 ); // 0
441  return true;
442  }
443  else if ( name == "arrow" )
444  {
445  polygon << QPointF( 0, -1 )
446  << QPointF( 0.5, -0.5 )
447  << QPointF( 0.25, -0.5 )
448  << QPointF( 0.25, 1 )
449  << QPointF( -0.25, 1 )
450  << QPointF( -0.25, -0.5 )
451  << QPointF( -0.5, -0.5 );
452  return true;
453  }
454  else if ( name == "filled_arrowhead" )
455  {
456  polygon << QPointF( 0, 0 ) << QPointF( -1, 1 ) << QPointF( -1, -1 );
457  return true;
458  }
459 
460  return false;
461 }
462 
464 {
465  mPath = QPainterPath();
466  if ( name.isNull() )
467  {
468  name = mName;
469  }
470 
471  if ( name == "circle" )
472  {
473  mPath.addEllipse( QRectF( -1, -1, 2, 2 ) ); // x,y,w,h
474  return true;
475  }
476  else if ( name == "semi_circle" )
477  {
478  mPath.arcTo( -1, -1, 2, 2, 0, 180 );
479  mPath.lineTo( 0, 0 );
480  return true;
481  }
482  else if ( name == "third_circle" )
483  {
484  mPath.arcTo( -1, -1, 2, 2, 90, 120 );
485  mPath.lineTo( 0, 0 );
486  return true;
487  }
488  else if ( name == "quarter_circle" )
489  {
490  mPath.arcTo( -1, -1, 2, 2, 90, 90 );
491  mPath.lineTo( 0, 0 );
492  return true;
493  }
494  else if ( name == "cross" )
495  {
496  mPath.moveTo( -1, 0 );
497  mPath.lineTo( 1, 0 ); // horizontal
498  mPath.moveTo( 0, -1 );
499  mPath.lineTo( 0, 1 ); // vertical
500  return true;
501  }
502  else if ( name == "cross_fill" )
503  {
504  mPath.moveTo( -1, -0.2 );
505  mPath.lineTo( -1, 0.2 );
506  mPath.lineTo( -0.2, 0.2 );
507  mPath.lineTo( -0.2, 1 );
508  mPath.lineTo( 0.2, 1 );
509  mPath.lineTo( 0.2, 0.2 );
510  mPath.lineTo( 1, 0.2 );
511  mPath.lineTo( 1, -0.2 );
512  mPath.lineTo( 0.2, -0.2 );
513  mPath.lineTo( 0.2, -1 );
514  mPath.lineTo( -0.2, -1 );
515  mPath.lineTo( -0.2, -0.2 );
516  mPath.lineTo( -1, -0.2 );
517  return true;
518  }
519  else if ( name == "x" || name == "cross2" )
520  {
521  mPath.moveTo( -1, -1 );
522  mPath.lineTo( 1, 1 );
523  mPath.moveTo( 1, -1 );
524  mPath.lineTo( -1, 1 );
525  return true;
526  }
527  else if ( name == "line" )
528  {
529  mPath.moveTo( 0, -1 );
530  mPath.lineTo( 0, 1 ); // vertical line
531  return true;
532  }
533  else if ( name == "arrowhead" )
534  {
535  mPath.moveTo( -1, -1 );
536  mPath.lineTo( 0, 0 );
537  mPath.lineTo( -1, 1 );
538  return true;
539  }
540 
541  return false;
542 }
543 
545 {
546  //making changes here? Don't forget to also update ::bounds if the changes affect the bounding box
547  //of the rendered point!
548 
549  QPainter *p = context.renderContext().painter();
550  if ( !p )
551  {
552  return;
553  }
554 
555  bool hasDataDefinedSize = false;
556  double scaledSize = calculateSize( context, hasDataDefinedSize );
557 
558  bool hasDataDefinedRotation = false;
559  QPointF offset;
560  double angle = 0;
561  calculateOffsetAndRotation( context, scaledSize, hasDataDefinedRotation, offset, angle );
562 
563  //data defined shape?
564  bool createdNewPath = false;
565  bool ok = true;
566  QString name = mName;
568  {
569  context.setOriginalValueVariable( mName );
571  if ( ok )
572  {
573  if ( !prepareShape( name ) ) // drawing as a polygon
574  {
575  preparePath( name ); // drawing as a painter path
576  }
577  createdNewPath = true;
578  }
579  else
580  {
581  name = mName;
582  }
583  }
584 
585  if ( mUsingCache )
586  {
587  //QgsDebugMsg( QString("XXX using cache") );
588  // we will use cached image
589  QImage &img = context.selected() ? mSelCache : mCache;
590  double s = img.width() / context.renderContext().rasterScaleFactor();
591  p->drawImage( QRectF( point.x() - s / 2.0 + offset.x(),
592  point.y() - s / 2.0 + offset.y(),
593  s, s ), img );
594  }
595  else
596  {
597  QMatrix transform;
598 
599  // move to the desired position
600  transform.translate( point.x() + offset.x(), point.y() + offset.y() );
601 
602  // resize if necessary
603  if ( hasDataDefinedSize || createdNewPath )
604  {
606  double half = s / 2.0;
607  transform.scale( half, half );
608  }
609 
610  if ( !qgsDoubleNear( angle, 0.0 ) && ( hasDataDefinedRotation || createdNewPath ) )
611  transform.rotate( angle );
612 
614  {
617  if ( ok )
619  }
621  {
624  if ( ok )
625  {
628  }
629  }
631  {
634  if ( ok )
635  {
638  }
639  }
641  {
644  if ( ok )
645  {
648  }
649  }
651  {
654  if ( ok )
655  {
658  }
659  }
660 
661  if ( symbolNeedsBrush( name ) )
662  {
663  p->setBrush( context.selected() ? mSelBrush : mBrush );
664  }
665  else
666  {
667  p->setBrush( Qt::NoBrush );
668  }
669  p->setPen( context.selected() ? mSelPen : mPen );
670 
671  if ( !mPolygon.isEmpty() )
672  p->drawPolygon( transform.map( mPolygon ) );
673  else
674  p->drawPath( transform.map( mPath ) );
675  }
676 }
677 
678 
679 double QgsSimpleMarkerSymbolLayerV2::calculateSize( QgsSymbolV2RenderContext& context, bool& hasDataDefinedSize ) const
680 {
681  double scaledSize = mSize;
682 
684  bool ok = true;
686  {
687  context.setOriginalValueVariable( mSize );
689  }
690 
691  if ( hasDataDefinedSize && ok )
692  {
693  switch ( mScaleMethod )
694  {
696  scaledSize = sqrt( scaledSize );
697  break;
699  break;
700  }
701  }
702 
703  return scaledSize;
704 }
705 
706 void QgsSimpleMarkerSymbolLayerV2::calculateOffsetAndRotation( QgsSymbolV2RenderContext& context,
707  double scaledSize,
708  bool& hasDataDefinedRotation,
709  QPointF& offset,
710  double& angle ) const
711 {
712  //offset
713  double offsetX = 0;
714  double offsetY = 0;
715  markerOffset( context, scaledSize, scaledSize, offsetX, offsetY );
716  offset = QPointF( offsetX, offsetY );
717 
718  //angle
719  bool ok = true;
720  angle = mAngle + mLineAngle;
721  bool usingDataDefinedRotation = false;
723  {
724  context.setOriginalValueVariable( angle );
726  usingDataDefinedRotation = ok;
727  }
728 
729  hasDataDefinedRotation = context.renderHints() & QgsSymbolV2::DataDefinedRotation || usingDataDefinedRotation;
730  if ( hasDataDefinedRotation )
731  {
732  // For non-point markers, "dataDefinedRotation" means following the
733  // shape (shape-data defined). For them, "field-data defined" does
734  // not work at all. TODO: if "field-data defined" ever gets implemented
735  // we'll need a way to distinguish here between the two, possibly
736  // using another flag in renderHints()
737  const QgsFeature* f = context.feature();
738  if ( f )
739  {
740  const QgsGeometry *g = f->constGeometry();
741  if ( g && g->type() == QGis::Point )
742  {
743  const QgsMapToPixel& m2p = context.renderContext().mapToPixel();
744  angle += m2p.mapRotation();
745  }
746  }
747  }
748 
749  if ( angle )
750  offset = _rotatedOffset( offset, angle );
751 }
752 
753 bool QgsSimpleMarkerSymbolLayerV2::symbolNeedsBrush( const QString &symbolName ) const
754 {
755  return symbolName != "arrowhead";
756 }
757 
759 {
760  QgsStringMap map;
761  map["name"] = mName;
762  map["color"] = QgsSymbolLayerV2Utils::encodeColor( mColor );
763  map["outline_color"] = QgsSymbolLayerV2Utils::encodeColor( mBorderColor );
764  map["size"] = QString::number( mSize );
766  map["size_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mSizeMapUnitScale );
767  map["angle"] = QString::number( mAngle );
768  map["offset"] = QgsSymbolLayerV2Utils::encodePoint( mOffset );
770  map["offset_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOffsetMapUnitScale );
772  map["outline_style"] = QgsSymbolLayerV2Utils::encodePenStyle( mOutlineStyle );
773  map["outline_width"] = QString::number( mOutlineWidth );
774  map["outline_width_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOutlineWidthUnit );
775  map["outline_width_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOutlineWidthMapUnitScale );
777  map["horizontal_anchor_point"] = QString::number( mHorizontalAnchorPoint );
778  map["vertical_anchor_point"] = QString::number( mVerticalAnchorPoint );
779 
780 
781  //data define properties
783  return map;
784 }
785 
787 {
789  m->setOffset( mOffset );
790  m->setSizeUnit( mSizeUnit );
801  copyPaintEffect( m );
802  return m;
803 }
804 
806 {
807  // <Graphic>
808  QDomElement graphicElem = doc.createElement( "se:Graphic" );
809  element.appendChild( graphicElem );
810 
812 
813  // <Rotation>
814  QString angleFunc;
815  bool ok;
816  double angle = props.value( "angle", "0" ).toDouble( &ok );
817  if ( !ok )
818  {
819  angleFunc = QString( "%1 + %2" ).arg( props.value( "angle", "0" ) ).arg( mAngle );
820  }
821  else if ( !qgsDoubleNear( angle + mAngle, 0.0 ) )
822  {
823  angleFunc = QString::number( angle + mAngle );
824  }
825  QgsSymbolLayerV2Utils::createRotationElement( doc, graphicElem, angleFunc );
826 
827  // <Displacement>
829 }
830 
831 QString QgsSimpleMarkerSymbolLayerV2::ogrFeatureStyle( double mmScaleFactor, double mapUnitScaleFactor ) const
832 {
833  Q_UNUSED( mmScaleFactor );
834  Q_UNUSED( mapUnitScaleFactor );
835 #if 0
836  QString ogrType = "3"; //default is circle
837  if ( mName == "square" )
838  {
839  ogrType = "5";
840  }
841  else if ( mName == "triangle" )
842  {
843  ogrType = "7";
844  }
845  else if ( mName == "star" )
846  {
847  ogrType = "9";
848  }
849  else if ( mName == "circle" )
850  {
851  ogrType = "3";
852  }
853  else if ( mName == "cross" )
854  {
855  ogrType = "0";
856  }
857  else if ( mName == "x" || mName == "cross2" )
858  {
859  ogrType = "1";
860  }
861  else if ( mName == "line" )
862  {
863  ogrType = "10";
864  }
865 
866  QString ogrString;
867  ogrString.append( "SYMBOL(" );
868  ogrString.append( "id:" );
869  ogrString.append( '\"' );
870  ogrString.append( "ogr-sym-" );
871  ogrString.append( ogrType );
872  ogrString.append( '\"' );
873  ogrString.append( ",c:" );
874  ogrString.append( mColor.name() );
875  ogrString.append( ",o:" );
876  ogrString.append( mBorderColor.name() );
877  ogrString.append( QString( ",s:%1mm" ).arg( mSize ) );
878  ogrString.append( ')' );
879  return ogrString;
880 #endif //0
881 
882  QString ogrString;
883  ogrString.append( "PEN(" );
884  ogrString.append( "c:" );
885  ogrString.append( mColor.name() );
886  ogrString.append( ",w:" );
887  ogrString.append( QString::number( mSize ) );
888  ogrString.append( "mm" );
889  ogrString.append( ")" );
890  return ogrString;
891 }
892 
894 {
895  QgsDebugMsg( "Entered." );
896 
897  QDomElement graphicElem = element.firstChildElement( "Graphic" );
898  if ( graphicElem.isNull() )
899  return nullptr;
900 
901  QString name = "square";
903  double borderWidth, size;
904  Qt::PenStyle borderStyle;
905 
906  if ( !QgsSymbolLayerV2Utils::wellKnownMarkerFromSld( graphicElem, name, color, borderColor, borderStyle, borderWidth, size ) )
907  return nullptr;
908 
909  double angle = 0.0;
910  QString angleFunc;
911  if ( QgsSymbolLayerV2Utils::rotationFromSldElement( graphicElem, angleFunc ) )
912  {
913  bool ok;
914  double d = angleFunc.toDouble( &ok );
915  if ( ok )
916  angle = d;
917  }
918 
919  QPointF offset;
921 
922  QgsSimpleMarkerSymbolLayerV2 *m = new QgsSimpleMarkerSymbolLayerV2( name, color, borderColor, size );
923  m->setAngle( angle );
924  m->setOffset( offset );
925  m->setOutlineStyle( borderStyle );
926  return m;
927 }
928 
930 {
931  Q_UNUSED( context );
932 
933  if ( mPolygon.count() != 0 )
934  {
935  p->drawPolygon( mPolygon );
936  }
937  else
938  {
939  p->drawPath( mPath );
940  }
941 }
942 
943 bool QgsSimpleMarkerSymbolLayerV2::writeDxf( QgsDxfExport& e, double mmMapUnitScaleFactor, const QString& layerName, QgsSymbolV2RenderContext &context, QPointF shift ) const
944 {
945  //data defined size?
946  double size = mSize;
947 
949 
950  //data defined size
951  bool ok = true;
952  if ( hasDataDefinedSize )
953  {
955  {
956  context.setOriginalValueVariable( mSize );
958  }
959 
960  if ( ok )
961  {
962  switch ( mScaleMethod )
963  {
965  size = sqrt( size );
966  break;
968  break;
969  }
970  }
971 
973  }
974  if ( mSizeUnit == QgsSymbolV2::MM )
975  {
976  size *= mmMapUnitScaleFactor;
977  }
978  double halfSize = size / 2.0;
979 
980  //outlineWidth
981  double outlineWidth = mOutlineWidth;
982 
984  {
987  }
988  if ( mSizeUnit == QgsSymbolV2::MM )
989  {
990  outlineWidth *= mmMapUnitScaleFactor;
991  }
992 
993  //color
994  QColor pc = mPen.color();
995  QColor bc = mBrush.color();
997  {
1000  if ( ok )
1001  bc = QgsSymbolLayerV2Utils::decodeColor( colorString );
1002  }
1004  {
1007  if ( ok )
1008  pc = QgsSymbolLayerV2Utils::decodeColor( colorString );
1009  }
1010 
1011  //offset
1012  double offsetX = 0;
1013  double offsetY = 0;
1014  markerOffset( context, offsetX, offsetY );
1015 
1016  QPointF off( offsetX, offsetY );
1017 
1018  //angle
1019  double angle = mAngle + mLineAngle;
1021  {
1022  context.setOriginalValueVariable( mAngle );
1024  }
1025 
1026  QString name( mName );
1028  {
1029  context.setOriginalValueVariable( mName );
1031  }
1032 
1033  angle = -angle; //rotation in Qt is counterclockwise
1034  if ( angle )
1035  off = _rotatedOffset( off, angle );
1036 
1037  if ( mSizeUnit == QgsSymbolV2::MM )
1038  {
1039  off *= mmMapUnitScaleFactor;
1040  }
1041 
1042  QTransform t;
1043  t.translate( shift.x() + offsetX, shift.y() + offsetY );
1044 
1045  if ( !qgsDoubleNear( angle, 0.0 ) )
1046  t.rotate( angle );
1047 
1048  QPolygonF polygon;
1049  if ( prepareShape( name, polygon ) )
1050  {
1051  t.scale( halfSize, -halfSize );
1052 
1053  polygon = t.map( polygon );
1054 
1056  for ( int i = 0; i < polygon.size(); i++ )
1057  p << QgsPointV2( polygon[i] );
1058  p << p[0];
1059 
1060  if ( mBrush.style() != Qt::NoBrush )
1061  e.writePolygon( QgsRingSequenceV2() << p, layerName, "SOLID", bc );
1062  if ( mPen.style() != Qt::NoPen )
1063  e.writePolyline( p, layerName, "CONTINUOUS", pc, outlineWidth );
1064  }
1065  else if ( name == "circle" )
1066  {
1067  if ( mBrush.style() != Qt::NoBrush )
1068  e.writeFilledCircle( layerName, bc, QgsPointV2( shift ), halfSize );
1069  if ( mPen.style() != Qt::NoPen )
1070  e.writeCircle( layerName, pc, QgsPointV2( shift ), halfSize, "CONTINUOUS", outlineWidth );
1071  }
1072  else if ( name == "line" )
1073  {
1074  QPointF pt1 = t.map( QPointF( 0, -halfSize ) );
1075  QPointF pt2 = t.map( QPointF( 0, halfSize ) );
1076 
1077  if ( mPen.style() != Qt::NoPen )
1078  e.writeLine( QgsPointV2( pt1 ), QgsPointV2( pt2 ), layerName, "CONTINUOUS", pc, outlineWidth );
1079  }
1080  else if ( name == "cross" )
1081  {
1082  if ( mPen.style() != Qt::NoPen )
1083  {
1084  QPointF pt1 = t.map( QPointF( -halfSize, 0 ) );
1085  QPointF pt2 = t.map( QPointF( halfSize, 0 ) );
1086  QPointF pt3 = t.map( QPointF( 0, -halfSize ) );
1087  QPointF pt4 = t.map( QPointF( 0, halfSize ) );
1088 
1089  e.writeLine( QgsPointV2( pt1 ), QgsPointV2( pt2 ), layerName, "CONTINUOUS", pc, outlineWidth );
1090  e.writeLine( QgsPointV2( pt3 ), QgsPointV2( pt4 ), layerName, "CONTINUOUS", pc, outlineWidth );
1091  }
1092  }
1093  else if ( name == "x" || name == "cross2" )
1094  {
1095  if ( mPen.style() != Qt::NoPen )
1096  {
1097  QPointF pt1 = t.map( QPointF( -halfSize, -halfSize ) );
1098  QPointF pt2 = t.map( QPointF( halfSize, halfSize ) );
1099  QPointF pt3 = t.map( QPointF( halfSize, -halfSize ) );
1100  QPointF pt4 = t.map( QPointF( -halfSize, halfSize ) );
1101 
1102  e.writeLine( QgsPointV2( pt1 ), QgsPointV2( pt2 ), layerName, "CONTINUOUS", pc, outlineWidth );
1103  e.writeLine( QgsPointV2( pt3 ), QgsPointV2( pt4 ), layerName, "CONTINUOUS", pc, outlineWidth );
1104  }
1105  }
1106  else if ( name == "arrowhead" )
1107  {
1108  if ( mPen.style() != Qt::NoPen )
1109  {
1110  QPointF pt1 = t.map( QPointF( -halfSize, halfSize ) );
1111  QPointF pt2 = t.map( QPointF( 0, 0 ) );
1112  QPointF pt3 = t.map( QPointF( -halfSize, -halfSize ) );
1113 
1114  e.writeLine( QgsPointV2( pt1 ), QgsPointV2( pt2 ), layerName, "CONTINUOUS", pc, outlineWidth );
1115  e.writeLine( QgsPointV2( pt3 ), QgsPointV2( pt2 ), layerName, "CONTINUOUS", pc, outlineWidth );
1116  }
1117  }
1118  else
1119  {
1120  QgsDebugMsg( QString( "Unsupported dxf marker name %1" ).arg( name ) );
1121  return false;
1122  }
1123 
1124  return true;
1125 }
1126 
1127 
1129 {
1131  mOutlineWidthUnit = unit;
1132 }
1133 
1135 {
1137  {
1138  return mOutlineWidthUnit;
1139  }
1140  return QgsSymbolV2::Mixed;
1141 }
1142 
1144 {
1146  mOutlineWidthMapUnitScale = scale;
1147 }
1148 
1150 {
1152  {
1154  }
1155  return QgsMapUnitScale();
1156 }
1157 
1159 {
1160  bool hasDataDefinedSize = false;
1161  double scaledSize = calculateSize( context, hasDataDefinedSize );
1162 
1163  bool hasDataDefinedRotation = false;
1164  QPointF offset;
1165  double angle = 0;
1166  calculateOffsetAndRotation( context, scaledSize, hasDataDefinedRotation, offset, angle );
1167 
1169  double pixelSize = 1.0 / context.renderContext().rasterScaleFactor();
1170 
1171  QMatrix transform;
1172 
1173  // move to the desired position
1174  transform.translate( point.x() + offset.x(), point.y() + offset.y() );
1175 
1176  if ( !qgsDoubleNear( angle, 0.0 ) )
1177  transform.rotate( angle );
1178 
1179  double penWidth = 0.0;
1180  bool ok = true;
1182  {
1185  if ( ok )
1186  {
1188  }
1189  }
1191  {
1194  if ( ok && outlineStyle == "no" )
1195  {
1196  penWidth = 0.0;
1197  }
1198  }
1199  //antialiasing
1200  penWidth += pixelSize;
1201 
1202  QRectF symbolBounds = transform.mapRect( QRectF( -scaledSize / 2.0,
1203  -scaledSize / 2.0,
1204  scaledSize,
1205  scaledSize ) );
1206 
1207  //extend bounds by pen width / 2.0
1208  symbolBounds.adjust( -penWidth / 2.0, -penWidth / 2.0,
1209  penWidth / 2.0, penWidth / 2.0 );
1210 
1211  return symbolBounds;
1212 }
1213 
1215 
1216 
1218 {
1220  mSize = size;
1221  mAngle = angle;
1222  mOffset = QPointF( 0, 0 );
1224  mOutlineWidth = 0.2;
1226  mColor = QColor( Qt::black );
1227  mOutlineColor = QColor( Qt::black );
1228 }
1229 
1230 
1232 {
1234  double size = DEFAULT_SVGMARKER_SIZE;
1235  double angle = DEFAULT_SVGMARKER_ANGLE;
1237 
1238  if ( props.contains( "name" ) )
1239  name = props["name"];
1240  if ( props.contains( "size" ) )
1241  size = props["size"].toDouble();
1242  if ( props.contains( "angle" ) )
1243  angle = props["angle"].toDouble();
1244  if ( props.contains( "scale_method" ) )
1245  scaleMethod = QgsSymbolLayerV2Utils::decodeScaleMethod( props["scale_method"] );
1246 
1247  QgsSvgMarkerSymbolLayerV2* m = new QgsSvgMarkerSymbolLayerV2( name, size, angle, scaleMethod );
1248 
1249  //we only check the svg default parameters if necessary, since it could be expensive
1250  if ( !props.contains( "fill" ) && !props.contains( "color" ) && !props.contains( "outline" ) &&
1251  !props.contains( "outline_color" ) && !props.contains( "outline-width" ) && !props.contains( "outline_width" ) )
1252  {
1254  double fillOpacity = 1.0;
1255  double outlineOpacity = 1.0;
1256  double outlineWidth;
1257  bool hasFillParam = false, hasFillOpacityParam = false, hasOutlineParam = false, hasOutlineWidthParam = false, hasOutlineOpacityParam = false;
1258  bool hasDefaultFillColor = false, hasDefaultFillOpacity = false, hasDefaultOutlineColor = false, hasDefaultOutlineWidth = false, hasDefaultOutlineOpacity = false;
1259  QgsSvgCache::instance()->containsParams( name, hasFillParam, hasDefaultFillColor, fillColor,
1260  hasFillOpacityParam, hasDefaultFillOpacity, fillOpacity,
1261  hasOutlineParam, hasDefaultOutlineColor, outlineColor,
1262  hasOutlineWidthParam, hasDefaultOutlineWidth, outlineWidth,
1263  hasOutlineOpacityParam, hasDefaultOutlineOpacity, outlineOpacity );
1264  if ( hasDefaultFillColor )
1265  {
1266  m->setFillColor( fillColor );
1267  }
1268  if ( hasDefaultFillOpacity )
1269  {
1270  QColor c = m->fillColor();
1271  c.setAlphaF( fillOpacity );
1272  m->setFillColor( c );
1273  }
1274  if ( hasDefaultOutlineColor )
1275  {
1276  m->setOutlineColor( outlineColor );
1277  }
1278  if ( hasDefaultOutlineWidth )
1279  {
1280  m->setOutlineWidth( outlineWidth );
1281  }
1282  if ( hasDefaultOutlineOpacity )
1283  {
1284  QColor c = m->outlineColor();
1285  c.setAlphaF( outlineOpacity );
1286  m->setOutlineColor( c );
1287  }
1288  }
1289 
1290  if ( props.contains( "size_unit" ) )
1291  m->setSizeUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["size_unit"] ) );
1292  if ( props.contains( "size_map_unit_scale" ) )
1293  m->setSizeMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["size_map_unit_scale"] ) );
1294  if ( props.contains( "offset" ) )
1295  m->setOffset( QgsSymbolLayerV2Utils::decodePoint( props["offset"] ) );
1296  if ( props.contains( "offset_unit" ) )
1297  m->setOffsetUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["offset_unit"] ) );
1298  if ( props.contains( "offset_map_unit_scale" ) )
1299  m->setOffsetMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["offset_map_unit_scale"] ) );
1300  if ( props.contains( "fill" ) )
1301  {
1302  //pre 2.5 projects used "fill"
1303  m->setFillColor( QgsSymbolLayerV2Utils::decodeColor( props["fill"] ) );
1304  }
1305  else if ( props.contains( "color" ) )
1306  {
1307  m->setFillColor( QgsSymbolLayerV2Utils::decodeColor( props["color"] ) );
1308  }
1309  if ( props.contains( "outline" ) )
1310  {
1311  //pre 2.5 projects used "outline"
1312  m->setOutlineColor( QgsSymbolLayerV2Utils::decodeColor( props["outline"] ) );
1313  }
1314  else if ( props.contains( "outline_color" ) )
1315  {
1316  m->setOutlineColor( QgsSymbolLayerV2Utils::decodeColor( props["outline_color"] ) );
1317  }
1318  else if ( props.contains( "line_color" ) )
1319  {
1320  m->setOutlineColor( QgsSymbolLayerV2Utils::decodeColor( props["line_color"] ) );
1321  }
1322 
1323  if ( props.contains( "outline-width" ) )
1324  {
1325  //pre 2.5 projects used "outline-width"
1326  m->setOutlineWidth( props["outline-width"].toDouble() );
1327  }
1328  else if ( props.contains( "outline_width" ) )
1329  {
1330  m->setOutlineWidth( props["outline_width"].toDouble() );
1331  }
1332  else if ( props.contains( "line_width" ) )
1333  {
1334  m->setOutlineWidth( props["line_width"].toDouble() );
1335  }
1336 
1337  if ( props.contains( "outline_width_unit" ) )
1338  {
1339  m->setOutlineWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["outline_width_unit"] ) );
1340  }
1341  else if ( props.contains( "line_width_unit" ) )
1342  {
1343  m->setOutlineWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["line_width_unit"] ) );
1344  }
1345  if ( props.contains( "outline_width_map_unit_scale" ) )
1346  m->setOutlineWidthMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["outline_width_map_unit_scale"] ) );
1347 
1348  if ( props.contains( "horizontal_anchor_point" ) )
1349  {
1350  m->setHorizontalAnchorPoint( QgsMarkerSymbolLayerV2::HorizontalAnchorPoint( props[ "horizontal_anchor_point" ].toInt() ) );
1351  }
1352  if ( props.contains( "vertical_anchor_point" ) )
1353  {
1354  m->setVerticalAnchorPoint( QgsMarkerSymbolLayerV2::VerticalAnchorPoint( props[ "vertical_anchor_point" ].toInt() ) );
1355  }
1356 
1357  m->restoreDataDefinedProperties( props );
1358 
1359  return m;
1360 }
1361 
1363 {
1364  mPath = path;
1365  QColor defaultFillColor, defaultOutlineColor;
1366  double outlineWidth, fillOpacity, outlineOpacity;
1367  bool hasFillParam = false, hasFillOpacityParam = false, hasOutlineParam = false, hasOutlineWidthParam = false, hasOutlineOpacityParam = false;
1368  bool hasDefaultFillColor = false, hasDefaultFillOpacity = false, hasDefaultOutlineColor = false, hasDefaultOutlineWidth = false, hasDefaultOutlineOpacity = false;
1369  QgsSvgCache::instance()->containsParams( path, hasFillParam, hasDefaultFillColor, defaultFillColor,
1370  hasFillOpacityParam, hasDefaultFillOpacity, fillOpacity,
1371  hasOutlineParam, hasDefaultOutlineColor, defaultOutlineColor,
1372  hasOutlineWidthParam, hasDefaultOutlineWidth, outlineWidth,
1373  hasOutlineOpacityParam, hasDefaultOutlineOpacity, outlineOpacity );
1374 
1375  double newFillOpacity = hasFillOpacityParam ? fillColor().alphaF() : 1.0;
1376  double newOutlineOpacity = hasOutlineOpacityParam ? outlineColor().alphaF() : 1.0;
1377 
1378  if ( hasDefaultFillColor )
1379  {
1380  defaultFillColor.setAlphaF( newFillOpacity );
1381  setFillColor( defaultFillColor );
1382  }
1383  if ( hasDefaultFillOpacity )
1384  {
1385  QColor c = fillColor();
1386  c.setAlphaF( fillOpacity );
1387  setFillColor( c );
1388  }
1389  if ( hasDefaultOutlineColor )
1390  {
1391  defaultOutlineColor.setAlphaF( newOutlineOpacity );
1392  setOutlineColor( defaultOutlineColor );
1393  }
1394  if ( hasDefaultOutlineWidth )
1395  {
1396  setOutlineWidth( outlineWidth );
1397  }
1398  if ( hasDefaultOutlineOpacity )
1399  {
1400  QColor c = outlineColor();
1401  c.setAlphaF( outlineOpacity );
1402  setOutlineColor( c );
1403  }
1404 }
1405 
1406 
1408 {
1409  return "SvgMarker";
1410 }
1411 
1413 {
1414  QgsMarkerSymbolLayerV2::startRender( context ); // get anchor point expressions
1415  Q_UNUSED( context );
1416  prepareExpressions( context );
1417 }
1418 
1420 {
1421  Q_UNUSED( context );
1422 }
1423 
1425 {
1426  QPainter *p = context.renderContext().painter();
1427  if ( !p )
1428  return;
1429 
1430  bool hasDataDefinedSize = false;
1431  double scaledSize = calculateSize( context, hasDataDefinedSize );
1433 
1434  //don't render symbols with size below one or above 10,000 pixels
1435  if ( static_cast< int >( size ) < 1 || 10000.0 < size )
1436  {
1437  return;
1438  }
1439 
1440  p->save();
1441 
1442  QPointF outputOffset;
1443  double angle = 0.0;
1444  calculateOffsetAndRotation( context, scaledSize, outputOffset, angle );
1445 
1446  p->translate( point + outputOffset );
1447 
1448  bool rotated = !qgsDoubleNear( angle, 0 );
1449  if ( rotated )
1450  p->rotate( angle );
1451 
1452  QString path = mPath;
1454  {
1455  context.setOriginalValueVariable( mPath );
1457  }
1458 
1459  double outlineWidth = mOutlineWidth;
1461  {
1464  }
1466 
1468  bool ok = false;
1470  {
1473  if ( ok )
1474  fillColor = QgsSymbolLayerV2Utils::decodeColor( colorString );
1475  }
1476 
1477  QColor outlineColor = mOutlineColor;
1479  {
1482  if ( ok )
1483  outlineColor = QgsSymbolLayerV2Utils::decodeColor( colorString );
1484  }
1485 
1486  bool fitsInCache = true;
1487  bool usePict = true;
1488  double hwRatio = 1.0;
1489  if ( !context.renderContext().forceVectorOutput() && !rotated )
1490  {
1491  usePict = false;
1492  const QImage& img = QgsSvgCache::instance()->svgAsImage( path, size, fillColor, outlineColor, outlineWidth,
1493  context.renderContext().scaleFactor(), context.renderContext().rasterScaleFactor(), fitsInCache );
1494  if ( fitsInCache && img.width() > 1 )
1495  {
1496  //consider transparency
1497  if ( !qgsDoubleNear( context.alpha(), 1.0 ) )
1498  {
1499  QImage transparentImage = img.copy();
1500  QgsSymbolLayerV2Utils::multiplyImageOpacity( &transparentImage, context.alpha() );
1501  p->drawImage( -transparentImage.width() / 2.0, -transparentImage.height() / 2.0, transparentImage );
1502  hwRatio = static_cast< double >( transparentImage.height() ) / static_cast< double >( transparentImage.width() );
1503  }
1504  else
1505  {
1506  p->drawImage( -img.width() / 2.0, -img.height() / 2.0, img );
1507  hwRatio = static_cast< double >( img.height() ) / static_cast< double >( img.width() );
1508  }
1509  }
1510  }
1511 
1512  if ( usePict || !fitsInCache )
1513  {
1514  p->setOpacity( context.alpha() );
1515  const QPicture& pct = QgsSvgCache::instance()->svgAsPicture( path, size, fillColor, outlineColor, outlineWidth,
1517 
1518  if ( pct.width() > 1 )
1519  {
1520  p->save();
1521  _fixQPictureDPI( p );
1522  p->drawPicture( 0, 0, pct );
1523  p->restore();
1524  hwRatio = static_cast< double >( pct.height() ) / static_cast< double >( pct.width() );
1525  }
1526  }
1527 
1528  if ( context.selected() )
1529  {
1530  QPen pen( context.renderContext().selectionColor() );
1532  if ( penWidth > size / 20 )
1533  {
1534  // keep the pen width from covering symbol
1535  penWidth = size / 20;
1536  }
1537  double penOffset = penWidth / 2;
1538  pen.setWidth( penWidth );
1539  p->setPen( pen );
1540  p->setBrush( Qt::NoBrush );
1541  double wSize = size + penOffset;
1542  double hSize = size * hwRatio + penOffset;
1543  p->drawRect( QRectF( -wSize / 2.0, -hSize / 2.0, wSize, hSize ) );
1544  }
1545 
1546  p->restore();
1547 }
1548 
1549 double QgsSvgMarkerSymbolLayerV2::calculateSize( QgsSymbolV2RenderContext& context, bool& hasDataDefinedSize ) const
1550 {
1551  double scaledSize = mSize;
1553 
1554  bool ok = true;
1556  {
1557  context.setOriginalValueVariable( mSize );
1558  scaledSize = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_SIZE, context, mSize, &ok ).toDouble();
1559  }
1560 
1561  if ( hasDataDefinedSize && ok )
1562  {
1563  switch ( mScaleMethod )
1564  {
1566  scaledSize = sqrt( scaledSize );
1567  break;
1569  break;
1570  }
1571  }
1572 
1573  return scaledSize;
1574 }
1575 
1576 void QgsSvgMarkerSymbolLayerV2::calculateOffsetAndRotation( QgsSymbolV2RenderContext& context, double scaledSize, QPointF& offset, double& angle ) const
1577 {
1578  //offset
1579  double offsetX = 0;
1580  double offsetY = 0;
1581  markerOffset( context, scaledSize, scaledSize, offsetX, offsetY );
1582  offset = QPointF( offsetX, offsetY );
1583 
1584  angle = mAngle + mLineAngle;
1586  {
1587  context.setOriginalValueVariable( mAngle );
1589  }
1590 
1592  if ( hasDataDefinedRotation )
1593  {
1594  // For non-point markers, "dataDefinedRotation" means following the
1595  // shape (shape-data defined). For them, "field-data defined" does
1596  // not work at all. TODO: if "field-data defined" ever gets implemented
1597  // we'll need a way to distinguish here between the two, possibly
1598  // using another flag in renderHints()
1599  const QgsFeature* f = context.feature();
1600  if ( f )
1601  {
1602  const QgsGeometry *g = f->constGeometry();
1603  if ( g && g->type() == QGis::Point )
1604  {
1605  const QgsMapToPixel& m2p = context.renderContext().mapToPixel();
1606  angle += m2p.mapRotation();
1607  }
1608  }
1609  }
1610 
1611  if ( angle )
1612  offset = _rotatedOffset( offset, angle );
1613 }
1614 
1615 
1617 {
1618  QgsStringMap map;
1620  map["size"] = QString::number( mSize );
1621  map["size_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mSizeUnit );
1622  map["size_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mSizeMapUnitScale );
1623  map["angle"] = QString::number( mAngle );
1624  map["offset"] = QgsSymbolLayerV2Utils::encodePoint( mOffset );
1625  map["offset_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOffsetUnit );
1626  map["offset_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOffsetMapUnitScale );
1627  map["scale_method"] = QgsSymbolLayerV2Utils::encodeScaleMethod( mScaleMethod );
1628  map["color"] = QgsSymbolLayerV2Utils::encodeColor( mColor );
1629  map["outline_color"] = QgsSymbolLayerV2Utils::encodeColor( mOutlineColor );
1630  map["outline_width"] = QString::number( mOutlineWidth );
1631  map["outline_width_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOutlineWidthUnit );
1632  map["outline_width_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOutlineWidthMapUnitScale );
1633  map["horizontal_anchor_point"] = QString::number( mHorizontalAnchorPoint );
1634  map["vertical_anchor_point"] = QString::number( mVerticalAnchorPoint );
1635 
1637  return map;
1638 }
1639 
1641 {
1643  m->setColor( mColor );
1644  m->setOutlineColor( mOutlineColor );
1648  m->setOffset( mOffset );
1649  m->setOffsetUnit( mOffsetUnit );
1651  m->setSizeUnit( mSizeUnit );
1656  copyPaintEffect( m );
1657  return m;
1658 }
1659 
1661 {
1663  mOutlineWidthUnit = unit;
1664 }
1665 
1667 {
1669  if ( unit != mOutlineWidthUnit )
1670  {
1671  return QgsSymbolV2::Mixed;
1672  }
1673  return unit;
1674 }
1675 
1677 {
1679  mOutlineWidthMapUnitScale = scale;
1680 }
1681 
1683 {
1685  {
1687  }
1688  return QgsMapUnitScale();
1689 }
1690 
1692 {
1693  // <Graphic>
1694  QDomElement graphicElem = doc.createElement( "se:Graphic" );
1695  element.appendChild( graphicElem );
1696 
1697  QgsSymbolLayerV2Utils::externalGraphicToSld( doc, graphicElem, mPath, "image/svg+xml", mColor, mSize );
1698 
1699  // <Rotation>
1700  QString angleFunc;
1701  bool ok;
1702  double angle = props.value( "angle", "0" ).toDouble( &ok );
1703  if ( !ok )
1704  {
1705  angleFunc = QString( "%1 + %2" ).arg( props.value( "angle", "0" ) ).arg( mAngle );
1706  }
1707  else if ( !qgsDoubleNear( angle + mAngle, 0.0 ) )
1708  {
1709  angleFunc = QString::number( angle + mAngle );
1710  }
1711 
1712  QgsSymbolLayerV2Utils::createRotationElement( doc, graphicElem, angleFunc );
1713 
1714  // <Displacement>
1716 }
1717 
1719 {
1720  QgsDebugMsg( "Entered." );
1721 
1722  QDomElement graphicElem = element.firstChildElement( "Graphic" );
1723  if ( graphicElem.isNull() )
1724  return nullptr;
1725 
1726  QString path, mimeType;
1727  QColor fillColor;
1728  double size;
1729 
1730  if ( !QgsSymbolLayerV2Utils::externalGraphicFromSld( graphicElem, path, mimeType, fillColor, size ) )
1731  return nullptr;
1732 
1733  if ( mimeType != "image/svg+xml" )
1734  return nullptr;
1735 
1736  double angle = 0.0;
1737  QString angleFunc;
1738  if ( QgsSymbolLayerV2Utils::rotationFromSldElement( graphicElem, angleFunc ) )
1739  {
1740  bool ok;
1741  double d = angleFunc.toDouble( &ok );
1742  if ( ok )
1743  angle = d;
1744  }
1745 
1746  QPointF offset;
1748 
1750  m->setFillColor( fillColor );
1751  //m->setOutlineColor( outlineColor );
1752  //m->setOutlineWidth( outlineWidth );
1753  m->setAngle( angle );
1754  m->setOffset( offset );
1755  return m;
1756 }
1757 
1758 bool QgsSvgMarkerSymbolLayerV2::writeDxf( QgsDxfExport& e, double mmMapUnitScaleFactor, const QString& layerName, QgsSymbolV2RenderContext &context, QPointF shift ) const
1759 {
1760  Q_UNUSED( layerName );
1761  Q_UNUSED( shift ); //todo...
1762 
1763  //size
1764  double size = mSize;
1765 
1767 
1768  bool ok = true;
1770  {
1771  context.setOriginalValueVariable( mSize );
1773  }
1774 
1775  if ( hasDataDefinedSize && ok )
1776  {
1777  switch ( mScaleMethod )
1778  {
1780  size = sqrt( size );
1781  break;
1783  break;
1784  }
1785  }
1786 
1787  if ( mSizeUnit == QgsSymbolV2::MM )
1788  {
1789  size *= mmMapUnitScaleFactor;
1790  }
1791 
1792  double halfSize = size / 2.0;
1793 
1794  //offset, angle
1795  QPointF offset = mOffset;
1796 
1798  {
1801  if ( ok )
1802  offset = QgsSymbolLayerV2Utils::decodePoint( offsetString );
1803  }
1804  double offsetX = offset.x();
1805  double offsetY = offset.y();
1806  if ( mSizeUnit == QgsSymbolV2::MM )
1807  {
1808  offsetX *= mmMapUnitScaleFactor;
1809  offsetY *= mmMapUnitScaleFactor;
1810  }
1811 
1812  QPointF outputOffset( offsetX, offsetY );
1813 
1814  double angle = mAngle + mLineAngle;
1816  {
1817  context.setOriginalValueVariable( mAngle );
1819  }
1820  //angle = -angle; //rotation in Qt is counterclockwise
1821  if ( angle )
1822  outputOffset = _rotatedOffset( outputOffset, angle );
1823 
1824  QString path = mPath;
1826  {
1827  context.setOriginalValueVariable( mPath );
1829  }
1830 
1831  double outlineWidth = mOutlineWidth;
1833  {
1836  }
1838 
1841  {
1844  if ( ok )
1845  fillColor = QgsSymbolLayerV2Utils::decodeColor( colorString );
1846  }
1847 
1848  QColor outlineColor = mOutlineColor;
1850  {
1853  if ( ok )
1854  outlineColor = QgsSymbolLayerV2Utils::decodeColor( colorString );
1855  }
1856 
1857  const QByteArray &svgContent = QgsSvgCache::instance()->svgContent( path, size, fillColor, outlineColor, outlineWidth,
1858  context.renderContext().scaleFactor(),
1859  context.renderContext().rasterScaleFactor() );
1860 
1861  //if current entry image is 0: cache image for entry
1862  // checks to see if image will fit into cache
1863  //update stats for memory usage
1864  QSvgRenderer r( svgContent );
1865  if ( !r.isValid() )
1866  {
1867  return false;
1868  }
1869 
1870  QgsDxfPaintDevice pd( &e );
1871  pd.setDrawingSize( QSizeF( r.defaultSize() ) );
1872 
1873  QPainter p;
1874  p.begin( &pd );
1875  if ( !qgsDoubleNear( angle, 0.0 ) )
1876  {
1877  p.translate( r.defaultSize().width() / 2.0, r.defaultSize().height() / 2.0 );
1878  p.rotate( angle );
1879  p.translate( -r.defaultSize().width() / 2.0, -r.defaultSize().height() / 2.0 );
1880  }
1881  pd.setShift( shift );
1882  pd.setOutputSize( QRectF( -halfSize, -halfSize, size, size ) );
1883  pd.setLayer( layerName );
1884  r.render( &p );
1885  p.end();
1886  return true;
1887 }
1888 
1890 {
1891  bool hasDataDefinedSize = false;
1892  double scaledSize = calculateSize( context, hasDataDefinedSize );
1894 
1895  //don't render symbols with size below one or above 10,000 pixels
1896  if ( static_cast< int >( scaledSize ) < 1 || 10000.0 < scaledSize )
1897  {
1898  return QRectF();
1899  }
1900 
1901  QPointF outputOffset;
1902  double angle = 0.0;
1903  calculateOffsetAndRotation( context, scaledSize, outputOffset, angle );
1904 
1905  QString path = mPath;
1907  {
1908  context.setOriginalValueVariable( mPath );
1910  }
1911 
1912  double outlineWidth = mOutlineWidth;
1914  {
1917  }
1919 
1920  //need to get colors to take advantage of cached SVGs
1922  bool ok = false;
1924  {
1927  if ( ok )
1928  fillColor = QgsSymbolLayerV2Utils::decodeColor( colorString );
1929  }
1930 
1931  QColor outlineColor = mOutlineColor;
1933  {
1936  if ( ok )
1937  outlineColor = QgsSymbolLayerV2Utils::decodeColor( colorString );
1938  }
1939 
1940  QSizeF svgViewbox = QgsSvgCache::instance()->svgViewboxSize( path, scaledSize, fillColor, outlineColor, outlineWidth,
1941  context.renderContext().scaleFactor(),
1942  context.renderContext().rasterScaleFactor() );
1943 
1944  double scaledHeight = svgViewbox.isValid() ? scaledSize * svgViewbox.height() / svgViewbox.width() : scaledSize;
1945  double pixelSize = 1.0 / context.renderContext().rasterScaleFactor();
1946 
1947  QMatrix transform;
1948 
1949  // move to the desired position
1950  transform.translate( point.x() + outputOffset.x(), point.y() + outputOffset.y() );
1951 
1952  if ( !qgsDoubleNear( angle, 0.0 ) )
1953  transform.rotate( angle );
1954 
1955  //antialiasing
1956  outlineWidth += pixelSize / 2.0;
1957 
1958  QRectF symbolBounds = transform.mapRect( QRectF( -scaledSize / 2.0,
1959  -scaledHeight / 2.0,
1960  scaledSize,
1961  scaledHeight ) );
1962 
1963  //extend bounds by pen width / 2.0
1964  symbolBounds.adjust( -outlineWidth / 2.0, -outlineWidth / 2.0,
1965  outlineWidth / 2.0, outlineWidth / 2.0 );
1966 
1967  return symbolBounds;
1968 
1969 }
1970 
1972 
1973 QgsFontMarkerSymbolLayerV2::QgsFontMarkerSymbolLayerV2( const QString& fontFamily, QChar chr, double pointSize, const QColor& color, double angle )
1974  : mFontMetrics( nullptr )
1975  , mChrWidth( 0 )
1976 {
1978  mChr = chr;
1979  mColor = color;
1980  mAngle = angle;
1981  mSize = pointSize;
1982  mOrigSize = pointSize;
1984  mOffset = QPointF( 0, 0 );
1986  mOutlineColor = DEFAULT_FONTMARKER_BORDERCOLOR;
1987  mOutlineWidth = 0.0;
1988  mOutlineWidthUnit = QgsSymbolV2::MM;
1989  mPenJoinStyle = DEFAULT_FONTMARKER_JOINSTYLE;
1990 }
1991 
1993 {
1994  delete mFontMetrics;
1995 }
1996 
1998 {
2001  double pointSize = DEFAULT_FONTMARKER_SIZE;
2004 
2005  if ( props.contains( "font" ) )
2006  fontFamily = props["font"];
2007  if ( props.contains( "chr" ) && props["chr"].length() > 0 )
2008  chr = props["chr"].at( 0 );
2009  if ( props.contains( "size" ) )
2010  pointSize = props["size"].toDouble();
2011  if ( props.contains( "color" ) )
2012  color = QgsSymbolLayerV2Utils::decodeColor( props["color"] );
2013  if ( props.contains( "angle" ) )
2014  angle = props["angle"].toDouble();
2015 
2016  QgsFontMarkerSymbolLayerV2* m = new QgsFontMarkerSymbolLayerV2( fontFamily, chr, pointSize, color, angle );
2017 
2018  if ( props.contains( "outline_color" ) )
2019  m->setOutlineColor( QgsSymbolLayerV2Utils::decodeColor( props["outline_color"] ) );
2020  if ( props.contains( "outline_width" ) )
2021  m->setOutlineWidth( props["outline_width"].toDouble() );
2022  if ( props.contains( "offset" ) )
2023  m->setOffset( QgsSymbolLayerV2Utils::decodePoint( props["offset"] ) );
2024  if ( props.contains( "offset_unit" ) )
2025  m->setOffsetUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["offset_unit" ] ) );
2026  if ( props.contains( "offset_map_unit_scale" ) )
2027  m->setOffsetMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["offset_map_unit_scale" ] ) );
2028  if ( props.contains( "size_unit" ) )
2029  m->setSizeUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["size_unit"] ) );
2030  if ( props.contains( "size_map_unit_scale" ) )
2031  m->setSizeMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["size_map_unit_scale"] ) );
2032  if ( props.contains( "outline_width_unit" ) )
2033  m->setOutlineWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["outline_width_unit"] ) );
2034  if ( props.contains( "outline_width_map_unit_scale" ) )
2035  m->setOutlineWidthMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["outline_width_map_unit_scale"] ) );
2036  if ( props.contains( "joinstyle" ) )
2037  m->setPenJoinStyle( QgsSymbolLayerV2Utils::decodePenJoinStyle( props["joinstyle"] ) );
2038  if ( props.contains( "horizontal_anchor_point" ) )
2039  m->setHorizontalAnchorPoint( QgsMarkerSymbolLayerV2::HorizontalAnchorPoint( props[ "horizontal_anchor_point" ].toInt() ) );
2040  if ( props.contains( "vertical_anchor_point" ) )
2041  m->setVerticalAnchorPoint( QgsMarkerSymbolLayerV2::VerticalAnchorPoint( props[ "vertical_anchor_point" ].toInt() ) );
2042 
2043  m->restoreDataDefinedProperties( props );
2044 
2045  return m;
2046 }
2047 
2049 {
2050  return "FontMarker";
2051 }
2052 
2054 {
2055  QColor brushColor = mColor;
2056  QColor penColor = mOutlineColor;
2057 
2058  brushColor.setAlphaF( mColor.alphaF() * context.alpha() );
2059  penColor.setAlphaF( mOutlineColor.alphaF() * context.alpha() );
2060 
2061  mBrush = QBrush( brushColor );
2062  mPen = QPen( penColor );
2063  mPen.setJoinStyle( mPenJoinStyle );
2064  mPen.setWidthF( QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), mOutlineWidth, mOutlineWidthUnit, mOutlineWidthMapUnitScale ) );
2065 
2066  mFont = QFont( mFontFamily );
2068  delete mFontMetrics;
2069  mFontMetrics = new QFontMetrics( mFont );
2071  mChrOffset = QPointF( mChrWidth / 2.0, -mFontMetrics->ascent() / 2.0 );
2072  mOrigSize = mSize; // save in case the size would be data defined
2073  prepareExpressions( context );
2074 }
2075 
2077 {
2078  Q_UNUSED( context );
2079 }
2080 
2081 QString QgsFontMarkerSymbolLayerV2::characterToRender( QgsSymbolV2RenderContext& context, QPointF& charOffset, double& charWidth )
2082 {
2083  charOffset = mChrOffset;
2084  QString charToRender = mChr;
2086  {
2087  context.setOriginalValueVariable( mChr );
2089  if ( charToRender != mChr )
2090  {
2091  charWidth = mFontMetrics->width( charToRender );
2092  charOffset = QPointF( charWidth / 2.0, -mFontMetrics->ascent() / 2.0 );
2093  }
2094  }
2095  return charToRender;
2096 }
2097 
2098 void QgsFontMarkerSymbolLayerV2::calculateOffsetAndRotation( QgsSymbolV2RenderContext& context,
2099  double scaledSize,
2100  bool& hasDataDefinedRotation,
2101  QPointF& offset,
2102  double& angle ) const
2103 {
2104  //offset
2105  double offsetX = 0;
2106  double offsetY = 0;
2107  markerOffset( context, scaledSize, scaledSize, offsetX, offsetY );
2108  offset = QPointF( offsetX, offsetY );
2109 
2110  //angle
2111  bool ok = true;
2112  angle = mAngle + mLineAngle;
2113  bool usingDataDefinedRotation = false;
2115  {
2116  context.setOriginalValueVariable( angle );
2118  usingDataDefinedRotation = ok;
2119  }
2120 
2121  hasDataDefinedRotation = context.renderHints() & QgsSymbolV2::DataDefinedRotation || usingDataDefinedRotation;
2122  if ( hasDataDefinedRotation )
2123  {
2124  // For non-point markers, "dataDefinedRotation" means following the
2125  // shape (shape-data defined). For them, "field-data defined" does
2126  // not work at all. TODO: if "field-data defined" ever gets implemented
2127  // we'll need a way to distinguish here between the two, possibly
2128  // using another flag in renderHints()
2129  const QgsFeature* f = context.feature();
2130  if ( f )
2131  {
2132  const QgsGeometry *g = f->constGeometry();
2133  if ( g && g->type() == QGis::Point )
2134  {
2135  const QgsMapToPixel& m2p = context.renderContext().mapToPixel();
2136  angle += m2p.mapRotation();
2137  }
2138  }
2139  }
2140 
2141  if ( angle )
2142  offset = _rotatedOffset( offset, angle );
2143 }
2144 
2145 double QgsFontMarkerSymbolLayerV2::calculateSize( QgsSymbolV2RenderContext& context )
2146 {
2147  double scaledSize = mSize;
2149 
2150  bool ok = true;
2152  {
2153  context.setOriginalValueVariable( mSize );
2154  scaledSize = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_SIZE, context, mSize, &ok ).toDouble();
2155  }
2156 
2157  if ( hasDataDefinedSize && ok )
2158  {
2159  switch ( mScaleMethod )
2160  {
2162  scaledSize = sqrt( scaledSize );
2163  break;
2165  break;
2166  }
2167  }
2168  return scaledSize;
2169 }
2170 
2172 {
2173  QPainter *p = context.renderContext().painter();
2174  if ( !p )
2175  return;
2176 
2177  QTransform transform;
2178 
2179  bool ok;
2180  QColor brushColor = mColor;
2182  {
2185  if ( ok )
2186  brushColor = QgsSymbolLayerV2Utils::decodeColor( colorString );
2187  }
2188  brushColor = context.selected() ? context.renderContext().selectionColor() : brushColor;
2189  brushColor.setAlphaF( brushColor.alphaF() * context.alpha() );
2190  mBrush.setColor( brushColor );
2191 
2192  QColor penColor = mOutlineColor;
2194  {
2197  if ( ok )
2198  penColor = QgsSymbolLayerV2Utils::decodeColor( colorString );
2199  }
2200  penColor.setAlphaF( penColor.alphaF() * context.alpha() );
2201 
2202  double penWidth = QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), mOutlineWidth, mOutlineWidthUnit, mOutlineWidthMapUnitScale );
2204  {
2205  context.setOriginalValueVariable( mOutlineWidth );
2207  if ( ok )
2208  {
2209  penWidth = QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), outlineWidth, mOutlineWidthUnit, mOutlineWidthMapUnitScale );
2210  }
2211  }
2212 
2214  {
2217  if ( ok )
2218  {
2220  }
2221  }
2222 
2223  p->setBrush( mBrush );
2224  if ( !qgsDoubleNear( penWidth, 0.0 ) )
2225  {
2226  mPen.setColor( penColor );
2227  mPen.setWidthF( penWidth );
2228  p->setPen( mPen );
2229  }
2230  else
2231  {
2232  p->setPen( Qt::NoPen );
2233  }
2234  p->save();
2235 
2236  QPointF chrOffset = mChrOffset;
2237  double chrWidth;
2238  QString charToRender = characterToRender( context, chrOffset, chrWidth );
2239 
2240  double sizeToRender = calculateSize( context );
2241 
2242  bool hasDataDefinedRotation = false;
2243  QPointF offset;
2244  double angle = 0;
2245  calculateOffsetAndRotation( context, sizeToRender, hasDataDefinedRotation, offset, angle );
2246 
2247  transform.translate( point.x() + offset.x(), point.y() + offset.y() );
2248 
2249  if ( !qgsDoubleNear( angle, 0.0 ) )
2250  transform.rotate( angle );
2251 
2252  if ( !qgsDoubleNear( sizeToRender, mOrigSize ) )
2253  {
2254  double s = sizeToRender / mOrigSize;
2255  transform.scale( s, s );
2256  }
2257 
2258  QPainterPath path;
2259  path.addText( -chrOffset.x(), -chrOffset.y(), mFont, charToRender );
2260  p->drawPath( transform.map( path ) );
2261  p->restore();
2262 }
2263 
2265 {
2266  QgsStringMap props;
2267  props["font"] = mFontFamily;
2268  props["chr"] = mChr;
2269  props["size"] = QString::number( mSize );
2270  props["size_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mSizeUnit );
2271  props["size_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mSizeMapUnitScale );
2272  props["color"] = QgsSymbolLayerV2Utils::encodeColor( mColor );
2273  props["outline_color"] = QgsSymbolLayerV2Utils::encodeColor( mOutlineColor );
2274  props["outline_width"] = QString::number( mOutlineWidth );
2275  props["outline_width_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOutlineWidthUnit );
2276  props["outline_width_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOutlineWidthMapUnitScale );
2277  props["joinstyle"] = QgsSymbolLayerV2Utils::encodePenJoinStyle( mPenJoinStyle );
2278  props["angle"] = QString::number( mAngle );
2279  props["offset"] = QgsSymbolLayerV2Utils::encodePoint( mOffset );
2280  props["offset_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOffsetUnit );
2281  props["offset_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOffsetMapUnitScale );
2282  props["horizontal_anchor_point"] = QString::number( mHorizontalAnchorPoint );
2283  props["vertical_anchor_point"] = QString::number( mVerticalAnchorPoint );
2284 
2285  //data define properties
2286  saveDataDefinedProperties( props );
2287 
2288  return props;
2289 }
2290 
2292 {
2294  m->setOutlineColor( mOutlineColor );
2295  m->setOutlineWidth( mOutlineWidth );
2296  m->setOutlineWidthUnit( mOutlineWidthUnit );
2297  m->setOutlineWidthMapUnitScale( mOutlineWidthMapUnitScale );
2298  m->setPenJoinStyle( mPenJoinStyle );
2299  m->setOffset( mOffset );
2300  m->setOffsetUnit( mOffsetUnit );
2302  m->setSizeUnit( mSizeUnit );
2307  copyPaintEffect( m );
2308  return m;
2309 }
2310 
2312 {
2313  // <Graphic>
2314  QDomElement graphicElem = doc.createElement( "se:Graphic" );
2315  element.appendChild( graphicElem );
2316 
2317  QString fontPath = QString( "ttf://%1" ).arg( mFontFamily );
2318  int markIndex = mChr.unicode();
2319  QgsSymbolLayerV2Utils::externalMarkerToSld( doc, graphicElem, fontPath, "ttf", &markIndex, mColor, mSize );
2320 
2321  // <Rotation>
2322  QString angleFunc;
2323  bool ok;
2324  double angle = props.value( "angle", "0" ).toDouble( &ok );
2325  if ( !ok )
2326  {
2327  angleFunc = QString( "%1 + %2" ).arg( props.value( "angle", "0" ) ).arg( mAngle );
2328  }
2329  else if ( !qgsDoubleNear( angle + mAngle, 0.0 ) )
2330  {
2331  angleFunc = QString::number( angle + mAngle );
2332  }
2333  QgsSymbolLayerV2Utils::createRotationElement( doc, graphicElem, angleFunc );
2334 
2335  // <Displacement>
2337 }
2338 
2340 {
2341  QPointF chrOffset = mChrOffset;
2342  double chrWidth = mChrWidth;
2343  //calculate width of rendered character
2344  ( void )characterToRender( context, chrOffset, chrWidth );
2345 
2346  if ( !mFontMetrics )
2347  mFontMetrics = new QFontMetrics( mFont );
2348 
2349  double scaledSize = calculateSize( context );
2350  if ( !qgsDoubleNear( scaledSize, mOrigSize ) )
2351  {
2352  chrWidth *= scaledSize / mOrigSize;
2353  }
2354 
2355  bool hasDataDefinedRotation = false;
2356  QPointF offset;
2357  double angle = 0;
2358  calculateOffsetAndRotation( context, scaledSize, hasDataDefinedRotation, offset, angle );
2360 
2361  QMatrix transform;
2362 
2363  // move to the desired position
2364  transform.translate( point.x() + offset.x(), point.y() + offset.y() );
2365 
2366  if ( !qgsDoubleNear( angle, 0.0 ) )
2367  transform.rotate( angle );
2368 
2369  QRectF symbolBounds = transform.mapRect( QRectF( -chrWidth / 2.0,
2370  -scaledSize / 2.0,
2371  chrWidth,
2372  scaledSize ) );
2373  return symbolBounds;
2374 }
2375 
2377 {
2378  QgsDebugMsg( "Entered." );
2379 
2380  QDomElement graphicElem = element.firstChildElement( "Graphic" );
2381  if ( graphicElem.isNull() )
2382  return nullptr;
2383 
2384  QString name, format;
2385  QColor color;
2386  double size;
2387  int chr;
2388 
2389  if ( !QgsSymbolLayerV2Utils::externalMarkerFromSld( graphicElem, name, format, chr, color, size ) )
2390  return nullptr;
2391 
2392  if ( !name.startsWith( "ttf://" ) || format != "ttf" )
2393  return nullptr;
2394 
2395  QString fontFamily = name.mid( 6 );
2396 
2397  double angle = 0.0;
2398  QString angleFunc;
2399  if ( QgsSymbolLayerV2Utils::rotationFromSldElement( graphicElem, angleFunc ) )
2400  {
2401  bool ok;
2402  double d = angleFunc.toDouble( &ok );
2403  if ( ok )
2404  angle = d;
2405  }
2406 
2407  QPointF offset;
2409 
2410  QgsMarkerSymbolLayerV2 *m = new QgsFontMarkerSymbolLayerV2( fontFamily, chr, size, color );
2411  m->setAngle( angle );
2412  m->setOffset( offset );
2413  return m;
2414 }
2415 
2416 
void addEllipse(const QRectF &boundingRectangle)
QgsSymbolV2::OutputUnit outputUnit() const override
static QString encodeOutputUnit(QgsSymbolV2::OutputUnit unit)
Q_GUI_EXPORT int qt_defaultDpiX()
static const QString EXPR_CHAR
void setOutlineStyle(Qt::PenStyle outlineStyle)
Set outline join style.
static void createRotationElement(QDomDocument &doc, QDomElement &element, const QString &rotationFunc)
void setOutlineColor(const QColor &color) override
Set outline color.
void setOpacity(qreal opacity)
Qt::PenStyle style() const
void setPenJoinStyle(Qt::PenJoinStyle style)
Set outline join style.
static void externalMarkerToSld(QDomDocument &doc, QDomElement &element, const QString &path, const QString &format, int *markIndex=nullptr, const QColor &color=QColor(), double size=-1)
void stopRender(QgsSymbolV2RenderContext &context) override
QgsSymbolV2::OutputUnit outputUnit() const override
void setStyle(Qt::PenStyle style)
QString & append(QChar ch)
static QPointF _rotatedOffset(QPointF offset, double angle)
static void multiplyImageOpacity(QImage *image, qreal alpha)
Multiplies opacity of image pixel values with a (global) transparency value.
int ascent() const
OutputUnit
The unit of the output.
Definition: qgssymbolv2.h:62
Q_DECL_DEPRECATED void writeLine(const QgsPoint &pt1, const QgsPoint &pt2, const QString &layer, const QString &lineStyleName, const QColor &color, double width=-1)
Write line (as a polyline)
int renderHints() const
Definition: qgssymbolv2.h:369
QgsMapUnitScale mSizeMapUnitScale
Q_GUI_EXPORT int qt_defaultDpiY()
int width() const
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.
QDomNode appendChild(const QDomNode &newChild)
#define DEFAULT_FONTMARKER_COLOR
void render(QPainter *painter)
QString name() const
const QPicture & svgAsPicture(const QString &file, double size, const QColor &fill, const QColor &outline, double outlineWidth, double widthScaleFactor, double rasterScaleFactor, bool forceVectorOutput=false)
Get SVG as QPicture&.
QSizeF svgViewboxSize(const QString &file, double size, const QColor &fill, const QColor &outline, double outlineWidth, double widthScaleFactor, double rasterScaleFactor)
Calculates the viewbox size of a (possibly cached) SVG file.
Qt::BrushStyle style() const
QColor selectionColor() const
void setOutlineColor(const QColor &c) override
Set outline color.
QString layerType() const override
Returns a string that represents this layer type.
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
QPoint map(const QPoint &point) const
void setOutlineWidthMapUnitScale(const QgsMapUnitScale &scale)
Set outline width map unit scale.
static QString encodeColor(const QColor &color)
#define DEFAULT_SIMPLEMARKER_ANGLE
void renderPoint(QPointF point, QgsSymbolV2RenderContext &context) override
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 QgsSymbolV2::ScaleMethod decodeScaleMethod(const QString &str)
Calculate scale by the diameter.
Definition: qgssymbolv2.h:90
bool isValid() const
void setOffset(QPointF offset)
QString ogrFeatureStyle(double mmScaleFactor, double mapUnitScaleFactor) const override
void setHorizontalAnchorPoint(HorizontalAnchorPoint h)
bool isValid() const
#define DEG2RAD(x)
QGis::GeometryType type() const
Returns type of the geometry as a QGis::GeometryType.
#define DEFAULT_SIMPLEMARKER_COLOR
void save()
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
void drawPolygon(const QPointF *points, int pointCount, Qt::FillRule fillRule)
void setVerticalAnchorPoint(VerticalAnchorPoint v)
void setFillColor(const QColor &color) override
Set fill color.
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
void setJoinStyle(Qt::PenJoinStyle style)
void moveTo(const QPointF &point)
void renderPoint(QPointF point, QgsSymbolV2RenderContext &context) override
bool writeDxf(QgsDxfExport &e, double mmMapUnitScaleFactor, const QString &layerName, QgsSymbolV2RenderContext &context, QPointF shift=QPointF(0.0, 0.0)) const override
write as DXF
static QPointF decodePoint(const QString &str)
static Qt::PenJoinStyle decodePenJoinStyle(const QString &str)
void copyPaintEffect(QgsSymbolLayerV2 *destLayer) const
Copies paint effect of this layer to another symbol layer.
void stopRender(QgsSymbolV2RenderContext &context) override
static QString encodeMapUnitScale(const QgsMapUnitScale &mapUnitScale)
virtual bool hasDataDefinedProperty(const QString &property) const
Checks whether the layer has a matching data defined property and if that property is currently activ...
void writeSldMarker(QDomDocument &doc, QDomElement &element, const QgsStringMap &props) const override
bool writeDxf(QgsDxfExport &e, double mmMapUnitScaleFactor, const QString &layerName, QgsSymbolV2RenderContext &context, QPointF shift=QPointF(0.0, 0.0)) const override
write as DXF
double scaleFactor() const
QColor fillColor() const override
Get fill color.
void rotate(qreal angle)
static QgsSymbolLayerV2 * create(const QgsStringMap &properties=QgsStringMap())
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:187
static void _fixQPictureDPI(QPainter *p)
void addText(const QPointF &point, const QFont &font, const QString &text)
void setOffsetMapUnitScale(const QgsMapUnitScale &scale)
QImage copy(const QRect &rectangle) const
static void createDisplacementElement(QDomDocument &doc, QDomElement &element, QPointF offset)
double toDouble(bool *ok) const
static QgsSymbolLayerV2 * create(const QgsStringMap &properties=QgsStringMap())
double mapRotation() const
Return current map rotation in degrees.
void adjust(qreal dx1, qreal dy1, qreal dx2, qreal dy2)
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
Compare two doubles (but allow some difference)
Definition: qgis.h:348
static const QString EXPR_OFFSET
void setMapUnitScale(const QgsMapUnitScale &scale) override
static QgsSymbolLayerV2 * createFromSld(QDomElement &element)
#define DEFAULT_FONTMARKER_JOINSTYLE
QSize defaultSize() const
#define DEFAULT_SVGMARKER_ANGLE
static const QString EXPR_SIZE
void setOffsetUnit(QgsSymbolV2::OutputUnit unit)
bool isNull() const
#define DEFAULT_SIMPLEMARKER_NAME
static const QString EXPR_JOIN_STYLE
void containsParams(const QString &path, bool &hasFillParam, QColor &defaultFillColor, bool &hasOutlineParam, QColor &defaultOutlineColor, bool &hasOutlineWidthParam, double &defaultOutlineWidth) const
Tests if an svg file contains parameters for fill, outline color, outline width.
static QgsSymbolV2::OutputUnit decodeOutputUnit(const QString &str)
static bool displacementFromSldElement(QDomElement &element, QPointF &offset)
int width() const
qreal alpha() const
Get alpha transparency 1 for opaque, 0 for invisible.
Definition: qgssymbolv2.h:362
void drawMarker(QPainter *p, QgsSymbolV2RenderContext &context)
const QColor & color() const
static QgsSvgCache * instance()
Definition: qgssvgcache.cpp:97
static QString encodePenStyle(Qt::PenStyle style)
void setOutlineWidthUnit(QgsSymbolV2::OutputUnit unit)
const QImage & svgAsImage(const QString &file, double size, const QColor &fill, const QColor &outline, double outlineWidth, double widthScaleFactor, double rasterScaleFactor, bool &fitsInCache)
Get SVG as QImage.
void drawRect(const QRectF &rectangle)
Perform transforms between map coordinates and device coordinates.
Definition: qgsmaptopixel.h:34
void setPixelSize(int pixelSize)
static QString symbolPathToName(QString path)
Get symbols&#39;s name from its path.
QColor color() const
void clear()
Mixed units in symbol layers.
Definition: qgssymbolv2.h:66
QTransform & translate(qreal dx, qreal dy)
The output shall be in millimeters.
Definition: qgssymbolv2.h:64
void setMapUnitScale(const QgsMapUnitScale &scale) override
QString number(int n, int base)
void setOutlineWidthUnit(QgsSymbolV2::OutputUnit u)
void markerOffset(QgsSymbolV2RenderContext &context, double &offsetX, double &offsetY) const
qreal x() const
qreal y() const
const QgsFeature * feature() const
Current feature being rendered - may be null.
Definition: qgssymbolv2.h:374
QTransform & scale(qreal sx, qreal sy)
QRectF bounds(QPointF point, QgsSymbolV2RenderContext &context) override
Returns the approximate bounding box of the marker symbol layer, taking into account any data defined...
void fill(uint pixelValue)
static QString encodePoint(QPointF point)
static double convertToPainterUnits(const QgsRenderContext &c, double size, QgsSymbolV2::OutputUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale())
Converts a size from the specied units to painter units.
QgsStringMap properties() const override
Should be reimplemented by subclasses to return a string map that contains the configuration informat...
void setPath(const QString &path)
void setPen(const QColor &color)
int width() const
void lineTo(const QPointF &endPoint)
#define DEFAULT_SCALE_METHOD
void setOutputUnit(QgsSymbolV2::OutputUnit unit) override
QMatrix & translate(qreal dx, qreal dy)
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.
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)
bool prepareShape(const QString &name=QString())
QgsSymbolV2::ScaleMethod mScaleMethod
static QString symbolNameToPath(QString name)
Get symbol&#39;s path from its name.
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const
bool forceVectorOutput() const
void setLayer(const QString &layer)
void setSizeUnit(QgsSymbolV2::OutputUnit unit)
static bool externalMarkerFromSld(QDomElement &element, QString &path, QString &format, int &markIndex, QColor &color, double &size)
QPaintDevice * device() const
QgsMapUnitScale mapUnitScale() const override
void setWidthF(qreal width)
QgsStringMap properties() const override
Should be reimplemented by subclasses to return a string map that contains the configuration informat...
void stopRender(QgsSymbolV2RenderContext &context) override
void setBrush(const QBrush &brush)
double rasterScaleFactor() const
Q_DECL_DEPRECATED void writeFilledCircle(const QString &layer, const QColor &color, const QgsPoint &pt, double radius)
Write filled circle (as hatch)
#define DEFAULT_FONTMARKER_ANGLE
QgsSymbolV2::OutputUnit outputUnit() const override
static const QString EXPR_FILL
virtual QColor color() const
The fill color.
const QByteArray & svgContent(const QString &file, double size, const QColor &fill, const QColor &outline, double outlineWidth, double widthScaleFactor, double rasterScaleFactor)
Get SVG content.
static QgsSymbolLayerV2 * createFromSld(QDomElement &element)
HorizontalAnchorPoint mHorizontalAnchorPoint
ushort unicode() const
QgsSvgMarkerSymbolLayerV2 * clone() const override
Shall be reimplemented by subclasses to create a deep copy of the instance.
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.
void renderPoint(QPointF point, QgsSymbolV2RenderContext &context) override
void setOutlineWidthMapUnitScale(const QgsMapUnitScale &scale)
static Qt::PenStyle decodePenStyle(const QString &str)
QgsSymbolV2::ScaleMethod scaleMethod() const
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
QgsSymbolV2::OutputUnit mOutlineWidthUnit
#define DEFAULT_SVGMARKER_SIZE
double ANALYSIS_EXPORT angle(Point3D *p1, Point3D *p2, Point3D *p3, Point3D *p4)
Calculates the angle between two segments (in 2 dimension, z-values are ignored)
void setOutlineWidth(double width)
Set outline width.
static const QString EXPR_COLOR
static const QString EXPR_ANGLE
QRect mapRect(const QRect &rectangle) const
int width(const QString &text, int len) const
void setOutlineWidthMapUnitScale(const QgsMapUnitScale &scale)
QgsMapUnitScale mapUnitScale() const override
void startRender(QgsSymbolV2RenderContext &context) override
#define DEFAULT_FONTMARKER_SIZE
bool isNull() const
void restore()
void startRender(QgsSymbolV2RenderContext &context) override
static const QString EXPR_OUTLINE_WIDTH
QTransform & rotate(qreal angle, Qt::Axis axis)
#define DEFAULT_FONTMARKER_FONT
#define DEFAULT_SVGMARKER_NAME
QMatrix & rotate(qreal degrees)
#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)
void drawImage(const QRectF &target, const QImage &image, const QRectF &source, QFlags< Qt::ImageConversionFlag > flags)
QPainter * painter()
QString mid(int position, int n) const
void drawPath(const QPainterPath &path)
static double lineWidthScaleFactor(const QgsRenderContext &c, QgsSymbolV2::OutputUnit u, const QgsMapUnitScale &scale=QgsMapUnitScale())
Returns the line width scale factor depending on the unit and the paint device.
Qt::PenJoinStyle penJoinStyle() const
Get outline join style.
static QgsSymbolLayerV2 * create(const QgsStringMap &properties=QgsStringMap())
void setOutputUnit(QgsSymbolV2::OutputUnit unit) override
ScaleMethod
Scale method.
Definition: qgssymbolv2.h:87
Struct for storing maximum and minimum scales for measurements in map units.
QgsMapUnitScale mapUnitScale() const override
#define DEFAULT_FONTMARKER_BORDERCOLOR
Qt::PenStyle outlineStyle() const
Get outline join style.
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
static QString encodeScaleMethod(QgsSymbolV2::ScaleMethod scaleMethod)
QgsRenderContext & renderContext()
Definition: qgssymbolv2.h:345
QgsSimpleMarkerSymbolLayerV2(const QString &name=DEFAULT_SIMPLEMARKER_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.
QDomElement firstChildElement(const QString &tagName) const
bool preparePath(QString name=QString())
int height() const
int count(const T &value) const
static const QString EXPR_COLOR_BORDER
const QgsGeometry * constGeometry() const
Gets a const pointer to the geometry object associated with this feature.
Definition: qgsfeature.cpp:82
Q_DECL_DEPRECATED void writePolygon(const QgsPolygon &polygon, const QString &layer, const QString &hatchPattern, const QColor &color)
Draw dxf filled polygon (HATCH)
qreal widthF() const
void translate(const QPointF &offset)
const QgsMapToPixel & mapToPixel() const
QColor fillColor() const override
Get fill color.
QgsSymbolV2::OutputUnit mOffsetUnit
double outlineWidth() const
Get outline width.
void setAlphaF(qreal alpha)
virtual void setColor(const QColor &color)
The fill color.
void startRender(QgsSymbolV2RenderContext &context) override
static bool rotationFromSldElement(QDomElement &element, QString &rotationFunc)
bool selected() const
Definition: qgssymbolv2.h:366
int height() const
double toDouble(bool *ok) const
static QColor decodeColor(const QString &str)
void startRender(QgsSymbolV2RenderContext &context) override
VerticalAnchorPoint mVerticalAnchorPoint
QgsSymbolV2::OutputUnit mSizeUnit
void setOutlineWidthUnit(QgsSymbolV2::OutputUnit unit)
Set outline width unit.
Calculate scale by the area.
Definition: qgssymbolv2.h:89
QgsMapUnitScale mOffsetMapUnitScale
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...
void restoreDataDefinedProperties(const QgsStringMap &stringMap)
Restores all data defined properties from string map.
static QgsMapUnitScale decodeMapUnitScale(const QString &str)
int height() const
QDomElement createElement(const QString &tagName)
qreal height() const
#define DEFAULT_SIMPLEMARKER_JOINSTYLE
void map(int x, int y, int *tx, int *ty) const
int size() const
void setAngle(double angle)
bool begin(QPaintDevice *device)
QPointF offset() const
static QgsSymbolLayerV2 * createFromSld(QDomElement &element)
void arcTo(const QRectF &rectangle, qreal startAngle, qreal sweepLength)
void setColor(const QColor &color)
QgsFontMarkerSymbolLayerV2 * clone() const override
Shall be reimplemented by subclasses to create a deep copy of the instance.
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
QString toString() const
void saveDataDefinedProperties(QgsStringMap &stringMap) const
Saves all data defined properties to a string map.
void setSizeMapUnitScale(const QgsMapUnitScale &scale)
QColor outlineColor() const override
Get outline color.
QgsSimpleMarkerSymbolLayerV2 * clone() const override
Shall be reimplemented by subclasses to create a deep copy of the instance.
void setOutputUnit(QgsSymbolV2::OutputUnit unit) override
qreal width() const
QColor outlineColor() const override
Get outline color.
bool prepareCache(QgsSymbolV2RenderContext &context)
Prepares cache image.
void copyDataDefinedProperties(QgsSymbolLayerV2 *destLayer) const
Copies all data defined properties of this layer to another symbol layer.
QMatrix & scale(qreal sx, qreal sy)
void setOutputSize(const QRectF &r)
const T value(const Key &key) const
static Q_DECL_DEPRECATED void wellKnownMarkerToSld(QDomDocument &doc, QDomElement &element, const QString &name, const QColor &color, const QColor &borderColor=QColor(), double borderWidth=-1, double size=-1)
virtual Q_DECL_DEPRECATED QVariant evaluateDataDefinedProperty(const QString &property, const QgsFeature *feature, const QVariant &defaultVal=QVariant(), bool *ok=nullptr) const
Evaluates the matching data defined property and returns the calculated value.
#define DEFAULT_SIMPLEMARKER_BORDERCOLOR
void setOutlineColor(const QColor &color) override
Set outline color.