QGIS API Documentation  2.14.11-Essen
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
qgsellipsesymbollayerv2.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsellipsesymbollayerv2.cpp
3  ---------------------
4  begin : June 2011
5  copyright : (C) 2011 by Marco Hugentobler
6  email : marco dot hugentobler at sourcepole dot ch
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
16 #include "qgsdxfexport.h"
17 #include "qgsexpression.h"
18 #include "qgsfeature.h"
19 #include "qgsrendercontext.h"
20 #include "qgsvectorlayer.h"
21 #include "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)
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:370
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)
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)
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...
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:375
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)
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.
double ANALYSIS_EXPORT angle(Point3D *p1, Point3D *p2, Point3D *p3, Point3D *p4)
Calculates the angle between two segments (in 2 dimension, z-values are ignored)
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:346
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.