QGIS API Documentation  2.8.6-Wien
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 
30  , mSymbolName( "circle" )
31  , mSymbolWidth( 4 )
32  , mSymbolWidthUnit( QgsSymbolV2::MM )
33  , mSymbolHeight( 3 )
34  , mSymbolHeightUnit( QgsSymbolV2::MM )
35  , mOutlineColor( Qt::black )
36  , mOutlineStyle( Qt::SolidLine )
37  , mOutlineWidth( 0 )
38  , mOutlineWidthUnit( QgsSymbolV2::MM )
39 {
40  mColor = Qt::white;
41  mPen.setColor( mOutlineColor );
42  mPen.setStyle( mOutlineStyle );
43  mPen.setWidth( 1.0 );
44  mPen.setJoinStyle( Qt::MiterJoin );
45  mBrush.setColor( mColor );
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  if ( properties.contains( "width_expression" ) )
171  {
172  layer->setDataDefinedProperty( "width", properties["width_expression"] );
173  }
174  if ( properties.contains( "height_expression" ) )
175  {
176  layer->setDataDefinedProperty( "height", properties["height_expression"] );
177  }
178  if ( properties.contains( "rotation_expression" ) )
179  {
180  layer->setDataDefinedProperty( "rotation", properties["rotation_expression"] );
181  }
182  if ( properties.contains( "outline_width_expression" ) )
183  {
184  layer->setDataDefinedProperty( "outline_width", properties[ "outline_width_expression" ] );
185  }
186  if ( properties.contains( "outline_style_expression" ) )
187  {
188  layer->setDataDefinedProperty( "outline_style", properties[ "outline_style_expression" ] );
189  }
190  if ( properties.contains( "fill_color_expression" ) )
191  {
192  layer->setDataDefinedProperty( "fill_color", properties["fill_color_expression"] );
193  }
194  if ( properties.contains( "outline_color_expression" ) )
195  {
196  layer->setDataDefinedProperty( "outline_color", properties["outline_color_expression"] );
197  }
198  if ( properties.contains( "symbol_name_expression" ) )
199  {
200  layer->setDataDefinedProperty( "symbol_name", properties["symbol_name_expression"] );
201  }
202  if ( properties.contains( "offset_expression" ) )
203  {
204  layer->setDataDefinedProperty( "offset", properties["offset_expression"] );
205  }
206  if ( properties.contains( "horizontal_anchor_point_expression" ) )
207  {
208  layer->setDataDefinedProperty( "horizontal_anchor_point", properties[ "horizontal_anchor_point_expression" ] );
209  }
210  if ( properties.contains( "vertical_anchor_point_expression" ) )
211  {
212  layer->setDataDefinedProperty( "vertical_anchor_point", properties[ "vertical_anchor_point_expression" ] );
213  }
214 
215  //compatibility with old project file format
216  if ( !properties["width_field"].isEmpty() )
217  {
218  layer->setDataDefinedProperty( "width", properties["width_field"] );
219  }
220  if ( !properties["height_field"].isEmpty() )
221  {
222  layer->setDataDefinedProperty( "height", properties["height_field"] );
223  }
224  if ( !properties["rotation_field"].isEmpty() )
225  {
226  layer->setDataDefinedProperty( "rotation", properties["rotation_field"] );
227  }
228  if ( !properties["outline_width_field"].isEmpty() )
229  {
230  layer->setDataDefinedProperty( "outline_width", properties[ "outline_width_field" ] );
231  }
232  if ( !properties["fill_color_field"].isEmpty() )
233  {
234  layer->setDataDefinedProperty( "fill_color", properties["fill_color_field"] );
235  }
236  if ( !properties["outline_color_field"].isEmpty() )
237  {
238  layer->setDataDefinedProperty( "outline_color", properties["outline_color_field"] );
239  }
240  if ( !properties["symbol_name_field"].isEmpty() )
241  {
242  layer->setDataDefinedProperty( "symbol_name", properties["symbol_name_field"] );
243  }
244 
245  return layer;
246 }
247 
249 {
250  QgsExpression* outlineWidthExpression = expression( "outline_width" );
251  QgsExpression* outlineStyleExpression = expression( "outline_style" );
252  QgsExpression* fillColorExpression = expression( "fill_color" );
253  QgsExpression* outlineColorExpression = expression( "outline_color" );
254  QgsExpression* widthExpression = expression( "width" );
255  QgsExpression* heightExpression = expression( "height" );
256  QgsExpression* symbolNameExpression = expression( "symbol_name" );
257  QgsExpression* rotationExpression = expression( "rotation" );
258 
259  if ( outlineWidthExpression )
260  {
261  double width = outlineWidthExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
262  width *= QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), mOutlineWidthUnit, mOutlineWidthMapUnitScale );
263  mPen.setWidthF( width );
264  }
265  if ( outlineStyleExpression )
266  {
267  Qt::PenStyle style = QgsSymbolLayerV2Utils::decodePenStyle( outlineStyleExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString() );
268  mPen.setStyle( style );
269  }
270  if ( fillColorExpression )
271  {
272  QString colorString = fillColorExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString();
273  mBrush.setColor( QColor( QgsSymbolLayerV2Utils::decodeColor( colorString ) ) );
274  }
275  if ( outlineColorExpression )
276  {
277  QString colorString = outlineColorExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString();
278  mPen.setColor( QColor( QgsSymbolLayerV2Utils::decodeColor( colorString ) ) );
279  }
280  double scaledWidth = mSymbolWidth;
281  double scaledHeight = mSymbolHeight;
282  if ( widthExpression || heightExpression || symbolNameExpression )
283  {
284  QString symbolName = mSymbolName;
285  if ( symbolNameExpression )
286  {
287  symbolName = symbolNameExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString();
288  }
289  preparePath( symbolName, context, &scaledWidth, &scaledHeight, context.feature() );
290  }
291 
292  //offset
293  double offsetX = 0;
294  double offsetY = 0;
295  markerOffset( context, scaledWidth, scaledHeight, mSymbolWidthUnit, mSymbolHeightUnit, offsetX, offsetY, mSymbolWidthMapUnitScale, mSymbolHeightMapUnitScale );
296  QPointF off( offsetX, offsetY );
297 
298  QPainter* p = context.renderContext().painter();
299  if ( !p )
300  {
301  return;
302  }
303 
304  //priority for rotation: 1. data defined symbol level, 2. symbol layer rotation (mAngle)
305  double rotation = 0.0;
306  if ( rotationExpression )
307  {
308  rotation = rotationExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
309  }
310  else if ( !qgsDoubleNear( mAngle, 0.0 ) )
311  {
312  rotation = mAngle;
313  }
314  if ( rotation )
315  off = _rotatedOffset( off, rotation );
316 
317  QMatrix transform;
318  transform.translate( point.x() + off.x(), point.y() + off.y() );
319  if ( !qgsDoubleNear( rotation, 0.0 ) )
320  {
321  transform.rotate( rotation );
322  }
323 
324  p->setPen( mPen );
325  p->setBrush( mBrush );
326  p->drawPath( transform.map( mPainterPath ) );
327 }
328 
330 {
331  return "EllipseMarker";
332 }
333 
335 {
336  QgsMarkerSymbolLayerV2::startRender( context ); // get anchor point expressions
337  if ( !context.feature() || !hasDataDefinedProperty() )
338  {
339  preparePath( mSymbolName, context );
340  }
341  mPen.setColor( mOutlineColor );
342  mPen.setStyle( mOutlineStyle );
343  mPen.setWidthF( mOutlineWidth * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), mOutlineWidthUnit, mOutlineWidthMapUnitScale ) );
344  mBrush.setColor( mColor );
345  prepareExpressions( context.fields(), context.renderContext().rendererScale() );
346 }
347 
349 {
350 }
351 
353 {
355 }
356 
357 void QgsEllipseSymbolLayerV2::toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
358 {
359  QDomElement symbolizerElem = doc.createElement( "se:PointSymbolizer" );
360  if ( !props.value( "uom", "" ).isEmpty() )
361  symbolizerElem.setAttribute( "uom", props.value( "uom", "" ) );
362  element.appendChild( symbolizerElem );
363 
364  // <Geometry>
365  QgsSymbolLayerV2Utils::createGeometryElement( doc, symbolizerElem, props.value( "geom", "" ) );
366 
367  writeSldMarker( doc, symbolizerElem, props );
368 }
369 
370 void QgsEllipseSymbolLayerV2::writeSldMarker( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
371 {
372  // <Graphic>
373  QDomElement graphicElem = doc.createElement( "se:Graphic" );
374  element.appendChild( graphicElem );
375 
376  QgsSymbolLayerV2Utils::wellKnownMarkerToSld( doc, graphicElem, mSymbolName, mColor, mOutlineColor, mOutlineStyle, mOutlineWidth, mSymbolWidth );
377 
378  // store w/h factor in a <VendorOption>
379  double widthHeightFactor = mSymbolWidth / mSymbolHeight;
380  QDomElement factorElem = QgsSymbolLayerV2Utils::createVendorOptionElement( doc, "widthHeightFactor", QString::number( widthHeightFactor ) );
381  graphicElem.appendChild( factorElem );
382 
383  // <Rotation>
384  const QgsExpression* rotationExpression = dataDefinedProperty( "rotation" );
385  QString angleFunc = props.value( "angle", "" );
386  if ( angleFunc.isEmpty() ) // symbol has no angle set
387  {
388 
389  if ( rotationExpression )
390  angleFunc = rotationExpression->expression();
391  else if ( !qgsDoubleNear( mAngle, 0.0 ) )
392  angleFunc = QString::number( mAngle );
393  }
394  else if ( rotationExpression )
395  {
396  // the symbol has an angle and the symbol layer have a rotation
397  // property set
398  angleFunc = QString( "%1 + %2" ).arg( angleFunc ).arg( rotationExpression->expression() );
399  }
400  else if ( !qgsDoubleNear( mAngle, 0.0 ) )
401  {
402  // both the symbol and the symbol layer have angle value set
403  bool ok;
404  double angle = angleFunc.toDouble( &ok );
405  if ( !ok )
406  {
407  // its a string (probably a property name or a function)
408  angleFunc = QString( "%1 + %2" ).arg( angleFunc ).arg( mAngle );
409  }
410  else if ( !qgsDoubleNear( angle + mAngle, 0.0 ) )
411  {
412  // it's a double value
413  angleFunc = QString::number( angle + mAngle );
414  }
415  }
416  QgsSymbolLayerV2Utils::createRotationElement( doc, graphicElem, angleFunc );
417 }
418 
420 {
421  QgsDebugMsg( "Entered." );
422 
423  QDomElement graphicElem = element.firstChildElement( "Graphic" );
424  if ( graphicElem.isNull() )
425  return NULL;
426 
427  QString name = "circle";
428  QColor fillColor, borderColor;
429  double borderWidth, size;
430  double widthHeightFactor = 1.0;
431  Qt::PenStyle borderStyle;
432 
433  QgsStringMap vendorOptions = QgsSymbolLayerV2Utils::getVendorOptionList( graphicElem );
434  for ( QgsStringMap::iterator it = vendorOptions.begin(); it != vendorOptions.end(); ++it )
435  {
436  if ( it.key() == "widthHeightFactor" )
437  {
438  bool ok;
439  double v = it.value().toDouble( &ok );
440  if ( ok && !qgsDoubleNear( v, 0.0 ) && v > 0 )
441  widthHeightFactor = v;
442  }
443  }
444 
445  if ( !QgsSymbolLayerV2Utils::wellKnownMarkerFromSld( graphicElem, name, fillColor, borderColor, borderStyle, borderWidth, size ) )
446  return NULL;
447 
448  double angle = 0.0;
449  QString angleFunc;
450  if ( QgsSymbolLayerV2Utils::rotationFromSldElement( graphicElem, angleFunc ) )
451  {
452  bool ok;
453  double d = angleFunc.toDouble( &ok );
454  if ( ok )
455  angle = d;
456  }
457 
459  m->setSymbolName( name );
460  m->setFillColor( fillColor );
461  m->setOutlineColor( borderColor );
462  m->setOutlineStyle( borderStyle );
463  m->setOutlineWidth( borderWidth );
464  m->setSymbolWidth( size );
465  m->setSymbolHeight( size / widthHeightFactor );
466  m->setAngle( angle );
467  return m;
468 }
469 
471 {
472  QgsStringMap map;
473  map["symbol_name"] = mSymbolName;
474  map["symbol_width"] = QString::number( mSymbolWidth );
475  map["symbol_width_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mSymbolWidthUnit );
476  map["symbol_width_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mSymbolWidthMapUnitScale );
477  map["symbol_height"] = QString::number( mSymbolHeight );
478  map["symbol_height_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mSymbolHeightUnit );
479  map["symbol_height_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mSymbolHeightMapUnitScale );
480  map["angle"] = QString::number( mAngle );
481  map["outline_style"] = QgsSymbolLayerV2Utils::encodePenStyle( mOutlineStyle );
482  map["outline_width"] = QString::number( mOutlineWidth );
483  map["outline_width_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOutlineWidthUnit );
484  map["outline_width_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOutlineWidthMapUnitScale );
485  map["color"] = QgsSymbolLayerV2Utils::encodeColor( mColor );
486  map["outline_color"] = QgsSymbolLayerV2Utils::encodeColor( mOutlineColor );
487  map["offset"] = QgsSymbolLayerV2Utils::encodePoint( mOffset );
489  map["offset_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOffsetMapUnitScale );
490  map["size"] = QString::number( mSize );
492  map["size_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mSizeMapUnitScale );
493  map["horizontal_anchor_point"] = QString::number( mHorizontalAnchorPoint );
494  map["vertical_anchor_point"] = QString::number( mVerticalAnchorPoint );
496  return map;
497 }
498 
499 bool QgsEllipseSymbolLayerV2::hasDataDefinedProperty() const
500 {
501  return ( dataDefinedProperty( "width" ) || dataDefinedProperty( "height" ) || dataDefinedProperty( "rotation" )
502  || dataDefinedProperty( "outline_width" ) || dataDefinedProperty( "fill_color" ) || dataDefinedProperty( "outline_color" )
503  || dataDefinedProperty( "symbol_name" ) || dataDefinedProperty( "offset" ) );
504 }
505 
506 void QgsEllipseSymbolLayerV2::preparePath( const QString& symbolName, QgsSymbolV2RenderContext& context, double* scaledWidth, double* scaledHeight, const QgsFeature* f )
507 {
508  mPainterPath = QPainterPath();
509  const QgsRenderContext& ct = context.renderContext();
510 
511  double width = 0;
512 
513  QgsExpression* widthExpression = expression( "width" );
514  if ( widthExpression ) //1. priority: data defined setting on symbol layer level
515  {
516  width = widthExpression->evaluate( const_cast<QgsFeature*>( f ) ).toDouble();
517  }
518  else if ( context.renderHints() & QgsSymbolV2::DataDefinedSizeScale ) //2. priority: is data defined size on symbol level
519  {
520  width = mSize;
521  }
522  else //3. priority: global width setting
523  {
524  width = mSymbolWidth;
525  }
526  if ( scaledWidth )
527  {
528  *scaledWidth = width;
529  }
530  width *= QgsSymbolLayerV2Utils::lineWidthScaleFactor( ct, mSymbolWidthUnit, mSymbolHeightMapUnitScale );
531 
532  double height = 0;
533  QgsExpression* heightExpression = expression( "height" );
534  if ( heightExpression ) //1. priority: data defined setting on symbol layer level
535  {
536  height = heightExpression->evaluate( const_cast<QgsFeature*>( f ) ).toDouble();
537  }
538  else if ( context.renderHints() & QgsSymbolV2::DataDefinedSizeScale ) //2. priority: is data defined size on symbol level
539  {
540  height = mSize;
541  }
542  else //3. priority: global height setting
543  {
544  height = mSymbolHeight;
545  }
546  if ( scaledHeight )
547  {
548  *scaledHeight = height;
549  }
550  height *= QgsSymbolLayerV2Utils::lineWidthScaleFactor( ct, mSymbolHeightUnit, mSymbolHeightMapUnitScale );
551 
552  if ( symbolName == "circle" )
553  {
554  mPainterPath.addEllipse( QRectF( -width / 2.0, -height / 2.0, width, height ) );
555  }
556  else if ( symbolName == "rectangle" )
557  {
558  mPainterPath.addRect( QRectF( -width / 2.0, -height / 2.0, width, height ) );
559  }
560  else if ( symbolName == "cross" )
561  {
562  mPainterPath.moveTo( 0, -height / 2.0 );
563  mPainterPath.lineTo( 0, height / 2.0 );
564  mPainterPath.moveTo( -width / 2.0, 0 );
565  mPainterPath.lineTo( width / 2.0, 0 );
566  }
567  else if ( symbolName == "triangle" )
568  {
569  mPainterPath.moveTo( 0, -height / 2.0 );
570  mPainterPath.lineTo( -width / 2.0, height / 2.0 );
571  mPainterPath.lineTo( width / 2.0, height / 2.0 );
572  mPainterPath.lineTo( 0, -height / 2.0 );
573  }
574 }
575 
577 {
579  mSymbolWidthUnit = unit;
580  mSymbolHeightUnit = unit;
581  mOutlineWidthUnit = unit;
582 }
583 
585 {
587  if ( mSymbolWidthUnit != unit || mSymbolHeightUnit != unit || mOutlineWidthUnit != unit )
588  {
589  return QgsSymbolV2::Mixed;
590  }
591  return unit;
592 }
593 
595 {
597  mSymbolWidthMapUnitScale = scale;
598  mSymbolHeightMapUnitScale = scale;
599  mOutlineWidthMapUnitScale = scale;
600 }
601 
603 {
604  if ( QgsMarkerSymbolLayerV2::mapUnitScale() == mSymbolWidthMapUnitScale &&
605  mSymbolWidthMapUnitScale == mSymbolHeightMapUnitScale &&
606  mSymbolHeightMapUnitScale == mOutlineWidthMapUnitScale )
607  {
608  return mSymbolWidthMapUnitScale;
609  }
610  return QgsMapUnitScale();
611 }
612 
613 bool QgsEllipseSymbolLayerV2::writeDxf( QgsDxfExport& e, double mmMapUnitScaleFactor, const QString& layerName, const QgsSymbolV2RenderContext* context, const QgsFeature* f, const QPointF& shift ) const
614 {
615  //width
616  double symbolWidth = mSymbolWidth;
617  QgsExpression* widthExpression = expression( "width" );
618  if ( widthExpression ) //1. priority: data defined setting on symbol layer level
619  {
620  symbolWidth = widthExpression->evaluate( const_cast<QgsFeature*>( f ) ).toDouble();
621  }
622  else if ( context->renderHints() & QgsSymbolV2::DataDefinedSizeScale ) //2. priority: is data defined size on symbol level
623  {
624  symbolWidth = mSize;
625  }
626  if ( mSymbolWidthUnit == QgsSymbolV2::MM )
627  {
628  symbolWidth *= mmMapUnitScaleFactor;
629  }
630 
631  //height
632  double symbolHeight = mSymbolHeight;
633  QgsExpression* heightExpression = expression( "height" );
634  if ( heightExpression ) //1. priority: data defined setting on symbol layer level
635  {
636  symbolHeight = heightExpression->evaluate( const_cast<QgsFeature*>( f ) ).toDouble();
637  }
638  else if ( context->renderHints() & QgsSymbolV2::DataDefinedSizeScale ) //2. priority: is data defined size on symbol level
639  {
640  symbolHeight = mSize;
641  }
642  if ( mSymbolHeightUnit == QgsSymbolV2::MM )
643  {
644  symbolHeight *= mmMapUnitScaleFactor;
645  }
646 
647  //outline width
648  double outlineWidth = mOutlineWidth;
649  QgsExpression* outlineWidthExpression = expression( "outline_width" );
650  if ( outlineWidthExpression )
651  {
652  outlineWidth = outlineWidthExpression->evaluate( const_cast<QgsFeature*>( context->feature() ) ).toDouble();
653  }
654  if ( mOutlineWidthUnit == QgsSymbolV2::MM )
655  {
656  outlineWidth *= outlineWidth;
657  }
658 
659  //fill color
660  QColor fc = mColor;
661  QgsExpression* fillColorExpression = expression( "fill_color" );
662  if ( fillColorExpression )
663  {
664  fc = QColor( fillColorExpression->evaluate( const_cast<QgsFeature*>( context->feature() ) ).toString() );
665  }
666 
667  //outline color
668  QColor oc = mOutlineColor;
669  QgsExpression* outlineColorExpression = expression( "outline_color" );
670  if ( outlineColorExpression )
671  {
672  oc = QColor( outlineColorExpression->evaluate( const_cast<QgsFeature*>( context->feature() ) ).toString() );
673  }
674 
675  //symbol name
676  QString symbolName = mSymbolName;
677  QgsExpression* symbolNameExpression = expression( "symbol_name" );
678  if ( symbolNameExpression )
679  {
680  QgsExpression* symbolNameExpression = expression( "symbol_name" );
681  symbolName = symbolNameExpression->evaluate( const_cast<QgsFeature*>( context->feature() ) ).toString();
682  }
683 
684  //offset
685  double offsetX = 0;
686  double offsetY = 0;
687  markerOffset( *context, offsetX, offsetY );
688  QPointF off( offsetX, offsetY );
689 
690  //priority for rotation: 1. data defined symbol level, 2. symbol layer rotation (mAngle)
691  double rotation = 0.0;
692  QgsExpression* rotationExpression = expression( "rotation" );
693  if ( rotationExpression )
694  {
695  rotation = rotationExpression->evaluate( const_cast<QgsFeature*>( context->feature() ) ).toDouble();
696  }
697  else if ( !qgsDoubleNear( mAngle, 0.0 ) )
698  {
699  rotation = mAngle;
700  }
701  rotation = -rotation; //rotation in Qt is counterclockwise
702  if ( rotation )
703  off = _rotatedOffset( off, rotation );
704 
705  QTransform t;
706  t.translate( shift.x() + offsetX, shift.y() + offsetY );
707 
708  if ( rotation != 0 )
709  t.rotate( rotation );
710 
711  double halfWidth = symbolWidth / 2.0;
712  double halfHeight = symbolHeight / 2.0;
713 
714  if ( symbolName == "circle" )
715  {
716  if ( qgsDoubleNear( halfWidth, halfHeight ) )
717  {
718  QPointF pt( t.map( QPointF( 0, 0 ) ) );
719  e.writeFilledCircle( layerName, oc, pt, halfWidth );
720  }
721  else
722  {
723  QgsPolyline line;
724  double stepsize = 2 * M_PI / 40;
725  for ( int i = 0; i < 39; ++i )
726  {
727  double angle = stepsize * i;
728  double x = halfWidth * cos( angle );
729  double y = halfHeight * sin( angle );
730  QPointF pt( t.map( QPointF( x, y ) ) );
731  line.push_back( pt );
732  }
733  //close ellipse with first point
734  line.push_back( line.at( 0 ) );
735  if ( mBrush.style() != Qt::NoBrush )
736  e.writePolygon( QgsPolygon() << line, layerName, "SOLID", fc );
737  if ( mPen.style() != Qt::NoPen )
738  e.writePolyline( line, layerName, "CONTINUOUS", oc, outlineWidth );
739  }
740  }
741  else if ( symbolName == "rectangle" )
742  {
743  QgsPolygon p( 1 );
744  p[0].resize( 5 );
745  p[0][0] = t.map( QPointF( -halfWidth, -halfHeight ) );
746  p[0][1] = t.map( QPointF( halfWidth, -halfHeight ) );
747  p[0][2] = t.map( QPointF( halfWidth, halfHeight ) );
748  p[0][3] = t.map( QPointF( -halfWidth, halfHeight ) );
749  p[0][4] = p[0][0];
750  if ( mBrush.style() != Qt::NoBrush )
751  e.writePolygon( p, layerName, "SOLID", fc );
752  if ( mPen.style() != Qt::NoPen )
753  e.writePolyline( p[0], layerName, "CONTINUOUS", oc, outlineWidth );
754  return true;
755  }
756  else if ( symbolName == "cross" && mPen.style() != Qt::NoPen )
757  {
758  QgsPolyline line( 2 );
759  line[0] = t.map( QPointF( -halfWidth, 0 ) );
760  line[1] = t.map( QPointF( halfWidth, 0 ) );
761  e.writePolyline( line, layerName, "CONTINUOUS", oc, outlineWidth );
762 
763  line[0] = t.map( QPointF( 0, halfHeight ) );
764  line[1] = t.map( QPointF( 0, -halfHeight ) );
765  e.writePolyline( line, layerName, "CONTINUOUS", oc, outlineWidth );
766 
767  return true;
768  }
769  else if ( symbolName == "triangle" )
770  {
771  QgsPolygon p( 1 );
772  p[0].resize( 4 );
773  p[0][0] = QPointF( t.map( QPointF( -halfWidth, -halfHeight ) ) );
774  p[0][1] = QPointF( t.map( QPointF( halfWidth, -halfHeight ) ) );
775  p[0][2] = QPointF( t.map( QPointF( 0, halfHeight ) ) );
776  p[0][3] = p[0][0];
777  if ( mBrush.style() != Qt::NoBrush )
778  e.writePolygon( p, layerName, "SOLID", fc );
779  if ( mPen.style() != Qt::NoPen )
780  e.writePolyline( p[0], layerName, "CONTINUOUS", oc, outlineWidth );
781  return true;
782  }
783 
784  return false; //soon...
785 }
786 
787 
static QString encodeOutputUnit(QgsSymbolV2::OutputUnit unit)
void renderPoint(const QPointF &point, QgsSymbolV2RenderContext &context) override
Class for parsing and evaluation of expressions (formerly called "search strings").
Definition: qgsexpression.h:87
void toSld(QDomDocument &doc, QDomElement &element, QgsStringMap props) const override
void setSymbolWidthUnit(QgsSymbolV2::OutputUnit unit)
QColor fillColor() const override
Get fill color.
QgsSymbolV2::OutputUnit outputUnit() const override
int renderHints() const
Definition: qgssymbolv2.h:208
QgsMapUnitScale mSizeMapUnitScale
static Q_DECL_DEPRECATED bool wellKnownMarkerFromSld(QDomElement &element, QString &name, QColor &color, QColor &borderColor, double &borderWidth, double &size)
QgsSymbolLayerV2 * clone() const override
void startRender(QgsSymbolV2RenderContext &context) override
const QString expression() const
Alias for dump()
QVariant evaluate(const QgsFeature *f=NULL)
Evaluate the feature and return the result.
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
void writePolygon(const QgsPolygon &polygon, const QString &layer, const QString &hatchPattern, QColor color)
Draw dxf polygon (HATCH)
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:33
static QgsStringMap getVendorOptionList(QDomElement &element)
void setOffset(QPointF offset)
void setOutlineWidthUnit(QgsSymbolV2::OutputUnit unit)
void setHorizontalAnchorPoint(HorizontalAnchorPoint h)
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 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)
QgsSymbolV2::OutputUnit outputUnit() const override
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:156
void setOffsetMapUnitScale(const QgsMapUnitScale &scale)
A symbol layer for rendering objects with major and minor axis (e.g.
QMap< QString, QString > QgsStringMap
Definition: qgis.h:429
QgsStringMap properties() const override
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
Definition: qgis.h:330
void setMapUnitScale(const QgsMapUnitScale &scale) override
void setOffsetUnit(QgsSymbolV2::OutputUnit unit)
static QString encodeColor(QColor color)
void setMapUnitScale(const QgsMapUnitScale &scale) override
virtual QgsExpression * expression(const QString &property) const
static QString encodePenStyle(Qt::PenStyle style)
void setSymbolHeightMapUnitScale(const QgsMapUnitScale &scale)
void setOutputUnit(QgsSymbolV2::OutputUnit unit) override
const QgsFeature * feature() const
Current feature being rendered - may be null.
Definition: qgssymbolv2.h:213
static QString encodePoint(QPointF point)
static Qt::PenStyle decodePenStyle(QString str)
#define M_PI
void setSizeUnit(QgsSymbolV2::OutputUnit unit)
HorizontalAnchorPoint mHorizontalAnchorPoint
void writePolyline(const QgsPolyline &line, const QString &layer, const QString &lineStyleName, QColor color, double width=-1, bool unusedPolygonFlag=false)
draw dxf primitives
QVector< QgsPolyline > QgsPolygon
polygon: first item of the list is outer ring, inner rings (if any) start from second item ...
Definition: qgsgeometry.h:39
void setOutlineStyle(Qt::PenStyle outlineStyle)
void setSymbolName(const QString &name)
virtual void prepareExpressions(const QgsFields *fields, double scale=-1.0)
static QgsSymbolLayerV2 * create(const QgsStringMap &properties=QgsStringMap())
void startRender(QgsSymbolV2RenderContext &context) override
static void createGeometryElement(QDomDocument &doc, QDomElement &element, QString geomFunc)
Contains information about the context of a rendering operation.
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.
Struct for storing maximum and minimum scales for measurements in map units.
QgsMapUnitScale mapUnitScale() const override
void setSymbolWidthMapUnitScale(const QgsMapUnitScale &scale)
virtual const QgsExpression * dataDefinedProperty(const QString &property) const
QgsRenderContext & renderContext()
Definition: qgssymbolv2.h:191
void setOutlineColor(const QColor &c) override
Set outline color.
void writeFilledCircle(const QString &layer, QColor color, const QgsPoint &pt, double radius)
Write filled circle (as hatch)
static Q_DECL_DEPRECATED void wellKnownMarkerToSld(QDomDocument &doc, QDomElement &element, QString name, QColor color, QColor borderColor=QColor(), double borderWidth=-1, double size=-1)
const QgsFields * fields() const
Fields of the layer.
Definition: qgssymbolv2.h:219
QgsSymbolV2::OutputUnit mOffsetUnit
static bool rotationFromSldElement(QDomElement &element, QString &rotationFunc)
VerticalAnchorPoint mVerticalAnchorPoint
void stopRender(QgsSymbolV2RenderContext &context) override
QgsSymbolV2::OutputUnit mSizeUnit
QgsMapUnitScale mOffsetMapUnitScale
void markerOffset(const QgsSymbolV2RenderContext &context, double &offsetX, double &offsetY) const
static QgsMapUnitScale decodeMapUnitScale(const QString &str)
QString layerType() const override
void writeSldMarker(QDomDocument &doc, QDomElement &element, QgsStringMap props) const override
QgsMapUnitScale mapUnitScale() const override
void setSize(double size)
void setAngle(double angle)
void saveDataDefinedProperties(QgsStringMap &stringMap) const
Saves data defined properties to string map.
void setSizeMapUnitScale(const QgsMapUnitScale &scale)
void setFillColor(const QColor &c) override
Set fill color.
void setSymbolHeightUnit(QgsSymbolV2::OutputUnit unit)
void setOutputUnit(QgsSymbolV2::OutputUnit unit) override
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)