QGIS API Documentation  2.14.11-Essen
qgsellipsesymbollayerv2.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsellipsesymbollayerv2.cpp
3  ---------------------
4  begin : June 2011
5  copyright : (C) 2011 by Marco Hugentobler
6  email : marco dot hugentobler at sourcepole dot ch
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
16 #include "qgsdxfexport.h"
17 #include "qgsexpression.h"
18 #include "qgsfeature.h"
19 #include "qgsrendercontext.h"
20 #include "qgsvectorlayer.h"
21 #include "qgsdatadefined.h"
22 #include "qgslogger.h"
23 #include "qgsunittypes.h"
24 
25 #include <QPainter>
26 #include <QSet>
27 #include <QDomDocument>
28 #include <QDomElement>
29 
32  , mSymbolName( "circle" )
33  , mSymbolWidth( 4 )
34  , mSymbolWidthUnit( QgsSymbolV2::MM )
35  , mSymbolHeight( 3 )
36  , mSymbolHeightUnit( QgsSymbolV2::MM )
37  , mOutlineColor( Qt::black )
38  , mOutlineStyle( Qt::SolidLine )
39  , mOutlineWidth( 0 )
40  , mOutlineWidthUnit( QgsSymbolV2::MM )
41 {
42  mColor = Qt::white;
43  mPen.setColor( mOutlineColor );
44  mPen.setStyle( mOutlineStyle );
45  mPen.setWidth( 1.0 );
46  mPen.setJoinStyle( Qt::MiterJoin );
47  mBrush.setColor( mColor );
48  mBrush.setStyle( Qt::SolidPattern );
49  mOffset = QPointF( 0, 0 );
50 
51  mAngle = 0;
52 }
53 
55 {
56 }
57 
59 {
61  if ( properties.contains( "symbol_name" ) )
62  {
63  layer->setSymbolName( properties[ "symbol_name" ] );
64  }
65  if ( properties.contains( "symbol_width" ) )
66  {
67  layer->setSymbolWidth( properties["symbol_width"].toDouble() );
68  }
69  if ( properties.contains( "symbol_width_unit" ) )
70  {
71  layer->setSymbolWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["symbol_width_unit"] ) );
72  }
73  if ( properties.contains( "symbol_width_map_unit_scale" ) )
74  {
75  layer->setSymbolWidthMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( properties["symbol_width_map_unit_scale"] ) );
76  }
77  if ( properties.contains( "symbol_height" ) )
78  {
79  layer->setSymbolHeight( properties["symbol_height"].toDouble() );
80  }
81  if ( properties.contains( "symbol_height_unit" ) )
82  {
83  layer->setSymbolHeightUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["symbol_height_unit"] ) );
84  }
85  if ( properties.contains( "symbol_height_map_unit_scale" ) )
86  {
87  layer->setSymbolHeightMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( properties["symbol_height_map_unit_scale"] ) );
88  }
89  if ( properties.contains( "angle" ) )
90  {
91  layer->setAngle( properties["angle"].toDouble() );
92  }
93  if ( properties.contains( "outline_style" ) )
94  {
95  layer->setOutlineStyle( QgsSymbolLayerV2Utils::decodePenStyle( properties["outline_style"] ) );
96  }
97  else if ( properties.contains( "line_style" ) )
98  {
99  layer->setOutlineStyle( QgsSymbolLayerV2Utils::decodePenStyle( properties["line_style"] ) );
100  }
101  if ( properties.contains( "outline_width" ) )
102  {
103  layer->setOutlineWidth( properties["outline_width"].toDouble() );
104  }
105  else if ( properties.contains( "line_width" ) )
106  {
107  layer->setOutlineWidth( properties["line_width"].toDouble() );
108  }
109  if ( properties.contains( "outline_width_unit" ) )
110  {
111  layer->setOutlineWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["outline_width_unit"] ) );
112  }
113  else if ( properties.contains( "line_width_unit" ) )
114  {
115  layer->setOutlineWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["line_width_unit"] ) );
116  }
117  if ( properties.contains( "outline_width_map_unit_scale" ) )
118  {
119  layer->setOutlineWidthMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( properties["outline_width_map_unit_scale"] ) );
120  }
121  if ( properties.contains( "fill_color" ) )
122  {
123  //pre 2.5 projects used "fill_color"
124  layer->setFillColor( QgsSymbolLayerV2Utils::decodeColor( properties["fill_color"] ) );
125  }
126  else if ( properties.contains( "color" ) )
127  {
128  layer->setFillColor( QgsSymbolLayerV2Utils::decodeColor( properties["color"] ) );
129  }
130  if ( properties.contains( "outline_color" ) )
131  {
132  layer->setOutlineColor( QgsSymbolLayerV2Utils::decodeColor( properties["outline_color"] ) );
133  }
134  else if ( properties.contains( "line_color" ) )
135  {
136  layer->setOutlineColor( QgsSymbolLayerV2Utils::decodeColor( properties["line_color"] ) );
137  }
138  if ( properties.contains( "size" ) )
139  {
140  layer->setSize( properties["size"].toDouble() );
141  }
142  if ( properties.contains( "size_unit" ) )
143  {
144  layer->setSizeUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["size_unit"] ) );
145  }
146  if ( properties.contains( "size_map_unit_scale" ) )
147  {
148  layer->setSizeMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( properties["size_map_unit_scale"] ) );
149  }
150  if ( properties.contains( "offset" ) )
151  {
152  layer->setOffset( QgsSymbolLayerV2Utils::decodePoint( properties["offset"] ) );
153  }
154  if ( properties.contains( "offset_unit" ) )
155  {
156  layer->setOffsetUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["offset_unit"] ) );
157  }
158  if ( properties.contains( "offset_map_unit_scale" ) )
159  {
160  layer->setOffsetMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( properties["offset_map_unit_scale"] ) );
161  }
162  if ( properties.contains( "horizontal_anchor_point" ) )
163  {
164  layer->setHorizontalAnchorPoint( QgsMarkerSymbolLayerV2::HorizontalAnchorPoint( properties[ "horizontal_anchor_point" ].toInt() ) );
165  }
166  if ( properties.contains( "vertical_anchor_point" ) )
167  {
168  layer->setVerticalAnchorPoint( QgsMarkerSymbolLayerV2::VerticalAnchorPoint( properties[ "vertical_anchor_point" ].toInt() ) );
169  }
170 
171  //data defined properties
172  layer->restoreDataDefinedProperties( properties );
173 
174  //compatibility with old project file format
175  if ( !properties["width_field"].isEmpty() )
176  {
177  layer->setDataDefinedProperty( QgsSymbolLayerV2::EXPR_WIDTH, new QgsDataDefined( properties["width_field"] ) );
178  }
179  if ( !properties["height_field"].isEmpty() )
180  {
181  layer->setDataDefinedProperty( QgsSymbolLayerV2::EXPR_HEIGHT, new QgsDataDefined( properties["height_field"] ) );
182  }
183  if ( !properties["rotation_field"].isEmpty() )
184  {
185  layer->setDataDefinedProperty( QgsSymbolLayerV2::EXPR_ROTATION, new QgsDataDefined( properties["rotation_field"] ) );
186  }
187  if ( !properties["outline_width_field"].isEmpty() )
188  {
189  layer->setDataDefinedProperty( QgsSymbolLayerV2::EXPR_OUTLINE_WIDTH, new QgsDataDefined( properties[ "outline_width_field" ] ) );
190  }
191  if ( !properties["fill_color_field"].isEmpty() )
192  {
193  layer->setDataDefinedProperty( QgsSymbolLayerV2::EXPR_FILL_COLOR, new QgsDataDefined( properties["fill_color_field"] ) );
194  }
195  if ( !properties["outline_color_field"].isEmpty() )
196  {
197  layer->setDataDefinedProperty( QgsSymbolLayerV2::EXPR_OUTLINE_COLOR, new QgsDataDefined( properties["outline_color_field"] ) );
198  }
199  if ( !properties["symbol_name_field"].isEmpty() )
200  {
201  layer->setDataDefinedProperty( QgsSymbolLayerV2::EXPR_SYMBOL_NAME, new QgsDataDefined( properties["symbol_name_field"] ) );
202  }
203 
204  return layer;
205 }
206 
208 {
209  bool ok;
211  {
212  context.setOriginalValueVariable( mOutlineWidth );
213  double width = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_OUTLINE_WIDTH, context, mOutlineWidth ).toDouble();
214  width = QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), width, mOutlineWidthUnit, mOutlineWidthMapUnitScale );
215  mPen.setWidthF( width );
216  }
218  {
221  if ( ok )
222  {
223  Qt::PenStyle style = QgsSymbolLayerV2Utils::decodePenStyle( styleString );
224  mPen.setStyle( style );
225  }
226  }
228  {
231  if ( ok )
232  mBrush.setColor( QgsSymbolLayerV2Utils::decodeColor( colorString ) );
233  }
235  {
238  if ( ok )
239  mPen.setColor( QgsSymbolLayerV2Utils::decodeColor( colorString ) );
240  }
241  double scaledWidth = mSymbolWidth;
242  double scaledHeight = mSymbolHeight;
244  {
245  QString symbolName = mSymbolName;
247  {
248  context.setOriginalValueVariable( mSymbolName );
249  symbolName = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_SYMBOL_NAME, context, mSymbolName ).toString();
250  }
251  preparePath( symbolName, context, &scaledWidth, &scaledHeight, context.feature() );
252  }
253 
254  //offset and rotation
255  bool hasDataDefinedRotation = false;
256  QPointF offset;
257  double angle = 0;
258  calculateOffsetAndRotation( context, scaledWidth, scaledHeight, hasDataDefinedRotation, offset, angle );
259 
260  QPainter* p = context.renderContext().painter();
261  if ( !p )
262  {
263  return;
264  }
265 
266  QMatrix transform;
267  transform.translate( point.x() + offset.x(), point.y() + offset.y() );
268  if ( !qgsDoubleNear( angle, 0.0 ) )
269  {
270  transform.rotate( angle );
271  }
272 
273  p->setPen( mPen );
274  p->setBrush( mBrush );
275  p->drawPath( transform.map( mPainterPath ) );
276 }
277 
278 
279 void QgsEllipseSymbolLayerV2::calculateOffsetAndRotation( QgsSymbolV2RenderContext& context,
280  double scaledWidth,
281  double scaledHeight,
282  bool& hasDataDefinedRotation,
283  QPointF& offset,
284  double& angle ) const
285 {
286  double offsetX = 0;
287  double offsetY = 0;
288  markerOffset( context, scaledWidth, scaledHeight, mSymbolWidthUnit, mSymbolHeightUnit, offsetX, offsetY, mSymbolWidthMapUnitScale, mSymbolHeightMapUnitScale );
289  offset = QPointF( offsetX, offsetY );
290 
291 //priority for rotation: 1. data defined symbol level, 2. symbol layer rotation (mAngle)
292  bool ok = true;
293  angle = mAngle + mLineAngle;
294  bool usingDataDefinedRotation = false;
296  {
297  context.setOriginalValueVariable( angle );
299  usingDataDefinedRotation = ok;
300  }
301 
302  hasDataDefinedRotation = context.renderHints() & QgsSymbolV2::DataDefinedRotation || usingDataDefinedRotation;
303  if ( hasDataDefinedRotation )
304  {
305  // For non-point markers, "dataDefinedRotation" means following the
306  // shape (shape-data defined). For them, "field-data defined" does
307  // not work at all. TODO: if "field-data defined" ever gets implemented
308  // we'll need a way to distinguish here between the two, possibly
309  // using another flag in renderHints()
310  const QgsFeature* f = context.feature();
311  if ( f )
312  {
313  const QgsGeometry *g = f->constGeometry();
314  if ( g && g->type() == QGis::Point )
315  {
316  const QgsMapToPixel& m2p = context.renderContext().mapToPixel();
317  angle += m2p.mapRotation();
318  }
319  }
320  }
321 
322  if ( angle )
323  offset = _rotatedOffset( offset, angle );
324 }
325 
327 {
328  return "EllipseMarker";
329 }
330 
332 {
333  QgsMarkerSymbolLayerV2::startRender( context ); // get anchor point expressions
334  if ( !context.feature() || !hasDataDefinedProperties() )
335  {
336  preparePath( mSymbolName, context );
337  }
338  mPen.setColor( mOutlineColor );
339  mPen.setStyle( mOutlineStyle );
340  mPen.setWidthF( QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), mOutlineWidth, mOutlineWidthUnit, mOutlineWidthMapUnitScale ) );
341  mBrush.setColor( mColor );
342  prepareExpressions( context );
343 }
344 
346 {
347 }
348 
350 {
352  m->setSymbolName( mSymbolName );
353  m->setSymbolWidth( mSymbolWidth );
354  m->setSymbolHeight( mSymbolHeight );
355  m->setOutlineStyle( mOutlineStyle );
356  m->setOffset( mOffset );
359  m->setOutlineStyle( mOutlineStyle );
360  m->setOutlineWidth( mOutlineWidth );
361  m->setColor( color() );
362  m->setOutlineColor( mOutlineColor );
363  m->setSymbolWidthUnit( mSymbolWidthUnit );
364  m->setSymbolWidthMapUnitScale( mSymbolWidthMapUnitScale );
365  m->setSymbolHeightUnit( mSymbolHeightUnit );
366  m->setSymbolHeightMapUnitScale( mSymbolHeightMapUnitScale );
367  m->setOutlineWidthUnit( mOutlineWidthUnit );
368  m->setOutlineWidthMapUnitScale( mOutlineWidthMapUnitScale );
369  m->setAngle( mAngle );
372 
374  copyPaintEffect( m );
375  return m;
376 }
377 
378 void QgsEllipseSymbolLayerV2::toSld( QDomDocument &doc, QDomElement &element, const QgsStringMap& props ) const
379 {
380  QDomElement symbolizerElem = doc.createElement( "se:PointSymbolizer" );
381  if ( !props.value( "uom", "" ).isEmpty() )
382  symbolizerElem.setAttribute( "uom", props.value( "uom", "" ) );
383  element.appendChild( symbolizerElem );
384 
385  // <Geometry>
386  QgsSymbolLayerV2Utils::createGeometryElement( doc, symbolizerElem, props.value( "geom", "" ) );
387 
388  writeSldMarker( doc, symbolizerElem, props );
389 }
390 
392 {
393  // <Graphic>
394  QDomElement graphicElem = doc.createElement( "se:Graphic" );
395  element.appendChild( graphicElem );
396 
397  double outlineWidth = QgsSymbolLayerV2Utils::rescaleUom( mOutlineWidth, mOutlineWidthUnit, props );
398  double symbolWidth = QgsSymbolLayerV2Utils::rescaleUom( mSymbolWidth, mSymbolWidthUnit, props );
399  QgsSymbolLayerV2Utils::wellKnownMarkerToSld( doc, graphicElem, mSymbolName, mColor, mOutlineColor, mOutlineStyle, outlineWidth, symbolWidth );
400 
401  // <Rotation>
403 
404  QString angleFunc = props.value( "angle", "" );
405  if ( angleFunc.isEmpty() ) // symbol has no angle set
406  {
407  if ( ddRotation && ddRotation->isActive() )
408  {
409  angleFunc = ddRotation->useExpression() ? ddRotation->expressionString() : ddRotation->field();
410  }
411  else if ( !qgsDoubleNear( mAngle, 0.0 ) )
412  angleFunc = QString::number( mAngle );
413  }
414  else if ( ddRotation && ddRotation->isActive() )
415  {
416  // the symbol has an angle and the symbol layer have a rotation
417  // property set
418  angleFunc = QString( "%1 + %2" ).arg( angleFunc, ddRotation->useExpression() ? ddRotation->expressionString() : ddRotation->field() );
419  }
420  else if ( !qgsDoubleNear( mAngle, 0.0 ) )
421  {
422  // both the symbol and the symbol layer have angle value set
423  bool ok;
424  double angle = angleFunc.toDouble( &ok );
425  if ( !ok )
426  {
427  // its a string (probably a property name or a function)
428  angleFunc = QString( "%1 + %2" ).arg( angleFunc ).arg( mAngle );
429  }
430  else if ( !qgsDoubleNear( angle + mAngle, 0.0 ) )
431  {
432  // it's a double value
433  angleFunc = QString::number( angle + mAngle );
434  }
435  }
436  QgsSymbolLayerV2Utils::createRotationElement( doc, graphicElem, angleFunc );
437  QgsSymbolLayerV2Utils::createRotationElement( doc, graphicElem, angleFunc );
438 
439  // <Displacement>
441  QgsSymbolLayerV2Utils::createDisplacementElement( doc, graphicElem, offset );
442 
443  // store w/h factor in a <VendorOption>
444  double widthHeightFactor = mSymbolWidth / mSymbolHeight;
445  QDomElement factorElem = QgsSymbolLayerV2Utils::createVendorOptionElement( doc, "widthHeightFactor", QString::number( widthHeightFactor ) );
446  graphicElem.appendChild( factorElem );
447 }
448 
450 {
451  QgsDebugMsg( "Entered." );
452 
453  QDomElement graphicElem = element.firstChildElement( "Graphic" );
454  if ( graphicElem.isNull() )
455  return nullptr;
456 
457  QString name = "circle";
458  QColor fillColor, borderColor;
459  double borderWidth, size;
460  double widthHeightFactor = 1.0;
461  Qt::PenStyle borderStyle;
462 
463  QgsStringMap vendorOptions = QgsSymbolLayerV2Utils::getVendorOptionList( graphicElem );
464  for ( QgsStringMap::iterator it = vendorOptions.begin(); it != vendorOptions.end(); ++it )
465  {
466  if ( it.key() == "widthHeightFactor" )
467  {
468  bool ok;
469  double v = it.value().toDouble( &ok );
470  if ( ok && !qgsDoubleNear( v, 0.0 ) && v > 0 )
471  widthHeightFactor = v;
472  }
473  }
474 
475  if ( !QgsSymbolLayerV2Utils::wellKnownMarkerFromSld( graphicElem, name, fillColor, borderColor, borderStyle, borderWidth, size ) )
476  return nullptr;
477 
478  double angle = 0.0;
479  QString angleFunc;
480  if ( QgsSymbolLayerV2Utils::rotationFromSldElement( graphicElem, angleFunc ) )
481  {
482  bool ok;
483  double d = angleFunc.toDouble( &ok );
484  if ( ok )
485  angle = d;
486  }
487 
489  m->setSymbolName( name );
490  m->setFillColor( fillColor );
491  m->setOutlineColor( borderColor );
492  m->setOutlineStyle( borderStyle );
493  m->setOutlineWidth( borderWidth );
494  m->setSymbolWidth( size );
495  m->setSymbolHeight( size / widthHeightFactor );
496  m->setAngle( angle );
497  return m;
498 }
499 
501 {
502  QgsStringMap map;
503  map["symbol_name"] = mSymbolName;
504  map["symbol_width"] = QString::number( mSymbolWidth );
505  map["symbol_width_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mSymbolWidthUnit );
506  map["symbol_width_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mSymbolWidthMapUnitScale );
507  map["symbol_height"] = QString::number( mSymbolHeight );
508  map["symbol_height_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mSymbolHeightUnit );
509  map["symbol_height_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mSymbolHeightMapUnitScale );
510  map["angle"] = QString::number( mAngle );
511  map["outline_style"] = QgsSymbolLayerV2Utils::encodePenStyle( mOutlineStyle );
512  map["outline_width"] = QString::number( mOutlineWidth );
513  map["outline_width_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOutlineWidthUnit );
514  map["outline_width_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOutlineWidthMapUnitScale );
515  map["color"] = QgsSymbolLayerV2Utils::encodeColor( mColor );
516  map["outline_color"] = QgsSymbolLayerV2Utils::encodeColor( mOutlineColor );
517  map["offset"] = QgsSymbolLayerV2Utils::encodePoint( mOffset );
519  map["offset_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOffsetMapUnitScale );
520  map["size"] = QString::number( mSize );
522  map["size_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mSizeMapUnitScale );
523  map["horizontal_anchor_point"] = QString::number( mHorizontalAnchorPoint );
524  map["vertical_anchor_point"] = QString::number( mVerticalAnchorPoint );
526  return map;
527 }
528 
529 QSizeF QgsEllipseSymbolLayerV2::calculateSize( QgsSymbolV2RenderContext& context, double* scaledWidth, double* scaledHeight )
530 {
531  double width = 0;
532 
533  if ( hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_WIDTH ) ) //1. priority: data defined setting on symbol layer le
534  {
535  context.setOriginalValueVariable( mSymbolWidth );
536  width = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_WIDTH, context, mSymbolWidth ).toDouble();
537  }
538  else if ( context.renderHints() & QgsSymbolV2::DataDefinedSizeScale ) //2. priority: is data defined size on symbol level
539  {
540  width = mSize;
541  }
542  else //3. priority: global width setting
543  {
544  width = mSymbolWidth;
545  }
546  if ( scaledWidth )
547  {
548  *scaledWidth = width;
549  }
550  width = QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), width, mSymbolWidthUnit, mSymbolHeightMapUnitScale );
551 
552  double height = 0;
553  if ( hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_HEIGHT ) ) //1. priority: data defined setting on symbol layer level
554  {
555  context.setOriginalValueVariable( mSymbolHeight );
556  height = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_HEIGHT, context, mSymbolHeight ).toDouble();
557  }
558  else if ( context.renderHints() & QgsSymbolV2::DataDefinedSizeScale ) //2. priority: is data defined size on symbol level
559  {
560  height = mSize;
561  }
562  else //3. priority: global height setting
563  {
564  height = mSymbolHeight;
565  }
566  if ( scaledHeight )
567  {
568  *scaledHeight = height;
569  }
570  height = QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), height, mSymbolHeightUnit, mSymbolHeightMapUnitScale );
571  return QSizeF( width, height );
572 }
573 
574 void QgsEllipseSymbolLayerV2::preparePath( const QString& symbolName, QgsSymbolV2RenderContext& context, double* scaledWidth, double* scaledHeight, const QgsFeature* )
575 {
576  mPainterPath = QPainterPath();
577 
578  QSizeF size = calculateSize( context, scaledWidth, scaledHeight );
579 
580  if ( symbolName == "circle" )
581  {
582  mPainterPath.addEllipse( QRectF( -size.width() / 2.0, -size.height() / 2.0, size.width(), size.height() ) );
583  }
584  else if ( symbolName == "rectangle" )
585  {
586  mPainterPath.addRect( QRectF( -size.width() / 2.0, -size.height() / 2.0, size.width(), size.height() ) );
587  }
588  else if ( symbolName == "cross" )
589  {
590  mPainterPath.moveTo( 0, -size.height() / 2.0 );
591  mPainterPath.lineTo( 0, size.height() / 2.0 );
592  mPainterPath.moveTo( -size.width() / 2.0, 0 );
593  mPainterPath.lineTo( size.width() / 2.0, 0 );
594  }
595  else if ( symbolName == "triangle" )
596  {
597  mPainterPath.moveTo( 0, -size.height() / 2.0 );
598  mPainterPath.lineTo( -size.width() / 2.0, size.height() / 2.0 );
599  mPainterPath.lineTo( size.width() / 2.0, size.height() / 2.0 );
600  mPainterPath.lineTo( 0, -size.height() / 2.0 );
601  }
602 }
603 
605 {
607  mSymbolWidthUnit = unit;
608  mSymbolHeightUnit = unit;
609  mOutlineWidthUnit = unit;
610 }
611 
613 {
615  if ( mSymbolWidthUnit != unit || mSymbolHeightUnit != unit || mOutlineWidthUnit != unit )
616  {
617  return QgsSymbolV2::Mixed;
618  }
619  return unit;
620 }
621 
623 {
625  mSymbolWidthMapUnitScale = scale;
626  mSymbolHeightMapUnitScale = scale;
627  mOutlineWidthMapUnitScale = scale;
628 }
629 
631 {
632  if ( QgsMarkerSymbolLayerV2::mapUnitScale() == mSymbolWidthMapUnitScale &&
633  mSymbolWidthMapUnitScale == mSymbolHeightMapUnitScale &&
634  mSymbolHeightMapUnitScale == mOutlineWidthMapUnitScale )
635  {
636  return mSymbolWidthMapUnitScale;
637  }
638  return QgsMapUnitScale();
639 }
640 
642 {
643  QSizeF size = calculateSize( context );
644 
645  bool hasDataDefinedRotation = false;
646  QPointF offset;
647  double angle = 0;
648  calculateOffsetAndRotation( context, size.width(), size.height(), hasDataDefinedRotation, offset, angle );
649 
650  double pixelSize = 1.0 / context.renderContext().rasterScaleFactor();
651 
652  QMatrix transform;
653 
654  // move to the desired position
655  transform.translate( point.x() + offset.x(), point.y() + offset.y() );
656 
657  if ( !qgsDoubleNear( angle, 0.0 ) )
658  transform.rotate( angle );
659 
660  double penWidth = 0.0;
661  bool ok = true;
663  {
664  context.setOriginalValueVariable( mOutlineWidth );
666  if ( ok )
667  {
668  penWidth = QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), outlineWidth, mOutlineWidthUnit, mOutlineWidthMapUnitScale );
669  }
670  }
672  {
675  if ( ok && outlineStyle == "no" )
676  {
677  penWidth = 0.0;
678  }
679  }
680 
681  //antialiasing
682  penWidth += pixelSize;
683 
684  QRectF symbolBounds = transform.mapRect( QRectF( -size.width() / 2.0,
685  -size.height() / 2.0,
686  size.width(),
687  size.height() ) );
688 
689  //extend bounds by pen width / 2.0
690  symbolBounds.adjust( -penWidth / 2.0, -penWidth / 2.0,
691  penWidth / 2.0, penWidth / 2.0 );
692 
693  return symbolBounds;
694 }
695 
696 bool QgsEllipseSymbolLayerV2::writeDxf( QgsDxfExport& e, double mmMapUnitScaleFactor, const QString& layerName, QgsSymbolV2RenderContext &context, QPointF shift ) const
697 {
698  //width
699  double symbolWidth = mSymbolWidth;
700 
701  if ( hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_WIDTH ) ) //1. priority: data defined setting on symbol layer le
702  {
703  context.setOriginalValueVariable( mSymbolWidth );
704  symbolWidth = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_WIDTH, context, mSymbolWidth ).toDouble();
705  }
706  else if ( context.renderHints() & QgsSymbolV2::DataDefinedSizeScale ) //2. priority: is data defined size on symbol level
707  {
708  symbolWidth = mSize;
709  }
710  if ( mSymbolWidthUnit == QgsSymbolV2::MM )
711  {
712  symbolWidth *= mmMapUnitScaleFactor;
713  }
714 
715  //height
716  double symbolHeight = mSymbolHeight;
717  if ( hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_HEIGHT ) ) //1. priority: data defined setting on symbol layer level
718  {
719  context.setOriginalValueVariable( mSymbolHeight );
720  symbolHeight = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_HEIGHT, context, mSymbolHeight ).toDouble();
721  }
722  else if ( context.renderHints() & QgsSymbolV2::DataDefinedSizeScale ) //2. priority: is data defined size on symbol level
723  {
724  symbolHeight = mSize;
725  }
726  if ( mSymbolHeightUnit == QgsSymbolV2::MM )
727  {
728  symbolHeight *= mmMapUnitScaleFactor;
729  }
730 
731  //outline width
732  double outlineWidth = mOutlineWidth;
733 
735  {
736  context.setOriginalValueVariable( mOutlineWidth );
737  outlineWidth = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_OUTLINE_WIDTH, context, mOutlineWidth ).toDouble();
738  }
739  if ( mOutlineWidthUnit == QgsSymbolV2::MM )
740  {
741  outlineWidth *= outlineWidth;
742  }
743 
744  //fill color
745  bool ok;
746  QColor fc = mColor;
748  {
751  if ( ok )
752  fc = QgsSymbolLayerV2Utils::decodeColor( colorString );
753  }
754 
755  //outline color
756  QColor oc = mOutlineColor;
758  {
761  if ( ok )
762  oc = QgsSymbolLayerV2Utils::decodeColor( colorString );
763  }
764 
765  //symbol name
766  QString symbolName = mSymbolName;
768  {
769  context.setOriginalValueVariable( mSymbolName );
770  symbolName = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_SYMBOL_NAME, context, mSymbolName ).toString();
771  }
772 
773  //offset
774  double offsetX = 0;
775  double offsetY = 0;
776  markerOffset( context, offsetX, offsetY );
777  QPointF off( offsetX, offsetY );
778 
779  //priority for rotation: 1. data defined symbol level, 2. symbol layer rotation (mAngle)
780  double rotation = 0.0;
782  {
783  context.setOriginalValueVariable( mAngle );
785  }
786  else if ( !qgsDoubleNear( mAngle + mLineAngle, 0.0 ) )
787  {
788  rotation = mAngle + mLineAngle;
789  }
790  rotation = -rotation; //rotation in Qt is counterclockwise
791  if ( rotation )
792  off = _rotatedOffset( off, rotation );
793 
794  QTransform t;
795  t.translate( shift.x() + offsetX, shift.y() + offsetY );
796 
797  if ( !qgsDoubleNear( rotation, 0.0 ) )
798  t.rotate( rotation );
799 
800  double halfWidth = symbolWidth / 2.0;
801  double halfHeight = symbolHeight / 2.0;
802 
803  if ( symbolName == "circle" )
804  {
805  if ( qgsDoubleNear( halfWidth, halfHeight ) )
806  {
807  QPointF pt( t.map( QPointF( 0, 0 ) ) );
808  e.writeFilledCircle( layerName, oc, pt, halfWidth );
809  }
810  else
811  {
812  QgsPolyline line;
813  line.reserve( 40 );
814  double stepsize = 2 * M_PI / 40;
815  for ( int i = 0; i < 39; ++i )
816  {
817  double angle = stepsize * i;
818  double x = halfWidth * cos( angle );
819  double y = halfHeight * sin( angle );
820  QPointF pt( t.map( QPointF( x, y ) ) );
821  line.push_back( pt );
822  }
823  //close ellipse with first point
824  line.push_back( line.at( 0 ) );
825  if ( mBrush.style() != Qt::NoBrush )
826  e.writePolygon( QgsPolygon() << line, layerName, "SOLID", fc );
827  if ( mPen.style() != Qt::NoPen )
828  e.writePolyline( line, layerName, "CONTINUOUS", oc, outlineWidth );
829  }
830  }
831  else if ( symbolName == "rectangle" )
832  {
833  QgsPolygon p( 1 );
834  p[0].resize( 5 );
835  p[0][0] = t.map( QPointF( -halfWidth, -halfHeight ) );
836  p[0][1] = t.map( QPointF( halfWidth, -halfHeight ) );
837  p[0][2] = t.map( QPointF( halfWidth, halfHeight ) );
838  p[0][3] = t.map( QPointF( -halfWidth, halfHeight ) );
839  p[0][4] = p[0][0];
840  if ( mBrush.style() != Qt::NoBrush )
841  e.writePolygon( p, layerName, "SOLID", fc );
842  if ( mPen.style() != Qt::NoPen )
843  e.writePolyline( p[0], layerName, "CONTINUOUS", oc, outlineWidth );
844  return true;
845  }
846  else if ( symbolName == "cross" && mPen.style() != Qt::NoPen )
847  {
848  QgsPolyline line( 2 );
849  line[0] = t.map( QPointF( -halfWidth, 0 ) );
850  line[1] = t.map( QPointF( halfWidth, 0 ) );
851  e.writePolyline( line, layerName, "CONTINUOUS", oc, outlineWidth );
852 
853  line[0] = t.map( QPointF( 0, halfHeight ) );
854  line[1] = t.map( QPointF( 0, -halfHeight ) );
855  e.writePolyline( line, layerName, "CONTINUOUS", oc, outlineWidth );
856 
857  return true;
858  }
859  else if ( symbolName == "triangle" )
860  {
861  QgsPolygon p( 1 );
862  p[0].resize( 4 );
863  p[0][0] = QPointF( t.map( QPointF( -halfWidth, -halfHeight ) ) );
864  p[0][1] = QPointF( t.map( QPointF( halfWidth, -halfHeight ) ) );
865  p[0][2] = QPointF( t.map( QPointF( 0, halfHeight ) ) );
866  p[0][3] = p[0][0];
867  if ( mBrush.style() != Qt::NoBrush )
868  e.writePolygon( p, layerName, "SOLID", fc );
869  if ( mPen.style() != Qt::NoPen )
870  e.writePolyline( p[0], layerName, "CONTINUOUS", oc, outlineWidth );
871  return true;
872  }
873 
874  return false; //soon...
875 }
876 
877 
void addEllipse(const QRectF &boundingRectangle)
static QString encodeOutputUnit(QgsSymbolV2::OutputUnit unit)
static const QString EXPR_OUTLINE_COLOR
void writeSldMarker(QDomDocument &doc, QDomElement &element, const QgsStringMap &props) const override
static void createRotationElement(QDomDocument &doc, QDomElement &element, const QString &rotationFunc)
void markerOffset(QgsSymbolV2RenderContext &context, double &offsetX, double &offsetY) const
Qt::PenStyle style() const
void setSymbolWidthUnit(QgsSymbolV2::OutputUnit unit)
QColor fillColor() const override
Get fill color.
QgsSymbolV2::OutputUnit outputUnit() const override
void setStyle(Qt::PenStyle style)
static QPointF _rotatedOffset(QPointF offset, double angle)
void renderPoint(QPointF point, QgsSymbolV2RenderContext &context) override
OutputUnit
The unit of the output.
Definition: qgssymbolv2.h:62
QgsMapUnitScale mSizeMapUnitScale
A container class for data source field mapping or expression.
bool contains(const Key &key) const
static Q_DECL_DEPRECATED bool wellKnownMarkerFromSld(QDomElement &element, QString &name, QColor &color, QColor &borderColor, double &borderWidth, double &size)
void startRender(QgsSymbolV2RenderContext &context) override
QDomNode appendChild(const QDomNode &newChild)
static double rescaleUom(double size, QgsSymbolV2::OutputUnit unit, const QgsStringMap &props)
Rescales the given size based on the uomScale found in the props, if any is found, otherwise returns the value un-modified.
static QDomElement createVendorOptionElement(QDomDocument &doc, const QString &name, const QString &value)
Qt::BrushStyle style() const
static void createGeometryElement(QDomDocument &doc, QDomElement &element, const QString &geomFunc)
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
QPoint map(const QPoint &point) const
static QString encodeColor(const QColor &color)
static const QString EXPR_WIDTH
static QgsStringMap getVendorOptionList(QDomElement &element)
void setOffset(QPointF offset)
void setOutlineWidthUnit(QgsSymbolV2::OutputUnit unit)
void setHorizontalAnchorPoint(HorizontalAnchorPoint h)
virtual bool hasDataDefinedProperties() const
Checks whether the layer has any associated data defined properties.
void setOriginalValueVariable(const QVariant &value)
Sets the original value variable value for data defined symbology.
void setVerticalAnchorPoint(VerticalAnchorPoint v)
QgsEllipseSymbolLayerV2 * clone() const override
Shall be reimplemented by subclasses to create a deep copy of the instance.
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:76
void setJoinStyle(Qt::PenJoinStyle style)
void moveTo(const QPointF &point)
static QPointF decodePoint(const QString &str)
const QgsGeometry * constGeometry() const
Gets a const pointer to the geometry object associated with this feature.
Definition: qgsfeature.cpp:82
const QgsFeature * feature() const
Current feature being rendered - may be null.
Definition: qgssymbolv2.h:375
static QString encodeMapUnitScale(const QgsMapUnitScale &mapUnitScale)
QRectF bounds(QPointF point, QgsSymbolV2RenderContext &context) override
Returns the approximate bounding box of the marker symbol layer, taking into account any data defined...
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:187
void setOffsetMapUnitScale(const QgsMapUnitScale &scale)
virtual QgsDataDefined * getDataDefinedProperty(const QString &property) const
Returns the data defined property corresponding to the specified property key.
static void createDisplacementElement(QDomDocument &doc, QDomElement &element, QPointF offset)
double toDouble(bool *ok) const
void setStyle(Qt::BrushStyle style)
A symbol layer for rendering objects with major and minor axis (e.g.
QgsStringMap properties() const override
Should be reimplemented by subclasses to return a string map that contains the configuration informat...
void adjust(qreal dx1, qreal dy1, qreal dx2, qreal dy2)
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
Definition: qgis.h:285
void setMapUnitScale(const QgsMapUnitScale &scale) override
virtual Q_DECL_DEPRECATED QVariant evaluateDataDefinedProperty(const QString &property, const QgsFeature *feature, const QVariant &defaultVal=QVariant(), bool *ok=nullptr) const
Evaluates the matching data defined property and returns the calculated value.
double mapRotation() const
Return current map rotation in degrees.
void setOffsetUnit(QgsSymbolV2::OutputUnit unit)
bool useExpression() const
Returns if the field or the expression part is active.
void setMapUnitScale(const QgsMapUnitScale &scale) override
static QgsSymbolV2::OutputUnit decodeOutputUnit(const QString &str)
static QString encodePenStyle(Qt::PenStyle style)
Perform transforms between map coordinates and device coordinates.
Definition: qgsmaptopixel.h:34
Mixed units in symbol layers.
Definition: qgssymbolv2.h:66
void setSymbolHeightMapUnitScale(const QgsMapUnitScale &scale)
QTransform & translate(qreal dx, qreal dy)
The output shall be in millimeters.
Definition: qgssymbolv2.h:64
QString number(int n, int base)
static const QString EXPR_FILL_COLOR
qreal x() const
qreal y() const
void setOutputUnit(QgsSymbolV2::OutputUnit unit) override
void resize(int size)
void toSld(QDomDocument &doc, QDomElement &element, const QgsStringMap &props) const override
Writes the SLD element following the SLD v1.1 specs.
static QString encodePoint(QPointF point)
static double convertToPainterUnits(const QgsRenderContext &c, double size, QgsSymbolV2::OutputUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale())
Converts a size from the specied units to painter units.
void setPen(const QColor &color)
void lineTo(const QPointF &endPoint)
void setAttribute(const QString &name, const QString &value)
QMatrix & translate(qreal dx, qreal dy)
QString expressionString() const
Returns the expression string of this QgsDataDefined.
bool isEmpty() const
void addRect(const QRectF &rectangle)
#define M_PI
void setSizeUnit(QgsSymbolV2::OutputUnit unit)
bool writeDxf(QgsDxfExport &e, double mmMapUnitScaleFactor, const QString &layerName, QgsSymbolV2RenderContext &context, QPointF shift=QPointF(0.0, 0.0)) const override
void setWidthF(qreal width)
void setBrush(const QBrush &brush)
void writeFilledCircle(const QString &layer, const QColor &color, const QgsPoint &pt, double radius)
Write filled circle (as hatch)
Qt::PenStyle outlineStyle() const
HorizontalAnchorPoint mHorizontalAnchorPoint
iterator end()
void setOutlineStyle(Qt::PenStyle outlineStyle)
void setColor(const QColor &color)
void setSymbolName(const QString &name)
virtual Q_DECL_DEPRECATED void prepareExpressions(const QgsFields *fields, double scale=-1.0)
Prepares all data defined property expressions for evaluation.
QGis::GeometryType type() const
Returns type of the geometry as a QGis::GeometryType.
virtual QColor color() const
The fill color.
iterator begin()
static Qt::PenStyle decodePenStyle(const QString &str)
static const QString EXPR_OUTLINE_STYLE
void writePolyline(const QgsPolyline &line, const QString &layer, const QString &lineStyleName, const QColor &color, double width=-1)
Draw dxf primitives (LWPOLYLINE)
static QgsSymbolLayerV2 * create(const QgsStringMap &properties=QgsStringMap())
void copyDataDefinedProperties(QgsSymbolLayerV2 *destLayer) const
Copies all data defined properties of this layer to another symbol layer.
void saveDataDefinedProperties(QgsStringMap &stringMap) const
Saves all data defined properties to a string map.
void reserve(int size)
QRect mapRect(const QRect &rectangle) const
QString field() const
Get the field which this QgsDataDefined represents.
bool isNull() const
void startRender(QgsSymbolV2RenderContext &context) override
static const QString EXPR_OUTLINE_WIDTH
QTransform & rotate(qreal angle, Qt::Axis axis)
void copyPaintEffect(QgsSymbolLayerV2 *destLayer) const
Copies paint effect of this layer to another symbol layer.
const T & at(int i) const
QMatrix & rotate(qreal degrees)
QPainter * painter()
const QgsMapToPixel & mapToPixel() const
void drawPath(const QPainterPath &path)
static QgsSymbolLayerV2 * createFromSld(QDomElement &element)
void setWidth(int width)
Struct for storing maximum and minimum scales for measurements in map units.
QgsMapUnitScale mapUnitScale() const override
virtual bool hasDataDefinedProperty(const QString &property) const
Checks whether the layer has a matching data defined property and if that property is currently activ...
void setSymbolWidthMapUnitScale(const QgsMapUnitScale &scale)
QgsRenderContext & renderContext()
Definition: qgssymbolv2.h:346
QDomElement firstChildElement(const QString &tagName) const
void setOutlineColor(const QColor &c) override
Set outline color.
void writePolygon(const QgsPolygon &polygon, const QString &layer, const QString &hatchPattern, const QColor &color)
Draw dxf filled polygon (HATCH)
static const QString EXPR_ROTATION
void push_back(const T &value)
QgsSymbolV2::OutputUnit mOffsetUnit
virtual void setColor(const QColor &color)
The fill color.
static bool rotationFromSldElement(QDomElement &element, QString &rotationFunc)
double toDouble(bool *ok) const
static QColor decodeColor(const QString &str)
VerticalAnchorPoint mVerticalAnchorPoint
void stopRender(QgsSymbolV2RenderContext &context) override
QgsSymbolV2::OutputUnit mSizeUnit
QgsMapUnitScale mOffsetMapUnitScale
void restoreDataDefinedProperties(const QgsStringMap &stringMap)
Restores all data defined properties from string map.
static QgsMapUnitScale decodeMapUnitScale(const QString &str)
QString layerType() const override
Returns a string that represents this layer type.
double rasterScaleFactor() const
QDomElement createElement(const QString &tagName)
static const QString EXPR_SYMBOL_NAME
qreal height() const
QgsMapUnitScale mapUnitScale() const override
void setSize(double size)
void map(int x, int y, int *tx, int *ty) const
void setAngle(double angle)
void setColor(const QColor &color)
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
QString toString() const
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
bool isActive() const
qreal width() const
void setOutlineWidthMapUnitScale(const QgsMapUnitScale &scale)
static const QString EXPR_HEIGHT
const T value(const Key &key) const
static Q_DECL_DEPRECATED void wellKnownMarkerToSld(QDomDocument &doc, QDomElement &element, const QString &name, const QColor &color, const QColor &borderColor=QColor(), double borderWidth=-1, double size=-1)
virtual Q_DECL_DEPRECATED void setDataDefinedProperty(const QString &property, const QString &expressionString)
Sets a data defined expression for a property.