QGIS API Documentation  2.14.0-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 }
353 
354 void QgsEllipseSymbolLayerV2::toSld( QDomDocument &doc, QDomElement &element, const QgsStringMap& props ) const
355 {
356  QDomElement symbolizerElem = doc.createElement( "se:PointSymbolizer" );
357  if ( !props.value( "uom", "" ).isEmpty() )
358  symbolizerElem.setAttribute( "uom", props.value( "uom", "" ) );
359  element.appendChild( symbolizerElem );
360 
361  // <Geometry>
362  QgsSymbolLayerV2Utils::createGeometryElement( doc, symbolizerElem, props.value( "geom", "" ) );
363 
364  writeSldMarker( doc, symbolizerElem, props );
365 }
366 
368 {
369  // <Graphic>
370  QDomElement graphicElem = doc.createElement( "se:Graphic" );
371  element.appendChild( graphicElem );
372 
373  QgsSymbolLayerV2Utils::wellKnownMarkerToSld( doc, graphicElem, mSymbolName, mColor, mOutlineColor, mOutlineStyle, mOutlineWidth, mSymbolWidth );
374 
375  // store w/h factor in a <VendorOption>
376  double widthHeightFactor = mSymbolWidth / mSymbolHeight;
377  QDomElement factorElem = QgsSymbolLayerV2Utils::createVendorOptionElement( doc, "widthHeightFactor", QString::number( widthHeightFactor ) );
378  graphicElem.appendChild( factorElem );
379 
380  // <Rotation>
382 
383  QString angleFunc = props.value( "angle", "" );
384  if ( angleFunc.isEmpty() ) // symbol has no angle set
385  {
386  if ( ddRotation && ddRotation->isActive() )
387  {
388  angleFunc = ddRotation->useExpression() ? ddRotation->expressionString() : ddRotation->field();
389  }
390  else if ( !qgsDoubleNear( mAngle, 0.0 ) )
391  angleFunc = QString::number( mAngle );
392  }
393  else if ( ddRotation && ddRotation->isActive() )
394  {
395  // the symbol has an angle and the symbol layer have a rotation
396  // property set
397  angleFunc = QString( "%1 + %2" ).arg( angleFunc, ddRotation->useExpression() ? ddRotation->expressionString() : ddRotation->field() );
398  }
399  else if ( !qgsDoubleNear( mAngle, 0.0 ) )
400  {
401  // both the symbol and the symbol layer have angle value set
402  bool ok;
403  double angle = angleFunc.toDouble( &ok );
404  if ( !ok )
405  {
406  // its a string (probably a property name or a function)
407  angleFunc = QString( "%1 + %2" ).arg( angleFunc ).arg( mAngle );
408  }
409  else if ( !qgsDoubleNear( angle + mAngle, 0.0 ) )
410  {
411  // it's a double value
412  angleFunc = QString::number( angle + mAngle );
413  }
414  }
415  QgsSymbolLayerV2Utils::createRotationElement( doc, graphicElem, angleFunc );
416 }
417 
419 {
420  QgsDebugMsg( "Entered." );
421 
422  QDomElement graphicElem = element.firstChildElement( "Graphic" );
423  if ( graphicElem.isNull() )
424  return nullptr;
425 
426  QString name = "circle";
427  QColor fillColor, borderColor;
428  double borderWidth, size;
429  double widthHeightFactor = 1.0;
430  Qt::PenStyle borderStyle;
431 
432  QgsStringMap vendorOptions = QgsSymbolLayerV2Utils::getVendorOptionList( graphicElem );
433  for ( QgsStringMap::iterator it = vendorOptions.begin(); it != vendorOptions.end(); ++it )
434  {
435  if ( it.key() == "widthHeightFactor" )
436  {
437  bool ok;
438  double v = it.value().toDouble( &ok );
439  if ( ok && !qgsDoubleNear( v, 0.0 ) && v > 0 )
440  widthHeightFactor = v;
441  }
442  }
443 
444  if ( !QgsSymbolLayerV2Utils::wellKnownMarkerFromSld( graphicElem, name, fillColor, borderColor, borderStyle, borderWidth, size ) )
445  return nullptr;
446 
447  double angle = 0.0;
448  QString angleFunc;
449  if ( QgsSymbolLayerV2Utils::rotationFromSldElement( graphicElem, angleFunc ) )
450  {
451  bool ok;
452  double d = angleFunc.toDouble( &ok );
453  if ( ok )
454  angle = d;
455  }
456 
458  m->setSymbolName( name );
459  m->setFillColor( fillColor );
460  m->setOutlineColor( borderColor );
461  m->setOutlineStyle( borderStyle );
462  m->setOutlineWidth( borderWidth );
463  m->setSymbolWidth( size );
464  m->setSymbolHeight( size / widthHeightFactor );
465  m->setAngle( angle );
466  return m;
467 }
468 
470 {
471  QgsStringMap map;
472  map["symbol_name"] = mSymbolName;
473  map["symbol_width"] = QString::number( mSymbolWidth );
474  map["symbol_width_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mSymbolWidthUnit );
475  map["symbol_width_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mSymbolWidthMapUnitScale );
476  map["symbol_height"] = QString::number( mSymbolHeight );
477  map["symbol_height_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mSymbolHeightUnit );
478  map["symbol_height_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mSymbolHeightMapUnitScale );
479  map["angle"] = QString::number( mAngle );
480  map["outline_style"] = QgsSymbolLayerV2Utils::encodePenStyle( mOutlineStyle );
481  map["outline_width"] = QString::number( mOutlineWidth );
482  map["outline_width_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOutlineWidthUnit );
483  map["outline_width_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOutlineWidthMapUnitScale );
484  map["color"] = QgsSymbolLayerV2Utils::encodeColor( mColor );
485  map["outline_color"] = QgsSymbolLayerV2Utils::encodeColor( mOutlineColor );
486  map["offset"] = QgsSymbolLayerV2Utils::encodePoint( mOffset );
488  map["offset_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOffsetMapUnitScale );
489  map["size"] = QString::number( mSize );
491  map["size_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mSizeMapUnitScale );
492  map["horizontal_anchor_point"] = QString::number( mHorizontalAnchorPoint );
493  map["vertical_anchor_point"] = QString::number( mVerticalAnchorPoint );
495  return map;
496 }
497 
498 QSizeF QgsEllipseSymbolLayerV2::calculateSize( QgsSymbolV2RenderContext& context, double* scaledWidth, double* scaledHeight )
499 {
500  double width = 0;
501 
502  if ( hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_WIDTH ) ) //1. priority: data defined setting on symbol layer le
503  {
504  context.setOriginalValueVariable( mSymbolWidth );
505  width = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_WIDTH, context, mSymbolWidth ).toDouble();
506  }
507  else if ( context.renderHints() & QgsSymbolV2::DataDefinedSizeScale ) //2. priority: is data defined size on symbol level
508  {
509  width = mSize;
510  }
511  else //3. priority: global width setting
512  {
513  width = mSymbolWidth;
514  }
515  if ( scaledWidth )
516  {
517  *scaledWidth = width;
518  }
519  width = QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), width, mSymbolWidthUnit, mSymbolHeightMapUnitScale );
520 
521  double height = 0;
522  if ( hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_HEIGHT ) ) //1. priority: data defined setting on symbol layer level
523  {
524  context.setOriginalValueVariable( mSymbolHeight );
525  height = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_HEIGHT, context, mSymbolHeight ).toDouble();
526  }
527  else if ( context.renderHints() & QgsSymbolV2::DataDefinedSizeScale ) //2. priority: is data defined size on symbol level
528  {
529  height = mSize;
530  }
531  else //3. priority: global height setting
532  {
533  height = mSymbolHeight;
534  }
535  if ( scaledHeight )
536  {
537  *scaledHeight = height;
538  }
539  height = QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), height, mSymbolHeightUnit, mSymbolHeightMapUnitScale );
540  return QSizeF( width, height );
541 }
542 
543 void QgsEllipseSymbolLayerV2::preparePath( const QString& symbolName, QgsSymbolV2RenderContext& context, double* scaledWidth, double* scaledHeight, const QgsFeature* )
544 {
545  mPainterPath = QPainterPath();
546 
547  QSizeF size = calculateSize( context, scaledWidth, scaledHeight );
548 
549  if ( symbolName == "circle" )
550  {
551  mPainterPath.addEllipse( QRectF( -size.width() / 2.0, -size.height() / 2.0, size.width(), size.height() ) );
552  }
553  else if ( symbolName == "rectangle" )
554  {
555  mPainterPath.addRect( QRectF( -size.width() / 2.0, -size.height() / 2.0, size.width(), size.height() ) );
556  }
557  else if ( symbolName == "cross" )
558  {
559  mPainterPath.moveTo( 0, -size.height() / 2.0 );
560  mPainterPath.lineTo( 0, size.height() / 2.0 );
561  mPainterPath.moveTo( -size.width() / 2.0, 0 );
562  mPainterPath.lineTo( size.width() / 2.0, 0 );
563  }
564  else if ( symbolName == "triangle" )
565  {
566  mPainterPath.moveTo( 0, -size.height() / 2.0 );
567  mPainterPath.lineTo( -size.width() / 2.0, size.height() / 2.0 );
568  mPainterPath.lineTo( size.width() / 2.0, size.height() / 2.0 );
569  mPainterPath.lineTo( 0, -size.height() / 2.0 );
570  }
571 }
572 
574 {
576  mSymbolWidthUnit = unit;
577  mSymbolHeightUnit = unit;
578  mOutlineWidthUnit = unit;
579 }
580 
582 {
584  if ( mSymbolWidthUnit != unit || mSymbolHeightUnit != unit || mOutlineWidthUnit != unit )
585  {
586  return QgsSymbolV2::Mixed;
587  }
588  return unit;
589 }
590 
592 {
594  mSymbolWidthMapUnitScale = scale;
595  mSymbolHeightMapUnitScale = scale;
596  mOutlineWidthMapUnitScale = scale;
597 }
598 
600 {
601  if ( QgsMarkerSymbolLayerV2::mapUnitScale() == mSymbolWidthMapUnitScale &&
602  mSymbolWidthMapUnitScale == mSymbolHeightMapUnitScale &&
603  mSymbolHeightMapUnitScale == mOutlineWidthMapUnitScale )
604  {
605  return mSymbolWidthMapUnitScale;
606  }
607  return QgsMapUnitScale();
608 }
609 
611 {
612  QSizeF size = calculateSize( context );
613 
614  bool hasDataDefinedRotation = false;
615  QPointF offset;
616  double angle = 0;
617  calculateOffsetAndRotation( context, size.width(), size.height(), hasDataDefinedRotation, offset, angle );
618 
619  double pixelSize = 1.0 / context.renderContext().rasterScaleFactor();
620 
621  QMatrix transform;
622 
623  // move to the desired position
624  transform.translate( point.x() + offset.x(), point.y() + offset.y() );
625 
626  if ( !qgsDoubleNear( angle, 0.0 ) )
627  transform.rotate( angle );
628 
629  double penWidth = 0.0;
630  bool ok = true;
632  {
633  context.setOriginalValueVariable( mOutlineWidth );
635  if ( ok )
636  {
637  penWidth = QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), outlineWidth, mOutlineWidthUnit, mOutlineWidthMapUnitScale );
638  }
639  }
641  {
644  if ( ok && outlineStyle == "no" )
645  {
646  penWidth = 0.0;
647  }
648  }
649 
650  //antialiasing
651  penWidth += pixelSize;
652 
653  QRectF symbolBounds = transform.mapRect( QRectF( -size.width() / 2.0,
654  -size.height() / 2.0,
655  size.width(),
656  size.height() ) );
657 
658  //extend bounds by pen width / 2.0
659  symbolBounds.adjust( -penWidth / 2.0, -penWidth / 2.0,
660  penWidth / 2.0, penWidth / 2.0 );
661 
662  return symbolBounds;
663 }
664 
665 bool QgsEllipseSymbolLayerV2::writeDxf( QgsDxfExport& e, double mmMapUnitScaleFactor, const QString& layerName, QgsSymbolV2RenderContext *context, const QgsFeature*, QPointF shift ) const
666 {
667  //width
668  double symbolWidth = mSymbolWidth;
669 
670  if ( hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_WIDTH ) ) //1. priority: data defined setting on symbol layer le
671  {
672  context->setOriginalValueVariable( mSymbolWidth );
673  symbolWidth = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_WIDTH, *context, mSymbolWidth ).toDouble();
674  }
675  else if ( context->renderHints() & QgsSymbolV2::DataDefinedSizeScale ) //2. priority: is data defined size on symbol level
676  {
677  symbolWidth = mSize;
678  }
679  if ( mSymbolWidthUnit == QgsSymbolV2::MM )
680  {
681  symbolWidth *= mmMapUnitScaleFactor;
682  }
683 
684  //height
685  double symbolHeight = mSymbolHeight;
686  if ( hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_HEIGHT ) ) //1. priority: data defined setting on symbol layer level
687  {
688  context->setOriginalValueVariable( mSymbolHeight );
689  symbolHeight = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_HEIGHT, *context, mSymbolHeight ).toDouble();
690  }
691  else if ( context->renderHints() & QgsSymbolV2::DataDefinedSizeScale ) //2. priority: is data defined size on symbol level
692  {
693  symbolHeight = mSize;
694  }
695  if ( mSymbolHeightUnit == QgsSymbolV2::MM )
696  {
697  symbolHeight *= mmMapUnitScaleFactor;
698  }
699 
700  //outline width
701  double outlineWidth = mOutlineWidth;
702 
704  {
705  context->setOriginalValueVariable( mOutlineWidth );
706  outlineWidth = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_OUTLINE_WIDTH, *context, mOutlineWidth ).toDouble();
707  }
708  if ( mOutlineWidthUnit == QgsSymbolV2::MM )
709  {
710  outlineWidth *= outlineWidth;
711  }
712 
713  //fill color
714  bool ok;
715  QColor fc = mColor;
717  {
720  if ( ok )
721  fc = QgsSymbolLayerV2Utils::decodeColor( colorString );
722  }
723 
724  //outline color
725  QColor oc = mOutlineColor;
727  {
730  if ( ok )
731  oc = QgsSymbolLayerV2Utils::decodeColor( colorString );
732  }
733 
734  //symbol name
735  QString symbolName = mSymbolName;
737  {
738  context->setOriginalValueVariable( mSymbolName );
739  symbolName = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_SYMBOL_NAME, *context, mSymbolName ).toString();
740  }
741 
742  //offset
743  double offsetX = 0;
744  double offsetY = 0;
745  markerOffset( *context, offsetX, offsetY );
746  QPointF off( offsetX, offsetY );
747 
748  //priority for rotation: 1. data defined symbol level, 2. symbol layer rotation (mAngle)
749  double rotation = 0.0;
751  {
752  context->setOriginalValueVariable( mAngle );
754  }
755  else if ( !qgsDoubleNear( mAngle + mLineAngle, 0.0 ) )
756  {
757  rotation = mAngle + mLineAngle;
758  }
759  rotation = -rotation; //rotation in Qt is counterclockwise
760  if ( rotation )
761  off = _rotatedOffset( off, rotation );
762 
763  QTransform t;
764  t.translate( shift.x() + offsetX, shift.y() + offsetY );
765 
766  if ( !qgsDoubleNear( rotation, 0.0 ) )
767  t.rotate( rotation );
768 
769  double halfWidth = symbolWidth / 2.0;
770  double halfHeight = symbolHeight / 2.0;
771 
772  if ( symbolName == "circle" )
773  {
774  if ( qgsDoubleNear( halfWidth, halfHeight ) )
775  {
776  QPointF pt( t.map( QPointF( 0, 0 ) ) );
777  e.writeFilledCircle( layerName, oc, pt, halfWidth );
778  }
779  else
780  {
781  QgsPolyline line;
782  line.reserve( 40 );
783  double stepsize = 2 * M_PI / 40;
784  for ( int i = 0; i < 39; ++i )
785  {
786  double angle = stepsize * i;
787  double x = halfWidth * cos( angle );
788  double y = halfHeight * sin( angle );
789  QPointF pt( t.map( QPointF( x, y ) ) );
790  line.push_back( pt );
791  }
792  //close ellipse with first point
793  line.push_back( line.at( 0 ) );
794  if ( mBrush.style() != Qt::NoBrush )
795  e.writePolygon( QgsPolygon() << line, layerName, "SOLID", fc );
796  if ( mPen.style() != Qt::NoPen )
797  e.writePolyline( line, layerName, "CONTINUOUS", oc, outlineWidth );
798  }
799  }
800  else if ( symbolName == "rectangle" )
801  {
802  QgsPolygon p( 1 );
803  p[0].resize( 5 );
804  p[0][0] = t.map( QPointF( -halfWidth, -halfHeight ) );
805  p[0][1] = t.map( QPointF( halfWidth, -halfHeight ) );
806  p[0][2] = t.map( QPointF( halfWidth, halfHeight ) );
807  p[0][3] = t.map( QPointF( -halfWidth, halfHeight ) );
808  p[0][4] = p[0][0];
809  if ( mBrush.style() != Qt::NoBrush )
810  e.writePolygon( p, layerName, "SOLID", fc );
811  if ( mPen.style() != Qt::NoPen )
812  e.writePolyline( p[0], layerName, "CONTINUOUS", oc, outlineWidth );
813  return true;
814  }
815  else if ( symbolName == "cross" && mPen.style() != Qt::NoPen )
816  {
817  QgsPolyline line( 2 );
818  line[0] = t.map( QPointF( -halfWidth, 0 ) );
819  line[1] = t.map( QPointF( halfWidth, 0 ) );
820  e.writePolyline( line, layerName, "CONTINUOUS", oc, outlineWidth );
821 
822  line[0] = t.map( QPointF( 0, halfHeight ) );
823  line[1] = t.map( QPointF( 0, -halfHeight ) );
824  e.writePolyline( line, layerName, "CONTINUOUS", oc, outlineWidth );
825 
826  return true;
827  }
828  else if ( symbolName == "triangle" )
829  {
830  QgsPolygon p( 1 );
831  p[0].resize( 4 );
832  p[0][0] = QPointF( t.map( QPointF( -halfWidth, -halfHeight ) ) );
833  p[0][1] = QPointF( t.map( QPointF( halfWidth, -halfHeight ) ) );
834  p[0][2] = QPointF( t.map( QPointF( 0, halfHeight ) ) );
835  p[0][3] = p[0][0];
836  if ( mBrush.style() != Qt::NoBrush )
837  e.writePolygon( p, layerName, "SOLID", fc );
838  if ( mPen.style() != Qt::NoPen )
839  e.writePolyline( p[0], layerName, "CONTINUOUS", oc, outlineWidth );
840  return true;
841  }
842 
843  return false; //soon...
844 }
845 
846 
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)
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
int renderHints() const
Definition: qgssymbolv2.h:369
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 QDomElement createVendorOptionElement(QDomDocument &doc, const QString &name, const QString &value)
Qt::BrushStyle style() const
static void createGeometryElement(QDomDocument &doc, QDomElement &element, const QString &geomFunc)
QString field() const
Get the field which this QgsDataDefined represents.
#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)
QGis::GeometryType type() const
Returns type of the geometry as a QGis::GeometryType.
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)
QString expressionString() const
Returns the expression string of this QgsDataDefined.
static QString encodeMapUnitScale(const QgsMapUnitScale &mapUnitScale)
virtual bool hasDataDefinedProperty(const QString &property) const
Checks whether the layer has a matching data defined property and if that property is currently activ...
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)
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...
double mapRotation() const
Return current map rotation in degrees.
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
void setOffsetUnit(QgsSymbolV2::OutputUnit unit)
void setMapUnitScale(const QgsMapUnitScale &scale) override
static QgsSymbolV2::OutputUnit decodeOutputUnit(const QString &str)
bool writeDxf(QgsDxfExport &e, double mmMapUnitScaleFactor, const QString &layerName, QgsSymbolV2RenderContext *context, const QgsFeature *f, QPointF shift=QPointF(0.0, 0.0)) const override
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
void markerOffset(QgsSymbolV2RenderContext &context, double &offsetX, double &offsetY) const
qreal x() const
qreal y() const
void setOutputUnit(QgsSymbolV2::OutputUnit unit) override
void resize(int size)
const QgsFeature * feature() const
Current feature being rendered - may be null.
Definition: qgssymbolv2.h:374
void toSld(QDomDocument &doc, QDomElement &element, const QgsStringMap &props) const override
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)
bool isEmpty() const
void addRect(const QRectF &rectangle)
#define M_PI
void setSizeUnit(QgsSymbolV2::OutputUnit unit)
void setWidthF(qreal width)
void setBrush(const QBrush &brush)
double rasterScaleFactor() const
void writeFilledCircle(const QString &layer, const QColor &color, const QgsPoint &pt, double radius)
Write filled circle (as hatch)
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.
virtual bool hasDataDefinedProperties() const
Checks whether the layer has any associated data defined properties.
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())
bool useExpression() const
Returns if the field or the expression part is active.
void reserve(int size)
QRect mapRect(const QRect &rectangle) const
bool isNull() const
void startRender(QgsSymbolV2RenderContext &context) override
static const QString EXPR_OUTLINE_WIDTH
QTransform & rotate(qreal angle, Qt::Axis axis)
const T & at(int i) const
QMatrix & rotate(qreal degrees)
QPainter * painter()
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
void setSymbolWidthMapUnitScale(const QgsMapUnitScale &scale)
QgsRenderContext & renderContext()
Definition: qgssymbolv2.h:345
virtual QgsDataDefined * getDataDefinedProperty(const QString &property) const
Returns the data defined property corresponding to the specified property key.
QDomElement firstChildElement(const QString &tagName) const
void setOutlineColor(const QColor &c) override
Set outline color.
const QgsGeometry * constGeometry() const
Gets a const pointer to the geometry object associated with this feature.
Definition: qgsfeature.cpp:82
void writePolygon(const QgsPolygon &polygon, const QString &layer, const QString &hatchPattern, const QColor &color)
Draw dxf filled polygon (HATCH)
static const QString EXPR_ROTATION
const QgsMapToPixel & mapToPixel() const
void push_back(const T &value)
Qt::PenStyle outlineStyle() const
QgsSymbolV2::OutputUnit mOffsetUnit
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.
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)
QPointF offset() const
void setColor(const QColor &color)
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
QString toString() const
void saveDataDefinedProperties(QgsStringMap &stringMap) const
Saves all data defined properties to a string map.
void setSizeMapUnitScale(const QgsMapUnitScale &scale)
void setFillColor(const QColor &c) override
Set fill color.
bool isActive() const
void setSymbolHeightUnit(QgsSymbolV2::OutputUnit unit)
void setOutputUnit(QgsSymbolV2::OutputUnit unit) override
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.
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.