QGIS API Documentation  3.2.0-Bonn (bc43194)
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 #include "qgssymbollayerutils.h"
25 
26 #include <QPainter>
27 #include <QSet>
28 #include <QDomDocument>
29 #include <QDomElement>
30 
32  : mSymbolName( QStringLiteral( "circle" ) )
33  , mStrokeColor( QColor( 35, 35, 35 ) )
34 {
35  mColor = Qt::white;
36  mPen.setColor( mStrokeColor );
37  mPen.setStyle( mStrokeStyle );
38  mPen.setJoinStyle( mPenJoinStyle );
39  mPen.setWidth( 1.0 );
40  mBrush.setColor( mColor );
41  mBrush.setStyle( Qt::SolidPattern );
42  mOffset = QPointF( 0, 0 );
43  mAngle = 0;
44 }
45 
47 {
49  if ( properties.contains( QStringLiteral( "symbol_name" ) ) )
50  {
51  layer->setSymbolName( properties[ QStringLiteral( "symbol_name" )] );
52  }
53  if ( properties.contains( QStringLiteral( "symbol_width" ) ) )
54  {
55  layer->setSymbolWidth( properties[QStringLiteral( "symbol_width" )].toDouble() );
56  }
57  if ( properties.contains( QStringLiteral( "symbol_width_unit" ) ) )
58  {
59  layer->setSymbolWidthUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "symbol_width_unit" )] ) );
60  }
61  if ( properties.contains( QStringLiteral( "symbol_width_map_unit_scale" ) ) )
62  {
63  layer->setSymbolWidthMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "symbol_width_map_unit_scale" )] ) );
64  }
65  if ( properties.contains( QStringLiteral( "symbol_height" ) ) )
66  {
67  layer->setSymbolHeight( properties[QStringLiteral( "symbol_height" )].toDouble() );
68  }
69  if ( properties.contains( QStringLiteral( "symbol_height_unit" ) ) )
70  {
71  layer->setSymbolHeightUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "symbol_height_unit" )] ) );
72  }
73  if ( properties.contains( QStringLiteral( "symbol_height_map_unit_scale" ) ) )
74  {
75  layer->setSymbolHeightMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "symbol_height_map_unit_scale" )] ) );
76  }
77  if ( properties.contains( QStringLiteral( "angle" ) ) )
78  {
79  layer->setAngle( properties[QStringLiteral( "angle" )].toDouble() );
80  }
81  if ( properties.contains( QStringLiteral( "outline_style" ) ) )
82  {
83  layer->setStrokeStyle( QgsSymbolLayerUtils::decodePenStyle( properties[QStringLiteral( "outline_style" )] ) );
84  }
85  else if ( properties.contains( QStringLiteral( "line_style" ) ) )
86  {
87  layer->setStrokeStyle( QgsSymbolLayerUtils::decodePenStyle( properties[QStringLiteral( "line_style" )] ) );
88  }
89  if ( properties.contains( QStringLiteral( "joinstyle" ) ) )
90  {
91  layer->setPenJoinStyle( QgsSymbolLayerUtils::decodePenJoinStyle( properties[QStringLiteral( "joinstyle" )] ) );
92  }
93  if ( properties.contains( QStringLiteral( "outline_width" ) ) )
94  {
95  layer->setStrokeWidth( properties[QStringLiteral( "outline_width" )].toDouble() );
96  }
97  else if ( properties.contains( QStringLiteral( "line_width" ) ) )
98  {
99  layer->setStrokeWidth( properties[QStringLiteral( "line_width" )].toDouble() );
100  }
101  if ( properties.contains( QStringLiteral( "outline_width_unit" ) ) )
102  {
103  layer->setStrokeWidthUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "outline_width_unit" )] ) );
104  }
105  else if ( properties.contains( QStringLiteral( "line_width_unit" ) ) )
106  {
107  layer->setStrokeWidthUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "line_width_unit" )] ) );
108  }
109  if ( properties.contains( QStringLiteral( "outline_width_map_unit_scale" ) ) )
110  {
111  layer->setStrokeWidthMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "outline_width_map_unit_scale" )] ) );
112  }
113  if ( properties.contains( QStringLiteral( "fill_color" ) ) )
114  {
115  //pre 2.5 projects used "fill_color"
116  layer->setFillColor( QgsSymbolLayerUtils::decodeColor( properties[QStringLiteral( "fill_color" )] ) );
117  }
118  else if ( properties.contains( QStringLiteral( "color" ) ) )
119  {
120  layer->setFillColor( QgsSymbolLayerUtils::decodeColor( properties[QStringLiteral( "color" )] ) );
121  }
122  if ( properties.contains( QStringLiteral( "outline_color" ) ) )
123  {
124  layer->setStrokeColor( QgsSymbolLayerUtils::decodeColor( properties[QStringLiteral( "outline_color" )] ) );
125  }
126  else if ( properties.contains( QStringLiteral( "line_color" ) ) )
127  {
128  layer->setStrokeColor( QgsSymbolLayerUtils::decodeColor( properties[QStringLiteral( "line_color" )] ) );
129  }
130  if ( properties.contains( QStringLiteral( "size" ) ) )
131  {
132  layer->setSize( properties[QStringLiteral( "size" )].toDouble() );
133  }
134  if ( properties.contains( QStringLiteral( "size_unit" ) ) )
135  {
136  layer->setSizeUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "size_unit" )] ) );
137  }
138  if ( properties.contains( QStringLiteral( "size_map_unit_scale" ) ) )
139  {
140  layer->setSizeMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "size_map_unit_scale" )] ) );
141  }
142  if ( properties.contains( QStringLiteral( "offset" ) ) )
143  {
144  layer->setOffset( QgsSymbolLayerUtils::decodePoint( properties[QStringLiteral( "offset" )] ) );
145  }
146  if ( properties.contains( QStringLiteral( "offset_unit" ) ) )
147  {
148  layer->setOffsetUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "offset_unit" )] ) );
149  }
150  if ( properties.contains( QStringLiteral( "offset_map_unit_scale" ) ) )
151  {
152  layer->setOffsetMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "offset_map_unit_scale" )] ) );
153  }
154  if ( properties.contains( QStringLiteral( "horizontal_anchor_point" ) ) )
155  {
156  layer->setHorizontalAnchorPoint( QgsMarkerSymbolLayer::HorizontalAnchorPoint( properties[ QStringLiteral( "horizontal_anchor_point" )].toInt() ) );
157  }
158  if ( properties.contains( QStringLiteral( "vertical_anchor_point" ) ) )
159  {
160  layer->setVerticalAnchorPoint( QgsMarkerSymbolLayer::VerticalAnchorPoint( properties[ QStringLiteral( "vertical_anchor_point" )].toInt() ) );
161  }
162 
163  //data defined properties
164  layer->restoreOldDataDefinedProperties( properties );
165 
166  return layer;
167 }
168 
170 {
171  double scaledWidth = mSymbolWidth;
172  double scaledHeight = mSymbolHeight;
173 
175  {
176  bool ok;
177  context.setOriginalValueVariable( mStrokeWidth );
179  if ( exprVal.isValid() )
180  {
181  double width = exprVal.toDouble( &ok );
182  if ( ok )
183  {
184  width = context.renderContext().convertToPainterUnits( width, mStrokeWidthUnit, mStrokeWidthMapUnitScale );
185  mPen.setWidthF( width );
186  }
187  }
188 
191  if ( exprVal.isValid() )
192  {
193  mPen.setStyle( QgsSymbolLayerUtils::decodePenStyle( exprVal.toString() ) );
194  }
195 
198  if ( exprVal.isValid() )
199  {
200  mPen.setJoinStyle( QgsSymbolLayerUtils::decodePenJoinStyle( exprVal.toString() ) );
201  }
202 
205 
208 
210  {
211  QString symbolName = mSymbolName;
212  context.setOriginalValueVariable( mSymbolName );
214  if ( exprVal.isValid() )
215  {
216  symbolName = exprVal.toString();
217  }
218  preparePath( symbolName, context, &scaledWidth, &scaledHeight, context.feature() );
219  }
220  }
221 
222  //offset and rotation
223  bool hasDataDefinedRotation = false;
224  QPointF offset;
225  double angle = 0;
226  calculateOffsetAndRotation( context, scaledWidth, scaledHeight, hasDataDefinedRotation, offset, angle );
227 
228  QPainter *p = context.renderContext().painter();
229  if ( !p )
230  {
231  return;
232  }
233 
234  QMatrix transform;
235  transform.translate( point.x() + offset.x(), point.y() + offset.y() );
236  if ( !qgsDoubleNear( angle, 0.0 ) )
237  {
238  transform.rotate( angle );
239  }
240 
241  p->setPen( mPen );
242  p->setBrush( mBrush );
243  p->drawPath( transform.map( mPainterPath ) );
244 }
245 
246 
247 void QgsEllipseSymbolLayer::calculateOffsetAndRotation( QgsSymbolRenderContext &context,
248  double scaledWidth,
249  double scaledHeight,
250  bool &hasDataDefinedRotation,
251  QPointF &offset,
252  double &angle ) const
253 {
254  double offsetX = 0;
255  double offsetY = 0;
256  markerOffset( context, scaledWidth, scaledHeight, mSymbolWidthUnit, mSymbolHeightUnit, offsetX, offsetY, mSymbolWidthMapUnitScale, mSymbolHeightMapUnitScale );
257  offset = QPointF( offsetX, offsetY );
258 
259 //priority for rotation: 1. data defined symbol level, 2. symbol layer rotation (mAngle)
260  bool ok = true;
261  angle = mAngle + mLineAngle;
262  bool usingDataDefinedRotation = false;
264  {
265  context.setOriginalValueVariable( angle );
267  usingDataDefinedRotation = ok;
268  }
269 
270  hasDataDefinedRotation = context.renderHints() & QgsSymbol::DynamicRotation || usingDataDefinedRotation;
271  if ( hasDataDefinedRotation )
272  {
273  // For non-point markers, "dataDefinedRotation" means following the
274  // shape (shape-data defined). For them, "field-data defined" does
275  // not work at all. TODO: if "field-data defined" ever gets implemented
276  // we'll need a way to distinguish here between the two, possibly
277  // using another flag in renderHints()
278  const QgsFeature *f = context.feature();
279  if ( f )
280  {
281  const QgsGeometry g = f->geometry();
282  if ( !g.isNull() && g.type() == QgsWkbTypes::PointGeometry )
283  {
284  const QgsMapToPixel &m2p = context.renderContext().mapToPixel();
285  angle += m2p.mapRotation();
286  }
287  }
288  }
289 
290  if ( angle )
291  offset = _rotatedOffset( offset, angle );
292 }
293 
295 {
296  return QStringLiteral( "EllipseMarker" );
297 }
298 
300 {
301  QgsMarkerSymbolLayer::startRender( context ); // get anchor point expressions
302  if ( !context.feature() || !dataDefinedProperties().hasActiveProperties() )
303  {
304  preparePath( mSymbolName, context );
305  }
306  mPen.setColor( mStrokeColor );
307  mPen.setStyle( mStrokeStyle );
308  mPen.setJoinStyle( mPenJoinStyle );
309  mPen.setWidthF( context.renderContext().convertToPainterUnits( mStrokeWidth, mStrokeWidthUnit, mStrokeWidthMapUnitScale ) );
310  mBrush.setColor( mColor );
311 }
312 
314 {
315 }
316 
318 {
320  m->setSymbolName( mSymbolName );
321  m->setSymbolWidth( mSymbolWidth );
322  m->setSymbolHeight( mSymbolHeight );
323  m->setStrokeStyle( mStrokeStyle );
324  m->setOffset( mOffset );
327  m->setStrokeStyle( mStrokeStyle );
328  m->setPenJoinStyle( mPenJoinStyle );
329  m->setStrokeWidth( mStrokeWidth );
330  m->setColor( color() );
331  m->setStrokeColor( mStrokeColor );
332  m->setSymbolWidthUnit( mSymbolWidthUnit );
333  m->setSymbolWidthMapUnitScale( mSymbolWidthMapUnitScale );
334  m->setSymbolHeightUnit( mSymbolHeightUnit );
335  m->setSymbolHeightMapUnitScale( mSymbolHeightMapUnitScale );
336  m->setStrokeWidthUnit( mStrokeWidthUnit );
337  m->setStrokeWidthMapUnitScale( mStrokeWidthMapUnitScale );
338  m->setAngle( mAngle );
341 
343  copyPaintEffect( m );
344  return m;
345 }
346 
347 void QgsEllipseSymbolLayer::toSld( QDomDocument &doc, QDomElement &element, const QgsStringMap &props ) const
348 {
349  QDomElement symbolizerElem = doc.createElement( QStringLiteral( "se:PointSymbolizer" ) );
350  if ( !props.value( QStringLiteral( "uom" ), QLatin1String( "" ) ).isEmpty() )
351  symbolizerElem.setAttribute( QStringLiteral( "uom" ), props.value( QStringLiteral( "uom" ), QLatin1String( "" ) ) );
352  element.appendChild( symbolizerElem );
353 
354  // <Geometry>
355  QgsSymbolLayerUtils::createGeometryElement( doc, symbolizerElem, props.value( QStringLiteral( "geom" ), QLatin1String( "" ) ) );
356 
357  writeSldMarker( doc, symbolizerElem, props );
358 }
359 
360 void QgsEllipseSymbolLayer::writeSldMarker( QDomDocument &doc, QDomElement &element, const QgsStringMap &props ) const
361 {
362  // <Graphic>
363  QDomElement graphicElem = doc.createElement( QStringLiteral( "se:Graphic" ) );
364  element.appendChild( graphicElem );
365 
366  double strokeWidth = QgsSymbolLayerUtils::rescaleUom( mStrokeWidth, mStrokeWidthUnit, props );
367  double symbolWidth = QgsSymbolLayerUtils::rescaleUom( mSymbolWidth, mSymbolWidthUnit, props );
368  QgsSymbolLayerUtils::wellKnownMarkerToSld( doc, graphicElem, mSymbolName, mColor, mStrokeColor, mStrokeStyle, strokeWidth, symbolWidth );
369 
370  // <Rotation>
372 
373  QString angleFunc = props.value( QStringLiteral( "angle" ), QLatin1String( "" ) );
374  if ( angleFunc.isEmpty() ) // symbol has no angle set
375  {
376  if ( ddRotation && ddRotation.isActive() )
377  {
378  angleFunc = ddRotation.asExpression();
379  }
380  else if ( !qgsDoubleNear( mAngle, 0.0 ) )
381  angleFunc = QString::number( mAngle );
382  }
383  else if ( ddRotation && ddRotation.isActive() )
384  {
385  // the symbol has an angle and the symbol layer have a rotation
386  // property set
387  angleFunc = QStringLiteral( "%1 + %2" ).arg( angleFunc, ddRotation.asExpression() );
388  }
389  else if ( !qgsDoubleNear( mAngle, 0.0 ) )
390  {
391  // both the symbol and the symbol layer have angle value set
392  bool ok;
393  double angle = angleFunc.toDouble( &ok );
394  if ( !ok )
395  {
396  // its a string (probably a property name or a function)
397  angleFunc = QStringLiteral( "%1 + %2" ).arg( angleFunc ).arg( mAngle );
398  }
399  else if ( !qgsDoubleNear( angle + mAngle, 0.0 ) )
400  {
401  // it's a double value
402  angleFunc = QString::number( angle + mAngle );
403  }
404  }
405  QgsSymbolLayerUtils::createRotationElement( doc, graphicElem, angleFunc );
406 
407  // <Displacement>
409  QgsSymbolLayerUtils::createDisplacementElement( doc, graphicElem, offset );
410 
411  // store w/h factor in a <VendorOption>
412  double widthHeightFactor = mSymbolWidth / mSymbolHeight;
413  QDomElement factorElem = QgsSymbolLayerUtils::createVendorOptionElement( doc, QStringLiteral( "widthHeightFactor" ), QString::number( widthHeightFactor ) );
414  graphicElem.appendChild( factorElem );
415 }
416 
418 {
419  QgsDebugMsg( "Entered." );
420 
421  QDomElement graphicElem = element.firstChildElement( QStringLiteral( "Graphic" ) );
422  if ( graphicElem.isNull() )
423  return nullptr;
424 
425  QString name = QStringLiteral( "circle" );
426  QColor fillColor, strokeColor;
427  double strokeWidth, size;
428  double widthHeightFactor = 1.0;
429  Qt::PenStyle strokeStyle;
430 
431  QgsStringMap vendorOptions = QgsSymbolLayerUtils::getVendorOptionList( graphicElem );
432  for ( QgsStringMap::iterator it = vendorOptions.begin(); it != vendorOptions.end(); ++it )
433  {
434  if ( it.key() == QLatin1String( "widthHeightFactor" ) )
435  {
436  bool ok;
437  double v = it.value().toDouble( &ok );
438  if ( ok && !qgsDoubleNear( v, 0.0 ) && v > 0 )
439  widthHeightFactor = v;
440  }
441  }
442 
443  if ( !QgsSymbolLayerUtils::wellKnownMarkerFromSld( graphicElem, name, fillColor, strokeColor, strokeStyle, strokeWidth, size ) )
444  return nullptr;
445 
446  QString uom = element.attribute( QStringLiteral( "uom" ) );
448  strokeWidth = QgsSymbolLayerUtils::sizeInPixelsFromSldUom( uom, strokeWidth );
449 
450  double angle = 0.0;
451  QString angleFunc;
452  if ( QgsSymbolLayerUtils::rotationFromSldElement( graphicElem, angleFunc ) )
453  {
454  bool ok;
455  double d = angleFunc.toDouble( &ok );
456  if ( ok )
457  angle = d;
458  }
459 
461  m->setOutputUnit( QgsUnitTypes::RenderUnit::RenderPixels );
462  m->setSymbolName( name );
463  m->setFillColor( fillColor );
464  m->setStrokeColor( strokeColor );
465  m->setStrokeStyle( strokeStyle );
466  m->setStrokeWidth( strokeWidth );
467  m->setSymbolWidth( size );
468  m->setSymbolHeight( size / widthHeightFactor );
469  m->setAngle( angle );
470  return m;
471 }
472 
474 {
475  QgsStringMap map;
476  map[QStringLiteral( "symbol_name" )] = mSymbolName;
477  map[QStringLiteral( "symbol_width" )] = QString::number( mSymbolWidth );
478  map[QStringLiteral( "symbol_width_unit" )] = QgsUnitTypes::encodeUnit( mSymbolWidthUnit );
479  map[QStringLiteral( "symbol_width_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mSymbolWidthMapUnitScale );
480  map[QStringLiteral( "symbol_height" )] = QString::number( mSymbolHeight );
481  map[QStringLiteral( "symbol_height_unit" )] = QgsUnitTypes::encodeUnit( mSymbolHeightUnit );
482  map[QStringLiteral( "symbol_height_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mSymbolHeightMapUnitScale );
483  map[QStringLiteral( "angle" )] = QString::number( mAngle );
484  map[QStringLiteral( "outline_style" )] = QgsSymbolLayerUtils::encodePenStyle( mStrokeStyle );
485  map[QStringLiteral( "outline_width" )] = QString::number( mStrokeWidth );
486  map[QStringLiteral( "outline_width_unit" )] = QgsUnitTypes::encodeUnit( mStrokeWidthUnit );
487  map[QStringLiteral( "outline_width_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mStrokeWidthMapUnitScale );
488  map[QStringLiteral( "joinstyle" )] = QgsSymbolLayerUtils::encodePenJoinStyle( mPenJoinStyle );
489  map[QStringLiteral( "color" )] = QgsSymbolLayerUtils::encodeColor( mColor );
490  map[QStringLiteral( "outline_color" )] = QgsSymbolLayerUtils::encodeColor( mStrokeColor );
491  map[QStringLiteral( "offset" )] = QgsSymbolLayerUtils::encodePoint( mOffset );
492  map[QStringLiteral( "offset_unit" )] = QgsUnitTypes::encodeUnit( mOffsetUnit );
493  map[QStringLiteral( "offset_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mOffsetMapUnitScale );
494  map[QStringLiteral( "size" )] = QString::number( mSize );
495  map[QStringLiteral( "size_unit" )] = QgsUnitTypes::encodeUnit( mSizeUnit );
496  map[QStringLiteral( "size_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mSizeMapUnitScale );
497  map[QStringLiteral( "horizontal_anchor_point" )] = QString::number( mHorizontalAnchorPoint );
498  map[QStringLiteral( "vertical_anchor_point" )] = QString::number( mVerticalAnchorPoint );
499  return map;
500 }
501 
502 QSizeF QgsEllipseSymbolLayer::calculateSize( QgsSymbolRenderContext &context, double *scaledWidth, double *scaledHeight )
503 {
504  double width = 0;
505 
506  if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyWidth ) ) //1. priority: data defined setting on symbol layer le
507  {
508  context.setOriginalValueVariable( mSymbolWidth );
510  }
511  else //2. priority: global width setting
512  {
513  width = mSymbolWidth;
514  }
515  if ( scaledWidth )
516  {
517  *scaledWidth = width;
518  }
519  width = context.renderContext().convertToPainterUnits( width, mSymbolWidthUnit, mSymbolHeightMapUnitScale );
520 
521  double height = 0;
522  if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyHeight ) ) //1. priority: data defined setting on symbol layer level
523  {
524  context.setOriginalValueVariable( mSymbolHeight );
526  }
527  else //2. priority: global height setting
528  {
529  height = mSymbolHeight;
530  }
531  if ( scaledHeight )
532  {
533  *scaledHeight = height;
534  }
535  height = context.renderContext().convertToPainterUnits( height, mSymbolHeightUnit, mSymbolHeightMapUnitScale );
536  return QSizeF( width, height );
537 }
538 
539 void QgsEllipseSymbolLayer::preparePath( const QString &symbolName, QgsSymbolRenderContext &context, double *scaledWidth, double *scaledHeight, const QgsFeature * )
540 {
541  mPainterPath = QPainterPath();
542 
543  QSizeF size = calculateSize( context, scaledWidth, scaledHeight );
544 
545  if ( symbolName == QLatin1String( "circle" ) )
546  {
547  mPainterPath.addEllipse( QRectF( -size.width() / 2.0, -size.height() / 2.0, size.width(), size.height() ) );
548  }
549  else if ( symbolName == QLatin1String( "semi_circle" ) )
550  {
551  mPainterPath.arcTo( -size.width() / 2.0, -size.height() / 2.0, size.width(), size.height(), 0, 180 );
552  mPainterPath.lineTo( 0, 0 );
553  }
554  else if ( symbolName == QLatin1String( "rectangle" ) )
555  {
556  mPainterPath.addRect( QRectF( -size.width() / 2.0, -size.height() / 2.0, size.width(), size.height() ) );
557  }
558  else if ( symbolName == QLatin1String( "diamond" ) )
559  {
560  mPainterPath.moveTo( -size.width() / 2.0, 0 );
561  mPainterPath.lineTo( 0, size.height() / 2.0 );
562  mPainterPath.lineTo( size.width() / 2.0, 0 );
563  mPainterPath.lineTo( 0, -size.height() / 2.0 );
564  mPainterPath.lineTo( -size.width() / 2.0, 0 );
565  }
566  else if ( symbolName == QLatin1String( "cross" ) )
567  {
568  mPainterPath.moveTo( 0, -size.height() / 2.0 );
569  mPainterPath.lineTo( 0, size.height() / 2.0 );
570  mPainterPath.moveTo( -size.width() / 2.0, 0 );
571  mPainterPath.lineTo( size.width() / 2.0, 0 );
572  }
573  else if ( symbolName == QLatin1String( "triangle" ) )
574  {
575  mPainterPath.moveTo( 0, -size.height() / 2.0 );
576  mPainterPath.lineTo( -size.width() / 2.0, size.height() / 2.0 );
577  mPainterPath.lineTo( size.width() / 2.0, size.height() / 2.0 );
578  mPainterPath.lineTo( 0, -size.height() / 2.0 );
579  }
580  else if ( symbolName == QLatin1String( "left_half_triangle" ) )
581  {
582  mPainterPath.moveTo( 0, size.height() / 2.0 );
583  mPainterPath.lineTo( size.width() / 2.0, size.height() / 2.0 );
584  mPainterPath.lineTo( 0, -size.height() / 2.0 );
585  mPainterPath.lineTo( 0, size.height() / 2.0 );
586  }
587  else if ( symbolName == QLatin1String( "right_half_triangle" ) )
588  {
589  mPainterPath.moveTo( -size.width() / 2.0, size.height() / 2.0 );
590  mPainterPath.lineTo( 0, size.height() / 2.0 );
591  mPainterPath.lineTo( 0, -size.height() / 2.0 );
592  mPainterPath.lineTo( -size.width() / 2.0, size.height() / 2.0 );
593  }
594 }
595 
597 {
599  mSymbolWidthUnit = unit;
600  mSymbolHeightUnit = unit;
601  mStrokeWidthUnit = unit;
602 }
603 
605 {
607  if ( mSymbolWidthUnit != unit || mSymbolHeightUnit != unit || mStrokeWidthUnit != unit )
608  {
610  }
611  return unit;
612 }
613 
615 {
617  mSymbolWidthMapUnitScale = scale;
618  mSymbolHeightMapUnitScale = scale;
619  mStrokeWidthMapUnitScale = scale;
620 }
621 
623 {
624  if ( QgsMarkerSymbolLayer::mapUnitScale() == mSymbolWidthMapUnitScale &&
625  mSymbolWidthMapUnitScale == mSymbolHeightMapUnitScale &&
626  mSymbolHeightMapUnitScale == mStrokeWidthMapUnitScale )
627  {
628  return mSymbolWidthMapUnitScale;
629  }
630  return QgsMapUnitScale();
631 }
632 
633 QRectF QgsEllipseSymbolLayer::bounds( QPointF point, QgsSymbolRenderContext &context )
634 {
635  QSizeF size = calculateSize( context );
636 
637  bool hasDataDefinedRotation = false;
638  QPointF offset;
639  double angle = 0;
640  calculateOffsetAndRotation( context, size.width(), size.height(), hasDataDefinedRotation, offset, angle );
641 
642  QMatrix transform;
643 
644  // move to the desired position
645  transform.translate( point.x() + offset.x(), point.y() + offset.y() );
646 
647  if ( !qgsDoubleNear( angle, 0.0 ) )
648  transform.rotate( angle );
649 
650  double penWidth = 0.0;
652  {
653  context.setOriginalValueVariable( mStrokeWidth );
655 
656  if ( exprVal.isValid() )
657  {
658  bool ok;
659  double strokeWidth = exprVal.toDouble( &ok );
660  if ( ok )
661  {
662  penWidth = context.renderContext().convertToPainterUnits( strokeWidth, mStrokeWidthUnit, mStrokeWidthMapUnitScale );
663  }
664  }
665  }
667  {
670  if ( exprVal.isValid() && exprVal.toString() == QLatin1String( "no" ) )
671  {
672  penWidth = 0.0;
673  }
674  }
675 
676  //antialiasing, add 1 pixel
677  penWidth += 1;
678 
679  QRectF symbolBounds = transform.mapRect( QRectF( -size.width() / 2.0,
680  -size.height() / 2.0,
681  size.width(),
682  size.height() ) );
683 
684  //extend bounds by pen width / 2.0
685  symbolBounds.adjust( -penWidth / 2.0, -penWidth / 2.0,
686  penWidth / 2.0, penWidth / 2.0 );
687 
688  return symbolBounds;
689 }
690 
691 bool QgsEllipseSymbolLayer::writeDxf( QgsDxfExport &e, double mmMapUnitScaleFactor, const QString &layerName, QgsSymbolRenderContext &context, QPointF shift ) const
692 {
693  //width
694  double symbolWidth = mSymbolWidth;
695 
696  if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyWidth ) ) //1. priority: data defined setting on symbol layer le
697  {
698  context.setOriginalValueVariable( mSymbolWidth );
700  }
701  if ( mSymbolWidthUnit == QgsUnitTypes::RenderMillimeters )
702  {
703  symbolWidth *= mmMapUnitScaleFactor;
704  }
705 
706  //height
707  double symbolHeight = mSymbolHeight;
708  if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyHeight ) ) //1. priority: data defined setting on symbol layer level
709  {
710  context.setOriginalValueVariable( mSymbolHeight );
712  }
713  if ( mSymbolHeightUnit == QgsUnitTypes::RenderMillimeters )
714  {
715  symbolHeight *= mmMapUnitScaleFactor;
716  }
717 
718  //stroke width
719  double strokeWidth = mStrokeWidth;
720 
722  {
723  context.setOriginalValueVariable( mStrokeWidth );
725  }
726  if ( mStrokeWidthUnit == QgsUnitTypes::RenderMillimeters )
727  {
728  strokeWidth *= strokeWidth;
729  }
730 
731  //fill color
732  QColor fc = mColor;
734  {
737  }
738 
739  //stroke color
740  QColor oc = mStrokeColor;
742  {
745  }
746 
747  //symbol name
748  QString symbolName = mSymbolName;
750  {
751  context.setOriginalValueVariable( mSymbolName );
753  }
754 
755  //offset
756  double offsetX = 0;
757  double offsetY = 0;
758  markerOffset( context, offsetX, offsetY );
759  QPointF off( offsetX, offsetY );
760 
761  //priority for rotation: 1. data defined symbol level, 2. symbol layer rotation (mAngle)
762  double rotation = 0.0;
764  {
765  context.setOriginalValueVariable( mAngle );
767  }
768  else if ( !qgsDoubleNear( mAngle + mLineAngle, 0.0 ) )
769  {
770  rotation = mAngle + mLineAngle;
771  }
772  rotation = -rotation; //rotation in Qt is counterclockwise
773  if ( rotation )
774  off = _rotatedOffset( off, rotation );
775 
776  QTransform t;
777  t.translate( shift.x() + offsetX, shift.y() + offsetY );
778 
779  if ( !qgsDoubleNear( rotation, 0.0 ) )
780  t.rotate( rotation );
781 
782  double halfWidth = symbolWidth / 2.0;
783  double halfHeight = symbolHeight / 2.0;
784 
785  if ( symbolName == QLatin1String( "circle" ) )
786  {
787  if ( qgsDoubleNear( halfWidth, halfHeight ) )
788  {
789  QgsPoint pt( t.map( QPointF( 0, 0 ) ) );
790  e.writeFilledCircle( layerName, oc, pt, halfWidth );
791  }
792  else
793  {
794  QgsPointSequence line;
795 
796  double stepsize = 2 * M_PI / 40;
797  for ( int i = 0; i < 39; ++i )
798  {
799  double angle = stepsize * i;
800  double x = halfWidth * std::cos( angle );
801  double y = halfHeight * std::sin( angle );
802  line << QgsPoint( t.map( QPointF( x, y ) ) );
803  }
804  //close ellipse with first point
805  line << line.at( 0 );
806 
807  if ( mBrush.style() != Qt::NoBrush )
808  e.writePolygon( QgsRingSequence() << line, layerName, QStringLiteral( "SOLID" ), fc );
809  if ( mPen.style() != Qt::NoPen )
810  e.writePolyline( line, layerName, QStringLiteral( "CONTINUOUS" ), oc, strokeWidth );
811  }
812  }
813  else if ( symbolName == QLatin1String( "rectangle" ) )
814  {
816  p << QgsPoint( t.map( QPointF( -halfWidth, -halfHeight ) ) )
817  << QgsPoint( t.map( QPointF( halfWidth, -halfHeight ) ) )
818  << QgsPoint( t.map( QPointF( halfWidth, halfHeight ) ) )
819  << QgsPoint( t.map( QPointF( -halfWidth, halfHeight ) ) );
820  p << p[0];
821 
822  if ( mBrush.style() != Qt::NoBrush )
823  e.writePolygon( QgsRingSequence() << p, layerName, QStringLiteral( "SOLID" ), fc );
824  if ( mPen.style() != Qt::NoPen )
825  e.writePolyline( p, layerName, QStringLiteral( "CONTINUOUS" ), oc, strokeWidth );
826  return true;
827  }
828  else if ( symbolName == QLatin1String( "cross" ) && mPen.style() != Qt::NoPen )
829  {
831  << QgsPoint( t.map( QPointF( -halfWidth, 0 ) ) )
832  << QgsPoint( t.map( QPointF( halfWidth, 0 ) ) ),
833  layerName, QStringLiteral( "CONTINUOUS" ), oc, strokeWidth );
835  << QgsPoint( t.map( QPointF( 0, halfHeight ) ) )
836  << QgsPoint( t.map( QPointF( 0, -halfHeight ) ) ),
837  layerName, QStringLiteral( "CONTINUOUS" ), oc, strokeWidth );
838  return true;
839  }
840  else if ( symbolName == QLatin1String( "triangle" ) )
841  {
843  p << QgsPoint( t.map( QPointF( -halfWidth, -halfHeight ) ) )
844  << QgsPoint( t.map( QPointF( halfWidth, -halfHeight ) ) )
845  << QgsPoint( t.map( QPointF( 0, halfHeight ) ) );
846  p << p[0];
847  if ( mBrush.style() != Qt::NoBrush )
848  e.writePolygon( QgsRingSequence() << p, layerName, QStringLiteral( "SOLID" ), fc );
849  if ( mPen.style() != Qt::NoPen )
850  e.writePolyline( p, layerName, QStringLiteral( "CONTINUOUS" ), oc, strokeWidth );
851  return true;
852  }
853 
854  return false; //soon...
855 }
856 
857 
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
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:251
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:104
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
Gets stroke color.
QMap< QString, QString > QgsStringMap
Definition: qgis.h:501
Rotation of symbol may be changed during rendering and symbol should not be cached.
Definition: qgssymbol.h:104
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
Returns 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:1050
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
Gets 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