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