QGIS API Documentation  2.14.5-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  QgsSymbolLayerV2Utils::wellKnownMarkerToSld( doc, graphicElem, mSymbolName, mColor, mOutlineColor, mOutlineStyle, mOutlineWidth, mSymbolWidth );
398 
399  // store w/h factor in a <VendorOption>
400  double widthHeightFactor = mSymbolWidth / mSymbolHeight;
401  QDomElement factorElem = QgsSymbolLayerV2Utils::createVendorOptionElement( doc, "widthHeightFactor", QString::number( widthHeightFactor ) );
402  graphicElem.appendChild( factorElem );
403 
404  // <Rotation>
406 
407  QString angleFunc = props.value( "angle", "" );
408  if ( angleFunc.isEmpty() ) // symbol has no angle set
409  {
410  if ( ddRotation && ddRotation->isActive() )
411  {
412  angleFunc = ddRotation->useExpression() ? ddRotation->expressionString() : ddRotation->field();
413  }
414  else if ( !qgsDoubleNear( mAngle, 0.0 ) )
415  angleFunc = QString::number( mAngle );
416  }
417  else if ( ddRotation && ddRotation->isActive() )
418  {
419  // the symbol has an angle and the symbol layer have a rotation
420  // property set
421  angleFunc = QString( "%1 + %2" ).arg( angleFunc, ddRotation->useExpression() ? ddRotation->expressionString() : ddRotation->field() );
422  }
423  else if ( !qgsDoubleNear( mAngle, 0.0 ) )
424  {
425  // both the symbol and the symbol layer have angle value set
426  bool ok;
427  double angle = angleFunc.toDouble( &ok );
428  if ( !ok )
429  {
430  // its a string (probably a property name or a function)
431  angleFunc = QString( "%1 + %2" ).arg( angleFunc ).arg( mAngle );
432  }
433  else if ( !qgsDoubleNear( angle + mAngle, 0.0 ) )
434  {
435  // it's a double value
436  angleFunc = QString::number( angle + mAngle );
437  }
438  }
439  QgsSymbolLayerV2Utils::createRotationElement( doc, graphicElem, angleFunc );
440 }
441 
443 {
444  QgsDebugMsg( "Entered." );
445 
446  QDomElement graphicElem = element.firstChildElement( "Graphic" );
447  if ( graphicElem.isNull() )
448  return nullptr;
449 
450  QString name = "circle";
451  QColor fillColor, borderColor;
452  double borderWidth, size;
453  double widthHeightFactor = 1.0;
454  Qt::PenStyle borderStyle;
455 
456  QgsStringMap vendorOptions = QgsSymbolLayerV2Utils::getVendorOptionList( graphicElem );
457  for ( QgsStringMap::iterator it = vendorOptions.begin(); it != vendorOptions.end(); ++it )
458  {
459  if ( it.key() == "widthHeightFactor" )
460  {
461  bool ok;
462  double v = it.value().toDouble( &ok );
463  if ( ok && !qgsDoubleNear( v, 0.0 ) && v > 0 )
464  widthHeightFactor = v;
465  }
466  }
467 
468  if ( !QgsSymbolLayerV2Utils::wellKnownMarkerFromSld( graphicElem, name, fillColor, borderColor, borderStyle, borderWidth, size ) )
469  return nullptr;
470 
471  double angle = 0.0;
472  QString angleFunc;
473  if ( QgsSymbolLayerV2Utils::rotationFromSldElement( graphicElem, angleFunc ) )
474  {
475  bool ok;
476  double d = angleFunc.toDouble( &ok );
477  if ( ok )
478  angle = d;
479  }
480 
482  m->setSymbolName( name );
483  m->setFillColor( fillColor );
484  m->setOutlineColor( borderColor );
485  m->setOutlineStyle( borderStyle );
486  m->setOutlineWidth( borderWidth );
487  m->setSymbolWidth( size );
488  m->setSymbolHeight( size / widthHeightFactor );
489  m->setAngle( angle );
490  return m;
491 }
492 
494 {
495  QgsStringMap map;
496  map["symbol_name"] = mSymbolName;
497  map["symbol_width"] = QString::number( mSymbolWidth );
498  map["symbol_width_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mSymbolWidthUnit );
499  map["symbol_width_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mSymbolWidthMapUnitScale );
500  map["symbol_height"] = QString::number( mSymbolHeight );
501  map["symbol_height_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mSymbolHeightUnit );
502  map["symbol_height_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mSymbolHeightMapUnitScale );
503  map["angle"] = QString::number( mAngle );
504  map["outline_style"] = QgsSymbolLayerV2Utils::encodePenStyle( mOutlineStyle );
505  map["outline_width"] = QString::number( mOutlineWidth );
506  map["outline_width_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOutlineWidthUnit );
507  map["outline_width_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOutlineWidthMapUnitScale );
508  map["color"] = QgsSymbolLayerV2Utils::encodeColor( mColor );
509  map["outline_color"] = QgsSymbolLayerV2Utils::encodeColor( mOutlineColor );
510  map["offset"] = QgsSymbolLayerV2Utils::encodePoint( mOffset );
512  map["offset_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOffsetMapUnitScale );
513  map["size"] = QString::number( mSize );
515  map["size_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mSizeMapUnitScale );
516  map["horizontal_anchor_point"] = QString::number( mHorizontalAnchorPoint );
517  map["vertical_anchor_point"] = QString::number( mVerticalAnchorPoint );
519  return map;
520 }
521 
522 QSizeF QgsEllipseSymbolLayerV2::calculateSize( QgsSymbolV2RenderContext& context, double* scaledWidth, double* scaledHeight )
523 {
524  double width = 0;
525 
526  if ( hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_WIDTH ) ) //1. priority: data defined setting on symbol layer le
527  {
528  context.setOriginalValueVariable( mSymbolWidth );
529  width = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_WIDTH, context, mSymbolWidth ).toDouble();
530  }
531  else if ( context.renderHints() & QgsSymbolV2::DataDefinedSizeScale ) //2. priority: is data defined size on symbol level
532  {
533  width = mSize;
534  }
535  else //3. priority: global width setting
536  {
537  width = mSymbolWidth;
538  }
539  if ( scaledWidth )
540  {
541  *scaledWidth = width;
542  }
543  width = QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), width, mSymbolWidthUnit, mSymbolHeightMapUnitScale );
544 
545  double height = 0;
546  if ( hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_HEIGHT ) ) //1. priority: data defined setting on symbol layer level
547  {
548  context.setOriginalValueVariable( mSymbolHeight );
549  height = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_HEIGHT, context, mSymbolHeight ).toDouble();
550  }
551  else if ( context.renderHints() & QgsSymbolV2::DataDefinedSizeScale ) //2. priority: is data defined size on symbol level
552  {
553  height = mSize;
554  }
555  else //3. priority: global height setting
556  {
557  height = mSymbolHeight;
558  }
559  if ( scaledHeight )
560  {
561  *scaledHeight = height;
562  }
563  height = QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), height, mSymbolHeightUnit, mSymbolHeightMapUnitScale );
564  return QSizeF( width, height );
565 }
566 
567 void QgsEllipseSymbolLayerV2::preparePath( const QString& symbolName, QgsSymbolV2RenderContext& context, double* scaledWidth, double* scaledHeight, const QgsFeature* )
568 {
569  mPainterPath = QPainterPath();
570 
571  QSizeF size = calculateSize( context, scaledWidth, scaledHeight );
572 
573  if ( symbolName == "circle" )
574  {
575  mPainterPath.addEllipse( QRectF( -size.width() / 2.0, -size.height() / 2.0, size.width(), size.height() ) );
576  }
577  else if ( symbolName == "rectangle" )
578  {
579  mPainterPath.addRect( QRectF( -size.width() / 2.0, -size.height() / 2.0, size.width(), size.height() ) );
580  }
581  else if ( symbolName == "cross" )
582  {
583  mPainterPath.moveTo( 0, -size.height() / 2.0 );
584  mPainterPath.lineTo( 0, size.height() / 2.0 );
585  mPainterPath.moveTo( -size.width() / 2.0, 0 );
586  mPainterPath.lineTo( size.width() / 2.0, 0 );
587  }
588  else if ( symbolName == "triangle" )
589  {
590  mPainterPath.moveTo( 0, -size.height() / 2.0 );
591  mPainterPath.lineTo( -size.width() / 2.0, size.height() / 2.0 );
592  mPainterPath.lineTo( size.width() / 2.0, size.height() / 2.0 );
593  mPainterPath.lineTo( 0, -size.height() / 2.0 );
594  }
595 }
596 
598 {
600  mSymbolWidthUnit = unit;
601  mSymbolHeightUnit = unit;
602  mOutlineWidthUnit = unit;
603 }
604 
606 {
608  if ( mSymbolWidthUnit != unit || mSymbolHeightUnit != unit || mOutlineWidthUnit != unit )
609  {
610  return QgsSymbolV2::Mixed;
611  }
612  return unit;
613 }
614 
616 {
618  mSymbolWidthMapUnitScale = scale;
619  mSymbolHeightMapUnitScale = scale;
620  mOutlineWidthMapUnitScale = scale;
621 }
622 
624 {
625  if ( QgsMarkerSymbolLayerV2::mapUnitScale() == mSymbolWidthMapUnitScale &&
626  mSymbolWidthMapUnitScale == mSymbolHeightMapUnitScale &&
627  mSymbolHeightMapUnitScale == mOutlineWidthMapUnitScale )
628  {
629  return mSymbolWidthMapUnitScale;
630  }
631  return QgsMapUnitScale();
632 }
633 
635 {
636  QSizeF size = calculateSize( context );
637 
638  bool hasDataDefinedRotation = false;
639  QPointF offset;
640  double angle = 0;
641  calculateOffsetAndRotation( context, size.width(), size.height(), hasDataDefinedRotation, offset, angle );
642 
643  double pixelSize = 1.0 / context.renderContext().rasterScaleFactor();
644 
645  QMatrix transform;
646 
647  // move to the desired position
648  transform.translate( point.x() + offset.x(), point.y() + offset.y() );
649 
650  if ( !qgsDoubleNear( angle, 0.0 ) )
651  transform.rotate( angle );
652 
653  double penWidth = 0.0;
654  bool ok = true;
656  {
657  context.setOriginalValueVariable( mOutlineWidth );
659  if ( ok )
660  {
661  penWidth = QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), outlineWidth, mOutlineWidthUnit, mOutlineWidthMapUnitScale );
662  }
663  }
665  {
668  if ( ok && outlineStyle == "no" )
669  {
670  penWidth = 0.0;
671  }
672  }
673 
674  //antialiasing
675  penWidth += pixelSize;
676 
677  QRectF symbolBounds = transform.mapRect( QRectF( -size.width() / 2.0,
678  -size.height() / 2.0,
679  size.width(),
680  size.height() ) );
681 
682  //extend bounds by pen width / 2.0
683  symbolBounds.adjust( -penWidth / 2.0, -penWidth / 2.0,
684  penWidth / 2.0, penWidth / 2.0 );
685 
686  return symbolBounds;
687 }
688 
689 bool QgsEllipseSymbolLayerV2::writeDxf( QgsDxfExport& e, double mmMapUnitScaleFactor, const QString& layerName, QgsSymbolV2RenderContext &context, QPointF shift ) const
690 {
691  //width
692  double symbolWidth = mSymbolWidth;
693 
694  if ( hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_WIDTH ) ) //1. priority: data defined setting on symbol layer le
695  {
696  context.setOriginalValueVariable( mSymbolWidth );
697  symbolWidth = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_WIDTH, context, mSymbolWidth ).toDouble();
698  }
699  else if ( context.renderHints() & QgsSymbolV2::DataDefinedSizeScale ) //2. priority: is data defined size on symbol level
700  {
701  symbolWidth = mSize;
702  }
703  if ( mSymbolWidthUnit == QgsSymbolV2::MM )
704  {
705  symbolWidth *= mmMapUnitScaleFactor;
706  }
707 
708  //height
709  double symbolHeight = mSymbolHeight;
710  if ( hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_HEIGHT ) ) //1. priority: data defined setting on symbol layer level
711  {
712  context.setOriginalValueVariable( mSymbolHeight );
713  symbolHeight = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_HEIGHT, context, mSymbolHeight ).toDouble();
714  }
715  else if ( context.renderHints() & QgsSymbolV2::DataDefinedSizeScale ) //2. priority: is data defined size on symbol level
716  {
717  symbolHeight = mSize;
718  }
719  if ( mSymbolHeightUnit == QgsSymbolV2::MM )
720  {
721  symbolHeight *= mmMapUnitScaleFactor;
722  }
723 
724  //outline width
725  double outlineWidth = mOutlineWidth;
726 
728  {
729  context.setOriginalValueVariable( mOutlineWidth );
730  outlineWidth = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_OUTLINE_WIDTH, context, mOutlineWidth ).toDouble();
731  }
732  if ( mOutlineWidthUnit == QgsSymbolV2::MM )
733  {
734  outlineWidth *= outlineWidth;
735  }
736 
737  //fill color
738  bool ok;
739  QColor fc = mColor;
741  {
744  if ( ok )
745  fc = QgsSymbolLayerV2Utils::decodeColor( colorString );
746  }
747 
748  //outline color
749  QColor oc = mOutlineColor;
751  {
754  if ( ok )
755  oc = QgsSymbolLayerV2Utils::decodeColor( colorString );
756  }
757 
758  //symbol name
759  QString symbolName = mSymbolName;
761  {
762  context.setOriginalValueVariable( mSymbolName );
763  symbolName = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_SYMBOL_NAME, context, mSymbolName ).toString();
764  }
765 
766  //offset
767  double offsetX = 0;
768  double offsetY = 0;
769  markerOffset( context, offsetX, offsetY );
770  QPointF off( offsetX, offsetY );
771 
772  //priority for rotation: 1. data defined symbol level, 2. symbol layer rotation (mAngle)
773  double rotation = 0.0;
775  {
776  context.setOriginalValueVariable( mAngle );
778  }
779  else if ( !qgsDoubleNear( mAngle + mLineAngle, 0.0 ) )
780  {
781  rotation = mAngle + mLineAngle;
782  }
783  rotation = -rotation; //rotation in Qt is counterclockwise
784  if ( rotation )
785  off = _rotatedOffset( off, rotation );
786 
787  QTransform t;
788  t.translate( shift.x() + offsetX, shift.y() + offsetY );
789 
790  if ( !qgsDoubleNear( rotation, 0.0 ) )
791  t.rotate( rotation );
792 
793  double halfWidth = symbolWidth / 2.0;
794  double halfHeight = symbolHeight / 2.0;
795 
796  if ( symbolName == "circle" )
797  {
798  if ( qgsDoubleNear( halfWidth, halfHeight ) )
799  {
800  QPointF pt( t.map( QPointF( 0, 0 ) ) );
801  e.writeFilledCircle( layerName, oc, pt, halfWidth );
802  }
803  else
804  {
805  QgsPolyline line;
806  line.reserve( 40 );
807  double stepsize = 2 * M_PI / 40;
808  for ( int i = 0; i < 39; ++i )
809  {
810  double angle = stepsize * i;
811  double x = halfWidth * cos( angle );
812  double y = halfHeight * sin( angle );
813  QPointF pt( t.map( QPointF( x, y ) ) );
814  line.push_back( pt );
815  }
816  //close ellipse with first point
817  line.push_back( line.at( 0 ) );
818  if ( mBrush.style() != Qt::NoBrush )
819  e.writePolygon( QgsPolygon() << line, layerName, "SOLID", fc );
820  if ( mPen.style() != Qt::NoPen )
821  e.writePolyline( line, layerName, "CONTINUOUS", oc, outlineWidth );
822  }
823  }
824  else if ( symbolName == "rectangle" )
825  {
826  QgsPolygon p( 1 );
827  p[0].resize( 5 );
828  p[0][0] = t.map( QPointF( -halfWidth, -halfHeight ) );
829  p[0][1] = t.map( QPointF( halfWidth, -halfHeight ) );
830  p[0][2] = t.map( QPointF( halfWidth, halfHeight ) );
831  p[0][3] = t.map( QPointF( -halfWidth, halfHeight ) );
832  p[0][4] = p[0][0];
833  if ( mBrush.style() != Qt::NoBrush )
834  e.writePolygon( p, layerName, "SOLID", fc );
835  if ( mPen.style() != Qt::NoPen )
836  e.writePolyline( p[0], layerName, "CONTINUOUS", oc, outlineWidth );
837  return true;
838  }
839  else if ( symbolName == "cross" && mPen.style() != Qt::NoPen )
840  {
841  QgsPolyline line( 2 );
842  line[0] = t.map( QPointF( -halfWidth, 0 ) );
843  line[1] = t.map( QPointF( halfWidth, 0 ) );
844  e.writePolyline( line, layerName, "CONTINUOUS", oc, outlineWidth );
845 
846  line[0] = t.map( QPointF( 0, halfHeight ) );
847  line[1] = t.map( QPointF( 0, -halfHeight ) );
848  e.writePolyline( line, layerName, "CONTINUOUS", oc, outlineWidth );
849 
850  return true;
851  }
852  else if ( symbolName == "triangle" )
853  {
854  QgsPolygon p( 1 );
855  p[0].resize( 4 );
856  p[0][0] = QPointF( t.map( QPointF( -halfWidth, -halfHeight ) ) );
857  p[0][1] = QPointF( t.map( QPointF( halfWidth, -halfHeight ) ) );
858  p[0][2] = QPointF( t.map( QPointF( 0, halfHeight ) ) );
859  p[0][3] = p[0][0];
860  if ( mBrush.style() != Qt::NoBrush )
861  e.writePolygon( p, layerName, "SOLID", fc );
862  if ( mPen.style() != Qt::NoPen )
863  e.writePolyline( p[0], layerName, "CONTINUOUS", oc, outlineWidth );
864  return true;
865  }
866 
867  return false; //soon...
868 }
869 
870 
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.
void copyPaintEffect(QgsSymbolLayerV2 *destLayer) const
Copies paint effect of this layer to another symbol layer.
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)
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)
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)
double rasterScaleFactor() const
void writeFilledCircle(const QString &layer, const QColor &color, const QgsPoint &pt, double radius)
Write filled circle (as hatch)
virtual QColor color() const
The fill color.
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
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.
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)
void copyDataDefinedProperties(QgsSymbolLayerV2 *destLayer) const
Copies all data defined properties of this layer to another symbol layer.
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.