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