QGIS API Documentation  3.0.2-Girona (307d082)
qgsellipsesymbollayer.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsellipsesymbollayer.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  ***************************************************************************/
15 #include "qgsellipsesymbollayer.h"
16 #include "qgsdxfexport.h"
17 #include "qgsexpression.h"
18 #include "qgsfeature.h"
19 #include "qgsrendercontext.h"
20 #include "qgsvectorlayer.h"
21 #include "qgslogger.h"
22 #include "qgsunittypes.h"
23 #include "qgsproperty.h"
24 
25 #include <QPainter>
26 #include <QSet>
27 #include <QDomDocument>
28 #include <QDomElement>
29 
31  : mSymbolName( QStringLiteral( "circle" ) )
32  , mStrokeColor( QColor( 35, 35, 35 ) )
33 {
34  mColor = Qt::white;
35  mPen.setColor( mStrokeColor );
36  mPen.setStyle( mStrokeStyle );
37  mPen.setJoinStyle( mPenJoinStyle );
38  mPen.setWidth( 1.0 );
39  mBrush.setColor( mColor );
40  mBrush.setStyle( Qt::SolidPattern );
41  mOffset = QPointF( 0, 0 );
42  mAngle = 0;
43 }
44 
46 {
48  if ( properties.contains( QStringLiteral( "symbol_name" ) ) )
49  {
50  layer->setSymbolName( properties[ QStringLiteral( "symbol_name" )] );
51  }
52  if ( properties.contains( QStringLiteral( "symbol_width" ) ) )
53  {
54  layer->setSymbolWidth( properties[QStringLiteral( "symbol_width" )].toDouble() );
55  }
56  if ( properties.contains( QStringLiteral( "symbol_width_unit" ) ) )
57  {
58  layer->setSymbolWidthUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "symbol_width_unit" )] ) );
59  }
60  if ( properties.contains( QStringLiteral( "symbol_width_map_unit_scale" ) ) )
61  {
62  layer->setSymbolWidthMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "symbol_width_map_unit_scale" )] ) );
63  }
64  if ( properties.contains( QStringLiteral( "symbol_height" ) ) )
65  {
66  layer->setSymbolHeight( properties[QStringLiteral( "symbol_height" )].toDouble() );
67  }
68  if ( properties.contains( QStringLiteral( "symbol_height_unit" ) ) )
69  {
70  layer->setSymbolHeightUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "symbol_height_unit" )] ) );
71  }
72  if ( properties.contains( QStringLiteral( "symbol_height_map_unit_scale" ) ) )
73  {
74  layer->setSymbolHeightMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "symbol_height_map_unit_scale" )] ) );
75  }
76  if ( properties.contains( QStringLiteral( "angle" ) ) )
77  {
78  layer->setAngle( properties[QStringLiteral( "angle" )].toDouble() );
79  }
80  if ( properties.contains( QStringLiteral( "outline_style" ) ) )
81  {
82  layer->setStrokeStyle( QgsSymbolLayerUtils::decodePenStyle( properties[QStringLiteral( "outline_style" )] ) );
83  }
84  else if ( properties.contains( QStringLiteral( "line_style" ) ) )
85  {
86  layer->setStrokeStyle( QgsSymbolLayerUtils::decodePenStyle( properties[QStringLiteral( "line_style" )] ) );
87  }
88  if ( properties.contains( QStringLiteral( "joinstyle" ) ) )
89  {
90  layer->setPenJoinStyle( QgsSymbolLayerUtils::decodePenJoinStyle( properties[QStringLiteral( "joinstyle" )] ) );
91  }
92  if ( properties.contains( QStringLiteral( "outline_width" ) ) )
93  {
94  layer->setStrokeWidth( properties[QStringLiteral( "outline_width" )].toDouble() );
95  }
96  else if ( properties.contains( QStringLiteral( "line_width" ) ) )
97  {
98  layer->setStrokeWidth( properties[QStringLiteral( "line_width" )].toDouble() );
99  }
100  if ( properties.contains( QStringLiteral( "outline_width_unit" ) ) )
101  {
102  layer->setStrokeWidthUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "outline_width_unit" )] ) );
103  }
104  else if ( properties.contains( QStringLiteral( "line_width_unit" ) ) )
105  {
106  layer->setStrokeWidthUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "line_width_unit" )] ) );
107  }
108  if ( properties.contains( QStringLiteral( "outline_width_map_unit_scale" ) ) )
109  {
110  layer->setStrokeWidthMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "outline_width_map_unit_scale" )] ) );
111  }
112  if ( properties.contains( QStringLiteral( "fill_color" ) ) )
113  {
114  //pre 2.5 projects used "fill_color"
115  layer->setFillColor( QgsSymbolLayerUtils::decodeColor( properties[QStringLiteral( "fill_color" )] ) );
116  }
117  else if ( properties.contains( QStringLiteral( "color" ) ) )
118  {
119  layer->setFillColor( QgsSymbolLayerUtils::decodeColor( properties[QStringLiteral( "color" )] ) );
120  }
121  if ( properties.contains( QStringLiteral( "outline_color" ) ) )
122  {
123  layer->setStrokeColor( QgsSymbolLayerUtils::decodeColor( properties[QStringLiteral( "outline_color" )] ) );
124  }
125  else if ( properties.contains( QStringLiteral( "line_color" ) ) )
126  {
127  layer->setStrokeColor( QgsSymbolLayerUtils::decodeColor( properties[QStringLiteral( "line_color" )] ) );
128  }
129  if ( properties.contains( QStringLiteral( "size" ) ) )
130  {
131  layer->setSize( properties[QStringLiteral( "size" )].toDouble() );
132  }
133  if ( properties.contains( QStringLiteral( "size_unit" ) ) )
134  {
135  layer->setSizeUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "size_unit" )] ) );
136  }
137  if ( properties.contains( QStringLiteral( "size_map_unit_scale" ) ) )
138  {
139  layer->setSizeMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "size_map_unit_scale" )] ) );
140  }
141  if ( properties.contains( QStringLiteral( "offset" ) ) )
142  {
143  layer->setOffset( QgsSymbolLayerUtils::decodePoint( properties[QStringLiteral( "offset" )] ) );
144  }
145  if ( properties.contains( QStringLiteral( "offset_unit" ) ) )
146  {
147  layer->setOffsetUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "offset_unit" )] ) );
148  }
149  if ( properties.contains( QStringLiteral( "offset_map_unit_scale" ) ) )
150  {
151  layer->setOffsetMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "offset_map_unit_scale" )] ) );
152  }
153  if ( properties.contains( QStringLiteral( "horizontal_anchor_point" ) ) )
154  {
155  layer->setHorizontalAnchorPoint( QgsMarkerSymbolLayer::HorizontalAnchorPoint( properties[ QStringLiteral( "horizontal_anchor_point" )].toInt() ) );
156  }
157  if ( properties.contains( QStringLiteral( "vertical_anchor_point" ) ) )
158  {
159  layer->setVerticalAnchorPoint( QgsMarkerSymbolLayer::VerticalAnchorPoint( properties[ QStringLiteral( "vertical_anchor_point" )].toInt() ) );
160  }
161 
162  //data defined properties
163  layer->restoreOldDataDefinedProperties( properties );
164 
165  return layer;
166 }
167 
169 {
170  double scaledWidth = mSymbolWidth;
171  double scaledHeight = mSymbolHeight;
172 
174  {
175  bool ok;
176  context.setOriginalValueVariable( mStrokeWidth );
178  if ( exprVal.isValid() )
179  {
180  double width = exprVal.toDouble( &ok );
181  if ( ok )
182  {
183  width = context.renderContext().convertToPainterUnits( width, mStrokeWidthUnit, mStrokeWidthMapUnitScale );
184  mPen.setWidthF( width );
185  }
186  }
187 
190  if ( exprVal.isValid() )
191  {
192  mPen.setStyle( QgsSymbolLayerUtils::decodePenStyle( exprVal.toString() ) );
193  }
194 
197  if ( exprVal.isValid() )
198  {
199  mPen.setJoinStyle( QgsSymbolLayerUtils::decodePenJoinStyle( exprVal.toString() ) );
200  }
201 
204 
207 
209  {
210  QString symbolName = mSymbolName;
211  context.setOriginalValueVariable( mSymbolName );
213  if ( exprVal.isValid() )
214  {
215  symbolName = exprVal.toString();
216  }
217  preparePath( symbolName, context, &scaledWidth, &scaledHeight, context.feature() );
218  }
219  }
220 
221  //offset and rotation
222  bool hasDataDefinedRotation = false;
223  QPointF offset;
224  double angle = 0;
225  calculateOffsetAndRotation( context, scaledWidth, scaledHeight, hasDataDefinedRotation, offset, angle );
226 
227  QPainter *p = context.renderContext().painter();
228  if ( !p )
229  {
230  return;
231  }
232 
233  QMatrix transform;
234  transform.translate( point.x() + offset.x(), point.y() + offset.y() );
235  if ( !qgsDoubleNear( angle, 0.0 ) )
236  {
237  transform.rotate( angle );
238  }
239 
240  p->setPen( mPen );
241  p->setBrush( mBrush );
242  p->drawPath( transform.map( mPainterPath ) );
243 }
244 
245 
246 void QgsEllipseSymbolLayer::calculateOffsetAndRotation( QgsSymbolRenderContext &context,
247  double scaledWidth,
248  double scaledHeight,
249  bool &hasDataDefinedRotation,
250  QPointF &offset,
251  double &angle ) const
252 {
253  double offsetX = 0;
254  double offsetY = 0;
255  markerOffset( context, scaledWidth, scaledHeight, mSymbolWidthUnit, mSymbolHeightUnit, offsetX, offsetY, mSymbolWidthMapUnitScale, mSymbolHeightMapUnitScale );
256  offset = QPointF( offsetX, offsetY );
257 
258 //priority for rotation: 1. data defined symbol level, 2. symbol layer rotation (mAngle)
259  bool ok = true;
260  angle = mAngle + mLineAngle;
261  bool usingDataDefinedRotation = false;
263  {
264  context.setOriginalValueVariable( angle );
266  usingDataDefinedRotation = ok;
267  }
268 
269  hasDataDefinedRotation = context.renderHints() & QgsSymbol::DynamicRotation || usingDataDefinedRotation;
270  if ( hasDataDefinedRotation )
271  {
272  // For non-point markers, "dataDefinedRotation" means following the
273  // shape (shape-data defined). For them, "field-data defined" does
274  // not work at all. TODO: if "field-data defined" ever gets implemented
275  // we'll need a way to distinguish here between the two, possibly
276  // using another flag in renderHints()
277  const QgsFeature *f = context.feature();
278  if ( f )
279  {
280  const QgsGeometry g = f->geometry();
281  if ( !g.isNull() && g.type() == QgsWkbTypes::PointGeometry )
282  {
283  const QgsMapToPixel &m2p = context.renderContext().mapToPixel();
284  angle += m2p.mapRotation();
285  }
286  }
287  }
288 
289  if ( angle )
290  offset = _rotatedOffset( offset, angle );
291 }
292 
294 {
295  return QStringLiteral( "EllipseMarker" );
296 }
297 
299 {
300  QgsMarkerSymbolLayer::startRender( context ); // get anchor point expressions
301  if ( !context.feature() || !dataDefinedProperties().hasActiveProperties() )
302  {
303  preparePath( mSymbolName, context );
304  }
305  mPen.setColor( mStrokeColor );
306  mPen.setStyle( mStrokeStyle );
307  mPen.setJoinStyle( mPenJoinStyle );
308  mPen.setWidthF( context.renderContext().convertToPainterUnits( mStrokeWidth, mStrokeWidthUnit, mStrokeWidthMapUnitScale ) );
309  mBrush.setColor( mColor );
310 }
311 
313 {
314 }
315 
317 {
319  m->setSymbolName( mSymbolName );
320  m->setSymbolWidth( mSymbolWidth );
321  m->setSymbolHeight( mSymbolHeight );
322  m->setStrokeStyle( mStrokeStyle );
323  m->setOffset( mOffset );
326  m->setStrokeStyle( mStrokeStyle );
327  m->setPenJoinStyle( mPenJoinStyle );
328  m->setStrokeWidth( mStrokeWidth );
329  m->setColor( color() );
330  m->setStrokeColor( mStrokeColor );
331  m->setSymbolWidthUnit( mSymbolWidthUnit );
332  m->setSymbolWidthMapUnitScale( mSymbolWidthMapUnitScale );
333  m->setSymbolHeightUnit( mSymbolHeightUnit );
334  m->setSymbolHeightMapUnitScale( mSymbolHeightMapUnitScale );
335  m->setStrokeWidthUnit( mStrokeWidthUnit );
336  m->setStrokeWidthMapUnitScale( mStrokeWidthMapUnitScale );
337  m->setAngle( mAngle );
340 
342  copyPaintEffect( m );
343  return m;
344 }
345 
346 void QgsEllipseSymbolLayer::toSld( QDomDocument &doc, QDomElement &element, const QgsStringMap &props ) const
347 {
348  QDomElement symbolizerElem = doc.createElement( QStringLiteral( "se:PointSymbolizer" ) );
349  if ( !props.value( QStringLiteral( "uom" ), QLatin1String( "" ) ).isEmpty() )
350  symbolizerElem.setAttribute( QStringLiteral( "uom" ), props.value( QStringLiteral( "uom" ), QLatin1String( "" ) ) );
351  element.appendChild( symbolizerElem );
352 
353  // <Geometry>
354  QgsSymbolLayerUtils::createGeometryElement( doc, symbolizerElem, props.value( QStringLiteral( "geom" ), QLatin1String( "" ) ) );
355 
356  writeSldMarker( doc, symbolizerElem, props );
357 }
358 
359 void QgsEllipseSymbolLayer::writeSldMarker( QDomDocument &doc, QDomElement &element, const QgsStringMap &props ) const
360 {
361  // <Graphic>
362  QDomElement graphicElem = doc.createElement( QStringLiteral( "se:Graphic" ) );
363  element.appendChild( graphicElem );
364 
365  double strokeWidth = QgsSymbolLayerUtils::rescaleUom( mStrokeWidth, mStrokeWidthUnit, props );
366  double symbolWidth = QgsSymbolLayerUtils::rescaleUom( mSymbolWidth, mSymbolWidthUnit, props );
367  QgsSymbolLayerUtils::wellKnownMarkerToSld( doc, graphicElem, mSymbolName, mColor, mStrokeColor, mStrokeStyle, strokeWidth, symbolWidth );
368 
369  // <Rotation>
371 
372  QString angleFunc = props.value( QStringLiteral( "angle" ), QLatin1String( "" ) );
373  if ( angleFunc.isEmpty() ) // symbol has no angle set
374  {
375  if ( ddRotation && ddRotation.isActive() )
376  {
377  angleFunc = ddRotation.asExpression();
378  }
379  else if ( !qgsDoubleNear( mAngle, 0.0 ) )
380  angleFunc = QString::number( mAngle );
381  }
382  else if ( ddRotation && ddRotation.isActive() )
383  {
384  // the symbol has an angle and the symbol layer have a rotation
385  // property set
386  angleFunc = QStringLiteral( "%1 + %2" ).arg( angleFunc, ddRotation.asExpression() );
387  }
388  else if ( !qgsDoubleNear( mAngle, 0.0 ) )
389  {
390  // both the symbol and the symbol layer have angle value set
391  bool ok;
392  double angle = angleFunc.toDouble( &ok );
393  if ( !ok )
394  {
395  // its a string (probably a property name or a function)
396  angleFunc = QStringLiteral( "%1 + %2" ).arg( angleFunc ).arg( mAngle );
397  }
398  else if ( !qgsDoubleNear( angle + mAngle, 0.0 ) )
399  {
400  // it's a double value
401  angleFunc = QString::number( angle + mAngle );
402  }
403  }
404  QgsSymbolLayerUtils::createRotationElement( doc, graphicElem, angleFunc );
405 
406  // <Displacement>
408  QgsSymbolLayerUtils::createDisplacementElement( doc, graphicElem, offset );
409 
410  // store w/h factor in a <VendorOption>
411  double widthHeightFactor = mSymbolWidth / mSymbolHeight;
412  QDomElement factorElem = QgsSymbolLayerUtils::createVendorOptionElement( doc, QStringLiteral( "widthHeightFactor" ), QString::number( widthHeightFactor ) );
413  graphicElem.appendChild( factorElem );
414 }
415 
417 {
418  QgsDebugMsg( "Entered." );
419 
420  QDomElement graphicElem = element.firstChildElement( QStringLiteral( "Graphic" ) );
421  if ( graphicElem.isNull() )
422  return nullptr;
423 
424  QString name = QStringLiteral( "circle" );
425  QColor fillColor, strokeColor;
426  double strokeWidth, size;
427  double widthHeightFactor = 1.0;
428  Qt::PenStyle strokeStyle;
429 
430  QgsStringMap vendorOptions = QgsSymbolLayerUtils::getVendorOptionList( graphicElem );
431  for ( QgsStringMap::iterator it = vendorOptions.begin(); it != vendorOptions.end(); ++it )
432  {
433  if ( it.key() == QLatin1String( "widthHeightFactor" ) )
434  {
435  bool ok;
436  double v = it.value().toDouble( &ok );
437  if ( ok && !qgsDoubleNear( v, 0.0 ) && v > 0 )
438  widthHeightFactor = v;
439  }
440  }
441 
442  if ( !QgsSymbolLayerUtils::wellKnownMarkerFromSld( graphicElem, name, fillColor, strokeColor, strokeStyle, strokeWidth, size ) )
443  return nullptr;
444 
445  QString uom = element.attribute( QStringLiteral( "uom" ) );
447  strokeWidth = QgsSymbolLayerUtils::sizeInPixelsFromSldUom( uom, strokeWidth );
448 
449  double angle = 0.0;
450  QString angleFunc;
451  if ( QgsSymbolLayerUtils::rotationFromSldElement( graphicElem, angleFunc ) )
452  {
453  bool ok;
454  double d = angleFunc.toDouble( &ok );
455  if ( ok )
456  angle = d;
457  }
458 
460  m->setOutputUnit( QgsUnitTypes::RenderUnit::RenderPixels );
461  m->setSymbolName( name );
462  m->setFillColor( fillColor );
463  m->setStrokeColor( strokeColor );
464  m->setStrokeStyle( strokeStyle );
465  m->setStrokeWidth( strokeWidth );
466  m->setSymbolWidth( size );
467  m->setSymbolHeight( size / widthHeightFactor );
468  m->setAngle( angle );
469  return m;
470 }
471 
473 {
474  QgsStringMap map;
475  map[QStringLiteral( "symbol_name" )] = mSymbolName;
476  map[QStringLiteral( "symbol_width" )] = QString::number( mSymbolWidth );
477  map[QStringLiteral( "symbol_width_unit" )] = QgsUnitTypes::encodeUnit( mSymbolWidthUnit );
478  map[QStringLiteral( "symbol_width_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mSymbolWidthMapUnitScale );
479  map[QStringLiteral( "symbol_height" )] = QString::number( mSymbolHeight );
480  map[QStringLiteral( "symbol_height_unit" )] = QgsUnitTypes::encodeUnit( mSymbolHeightUnit );
481  map[QStringLiteral( "symbol_height_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mSymbolHeightMapUnitScale );
482  map[QStringLiteral( "angle" )] = QString::number( mAngle );
483  map[QStringLiteral( "outline_style" )] = QgsSymbolLayerUtils::encodePenStyle( mStrokeStyle );
484  map[QStringLiteral( "outline_width" )] = QString::number( mStrokeWidth );
485  map[QStringLiteral( "outline_width_unit" )] = QgsUnitTypes::encodeUnit( mStrokeWidthUnit );
486  map[QStringLiteral( "outline_width_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mStrokeWidthMapUnitScale );
487  map[QStringLiteral( "joinstyle" )] = QgsSymbolLayerUtils::encodePenJoinStyle( mPenJoinStyle );
488  map[QStringLiteral( "color" )] = QgsSymbolLayerUtils::encodeColor( mColor );
489  map[QStringLiteral( "outline_color" )] = QgsSymbolLayerUtils::encodeColor( mStrokeColor );
490  map[QStringLiteral( "offset" )] = QgsSymbolLayerUtils::encodePoint( mOffset );
491  map[QStringLiteral( "offset_unit" )] = QgsUnitTypes::encodeUnit( mOffsetUnit );
492  map[QStringLiteral( "offset_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mOffsetMapUnitScale );
493  map[QStringLiteral( "size" )] = QString::number( mSize );
494  map[QStringLiteral( "size_unit" )] = QgsUnitTypes::encodeUnit( mSizeUnit );
495  map[QStringLiteral( "size_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mSizeMapUnitScale );
496  map[QStringLiteral( "horizontal_anchor_point" )] = QString::number( mHorizontalAnchorPoint );
497  map[QStringLiteral( "vertical_anchor_point" )] = QString::number( mVerticalAnchorPoint );
498  return map;
499 }
500 
501 QSizeF QgsEllipseSymbolLayer::calculateSize( QgsSymbolRenderContext &context, double *scaledWidth, double *scaledHeight )
502 {
503  double width = 0;
504 
505  if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyWidth ) ) //1. priority: data defined setting on symbol layer le
506  {
507  context.setOriginalValueVariable( mSymbolWidth );
509  }
510  else //2. priority: global width setting
511  {
512  width = mSymbolWidth;
513  }
514  if ( scaledWidth )
515  {
516  *scaledWidth = width;
517  }
518  width = context.renderContext().convertToPainterUnits( width, mSymbolWidthUnit, mSymbolHeightMapUnitScale );
519 
520  double height = 0;
521  if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyHeight ) ) //1. priority: data defined setting on symbol layer level
522  {
523  context.setOriginalValueVariable( mSymbolHeight );
525  }
526  else //2. priority: global height setting
527  {
528  height = mSymbolHeight;
529  }
530  if ( scaledHeight )
531  {
532  *scaledHeight = height;
533  }
534  height = context.renderContext().convertToPainterUnits( height, mSymbolHeightUnit, mSymbolHeightMapUnitScale );
535  return QSizeF( width, height );
536 }
537 
538 void QgsEllipseSymbolLayer::preparePath( const QString &symbolName, QgsSymbolRenderContext &context, double *scaledWidth, double *scaledHeight, const QgsFeature * )
539 {
540  mPainterPath = QPainterPath();
541 
542  QSizeF size = calculateSize( context, scaledWidth, scaledHeight );
543 
544  if ( symbolName == QLatin1String( "circle" ) )
545  {
546  mPainterPath.addEllipse( QRectF( -size.width() / 2.0, -size.height() / 2.0, size.width(), size.height() ) );
547  }
548  else if ( symbolName == QLatin1String( "semi_circle" ) )
549  {
550  mPainterPath.arcTo( -size.width() / 2.0, -size.height() / 2.0, size.width(), size.height(), 0, 180 );
551  mPainterPath.lineTo( 0, 0 );
552  }
553  else if ( symbolName == QLatin1String( "rectangle" ) )
554  {
555  mPainterPath.addRect( QRectF( -size.width() / 2.0, -size.height() / 2.0, size.width(), size.height() ) );
556  }
557  else if ( symbolName == QLatin1String( "diamond" ) )
558  {
559  mPainterPath.moveTo( -size.width() / 2.0, 0 );
560  mPainterPath.lineTo( 0, size.height() / 2.0 );
561  mPainterPath.lineTo( size.width() / 2.0, 0 );
562  mPainterPath.lineTo( 0, -size.height() / 2.0 );
563  mPainterPath.lineTo( -size.width() / 2.0, 0 );
564  }
565  else if ( symbolName == QLatin1String( "cross" ) )
566  {
567  mPainterPath.moveTo( 0, -size.height() / 2.0 );
568  mPainterPath.lineTo( 0, size.height() / 2.0 );
569  mPainterPath.moveTo( -size.width() / 2.0, 0 );
570  mPainterPath.lineTo( size.width() / 2.0, 0 );
571  }
572  else if ( symbolName == QLatin1String( "triangle" ) )
573  {
574  mPainterPath.moveTo( 0, -size.height() / 2.0 );
575  mPainterPath.lineTo( -size.width() / 2.0, size.height() / 2.0 );
576  mPainterPath.lineTo( size.width() / 2.0, size.height() / 2.0 );
577  mPainterPath.lineTo( 0, -size.height() / 2.0 );
578  }
579  else if ( symbolName == QLatin1String( "left_half_triangle" ) )
580  {
581  mPainterPath.moveTo( 0, size.height() / 2.0 );
582  mPainterPath.lineTo( size.width() / 2.0, size.height() / 2.0 );
583  mPainterPath.lineTo( 0, -size.height() / 2.0 );
584  mPainterPath.lineTo( 0, size.height() / 2.0 );
585  }
586  else if ( symbolName == QLatin1String( "right_half_triangle" ) )
587  {
588  mPainterPath.moveTo( -size.width() / 2.0, size.height() / 2.0 );
589  mPainterPath.lineTo( 0, size.height() / 2.0 );
590  mPainterPath.lineTo( 0, -size.height() / 2.0 );
591  mPainterPath.lineTo( -size.width() / 2.0, size.height() / 2.0 );
592  }
593 }
594 
596 {
598  mSymbolWidthUnit = unit;
599  mSymbolHeightUnit = unit;
600  mStrokeWidthUnit = unit;
601 }
602 
604 {
606  if ( mSymbolWidthUnit != unit || mSymbolHeightUnit != unit || mStrokeWidthUnit != unit )
607  {
609  }
610  return unit;
611 }
612 
614 {
616  mSymbolWidthMapUnitScale = scale;
617  mSymbolHeightMapUnitScale = scale;
618  mStrokeWidthMapUnitScale = scale;
619 }
620 
622 {
623  if ( QgsMarkerSymbolLayer::mapUnitScale() == mSymbolWidthMapUnitScale &&
624  mSymbolWidthMapUnitScale == mSymbolHeightMapUnitScale &&
625  mSymbolHeightMapUnitScale == mStrokeWidthMapUnitScale )
626  {
627  return mSymbolWidthMapUnitScale;
628  }
629  return QgsMapUnitScale();
630 }
631 
632 QRectF QgsEllipseSymbolLayer::bounds( QPointF point, QgsSymbolRenderContext &context )
633 {
634  QSizeF size = calculateSize( context );
635 
636  bool hasDataDefinedRotation = false;
637  QPointF offset;
638  double angle = 0;
639  calculateOffsetAndRotation( context, size.width(), size.height(), hasDataDefinedRotation, offset, angle );
640 
641  QMatrix transform;
642 
643  // move to the desired position
644  transform.translate( point.x() + offset.x(), point.y() + offset.y() );
645 
646  if ( !qgsDoubleNear( angle, 0.0 ) )
647  transform.rotate( angle );
648 
649  double penWidth = 0.0;
651  {
652  context.setOriginalValueVariable( mStrokeWidth );
654 
655  if ( exprVal.isValid() )
656  {
657  bool ok;
658  double strokeWidth = exprVal.toDouble( &ok );
659  if ( ok )
660  {
661  penWidth = context.renderContext().convertToPainterUnits( strokeWidth, mStrokeWidthUnit, mStrokeWidthMapUnitScale );
662  }
663  }
664  }
666  {
669  if ( exprVal.isValid() && exprVal.toString() == QLatin1String( "no" ) )
670  {
671  penWidth = 0.0;
672  }
673  }
674 
675  //antialiasing, add 1 pixel
676  penWidth += 1;
677 
678  QRectF symbolBounds = transform.mapRect( QRectF( -size.width() / 2.0,
679  -size.height() / 2.0,
680  size.width(),
681  size.height() ) );
682 
683  //extend bounds by pen width / 2.0
684  symbolBounds.adjust( -penWidth / 2.0, -penWidth / 2.0,
685  penWidth / 2.0, penWidth / 2.0 );
686 
687  return symbolBounds;
688 }
689 
690 bool QgsEllipseSymbolLayer::writeDxf( QgsDxfExport &e, double mmMapUnitScaleFactor, const QString &layerName, QgsSymbolRenderContext &context, QPointF shift ) const
691 {
692  //width
693  double symbolWidth = mSymbolWidth;
694 
695  if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyWidth ) ) //1. priority: data defined setting on symbol layer le
696  {
697  context.setOriginalValueVariable( mSymbolWidth );
699  }
700  if ( mSymbolWidthUnit == QgsUnitTypes::RenderMillimeters )
701  {
702  symbolWidth *= mmMapUnitScaleFactor;
703  }
704 
705  //height
706  double symbolHeight = mSymbolHeight;
707  if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyHeight ) ) //1. priority: data defined setting on symbol layer level
708  {
709  context.setOriginalValueVariable( mSymbolHeight );
711  }
712  if ( mSymbolHeightUnit == QgsUnitTypes::RenderMillimeters )
713  {
714  symbolHeight *= mmMapUnitScaleFactor;
715  }
716 
717  //stroke width
718  double strokeWidth = mStrokeWidth;
719 
721  {
722  context.setOriginalValueVariable( mStrokeWidth );
724  }
725  if ( mStrokeWidthUnit == QgsUnitTypes::RenderMillimeters )
726  {
727  strokeWidth *= strokeWidth;
728  }
729 
730  //fill color
731  QColor fc = mColor;
733  {
736  }
737 
738  //stroke color
739  QColor oc = mStrokeColor;
741  {
744  }
745 
746  //symbol name
747  QString symbolName = mSymbolName;
749  {
750  context.setOriginalValueVariable( mSymbolName );
752  }
753 
754  //offset
755  double offsetX = 0;
756  double offsetY = 0;
757  markerOffset( context, offsetX, offsetY );
758  QPointF off( offsetX, offsetY );
759 
760  //priority for rotation: 1. data defined symbol level, 2. symbol layer rotation (mAngle)
761  double rotation = 0.0;
763  {
764  context.setOriginalValueVariable( mAngle );
766  }
767  else if ( !qgsDoubleNear( mAngle + mLineAngle, 0.0 ) )
768  {
769  rotation = mAngle + mLineAngle;
770  }
771  rotation = -rotation; //rotation in Qt is counterclockwise
772  if ( rotation )
773  off = _rotatedOffset( off, rotation );
774 
775  QTransform t;
776  t.translate( shift.x() + offsetX, shift.y() + offsetY );
777 
778  if ( !qgsDoubleNear( rotation, 0.0 ) )
779  t.rotate( rotation );
780 
781  double halfWidth = symbolWidth / 2.0;
782  double halfHeight = symbolHeight / 2.0;
783 
784  if ( symbolName == QLatin1String( "circle" ) )
785  {
786  if ( qgsDoubleNear( halfWidth, halfHeight ) )
787  {
788  QgsPoint pt( t.map( QPointF( 0, 0 ) ) );
789  e.writeFilledCircle( layerName, oc, pt, halfWidth );
790  }
791  else
792  {
793  QgsPointSequence line;
794 
795  double stepsize = 2 * M_PI / 40;
796  for ( int i = 0; i < 39; ++i )
797  {
798  double angle = stepsize * i;
799  double x = halfWidth * std::cos( angle );
800  double y = halfHeight * std::sin( angle );
801  line << QgsPoint( t.map( QPointF( x, y ) ) );
802  }
803  //close ellipse with first point
804  line << line.at( 0 );
805 
806  if ( mBrush.style() != Qt::NoBrush )
807  e.writePolygon( QgsRingSequence() << line, layerName, QStringLiteral( "SOLID" ), fc );
808  if ( mPen.style() != Qt::NoPen )
809  e.writePolyline( line, layerName, QStringLiteral( "CONTINUOUS" ), oc, strokeWidth );
810  }
811  }
812  else if ( symbolName == QLatin1String( "rectangle" ) )
813  {
815  p << QgsPoint( t.map( QPointF( -halfWidth, -halfHeight ) ) )
816  << QgsPoint( t.map( QPointF( halfWidth, -halfHeight ) ) )
817  << QgsPoint( t.map( QPointF( halfWidth, halfHeight ) ) )
818  << QgsPoint( t.map( QPointF( -halfWidth, halfHeight ) ) );
819  p << p[0];
820 
821  if ( mBrush.style() != Qt::NoBrush )
822  e.writePolygon( QgsRingSequence() << p, layerName, QStringLiteral( "SOLID" ), fc );
823  if ( mPen.style() != Qt::NoPen )
824  e.writePolyline( p, layerName, QStringLiteral( "CONTINUOUS" ), oc, strokeWidth );
825  return true;
826  }
827  else if ( symbolName == QLatin1String( "cross" ) && mPen.style() != Qt::NoPen )
828  {
830  << QgsPoint( t.map( QPointF( -halfWidth, 0 ) ) )
831  << QgsPoint( t.map( QPointF( halfWidth, 0 ) ) ),
832  layerName, QStringLiteral( "CONTINUOUS" ), oc, strokeWidth );
834  << QgsPoint( t.map( QPointF( 0, halfHeight ) ) )
835  << QgsPoint( t.map( QPointF( 0, -halfHeight ) ) ),
836  layerName, QStringLiteral( "CONTINUOUS" ), oc, strokeWidth );
837  return true;
838  }
839  else if ( symbolName == QLatin1String( "triangle" ) )
840  {
842  p << QgsPoint( t.map( QPointF( -halfWidth, -halfHeight ) ) )
843  << QgsPoint( t.map( QPointF( halfWidth, -halfHeight ) ) )
844  << QgsPoint( t.map( QPointF( 0, halfHeight ) ) );
845  p << p[0];
846  if ( mBrush.style() != Qt::NoBrush )
847  e.writePolygon( QgsRingSequence() << p, layerName, QStringLiteral( "SOLID" ), fc );
848  if ( mPen.style() != Qt::NoPen )
849  e.writePolyline( p, layerName, QStringLiteral( "CONTINUOUS" ), oc, strokeWidth );
850  return true;
851  }
852 
853  return false; //soon...
854 }
855 
856 
void setOffset(QPointF offset)
Sets the marker&#39;s offset, which is the horizontal and vertical displacement which the rendered marker...
static void wellKnownMarkerToSld(QDomDocument &doc, QDomElement &element, const QString &name, const QColor &color, const QColor &strokeColor, Qt::PenStyle strokeStyle, double strokeWidth=-1, double size=-1)
QgsMapUnitScale mapUnitScale() const override
QColor valueAsColor(int key, const QgsExpressionContext &context, const QColor &defaultColor=QColor(), bool *ok=nullptr) const
Calculates the current value of the property with the specified key and interprets it as a color...
void setOffsetUnit(QgsUnitTypes::RenderUnit unit)
Sets the units for the symbol&#39;s offset.
QString asExpression() const
Returns an expression string representing the state of the property, or an empty string if the proper...
void setStrokeWidthMapUnitScale(const QgsMapUnitScale &scale)
static QDomElement createVendorOptionElement(QDomDocument &doc, const QString &name, const QString &value)
QgsUnitTypes::RenderUnit outputUnit() const override
Returns the units to use for sizes and widths within the symbol layer.
bool isNull() const
Returns true if the geometry is null (ie, contains no underlying geometry accessible via geometry() )...
double valueAsDouble(int key, const QgsExpressionContext &context, double defaultValue=0.0, bool *ok=nullptr) const
Calculates the current value of the property with the specified key and interprets it as a double...
void writePolyline(const QgsPointSequence &line, const QString &layer, const QString &lineStyleName, const QColor &color, double width=-1)
Draw dxf primitives (LWPOLYLINE)
void setFillColor(const QColor &c) override
Set fill color.
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
void startRender(QgsSymbolRenderContext &context) override
double mLineAngle
Line rotation angle (see setLineAngle() for details)
QgsUnitTypes::RenderUnit mSizeUnit
Marker size unit.
static QPointF decodePoint(const QString &string)
Decodes a QSizeF from a string.
void copyPaintEffect(QgsSymbolLayer *destLayer) const
Copies paint effect of this layer to another symbol layer.
QString layerType() const override
Returns a string that represents this layer type.
static QgsSymbolLayer * create(const QgsStringMap &properties=QgsStringMap())
void setOutputUnit(QgsUnitTypes::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
static QString encodeMapUnitScale(const QgsMapUnitScale &mapUnitScale)
static void createDisplacementElement(QDomDocument &doc, QDomElement &element, QPointF offset)
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:111
void setOffsetMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale for the symbol&#39;s offset.
void restoreOldDataDefinedProperties(const QgsStringMap &stringMap)
Restores older data defined properties from string map.
static double sizeInPixelsFromSldUom(const QString &uom, double size)
Returns the size scaled in pixels according to the uom attribute.
void setPenJoinStyle(Qt::PenJoinStyle style)
Set stroke join style.
QVariant value(const QgsExpressionContext &context, const QVariant &defaultValue=QVariant(), bool *ok=nullptr) const
Calculates the current value of the property, including any transforms which are set for the property...
QPointF mOffset
Marker offset.
void setSymbolWidthUnit(QgsUnitTypes::RenderUnit unit)
Sets the units for the symbol&#39;s width.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:62
static bool rotationFromSldElement(QDomElement &element, QString &rotationFunc)
void toSld(QDomDocument &doc, QDomElement &element, const QgsStringMap &props) const override
QColor strokeColor() const override
Get stroke color.
QMap< QString, QString > QgsStringMap
Definition: qgis.h:479
Rotation of symbol may be changed during rendering and symbol should not be cached.
Definition: qgssymbol.h:104
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
Compare two doubles (but allow some difference)
Definition: qgis.h:251
static QString encodePoint(QPointF point)
Encodes a QPointF to a string.
Name, eg shape name for simple markers.
static Qt::PenJoinStyle decodePenJoinStyle(const QString &str)
bool isActive(int key) const override
Returns true if the collection contains an active property with the specified key.
void writePolygon(const QgsRingSequence &polygon, const QString &layer, const QString &hatchPattern, const QColor &color)
Draw dxf filled polygon (HATCH)
double mapRotation() const
Return current map rotation in degrees.
static QString encodeColor(const QColor &color)
virtual void setColor(const QColor &color)
The fill color.
QVariant value(int key, const QgsExpressionContext &context, const QVariant &defaultValue=QVariant()) const override
Returns the calculated value of the property with the specified key from within the collection...
void setOriginalValueVariable(const QVariant &value)
Sets the original value variable value for data defined symbology.
Definition: qgssymbol.cpp:1055
static QString encodePenStyle(Qt::PenStyle style)
Perform transforms between map coordinates and device coordinates.
Definition: qgsmaptopixel.h:36
static double rescaleUom(double size, QgsUnitTypes::RenderUnit 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.
Qt::PenStyle strokeStyle() const
double angle() const
Returns the rotation angle for the marker, in degrees clockwise from north.
QgsUnitTypes::RenderUnit mOffsetUnit
Offset units.
A symbol layer for rendering objects with major and minor axis (e.g.
static QgsStringMap getVendorOptionList(QDomElement &element)
QgsStringMap properties() const override
Should be reimplemented by subclasses to return a string map that contains the configuration informat...
double size() const
Returns the symbol size.
void writeSldMarker(QDomDocument &doc, QDomElement &element, const QgsStringMap &props) const override
Writes the symbol layer definition as a SLD XML element.
void stopRender(QgsSymbolRenderContext &context) override
void setSymbolName(const QString &name)
QgsPropertyCollection & dataDefinedProperties()
Returns a reference to the symbol layer&#39;s property collection, used for data defined overrides...
void setSize(double size)
Sets the symbol size.
void setHorizontalAnchorPoint(HorizontalAnchorPoint h)
Sets the horizontal anchor point for positioning the symbol.
void setStrokeWidthUnit(QgsUnitTypes::RenderUnit unit)
Sets the units for the symbol&#39;s stroke width.
void setSizeMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale for the symbol&#39;s size.
virtual QColor color() const
The fill color.
static void createRotationElement(QDomDocument &doc, QDomElement &element, const QString &rotationFunc)
double mAngle
Marker rotation angle, in degrees clockwise from north.
void writeFilledCircle(const QString &layer, const QColor &color, const QgsPoint &pt, double radius)
Write filled circle (as hatch)
bool writeDxf(QgsDxfExport &e, double mmMapUnitScaleFactor, const QString &layerName, QgsSymbolRenderContext &context, QPointF shift=QPointF(0.0, 0.0)) const override
write as DXF
static QgsSymbolLayer * createFromSld(QDomElement &element)
void setMapUnitScale(const QgsMapUnitScale &scale) override
void markerOffset(QgsSymbolRenderContext &context, double &offsetX, double &offsetY) const
Calculates the required marker offset, including both the symbol offset and any displacement required...
void setSymbolHeightMapUnitScale(const QgsMapUnitScale &scale)
QgsMapUnitScale mSizeMapUnitScale
Marker size map unit scale.
static Q_INVOKABLE QgsUnitTypes::RenderUnit decodeRenderUnit(const QString &string, bool *ok=nullptr)
Decodes a render unit from a string.
QgsGeometry geometry() const
Returns the geometry associated with this feature.
Definition: qgsfeature.cpp:101
A store for object properties.
Definition: qgsproperty.h:229
QgsRenderContext & renderContext()
Returns a reference to the context&#39;s render context.
Definition: qgssymbol.h:453
QgsMapUnitScale mapUnitScale() const override
QRectF bounds(QPointF point, QgsSymbolRenderContext &context) override
Returns the approximate bounding box of the marker symbol layer, taking into account any data defined...
Point geometry type, with support for z-dimension and m-values.
Definition: qgspoint.h:37
static Qt::PenStyle decodePenStyle(const QString &str)
QgsWkbTypes::GeometryType type() const
Returns type of the geometry as a QgsWkbTypes::GeometryType.
void renderPoint(QPointF point, QgsSymbolRenderContext &context) override
Renders a marker at the specified point.
HorizontalAnchorPoint
Symbol horizontal anchor points.
VerticalAnchorPoint
Symbol vertical anchor points.
static void createGeometryElement(QDomDocument &doc, QDomElement &element, const QString &geomFunc)
static Q_INVOKABLE QString encodeUnit(QgsUnitTypes::DistanceUnit unit)
Encodes a distance unit to a string.
void setSymbolHeightUnit(QgsUnitTypes::RenderUnit unit)
Sets the units for the symbol&#39;s height.
QgsExpressionContext & expressionContext()
Gets the expression context.
QVector< QgsPoint > QgsPointSequence
QVector< QgsPointSequence > QgsRingSequence
void setSizeUnit(QgsUnitTypes::RenderUnit unit)
Sets the units for the symbol&#39;s size.
QString valueAsString(int key, const QgsExpressionContext &context, const QString &defaultString=QString(), bool *ok=nullptr) const
Calculates the current value of the property with the specified key and interprets it as a string...
Stroke style (eg solid, dashed)
double convertToPainterUnits(double size, QgsUnitTypes::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale()) const
Converts a size from the specified units to painter units (pixels).
QPainter * painter()
Returns the destination QPainter for the render operation.
const QgsMapToPixel & mapToPixel() const
void setStrokeStyle(Qt::PenStyle strokeStyle)
void setStrokeColor(const QColor &c) override
Set stroke color.
Struct for storing maximum and minimum scales for measurements in map units.
void setMapUnitScale(const QgsMapUnitScale &scale) override
const QgsFeature * feature() const
Current feature being rendered - may be null.
Definition: qgssymbol.h:509
QgsUnitTypes::RenderUnit outputUnit() const override
Returns the units to use for sizes and widths within the symbol layer.
HorizontalAnchorPoint mHorizontalAnchorPoint
Horizontal anchor point.
static bool wellKnownMarkerFromSld(QDomElement &element, QString &name, QColor &color, QColor &strokeColor, Qt::PenStyle &strokeStyle, double &strokeWidth, double &size)
double mSize
Marker size.
void setAngle(double angle)
Sets the rotation angle for the marker.
static QgsMapUnitScale decodeMapUnitScale(const QString &str)
QColor fillColor() const override
Get fill color.
bool hasActiveProperties() const override
Returns true if the collection has any active properties, or false if all properties within the colle...
QgsMapUnitScale mOffsetMapUnitScale
Offset map unit scale.
VerticalAnchorPoint mVerticalAnchorPoint
Vertical anchor point.
QgsEllipseSymbolLayer * clone() const override
Shall be reimplemented by subclasses to create a deep copy of the instance.
static QPointF _rotatedOffset(QPointF offset, double angle)
Adjusts a marker offset to account for rotation.
QPointF offset() const
Returns the marker&#39;s offset, which is the horizontal and vertical displacement which the rendered mar...
void setOutputUnit(QgsUnitTypes::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
void setSymbolWidthMapUnitScale(const QgsMapUnitScale &scale)
static QString encodePenJoinStyle(Qt::PenJoinStyle style)
QgsPropertyCollection mDataDefinedProperties
bool isActive() const
Returns whether the property is currently active.
QgsProperty property(int key) const override
Returns a matching property from the collection, if one exists.
RenderUnit
Rendering size units.
Definition: qgsunittypes.h:100
static QColor decodeColor(const QString &str)
void copyDataDefinedProperties(QgsSymbolLayer *destLayer) const
Copies all data defined properties of this layer to another symbol layer.
void setVerticalAnchorPoint(VerticalAnchorPoint v)
Sets the vertical anchor point for positioning the symbol.
QgsSymbol::RenderHints renderHints() const
Returns the rendering hint flags for the symbol.
Definition: qgssymbol.h:499
void startRender(QgsSymbolRenderContext &context) override