QGIS API Documentation  3.21.0-Master (909859188c)
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  : 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 
47 QgsSymbolLayer *QgsEllipseSymbolLayer::create( const QVariantMap &properties )
48 {
50  if ( properties.contains( QStringLiteral( "symbol_name" ) ) )
51  {
52  layer->setShape( decodeShape( properties[ QStringLiteral( "symbol_name" )].toString() ) );
53  }
54  if ( properties.contains( QStringLiteral( "size" ) ) )
55  {
56  layer->setSize( properties[QStringLiteral( "size" )].toDouble() );
57  }
58  if ( properties.contains( QStringLiteral( "size_unit" ) ) )
59  {
60  layer->setSizeUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "size_unit" )].toString() ) );
61  }
62  if ( properties.contains( QStringLiteral( "size_map_unit_scale" ) ) )
63  {
64  layer->setSizeMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "size_map_unit_scale" )].toString() ) );
65  }
66  if ( properties.contains( QStringLiteral( "symbol_width" ) ) )
67  {
68  layer->setSymbolWidth( properties[QStringLiteral( "symbol_width" )].toDouble() );
69  }
70  if ( properties.contains( QStringLiteral( "symbol_width_unit" ) ) )
71  {
72  layer->setSymbolWidthUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "symbol_width_unit" )].toString() ) );
73  }
74  if ( properties.contains( QStringLiteral( "symbol_width_map_unit_scale" ) ) )
75  {
76  layer->setSymbolWidthMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "symbol_width_map_unit_scale" )].toString() ) );
77  }
78  if ( properties.contains( QStringLiteral( "symbol_height" ) ) )
79  {
80  layer->setSymbolHeight( properties[QStringLiteral( "symbol_height" )].toDouble() );
81  }
82  if ( properties.contains( QStringLiteral( "symbol_height_unit" ) ) )
83  {
84  layer->setSymbolHeightUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "symbol_height_unit" )].toString() ) );
85  }
86  if ( properties.contains( QStringLiteral( "symbol_height_map_unit_scale" ) ) )
87  {
88  layer->setSymbolHeightMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "symbol_height_map_unit_scale" )].toString() ) );
89  }
90  if ( properties.contains( QStringLiteral( "angle" ) ) )
91  {
92  layer->setAngle( properties[QStringLiteral( "angle" )].toDouble() );
93  }
94  if ( properties.contains( QStringLiteral( "outline_style" ) ) )
95  {
96  layer->setStrokeStyle( QgsSymbolLayerUtils::decodePenStyle( properties[QStringLiteral( "outline_style" )].toString() ) );
97  }
98  else if ( properties.contains( QStringLiteral( "line_style" ) ) )
99  {
100  layer->setStrokeStyle( QgsSymbolLayerUtils::decodePenStyle( properties[QStringLiteral( "line_style" )].toString() ) );
101  }
102  if ( properties.contains( QStringLiteral( "joinstyle" ) ) )
103  {
104  layer->setPenJoinStyle( QgsSymbolLayerUtils::decodePenJoinStyle( properties[QStringLiteral( "joinstyle" )].toString() ) );
105  }
106  if ( properties.contains( QStringLiteral( "cap_style" ) ) )
107  {
108  layer->setPenCapStyle( QgsSymbolLayerUtils::decodePenCapStyle( properties[QStringLiteral( "cap_style" )].toString() ) );
109  }
110  if ( properties.contains( QStringLiteral( "outline_width" ) ) )
111  {
112  layer->setStrokeWidth( properties[QStringLiteral( "outline_width" )].toDouble() );
113  }
114  else if ( properties.contains( QStringLiteral( "line_width" ) ) )
115  {
116  layer->setStrokeWidth( properties[QStringLiteral( "line_width" )].toDouble() );
117  }
118  if ( properties.contains( QStringLiteral( "outline_width_unit" ) ) )
119  {
120  layer->setStrokeWidthUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "outline_width_unit" )].toString() ) );
121  }
122  else if ( properties.contains( QStringLiteral( "line_width_unit" ) ) )
123  {
124  layer->setStrokeWidthUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "line_width_unit" )].toString() ) );
125  }
126  if ( properties.contains( QStringLiteral( "outline_width_map_unit_scale" ) ) )
127  {
128  layer->setStrokeWidthMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "outline_width_map_unit_scale" )].toString() ) );
129  }
130  if ( properties.contains( QStringLiteral( "fill_color" ) ) )
131  {
132  //pre 2.5 projects used "fill_color"
133  layer->setFillColor( QgsSymbolLayerUtils::decodeColor( properties[QStringLiteral( "fill_color" )].toString() ) );
134  }
135  else if ( properties.contains( QStringLiteral( "color" ) ) )
136  {
137  layer->setFillColor( QgsSymbolLayerUtils::decodeColor( properties[QStringLiteral( "color" )].toString() ) );
138  }
139  if ( properties.contains( QStringLiteral( "outline_color" ) ) )
140  {
141  layer->setStrokeColor( QgsSymbolLayerUtils::decodeColor( properties[QStringLiteral( "outline_color" )].toString() ) );
142  }
143  else if ( properties.contains( QStringLiteral( "line_color" ) ) )
144  {
145  layer->setStrokeColor( QgsSymbolLayerUtils::decodeColor( properties[QStringLiteral( "line_color" )].toString() ) );
146  }
147  if ( properties.contains( QStringLiteral( "offset" ) ) )
148  {
149  layer->setOffset( QgsSymbolLayerUtils::decodePoint( properties[QStringLiteral( "offset" )].toString() ) );
150  }
151  if ( properties.contains( QStringLiteral( "offset_unit" ) ) )
152  {
153  layer->setOffsetUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "offset_unit" )].toString() ) );
154  }
155  if ( properties.contains( QStringLiteral( "offset_map_unit_scale" ) ) )
156  {
157  layer->setOffsetMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "offset_map_unit_scale" )].toString() ) );
158  }
159  if ( properties.contains( QStringLiteral( "horizontal_anchor_point" ) ) )
160  {
161  layer->setHorizontalAnchorPoint( QgsMarkerSymbolLayer::HorizontalAnchorPoint( properties[ QStringLiteral( "horizontal_anchor_point" )].toInt() ) );
162  }
163  if ( properties.contains( QStringLiteral( "vertical_anchor_point" ) ) )
164  {
165  layer->setVerticalAnchorPoint( QgsMarkerSymbolLayer::VerticalAnchorPoint( properties[ QStringLiteral( "vertical_anchor_point" )].toInt() ) );
166  }
167 
168  //data defined properties
170 
171  return layer;
172 }
173 
175 {
176  double scaledWidth = mSymbolWidth;
177  double scaledHeight = mSymbolHeight;
178 
179  QColor brushColor = mColor;
180  brushColor.setAlphaF( brushColor.alphaF() * context.opacity() );
181  mBrush.setColor( brushColor );
182 
183  QColor penColor = mStrokeColor;
184  penColor.setAlphaF( penColor.alphaF() * context.opacity() );
185  mPen.setColor( penColor );
186 
187  bool ok;
189  {
190  context.setOriginalValueVariable( mStrokeWidth );
192  if ( !exprVal.isNull() )
193  {
194  double width = exprVal.toDouble( &ok );
195  if ( ok )
196  {
197  width = context.renderContext().convertToPainterUnits( width, mStrokeWidthUnit, mStrokeWidthMapUnitScale );
198  mPen.setWidthF( width );
199  mSelPen.setWidthF( width );
200  }
201  }
202  }
203 
205  {
208  if ( !exprVal.isNull() )
209  {
210  mPen.setStyle( QgsSymbolLayerUtils::decodePenStyle( exprVal.toString() ) );
211  mSelPen.setStyle( mPen.style() );
212  }
213  }
214 
216  {
219  if ( !exprVal.isNull() )
220  {
221  mPen.setJoinStyle( QgsSymbolLayerUtils::decodePenJoinStyle( exprVal.toString() ) );
222  mSelPen.setJoinStyle( mPen.joinStyle() );
223  }
224  }
225 
227  {
229  const QString style = mDataDefinedProperties.valueAsString( QgsSymbolLayer::PropertyCapStyle, context.renderContext().expressionContext(), QString(), &ok );
230  if ( ok )
231  {
232  mPen.setCapStyle( QgsSymbolLayerUtils::decodePenCapStyle( style ) );
233  mSelPen.setCapStyle( QgsSymbolLayerUtils::decodePenCapStyle( style ) );
234  }
235  }
236 
238  {
241  brushColor.setAlphaF( brushColor.alphaF() * context.opacity() );
242  mBrush.setColor( brushColor );
243  }
244 
246  {
249  penColor.setAlphaF( penColor.alphaF() * context.opacity() );
250  mPen.setColor( penColor );
251  }
252 
255  {
258  if ( !exprVal.isNull() )
259  {
260  shape = decodeShape( exprVal.toString() );
261  }
262  preparePath( shape, context, &scaledWidth, &scaledHeight, context.feature() );
263  }
264 
265  //offset and rotation
266  bool hasDataDefinedRotation = false;
267  QPointF offset;
268  double angle = 0;
269  calculateOffsetAndRotation( context, scaledWidth, scaledHeight, hasDataDefinedRotation, offset, angle );
270 
271  QPainter *p = context.renderContext().painter();
272  if ( !p )
273  {
274  return;
275  }
276 
277  QTransform transform;
278  transform.translate( point.x() + offset.x(), point.y() + offset.y() );
279  if ( !qgsDoubleNear( angle, 0.0 ) )
280  {
281  transform.rotate( angle );
282  }
283 
284  if ( shapeIsFilled( shape ) )
285  {
286  p->setPen( context.selected() ? mSelPen : mPen );
287  p->setBrush( context.selected() ? mSelBrush : mBrush );
288  }
289  else
290  {
291  p->setPen( context.selected() ? mSelPen : mPen );
292  p->setBrush( QBrush() );
293  }
294  p->drawPath( transform.map( mPainterPath ) );
295 }
296 
297 
298 void QgsEllipseSymbolLayer::calculateOffsetAndRotation( QgsSymbolRenderContext &context,
299  double scaledWidth,
300  double scaledHeight,
301  bool &hasDataDefinedRotation,
302  QPointF &offset,
303  double &angle ) const
304 {
305  double offsetX = 0;
306  double offsetY = 0;
307  markerOffset( context, scaledWidth, scaledHeight, mSymbolWidthUnit, mSymbolHeightUnit, offsetX, offsetY, mSymbolWidthMapUnitScale, mSymbolHeightMapUnitScale );
308  offset = QPointF( offsetX, offsetY );
309 
310 //priority for rotation: 1. data defined symbol level, 2. symbol layer rotation (mAngle)
311  const bool ok = true;
312  angle = mAngle + mLineAngle;
313  bool usingDataDefinedRotation = false;
315  {
316  context.setOriginalValueVariable( angle );
318  usingDataDefinedRotation = ok;
319  }
320 
321  hasDataDefinedRotation = context.renderHints() & Qgis::SymbolRenderHint::DynamicRotation || usingDataDefinedRotation;
322  if ( hasDataDefinedRotation )
323  {
324  // For non-point markers, "dataDefinedRotation" means following the
325  // shape (shape-data defined). For them, "field-data defined" does
326  // not work at all. TODO: if "field-data defined" ever gets implemented
327  // we'll need a way to distinguish here between the two, possibly
328  // using another flag in renderHints()
329  const QgsFeature *f = context.feature();
330  if ( f )
331  {
332  const QgsGeometry g = f->geometry();
333  if ( !g.isNull() && g.type() == QgsWkbTypes::PointGeometry )
334  {
335  const QgsMapToPixel &m2p = context.renderContext().mapToPixel();
336  angle += m2p.mapRotation();
337  }
338  }
339  }
340 
341  if ( angle )
343 }
344 
346 {
347  return QStringLiteral( "EllipseMarker" );
348 }
349 
351 {
352  QgsMarkerSymbolLayer::startRender( context ); // get anchor point expressions
353  if ( !context.feature() || !dataDefinedProperties().hasActiveProperties() )
354  {
355  preparePath( mShape, context );
356  }
357  mPen.setColor( mStrokeColor );
358  mPen.setStyle( mStrokeStyle );
359  mPen.setJoinStyle( mPenJoinStyle );
360  mPen.setCapStyle( mPenCapStyle );
361  mPen.setWidthF( context.renderContext().convertToPainterUnits( mStrokeWidth, mStrokeWidthUnit, mStrokeWidthMapUnitScale ) );
362  mBrush.setColor( mColor );
363 
364  QColor selBrushColor = context.renderContext().selectionColor();
365  QColor selPenColor = selBrushColor == mColor ? selBrushColor : mStrokeColor;
366  if ( context.opacity() < 1 && !SELECTION_IS_OPAQUE )
367  {
368  selBrushColor.setAlphaF( context.opacity() );
369  selPenColor.setAlphaF( context.opacity() );
370  }
371  mSelBrush = QBrush( selBrushColor );
372  mSelPen = QPen( !shapeIsFilled( mShape ) ? selBrushColor : selPenColor );
373  mSelPen.setStyle( mStrokeStyle );
374  mSelPen.setWidthF( context.renderContext().convertToPainterUnits( mStrokeWidth, mStrokeWidthUnit, mStrokeWidthMapUnitScale ) );
375 }
376 
378 {
379 }
380 
382 {
384  m->setShape( mShape );
385  m->setSymbolWidth( mSymbolWidth );
386  m->setSymbolHeight( mSymbolHeight );
387  m->setStrokeStyle( mStrokeStyle );
388  m->setOffset( mOffset );
391  m->setStrokeStyle( mStrokeStyle );
392  m->setPenJoinStyle( mPenJoinStyle );
393  m->setPenCapStyle( mPenCapStyle );
394  m->setStrokeWidth( mStrokeWidth );
395  m->setColor( color() );
396  m->setStrokeColor( mStrokeColor );
397  m->setSymbolWidthUnit( mSymbolWidthUnit );
398  m->setSymbolWidthMapUnitScale( mSymbolWidthMapUnitScale );
399  m->setSymbolHeightUnit( mSymbolHeightUnit );
400  m->setSymbolHeightMapUnitScale( mSymbolHeightMapUnitScale );
401  m->setStrokeWidthUnit( mStrokeWidthUnit );
402  m->setStrokeWidthMapUnitScale( mStrokeWidthMapUnitScale );
403  m->setAngle( mAngle );
406 
408  copyPaintEffect( m );
409  return m;
410 }
411 
412 void QgsEllipseSymbolLayer::toSld( QDomDocument &doc, QDomElement &element, const QVariantMap &props ) const
413 {
414  QDomElement symbolizerElem = doc.createElement( QStringLiteral( "se:PointSymbolizer" ) );
415  if ( !props.value( QStringLiteral( "uom" ), QString() ).toString().isEmpty() )
416  symbolizerElem.setAttribute( QStringLiteral( "uom" ), props.value( QStringLiteral( "uom" ), QString() ).toString() );
417  element.appendChild( symbolizerElem );
418 
419  // <Geometry>
420  QgsSymbolLayerUtils::createGeometryElement( doc, symbolizerElem, props.value( QStringLiteral( "geom" ), QString() ).toString() );
421 
422  writeSldMarker( doc, symbolizerElem, props );
423 }
424 
425 void QgsEllipseSymbolLayer::writeSldMarker( QDomDocument &doc, QDomElement &element, const QVariantMap &props ) const
426 {
427  // <Graphic>
428  QDomElement graphicElem = doc.createElement( QStringLiteral( "se:Graphic" ) );
429  element.appendChild( graphicElem );
430 
431  const double strokeWidth = QgsSymbolLayerUtils::rescaleUom( mStrokeWidth, mStrokeWidthUnit, props );
432  const double symbolWidth = QgsSymbolLayerUtils::rescaleUom( mSymbolWidth, mSymbolWidthUnit, props );
433  QgsSymbolLayerUtils::wellKnownMarkerToSld( doc, graphicElem, encodeShape( mShape ), mColor, mStrokeColor, mStrokeStyle, strokeWidth, symbolWidth );
434 
435  // <Rotation>
437 
438  QString angleFunc = props.value( QStringLiteral( "angle" ), QString() ).toString();
439  if ( angleFunc.isEmpty() ) // symbol has no angle set
440  {
441  if ( ddRotation && ddRotation.isActive() )
442  {
443  angleFunc = ddRotation.asExpression();
444  }
445  else if ( !qgsDoubleNear( mAngle, 0.0 ) )
446  angleFunc = QString::number( mAngle );
447  }
448  else if ( ddRotation && ddRotation.isActive() )
449  {
450  // the symbol has an angle and the symbol layer have a rotation
451  // property set
452  angleFunc = QStringLiteral( "%1 + %2" ).arg( angleFunc, ddRotation.asExpression() );
453  }
454  else if ( !qgsDoubleNear( mAngle, 0.0 ) )
455  {
456  // both the symbol and the symbol layer have angle value set
457  bool ok;
458  const double angle = angleFunc.toDouble( &ok );
459  if ( !ok )
460  {
461  // its a string (probably a property name or a function)
462  angleFunc = QStringLiteral( "%1 + %2" ).arg( angleFunc ).arg( mAngle );
463  }
464  else if ( !qgsDoubleNear( angle + mAngle, 0.0 ) )
465  {
466  // it's a double value
467  angleFunc = QString::number( angle + mAngle );
468  }
469  }
470  QgsSymbolLayerUtils::createRotationElement( doc, graphicElem, angleFunc );
471 
472  // <Displacement>
473  const QPointF offset = QgsSymbolLayerUtils::rescaleUom( mOffset, mOffsetUnit, props );
475 
476  // store w/h factor in a <VendorOption>
477  const double widthHeightFactor = mSymbolWidth / mSymbolHeight;
478  const QDomElement factorElem = QgsSymbolLayerUtils::createVendorOptionElement( doc, QStringLiteral( "widthHeightFactor" ), QString::number( widthHeightFactor ) );
479  graphicElem.appendChild( factorElem );
480 }
481 
483 {
484  QgsDebugMsgLevel( QStringLiteral( "Entered." ), 4 );
485 
486  QDomElement graphicElem = element.firstChildElement( QStringLiteral( "Graphic" ) );
487  if ( graphicElem.isNull() )
488  return nullptr;
489 
490  QString name = QStringLiteral( "circle" );
491  QColor fillColor, strokeColor;
492  double strokeWidth, size;
493  double widthHeightFactor = 1.0;
494  Qt::PenStyle strokeStyle;
495 
496  QgsStringMap vendorOptions = QgsSymbolLayerUtils::getVendorOptionList( graphicElem );
497  for ( QgsStringMap::iterator it = vendorOptions.begin(); it != vendorOptions.end(); ++it )
498  {
499  if ( it.key() == QLatin1String( "widthHeightFactor" ) )
500  {
501  bool ok;
502  const double v = it.value().toDouble( &ok );
503  if ( ok && !qgsDoubleNear( v, 0.0 ) && v > 0 )
504  widthHeightFactor = v;
505  }
506  }
507 
509  return nullptr;
510 
511  const QString uom = element.attribute( QStringLiteral( "uom" ) );
514 
515  double angle = 0.0;
516  QString angleFunc;
517  if ( QgsSymbolLayerUtils::rotationFromSldElement( graphicElem, angleFunc ) )
518  {
519  bool ok;
520  const double d = angleFunc.toDouble( &ok );
521  if ( ok )
522  angle = d;
523  }
524 
526  m->setOutputUnit( QgsUnitTypes::RenderUnit::RenderPixels );
527  m->setShape( decodeShape( name ) );
528  m->setFillColor( fillColor );
532  m->setSymbolWidth( size );
533  m->setSymbolHeight( size / widthHeightFactor );
534  m->setAngle( angle );
535  return m;
536 }
537 
539 {
540  QVariantMap map;
541  map[QStringLiteral( "symbol_name" )] = encodeShape( mShape );
542  map[QStringLiteral( "symbol_width" )] = QString::number( mSymbolWidth );
543  map[QStringLiteral( "symbol_width_unit" )] = QgsUnitTypes::encodeUnit( mSymbolWidthUnit );
544  map[QStringLiteral( "symbol_width_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mSymbolWidthMapUnitScale );
545  map[QStringLiteral( "symbol_height" )] = QString::number( mSymbolHeight );
546  map[QStringLiteral( "symbol_height_unit" )] = QgsUnitTypes::encodeUnit( mSymbolHeightUnit );
547  map[QStringLiteral( "symbol_height_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mSymbolHeightMapUnitScale );
548  map[QStringLiteral( "angle" )] = QString::number( mAngle );
549  map[QStringLiteral( "outline_style" )] = QgsSymbolLayerUtils::encodePenStyle( mStrokeStyle );
550  map[QStringLiteral( "outline_width" )] = QString::number( mStrokeWidth );
551  map[QStringLiteral( "outline_width_unit" )] = QgsUnitTypes::encodeUnit( mStrokeWidthUnit );
552  map[QStringLiteral( "outline_width_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mStrokeWidthMapUnitScale );
553  map[QStringLiteral( "joinstyle" )] = QgsSymbolLayerUtils::encodePenJoinStyle( mPenJoinStyle );
554  map[QStringLiteral( "cap_style" )] = QgsSymbolLayerUtils::encodePenCapStyle( mPenCapStyle );
555  map[QStringLiteral( "color" )] = QgsSymbolLayerUtils::encodeColor( mColor );
556  map[QStringLiteral( "outline_color" )] = QgsSymbolLayerUtils::encodeColor( mStrokeColor );
557  map[QStringLiteral( "offset" )] = QgsSymbolLayerUtils::encodePoint( mOffset );
558  map[QStringLiteral( "offset_unit" )] = QgsUnitTypes::encodeUnit( mOffsetUnit );
559  map[QStringLiteral( "offset_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mOffsetMapUnitScale );
560  map[QStringLiteral( "size" )] = QString::number( mSize );
561  map[QStringLiteral( "size_unit" )] = QgsUnitTypes::encodeUnit( mSizeUnit );
562  map[QStringLiteral( "size_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mSizeMapUnitScale );
563  map[QStringLiteral( "horizontal_anchor_point" )] = QString::number( mHorizontalAnchorPoint );
564  map[QStringLiteral( "vertical_anchor_point" )] = QString::number( mVerticalAnchorPoint );
565  return map;
566 }
567 
568 QSizeF QgsEllipseSymbolLayer::calculateSize( QgsSymbolRenderContext &context, double *scaledWidth, double *scaledHeight )
569 {
570  double width = 0;
571 
572  if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyWidth ) ) //1. priority: data defined setting on symbol layer le
573  {
574  context.setOriginalValueVariable( mSymbolWidth );
576  }
577  else //2. priority: global width setting
578  {
579  width = mSymbolWidth;
580  }
581  if ( scaledWidth )
582  {
583  *scaledWidth = width;
584  }
585  width = context.renderContext().convertToPainterUnits( width, mSymbolWidthUnit, mSymbolHeightMapUnitScale );
586 
587  double height = 0;
588  if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyHeight ) ) //1. priority: data defined setting on symbol layer level
589  {
590  context.setOriginalValueVariable( mSymbolHeight );
592  }
593  else //2. priority: global height setting
594  {
595  height = mSymbolHeight;
596  }
597  if ( scaledHeight )
598  {
599  *scaledHeight = height;
600  }
601  height = context.renderContext().convertToPainterUnits( height, mSymbolHeightUnit, mSymbolHeightMapUnitScale );
602  return QSizeF( width, height );
603 }
604 
605 void QgsEllipseSymbolLayer::preparePath( const QgsEllipseSymbolLayer::Shape &shape, QgsSymbolRenderContext &context, double *scaledWidth, double *scaledHeight, const QgsFeature * )
606 {
607  mPainterPath = QPainterPath();
608 
609  const QSizeF size = calculateSize( context, scaledWidth, scaledHeight );
610 
611  switch ( shape )
612  {
613  case Circle:
614  mPainterPath.addEllipse( QRectF( -size.width() / 2.0, -size.height() / 2.0, size.width(), size.height() ) );
615  return;
616 
617  case SemiCircle:
618  mPainterPath.arcTo( -size.width() / 2.0, -size.height() / 2.0, size.width(), size.height(), 0, 180 );
619  mPainterPath.lineTo( 0, 0 );
620  return;
621 
622  case Rectangle:
623  mPainterPath.addRect( QRectF( -size.width() / 2.0, -size.height() / 2.0, size.width(), size.height() ) );
624  return;
625 
626  case Diamond:
627  mPainterPath.moveTo( -size.width() / 2.0, 0 );
628  mPainterPath.lineTo( 0, size.height() / 2.0 );
629  mPainterPath.lineTo( size.width() / 2.0, 0 );
630  mPainterPath.lineTo( 0, -size.height() / 2.0 );
631  mPainterPath.lineTo( -size.width() / 2.0, 0 );
632  return;
633 
634  case Cross:
635  mPainterPath.moveTo( 0, -size.height() / 2.0 );
636  mPainterPath.lineTo( 0, size.height() / 2.0 );
637  mPainterPath.moveTo( -size.width() / 2.0, 0 );
638  mPainterPath.lineTo( size.width() / 2.0, 0 );
639  return;
640 
641  case Arrow:
642  mPainterPath.moveTo( -size.width() / 2.0, size.height() / 2.0 );
643  mPainterPath.lineTo( 0, -size.height() / 2.0 );
644  mPainterPath.lineTo( size.width() / 2.0, size.height() / 2.0 );
645  return;
646 
647  case HalfArc:
648  mPainterPath.moveTo( size.width() / 2.0, 0 );
649  mPainterPath.arcTo( -size.width() / 2.0, -size.height() / 2.0, size.width(), size.height(), 0, 180 );
650  return;
651 
652  case Triangle:
653  mPainterPath.moveTo( 0, -size.height() / 2.0 );
654  mPainterPath.lineTo( -size.width() / 2.0, size.height() / 2.0 );
655  mPainterPath.lineTo( size.width() / 2.0, size.height() / 2.0 );
656  mPainterPath.lineTo( 0, -size.height() / 2.0 );
657  return;
658 
659  case LeftHalfTriangle:
660  mPainterPath.moveTo( 0, size.height() / 2.0 );
661  mPainterPath.lineTo( size.width() / 2.0, size.height() / 2.0 );
662  mPainterPath.lineTo( 0, -size.height() / 2.0 );
663  mPainterPath.lineTo( 0, size.height() / 2.0 );
664  return;
665 
666  case RightHalfTriangle:
667  mPainterPath.moveTo( -size.width() / 2.0, size.height() / 2.0 );
668  mPainterPath.lineTo( 0, size.height() / 2.0 );
669  mPainterPath.lineTo( 0, -size.height() / 2.0 );
670  mPainterPath.lineTo( -size.width() / 2.0, size.height() / 2.0 );
671  return;
672  }
673 }
674 
676 {
677  switch ( shape )
678  {
679  case Circle:
680  case Rectangle:
681  case Diamond:
682  case Triangle:
683  case RightHalfTriangle:
684  case LeftHalfTriangle:
685  case SemiCircle:
686  return true;
687 
688  case Cross:
689  case Arrow:
690  case HalfArc:
691  return false;
692  }
693 
694  return true;
695 }
696 
698 {
699  if ( mSymbolWidth >= mSymbolHeight )
700  {
701  mSymbolHeight = mSymbolHeight * size / mSymbolWidth;
702  mSymbolWidth = size;
703  }
704  else
705  {
706  mSymbolWidth = mSymbolWidth * size / mSymbolHeight;
707  mSymbolHeight = size;
708  }
710 }
711 
713 {
714  mSymbolWidth = w;
715  QgsMarkerSymbolLayer::setSize( mSymbolWidth >= mSymbolHeight ? mSymbolWidth : mSymbolHeight );
716 }
717 
719 {
720  mSymbolHeight = h;
721  QgsMarkerSymbolLayer::setSize( mSymbolWidth >= mSymbolHeight ? mSymbolWidth : mSymbolHeight );
722 }
723 
725 {
727  mSymbolWidthUnit = unit;
728  mSymbolHeightUnit = unit;
729  mStrokeWidthUnit = unit;
730 }
731 
733 {
735  if ( mSymbolWidthUnit != unit || mSymbolHeightUnit != unit || mStrokeWidthUnit != unit )
736  {
738  }
739  return unit;
740 }
741 
743 {
744  return mSymbolWidthUnit == QgsUnitTypes::RenderMapUnits || mSymbolWidthUnit == QgsUnitTypes::RenderMetersInMapUnits
745  || mSymbolHeightUnit == QgsUnitTypes::RenderMapUnits || mSymbolHeightUnit == QgsUnitTypes::RenderMetersInMapUnits
746  || mStrokeWidthUnit == QgsUnitTypes::RenderMapUnits || mStrokeWidthUnit == QgsUnitTypes::RenderMetersInMapUnits
748 }
749 
751 {
753  mSymbolWidthMapUnitScale = scale;
754  mSymbolHeightMapUnitScale = scale;
755  mStrokeWidthMapUnitScale = scale;
756 }
757 
759 {
760  if ( QgsMarkerSymbolLayer::mapUnitScale() == mSymbolWidthMapUnitScale &&
761  mSymbolWidthMapUnitScale == mSymbolHeightMapUnitScale &&
762  mSymbolHeightMapUnitScale == mStrokeWidthMapUnitScale )
763  {
764  return mSymbolWidthMapUnitScale;
765  }
766  return QgsMapUnitScale();
767 }
768 
769 QRectF QgsEllipseSymbolLayer::bounds( QPointF point, QgsSymbolRenderContext &context )
770 {
771  const QSizeF size = calculateSize( context );
772 
773  bool hasDataDefinedRotation = false;
774  QPointF offset;
775  double angle = 0;
776  calculateOffsetAndRotation( context, size.width(), size.height(), hasDataDefinedRotation, offset, angle );
777 
778  QTransform transform;
779 
780  // move to the desired position
781  transform.translate( point.x() + offset.x(), point.y() + offset.y() );
782 
783  if ( !qgsDoubleNear( angle, 0.0 ) )
784  transform.rotate( angle );
785 
786  double penWidth = mStrokeWidth;
788  {
789  context.setOriginalValueVariable( mStrokeWidth );
791 
792  if ( !exprVal.isNull() )
793  {
794  bool ok;
795  const double strokeWidth = exprVal.toDouble( &ok );
796  if ( ok )
797  {
798  penWidth = strokeWidth;
799  }
800  }
801  }
802  penWidth = context.renderContext().convertToPainterUnits( penWidth, mStrokeWidthUnit, mStrokeWidthMapUnitScale );
803 
805  {
808  if ( !exprVal.isNull() && exprVal.toString() == QLatin1String( "no" ) )
809  {
810  penWidth = 0.0;
811  }
812  }
813  else if ( mStrokeStyle == Qt::NoPen )
814  penWidth = 0;
815 
816  //antialiasing, add 1 pixel
817  penWidth += 1;
818 
819  QRectF symbolBounds = transform.mapRect( QRectF( -size.width() / 2.0,
820  -size.height() / 2.0,
821  size.width(),
822  size.height() ) );
823 
824  //extend bounds by pen width / 2.0
825  symbolBounds.adjust( -penWidth / 2.0, -penWidth / 2.0,
826  penWidth / 2.0, penWidth / 2.0 );
827 
828  return symbolBounds;
829 }
830 
831 bool QgsEllipseSymbolLayer::writeDxf( QgsDxfExport &e, double mmMapUnitScaleFactor, const QString &layerName, QgsSymbolRenderContext &context, QPointF shift ) const
832 {
833  //width
834  double symbolWidth = mSymbolWidth;
835 
836  if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyWidth ) ) //1. priority: data defined setting on symbol layer le
837  {
838  context.setOriginalValueVariable( mSymbolWidth );
840  }
841  if ( mSymbolWidthUnit == QgsUnitTypes::RenderMillimeters )
842  {
843  symbolWidth *= mmMapUnitScaleFactor;
844  }
845 
846  //height
847  double symbolHeight = mSymbolHeight;
848  if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyHeight ) ) //1. priority: data defined setting on symbol layer level
849  {
850  context.setOriginalValueVariable( mSymbolHeight );
852  }
853  if ( mSymbolHeightUnit == QgsUnitTypes::RenderMillimeters )
854  {
855  symbolHeight *= mmMapUnitScaleFactor;
856  }
857 
858  //stroke width
859  double strokeWidth = mStrokeWidth;
860 
862  {
863  context.setOriginalValueVariable( mStrokeWidth );
865  }
866  if ( mStrokeWidthUnit == QgsUnitTypes::RenderMillimeters )
867  {
869  }
870 
871  //fill color
872  QColor fc = mColor;
874  {
877  }
878 
879  //stroke color
880  QColor oc = mStrokeColor;
882  {
885  }
886 
887  //symbol name
890  {
893  }
894 
895  //offset
896  double offsetX = 0;
897  double offsetY = 0;
898  markerOffset( context, offsetX, offsetY );
899  QPointF off( offsetX, offsetY );
900 
901  //priority for rotation: 1. data defined symbol level, 2. symbol layer rotation (mAngle)
902  double rotation = 0.0;
904  {
905  context.setOriginalValueVariable( mAngle );
907  }
908  else if ( !qgsDoubleNear( mAngle + mLineAngle, 0.0 ) )
909  {
910  rotation = mAngle + mLineAngle;
911  }
912  rotation = -rotation; //rotation in Qt is counterclockwise
913  if ( rotation )
914  off = _rotatedOffset( off, rotation );
915 
916  QTransform t;
917  t.translate( shift.x() + offsetX, shift.y() + offsetY );
918 
919  if ( !qgsDoubleNear( rotation, 0.0 ) )
920  t.rotate( rotation );
921 
922  const double halfWidth = symbolWidth / 2.0;
923  const double halfHeight = symbolHeight / 2.0;
924 
925  switch ( shape )
926  {
927  case Circle:
928  {
929  if ( qgsDoubleNear( halfWidth, halfHeight ) )
930  {
931  const QgsPoint pt( t.map( QPointF( 0, 0 ) ) );
932  e.writeFilledCircle( layerName, oc, pt, halfWidth );
933  }
934  else
935  {
936  QgsPointSequence line;
937 
938  const double stepsize = 2 * M_PI / 40;
939  for ( int i = 0; i < 39; ++i )
940  {
941  const double angle = stepsize * i;
942  const double x = halfWidth * std::cos( angle );
943  const double y = halfHeight * std::sin( angle );
944  line << QgsPoint( t.map( QPointF( x, y ) ) );
945  }
946  //close ellipse with first point
947  line << line.at( 0 );
948 
949  if ( mBrush.style() != Qt::NoBrush )
950  e.writePolygon( QgsRingSequence() << line, layerName, QStringLiteral( "SOLID" ), fc );
951  if ( mPen.style() != Qt::NoPen )
952  e.writePolyline( line, layerName, QStringLiteral( "CONTINUOUS" ), oc, strokeWidth );
953  }
954  return true;
955  }
956 
957  case Rectangle:
958  {
960  p << QgsPoint( t.map( QPointF( -halfWidth, -halfHeight ) ) )
961  << QgsPoint( t.map( QPointF( halfWidth, -halfHeight ) ) )
962  << QgsPoint( t.map( QPointF( halfWidth, halfHeight ) ) )
963  << QgsPoint( t.map( QPointF( -halfWidth, halfHeight ) ) );
964  p << p[0];
965 
966  if ( mBrush.style() != Qt::NoBrush )
967  e.writePolygon( QgsRingSequence() << p, layerName, QStringLiteral( "SOLID" ), fc );
968  if ( mPen.style() != Qt::NoPen )
969  e.writePolyline( p, layerName, QStringLiteral( "CONTINUOUS" ), oc, strokeWidth );
970  return true;
971  }
972  case Cross:
973  {
974  if ( mPen.style() != Qt::NoPen )
975  {
977  << QgsPoint( t.map( QPointF( -halfWidth, 0 ) ) )
978  << QgsPoint( t.map( QPointF( halfWidth, 0 ) ) ),
979  layerName, QStringLiteral( "CONTINUOUS" ), oc, strokeWidth );
981  << QgsPoint( t.map( QPointF( 0, halfHeight ) ) )
982  << QgsPoint( t.map( QPointF( 0, -halfHeight ) ) ),
983  layerName, QStringLiteral( "CONTINUOUS" ), oc, strokeWidth );
984  return true;
985  }
986  break;
987  }
988 
989  case Triangle:
990  {
992  p << QgsPoint( t.map( QPointF( -halfWidth, -halfHeight ) ) )
993  << QgsPoint( t.map( QPointF( halfWidth, -halfHeight ) ) )
994  << QgsPoint( t.map( QPointF( 0, halfHeight ) ) );
995  p << p[0];
996  if ( mBrush.style() != Qt::NoBrush )
997  e.writePolygon( QgsRingSequence() << p, layerName, QStringLiteral( "SOLID" ), fc );
998  if ( mPen.style() != Qt::NoPen )
999  e.writePolyline( p, layerName, QStringLiteral( "CONTINUOUS" ), oc, strokeWidth );
1000  return true;
1001  }
1002 
1003  case Diamond:
1004  case Arrow:
1005  case HalfArc:
1006  case RightHalfTriangle:
1007  case LeftHalfTriangle:
1008  case SemiCircle:
1009  return false;
1010  }
1011 
1012  return false;
1013 }
1014 
1016 {
1017  if ( ok )
1018  *ok = true;
1019  const QString cleaned = name.toLower().trimmed();
1020 
1021  if ( cleaned == QLatin1String( "circle" ) )
1022  return Circle;
1023  else if ( cleaned == QLatin1String( "square" ) || cleaned == QLatin1String( "rectangle" ) )
1024  return Rectangle;
1025  else if ( cleaned == QLatin1String( "diamond" ) )
1026  return Diamond;
1027  else if ( cleaned == QLatin1String( "cross" ) )
1028  return Cross;
1029  else if ( cleaned == QLatin1String( "arrow" ) )
1030  return Arrow;
1031  else if ( cleaned == QLatin1String( "half_arc" ) )
1032  return HalfArc;
1033  else if ( cleaned == QLatin1String( "triangle" ) )
1034  return Triangle;
1035  else if ( cleaned == QLatin1String( "right_half_triangle" ) )
1036  return RightHalfTriangle;
1037  else if ( cleaned == QLatin1String( "left_half_triangle" ) )
1038  return LeftHalfTriangle;
1039  else if ( cleaned == QLatin1String( "semi_circle" ) )
1040  return SemiCircle;
1041 
1042  if ( ok )
1043  *ok = false;
1044  return Circle;
1045 }
1046 
1048 {
1049  switch ( shape )
1050  {
1051  case Circle:
1052  return QStringLiteral( "circle" );
1053  case Rectangle:
1054  return QStringLiteral( "rectangle" );
1055  case Diamond:
1056  return QStringLiteral( "diamond" );
1057  case Cross:
1058  return QStringLiteral( "cross" );
1059  case Arrow:
1060  return QStringLiteral( "arrow" );
1061  case HalfArc:
1062  return QStringLiteral( "half_arc" );
1063  case Triangle:
1064  return QStringLiteral( "triangle" );
1065  case RightHalfTriangle:
1066  return QStringLiteral( "right_half_triangle" );
1067  case LeftHalfTriangle:
1068  return QStringLiteral( "left_half_triangle" );
1069  case SemiCircle:
1070  return QStringLiteral( "semi_circle" );
1071  }
1072  return QString();
1073 }
1074 
1075 QList<QgsEllipseSymbolLayer::Shape> QgsEllipseSymbolLayer::availableShapes()
1076 {
1077  QList< Shape > shapes;
1078  shapes << Circle
1079  << Rectangle
1080  << Diamond
1081  << Cross
1082  << Arrow
1083  << HalfArc
1084  << Triangle
1085  << LeftHalfTriangle
1087  << SemiCircle;
1088  return shapes;
1089 }
@ DynamicRotation
Rotation of symbol may be changed during rendering and symbol should not be cached.
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.
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.
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.
Exports QGIS layers to the DXF format.
Definition: qgsdxfexport.h:64
void writeFilledCircle(const QString &layer, const QColor &color, const QgsPoint &pt, double radius)
Write filled circle (as hatch)
void writePolygon(const QgsRingSequence &polygon, const QString &layer, const QString &hatchPattern, const QColor &color)
Draw dxf filled polygon (HATCH)
void writePolyline(const QgsPointSequence &line, const QString &layer, const QString &lineStyleName, const QColor &color, double width=-1)
Draw dxf primitives (LWPOLYLINE)
A symbol layer for rendering objects with major and minor axis (e.g.
void setPenCapStyle(Qt::PenCapStyle style)
Sets the marker's stroke cap style (e.g., flat, round, etc).
bool writeDxf(QgsDxfExport &e, double mmMapUnitScaleFactor, const QString &layerName, QgsSymbolRenderContext &context, QPointF shift=QPointF(0.0, 0.0)) const override
write as DXF
void setSymbolHeightMapUnitScale(const QgsMapUnitScale &scale)
void setSymbolWidthMapUnitScale(const QgsMapUnitScale &scale)
QVariantMap properties() const override
Should be reimplemented by subclasses to return a string map that contains the configuration informat...
QRectF bounds(QPointF point, QgsSymbolRenderContext &context) override
Returns the approximate bounding box of the marker symbol layer, taking into account any data defined...
void renderPoint(QPointF point, QgsSymbolRenderContext &context) override
Renders a marker at the specified point.
void toSld(QDomDocument &doc, QDomElement &element, const QVariantMap &props) const override
Saves the symbol layer as SLD.
void setStrokeColor(const QColor &c) override
Set stroke color.
void setStrokeStyle(Qt::PenStyle strokeStyle)
QgsUnitTypes::RenderUnit outputUnit() const override
Returns the units to use for sizes and widths within the symbol layer.
static QgsEllipseSymbolLayer::Shape decodeShape(const QString &name, bool *ok=nullptr)
Attempts to decode a string representation of a shape name to the corresponding shape.
void setSize(double size) override
Sets the symbol size.
QgsMapUnitScale mapUnitScale() const override
Shape
Marker symbol shapes.
@ Cross
Stroke-only cross.
@ HalfArc
Stroke-only half arc (since QGIS 3.20)
@ Arrow
Stroke-only arrow (since QGIS 3.20)
@ RightHalfTriangle
Right half of a triangle.
@ LeftHalfTriangle
Left half of a triangle.
QColor fillColor() const override
Gets fill color.
QgsEllipseSymbolLayer::Shape shape() const
Returns the shape for the rendered ellipse marker symbol.
bool usesMapUnits() const override
Returns true if the symbol layer has any components which use map unit based sizes.
void setFillColor(const QColor &c) override
Set fill color.
void setShape(QgsEllipseSymbolLayer::Shape shape)
Sets the rendered ellipse marker shape.
static QList< QgsEllipseSymbolLayer::Shape > availableShapes()
Returns a list of all available shape types.
Qt::PenStyle strokeStyle() const
static QgsSymbolLayer * create(const QVariantMap &properties=QVariantMap())
Creates the symbol layer.
static QgsSymbolLayer * createFromSld(QDomElement &element)
static QString encodeShape(QgsEllipseSymbolLayer::Shape shape)
Encodes a shape to its string representation.
void setStrokeWidthMapUnitScale(const QgsMapUnitScale &scale)
void stopRender(QgsSymbolRenderContext &context) override
Called after a set of rendering operations has finished on the supplied render context.
QString layerType() const override
Returns a string that represents this layer type.
QColor strokeColor() const override
Gets stroke color.
void setSymbolWidthUnit(QgsUnitTypes::RenderUnit unit)
Sets the units for the symbol's width.
void setPenJoinStyle(Qt::PenJoinStyle style)
Set stroke join style.
static bool shapeIsFilled(const QgsEllipseSymbolLayer::Shape &shape)
Returns true if a shape has a fill.
void startRender(QgsSymbolRenderContext &context) override
Called before a set of rendering operations commences on the supplied render context.
void setStrokeWidthUnit(QgsUnitTypes::RenderUnit unit)
Sets the units for the symbol's stroke width.
~QgsEllipseSymbolLayer() override
void setMapUnitScale(const QgsMapUnitScale &scale) override
void setSymbolHeightUnit(QgsUnitTypes::RenderUnit unit)
Sets the units for the symbol's height.
void writeSldMarker(QDomDocument &doc, QDomElement &element, const QVariantMap &props) const override
Writes the symbol layer definition as a SLD XML element.
QgsEllipseSymbolLayer * clone() const override
Shall be reimplemented by subclasses to create a deep copy of the instance.
void setOutputUnit(QgsUnitTypes::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition: qgsfeature.h:56
QgsGeometry geometry
Definition: qgsfeature.h:67
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:124
Q_GADGET bool isNull
Definition: qgsgeometry.h:126
QgsWkbTypes::GeometryType type
Definition: qgsgeometry.h:127
Perform transforms between map coordinates and device coordinates.
Definition: qgsmaptopixel.h:39
double mapRotation() const
Returns current map rotation in degrees (clockwise)
Struct for storing maximum and minimum scales for measurements in map units.
double mSize
Marker size.
virtual void setSize(double size)
Sets the symbol size.
QPointF offset() const
Returns the marker's offset, which is the horizontal and vertical displacement which the rendered mar...
double mLineAngle
Line rotation angle (see setLineAngle() for details)
HorizontalAnchorPoint
Symbol horizontal anchor points.
void setAngle(double angle)
Sets the rotation angle for the marker.
QgsUnitTypes::RenderUnit mOffsetUnit
Offset units.
void setSizeUnit(QgsUnitTypes::RenderUnit unit)
Sets the units for the symbol's size.
void setVerticalAnchorPoint(VerticalAnchorPoint v)
Sets the vertical anchor point for positioning the symbol.
void setOutputUnit(QgsUnitTypes::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
QPointF mOffset
Marker offset.
void setHorizontalAnchorPoint(HorizontalAnchorPoint h)
Sets the horizontal anchor point for positioning the symbol.
QgsMapUnitScale mapUnitScale() const override
void setOffset(QPointF offset)
Sets the marker's offset, which is the horizontal and vertical displacement which the rendered marker...
void setSizeMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale for the symbol's size.
double size() const
Returns the symbol size.
QgsMapUnitScale mOffsetMapUnitScale
Offset map unit scale.
HorizontalAnchorPoint mHorizontalAnchorPoint
Horizontal anchor point.
static QPointF _rotatedOffset(QPointF offset, double angle)
Adjusts a marker offset to account for rotation.
QgsMapUnitScale mSizeMapUnitScale
Marker size map unit scale.
VerticalAnchorPoint
Symbol vertical anchor points.
void markerOffset(QgsSymbolRenderContext &context, double &offsetX, double &offsetY) const
Calculates the required marker offset, including both the symbol offset and any displacement required...
VerticalAnchorPoint mVerticalAnchorPoint
Vertical anchor point.
QgsUnitTypes::RenderUnit mSizeUnit
Marker size unit.
void setOffsetUnit(QgsUnitTypes::RenderUnit unit)
Sets the units for the symbol's offset.
void setOffsetMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale for the symbol's offset.
double mAngle
Marker rotation angle, in degrees clockwise from north.
QgsUnitTypes::RenderUnit outputUnit() const override
Returns the units to use for sizes and widths within the symbol layer.
void startRender(QgsSymbolRenderContext &context) override
Called before a set of rendering operations commences on the supplied render context.
double angle() const
Returns the rotation angle for the marker, in degrees clockwise from north.
void setMapUnitScale(const QgsMapUnitScale &scale) override
Point geometry type, with support for z-dimension and m-values.
Definition: qgspoint.h:49
QgsProperty property(int key) const override
Returns a matching property from the collection, if one exists.
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.
bool isActive(int key) const override
Returns true if the collection contains an active property with the specified key.
A store for object properties.
Definition: qgsproperty.h:232
QString asExpression() const
Returns an expression string representing the state of the property, or an empty string if the proper...
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...
bool isActive() const
Returns whether the property is currently active.
QPainter * painter()
Returns the destination QPainter for the render operation.
QgsExpressionContext & expressionContext()
Gets the expression context.
const QgsMapToPixel & mapToPixel() const
Returns the context's map to pixel transform, which transforms between map coordinates and device coo...
QColor selectionColor() const
Returns the color to use when rendering selected features.
double convertToPainterUnits(double size, QgsUnitTypes::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale()) const
Converts a size from the specified units to painter units (pixels).
static bool rotationFromSldElement(QDomElement &element, QString &rotationFunc)
static QString encodePenStyle(Qt::PenStyle style)
static Qt::PenJoinStyle decodePenJoinStyle(const QString &str)
static QString encodeMapUnitScale(const QgsMapUnitScale &mapUnitScale)
static QColor decodeColor(const QString &str)
static double rescaleUom(double size, QgsUnitTypes::RenderUnit unit, const QVariantMap &props)
Rescales the given size based on the uomScale found in the props, if any is found,...
static QgsMapUnitScale decodeMapUnitScale(const QString &str)
static Qt::PenCapStyle decodePenCapStyle(const QString &str)
static QString encodePenCapStyle(Qt::PenCapStyle style)
static QDomElement createVendorOptionElement(QDomDocument &doc, const QString &name, const QString &value)
static double sizeInPixelsFromSldUom(const QString &uom, double size)
Returns the size scaled in pixels according to the uom attribute.
static bool wellKnownMarkerFromSld(QDomElement &element, QString &name, QColor &color, QColor &strokeColor, Qt::PenStyle &strokeStyle, double &strokeWidth, double &size)
static void createDisplacementElement(QDomDocument &doc, QDomElement &element, QPointF offset)
static QString encodeColor(const QColor &color)
static void createGeometryElement(QDomDocument &doc, QDomElement &element, const QString &geomFunc)
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)
static Qt::PenStyle decodePenStyle(const QString &str)
static void createRotationElement(QDomDocument &doc, QDomElement &element, const QString &rotationFunc)
static QString encodePoint(QPointF point)
Encodes a QPointF to a string.
static QString encodePenJoinStyle(Qt::PenJoinStyle style)
static QgsStringMap getVendorOptionList(QDomElement &element)
static QPointF decodePoint(const QString &string)
Decodes a QSizeF from a string.
@ PropertyStrokeStyle
Stroke style (eg solid, dashed)
@ PropertyCapStyle
Line cap style.
@ PropertyAngle
Symbol angle.
@ PropertyJoinStyle
Line join style.
@ PropertyStrokeWidth
Stroke width.
@ PropertyFillColor
Fill color.
@ PropertyHeight
Symbol height.
@ PropertyName
Name, eg shape name for simple markers.
@ PropertyStrokeColor
Stroke color.
@ PropertyWidth
Symbol width.
static const bool SELECTION_IS_OPAQUE
Whether styles for selected features ignore symbol alpha.
virtual QColor color() const
The fill color.
void copyDataDefinedProperties(QgsSymbolLayer *destLayer) const
Copies all data defined properties of this layer to another symbol layer.
void restoreOldDataDefinedProperties(const QVariantMap &stringMap)
Restores older data defined properties from string map.
virtual void setColor(const QColor &color)
The fill color.
QgsPropertyCollection & dataDefinedProperties()
Returns a reference to the symbol layer's property collection, used for data defined overrides.
void copyPaintEffect(QgsSymbolLayer *destLayer) const
Copies paint effect of this layer to another symbol layer.
QgsPropertyCollection mDataDefinedProperties
bool selected() const
Returns true if symbols should be rendered using the selected symbol coloring and style.
Qgis::SymbolRenderHints renderHints() const
Returns the rendering hint flags for the symbol.
QgsRenderContext & renderContext()
Returns a reference to the context's render context.
const QgsFeature * feature() const
Returns the current feature being rendered.
void setOriginalValueVariable(const QVariant &value)
Sets the original value variable value for data defined symbology.
qreal opacity() const
Returns the opacity for the symbol.
static Q_INVOKABLE QString encodeUnit(QgsUnitTypes::DistanceUnit unit)
Encodes a distance unit to a string.
static Q_INVOKABLE QgsUnitTypes::RenderUnit decodeRenderUnit(const QString &string, bool *ok=nullptr)
Decodes a render unit from a string.
RenderUnit
Rendering size units.
Definition: qgsunittypes.h:168
@ RenderUnknownUnit
Mixed or unknown units.
Definition: qgsunittypes.h:175
@ RenderMetersInMapUnits
Meters value as Map units.
Definition: qgsunittypes.h:176
@ RenderMillimeters
Millimeters.
Definition: qgsunittypes.h:169
@ RenderMapUnits
Map units.
Definition: qgsunittypes.h:170
double ANALYSIS_EXPORT angle(QgsPoint *p1, QgsPoint *p2, QgsPoint *p3, QgsPoint *p4)
Calculates the angle between two segments (in 2 dimension, z-values are ignored)
Definition: MathUtils.cpp:786
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:1108
QMap< QString, QString > QgsStringMap
Definition: qgis.h:1565
QVector< QgsPointSequence > QgsRingSequence
QVector< QgsPoint > QgsPointSequence
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39