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