QGIS API Documentation  2.7.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
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 
26 #include <QPainter>
27 #include <QSvgRenderer>
28 #include <QFileInfo>
29 #include <QDir>
30 #include <QDomDocument>
31 #include <QDomElement>
32 
33 #include <cmath>
34 
35 Q_GUI_EXPORT extern int qt_defaultDpiX();
36 Q_GUI_EXPORT extern int qt_defaultDpiY();
37 
38 static void _fixQPictureDPI( QPainter* p )
39 {
40  // QPicture makes an assumption that we drawing to it with system DPI.
41  // Then when being drawn, it scales the painter. The following call
42  // negates the effect. There is no way of setting QPicture's DPI.
43  // See QTBUG-20361
44  p->scale(( double )qt_defaultDpiX() / p->device()->logicalDpiX(),
45  ( double )qt_defaultDpiY() / p->device()->logicalDpiY() );
46 }
47 
48 const QString QgsSimpleMarkerSymbolLayerV2::EXPR_SIZE( "size" );
49 
51 
52 QgsSimpleMarkerSymbolLayerV2::QgsSimpleMarkerSymbolLayerV2( QString name, QColor color, QColor borderColor, double size, double angle, QgsSymbolV2::ScaleMethod scaleMethod )
53  : mOutlineStyle( Qt::SolidLine ), mOutlineWidth( 0 ), mOutlineWidthUnit( QgsSymbolV2::MM )
54 {
55  mName = name;
56  mColor = color;
58  mSize = size;
59  mAngle = angle;
60  mOffset = QPointF( 0, 0 );
64  mAngleExpression = NULL;
65  mNameExpression = NULL;
66 }
67 
69 {
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( "size" ) )
95  size = props["size"].toDouble();
96  if ( props.contains( "angle" ) )
97  angle = props["angle"].toDouble();
98  if ( props.contains( "scale_method" ) )
99  scaleMethod = QgsSymbolLayerV2Utils::decodeScaleMethod( props["scale_method"] );
100 
101  QgsSimpleMarkerSymbolLayerV2* m = new QgsSimpleMarkerSymbolLayerV2( name, color, borderColor, size, angle, scaleMethod );
102  if ( props.contains( "offset" ) )
103  m->setOffset( QgsSymbolLayerV2Utils::decodePoint( props["offset"] ) );
104  if ( props.contains( "offset_unit" ) )
105  m->setOffsetUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["offset_unit"] ) );
106  if ( props.contains( "offset_map_unit_scale" ) )
107  m->setOffsetMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["offset_map_unit_scale"] ) );
108  if ( props.contains( "size_unit" ) )
109  m->setSizeUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["size_unit"] ) );
110  if ( props.contains( "size_map_unit_scale" ) )
111  m->setSizeMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["size_map_unit_scale"] ) );
112 
113  if ( props.contains( "outline_style" ) )
114  {
115  m->setOutlineStyle( QgsSymbolLayerV2Utils::decodePenStyle( props["outline_style"] ) );
116  }
117  else if ( props.contains( "line_style" ) )
118  {
119  m->setOutlineStyle( QgsSymbolLayerV2Utils::decodePenStyle( props["line_style"] ) );
120  }
121  if ( props.contains( "outline_width" ) )
122  {
123  m->setOutlineWidth( props["outline_width"].toDouble() );
124  }
125  else if ( props.contains( "line_width" ) )
126  {
127  m->setOutlineWidth( props["line_width"].toDouble() );
128  }
129  if ( props.contains( "outline_width_unit" ) )
130  {
131  m->setOutlineWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["outline_width_unit"] ) );
132  }
133  if ( props.contains( "line_width_unit" ) )
134  {
135  m->setOutlineWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["line_width_unit"] ) );
136  }
137  if ( props.contains( "outline_width_map_unit_scale" ) )
138  {
139  m->setOutlineWidthMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["outline_width_map_unit_scale"] ) );
140  }
141 
142  if ( props.contains( "horizontal_anchor_point" ) )
143  {
144  m->setHorizontalAnchorPoint( QgsMarkerSymbolLayerV2::HorizontalAnchorPoint( props[ "horizontal_anchor_point" ].toInt() ) );
145  }
146  if ( props.contains( "vertical_anchor_point" ) )
147  {
148  m->setVerticalAnchorPoint( QgsMarkerSymbolLayerV2::VerticalAnchorPoint( props[ "vertical_anchor_point" ].toInt() ) );
149  }
150 
151  //data defined properties
152  if ( props.contains( "name_expression" ) )
153  {
154  m->setDataDefinedProperty( "name", props["name_expression"] );
155  }
156  if ( props.contains( "color_expression" ) )
157  {
158  m->setDataDefinedProperty( "color", props["color_expression"] );
159  }
160  if ( props.contains( "color_border_expression" ) )
161  {
162  m->setDataDefinedProperty( "color_border", props["color_border_expression"] );
163  }
164  if ( props.contains( "outline_style_expression" ) )
165  {
166  m->setDataDefinedProperty( "outline_style", props["outline_style_expression"] );
167  }
168  if ( props.contains( "outline_width_expression" ) )
169  {
170  m->setDataDefinedProperty( "outline_width", props["outline_width_expression"] );
171  }
172  if ( props.contains( "size_expression" ) )
173  {
174  m->setDataDefinedProperty( "size", props["size_expression"] );
175  }
176  if ( props.contains( "angle_expression" ) )
177  {
178  m->setDataDefinedProperty( "angle", props["angle_expression"] );
179  }
180  if ( props.contains( "offset_expression" ) )
181  {
182  m->setDataDefinedProperty( "offset", props["offset_expression"] );
183  }
184  if ( props.contains( "horizontal_anchor_point_expression" ) )
185  {
186  m->setDataDefinedProperty( "horizontal_anchor_point", props[ "horizontal_anchor_point_expression" ] );
187  }
188  if ( props.contains( "vertical_anchor_point_expression" ) )
189  {
190  m->setDataDefinedProperty( "vertical_anchor_point", props[ "vertical_anchor_point_expression" ] );
191  }
192  return m;
193 }
194 
195 
197 {
198  return "SimpleMarker";
199 }
200 
202 {
203  QColor brushColor = mColor;
204  QColor penColor = mBorderColor;
205 
206  brushColor.setAlphaF( mColor.alphaF() * context.alpha() );
207  penColor.setAlphaF( mBorderColor.alphaF() * context.alpha() );
208 
209  mBrush = QBrush( brushColor );
210  mPen = QPen( penColor );
211  mPen.setStyle( mOutlineStyle );
213 
214  QColor selBrushColor = context.renderContext().selectionColor();
215  QColor selPenColor = selBrushColor == mColor ? selBrushColor : mBorderColor;
216  if ( context.alpha() < 1 )
217  {
218  selBrushColor.setAlphaF( context.alpha() );
219  selPenColor.setAlphaF( context.alpha() );
220  }
221  mSelBrush = QBrush( selBrushColor );
222  mSelPen = QPen( selPenColor );
223  mSelPen.setStyle( mOutlineStyle );
225 
226  bool hasDataDefinedRotation = context.renderHints() & QgsSymbolV2::DataDefinedRotation || dataDefinedProperty( "angle" );
227  bool hasDataDefinedSize = context.renderHints() & QgsSymbolV2::DataDefinedSizeScale || dataDefinedProperty( "size" );
228 
229  // use caching only when:
230  // - size, rotation, shape, color, border color is not data-defined
231  // - drawing to screen (not printer)
232  mUsingCache = !hasDataDefinedRotation && !hasDataDefinedSize && !context.renderContext().forceVectorOutput()
233  && !dataDefinedProperty( "name" ) && !dataDefinedProperty( "color" ) && !dataDefinedProperty( "color_border" )
234  && !dataDefinedProperty( "outline_width" ) && !dataDefinedProperty( "outline_style" ) &&
235  !dataDefinedProperty( "size" );
236 
237  // use either QPolygonF or QPainterPath for drawing
238  // TODO: find out whether drawing directly doesn't bring overhead - if not, use it for all shapes
239  if ( !prepareShape() ) // drawing as a polygon
240  {
241  if ( preparePath() ) // drawing as a painter path
242  {
243  // some markers can't be drawn as a polygon (circle, cross)
244  // For these set the selected border color to the selected color
245 
246  if ( mName != "circle" )
247  mSelPen.setColor( selBrushColor );
248  }
249  else
250  {
251  QgsDebugMsg( "unknown symbol" );
252  return;
253  }
254  }
255 
256  QMatrix transform;
257 
258  // scale the shape (if the size is not going to be modified)
259  if ( !hasDataDefinedSize )
260  {
262  if ( mUsingCache )
263  scaledSize *= context.renderContext().rasterScaleFactor();
264  double half = scaledSize / 2.0;
265  transform.scale( half, half );
266  }
267 
268  // rotate if the rotation is not going to be changed during the rendering
269  if ( !hasDataDefinedRotation && mAngle != 0 )
270  {
271  transform.rotate( mAngle );
272  }
273 
274  if ( !mPolygon.isEmpty() )
275  mPolygon = transform.map( mPolygon );
276  else
277  mPath = transform.map( mPath );
278 
279  if ( mUsingCache )
280  {
281  if ( !prepareCache( context ) )
282  {
283  mUsingCache = false;
284  }
285  }
286  else
287  {
288  mCache = QImage();
289  mSelCache = QImage();
290  }
291 
292  prepareExpressions( context.fields(), context.renderContext().rendererScale() );
293  mAngleExpression = expression( "angle" );
294  mNameExpression = expression( "name" );
295 
297 }
298 
299 
301 {
303 
304  // calculate necessary image size for the cache
305  double pw = (( mPen.widthF() == 0 ? 1 : mPen.widthF() ) + 1 ) / 2 * 2; // make even (round up); handle cosmetic pen
306  int imageSize = (( int ) scaledSize + pw ) / 2 * 2 + 1; // make image width, height odd; account for pen width
307  double center = imageSize / 2.0;
308 
309  if ( imageSize > mMaximumCacheWidth )
310  {
311  return false;
312  }
313 
314  mCache = QImage( QSize( imageSize, imageSize ), QImage::Format_ARGB32_Premultiplied );
315  mCache.fill( 0 );
316 
317  QPainter p;
318  p.begin( &mCache );
319  p.setRenderHint( QPainter::Antialiasing );
320  p.setBrush( mBrush );
321  p.setPen( mPen );
322  p.translate( QPointF( center, center ) );
323  drawMarker( &p, context );
324  p.end();
325 
326  // Construct the selected version of the Cache
327 
328  QColor selColor = context.renderContext().selectionColor();
329 
330  mSelCache = QImage( QSize( imageSize, imageSize ), QImage::Format_ARGB32_Premultiplied );
331  mSelCache.fill( 0 );
332 
333  p.begin( &mSelCache );
334  p.setRenderHint( QPainter::Antialiasing );
335  p.setBrush( mSelBrush );
336  p.setPen( mSelPen );
337  p.translate( QPointF( center, center ) );
338  drawMarker( &p, context );
339  p.end();
340 
341  // Check that the selected version is different. If not, then re-render,
342  // filling the background with the selection color and using the normal
343  // colors for the symbol .. could be ugly!
344 
345  if ( mSelCache == mCache )
346  {
347  p.begin( &mSelCache );
348  p.setRenderHint( QPainter::Antialiasing );
349  p.fillRect( 0, 0, imageSize, imageSize, selColor );
350  p.setBrush( mBrush );
351  p.setPen( mPen );
352  p.translate( QPointF( center, center ) );
353  drawMarker( &p, context );
354  p.end();
355  }
356 
357  return true;
358 }
359 
361 {
362  Q_UNUSED( context );
363 }
364 
366 {
367  mPolygon.clear();
368 
369  if ( name.isNull() )
370  {
371  name = mName;
372  }
373 
374  if ( name == "square" || name == "rectangle" )
375  {
376  mPolygon = QPolygonF( QRectF( QPointF( -1, -1 ), QPointF( 1, 1 ) ) );
377  return true;
378  }
379  else if ( name == "diamond" )
380  {
381  mPolygon << QPointF( -1, 0 ) << QPointF( 0, 1 )
382  << QPointF( 1, 0 ) << QPointF( 0, -1 );
383  return true;
384  }
385  else if ( name == "pentagon" )
386  {
387  mPolygon << QPointF( sin( DEG2RAD( 288.0 ) ), - cos( DEG2RAD( 288.0 ) ) )
388  << QPointF( sin( DEG2RAD( 216.0 ) ), - cos( DEG2RAD( 216.0 ) ) )
389  << QPointF( sin( DEG2RAD( 144.0 ) ), - cos( DEG2RAD( 144.0 ) ) )
390  << QPointF( sin( DEG2RAD( 72.0 ) ), - cos( DEG2RAD( 72.0 ) ) )
391  << QPointF( 0, -1 );
392  return true;
393  }
394  else if ( name == "triangle" )
395  {
396  mPolygon << QPointF( -1, 1 ) << QPointF( 1, 1 ) << QPointF( 0, -1 );
397  return true;
398  }
399  else if ( name == "equilateral_triangle" )
400  {
401  mPolygon << QPointF( sin( DEG2RAD( 240.0 ) ), - cos( DEG2RAD( 240.0 ) ) )
402  << QPointF( sin( DEG2RAD( 120.0 ) ), - cos( DEG2RAD( 120.0 ) ) )
403  << QPointF( 0, -1 );
404  return true;
405  }
406  else if ( name == "star" )
407  {
408  double sixth = 1.0 / 3;
409 
410  mPolygon << QPointF( 0, -1 )
411  << QPointF( -sixth, -sixth )
412  << QPointF( -1, -sixth )
413  << QPointF( -sixth, 0 )
414  << QPointF( -1, 1 )
415  << QPointF( 0, + sixth )
416  << QPointF( 1, 1 )
417  << QPointF( + sixth, 0 )
418  << QPointF( 1, -sixth )
419  << QPointF( + sixth, -sixth );
420  return true;
421  }
422  else if ( name == "regular_star" )
423  {
424  double inner_r = cos( DEG2RAD( 72.0 ) ) / cos( DEG2RAD( 36.0 ) );
425 
426  mPolygon << QPointF( inner_r * sin( DEG2RAD( 324.0 ) ), - inner_r * cos( DEG2RAD( 324.0 ) ) ) // 324
427  << QPointF( sin( DEG2RAD( 288.0 ) ), - cos( DEG2RAD( 288 ) ) ) // 288
428  << QPointF( inner_r * sin( DEG2RAD( 252.0 ) ), - inner_r * cos( DEG2RAD( 252.0 ) ) ) // 252
429  << QPointF( sin( DEG2RAD( 216.0 ) ), - cos( DEG2RAD( 216.0 ) ) ) // 216
430  << QPointF( 0, inner_r ) // 180
431  << QPointF( sin( DEG2RAD( 144.0 ) ), - cos( DEG2RAD( 144.0 ) ) ) // 144
432  << QPointF( inner_r * sin( DEG2RAD( 108.0 ) ), - inner_r * cos( DEG2RAD( 108.0 ) ) ) // 108
433  << QPointF( sin( DEG2RAD( 72.0 ) ), - cos( DEG2RAD( 72.0 ) ) ) // 72
434  << QPointF( inner_r * sin( DEG2RAD( 36.0 ) ), - inner_r * cos( DEG2RAD( 36.0 ) ) ) // 36
435  << QPointF( 0, -1 ); // 0
436  return true;
437  }
438  else if ( name == "arrow" )
439  {
440  mPolygon
441  << QPointF( 0, -1 )
442  << QPointF( 0.5, -0.5 )
443  << QPointF( 0.25, -0.5 )
444  << QPointF( 0.25, 1 )
445  << QPointF( -0.25, 1 )
446  << QPointF( -0.25, -0.5 )
447  << QPointF( -0.5, -0.5 );
448  return true;
449  }
450  else if ( name == "filled_arrowhead" )
451  {
452  mPolygon << QPointF( 0, 0 ) << QPointF( -1, 1 ) << QPointF( -1, -1 );
453  return true;
454  }
455 
456  return false;
457 }
458 
460 {
461  mPath = QPainterPath();
462  if ( name.isNull() )
463  {
464  name = mName;
465  }
466 
467  if ( name == "circle" )
468  {
469  mPath.addEllipse( QRectF( -1, -1, 2, 2 ) ); // x,y,w,h
470  return true;
471  }
472  else if ( name == "cross" )
473  {
474  mPath.moveTo( -1, 0 );
475  mPath.lineTo( 1, 0 ); // horizontal
476  mPath.moveTo( 0, -1 );
477  mPath.lineTo( 0, 1 ); // vertical
478  return true;
479  }
480  else if ( name == "x" || name == "cross2" )
481  {
482  mPath.moveTo( -1, -1 );
483  mPath.lineTo( 1, 1 );
484  mPath.moveTo( 1, -1 );
485  mPath.lineTo( -1, 1 );
486  return true;
487  }
488  else if ( name == "line" )
489  {
490  mPath.moveTo( 0, -1 );
491  mPath.lineTo( 0, 1 ); // vertical line
492  return true;
493  }
494  else if ( name == "arrowhead" )
495  {
496  mPath.moveTo( 0, 0 );
497  mPath.lineTo( -1, -1 );
498  mPath.moveTo( 0, 0 );
499  mPath.lineTo( -1, 1 );
500  return true;
501  }
502 
503  return false;
504 }
505 
507 {
508  QPainter *p = context.renderContext().painter();
509  if ( !p )
510  {
511  return;
512  }
513 
514  QgsExpression *sizeExpression = expression( EXPR_SIZE );
515  bool hasDataDefinedSize = context.renderHints() & QgsSymbolV2::DataDefinedSizeScale || sizeExpression;
516 
517  double scaledSize = mSize;
518  if ( hasDataDefinedSize )
519  {
520  if ( sizeExpression )
521  {
522  scaledSize = sizeExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
523  }
524 
526  {
527  scaledSize = sqrt( scaledSize );
528  }
529  }
530 
531  //offset
532  double offsetX = 0;
533  double offsetY = 0;
534  markerOffset( context, scaledSize, scaledSize, offsetX, offsetY );
535  QPointF off( offsetX, offsetY );
536 
537  //angle
538  double angle = mAngle;
539  if ( mAngleExpression )
540  {
541  angle = mAngleExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
542  }
543  if ( angle )
544  off = _rotatedOffset( off, angle );
545 
546  //data defined shape?
547  bool createdNewPath = false;
548  if ( mNameExpression )
549  {
550  QString name = mNameExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString();
551  if ( !prepareShape( name ) ) // drawing as a polygon
552  {
553  preparePath( name ); // drawing as a painter path
554  }
555  createdNewPath = true;
556  }
557 
558  if ( mUsingCache )
559  {
560  // we will use cached image
561  QImage &img = context.selected() ? mSelCache : mCache;
562  double s = img.width() / context.renderContext().rasterScaleFactor();
563  p->drawImage( QRectF( point.x() - s / 2.0 + off.x(),
564  point.y() - s / 2.0 + off.y(),
565  s, s ), img );
566  }
567  else
568  {
569  QMatrix transform;
570 
571  // move to the desired position
572  transform.translate( point.x() + off.x(), point.y() + off.y() );
573 
574  // resize if necessary
575  if ( hasDataDefinedSize || createdNewPath )
576  {
578  double half = s / 2.0;
579  transform.scale( half, half );
580  }
581 
582  bool hasDataDefinedRotation = context.renderHints() & QgsSymbolV2::DataDefinedRotation || mAngleExpression;
583  if ( angle != 0 && ( hasDataDefinedRotation || createdNewPath ) )
584  transform.rotate( angle );
585 
586  QgsExpression* colorExpression = expression( "color" );
587  QgsExpression* colorBorderExpression = expression( "color_border" );
588  QgsExpression* outlineWidthExpression = expression( "outline_width" );
589  QgsExpression* outlineStyleExpression = expression( "outline_style" );
590  if ( colorExpression )
591  {
592  mBrush.setColor( QgsSymbolLayerV2Utils::decodeColor( colorExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString() ) );
593  }
594  if ( colorBorderExpression )
595  {
596  mPen.setColor( QgsSymbolLayerV2Utils::decodeColor( colorBorderExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString() ) );
597  mSelPen.setColor( QgsSymbolLayerV2Utils::decodeColor( colorBorderExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString() ) );
598  }
599  if ( outlineWidthExpression )
600  {
601  double outlineWidth = outlineWidthExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
604  }
605  if ( outlineStyleExpression )
606  {
607  QString outlineStyle = outlineStyleExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString();
608  mPen.setStyle( QgsSymbolLayerV2Utils::decodePenStyle( outlineStyle ) );
609  mSelPen.setStyle( QgsSymbolLayerV2Utils::decodePenStyle( outlineStyle ) );
610  }
611 
612  p->setBrush( context.selected() ? mSelBrush : mBrush );
613  p->setPen( context.selected() ? mSelPen : mPen );
614 
615  if ( !mPolygon.isEmpty() )
616  p->drawPolygon( transform.map( mPolygon ) );
617  else
618  p->drawPath( transform.map( mPath ) );
619  }
620 }
621 
622 
624 {
625  QgsStringMap map;
626  map["name"] = mName;
627  map["color"] = QgsSymbolLayerV2Utils::encodeColor( mColor );
628  map["outline_color"] = QgsSymbolLayerV2Utils::encodeColor( mBorderColor );
629  map["size"] = QString::number( mSize );
631  map["size_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mSizeMapUnitScale );
632  map["angle"] = QString::number( mAngle );
633  map["offset"] = QgsSymbolLayerV2Utils::encodePoint( mOffset );
635  map["offset_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOffsetMapUnitScale );
637  map["outline_style"] = QgsSymbolLayerV2Utils::encodePenStyle( mOutlineStyle );
638  map["outline_width"] = QString::number( mOutlineWidth );
639  map["outline_width_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOutlineWidthUnit );
640  map["outline_width_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOutlineWidthMapUnitScale );
641  map["horizontal_anchor_point"] = QString::number( mHorizontalAnchorPoint );
642  map["vertical_anchor_point"] = QString::number( mVerticalAnchorPoint );
643 
644 
645  //data define properties
647  return map;
648 }
649 
651 {
653  m->setOffset( mOffset );
654  m->setSizeUnit( mSizeUnit );
665  return m;
666 }
667 
668 void QgsSimpleMarkerSymbolLayerV2::writeSldMarker( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
669 {
670  // <Graphic>
671  QDomElement graphicElem = doc.createElement( "se:Graphic" );
672  element.appendChild( graphicElem );
673 
675 
676  // <Rotation>
677  QString angleFunc;
678  bool ok;
679  double angle = props.value( "angle", "0" ).toDouble( &ok );
680  if ( !ok )
681  {
682  angleFunc = QString( "%1 + %2" ).arg( props.value( "angle", "0" ) ).arg( mAngle );
683  }
684  else if ( angle + mAngle != 0 )
685  {
686  angleFunc = QString::number( angle + mAngle );
687  }
688  QgsSymbolLayerV2Utils::createRotationElement( doc, graphicElem, angleFunc );
689 
690  // <Displacement>
692 }
693 
694 QString QgsSimpleMarkerSymbolLayerV2::ogrFeatureStyle( double mmScaleFactor, double mapUnitScaleFactor ) const
695 {
696  Q_UNUSED( mmScaleFactor );
697  Q_UNUSED( mapUnitScaleFactor );
698 #if 0
699  QString ogrType = "3"; //default is circle
700  if ( mName == "square" )
701  {
702  ogrType = "5";
703  }
704  else if ( mName == "triangle" )
705  {
706  ogrType = "7";
707  }
708  else if ( mName == "star" )
709  {
710  ogrType = "9";
711  }
712  else if ( mName == "circle" )
713  {
714  ogrType = "3";
715  }
716  else if ( mName == "cross" )
717  {
718  ogrType = "0";
719  }
720  else if ( mName == "x" || mName == "cross2" )
721  {
722  ogrType = "1";
723  }
724  else if ( mName == "line" )
725  {
726  ogrType = "10";
727  }
728 
729  QString ogrString;
730  ogrString.append( "SYMBOL(" );
731  ogrString.append( "id:" );
732  ogrString.append( "\"" );
733  ogrString.append( "ogr-sym-" );
734  ogrString.append( ogrType );
735  ogrString.append( "\"" );
736  ogrString.append( ",c:" );
737  ogrString.append( mColor.name() );
738  ogrString.append( ",o:" );
739  ogrString.append( mBorderColor.name() );
740  ogrString.append( QString( ",s:%1mm" ).arg( mSize ) );
741  ogrString.append( ")" );
742  return ogrString;
743 #endif //0
744 
745  QString ogrString;
746  ogrString.append( "PEN(" );
747  ogrString.append( "c:" );
748  ogrString.append( mColor.name() );
749  ogrString.append( ",w:" );
750  ogrString.append( QString::number( mSize ) );
751  ogrString.append( "mm" );
752  ogrString.append( ")" );
753  return ogrString;
754 }
755 
757 {
758  QgsDebugMsg( "Entered." );
759 
760  QDomElement graphicElem = element.firstChildElement( "Graphic" );
761  if ( graphicElem.isNull() )
762  return NULL;
763 
764  QString name = "square";
765  QColor color, borderColor;
766  double borderWidth, size;
767  Qt::PenStyle borderStyle;
768 
769  if ( !QgsSymbolLayerV2Utils::wellKnownMarkerFromSld( graphicElem, name, color, borderColor, borderStyle, borderWidth, size ) )
770  return NULL;
771 
772  double angle = 0.0;
773  QString angleFunc;
774  if ( QgsSymbolLayerV2Utils::rotationFromSldElement( graphicElem, angleFunc ) )
775  {
776  bool ok;
777  double d = angleFunc.toDouble( &ok );
778  if ( ok )
779  angle = d;
780  }
781 
782  QPointF offset;
784 
785  QgsSimpleMarkerSymbolLayerV2 *m = new QgsSimpleMarkerSymbolLayerV2( name, color, borderColor, size );
786  m->setAngle( angle );
787  m->setOffset( offset );
788  m->setOutlineStyle( borderStyle );
789  return m;
790 }
791 
793 {
794  Q_UNUSED( context );
795 
796  if ( mPolygon.count() != 0 )
797  {
798  p->drawPolygon( mPolygon );
799  }
800  else
801  {
802  p->drawPath( mPath );
803  }
804 }
805 
806 bool QgsSimpleMarkerSymbolLayerV2::writeDxf( QgsDxfExport& e, double mmMapUnitScaleFactor, const QString& layerName, const QgsSymbolV2RenderContext* context, const QgsFeature* f, const QPointF& shift ) const
807 {
808  //data defined size?
809  double size = mSize;
810 
811  QgsExpression *sizeExpression = expression( "size" );
812  bool hasDataDefinedSize = false;
813  if ( context )
814  {
815  hasDataDefinedSize = context->renderHints() & QgsSymbolV2::DataDefinedSizeScale || sizeExpression;
816  }
817 
818  //data defined size
819  if ( hasDataDefinedSize )
820  {
821  if ( sizeExpression )
822  {
823  size = sizeExpression->evaluate( const_cast<QgsFeature*>( context->feature() ) ).toDouble();
824  }
825 
826  switch ( mScaleMethod )
827  {
829  size = sqrt( size );
830  break;
832  break;
833  }
834 
836  }
837  if ( mSizeUnit == QgsSymbolV2::MM )
838  {
839  size *= mmMapUnitScaleFactor;
840  }
841  double halfSize = size / 2.0;
842 
843  //outlineWidth
844  double outlineWidth = mOutlineWidth;
845  QgsExpression* outlineWidthExpression = expression( "outline_width" );
846  if ( outlineWidthExpression )
847  {
848  outlineWidth = outlineWidthExpression->evaluate( const_cast<QgsFeature*>( context->feature() ) ).toDouble();
849  }
850  if ( mSizeUnit == QgsSymbolV2::MM )
851  {
852  outlineWidth *= mmMapUnitScaleFactor;
853  }
854 
855  //color
856  QColor pc = mPen.color();
857  QColor bc = mBrush.color();
858 
859  QgsExpression* colorExpression = expression( "color" );
860  if ( colorExpression )
861  {
862  bc = QgsSymbolLayerV2Utils::decodeColor( colorExpression->evaluate( *f ).toString() );
863  }
864 
865  QgsExpression* outlinecolorExpression = expression( "outline_color" );
866  if ( outlinecolorExpression )
867  {
868  pc = QgsSymbolLayerV2Utils::decodeColor( outlinecolorExpression->evaluate( *f ).toString() );
869  }
870 
871  //offset
872  double offsetX = 0;
873  double offsetY = 0;
874  markerOffset( *context, offsetX, offsetY );
875  QPointF off( offsetX, offsetY );
876 
877  //angle
878  double angle = mAngle;
879  QgsExpression* angleExpression = expression( "angle" );
880  if ( angleExpression )
881  {
882  angle = angleExpression->evaluate( const_cast<QgsFeature*>( context->feature() ) ).toDouble();
883  }
884  angle = -angle; //rotation in Qt is counterclockwise
885  if ( angle )
886  off = _rotatedOffset( off, angle );
887 
888  if ( mSizeUnit == QgsSymbolV2::MM )
889  {
890  off *= mmMapUnitScaleFactor;
891  }
892 
893  QTransform t;
894  t.translate( shift.x() + offsetX, shift.y() + offsetY );
895 
896  if ( angle != 0 )
897  t.rotate( angle );
898 
899  //data defined symbol name
900 
901  if ( mName == "circle" )
902  {
903  if ( mBrush.style() != Qt::NoBrush )
904  e.writeFilledCircle( layerName, bc, shift, halfSize );
905  if ( mPen.style() != Qt::NoPen )
906  e.writeCircle( layerName, pc, shift, halfSize, "CONTINUOUS", outlineWidth );
907  }
908  else if ( mName == "square" || mName == "rectangle" )
909  {
910  // pt1 pt2
911  // pt3 pt4
912  QPointF pt1 = t.map( QPointF( -halfSize, -halfSize ) );
913  QPointF pt2 = t.map( QPointF( halfSize, -halfSize ) );
914  QPointF pt3 = t.map( QPointF( -halfSize, halfSize ) );
915  QPointF pt4 = t.map( QPointF( halfSize, halfSize ) );
916 
917  if ( mBrush.style() != Qt::NoBrush )
918  e.writeSolid( layerName, bc, pt1, pt2, pt3, pt4 );
919 
920  if ( mPen.style() != Qt::NoPen )
921  {
922  e.writeLine( pt1, pt2, layerName, "CONTINUOUS", pc, outlineWidth );
923  e.writeLine( pt2, pt4, layerName, "CONTINUOUS", pc, outlineWidth );
924  e.writeLine( pt4, pt3, layerName, "CONTINUOUS", pc, outlineWidth );
925  e.writeLine( pt3, pt1, layerName, "CONTINUOUS", pc, outlineWidth );
926  }
927  }
928  else if ( mName == "diamond" )
929  {
930  QPointF pt1 = t.map( QPointF( -halfSize, 0 ) );
931  QPointF pt2 = t.map( QPointF( 0, -halfSize ) );
932  QPointF pt3 = t.map( QPointF( 0, halfSize ) );
933  QPointF pt4 = t.map( QPointF( halfSize, 0 ) );
934 
935  if ( mBrush.style() != Qt::NoBrush )
936  e.writeSolid( layerName, bc, pt1, pt2, pt3, pt4 );
937 
938  if ( mPen.style() != Qt::NoPen )
939  {
940  e.writeLine( pt1, pt2, layerName, "CONTINUOUS", pc, outlineWidth );
941  e.writeLine( pt2, pt3, layerName, "CONTINUOUS", pc, outlineWidth );
942  e.writeLine( pt3, pt4, layerName, "CONTINUOUS", pc, outlineWidth );
943  e.writeLine( pt4, pt1, layerName, "CONTINUOUS", pc, outlineWidth );
944  }
945  }
946  else if ( mName == "triangle" )
947  {
948  QPointF pt1 = t.map( QPointF( -halfSize, -halfSize ) );
949  QPointF pt2 = t.map( QPointF( halfSize, -halfSize ) );
950  QPointF pt3 = t.map( QPointF( 0, halfSize ) );
951 
952  if ( mBrush.style() != Qt::NoBrush )
953  e.writeSolid( layerName, bc, pt1, pt2, pt3, pt3 );
954 
955  if ( mPen.style() != Qt::NoPen )
956  {
957  e.writeLine( pt1, pt2, layerName, "CONTINUOUS", pc, outlineWidth );
958  e.writeLine( pt2, pt3, layerName, "CONTINUOUS", pc, outlineWidth );
959  e.writeLine( pt3, pt1, layerName, "CONTINUOUS", pc, outlineWidth );
960  }
961  }
962 #if 0
963  else if ( mName == "equilateral_triangle" )
964  {
965 
966  }
967 #endif
968  else if ( mName == "line" )
969  {
970  QPointF pt1 = t.map( QPointF( 0, halfSize ) );
971  QPointF pt2 = t.map( QPointF( 0, -halfSize ) );
972 
973  if ( mPen.style() != Qt::NoPen )
974  e.writeLine( pt1, pt2, layerName, "CONTINUOUS", pc, outlineWidth );
975  }
976  else if ( mName == "cross" )
977  {
978  QPointF pt1 = t.map( QPointF( -halfSize, 0 ) );
979  QPointF pt2 = t.map( QPointF( halfSize, 0 ) );
980  QPointF pt3 = t.map( QPointF( 0, -halfSize ) );
981  QPointF pt4 = t.map( QPointF( 0, halfSize ) );
982 
983  if ( mPen.style() != Qt::NoPen )
984  {
985  e.writeLine( pt1, pt2, layerName, "CONTINUOUS", pc, outlineWidth );
986  e.writeLine( pt3, pt4, layerName, "CONTINUOUS", pc, outlineWidth );
987  }
988  }
989  else if ( mName == "x" || mName == "cross2" )
990  {
991  QPointF pt1 = t.map( QPointF( -halfSize, -halfSize ) );
992  QPointF pt2 = t.map( QPointF( halfSize, halfSize ) );
993  QPointF pt3 = t.map( QPointF( -halfSize, halfSize ) );
994  QPointF pt4 = t.map( QPointF( halfSize, -halfSize ) );
995 
996  if ( mPen.style() != Qt::NoPen )
997  {
998  e.writeLine( pt1, pt2, layerName, "CONTINUOUS", pc, outlineWidth );
999  e.writeLine( pt3, pt4, layerName, "CONTINUOUS", pc, outlineWidth );
1000  }
1001  }
1002  else if ( mName == "arrowhead" )
1003  {
1004  QPointF pt1 = t.map( QPointF( -halfSize, halfSize ) );
1005  QPointF pt2 = t.map( QPointF( 0, 0 ) );
1006  QPointF pt3 = t.map( QPointF( -halfSize, -halfSize ) );
1007 
1008  if ( mPen.style() != Qt::NoPen )
1009  {
1010  e.writeLine( pt1, pt2, layerName, "CONTINUOUS", pc, outlineWidth );
1011  e.writeLine( pt3, pt2, layerName, "CONTINUOUS", pc, outlineWidth );
1012  }
1013  }
1014  else if ( mName == "filled_arrowhead" )
1015  {
1016  QPointF pt1 = t.map( QPointF( -halfSize, halfSize ) );
1017  QPointF pt2 = t.map( QPointF( 0, 0 ) );
1018  QPointF pt3 = t.map( QPointF( -halfSize, -halfSize ) );
1019 
1020  if ( mBrush.style() != Qt::NoBrush )
1021  {
1022  e.writeSolid( layerName, bc, pt1, pt2, pt3, pt3 );
1023  }
1024  }
1025  else
1026  {
1027  return false;
1028  }
1029 
1030  return true;
1031 }
1032 
1033 
1035 {
1037  mOutlineWidthUnit = unit;
1038 }
1039 
1041 {
1043  {
1044  return mOutlineWidthUnit;
1045  }
1046  return QgsSymbolV2::Mixed;
1047 }
1048 
1050 {
1052  mOutlineWidthMapUnitScale = scale;
1053 }
1054 
1056 {
1058  {
1060  }
1061  return QgsMapUnitScale();
1062 }
1063 
1065 
1066 
1068 {
1070  mSize = size;
1071  mAngle = angle;
1072  mOffset = QPointF( 0, 0 );
1074  mOutlineWidth = 1.0;
1076  mFillColor = QColor( Qt::black );
1077  mOutlineColor = QColor( Qt::black );
1078 }
1079 
1080 
1082 {
1083  QString name = DEFAULT_SVGMARKER_NAME;
1084  double size = DEFAULT_SVGMARKER_SIZE;
1085  double angle = DEFAULT_SVGMARKER_ANGLE;
1087 
1088  if ( props.contains( "name" ) )
1089  name = props["name"];
1090  if ( props.contains( "size" ) )
1091  size = props["size"].toDouble();
1092  if ( props.contains( "angle" ) )
1093  angle = props["angle"].toDouble();
1094  if ( props.contains( "scale_method" ) )
1095  scaleMethod = QgsSymbolLayerV2Utils::decodeScaleMethod( props["scale_method"] );
1096 
1097  QgsSvgMarkerSymbolLayerV2* m = new QgsSvgMarkerSymbolLayerV2( name, size, angle, scaleMethod );
1098 
1099  //we only check the svg default parameters if necessary, since it could be expensive
1100  if ( !props.contains( "fill" ) && !props.contains( "color" ) && !props.contains( "outline" ) &&
1101  !props.contains( "outline_color" ) && !props.contains( "outline-width" ) && !props.contains( "outline_width" ) )
1102  {
1103  QColor fillColor, outlineColor;
1104  double outlineWidth;
1105  bool hasFillParam, hasOutlineParam, hasOutlineWidthParam;
1106  QgsSvgCache::instance()->containsParams( name, hasFillParam, fillColor, hasOutlineParam, outlineColor, hasOutlineWidthParam, outlineWidth );
1107  if ( hasFillParam )
1108  {
1109  m->setFillColor( fillColor );
1110  }
1111  if ( hasOutlineParam )
1112  {
1113  m->setOutlineColor( outlineColor );
1114  }
1115  if ( hasOutlineWidthParam )
1116  {
1117  m->setOutlineWidth( outlineWidth );
1118  }
1119  }
1120 
1121  if ( props.contains( "size_unit" ) )
1122  m->setSizeUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["size_unit"] ) );
1123  if ( props.contains( "size_map_unit_scale" ) )
1124  m->setSizeMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["size_map_unit_scale"] ) );
1125  if ( props.contains( "offset" ) )
1126  m->setOffset( QgsSymbolLayerV2Utils::decodePoint( props["offset"] ) );
1127  if ( props.contains( "offset_unit" ) )
1128  m->setOffsetUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["offset_unit"] ) );
1129  if ( props.contains( "offset_map_unit_scale" ) )
1130  m->setOffsetMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["offset_map_unit_scale"] ) );
1131  if ( props.contains( "fill" ) )
1132  {
1133  //pre 2.5 projects used "fill"
1134  m->setFillColor( QColor( props["fill"] ) );
1135  }
1136  else if ( props.contains( "color" ) )
1137  {
1138  m->setFillColor( QColor( props["color"] ) );
1139  }
1140  if ( props.contains( "outline" ) )
1141  {
1142  //pre 2.5 projects used "outline"
1143  m->setOutlineColor( QColor( props["outline"] ) );
1144  }
1145  else if ( props.contains( "outline_color" ) )
1146  {
1147  m->setOutlineColor( QColor( props["outline_color"] ) );
1148  }
1149  else if ( props.contains( "line_color" ) )
1150  {
1151  m->setOutlineColor( QColor( props["line_color"] ) );
1152  }
1153 
1154  if ( props.contains( "outline-width" ) )
1155  {
1156  //pre 2.5 projects used "outline-width"
1157  m->setOutlineWidth( props["outline-width"].toDouble() );
1158  }
1159  else if ( props.contains( "outline_width" ) )
1160  {
1161  m->setOutlineWidth( props["outline_width"].toDouble() );
1162  }
1163  else if ( props.contains( "line_width" ) )
1164  {
1165  m->setOutlineWidth( props["line_width"].toDouble() );
1166  }
1167 
1168  if ( props.contains( "outline_width_unit" ) )
1169  {
1170  m->setOutlineWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["outline_width_unit"] ) );
1171  }
1172  else if ( props.contains( "line_width_unit" ) )
1173  {
1174  m->setOutlineWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["line_width_unit"] ) );
1175  }
1176  if ( props.contains( "outline_width_map_unit_scale" ) )
1177  m->setOutlineWidthMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["outline_width_map_unit_scale"] ) );
1178 
1179  if ( props.contains( "horizontal_anchor_point" ) )
1180  {
1181  m->setHorizontalAnchorPoint( QgsMarkerSymbolLayerV2::HorizontalAnchorPoint( props[ "horizontal_anchor_point" ].toInt() ) );
1182  }
1183  if ( props.contains( "vertical_anchor_point" ) )
1184  {
1185  m->setVerticalAnchorPoint( QgsMarkerSymbolLayerV2::VerticalAnchorPoint( props[ "vertical_anchor_point" ].toInt() ) );
1186  }
1187 
1188  //data defined properties
1189  if ( props.contains( "size_expression" ) )
1190  {
1191  m->setDataDefinedProperty( "size", props["size_expression"] );
1192  }
1193  if ( props.contains( "outline-width_expression" ) )
1194  {
1195  m->setDataDefinedProperty( "outline-width", props["outline-width_expression"] );
1196  }
1197  if ( props.contains( "angle_expression" ) )
1198  {
1199  m->setDataDefinedProperty( "angle", props["angle_expression"] );
1200  }
1201  if ( props.contains( "offset_expression" ) )
1202  {
1203  m->setDataDefinedProperty( "offset", props["offset_expression"] );
1204  }
1205  if ( props.contains( "name_expression" ) )
1206  {
1207  m->setDataDefinedProperty( "name", props["name_expression"] );
1208  }
1209  if ( props.contains( "fill_expression" ) )
1210  {
1211  m->setDataDefinedProperty( "fill", props["fill_expression"] );
1212  }
1213  if ( props.contains( "outline_expression" ) )
1214  {
1215  m->setDataDefinedProperty( "outline", props["outline_expression"] );
1216  }
1217  if ( props.contains( "horizontal_anchor_point_expression" ) )
1218  {
1219  m->setDataDefinedProperty( "horizontal_anchor_point", props[ "horizontal_anchor_point_expression" ] );
1220  }
1221  if ( props.contains( "vertical_anchor_point_expression" ) )
1222  {
1223  m->setDataDefinedProperty( "vertical_anchor_point", props[ "vertical_anchor_point_expression" ] );
1224  }
1225  return m;
1226 }
1227 
1229 {
1230  mPath = path;
1231  QColor fillColor, outlineColor;
1232  double outlineWidth;
1233  bool hasFillParam, hasOutlineParam, hasOutlineWidthParam;
1234  QgsSvgCache::instance()->containsParams( path, hasFillParam, fillColor, hasOutlineParam, outlineColor, hasOutlineWidthParam, outlineWidth );
1235  if ( hasFillParam )
1236  {
1237  setFillColor( fillColor );
1238  }
1239  if ( hasOutlineParam )
1240  {
1241  setOutlineColor( outlineColor );
1242  }
1243  if ( hasOutlineWidthParam )
1244  {
1245  setOutlineWidth( outlineWidth );
1246  }
1247 }
1248 
1249 
1251 {
1252  return "SvgMarker";
1253 }
1254 
1256 {
1257  QgsMarkerSymbolLayerV2::startRender( context ); // get anchor point expressions
1258  mOrigSize = mSize; // save in case the size would be data defined
1259  Q_UNUSED( context );
1260  prepareExpressions( context.fields(), context.renderContext().rendererScale() );
1261 }
1262 
1264 {
1265  Q_UNUSED( context );
1266 }
1267 
1269 {
1270  QPainter *p = context.renderContext().painter();
1271  if ( !p )
1272  return;
1273 
1274  double scaledSize = mSize;
1275  QgsExpression* sizeExpression = expression( "size" );
1276 
1277  bool hasDataDefinedSize = context.renderHints() & QgsSymbolV2::DataDefinedSizeScale || sizeExpression;
1278 
1279  if ( sizeExpression )
1280  {
1281  scaledSize = sizeExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
1282  }
1283 
1284  if ( hasDataDefinedSize )
1285  {
1286  switch ( mScaleMethod )
1287  {
1289  scaledSize = sqrt( scaledSize );
1290  break;
1292  break;
1293  }
1294  }
1295 
1297 
1298  //don't render symbols with size below one or above 10,000 pixels
1299  if (( int )size < 1 || 10000.0 < size )
1300  {
1301  return;
1302  }
1303 
1304  p->save();
1305 
1306  //offset
1307  double offsetX = 0;
1308  double offsetY = 0;
1309  markerOffset( context, scaledSize, scaledSize, offsetX, offsetY );
1310  QPointF outputOffset( offsetX, offsetY );
1311 
1312  double angle = mAngle;
1313  QgsExpression* angleExpression = expression( "angle" );
1314  if ( angleExpression )
1315  {
1316  angle = angleExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
1317  }
1318  if ( angle )
1319  outputOffset = _rotatedOffset( outputOffset, angle );
1320  p->translate( point + outputOffset );
1321 
1322  bool rotated = !qgsDoubleNear( angle, 0 );
1323  if ( rotated )
1324  p->rotate( angle );
1325 
1326  QString path = mPath;
1327  QgsExpression* nameExpression = expression( "name" );
1328  if ( nameExpression )
1329  {
1330  path = nameExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString();
1331  }
1332 
1333  double outlineWidth = mOutlineWidth;
1334  QgsExpression* outlineWidthExpression = expression( "outline_width" );
1335  if ( outlineWidthExpression )
1336  {
1337  outlineWidth = outlineWidthExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
1338  }
1339 
1340  QColor fillColor = mFillColor;
1341  QgsExpression* fillExpression = expression( "fill" );
1342  if ( fillExpression )
1343  {
1344  fillColor = QgsSymbolLayerV2Utils::decodeColor( fillExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString() );
1345  }
1346 
1347  QColor outlineColor = mOutlineColor;
1348  QgsExpression* outlineExpression = expression( "outline" );
1349  if ( outlineExpression )
1350  {
1351  outlineColor = QgsSymbolLayerV2Utils::decodeColor( outlineExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString() );
1352  }
1353 
1354 
1355  bool fitsInCache = true;
1356  bool usePict = true;
1357  double hwRatio = 1.0;
1358  if ( !context.renderContext().forceVectorOutput() && !rotated )
1359  {
1360  usePict = false;
1361  const QImage& img = QgsSvgCache::instance()->svgAsImage( path, size, fillColor, outlineColor, outlineWidth,
1362  context.renderContext().scaleFactor(), context.renderContext().rasterScaleFactor(), fitsInCache );
1363  if ( fitsInCache && img.width() > 1 )
1364  {
1365  //consider transparency
1366  if ( !qgsDoubleNear( context.alpha(), 1.0 ) )
1367  {
1368  QImage transparentImage = img.copy();
1369  QgsSymbolLayerV2Utils::multiplyImageOpacity( &transparentImage, context.alpha() );
1370  p->drawImage( -transparentImage.width() / 2.0, -transparentImage.height() / 2.0, transparentImage );
1371  hwRatio = ( double )transparentImage.height() / ( double )transparentImage.width();
1372  }
1373  else
1374  {
1375  p->drawImage( -img.width() / 2.0, -img.height() / 2.0, img );
1376  hwRatio = ( double )img.height() / ( double )img.width();
1377  }
1378  }
1379  }
1380 
1381  if ( usePict || !fitsInCache )
1382  {
1383  p->setOpacity( context.alpha() );
1384  const QPicture& pct = QgsSvgCache::instance()->svgAsPicture( path, size, fillColor, outlineColor, outlineWidth,
1386 
1387  if ( pct.width() > 1 )
1388  {
1389  p->save();
1390  _fixQPictureDPI( p );
1391  p->drawPicture( 0, 0, pct );
1392  p->restore();
1393  hwRatio = ( double )pct.height() / ( double )pct.width();
1394  }
1395  }
1396 
1397  if ( context.selected() )
1398  {
1399  QPen pen( context.renderContext().selectionColor() );
1401  if ( penWidth > size / 20 )
1402  {
1403  // keep the pen width from covering symbol
1404  penWidth = size / 20;
1405  }
1406  double penOffset = penWidth / 2;
1407  pen.setWidth( penWidth );
1408  p->setPen( pen );
1409  p->setBrush( Qt::NoBrush );
1410  double wSize = size + penOffset;
1411  double hSize = size * hwRatio + penOffset;
1412  p->drawRect( QRectF( -wSize / 2.0, -hSize / 2.0, wSize, hSize ) );
1413  }
1414 
1415  p->restore();
1416 }
1417 
1418 
1420 {
1421  QgsStringMap map;
1423  map["size"] = QString::number( mSize );
1424  map["size_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mSizeUnit );
1425  map["size_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mSizeMapUnitScale );
1426  map["angle"] = QString::number( mAngle );
1427  map["offset"] = QgsSymbolLayerV2Utils::encodePoint( mOffset );
1428  map["offset_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOffsetUnit );
1429  map["offset_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOffsetMapUnitScale );
1430  map["scale_method"] = QgsSymbolLayerV2Utils::encodeScaleMethod( mScaleMethod );
1431  map["color"] = mFillColor.name();
1432  map["outline_color"] = mOutlineColor.name();
1433  map["outline_width"] = QString::number( mOutlineWidth );
1434  map["outline_width_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOutlineWidthUnit );
1435  map["outline_width_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOutlineWidthMapUnitScale );
1436  map["horizontal_anchor_point"] = QString::number( mHorizontalAnchorPoint );
1437  map["vertical_anchor_point"] = QString::number( mVerticalAnchorPoint );
1438 
1440  return map;
1441 }
1442 
1444 {
1446  m->setFillColor( mFillColor );
1451  m->setOffset( mOffset );
1452  m->setOffsetUnit( mOffsetUnit );
1454  m->setSizeUnit( mSizeUnit );
1459  return m;
1460 }
1461 
1463 {
1465  mOutlineWidthUnit = unit;
1466 }
1467 
1469 {
1471  if ( unit != mOutlineWidthUnit )
1472  {
1473  return QgsSymbolV2::Mixed;
1474  }
1475  return unit;
1476 }
1477 
1479 {
1481  mOutlineWidthMapUnitScale = scale;
1482 }
1483 
1485 {
1487  {
1489  }
1490  return QgsMapUnitScale();
1491 }
1492 
1493 void QgsSvgMarkerSymbolLayerV2::writeSldMarker( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
1494 {
1495  // <Graphic>
1496  QDomElement graphicElem = doc.createElement( "se:Graphic" );
1497  element.appendChild( graphicElem );
1498 
1499  QgsSymbolLayerV2Utils::externalGraphicToSld( doc, graphicElem, mPath, "image/svg+xml", mFillColor, mSize );
1500 
1501  // <Rotation>
1502  QString angleFunc;
1503  bool ok;
1504  double angle = props.value( "angle", "0" ).toDouble( &ok );
1505  if ( !ok )
1506  {
1507  angleFunc = QString( "%1 + %2" ).arg( props.value( "angle", "0" ) ).arg( mAngle );
1508  }
1509  else if ( angle + mAngle != 0 )
1510  {
1511  angleFunc = QString::number( angle + mAngle );
1512  }
1513 
1514  QgsSymbolLayerV2Utils::createRotationElement( doc, graphicElem, angleFunc );
1515 
1516  // <Displacement>
1518 }
1519 
1521 {
1522  QgsDebugMsg( "Entered." );
1523 
1524  QDomElement graphicElem = element.firstChildElement( "Graphic" );
1525  if ( graphicElem.isNull() )
1526  return NULL;
1527 
1528  QString path, mimeType;
1529  QColor fillColor;
1530  double size;
1531 
1532  if ( !QgsSymbolLayerV2Utils::externalGraphicFromSld( graphicElem, path, mimeType, fillColor, size ) )
1533  return NULL;
1534 
1535  if ( mimeType != "image/svg+xml" )
1536  return NULL;
1537 
1538  double angle = 0.0;
1539  QString angleFunc;
1540  if ( QgsSymbolLayerV2Utils::rotationFromSldElement( graphicElem, angleFunc ) )
1541  {
1542  bool ok;
1543  double d = angleFunc.toDouble( &ok );
1544  if ( ok )
1545  angle = d;
1546  }
1547 
1548  QPointF offset;
1550 
1552  m->setFillColor( fillColor );
1553  //m->setOutlineColor( outlineColor );
1554  //m->setOutlineWidth( outlineWidth );
1555  m->setAngle( angle );
1556  m->setOffset( offset );
1557  return m;
1558 }
1559 
1560 bool QgsSvgMarkerSymbolLayerV2::writeDxf( QgsDxfExport& e, double mmMapUnitScaleFactor, const QString& layerName, const QgsSymbolV2RenderContext* context, const QgsFeature* f,
1561  const QPointF& shift ) const
1562 {
1563  Q_UNUSED( layerName );
1564  Q_UNUSED( shift ); //todo...
1565 
1566  QSvgRenderer r( mPath );
1567  if ( !r.isValid() )
1568  {
1569  return false;
1570  }
1571 
1572  QgsDxfPaintDevice pd( &e );
1573  pd.setDrawingSize( QSizeF( r.defaultSize() ) );
1574 
1575  //size
1576  double size = mSize;
1577  QgsExpression* sizeExpression = expression( "size" );
1578  bool hasDataDefinedSize = context->renderHints() & QgsSymbolV2::DataDefinedSizeScale || sizeExpression;
1579 
1580  if ( sizeExpression )
1581  {
1582  size = sizeExpression->evaluate( *f ).toDouble();
1583  }
1584 
1585  if ( hasDataDefinedSize )
1586  {
1587  switch ( mScaleMethod )
1588  {
1590  size = sqrt( size );
1591  break;
1593  break;
1594  }
1595  }
1596 
1597  if ( mSizeUnit == QgsSymbolV2::MM )
1598  {
1599  size *= mmMapUnitScaleFactor;
1600  }
1601 
1602  double halfSize = size / 2.0;
1603 
1604  //offset, angle
1605  QPointF offset = mOffset;
1606  QgsExpression* offsetExpression = expression( "offset" );
1607  if ( offsetExpression )
1608  {
1609  QString offsetString = offsetExpression->evaluate( *f ).toString();
1610  offset = QgsSymbolLayerV2Utils::decodePoint( offsetString );
1611  }
1612  double offsetX = offset.x();
1613  double offsetY = offset.y();
1614  if ( mSizeUnit == QgsSymbolV2::MM )
1615  {
1616  offsetX *= mmMapUnitScaleFactor;
1617  offsetY *= mmMapUnitScaleFactor;
1618  }
1619 
1620  QPointF outputOffset( offsetX, offsetY );
1621 
1622  double angle = mAngle;
1623  QgsExpression* angleExpression = expression( "angle" );
1624  if ( angleExpression )
1625  {
1626  angle = angleExpression->evaluate( *f ).toDouble();
1627  }
1628  //angle = -angle; //rotation in Qt is counterclockwise
1629  if ( angle )
1630  outputOffset = _rotatedOffset( outputOffset, angle );
1631 
1632  QPainter p;
1633  p.begin( &pd );
1634  if ( !qgsDoubleNear( angle, 0.0 ) )
1635  {
1636  p.translate( r.defaultSize().width() / 2.0, r.defaultSize().height() / 2.0 );
1637  p.rotate( angle );
1638  p.translate( -r.defaultSize().width() / 2.0, -r.defaultSize().height() / 2.0 );
1639  }
1640  pd.setShift( shift );
1641  pd.setOutputSize( QRectF( -halfSize, -halfSize, size, size ) );
1642  pd.setLayer( layerName );
1643  r.render( &p );
1644  p.end();
1645  return true;
1646 }
1647 
1649 
1650 QgsFontMarkerSymbolLayerV2::QgsFontMarkerSymbolLayerV2( QString fontFamily, QChar chr, double pointSize, QColor color, double angle )
1651 {
1653  mChr = chr;
1654  mColor = color;
1655  mAngle = angle;
1656  mSize = pointSize;
1658  mOffset = QPointF( 0, 0 );
1660 }
1661 
1663 {
1665  QChar chr = DEFAULT_FONTMARKER_CHR;
1666  double pointSize = DEFAULT_FONTMARKER_SIZE;
1669 
1670  if ( props.contains( "font" ) )
1671  fontFamily = props["font"];
1672  if ( props.contains( "chr" ) && props["chr"].length() > 0 )
1673  chr = props["chr"].at( 0 );
1674  if ( props.contains( "size" ) )
1675  pointSize = props["size"].toDouble();
1676  if ( props.contains( "color" ) )
1677  color = QgsSymbolLayerV2Utils::decodeColor( props["color"] );
1678  if ( props.contains( "angle" ) )
1679  angle = props["angle"].toDouble();
1680 
1681  QgsFontMarkerSymbolLayerV2* m = new QgsFontMarkerSymbolLayerV2( fontFamily, chr, pointSize, color, angle );
1682  if ( props.contains( "offset" ) )
1683  m->setOffset( QgsSymbolLayerV2Utils::decodePoint( props["offset"] ) );
1684  if ( props.contains( "offset_unit" ) )
1685  m->setOffsetUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["offset_unit" ] ) );
1686  if ( props.contains( "offset_map_unit_scale" ) )
1687  m->setOffsetMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["offset_map_unit_scale" ] ) );
1688  if ( props.contains( "size_unit" ) )
1689  m->setSizeUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["size_unit"] ) );
1690  if ( props.contains( "size_map_unit_scale" ) )
1691  m->setSizeMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["size_map_unit_scale"] ) );
1692  if ( props.contains( "horizontal_anchor_point" ) )
1693  {
1694  m->setHorizontalAnchorPoint( QgsMarkerSymbolLayerV2::HorizontalAnchorPoint( props[ "horizontal_anchor_point" ].toInt() ) );
1695  }
1696  if ( props.contains( "vertical_anchor_point" ) )
1697  {
1698  m->setVerticalAnchorPoint( QgsMarkerSymbolLayerV2::VerticalAnchorPoint( props[ "vertical_anchor_point" ].toInt() ) );
1699  }
1700  return m;
1701 }
1702 
1704 {
1705  return "FontMarker";
1706 }
1707 
1709 {
1710  mFont = QFont( mFontFamily );
1712  QFontMetrics fm( mFont );
1713  mChrOffset = QPointF( fm.width( mChr ) / 2, -fm.ascent() / 2 );
1714 
1715  mOrigSize = mSize; // save in case the size would be data defined
1716 }
1717 
1719 {
1720  Q_UNUSED( context );
1721 }
1722 
1724 {
1725  QPainter *p = context.renderContext().painter();
1726  if ( !p )
1727  return;
1728 
1729  QColor penColor = context.selected() ? context.renderContext().selectionColor() : mColor;
1730  penColor.setAlphaF( mColor.alphaF() * context.alpha() );
1731  p->setPen( penColor );
1732  p->setFont( mFont );
1733 
1734  p->save();
1735  //offset
1736  double offsetX = 0;
1737  double offsetY = 0;
1738  markerOffset( context, offsetX, offsetY );
1739  QPointF outputOffset( offsetX, offsetY );
1740  if ( mAngle )
1741  outputOffset = _rotatedOffset( outputOffset, mAngle );
1742  p->translate( point + outputOffset );
1743 
1745  {
1746  double s = mSize / mOrigSize;
1747  p->scale( s, s );
1748  }
1749 
1750  if ( mAngle != 0 )
1751  p->rotate( mAngle );
1752 
1753  p->drawText( -mChrOffset, mChr );
1754  p->restore();
1755 }
1756 
1758 {
1759  QgsStringMap props;
1760  props["font"] = mFontFamily;
1761  props["chr"] = mChr;
1762  props["size"] = QString::number( mSize );
1763  props["size_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mSizeUnit );
1764  props["size_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mSizeMapUnitScale );
1765  props["color"] = QgsSymbolLayerV2Utils::encodeColor( mColor );
1766  props["angle"] = QString::number( mAngle );
1767  props["offset"] = QgsSymbolLayerV2Utils::encodePoint( mOffset );
1768  props["offset_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOffsetUnit );
1769  props["offset_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOffsetMapUnitScale );
1770  props["horizontal_anchor_point"] = QString::number( mHorizontalAnchorPoint );
1771  props["vertical_anchor_point"] = QString::number( mVerticalAnchorPoint );
1772  return props;
1773 }
1774 
1776 {
1778  m->setOffset( mOffset );
1779  m->setOffsetUnit( mOffsetUnit );
1781  m->setSizeUnit( mSizeUnit );
1785  return m;
1786 }
1787 
1788 void QgsFontMarkerSymbolLayerV2::writeSldMarker( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
1789 {
1790  // <Graphic>
1791  QDomElement graphicElem = doc.createElement( "se:Graphic" );
1792  element.appendChild( graphicElem );
1793 
1794  QString fontPath = QString( "ttf://%1" ).arg( mFontFamily );
1795  int markIndex = mChr.unicode();
1796  QgsSymbolLayerV2Utils::externalMarkerToSld( doc, graphicElem, fontPath, "ttf", &markIndex, mColor, mSize );
1797 
1798  // <Rotation>
1799  QString angleFunc;
1800  bool ok;
1801  double angle = props.value( "angle", "0" ).toDouble( &ok );
1802  if ( !ok )
1803  {
1804  angleFunc = QString( "%1 + %2" ).arg( props.value( "angle", "0" ) ).arg( mAngle );
1805  }
1806  else if ( angle + mAngle != 0 )
1807  {
1808  angleFunc = QString::number( angle + mAngle );
1809  }
1810  QgsSymbolLayerV2Utils::createRotationElement( doc, graphicElem, angleFunc );
1811 
1812  // <Displacement>
1814 }
1815 
1817 {
1818  QgsDebugMsg( "Entered." );
1819 
1820  QDomElement graphicElem = element.firstChildElement( "Graphic" );
1821  if ( graphicElem.isNull() )
1822  return NULL;
1823 
1824  QString name, format;
1825  QColor color;
1826  double size;
1827  int chr;
1828 
1829  if ( !QgsSymbolLayerV2Utils::externalMarkerFromSld( graphicElem, name, format, chr, color, size ) )
1830  return NULL;
1831 
1832  if ( !name.startsWith( "ttf://" ) || format != "ttf" )
1833  return NULL;
1834 
1835  QString fontFamily = name.mid( 6 );
1836 
1837  double angle = 0.0;
1838  QString angleFunc;
1839  if ( QgsSymbolLayerV2Utils::rotationFromSldElement( graphicElem, angleFunc ) )
1840  {
1841  bool ok;
1842  double d = angleFunc.toDouble( &ok );
1843  if ( ok )
1844  angle = d;
1845  }
1846 
1847  QPointF offset;
1849 
1850  QgsMarkerSymbolLayerV2 *m = new QgsFontMarkerSymbolLayerV2( fontFamily, chr, size, color );
1851  m->setAngle( angle );
1852  m->setOffset( offset );
1853  return m;
1854 }
1855 
1856 
QgsSymbolV2::OutputUnit outputUnit() const override
static QString encodeOutputUnit(QgsSymbolV2::OutputUnit unit)
Q_GUI_EXPORT int qt_defaultDpiX()
Class for parsing and evaluation of expressions (formerly called "search strings").
Definition: qgsexpression.h:87
void setOutlineStyle(Qt::PenStyle outlineStyle)
void stopRender(QgsSymbolV2RenderContext &context) override
QgsSymbolV2::OutputUnit outputUnit() const override
static void multiplyImageOpacity(QImage *image, qreal alpha)
Multiplies opacity of image pixel values with a (global) transparency value.
int renderHints() const
Definition: qgssymbolv2.h:208
QgsMapUnitScale mSizeMapUnitScale
Q_GUI_EXPORT int qt_defaultDpiY()
QString layerType() const override
QgsStringMap properties() const override
static Q_DECL_DEPRECATED bool wellKnownMarkerFromSld(QDomElement &element, QString &name, QColor &color, QColor &borderColor, double &borderWidth, double &size)
A paint device for drawing into dxf files.
QString layerType() const override
#define DEFAULT_FONTMARKER_COLOR
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&.
QVariant evaluate(const QgsFeature *f=NULL)
Evaluate the feature and return the result.
QColor selectionColor() const
QgsSymbolLayerV2 * clone() const override
QgsSymbolV2::OutputUnit mOutlineWidthUnit
void setOutlineColor(const QColor &c) override
Set outline color.
QString layerType() const override
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
#define DEFAULT_SIMPLEMARKER_ANGLE
static void createRotationElement(QDomDocument &doc, QDomElement &element, QString rotationFunc)
double rendererScale() const
#define DEFAULT_FONTMARKER_CHR
void writeSolid(const QString &layer, QColor color, const QgsPoint &pt1, const QgsPoint &pt2, const QgsPoint &pt3, const QgsPoint &pt4)
void setOffset(QPointF offset)
QString ogrFeatureStyle(double mmScaleFactor, double mapUnitScaleFactor) const override
void setHorizontalAnchorPoint(HorizontalAnchorPoint h)
#define DEG2RAD(x)
#define DEFAULT_SIMPLEMARKER_COLOR
void writeSldMarker(QDomDocument &doc, QDomElement &element, QgsStringMap props) const override
QgsSymbolLayerV2 * clone() const override
static QPointF decodePoint(QString str)
void setVerticalAnchorPoint(VerticalAnchorPoint v)
static bool externalGraphicFromSld(QDomElement &element, QString &path, QString &mime, QColor &color, double &size)
static QColor decodeColor(QString str)
void stopRender(QgsSymbolV2RenderContext &context) override
static QString encodeMapUnitScale(const QgsMapUnitScale &mapUnitScale)
double scaleFactor() const
QColor fillColor() const override
Get fill color.
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:113
static void _fixQPictureDPI(QPainter *p)
void setOffsetMapUnitScale(const QgsMapUnitScale &scale)
static void createDisplacementElement(QDomDocument &doc, QDomElement &element, QPointF offset)
void writeSldMarker(QDomDocument &doc, QDomElement &element, QgsStringMap props) const override
static QgsSymbolLayerV2 * create(const QgsStringMap &properties=QgsStringMap())
QMap< QString, QString > QgsStringMap
Definition: qgis.h:416
QgsSymbolLayerV2 * clone() const override
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
Definition: qgis.h:325
void setMapUnitScale(const QgsMapUnitScale &scale) override
static QgsSymbolLayerV2 * createFromSld(QDomElement &element)
void writeCircle(const QString &layer, QColor color, const QgsPoint &pt, double radius, const QString &lineStyleName, double width)
#define DEFAULT_SVGMARKER_ANGLE
void setOffsetUnit(QgsSymbolV2::OutputUnit unit)
static QString encodeColor(QColor color)
#define DEFAULT_SIMPLEMARKER_NAME
virtual QgsExpression * expression(const QString &property) const
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 bool displacementFromSldElement(QDomElement &element, QPointF &offset)
qreal alpha() const
Get alpha transparency 1 for opaque, 0 for invisible.
Definition: qgssymbolv2.h:201
void drawMarker(QPainter *p, QgsSymbolV2RenderContext &context)
static QgsSvgCache * instance()
Definition: qgssvgcache.cpp:84
static QString encodePenStyle(Qt::PenStyle style)
void setOutlineWidthUnit(QgsSymbolV2::OutputUnit unit)
bool writeDxf(QgsDxfExport &e, double mmMapUnitScaleFactor, const QString &layerName, const QgsSymbolV2RenderContext *context, const QgsFeature *f, const QPointF &shift=QPointF(0.0, 0.0)) const override
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.
QgsFontMarkerSymbolLayerV2(QString fontFamily=DEFAULT_FONTMARKER_FONT, QChar chr=DEFAULT_FONTMARKER_CHR, double pointSize=DEFAULT_FONTMARKER_SIZE, QColor color=DEFAULT_FONTMARKER_COLOR, double angle=DEFAULT_FONTMARKER_ANGLE)
static QString symbolPathToName(QString path)
Get symbols's name from its path.
void setMapUnitScale(const QgsMapUnitScale &scale) override
void setOutlineWidthUnit(QgsSymbolV2::OutputUnit u)
const QgsFeature * feature() const
Current feature being rendered - may be null.
Definition: qgssymbolv2.h:213
static QString encodePoint(QPointF point)
QgsStringMap properties() const override
static Qt::PenStyle decodePenStyle(QString str)
void renderPoint(const QPointF &point, QgsSymbolV2RenderContext &context) override
#define DEFAULT_SCALE_METHOD
void setOutputUnit(QgsSymbolV2::OutputUnit unit) override
void setMapUnitScale(const QgsMapUnitScale &scale) override
QgsSymbolV2::ScaleMethod mScaleMethod
static QString symbolNameToPath(QString name)
Get symbol's path from its name.
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)
QgsMapUnitScale mapUnitScale() const override
QgsStringMap properties() const override
void stopRender(QgsSymbolV2RenderContext &context) override
double rasterScaleFactor() const
#define DEFAULT_FONTMARKER_ANGLE
QgsSymbolV2::OutputUnit outputUnit() const override
void writeLine(const QgsPoint &pt1, const QgsPoint &pt2, const QString &layer, const QString &lineStyleName, QColor color, double width=-1)
virtual QColor color() const
QgsSvgMarkerSymbolLayerV2(QString name=DEFAULT_SVGMARKER_NAME, double size=DEFAULT_SVGMARKER_SIZE, double angle=DEFAULT_SVGMARKER_ANGLE, QgsSymbolV2::ScaleMethod scaleMethod=DEFAULT_SCALE_METHOD)
static QgsSymbolLayerV2 * createFromSld(QDomElement &element)
HorizontalAnchorPoint mHorizontalAnchorPoint
virtual void prepareExpressions(const QgsFields *fields, double scale=-1.0)
void setOutlineWidthMapUnitScale(const QgsMapUnitScale &scale)
QgsSymbolV2::ScaleMethod scaleMethod() 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 setOutlineWidthMapUnitScale(const QgsMapUnitScale &scale)
QgsMapUnitScale mapUnitScale() const override
void startRender(QgsSymbolV2RenderContext &context) override
#define DEFAULT_FONTMARKER_SIZE
void startRender(QgsSymbolV2RenderContext &context) override
#define DEFAULT_FONTMARKER_FONT
#define DEFAULT_SVGMARKER_NAME
#define DEFAULT_SIMPLEMARKER_SIZE
QPainter * painter()
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.
void renderPoint(const QPointF &point, QgsSymbolV2RenderContext &context) override
static QgsSymbolLayerV2 * create(const QgsStringMap &properties=QgsStringMap())
void setOutputUnit(QgsSymbolV2::OutputUnit unit) override
QgsMapUnitScale mapUnitScale() const override
Qt::PenStyle outlineStyle() const
void setShift(const QPointF &shift)
QgsSimpleMarkerSymbolLayerV2(QString name=DEFAULT_SIMPLEMARKER_NAME, QColor color=DEFAULT_SIMPLEMARKER_COLOR, QColor borderColor=DEFAULT_SIMPLEMARKER_BORDERCOLOR, double size=DEFAULT_SIMPLEMARKER_SIZE, double angle=DEFAULT_SIMPLEMARKER_ANGLE, QgsSymbolV2::ScaleMethod scaleMethod=DEFAULT_SCALE_METHOD)
virtual const QgsExpression * dataDefinedProperty(const QString &property) const
static QString encodeScaleMethod(QgsSymbolV2::ScaleMethod scaleMethod)
QgsRenderContext & renderContext()
Definition: qgssymbolv2.h:191
bool preparePath(QString name=QString())
void writeFilledCircle(const QString &layer, QColor color, const QgsPoint &pt, double radius)
static void externalGraphicToSld(QDomDocument &doc, QDomElement &element, QString path, QString mime, QColor color, double size=-1)
bool writeDxf(QgsDxfExport &e, double mmMapUnitScaleFactor, const QString &layerName, const QgsSymbolV2RenderContext *context, const QgsFeature *f, const QPointF &shift=QPointF(0.0, 0.0)) const override
static Q_DECL_DEPRECATED void wellKnownMarkerToSld(QDomDocument &doc, QDomElement &element, QString name, QColor color, QColor borderColor=QColor(), double borderWidth=-1, double size=-1)
const QgsFields * fields() const
Fields of the layer.
Definition: qgssymbolv2.h:219
QgsSymbolV2::OutputUnit mOffsetUnit
void startRender(QgsSymbolV2RenderContext &context) override
static bool rotationFromSldElement(QDomElement &element, QString &rotationFunc)
bool selected() const
Definition: qgssymbolv2.h:205
static QgsSymbolV2::ScaleMethod decodeScaleMethod(QString str)
void startRender(QgsSymbolV2RenderContext &context) override
VerticalAnchorPoint mVerticalAnchorPoint
bool prepareShape(QString name=QString())
QgsSymbolV2::OutputUnit mSizeUnit
void setDrawingSize(const QSizeF &size)
QgsMapUnitScale mOffsetMapUnitScale
void markerOffset(const QgsSymbolV2RenderContext &context, double &offsetX, double &offsetY) const
static QgsMapUnitScale decodeMapUnitScale(const QString &str)
void writeSldMarker(QDomDocument &doc, QDomElement &element, QgsStringMap props) const override
void setAngle(double angle)
double size
Definition: qgssvgcache.cpp:77
static QgsSymbolLayerV2 * createFromSld(QDomElement &element)
void saveDataDefinedProperties(QgsStringMap &stringMap) const
Saves data defined properties to string map.
void setSizeMapUnitScale(const QgsMapUnitScale &scale)
QColor outlineColor() const override
Get outline color.
void setOutputUnit(QgsSymbolV2::OutputUnit unit) override
bool prepareCache(QgsSymbolV2RenderContext &context)
Prepares cache image.
static QgsSymbolV2::OutputUnit decodeOutputUnit(QString str)
void renderPoint(const QPointF &point, QgsSymbolV2RenderContext &context) override
static void externalMarkerToSld(QDomDocument &doc, QDomElement &element, QString path, QString format, int *markIndex=0, QColor color=QColor(), double size=-1)
void copyDataDefinedProperties(QgsSymbolLayerV2 *destLayer) const
Copies data defined properties of this layer to another symbol layer.
void setFillColor(const QColor &c) override
Set fill color.
void setOutputSize(const QRectF &r)
virtual void setDataDefinedProperty(const QString &property, const QString &expressionString)
static QPointF _rotatedOffset(const QPointF &offset, double angle)
#define DEFAULT_SIMPLEMARKER_BORDERCOLOR