QGIS API Documentation  2.9.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
qgsellipsesymbollayerv2.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsellipsesymbollayerv2.cpp
3  ---------------------
4  begin : June 2011
5  copyright : (C) 2011 by Marco Hugentobler
6  email : marco dot hugentobler at sourcepole dot ch
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  ***************************************************************************/
16 #include "qgsdxfexport.h"
17 #include "qgsexpression.h"
18 #include "qgsfeature.h"
19 #include "qgsrendercontext.h"
20 #include "qgsvectorlayer.h"
21 #include "qgsdatadefined.h"
22 #include "qgslogger.h"
23 
24 #include <QPainter>
25 #include <QSet>
26 #include <QDomDocument>
27 #include <QDomElement>
28 
30  : mSymbolName( "circle" )
31  , mSymbolWidth( 4 )
32  , mSymbolWidthUnit( QgsSymbolV2::MM )
33  , mSymbolHeight( 3 )
34  , mSymbolHeightUnit( QgsSymbolV2::MM )
35  , mFillColor( Qt::white )
36  , mOutlineColor( Qt::black )
37  , mOutlineStyle( Qt::SolidLine )
38  , mOutlineWidth( 0 )
39  , mOutlineWidthUnit( QgsSymbolV2::MM )
40 {
41  mPen.setColor( mOutlineColor );
42  mPen.setStyle( mOutlineStyle );
43  mPen.setWidth( 1.0 );
44  mPen.setJoinStyle( Qt::MiterJoin );
45  mBrush.setColor( mFillColor );
46  mBrush.setStyle( Qt::SolidPattern );
47  mOffset = QPointF( 0, 0 );
48 
49  mAngle = 0;
50 }
51 
53 {
54 }
55 
57 {
59  if ( properties.contains( "symbol_name" ) )
60  {
61  layer->setSymbolName( properties[ "symbol_name" ] );
62  }
63  if ( properties.contains( "symbol_width" ) )
64  {
65  layer->setSymbolWidth( properties["symbol_width"].toDouble() );
66  }
67  if ( properties.contains( "symbol_width_unit" ) )
68  {
69  layer->setSymbolWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["symbol_width_unit"] ) );
70  }
71  if ( properties.contains( "symbol_width_map_unit_scale" ) )
72  {
73  layer->setSymbolWidthMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( properties["symbol_width_map_unit_scale"] ) );
74  }
75  if ( properties.contains( "symbol_height" ) )
76  {
77  layer->setSymbolHeight( properties["symbol_height"].toDouble() );
78  }
79  if ( properties.contains( "symbol_height_unit" ) )
80  {
81  layer->setSymbolHeightUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["symbol_height_unit"] ) );
82  }
83  if ( properties.contains( "symbol_height_map_unit_scale" ) )
84  {
85  layer->setSymbolHeightMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( properties["symbol_height_map_unit_scale"] ) );
86  }
87  if ( properties.contains( "angle" ) )
88  {
89  layer->setAngle( properties["angle"].toDouble() );
90  }
91  if ( properties.contains( "outline_style" ) )
92  {
93  layer->setOutlineStyle( QgsSymbolLayerV2Utils::decodePenStyle( properties["outline_style"] ) );
94  }
95  else if ( properties.contains( "line_style" ) )
96  {
97  layer->setOutlineStyle( QgsSymbolLayerV2Utils::decodePenStyle( properties["line_style"] ) );
98  }
99  if ( properties.contains( "outline_width" ) )
100  {
101  layer->setOutlineWidth( properties["outline_width"].toDouble() );
102  }
103  else if ( properties.contains( "line_width" ) )
104  {
105  layer->setOutlineWidth( properties["line_width"].toDouble() );
106  }
107  if ( properties.contains( "outline_width_unit" ) )
108  {
109  layer->setOutlineWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["outline_width_unit"] ) );
110  }
111  else if ( properties.contains( "line_width_unit" ) )
112  {
113  layer->setOutlineWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["line_width_unit"] ) );
114  }
115  if ( properties.contains( "outline_width_map_unit_scale" ) )
116  {
117  layer->setOutlineWidthMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( properties["outline_width_map_unit_scale"] ) );
118  }
119  if ( properties.contains( "fill_color" ) )
120  {
121  //pre 2.5 projects used "fill_color"
122  layer->setFillColor( QgsSymbolLayerV2Utils::decodeColor( properties["fill_color"] ) );
123  }
124  else if ( properties.contains( "color" ) )
125  {
126  layer->setFillColor( QgsSymbolLayerV2Utils::decodeColor( properties["color"] ) );
127  }
128  if ( properties.contains( "outline_color" ) )
129  {
130  layer->setOutlineColor( QgsSymbolLayerV2Utils::decodeColor( properties["outline_color"] ) );
131  }
132  else if ( properties.contains( "line_color" ) )
133  {
134  layer->setOutlineColor( QgsSymbolLayerV2Utils::decodeColor( properties["line_color"] ) );
135  }
136  if ( properties.contains( "size" ) )
137  {
138  layer->setSize( properties["size"].toDouble() );
139  }
140  if ( properties.contains( "size_unit" ) )
141  {
142  layer->setSizeUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["size_unit"] ) );
143  }
144  if ( properties.contains( "size_map_unit_scale" ) )
145  {
146  layer->setSizeMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( properties["size_map_unit_scale"] ) );
147  }
148  if ( properties.contains( "offset" ) )
149  {
150  layer->setOffset( QgsSymbolLayerV2Utils::decodePoint( properties["offset"] ) );
151  }
152  if ( properties.contains( "offset_unit" ) )
153  {
154  layer->setOffsetUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["offset_unit"] ) );
155  }
156  if ( properties.contains( "offset_map_unit_scale" ) )
157  {
158  layer->setOffsetMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( properties["offset_map_unit_scale"] ) );
159  }
160  if ( properties.contains( "horizontal_anchor_point" ) )
161  {
162  layer->setHorizontalAnchorPoint( QgsMarkerSymbolLayerV2::HorizontalAnchorPoint( properties[ "horizontal_anchor_point" ].toInt() ) );
163  }
164  if ( properties.contains( "vertical_anchor_point" ) )
165  {
166  layer->setVerticalAnchorPoint( QgsMarkerSymbolLayerV2::VerticalAnchorPoint( properties[ "vertical_anchor_point" ].toInt() ) );
167  }
168 
169  //data defined properties
170  layer->restoreDataDefinedProperties( properties );
171 
172  //compatibility with old project file format
173  if ( !properties["width_field"].isEmpty() )
174  {
175  layer->setDataDefinedProperty( QgsSymbolLayerV2::EXPR_WIDTH, new QgsDataDefined( properties["width_field"] ) );
176  }
177  if ( !properties["height_field"].isEmpty() )
178  {
179  layer->setDataDefinedProperty( QgsSymbolLayerV2::EXPR_HEIGHT, new QgsDataDefined( properties["height_field"] ) );
180  }
181  if ( !properties["rotation_field"].isEmpty() )
182  {
183  layer->setDataDefinedProperty( QgsSymbolLayerV2::EXPR_ROTATION, new QgsDataDefined( properties["rotation_field"] ) );
184  }
185  if ( !properties["outline_width_field"].isEmpty() )
186  {
187  layer->setDataDefinedProperty( QgsSymbolLayerV2::EXPR_OUTLINE_WIDTH, new QgsDataDefined( properties[ "outline_width_field" ] ) );
188  }
189  if ( !properties["fill_color_field"].isEmpty() )
190  {
191  layer->setDataDefinedProperty( QgsSymbolLayerV2::EXPR_FILL_COLOR, new QgsDataDefined( properties["fill_color_field"] ) );
192  }
193  if ( !properties["outline_color_field"].isEmpty() )
194  {
195  layer->setDataDefinedProperty( QgsSymbolLayerV2::EXPR_OUTLINE_COLOR, new QgsDataDefined( properties["outline_color_field"] ) );
196  }
197  if ( !properties["symbol_name_field"].isEmpty() )
198  {
199  layer->setDataDefinedProperty( QgsSymbolLayerV2::EXPR_SYMBOL_NAME, new QgsDataDefined( properties["symbol_name_field"] ) );
200  }
201 
202  return layer;
203 }
204 
206 {
207  bool ok;
209  {
210  double width = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_OUTLINE_WIDTH, context.feature(), mOutlineWidth ).toDouble();
211  width *= QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), mOutlineWidthUnit, mOutlineWidthMapUnitScale );
212  mPen.setWidthF( width );
213  }
215  {
216  QString styleString = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_OUTLINE_STYLE, context.feature(), QVariant(), &ok ).toString();
217  if ( ok )
218  {
219  Qt::PenStyle style = QgsSymbolLayerV2Utils::decodePenStyle( styleString );
220  mPen.setStyle( style );
221  }
222  }
224  {
225  QString colorString = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_FILL_COLOR, context.feature(), QVariant(), &ok ).toString();
226  if ( ok )
227  mBrush.setColor( QColor( QgsSymbolLayerV2Utils::decodeColor( colorString ) ) );
228  }
230  {
231  QString colorString = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_OUTLINE_COLOR, context.feature(), QVariant(), &ok ).toString();
232  if ( ok )
233  mPen.setColor( QColor( QgsSymbolLayerV2Utils::decodeColor( colorString ) ) );
234  }
235  double scaledWidth = mSymbolWidth;
236  double scaledHeight = mSymbolHeight;
238  {
239  QString symbolName = mSymbolName;
241  {
242  symbolName = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_SYMBOL_NAME, context.feature(), mSymbolName ).toString();
243  }
244  preparePath( symbolName, context, &scaledWidth, &scaledHeight, context.feature() );
245  }
246 
247  //offset
248  double offsetX = 0;
249  double offsetY = 0;
250  markerOffset( context, scaledWidth, scaledHeight, mSymbolWidthUnit, mSymbolHeightUnit, offsetX, offsetY, mSymbolWidthMapUnitScale, mSymbolHeightMapUnitScale );
251  QPointF off( offsetX, offsetY );
252 
253  QPainter* p = context.renderContext().painter();
254  if ( !p )
255  {
256  return;
257  }
258 
259  //priority for rotation: 1. data defined symbol level, 2. symbol layer rotation (mAngle)
260  double rotation = 0.0;
262  {
264  }
265  else if ( !qgsDoubleNear( mAngle + mLineAngle, 0.0 ) )
266  {
267  rotation = mAngle + mLineAngle;
268  }
269  if ( rotation )
270  off = _rotatedOffset( off, rotation );
271 
272  QMatrix transform;
273  transform.translate( point.x() + off.x(), point.y() + off.y() );
274  if ( !qgsDoubleNear( rotation, 0.0 ) )
275  {
276  transform.rotate( rotation );
277  }
278 
279  p->setPen( mPen );
280  p->setBrush( mBrush );
281  p->drawPath( transform.map( mPainterPath ) );
282 }
283 
285 {
286  return "EllipseMarker";
287 }
288 
290 {
291  QgsMarkerSymbolLayerV2::startRender( context ); // get anchor point expressions
292  if ( !context.feature() || !hasDataDefinedProperties() )
293  {
294  preparePath( mSymbolName, context );
295  }
296  mPen.setColor( mOutlineColor );
297  mPen.setStyle( mOutlineStyle );
298  mPen.setWidthF( mOutlineWidth * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), mOutlineWidthUnit, mOutlineWidthMapUnitScale ) );
299  mBrush.setColor( mFillColor );
300  prepareExpressions( context.fields(), context.renderContext().rendererScale() );
301 }
302 
304 {
305 }
306 
308 {
310 }
311 
312 void QgsEllipseSymbolLayerV2::toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
313 {
314  QDomElement symbolizerElem = doc.createElement( "se:PointSymbolizer" );
315  if ( !props.value( "uom", "" ).isEmpty() )
316  symbolizerElem.setAttribute( "uom", props.value( "uom", "" ) );
317  element.appendChild( symbolizerElem );
318 
319  // <Geometry>
320  QgsSymbolLayerV2Utils::createGeometryElement( doc, symbolizerElem, props.value( "geom", "" ) );
321 
322  writeSldMarker( doc, symbolizerElem, props );
323 }
324 
325 void QgsEllipseSymbolLayerV2::writeSldMarker( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
326 {
327  // <Graphic>
328  QDomElement graphicElem = doc.createElement( "se:Graphic" );
329  element.appendChild( graphicElem );
330 
331  QgsSymbolLayerV2Utils::wellKnownMarkerToSld( doc, graphicElem, mSymbolName, mFillColor, mOutlineColor, mOutlineStyle, mOutlineWidth, mSymbolWidth );
332 
333  // store w/h factor in a <VendorOption>
334  double widthHeightFactor = mSymbolWidth / mSymbolHeight;
335  QDomElement factorElem = QgsSymbolLayerV2Utils::createVendorOptionElement( doc, "widthHeightFactor", QString::number( widthHeightFactor ) );
336  graphicElem.appendChild( factorElem );
337 
338  // <Rotation>
340 
341  QString angleFunc = props.value( "angle", "" );
342  if ( angleFunc.isEmpty() ) // symbol has no angle set
343  {
344  if ( ddRotation && ddRotation->isActive() )
345  {
346  angleFunc = ddRotation->useExpression() ? ddRotation->expressionString() : ddRotation->field();
347  }
348  else if ( !qgsDoubleNear( mAngle, 0.0 ) )
349  angleFunc = QString::number( mAngle );
350  }
351  else if ( ddRotation && ddRotation->isActive() )
352  {
353  // the symbol has an angle and the symbol layer have a rotation
354  // property set
355  angleFunc = QString( "%1 + %2" ).arg( angleFunc ).arg( ddRotation->useExpression() ? ddRotation->expressionString() : ddRotation->field() );
356  }
357  else if ( !qgsDoubleNear( mAngle, 0.0 ) )
358  {
359  // both the symbol and the symbol layer have angle value set
360  bool ok;
361  double angle = angleFunc.toDouble( &ok );
362  if ( !ok )
363  {
364  // its a string (probably a property name or a function)
365  angleFunc = QString( "%1 + %2" ).arg( angleFunc ).arg( mAngle );
366  }
367  else if ( !qgsDoubleNear( angle + mAngle, 0.0 ) )
368  {
369  // it's a double value
370  angleFunc = QString::number( angle + mAngle );
371  }
372  }
373  QgsSymbolLayerV2Utils::createRotationElement( doc, graphicElem, angleFunc );
374 }
375 
377 {
378  QgsDebugMsg( "Entered." );
379 
380  QDomElement graphicElem = element.firstChildElement( "Graphic" );
381  if ( graphicElem.isNull() )
382  return NULL;
383 
384  QString name = "circle";
385  QColor fillColor, borderColor;
386  double borderWidth, size;
387  double widthHeightFactor = 1.0;
388  Qt::PenStyle borderStyle;
389 
390  QgsStringMap vendorOptions = QgsSymbolLayerV2Utils::getVendorOptionList( graphicElem );
391  for ( QgsStringMap::iterator it = vendorOptions.begin(); it != vendorOptions.end(); ++it )
392  {
393  if ( it.key() == "widthHeightFactor" )
394  {
395  bool ok;
396  double v = it.value().toDouble( &ok );
397  if ( ok && !qgsDoubleNear( v, 0.0 ) && v > 0 )
398  widthHeightFactor = v;
399  }
400  }
401 
402  if ( !QgsSymbolLayerV2Utils::wellKnownMarkerFromSld( graphicElem, name, fillColor, borderColor, borderStyle, borderWidth, size ) )
403  return NULL;
404 
405  double angle = 0.0;
406  QString angleFunc;
407  if ( QgsSymbolLayerV2Utils::rotationFromSldElement( graphicElem, angleFunc ) )
408  {
409  bool ok;
410  double d = angleFunc.toDouble( &ok );
411  if ( ok )
412  angle = d;
413  }
414 
416  m->setSymbolName( name );
417  m->setFillColor( fillColor );
418  m->setOutlineColor( borderColor );
419  m->setOutlineStyle( borderStyle );
420  m->setOutlineWidth( borderWidth );
421  m->setSymbolWidth( size );
422  m->setSymbolHeight( size / widthHeightFactor );
423  m->setAngle( angle );
424  return m;
425 }
426 
428 {
429  QgsStringMap map;
430  map["symbol_name"] = mSymbolName;
431  map["symbol_width"] = QString::number( mSymbolWidth );
432  map["symbol_width_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mSymbolWidthUnit );
433  map["symbol_width_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mSymbolWidthMapUnitScale );
434  map["symbol_height"] = QString::number( mSymbolHeight );
435  map["symbol_height_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mSymbolHeightUnit );
436  map["symbol_height_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mSymbolHeightMapUnitScale );
437  map["angle"] = QString::number( mAngle );
438  map["outline_style"] = QgsSymbolLayerV2Utils::encodePenStyle( mOutlineStyle );
439  map["outline_width"] = QString::number( mOutlineWidth );
440  map["outline_width_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOutlineWidthUnit );
441  map["outline_width_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOutlineWidthMapUnitScale );
442  map["color"] = QgsSymbolLayerV2Utils::encodeColor( mFillColor );
443  map["outline_color"] = QgsSymbolLayerV2Utils::encodeColor( mOutlineColor );
444  map["offset"] = QgsSymbolLayerV2Utils::encodePoint( mOffset );
446  map["offset_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOffsetMapUnitScale );
447  map["size"] = QString::number( mSize );
449  map["size_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mSizeMapUnitScale );
450  map["horizontal_anchor_point"] = QString::number( mHorizontalAnchorPoint );
451  map["vertical_anchor_point"] = QString::number( mVerticalAnchorPoint );
453  return map;
454 }
455 
456 void QgsEllipseSymbolLayerV2::preparePath( const QString& symbolName, QgsSymbolV2RenderContext& context, double* scaledWidth, double* scaledHeight, const QgsFeature* f )
457 {
458  mPainterPath = QPainterPath();
459  const QgsRenderContext& ct = context.renderContext();
460 
461  double width = 0;
462 
463  if ( hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_WIDTH ) ) //1. priority: data defined setting on symbol layer le
464  {
465  width = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_WIDTH, f, mSymbolWidth ).toDouble();
466  }
467  else if ( context.renderHints() & QgsSymbolV2::DataDefinedSizeScale ) //2. priority: is data defined size on symbol level
468  {
469  width = mSize;
470  }
471  else //3. priority: global width setting
472  {
473  width = mSymbolWidth;
474  }
475  if ( scaledWidth )
476  {
477  *scaledWidth = width;
478  }
479  width *= QgsSymbolLayerV2Utils::lineWidthScaleFactor( ct, mSymbolWidthUnit, mSymbolHeightMapUnitScale );
480 
481  double height = 0;
482  if ( hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_HEIGHT ) ) //1. priority: data defined setting on symbol layer level
483  {
484  height = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_HEIGHT, f, mSymbolHeight ).toDouble();
485  }
486  else if ( context.renderHints() & QgsSymbolV2::DataDefinedSizeScale ) //2. priority: is data defined size on symbol level
487  {
488  height = mSize;
489  }
490  else //3. priority: global height setting
491  {
492  height = mSymbolHeight;
493  }
494  if ( scaledHeight )
495  {
496  *scaledHeight = height;
497  }
498  height *= QgsSymbolLayerV2Utils::lineWidthScaleFactor( ct, mSymbolHeightUnit, mSymbolHeightMapUnitScale );
499 
500  if ( symbolName == "circle" )
501  {
502  mPainterPath.addEllipse( QRectF( -width / 2.0, -height / 2.0, width, height ) );
503  }
504  else if ( symbolName == "rectangle" )
505  {
506  mPainterPath.addRect( QRectF( -width / 2.0, -height / 2.0, width, height ) );
507  }
508  else if ( symbolName == "cross" )
509  {
510  mPainterPath.moveTo( 0, -height / 2.0 );
511  mPainterPath.lineTo( 0, height / 2.0 );
512  mPainterPath.moveTo( -width / 2.0, 0 );
513  mPainterPath.lineTo( width / 2.0, 0 );
514  }
515  else if ( symbolName == "triangle" )
516  {
517  mPainterPath.moveTo( 0, -height / 2.0 );
518  mPainterPath.lineTo( -width / 2.0, height / 2.0 );
519  mPainterPath.lineTo( width / 2.0, height / 2.0 );
520  mPainterPath.lineTo( 0, -height / 2.0 );
521  }
522 }
523 
525 {
527  mSymbolWidthUnit = unit;
528  mSymbolHeightUnit = unit;
529  mOutlineWidthUnit = unit;
530 }
531 
533 {
535  if ( mSymbolWidthUnit != unit || mSymbolHeightUnit != unit || mOutlineWidthUnit != unit )
536  {
537  return QgsSymbolV2::Mixed;
538  }
539  return unit;
540 }
541 
543 {
545  mSymbolWidthMapUnitScale = scale;
546  mSymbolHeightMapUnitScale = scale;
547  mOutlineWidthMapUnitScale = scale;
548 }
549 
551 {
552  if ( QgsMarkerSymbolLayerV2::mapUnitScale() == mSymbolWidthMapUnitScale &&
553  mSymbolWidthMapUnitScale == mSymbolHeightMapUnitScale &&
554  mSymbolHeightMapUnitScale == mOutlineWidthMapUnitScale )
555  {
556  return mSymbolWidthMapUnitScale;
557  }
558  return QgsMapUnitScale();
559 }
560 
561 bool QgsEllipseSymbolLayerV2::writeDxf( QgsDxfExport& e, double mmMapUnitScaleFactor, const QString& layerName, const QgsSymbolV2RenderContext* context, const QgsFeature* f, const QPointF& shift ) const
562 {
563  //width
564  double symbolWidth = mSymbolWidth;
565 
566  if ( hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_WIDTH ) ) //1. priority: data defined setting on symbol layer le
567  {
568  symbolWidth = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_WIDTH, f, mSymbolWidth ).toDouble();
569  }
570  else if ( context->renderHints() & QgsSymbolV2::DataDefinedSizeScale ) //2. priority: is data defined size on symbol level
571  {
572  symbolWidth = mSize;
573  }
574  if ( mSymbolWidthUnit == QgsSymbolV2::MM )
575  {
576  symbolWidth *= mmMapUnitScaleFactor;
577  }
578 
579  //height
580  double symbolHeight = mSymbolHeight;
581  if ( hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_HEIGHT ) ) //1. priority: data defined setting on symbol layer level
582  {
583  symbolHeight = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_HEIGHT, f, mSymbolHeight ).toDouble();
584  }
585  else if ( context->renderHints() & QgsSymbolV2::DataDefinedSizeScale ) //2. priority: is data defined size on symbol level
586  {
587  symbolHeight = mSize;
588  }
589  if ( mSymbolHeightUnit == QgsSymbolV2::MM )
590  {
591  symbolHeight *= mmMapUnitScaleFactor;
592  }
593 
594  //outline width
595  double outlineWidth = mOutlineWidth;
596 
598  {
599  outlineWidth = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_OUTLINE_WIDTH, f, mOutlineWidth ).toDouble();
600  }
601  if ( mOutlineWidthUnit == QgsSymbolV2::MM )
602  {
603  outlineWidth *= outlineWidth;
604  }
605 
606  //fill color
607  bool ok;
608  QColor fc = mFillColor;
610  {
611  QString colorString = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_FILL_COLOR, f, QVariant(), &ok ).toString();
612  if ( ok )
613  fc = QColor( colorString );
614  }
615 
616  //outline color
617  QColor oc = mOutlineColor;
619  {
620  QString colorString = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_OUTLINE_COLOR, f, QVariant(), &ok ).toString();
621  if ( ok )
622  oc = QColor( colorString );
623  }
624 
625  //symbol name
626  QString symbolName = mSymbolName;
628  {
629  symbolName = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_SYMBOL_NAME, f, mSymbolName ).toString();
630  }
631 
632  //offset
633  double offsetX = 0;
634  double offsetY = 0;
635  markerOffset( *context, offsetX, offsetY );
636  QPointF off( offsetX, offsetY );
637 
638  //priority for rotation: 1. data defined symbol level, 2. symbol layer rotation (mAngle)
639  double rotation = 0.0;
641  {
643  }
644  else if ( !qgsDoubleNear( mAngle + mLineAngle, 0.0 ) )
645  {
646  rotation = mAngle + mLineAngle;
647  }
648  rotation = -rotation; //rotation in Qt is counterclockwise
649  if ( rotation )
650  off = _rotatedOffset( off, rotation );
651 
652  QTransform t;
653  t.translate( shift.x() + offsetX, shift.y() + offsetY );
654 
655  if ( rotation != 0 )
656  t.rotate( rotation );
657 
658  double halfWidth = symbolWidth / 2.0;
659  double halfHeight = symbolHeight / 2.0;
660 
661  if ( symbolName == "circle" )
662  {
663  if ( qgsDoubleNear( halfWidth, halfHeight ) )
664  {
665  QPointF pt( t.map( QPointF( 0, 0 ) ) );
666  e.writeFilledCircle( layerName, oc, pt, halfWidth );
667  }
668  else
669  {
670  QgsPolyline line;
671  double stepsize = 2 * M_PI / 40;
672  for ( int i = 0; i < 39; ++i )
673  {
674  double angle = stepsize * i;
675  double x = halfWidth * cos( angle );
676  double y = halfHeight * sin( angle );
677  QPointF pt( t.map( QPointF( x, y ) ) );
678  line.push_back( pt );
679  }
680  //close ellipse with first point
681  line.push_back( line.at( 0 ) );
682  if ( mBrush.style() != Qt::NoBrush )
683  e.writePolygon( QgsPolygon() << line, layerName, "SOLID", fc );
684  if ( mPen.style() != Qt::NoPen )
685  e.writePolyline( line, layerName, "CONTINUOUS", oc, outlineWidth );
686  }
687  }
688  else if ( symbolName == "rectangle" )
689  {
690  QPointF pt1( t.map( QPointF( -halfWidth, -halfHeight ) ) );
691  QPointF pt2( t.map( QPointF( halfWidth, -halfHeight ) ) );
692  QPointF pt3( t.map( QPointF( -halfWidth, halfHeight ) ) );
693  QPointF pt4( t.map( QPointF( halfWidth, halfHeight ) ) );
694  if ( mBrush.style() != Qt::NoBrush )
695  e.writeSolid( layerName, fc, pt1, pt2, pt3, pt4 );
696  QgsPolyline line( 5 );
697  line[0] = pt1;
698  line[1] = pt2;
699  line[2] = pt3;
700  line[3] = pt4;
701  line[4] = pt1;
702  if ( mPen.style() != Qt::NoPen )
703  e.writePolyline( line, layerName, "CONTINUOUS", oc, outlineWidth );
704  return true;
705  }
706  else if ( symbolName == "cross" && mPen.style() != Qt::NoPen )
707  {
708  QgsPolyline line1( 2 );
709  QPointF pt1( t.map( QPointF( -halfWidth, 0 ) ) );
710  QPointF pt2( t.map( QPointF( halfWidth, 0 ) ) );
711  line1[0] = pt1;
712  line1[1] = pt2;
713  e.writePolyline( line1, layerName, "CONTINUOUS", oc, outlineWidth );
714  QgsPolyline line2( 2 );
715  QPointF pt3( t.map( QPointF( 0, halfHeight ) ) );
716  QPointF pt4( t.map( QPointF( 0, -halfHeight ) ) );
717  line2[0] = pt3;
718  line2[1] = pt4;
719  e.writePolyline( line2, layerName, "CONTINUOUS", oc, outlineWidth );
720  return true;
721  }
722  else if ( symbolName == "triangle" )
723  {
724  QPointF pt1( t.map( QPointF( -halfWidth, -halfHeight ) ) );
725  QPointF pt2( t.map( QPointF( halfWidth, -halfHeight ) ) );
726  QPointF pt3( t.map( QPointF( 0, halfHeight ) ) );
727  QPointF pt4( t.map( QPointF( 0, halfHeight ) ) );
728  if ( mBrush.style() != Qt::NoBrush )
729  e.writeSolid( layerName, fc, pt1, pt2, pt3, pt4 );
730  if ( mPen.style() != Qt::NoPen )
731  {
732  QgsPolyline line( 4 );
733  line[0] = pt1;
734  line[1] = pt2;
735  line[2] = pt3;
736  line[3] = pt4;
737  e.writePolyline( line, layerName, "CONTINUOUS", oc, outlineWidth );
738  }
739  return true;
740  }
741 
742  return false; //soon...
743 }
744 
745