QGIS API Documentation  2.5.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 "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  if ( properties.contains( "outline_width" ) )
86  {
87  layer->setOutlineWidth( properties["outline_width"].toDouble() );
88  }
89  if ( properties.contains( "outline_width_unit" ) )
90  {
91  layer->setOutlineWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["outline_width_unit"] ) );
92  }
93  if ( properties.contains( "outline_width_map_unit_scale" ) )
94  {
95  layer->setOutlineWidthMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( properties["outline_width_map_unit_scale"] ) );
96  }
97  if ( properties.contains( "fill_color" ) )
98  {
99  layer->setFillColor( QgsSymbolLayerV2Utils::decodeColor( properties["fill_color"] ) );
100  }
101  if ( properties.contains( "outline_color" ) )
102  {
103  layer->setOutlineColor( QgsSymbolLayerV2Utils::decodeColor( properties["outline_color"] ) );
104  }
105  if ( properties.contains( "size" ) )
106  {
107  layer->setSize( properties["size"].toDouble() );
108  }
109  if ( properties.contains( "size_unit" ) )
110  {
111  layer->setSizeUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["size_unit"] ) );
112  }
113  if ( properties.contains( "size_map_unit_scale" ) )
114  {
115  layer->setSizeMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( properties["size_map_unit_scale"] ) );
116  }
117  if ( properties.contains( "offset" ) )
118  {
119  layer->setOffset( QgsSymbolLayerV2Utils::decodePoint( properties["offset"] ) );
120  }
121  if ( properties.contains( "offset_unit" ) )
122  {
123  layer->setOffsetUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["offset_unit"] ) );
124  }
125  if ( properties.contains( "offset_map_unit_scale" ) )
126  {
127  layer->setOffsetMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( properties["offset_map_unit_scale"] ) );
128  }
129  if ( properties.contains( "horizontal_anchor_point" ) )
130  {
131  layer->setHorizontalAnchorPoint( QgsMarkerSymbolLayerV2::HorizontalAnchorPoint( properties[ "horizontal_anchor_point" ].toInt() ) );
132  }
133  if ( properties.contains( "vertical_anchor_point" ) )
134  {
135  layer->setVerticalAnchorPoint( QgsMarkerSymbolLayerV2::VerticalAnchorPoint( properties[ "vertical_anchor_point" ].toInt() ) );
136  }
137 
138  //data defined properties
139  if ( properties.contains( "width_expression" ) )
140  {
141  layer->setDataDefinedProperty( "width", properties["width_expression"] );
142  }
143  if ( properties.contains( "height_expression" ) )
144  {
145  layer->setDataDefinedProperty( "height", properties["height_expression"] );
146  }
147  if ( properties.contains( "rotation_expression" ) )
148  {
149  layer->setDataDefinedProperty( "rotation", properties["rotation_expression"] );
150  }
151  if ( properties.contains( "outline_width_expression" ) )
152  {
153  layer->setDataDefinedProperty( "outline_width", properties[ "outline_width_expression" ] );
154  }
155  if ( properties.contains( "fill_color_expression" ) )
156  {
157  layer->setDataDefinedProperty( "fill_color", properties["fill_color_expression"] );
158  }
159  if ( properties.contains( "outline_color_expression" ) )
160  {
161  layer->setDataDefinedProperty( "outline_color", properties["outline_color_expression"] );
162  }
163  if ( properties.contains( "symbol_name_expression" ) )
164  {
165  layer->setDataDefinedProperty( "symbol_name", properties["symbol_name_expression"] );
166  }
167  if ( properties.contains( "offset_expression" ) )
168  {
169  layer->setDataDefinedProperty( "offset", properties["offset_expression"] );
170  }
171  if ( properties.contains( "horizontal_anchor_point_expression" ) )
172  {
173  layer->setDataDefinedProperty( "horizontal_anchor_point", properties[ "horizontal_anchor_point_expression" ] );
174  }
175  if ( properties.contains( "vertical_anchor_point_expression" ) )
176  {
177  layer->setDataDefinedProperty( "vertical_anchor_point", properties[ "vertical_anchor_point_expression" ] );
178  }
179 
180  //compatibility with old project file format
181  if ( !properties["width_field"].isEmpty() )
182  {
183  layer->setDataDefinedProperty( "width", properties["width_field"] );
184  }
185  if ( !properties["height_field"].isEmpty() )
186  {
187  layer->setDataDefinedProperty( "height", properties["height_field"] );
188  }
189  if ( !properties["rotation_field"].isEmpty() )
190  {
191  layer->setDataDefinedProperty( "rotation", properties["rotation_field"] );
192  }
193  if ( !properties["outline_width_field"].isEmpty() )
194  {
195  layer->setDataDefinedProperty( "outline_width", properties[ "outline_width_field" ] );
196  }
197  if ( !properties["fill_color_field"].isEmpty() )
198  {
199  layer->setDataDefinedProperty( "fill_color", properties["fill_color_field"] );
200  }
201  if ( !properties["outline_color_field"].isEmpty() )
202  {
203  layer->setDataDefinedProperty( "outline_color", properties["outline_color_field"] );
204  }
205  if ( !properties["symbol_name_field"].isEmpty() )
206  {
207  layer->setDataDefinedProperty( "symbol_name", properties["symbol_name_field"] );
208  }
209 
210  return layer;
211 }
212 
214 {
215  QgsExpression* outlineWidthExpression = expression( "outline_width" );
216  QgsExpression* fillColorExpression = expression( "fill_color" );
217  QgsExpression* outlineColorExpression = expression( "outline_color" );
218  QgsExpression* widthExpression = expression( "width" );
219  QgsExpression* heightExpression = expression( "height" );
220  QgsExpression* symbolNameExpression = expression( "symbol_name" );
221  QgsExpression* rotationExpression = expression( "rotation" );
222 
223  if ( outlineWidthExpression )
224  {
225  double width = outlineWidthExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
227  mPen.setWidthF( width );
228  }
229  if ( fillColorExpression )
230  {
231  QString colorString = fillColorExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString();
232  mBrush.setColor( QColor( QgsSymbolLayerV2Utils::decodeColor( colorString ) ) );
233  }
234  if ( outlineColorExpression )
235  {
236  QString colorString = outlineColorExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString();
237  mPen.setColor( QColor( QgsSymbolLayerV2Utils::decodeColor( colorString ) ) );
238  }
239  double scaledWidth = mSymbolWidth;
240  double scaledHeight = mSymbolHeight;
241  if ( widthExpression || heightExpression || symbolNameExpression )
242  {
243  QString symbolName = mSymbolName;
244  if ( symbolNameExpression )
245  {
246  symbolName = symbolNameExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString();
247  }
248  preparePath( symbolName, context, &scaledWidth, &scaledHeight, context.feature() );
249  }
250 
251  //offset
252  double offsetX = 0;
253  double offsetY = 0;
254  markerOffset( context, scaledWidth, scaledHeight, mSymbolWidthUnit, mSymbolHeightUnit, offsetX, offsetY, mSymbolWidthMapUnitScale, mSymbolHeightMapUnitScale );
255  QPointF off( offsetX, offsetY );
256 
257  QPainter* p = context.renderContext().painter();
258  if ( !p )
259  {
260  return;
261  }
262 
263  //priority for rotation: 1. data defined symbol level, 2. symbol layer rotation (mAngle)
264  double rotation = 0.0;
265  if ( rotationExpression )
266  {
267  rotation = rotationExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
268  }
269  else if ( !qgsDoubleNear( mAngle, 0.0 ) )
270  {
271  rotation = mAngle;
272  }
273  if ( rotation )
274  off = _rotatedOffset( off, rotation );
275 
276  QMatrix transform;
277  transform.translate( point.x() + off.x(), point.y() + off.y() );
278  if ( !qgsDoubleNear( rotation, 0.0 ) )
279  {
280  transform.rotate( rotation );
281  }
282 
283  p->setPen( mPen );
284  p->setBrush( mBrush );
285  p->drawPath( transform.map( mPainterPath ) );
286 }
287 
289 {
290  return "EllipseMarker";
291 }
292 
294 {
295  QgsMarkerSymbolLayerV2::startRender( context ); // get anchor point expressions
296  if ( !context.feature() || !hasDataDefinedProperty() )
297  {
298  preparePath( mSymbolName, context );
299  }
300  mPen.setColor( mOutlineColor );
301  mPen.setStyle( mOutlineStyle );
303  mBrush.setColor( mFillColor );
304  prepareExpressions( context.fields(), context.renderContext().rendererScale() );
305 }
306 
308 {
309 }
310 
312 {
314 }
315 
316 void QgsEllipseSymbolLayerV2::toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
317 {
318  QDomElement symbolizerElem = doc.createElement( "se:PointSymbolizer" );
319  if ( !props.value( "uom", "" ).isEmpty() )
320  symbolizerElem.setAttribute( "uom", props.value( "uom", "" ) );
321  element.appendChild( symbolizerElem );
322 
323  // <Geometry>
324  QgsSymbolLayerV2Utils::createGeometryElement( doc, symbolizerElem, props.value( "geom", "" ) );
325 
326  writeSldMarker( doc, symbolizerElem, props );
327 }
328 
329 void QgsEllipseSymbolLayerV2::writeSldMarker( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
330 {
331  // <Graphic>
332  QDomElement graphicElem = doc.createElement( "se:Graphic" );
333  element.appendChild( graphicElem );
334 
336 
337  // store w/h factor in a <VendorOption>
338  double widthHeightFactor = mSymbolWidth / mSymbolHeight;
339  QDomElement factorElem = QgsSymbolLayerV2Utils::createVendorOptionElement( doc, "widthHeightFactor", QString::number( widthHeightFactor ) );
340  graphicElem.appendChild( factorElem );
341 
342  // <Rotation>
343  const QgsExpression* rotationExpression = dataDefinedProperty( "rotation" );
344  QString angleFunc = props.value( "angle", "" );
345  if ( angleFunc.isEmpty() ) // symbol has no angle set
346  {
347 
348  if ( rotationExpression )
349  angleFunc = rotationExpression->expression();
350  else if ( !qgsDoubleNear( mAngle, 0.0 ) )
351  angleFunc = QString::number( mAngle );
352  }
353  else if ( rotationExpression )
354  {
355  // the symbol has an angle and the symbol layer have a rotation
356  // property set
357  angleFunc = QString( "%1 + %2" ).arg( angleFunc ).arg( rotationExpression->expression() );
358  }
359  else if ( !qgsDoubleNear( mAngle, 0.0 ) )
360  {
361  // both the symbol and the symbol layer have angle value set
362  bool ok;
363  double angle = angleFunc.toDouble( &ok );
364  if ( !ok )
365  {
366  // its a string (probably a property name or a function)
367  angleFunc = QString( "%1 + %2" ).arg( angleFunc ).arg( mAngle );
368  }
369  else if ( !qgsDoubleNear( angle + mAngle, 0.0 ) )
370  {
371  // it's a double value
372  angleFunc = QString::number( angle + mAngle );
373  }
374  }
375  QgsSymbolLayerV2Utils::createRotationElement( doc, graphicElem, angleFunc );
376 }
377 
379 {
380  QgsDebugMsg( "Entered." );
381 
382  QDomElement graphicElem = element.firstChildElement( "Graphic" );
383  if ( graphicElem.isNull() )
384  return NULL;
385 
386  QString name = "circle";
387  QColor fillColor, borderColor;
388  double borderWidth, size;
389  double widthHeightFactor = 1.0;
390  Qt::PenStyle borderStyle;
391 
392  QgsStringMap vendorOptions = QgsSymbolLayerV2Utils::getVendorOptionList( graphicElem );
393  for ( QgsStringMap::iterator it = vendorOptions.begin(); it != vendorOptions.end(); ++it )
394  {
395  if ( it.key() == "widthHeightFactor" )
396  {
397  bool ok;
398  double v = it.value().toDouble( &ok );
399  if ( ok && !qgsDoubleNear( v, 0.0 ) && v > 0 )
400  widthHeightFactor = v;
401  }
402  }
403 
404  if ( !QgsSymbolLayerV2Utils::wellKnownMarkerFromSld( graphicElem, name, fillColor, borderColor, borderStyle, borderWidth, size ) )
405  return NULL;
406 
407  double angle = 0.0;
408  QString angleFunc;
409  if ( QgsSymbolLayerV2Utils::rotationFromSldElement( graphicElem, angleFunc ) )
410  {
411  bool ok;
412  double d = angleFunc.toDouble( &ok );
413  if ( ok )
414  angle = d;
415  }
416 
418  m->setSymbolName( name );
419  m->setFillColor( fillColor );
420  m->setOutlineColor( borderColor );
421  m->setOutlineStyle( borderStyle );
422  m->setOutlineWidth( borderWidth );
423  m->setSymbolWidth( size );
424  m->setSymbolHeight( size / widthHeightFactor );
425  m->setAngle( angle );
426  return m;
427 }
428 
430 {
431  QgsStringMap map;
432  map["symbol_name"] = mSymbolName;
433  map["symbol_width"] = QString::number( mSymbolWidth );
434  map["symbol_width_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mSymbolWidthUnit );
435  map["symbol_width_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mSymbolWidthMapUnitScale );
436  map["symbol_height"] = QString::number( mSymbolHeight );
437  map["symbol_height_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mSymbolHeightUnit );
438  map["symbol_height_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mSymbolHeightMapUnitScale );
439  map["angle"] = QString::number( mAngle );
440  map["outline_style"] = QgsSymbolLayerV2Utils::encodePenStyle( mOutlineStyle );
441  map["outline_width"] = QString::number( mOutlineWidth );
442  map["outline_width_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOutlineWidthUnit );
443  map["outline_width_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOutlineWidthMapUnitScale );
444  map["fill_color"] = QgsSymbolLayerV2Utils::encodeColor( mFillColor );
445  map["outline_color"] = QgsSymbolLayerV2Utils::encodeColor( mOutlineColor );
446  map["offset"] = QgsSymbolLayerV2Utils::encodePoint( mOffset );
448  map["offset_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOffsetMapUnitScale );
449  map["size"] = QString::number( mSize );
451  map["size_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mSizeMapUnitScale );
452  map["horizontal_anchor_point"] = QString::number( mHorizontalAnchorPoint );
453  map["vertical_anchor_point"] = QString::number( mVerticalAnchorPoint );
455  return map;
456 }
457 
459 {
460  return ( dataDefinedProperty( "width" ) || dataDefinedProperty( "height" ) || dataDefinedProperty( "rotation" )
461  || dataDefinedProperty( "outline_width" ) || dataDefinedProperty( "fill_color" ) || dataDefinedProperty( "outline_color" )
462  || dataDefinedProperty( "symbol_name" ) || dataDefinedProperty( "offset" ) );
463 }
464 
465 void QgsEllipseSymbolLayerV2::preparePath( const QString& symbolName, QgsSymbolV2RenderContext& context, double* scaledWidth, double* scaledHeight, const QgsFeature* f )
466 {
467  mPainterPath = QPainterPath();
468  const QgsRenderContext& ct = context.renderContext();
469 
470  double width = 0;
471 
472  QgsExpression* widthExpression = expression( "width" );
473  if ( widthExpression ) //1. priority: data defined setting on symbol layer level
474  {
475  width = widthExpression->evaluate( const_cast<QgsFeature*>( f ) ).toDouble();
476  }
477  else if ( context.renderHints() & QgsSymbolV2::DataDefinedSizeScale ) //2. priority: is data defined size on symbol level
478  {
479  width = mSize;
480  }
481  else //3. priority: global width setting
482  {
483  width = mSymbolWidth;
484  }
485  if ( scaledWidth )
486  {
487  *scaledWidth = width;
488  }
490 
491  double height = 0;
492  QgsExpression* heightExpression = expression( "height" );
493  if ( heightExpression ) //1. priority: data defined setting on symbol layer level
494  {
495  height = heightExpression->evaluate( const_cast<QgsFeature*>( f ) ).toDouble();
496  }
497  else if ( context.renderHints() & QgsSymbolV2::DataDefinedSizeScale ) //2. priority: is data defined size on symbol level
498  {
499  height = mSize;
500  }
501  else //3. priority: global height setting
502  {
503  height = mSymbolHeight;
504  }
505  if ( scaledHeight )
506  {
507  *scaledHeight = height;
508  }
510 
511  if ( symbolName == "circle" )
512  {
513  mPainterPath.addEllipse( QRectF( -width / 2.0, -height / 2.0, width, height ) );
514  }
515  else if ( symbolName == "rectangle" )
516  {
517  mPainterPath.addRect( QRectF( -width / 2.0, -height / 2.0, width, height ) );
518  }
519  else if ( symbolName == "cross" )
520  {
521  mPainterPath.moveTo( 0, -height / 2.0 );
522  mPainterPath.lineTo( 0, height / 2.0 );
523  mPainterPath.moveTo( -width / 2.0, 0 );
524  mPainterPath.lineTo( width / 2.0, 0 );
525  }
526  else if ( symbolName == "triangle" )
527  {
528  mPainterPath.moveTo( 0, -height / 2.0 );
529  mPainterPath.lineTo( -width / 2.0, height / 2.0 );
530  mPainterPath.lineTo( width / 2.0, height / 2.0 );
531  mPainterPath.lineTo( 0, -height / 2.0 );
532  }
533 }
534 
536 {
538  mSymbolWidthUnit = unit;
539  mSymbolHeightUnit = unit;
540  mOutlineWidthUnit = unit;
541 }
542 
544 {
546  if ( mSymbolWidthUnit != unit || mSymbolHeightUnit != unit || mOutlineWidthUnit != unit )
547  {
548  return QgsSymbolV2::Mixed;
549  }
550  return unit;
551 }
552 
554 {
556  mSymbolWidthMapUnitScale = scale;
559 }
560 
562 {
566  {
568  }
569  return QgsMapUnitScale();
570 }
571 
572 bool QgsEllipseSymbolLayerV2::writeDxf( QgsDxfExport& e, double mmMapUnitScaleFactor, const QString& layerName, const QgsSymbolV2RenderContext* context, const QgsFeature* f, const QPointF& shift ) const
573 {
574  //width
575  double symbolWidth = mSymbolWidth;
576  QgsExpression* widthExpression = expression( "width" );
577  if ( widthExpression ) //1. priority: data defined setting on symbol layer level
578  {
579  symbolWidth = widthExpression->evaluate( const_cast<QgsFeature*>( f ) ).toDouble();
580  }
581  else if ( context->renderHints() & QgsSymbolV2::DataDefinedSizeScale ) //2. priority: is data defined size on symbol level
582  {
583  symbolWidth = mSize;
584  }
586  {
587  symbolWidth *= mmMapUnitScaleFactor;
588  }
589 
590  //height
591  double symbolHeight = mSymbolHeight;
592  QgsExpression* heightExpression = expression( "height" );
593  if ( heightExpression ) //1. priority: data defined setting on symbol layer level
594  {
595  symbolHeight = heightExpression->evaluate( const_cast<QgsFeature*>( f ) ).toDouble();
596  }
597  else if ( context->renderHints() & QgsSymbolV2::DataDefinedSizeScale ) //2. priority: is data defined size on symbol level
598  {
599  symbolHeight = mSize;
600  }
602  {
603  symbolHeight *= mmMapUnitScaleFactor;
604  }
605 
606  //outline width
607  double outlineWidth = mOutlineWidth;
608  QgsExpression* outlineWidthExpression = expression( "outline_width" );
609  if ( outlineWidthExpression )
610  {
611  outlineWidth = outlineWidthExpression->evaluate( const_cast<QgsFeature*>( context->feature() ) ).toDouble();
612  }
614  {
615  outlineWidth *= outlineWidth;
616  }
617 
618  //fill color
619  QColor fc = mFillColor;
620  QgsExpression* fillColorExpression = expression( "fill_color" );
621  if ( fillColorExpression )
622  {
623  fc = QColor( fillColorExpression->evaluate( const_cast<QgsFeature*>( context->feature() ) ).toString() );
624  }
625  int fillColorIndex = e.closestColorMatch( fc.rgb() );
626 
627  //outline color
628  QColor oc = mOutlineColor;
629  QgsExpression* outlineColorExpression = expression( "outline_color" );
630  if ( outlineColorExpression )
631  {
632  oc = QColor( outlineColorExpression->evaluate( const_cast<QgsFeature*>( context->feature() ) ).toString() );
633  }
634  int outlineColorIndex = e.closestColorMatch( oc.rgb() );
635 
636 
637  //symbol name
638  QString symbolName = mSymbolName;
639  QgsExpression* symbolNameExpression = expression( "symbol_name" );
640  if ( symbolNameExpression )
641  {
642  QgsExpression* symbolNameExpression = expression( "symbol_name" );
643  symbolName = symbolNameExpression->evaluate( const_cast<QgsFeature*>( context->feature() ) ).toString();
644  }
645 
646  //offset
647  double offsetX = 0;
648  double offsetY = 0;
649  markerOffset( *context, offsetX, offsetY );
650  QPointF off( offsetX, offsetY );
651 
652  //priority for rotation: 1. data defined symbol level, 2. symbol layer rotation (mAngle)
653  double rotation = 0.0;
654  QgsExpression* rotationExpression = expression( "rotation" );
655  if ( rotationExpression )
656  {
657  rotation = rotationExpression->evaluate( const_cast<QgsFeature*>( context->feature() ) ).toDouble();
658  }
659  else if ( !qgsDoubleNear( mAngle, 0.0 ) )
660  {
661  rotation = mAngle;
662  }
663  rotation = -rotation; //rotation in Qt is counterclockwise
664  if ( rotation )
665  off = _rotatedOffset( off, rotation );
666 
667  QTransform t;
668  t.translate( shift.x() + offsetX, shift.y() + offsetY );
669 
670  if ( rotation != 0 )
671  t.rotate( rotation );
672 
673  double halfWidth = symbolWidth / 2.0;
674  double halfHeight = symbolHeight / 2.0;
675 
676  if ( symbolName == "circle" )
677  {
678  if ( qgsDoubleNear( halfWidth, halfHeight ) )
679  {
680  QPointF pt( t.map( QPointF( 0, 0 ) ) );
681  e.writeCircle( layerName, outlineColorIndex, QgsPoint( pt.x(), pt.y() ), halfWidth );
682  }
683  else
684  {
685  QgsPolyline line;
686  double stepsize = 2 * M_PI / 40;
687  for ( int i = 0; i < 39; ++i )
688  {
689  double angle = stepsize * i;
690  double x = halfWidth * cos( angle );
691  double y = halfHeight * sin( angle );
692  QPointF pt( t.map( QPointF( x, y ) ) );
693  line.push_back( QgsPoint( pt.x(), pt.y() ) );
694  }
695  //close ellipse with first point
696  line.push_back( line.at( 0 ) );
697  e.writePolyline( line, layerName, "solid", outlineColorIndex, outlineWidth, true );
698  }
699  }
700  else if ( symbolName == "rectangle" )
701  {
702  QPointF pt1( t.map( QPointF( -halfWidth, -halfHeight ) ) );
703  QPointF pt2( t.map( QPointF( halfWidth, -halfHeight ) ) );
704  QPointF pt3( t.map( QPointF( -halfWidth, halfHeight ) ) );
705  QPointF pt4( t.map( QPointF( halfWidth, halfHeight ) ) );
706  e.writeSolid( layerName, fillColorIndex, QgsPoint( pt1.x(), pt1.y() ), QgsPoint( pt2.x(), pt2.y() ), QgsPoint( pt3.x(), pt3.y() ), QgsPoint( pt4.x(), pt4.y() ) );
707  return true;
708  }
709  else if ( symbolName == "cross" )
710  {
711  QgsPolyline line1( 2 );
712  QPointF pt1( t.map( QPointF( -halfWidth, 0 ) ) );
713  QPointF pt2( t.map( QPointF( halfWidth, 0 ) ) );
714  line1[0] = QgsPoint( pt1.x(), pt1.y() );
715  line1[1] = QgsPoint( pt2.x(), pt2.y() );
716  e.writePolyline( line1, layerName, "CONTINUOUS", outlineColorIndex, outlineWidth, false );
717  QgsPolyline line2( 2 );
718  QPointF pt3( t.map( QPointF( 0, halfHeight ) ) );
719  QPointF pt4( t.map( QPointF( 0, -halfHeight ) ) );
720  line2[0] = QgsPoint( pt3.x(), pt3.y() );
721  line2[1] = QgsPoint( pt4.x(), pt4.y() );
722  e.writePolyline( line2, layerName, "CONTINUOUS", outlineColorIndex, outlineWidth, false );
723  return true;
724  }
725  else if ( symbolName == "triangle" )
726  {
727  QPointF pt1( t.map( QPointF( -halfWidth, -halfHeight ) ) );
728  QPointF pt2( t.map( QPointF( halfWidth, -halfHeight ) ) );
729  QPointF pt3( t.map( QPointF( 0, halfHeight ) ) );
730  QPointF pt4( t.map( QPointF( 0, halfHeight ) ) );
731  e.writeSolid( layerName, fillColorIndex, QgsPoint( pt1.x(), pt1.y() ), QgsPoint( pt2.x(), pt2.y() ), QgsPoint( pt3.x(), pt3.y() ), QgsPoint( pt4.x(), pt4.y() ) );
732  return true;
733  }
734 
735  return false; //soon...
736 }
737 
738 
void writeCircle(const QString &layer, int color, const QgsPoint &pt, double radius)
static QString encodeOutputUnit(QgsSymbolV2::OutputUnit unit)
Class for parsing and evaluation of expressions (formerly called "search strings").
Definition: qgsexpression.h:89
void setSymbolWidthUnit(QgsSymbolV2::OutputUnit unit)
void setOutputUnit(QgsSymbolV2::OutputUnit unit)
int renderHints() const
Definition: qgssymbolv2.h:187
QgsMapUnitScale mSizeMapUnitScale
bool writeDxf(QgsDxfExport &e, double mmMapUnitScaleFactor, const QString &layerName, const QgsSymbolV2RenderContext *context, const QgsFeature *f, const QPointF &shift=QPointF(0.0, 0.0)) const
QgsSymbolV2::OutputUnit outputUnit() const
QColor fillColor() const
Get fill color.
static Q_DECL_DEPRECATED bool wellKnownMarkerFromSld(QDomElement &element, QString &name, QColor &color, QColor &borderColor, double &borderWidth, double &size)
QgsSymbolV2::OutputUnit mOutlineWidthUnit
const QString expression() const
Alias for dump()
void setMapUnitScale(const QgsMapUnitScale &scale)
QgsSymbolV2::OutputUnit mSymbolHeightUnit
QVariant evaluate(const QgsFeature *f=NULL)
Evaluate the feature and return the result.
#define QgsDebugMsg(str)
Definition: qgslogger.h:36
void startRender(QgsSymbolV2RenderContext &context)
QgsSymbolV2::OutputUnit mSymbolWidthUnit
static void createRotationElement(QDomDocument &doc, QDomElement &element, QString rotationFunc)
double rendererScale() const
QVector< QgsPoint > QgsPolyline
polyline is represented as a vector of points
Definition: qgsgeometry.h:38
QgsSymbolV2::OutputUnit outputUnit() const
static QgsStringMap getVendorOptionList(QDomElement &element)
void setOffset(QPointF offset)
void setOutlineWidthUnit(QgsSymbolV2::OutputUnit unit)
void setHorizontalAnchorPoint(HorizontalAnchorPoint h)
void toSld(QDomDocument &doc, QDomElement &element, QgsStringMap props) const
static QPointF decodePoint(QString str)
void setVerticalAnchorPoint(VerticalAnchorPoint v)
static QDomElement createVendorOptionElement(QDomDocument &doc, QString name, QString value)
static QColor decodeColor(QString str)
static QString encodeMapUnitScale(const QgsMapUnitScale &mapUnitScale)
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:113
void setOffsetMapUnitScale(const QgsMapUnitScale &scale)
void renderPoint(const QPointF &point, QgsSymbolV2RenderContext &context)
void setOutputUnit(QgsSymbolV2::OutputUnit unit)
static int closestColorMatch(QRgb pixel)
A symbol layer for rendering objects with major and minor axis (e.g.
QMap< QString, QString > QgsStringMap
Definition: qgis.h:416
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
Definition: qgis.h:324
void writePolyline(const QgsPolyline &line, const QString &layer, const QString &lineStyleName, int color, double width=-1, bool polygon=false)
QgsMapUnitScale mOutlineWidthMapUnitScale
void setOffsetUnit(QgsSymbolV2::OutputUnit unit)
static QString encodeColor(QColor color)
virtual QgsExpression * expression(const QString &property) const
static QString encodePenStyle(Qt::PenStyle style)
void preparePath(const QString &symbolName, QgsSymbolV2RenderContext &context, double *scaledWidth=0, double *scaledHeight=0, const QgsFeature *f=0)
Setup mPainterPath.
void setSymbolHeightMapUnitScale(const QgsMapUnitScale &scale)
void setMapUnitScale(const QgsMapUnitScale &scale)
const QgsFeature * feature() const
Current feature being rendered - may be null.
Definition: qgssymbolv2.h:193
static QString encodePoint(QPointF point)
void setFillColor(const QColor &c)
Set fill color.
static Qt::PenStyle decodePenStyle(QString str)
#define M_PI
void setSizeUnit(QgsSymbolV2::OutputUnit unit)
void writeSolid(const QString &layer, int color, const QgsPoint &pt1, const QgsPoint &pt2, const QgsPoint &pt3, const QgsPoint &pt4)
HorizontalAnchorPoint mHorizontalAnchorPoint
void setOutlineStyle(Qt::PenStyle outlineStyle)
void setSymbolName(const QString &name)
virtual void prepareExpressions(const QgsFields *fields, double scale=-1.0)
QgsMapUnitScale mSymbolWidthMapUnitScale
A class to represent a point geometry.
Definition: qgspoint.h:63
QgsMapUnitScale mapUnitScale() const
static QgsSymbolLayerV2 * create(const QgsStringMap &properties=QgsStringMap())
bool hasDataDefinedProperty() const
True if this symbol layer uses a data defined property.
static void createGeometryElement(QDomDocument &doc, QDomElement &element, QString geomFunc)
Contains information about the context of a rendering operation.
void startRender(QgsSymbolV2RenderContext &context)
QPainter * painter()
static QgsSymbolLayerV2 * createFromSld(QDomElement &element)
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 setSymbolWidthMapUnitScale(const QgsMapUnitScale &scale)
QgsSymbolLayerV2 * clone() const
void writeSldMarker(QDomDocument &doc, QDomElement &element, QgsStringMap props) const
virtual const QgsExpression * dataDefinedProperty(const QString &property) const
QgsRenderContext & renderContext()
Definition: qgssymbolv2.h:168
void stopRender(QgsSymbolV2RenderContext &context)
QgsMapUnitScale mapUnitScale() const
static Q_DECL_DEPRECATED void wellKnownMarkerToSld(QDomDocument &doc, QDomElement &element, QString name, QColor color, QColor borderColor=QColor(), double borderWidth=-1, double size=-1)
const QgsFields * fields() const
Fields of the layer.
Definition: qgssymbolv2.h:199
QgsSymbolV2::OutputUnit mOffsetUnit
static bool rotationFromSldElement(QDomElement &element, QString &rotationFunc)
VerticalAnchorPoint mVerticalAnchorPoint
QgsSymbolV2::OutputUnit mSizeUnit
QgsMapUnitScale mOffsetMapUnitScale
void markerOffset(const QgsSymbolV2RenderContext &context, double &offsetX, double &offsetY) const
static QgsMapUnitScale decodeMapUnitScale(const QString &str)
void setSize(double size)
void setAngle(double angle)
QgsStringMap properties() const
void saveDataDefinedProperties(QgsStringMap &stringMap) const
Saves data defined properties to string map.
void setSizeMapUnitScale(const QgsMapUnitScale &scale)
void setSymbolHeightUnit(QgsSymbolV2::OutputUnit unit)
QgsMapUnitScale mSymbolHeightMapUnitScale
void setOutlineColor(const QColor &c)
Set outline color.
void setOutlineWidthMapUnitScale(const QgsMapUnitScale &scale)
static QgsSymbolV2::OutputUnit decodeOutputUnit(QString str)
virtual void setDataDefinedProperty(const QString &property, const QString &expressionString)
static QPointF _rotatedOffset(const QPointF &offset, double angle)