QGIS API Documentation  3.12.1-BucureČ™ti (121cc00ff0)
qgssymbollayer.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgssymbollayer.cpp
3  ---------------------
4  begin : November 2009
5  copyright : (C) 2009 by Martin Dobias
6  email : wonder dot sk at gmail dot com
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 
16 #include "qgssymbollayer.h"
17 #include "qgsclipper.h"
18 #include "qgsexpression.h"
19 #include "qgsrendercontext.h"
20 #include "qgsvectorlayer.h"
21 #include "qgsdxfexport.h"
22 #include "qgsgeometrysimplifier.h"
23 #include "qgspainteffect.h"
24 #include "qgseffectstack.h"
25 #include "qgspainteffectregistry.h"
26 #include "qgsproperty.h"
27 #include "qgsexpressioncontext.h"
28 #include "qgssymbollayerutils.h"
29 #include "qgsapplication.h"
30 
31 #include <QSize>
32 #include <QPainter>
33 #include <QPointF>
34 #include <QPolygonF>
35 
36 QgsPropertiesDefinition QgsSymbolLayer::sPropertyDefinitions;
37 
38 void QgsSymbolLayer::initPropertyDefinitions()
39 {
40  if ( !sPropertyDefinitions.isEmpty() )
41  return;
42 
43  QString origin = QStringLiteral( "symbol" );
44 
45  sPropertyDefinitions = QgsPropertiesDefinition
46  {
47  { QgsSymbolLayer::PropertySize, QgsPropertyDefinition( "size", QObject::tr( "Symbol size" ), QgsPropertyDefinition::Size, origin ) },
48  { QgsSymbolLayer::PropertyAngle, QgsPropertyDefinition( "angle", QObject::tr( "Rotation angle" ), QgsPropertyDefinition::Rotation, origin ) },
49  { QgsSymbolLayer::PropertyName, QgsPropertyDefinition( "name", QObject::tr( "Symbol name" ), QgsPropertyDefinition::String, origin ) },
50  { QgsSymbolLayer::PropertyFillColor, QgsPropertyDefinition( "fillColor", QObject::tr( "Symbol fill color" ), QgsPropertyDefinition::ColorWithAlpha, origin ) },
51  { QgsSymbolLayer::PropertyStrokeColor, QgsPropertyDefinition( "outlineColor", QObject::tr( "Symbol stroke color" ), QgsPropertyDefinition::ColorWithAlpha, origin ) },
52  { QgsSymbolLayer::PropertyStrokeWidth, QgsPropertyDefinition( "outlineWidth", QObject::tr( "Symbol stroke width" ), QgsPropertyDefinition::StrokeWidth, origin ) },
53  { QgsSymbolLayer::PropertyStrokeStyle, QgsPropertyDefinition( "outlineStyle", QObject::tr( "Symbol stroke style" ), QgsPropertyDefinition::LineStyle, origin )},
54  { QgsSymbolLayer::PropertyOffset, QgsPropertyDefinition( "offset", QObject::tr( "Symbol offset" ), QgsPropertyDefinition::Offset, origin )},
55  { QgsSymbolLayer::PropertyCharacter, QgsPropertyDefinition( "char", QObject::tr( "Marker character(s)" ), QgsPropertyDefinition::String, origin )},
56  { QgsSymbolLayer::PropertyWidth, QgsPropertyDefinition( "width", QObject::tr( "Symbol width" ), QgsPropertyDefinition::DoublePositive, origin )},
57  { QgsSymbolLayer::PropertyHeight, QgsPropertyDefinition( "height", QObject::tr( "Symbol height" ), QgsPropertyDefinition::DoublePositive, origin )},
58  { QgsSymbolLayer::PropertyPreserveAspectRatio, QgsPropertyDefinition( "preserveAspectRatio", QObject::tr( "Preserve aspect ratio between width and height" ), QgsPropertyDefinition::Boolean, origin )},
59  { QgsSymbolLayer::PropertyFillStyle, QgsPropertyDefinition( "fillStyle", QObject::tr( "Symbol fill style" ), QgsPropertyDefinition::FillStyle, origin )},
60  { QgsSymbolLayer::PropertyJoinStyle, QgsPropertyDefinition( "joinStyle", QObject::tr( "Outline join style" ), QgsPropertyDefinition::PenJoinStyle, origin )},
61  { QgsSymbolLayer::PropertySecondaryColor, QgsPropertyDefinition( "color2", QObject::tr( "Secondary fill color" ), QgsPropertyDefinition::ColorWithAlpha, origin )},
62  { QgsSymbolLayer::PropertyLineAngle, QgsPropertyDefinition( "lineAngle", QObject::tr( "Angle for line fills" ), QgsPropertyDefinition::Rotation, origin )},
63  { QgsSymbolLayer::PropertyGradientType, QgsPropertyDefinition( "gradientType", QgsPropertyDefinition::DataTypeString, QObject::tr( "Gradient type" ), QObject::tr( "string " ) + QLatin1String( "[<b>linear</b>|<b>radial</b>|<b>conical</b>]" ), origin )},
64  { QgsSymbolLayer::PropertyCoordinateMode, QgsPropertyDefinition( "gradientMode", QgsPropertyDefinition::DataTypeString, QObject::tr( "Gradient mode" ), QObject::tr( "string " ) + QLatin1String( "[<b>feature</b>|<b>viewport</b>]" ), origin )},
65  { QgsSymbolLayer::PropertyGradientSpread, QgsPropertyDefinition( "gradientSpread", QgsPropertyDefinition::DataTypeString, QObject::tr( "Gradient spread" ), QObject::tr( "string " ) + QLatin1String( "[<b>pad</b>|<b>repeat</b>|<b>reflect</b>]" ), origin )},
66  { QgsSymbolLayer::PropertyGradientReference1X, QgsPropertyDefinition( "gradientRef1X", QObject::tr( "Reference point 1 (X)" ), QgsPropertyDefinition::Double0To1, origin )},
67  { QgsSymbolLayer::PropertyGradientReference1Y, QgsPropertyDefinition( "gradientRef1Y", QObject::tr( "Reference point 1 (Y)" ), QgsPropertyDefinition::Double0To1, origin )},
68  { QgsSymbolLayer::PropertyGradientReference2X, QgsPropertyDefinition( "gradientRef2X", QObject::tr( "Reference point 2 (X)" ), QgsPropertyDefinition::Double0To1, origin )},
69  { QgsSymbolLayer::PropertyGradientReference2Y, QgsPropertyDefinition( "gradientRef2Y", QObject::tr( "Reference point 2 (Y)" ), QgsPropertyDefinition::Double0To1, origin )},
70  { QgsSymbolLayer::PropertyGradientReference1IsCentroid, QgsPropertyDefinition( "gradientRef1Centroid", QObject::tr( "Reference point 1 follows feature centroid" ), QgsPropertyDefinition::Boolean, origin )},
71  { QgsSymbolLayer::PropertyGradientReference2IsCentroid, QgsPropertyDefinition( "gradientRef2Centroid", QObject::tr( "Reference point 2 follows feature centroid" ), QgsPropertyDefinition::Boolean, origin )},
72  { QgsSymbolLayer::PropertyBlurRadius, QgsPropertyDefinition( "blurRadius", QgsPropertyDefinition::DataTypeNumeric, QObject::tr( "Blur radius" ), QObject::tr( "Integer between 0 and 18" ), origin )},
73  { QgsSymbolLayer::PropertyLineDistance, QgsPropertyDefinition( "lineDistance", QObject::tr( "Distance between lines" ), QgsPropertyDefinition::DoublePositive, origin )},
74  { QgsSymbolLayer::PropertyShapeburstUseWholeShape, QgsPropertyDefinition( "shapeburstWholeShape", QObject::tr( "Shade whole shape" ), QgsPropertyDefinition::Boolean, origin )},
75  { QgsSymbolLayer::PropertyShapeburstMaxDistance, QgsPropertyDefinition( "shapeburstMaxDist", QObject::tr( "Maximum distance for shapeburst fill" ), QgsPropertyDefinition::DoublePositive, origin )},
76  { QgsSymbolLayer::PropertyShapeburstIgnoreRings, QgsPropertyDefinition( "shapeburstIgnoreRings", QObject::tr( "Ignore rings in feature" ), QgsPropertyDefinition::Boolean, origin )},
77  { QgsSymbolLayer::PropertyFile, QgsPropertyDefinition( "file", QObject::tr( "Symbol file path" ), QgsPropertyDefinition::String, origin )},
78  { QgsSymbolLayer::PropertyDistanceX, QgsPropertyDefinition( "distanceX", QObject::tr( "Horizontal distance between markers" ), QgsPropertyDefinition::DoublePositive, origin )},
79  { QgsSymbolLayer::PropertyDistanceY, QgsPropertyDefinition( "distanceY", QObject::tr( "Vertical distance between markers" ), QgsPropertyDefinition::DoublePositive, origin )},
80  { QgsSymbolLayer::PropertyDisplacementX, QgsPropertyDefinition( "displacementX", QObject::tr( "Horizontal displacement between rows" ), QgsPropertyDefinition::DoublePositive, origin )},
81  { QgsSymbolLayer::PropertyDisplacementY, QgsPropertyDefinition( "displacementY", QObject::tr( "Vertical displacement between columns" ), QgsPropertyDefinition::DoublePositive, origin )},
82  { QgsSymbolLayer::PropertyOpacity, QgsPropertyDefinition( "alpha", QObject::tr( "Opacity" ), QgsPropertyDefinition::Opacity, origin )},
83  { QgsSymbolLayer::PropertyCustomDash, QgsPropertyDefinition( "customDash", QgsPropertyDefinition::DataTypeString, QObject::tr( "Custom dash pattern" ), QObject::tr( "[<b><dash>;<space></b>] e.g. '8;2;1;2'" ), origin )},
84  { QgsSymbolLayer::PropertyCapStyle, QgsPropertyDefinition( "capStyle", QObject::tr( "Line cap style" ), QgsPropertyDefinition::CapStyle, origin )},
85  { QgsSymbolLayer::PropertyPlacement, QgsPropertyDefinition( "placement", QgsPropertyDefinition::DataTypeString, QObject::tr( "Marker placement" ), QObject::tr( "string " ) + "[<b>interval</b>|<b>vertex</b>|<b>lastvertex</b>|<b>firstvertex</b>|<b>centerpoint</b>|<b>curvepoint</b>|<b>segmentcenter</b>]", origin )},
86  { QgsSymbolLayer::PropertyInterval, QgsPropertyDefinition( "interval", QObject::tr( "Marker interval" ), QgsPropertyDefinition::DoublePositive, origin )},
87  { QgsSymbolLayer::PropertyOffsetAlongLine, QgsPropertyDefinition( "offsetAlongLine", QObject::tr( "Offset along line" ), QgsPropertyDefinition::DoublePositive, origin )},
88  { QgsSymbolLayer::PropertyAverageAngleLength, QgsPropertyDefinition( "averageAngleLength", QObject::tr( "Average line angles over" ), QgsPropertyDefinition::DoublePositive, origin )},
89  { QgsSymbolLayer::PropertyHorizontalAnchor, QgsPropertyDefinition( "hAnchor", QObject::tr( "Horizontal anchor point" ), QgsPropertyDefinition::HorizontalAnchor, origin )},
90  { QgsSymbolLayer::PropertyVerticalAnchor, QgsPropertyDefinition( "vAnchor", QObject::tr( "Vertical anchor point" ), QgsPropertyDefinition::VerticalAnchor, origin )},
91  { QgsSymbolLayer::PropertyLayerEnabled, QgsPropertyDefinition( "enabled", QObject::tr( "Layer enabled" ), QgsPropertyDefinition::Boolean, origin )},
92  { QgsSymbolLayer::PropertyArrowWidth, QgsPropertyDefinition( "arrowWidth", QObject::tr( "Arrow line width" ), QgsPropertyDefinition::StrokeWidth, origin )},
93  { QgsSymbolLayer::PropertyArrowStartWidth, QgsPropertyDefinition( "arrowStartWidth", QObject::tr( "Arrow line start width" ), QgsPropertyDefinition::StrokeWidth, origin )},
94  { QgsSymbolLayer::PropertyArrowHeadLength, QgsPropertyDefinition( "arrowHeadLength", QObject::tr( "Arrow head length" ), QgsPropertyDefinition::DoublePositive, origin )},
95  { QgsSymbolLayer::PropertyArrowHeadThickness, QgsPropertyDefinition( "arrowHeadThickness", QObject::tr( "Arrow head thickness" ), QgsPropertyDefinition::DoublePositive, origin )},
96  { QgsSymbolLayer::PropertyArrowHeadType, QgsPropertyDefinition( "arrowHeadType", QgsPropertyDefinition::DataTypeString, QObject::tr( "Arrow head type" ), QObject::tr( "string " ) + QLatin1String( "[<b>single</b>|<b>reversed</b>|<b>double</b>]" ), origin )},
97  { QgsSymbolLayer::PropertyArrowType, QgsPropertyDefinition( "arrowType", QgsPropertyDefinition::DataTypeString, QObject::tr( "Arrow type" ), QObject::tr( "string " ) + QLatin1String( "[<b>plain</b>|<b>lefthalf</b>|<b>righthalf</b>]" ), origin )},
98  { QgsSymbolLayer::PropertyPointCount, QgsPropertyDefinition( "pointCount", QObject::tr( "Point count" ), QgsPropertyDefinition::IntegerPositive, origin )},
99  { QgsSymbolLayer::PropertyRandomSeed, QgsPropertyDefinition( "randomSeed", QgsPropertyDefinition::DataTypeNumeric, QObject::tr( "Random number seed" ), QObject::tr( "integer > 0, or 0 for completely random sequence" ), origin )},
100  { QgsSymbolLayer::PropertyClipPoints, QgsPropertyDefinition( "clipPoints", QObject::tr( "Clip markers" ), QgsPropertyDefinition::Boolean, origin )},
101  { QgsSymbolLayer::PropertyClipPoints, QgsPropertyDefinition( "densityArea", QObject::tr( "Density area" ), QgsPropertyDefinition::DoublePositive, origin )},
102  };
103 }
104 
106 {
107  dataDefinedProperties().setProperty( key, property );
108 }
109 
111 {
112 
113 }
114 
116 {
117 
118 }
119 
120 bool QgsSymbolLayer::writeDxf( QgsDxfExport &e, double mmMapUnitScaleFactor, const QString &layerName, QgsSymbolRenderContext &context, QPointF shift ) const
121 {
122  Q_UNUSED( e )
123  Q_UNUSED( mmMapUnitScaleFactor )
124  Q_UNUSED( layerName )
125  Q_UNUSED( context )
126  Q_UNUSED( shift )
127  return false;
128 }
129 
131 {
132  Q_UNUSED( e )
133  Q_UNUSED( context )
134  return 1.0;
135 }
136 
138 {
139  Q_UNUSED( e )
140  Q_UNUSED( context )
141  return 0.0;
142 }
143 
145 {
146  Q_UNUSED( context )
147  return color();
148 }
149 
151 {
152  Q_UNUSED( context )
153  return 0.0;
154 }
155 
157 {
158  Q_UNUSED( unit )
159  return QVector<qreal>();
160 }
161 
162 Qt::PenStyle QgsSymbolLayer::dxfPenStyle() const
163 {
164  return Qt::SolidLine;
165 }
166 
168 {
169  Q_UNUSED( context )
170  return color();
171 }
172 
173 Qt::BrushStyle QgsSymbolLayer::dxfBrushStyle() const
174 {
175  return Qt::NoBrush;
176 }
177 
179 {
180  return mPaintEffect.get();
181 }
182 
184 {
185  if ( effect == mPaintEffect.get() )
186  return;
187 
188  mPaintEffect.reset( effect );
189 }
190 
192  : mType( type )
193  , mLocked( locked )
194 {
195 }
196 
198 {
200 
201  if ( !context.fields().isEmpty() )
202  {
203  //QgsFields is implicitly shared, so it's cheap to make a copy
204  mFields = context.fields();
205  }
206 }
207 
209 {
211 }
212 
214 {
215  QgsSymbolLayer::initPropertyDefinitions();
216  return sPropertyDefinitions;
217 }
218 
220 
222 {
223  if ( symbol->type() == QgsSymbol::Fill && mType == QgsSymbol::Line )
224  return true;
225 
226  return symbol->type() == mType;
227 }
228 
230 {
232 }
233 
235 {
236  return mRenderingPass;
237 }
238 
239 QSet<QString> QgsSymbolLayer::usedAttributes( const QgsRenderContext &context ) const
240 {
241  QSet<QString> columns = mDataDefinedProperties.referencedFields( context.expressionContext() );
242  return columns;
243 }
244 
245 QgsProperty propertyFromMap( const QgsStringMap &map, const QString &baseName )
246 {
247  QString prefix;
248  if ( !baseName.isEmpty() )
249  {
250  prefix.append( QStringLiteral( "%1_dd_" ).arg( baseName ) );
251  }
252 
253  if ( !map.contains( QStringLiteral( "%1expression" ).arg( prefix ) ) )
254  {
255  //requires at least the expression value
256  return QgsProperty();
257  }
258 
259  bool active = ( map.value( QStringLiteral( "%1active" ).arg( prefix ), QStringLiteral( "1" ) ) != QLatin1String( "0" ) );
260  QString expression = map.value( QStringLiteral( "%1expression" ).arg( prefix ) );
261  bool useExpression = ( map.value( QStringLiteral( "%1useexpr" ).arg( prefix ), QStringLiteral( "1" ) ) != QLatin1String( "0" ) );
262  QString field = map.value( QStringLiteral( "%1field" ).arg( prefix ), QString() );
263 
264  if ( useExpression )
265  return QgsProperty::fromExpression( expression, active );
266  else
267  return QgsProperty::fromField( field, active );
268 }
269 
271 {
272  // property string to type upgrade map
273  static const QMap< QString, QgsSymbolLayer::Property > OLD_PROPS
274  {
276  { "arrow_width", QgsSymbolLayer::PropertyArrowWidth },
277  { "arrow_start_width", QgsSymbolLayer::PropertyArrowStartWidth },
278  { "head_length", QgsSymbolLayer::PropertyArrowHeadLength },
279  { "head_thickness", QgsSymbolLayer::PropertyArrowHeadThickness },
280  { "offset", QgsSymbolLayer::PropertyOffset },
281  { "head_type", QgsSymbolLayer::PropertyArrowHeadType },
282  { "arrow_type", QgsSymbolLayer::PropertyArrowType },
283  { "width_field", QgsSymbolLayer::PropertyWidth },
284  { "height_field", QgsSymbolLayer::PropertyHeight },
285  { "rotation_field", QgsSymbolLayer::PropertyAngle },
286  { "outline_width_field", QgsSymbolLayer::PropertyStrokeWidth },
287  { "fill_color_field", QgsSymbolLayer::PropertyFillColor },
288  { "outline_color_field", QgsSymbolLayer::PropertyStrokeColor },
289  { "symbol_name_field", QgsSymbolLayer::PropertyName },
290  { "outline_width", QgsSymbolLayer::PropertyStrokeWidth },
291  { "outline_style", QgsSymbolLayer::PropertyStrokeStyle },
292  { "join_style", QgsSymbolLayer::PropertyJoinStyle },
293  { "fill_color", QgsSymbolLayer::PropertyFillColor },
294  { "outline_color", QgsSymbolLayer::PropertyStrokeColor },
295  { "width", QgsSymbolLayer::PropertyWidth },
296  { "height", QgsSymbolLayer::PropertyHeight },
297  { "symbol_name", QgsSymbolLayer::PropertyName },
298  { "angle", QgsSymbolLayer::PropertyAngle },
299  { "fill_style", QgsSymbolLayer::PropertyFillStyle },
300  { "color_border", QgsSymbolLayer::PropertyStrokeColor },
301  { "width_border", QgsSymbolLayer::PropertyStrokeWidth },
302  { "border_color", QgsSymbolLayer::PropertyStrokeColor },
303  { "border_style", QgsSymbolLayer::PropertyStrokeStyle },
305  { "gradient_type", QgsSymbolLayer::PropertyGradientType },
306  { "coordinate_mode", QgsSymbolLayer::PropertyCoordinateMode },
312  { "reference1_iscentroid", QgsSymbolLayer::PropertyGradientReference1IsCentroid },
313  { "reference2_iscentroid", QgsSymbolLayer::PropertyGradientReference2IsCentroid },
314  { "blur_radius", QgsSymbolLayer::PropertyBlurRadius },
318  { "svgFillColor", QgsSymbolLayer::PropertyFillColor },
319  { "svgOutlineColor", QgsSymbolLayer::PropertyStrokeColor },
320  { "svgOutlineWidth", QgsSymbolLayer::PropertyStrokeWidth },
321  { "svgFile", QgsSymbolLayer::PropertyFile },
322  { "lineangle", QgsSymbolLayer::PropertyLineAngle },
323  { "distance", QgsSymbolLayer::PropertyLineDistance },
324  { "distance_x", QgsSymbolLayer::PropertyDistanceX },
325  { "distance_y", QgsSymbolLayer::PropertyDistanceY },
326  { "displacement_x", QgsSymbolLayer::PropertyDisplacementX },
327  { "displacement_y", QgsSymbolLayer::PropertyDisplacementY },
328  { "file", QgsSymbolLayer::PropertyFile },
329  { "alpha", QgsSymbolLayer::PropertyOpacity },
330  { "customdash", QgsSymbolLayer::PropertyCustomDash },
331  { "line_style", QgsSymbolLayer::PropertyStrokeStyle },
332  { "joinstyle", QgsSymbolLayer::PropertyJoinStyle },
333  { "capstyle", QgsSymbolLayer::PropertyCapStyle },
334  { "placement", QgsSymbolLayer::PropertyPlacement },
335  { "interval", QgsSymbolLayer::PropertyInterval },
336  { "offset_along_line", QgsSymbolLayer::PropertyOffsetAlongLine },
337  { "name", QgsSymbolLayer::PropertyName },
338  { "size", QgsSymbolLayer::PropertySize },
343  { "rotation", QgsSymbolLayer::PropertyAngle },
344  { "horizontal_anchor_point", QgsSymbolLayer::PropertyHorizontalAnchor },
345  { "vertical_anchor_point", QgsSymbolLayer::PropertyVerticalAnchor },
346  };
347 
348  QgsStringMap::const_iterator propIt = stringMap.constBegin();
349  for ( ; propIt != stringMap.constEnd(); ++propIt )
350  {
351  QgsProperty prop;
352  QString propertyName;
353 
354  if ( propIt.key().endsWith( QLatin1String( "_dd_expression" ) ) )
355  {
356  //found a data defined property
357 
358  //get data defined property name by stripping "_dd_expression" from property key
359  propertyName = propIt.key().left( propIt.key().length() - 14 );
360 
361  prop = propertyFromMap( stringMap, propertyName );
362  }
363  else if ( propIt.key().endsWith( QLatin1String( "_expression" ) ) )
364  {
365  //old style data defined property, upgrade
366 
367  //get data defined property name by stripping "_expression" from property key
368  propertyName = propIt.key().left( propIt.key().length() - 11 );
369 
370  prop = QgsProperty::fromExpression( propIt.value() );
371  }
372 
373  if ( !prop || !OLD_PROPS.contains( propertyName ) )
374  continue;
375 
376  QgsSymbolLayer::Property key = static_cast< QgsSymbolLayer::Property >( OLD_PROPS.value( propertyName ) );
377 
378  if ( type() == QgsSymbol::Line )
379  {
380  //these keys had different meaning for line symbol layers
381  if ( propertyName == QLatin1String( "width" ) )
383  else if ( propertyName == QLatin1String( "color" ) )
385  }
386 
387  setDataDefinedProperty( key, prop );
388  }
389 }
390 
392 {
393  if ( !destLayer )
394  return;
395 
397 }
398 
400 {
401  if ( !destLayer || !mPaintEffect )
402  return;
403 
405  destLayer->setPaintEffect( mPaintEffect->clone() );
406  else
407  destLayer->setPaintEffect( nullptr );
408 }
409 
411  : QgsSymbolLayer( QgsSymbol::Marker, locked )
412 {
413 
414 }
415 
417  : QgsSymbolLayer( QgsSymbol::Line, locked )
418 {
419 }
420 
422 {
423  return mRingFilter;
424 }
425 
427 {
428  mRingFilter = filter;
429 }
430 
432  : QgsSymbolLayer( QgsSymbol::Fill, locked )
433 {
434 }
435 
437 {
438  Q_UNUSED( context )
439 }
440 
442 {
443  Q_UNUSED( context )
444 }
445 
447 {
448  startRender( context );
449  QgsPaintEffect *effect = paintEffect();
450  if ( effect && effect->enabled() )
451  {
452  QgsEffectPainter p( context.renderContext(), effect );
453  renderPoint( QPointF( size.width() / 2, size.height() / 2 ), context );
454  }
455  else
456  {
457  renderPoint( QPointF( size.width() / 2, size.height() / 2 ), context );
458  }
459  stopRender( context );
460 }
461 
462 void QgsMarkerSymbolLayer::markerOffset( QgsSymbolRenderContext &context, double &offsetX, double &offsetY ) const
463 {
464  markerOffset( context, mSize, mSize, mSizeUnit, mSizeUnit, offsetX, offsetY, mSizeMapUnitScale, mSizeMapUnitScale );
465 }
466 
467 void QgsMarkerSymbolLayer::markerOffset( QgsSymbolRenderContext &context, double width, double height, double &offsetX, double &offsetY ) const
468 {
469  markerOffset( context, width, height, mSizeUnit, mSizeUnit, offsetX, offsetY, mSizeMapUnitScale, mSizeMapUnitScale );
470 }
471 
472 void QgsMarkerSymbolLayer::markerOffset( QgsSymbolRenderContext &context, double width, double height,
474  double &offsetX, double &offsetY, const QgsMapUnitScale &widthMapUnitScale, const QgsMapUnitScale &heightMapUnitScale ) const
475 {
476  offsetX = mOffset.x();
477  offsetY = mOffset.y();
478 
480  {
483  bool ok = false;
484  const QPointF offset = QgsSymbolLayerUtils::toPoint( exprVal, &ok );
485  if ( ok )
486  {
487  offsetX = offset.x();
488  offsetY = offset.y();
489  }
490  }
491 
492  offsetX = context.renderContext().convertToPainterUnits( offsetX, mOffsetUnit, mOffsetMapUnitScale );
493  offsetY = context.renderContext().convertToPainterUnits( offsetY, mOffsetUnit, mOffsetMapUnitScale );
494 
495  HorizontalAnchorPoint horizontalAnchorPoint = mHorizontalAnchorPoint;
496  VerticalAnchorPoint verticalAnchorPoint = mVerticalAnchorPoint;
498  {
500  if ( exprVal.isValid() )
501  {
502  horizontalAnchorPoint = decodeHorizontalAnchorPoint( exprVal.toString() );
503  }
504  }
506  {
508  if ( exprVal.isValid() )
509  {
510  verticalAnchorPoint = decodeVerticalAnchorPoint( exprVal.toString() );
511  }
512  }
513 
514  //correct horizontal position according to anchor point
515  if ( horizontalAnchorPoint == HCenter && verticalAnchorPoint == VCenter )
516  {
517  return;
518  }
519 
520  double anchorPointCorrectionX = context.renderContext().convertToPainterUnits( width, widthUnit, widthMapUnitScale ) / 2.0;
521  double anchorPointCorrectionY = context.renderContext().convertToPainterUnits( height, heightUnit, heightMapUnitScale ) / 2.0;
522  if ( horizontalAnchorPoint == Left )
523  {
524  offsetX += anchorPointCorrectionX;
525  }
526  else if ( horizontalAnchorPoint == Right )
527  {
528  offsetX -= anchorPointCorrectionX;
529  }
530 
531  //correct vertical position according to anchor point
532  if ( verticalAnchorPoint == Top )
533  {
534  offsetY += anchorPointCorrectionY;
535  }
536  else if ( verticalAnchorPoint == Bottom )
537  {
538  offsetY -= anchorPointCorrectionY;
539  }
540 }
541 
542 QPointF QgsMarkerSymbolLayer::_rotatedOffset( QPointF offset, double angle )
543 {
544  angle = DEG2RAD( angle );
545  double c = std::cos( angle ), s = std::sin( angle );
546  return QPointF( offset.x() * c - offset.y() * s, offset.x() * s + offset.y() * c );
547 }
548 
549 QgsMarkerSymbolLayer::HorizontalAnchorPoint QgsMarkerSymbolLayer::decodeHorizontalAnchorPoint( const QString &str )
550 {
551  if ( str.compare( QLatin1String( "left" ), Qt::CaseInsensitive ) == 0 )
552  {
554  }
555  else if ( str.compare( QLatin1String( "right" ), Qt::CaseInsensitive ) == 0 )
556  {
558  }
559  else
560  {
562  }
563 }
564 
565 QgsMarkerSymbolLayer::VerticalAnchorPoint QgsMarkerSymbolLayer::decodeVerticalAnchorPoint( const QString &str )
566 {
567  if ( str.compare( QLatin1String( "top" ), Qt::CaseInsensitive ) == 0 )
568  {
570  }
571  else if ( str.compare( QLatin1String( "bottom" ), Qt::CaseInsensitive ) == 0 )
572  {
574  }
575  else
576  {
578  }
579 }
580 
582 {
583  mSizeUnit = unit;
584  mOffsetUnit = unit;
585 }
586 
588 {
589  if ( mOffsetUnit != mSizeUnit )
590  {
592  }
593  return mOffsetUnit;
594 }
595 
597 {
598  mSizeMapUnitScale = scale;
599  mOffsetMapUnitScale = scale;
600 }
601 
603 {
604  if ( mSizeMapUnitScale == mOffsetMapUnitScale )
605  {
606  return mSizeMapUnitScale;
607  }
608  return QgsMapUnitScale();
609 }
610 
612 {
613  mWidthUnit = unit;
614 }
615 
617 {
618  return mWidthUnit;
619 }
620 
622 {
623  mWidthMapUnitScale = scale;
624 }
625 
627 {
628  return mWidthMapUnitScale;
629 }
630 
631 
633 {
634  QPolygonF points;
635  // we're adding 0.5 to get rid of blurred preview:
636  // drawing antialiased lines of width 1 at (x,0)-(x,100) creates 2px line
637  points << QPointF( 0, int( size.height() / 2 ) + 0.5 ) << QPointF( size.width(), int( size.height() / 2 ) + 0.5 );
638 
639  startRender( context );
640  QgsPaintEffect *effect = paintEffect();
641  if ( effect && effect->enabled() )
642  {
643  QgsEffectPainter p( context.renderContext(), effect );
644  renderPolyline( points, context );
645  }
646  else
647  {
648  renderPolyline( points, context );
649  }
650  stopRender( context );
651 }
652 
653 void QgsLineSymbolLayer::renderPolygonStroke( const QPolygonF &points, QList<QPolygonF> *rings, QgsSymbolRenderContext &context )
654 {
655  switch ( mRingFilter )
656  {
657  case AllRings:
658  case ExteriorRingOnly:
659  renderPolyline( points, context );
660  break;
661  case InteriorRingsOnly:
662  break;
663  }
664 
665  if ( rings )
666  {
667  switch ( mRingFilter )
668  {
669  case AllRings:
670  case InteriorRingsOnly:
671  {
672  for ( const QPolygonF &ring : qgis::as_const( *rings ) )
673  renderPolyline( ring, context );
674  }
675  break;
676  case ExteriorRingOnly:
677  break;
678  }
679  }
680 }
681 
682 double QgsLineSymbolLayer::width( const QgsRenderContext &context ) const
683 {
684  return context.convertToPainterUnits( mWidth, mWidthUnit, mWidthMapUnitScale );
685 }
686 
688 {
689  Q_UNUSED( context )
690  return width() * e.mapUnitScaleFactor( e.symbologyScale(), widthUnit(), e.mapUnits(), context.renderContext().mapToPixel().mapUnitsPerPixel() );
691 }
692 
693 
695 {
696  QPolygonF poly = QRectF( QPointF( 0, 0 ), QPointF( size.width(), size.height() ) );
697  startRender( context );
698  QgsPaintEffect *effect = paintEffect();
699  if ( effect && effect->enabled() )
700  {
701  QgsEffectPainter p( context.renderContext(), effect );
702  renderPolygon( poly, nullptr, context );
703  }
704  else
705  {
706  renderPolygon( poly, nullptr, context );
707  }
708  stopRender( context );
709 }
710 
711 void QgsFillSymbolLayer::_renderPolygon( QPainter *p, const QPolygonF &points, const QList<QPolygonF> *rings, QgsSymbolRenderContext &context )
712 {
713  if ( !p )
714  {
715  return;
716  }
717 
718  // Disable 'Antialiasing' if the geometry was generalized in the current RenderContext (We known that it must have least #5 points).
719  if ( points.size() <= 5 &&
722  ( p->renderHints() & QPainter::Antialiasing ) )
723  {
724  p->setRenderHint( QPainter::Antialiasing, false );
725  p->drawRect( points.boundingRect() );
726  p->setRenderHint( QPainter::Antialiasing, true );
727  return;
728  }
729 
730  // polygons outlines are sometimes rendered wrongly with drawPolygon, when
731  // clipped (see #13343), so use drawPath instead.
732  if ( !rings && p->pen().style() == Qt::NoPen )
733  {
734  // simple polygon without holes
735  p->drawPolygon( points );
736  }
737  else
738  {
739  // polygon with holes must be drawn using painter path
740  QPainterPath path;
741  path.addPolygon( points );
742 
743  if ( rings )
744  {
745  QList<QPolygonF>::const_iterator it = rings->constBegin();
746  for ( ; it != rings->constEnd(); ++it )
747  {
748  QPolygonF ring = *it;
749  path.addPolygon( ring );
750  }
751  }
752 
753  p->drawPath( path );
754  }
755 }
756 
757 void QgsMarkerSymbolLayer::toSld( QDomDocument &doc, QDomElement &element, const QgsStringMap &props ) const
758 {
759  QDomElement symbolizerElem = doc.createElement( QStringLiteral( "se:PointSymbolizer" ) );
760  if ( !props.value( QStringLiteral( "uom" ), QString() ).isEmpty() )
761  symbolizerElem.setAttribute( QStringLiteral( "uom" ), props.value( QStringLiteral( "uom" ), QString() ) );
762  element.appendChild( symbolizerElem );
763 
764  // <Geometry>
765  QgsSymbolLayerUtils::createGeometryElement( doc, symbolizerElem, props.value( QStringLiteral( "geom" ), QString() ) );
766 
767  writeSldMarker( doc, symbolizerElem, props );
768 }
769 
771 {
772  return {};
773 }
774 
void setProperty(int key, const QgsProperty &property)
Adds a property to the collection and takes ownership of it.
QgsMapUnitScale mapUnitScale() const override
virtual QVector< qreal > dxfCustomDashPattern(QgsUnitTypes::RenderUnit &unit) const
Gets dash pattern.
QgsLineSymbolLayer(const QgsLineSymbolLayer &other)=delete
QgsLineSymbolLayer cannot be copied.
RenderRingFilter ringFilter() const
Returns the line symbol layer&#39;s ring filter, which controls which rings are rendered when the line sy...
Gradient reference point 1 is centroid.
QgsFillSymbolLayer(const QgsFillSymbolLayer &other)=delete
QgsFillSymbolLayer cannot be copied.
double symbologyScale() const
Returns the reference scale for output.
Definition: qgsdxfexport.h:221
void setRenderingPass(int renderingPass)
Specifies the rendering pass in which this symbol layer should be rendered.
Positive integer values (including 0)
Definition: qgsproperty.h:55
void setMapUnitScale(const QgsMapUnitScale &scale) override
static QPointF toPoint(const QVariant &value, bool *ok=nullptr)
Converts a value to a point.
const QgsVectorSimplifyMethod & vectorSimplifyMethod() const
Returns the simplification settings to use when rendering vector layers.
Gradient reference point 1 x.
QgsFields fields() const
Fields of the layer.
Definition: qgssymbol.h:809
QgsUnitTypes::RenderUnit outputUnit() const override
Returns the units to use for sizes and widths within the symbol layer.
QgsPaintEffect * paintEffect() const
Returns the current paint effect for the layer.
1D size (eg marker radius, or square marker height/width)
Definition: qgsproperty.h:69
Abstract base class for all rendered symbols.
Definition: qgssymbol.h:62
virtual double dxfOffset(const QgsDxfExport &e, QgsSymbolRenderContext &context) const
Gets offset.
Align to right side of symbol.
virtual void prepareExpressions(const QgsSymbolRenderContext &context)
Prepares all data defined property expressions for evaluation.
double angle() const
void startRender(QgsSymbolRenderContext &context) override
Called before a set of rendering operations commences on the supplied render context.
QgsMarkerSymbolLayer(const QgsMarkerSymbolLayer &other)=delete
QgsMarkerSymbolLayer cannot be copied.
static bool isDefaultStack(QgsPaintEffect *effect)
Tests whether a paint effect matches the default effects stack.
static QgsProperty fromField(const QString &fieldName, bool isActive=true)
Returns a new FieldBasedProperty created from the specified field name.
#define DEG2RAD(x)
Base class for visual effects which can be applied to QPicture drawings.
Whether markers should be clipped to polygon boundaries.
static QgsProperty fromExpression(const QString &expression, bool isActive=true)
Returns a new ExpressionBasedProperty created from the specified expression.
void copyPaintEffect(QgsSymbolLayer *destLayer) const
Copies paint effect of this layer to another symbol layer.
Mixed or unknown units.
Definition: qgsunittypes.h:153
void restoreOldDataDefinedProperties(const QgsStringMap &stringMap)
Restores older data defined properties from string map.
void _renderPolygon(QPainter *p, const QPolygonF &points, const QList< QPolygonF > *rings, QgsSymbolRenderContext &context)
Default method to render polygon.
Color with alpha channel.
Definition: qgsproperty.h:64
QgsUnitTypes::DistanceUnit mapUnits() const
Retrieve map units.
virtual double dxfWidth(const QgsDxfExport &e, QgsSymbolRenderContext &context) const
Gets line width.
Line symbol.
Definition: qgssymbol.h:87
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:55
Positive double value (including 0)
Definition: qgsproperty.h:58
void drawPreviewIcon(QgsSymbolRenderContext &context, QSize size) override
Align to horizontal center of symbol.
double dxfWidth(const QgsDxfExport &e, QgsSymbolRenderContext &context) const override
Gets line width.
QMap< QString, QString > QgsStringMap
Definition: qgis.h:694
static QString encodePoint(QPointF point)
Encodes a QPointF to a string.
virtual double width() const
Returns the estimated width for the line symbol layer.
Rotation (value between 0-360 degrees)
Definition: qgsproperty.h:60
Name, eg shape name for simple markers.
Gradient reference point 2 y.
Any string value.
Definition: qgsproperty.h:61
bool isActive(int key) const override
Returns true if the collection contains an active property with the specified key.
QgsProperty propertyFromMap(const QgsStringMap &map, const QString &baseName)
virtual bool hasDataDefinedProperties() const
Returns true if the symbol layer (or any of its sub-symbols) contains data defined properties...
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
virtual void renderPolygon(const QPolygonF &points, QList< QPolygonF > *rings, QgsSymbolRenderContext &context)=0
SymbolType
Type of the symbol.
Definition: qgssymbol.h:84
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:1251
bool prepare(const QgsExpressionContext &context=QgsExpressionContext()) const override
Prepares the collection against a specified expression context.
int renderingPass() const
Specifies the rendering pass in which this symbol layer should be rendered.
Align to bottom of symbol.
QgsUnitTypes::RenderUnit outputUnit() const override
Returns the units to use for sizes and widths within the symbol layer.
The geometries can be rendered with &#39;AntiAliasing&#39; disabled because of it is &#39;1-pixel size&#39;...
virtual QgsSymbolLayerReferenceList masks() const
Returns masks defined by this symbol layer.
virtual void startFeatureRender(const QgsFeature &feature, QgsRenderContext &context)
Called before the layer will be rendered for a particular feature.
QList< QgsSymbolLayerReference > QgsSymbolLayerReferenceList
QgsPropertyCollection & dataDefinedProperties()
Returns a reference to the symbol layer&#39;s property collection, used for data defined overrides...
virtual Qt::BrushStyle dxfBrushStyle() const
Gets brush/fill style.
static double mapUnitScaleFactor(double scale, QgsUnitTypes::RenderUnit symbolUnits, QgsUnitTypes::DistanceUnit mapUnits, double mapUnitsPerPixel=1.0)
Returns scale factor for conversion to map units.
Property requires a numeric value.
Definition: qgsproperty.h:98
virtual QColor color() const
The fill color.
Filename, eg for svg files.
float threshold() const
Gets the simplification threshold of the vector layer managed.
Align to left side of symbol.
void drawPreviewIcon(QgsSymbolRenderContext &context, QSize size) override
void markerOffset(QgsSymbolRenderContext &context, double &offsetX, double &offsetY) const
Calculates the required marker offset, including both the symbol offset and any displacement required...
Shapeburst fill from edge distance.
QgsSymbolLayer(const QgsSymbolLayer &other)=delete
QgsSymbolLayer cannot be copied.
QgsSymbol::SymbolType type() const
void setPaintEffect(QgsPaintEffect *effect)
Sets the current paint effect for the layer.
bool enabled() const
Returns whether the effect is enabled.
Character, eg for font marker symbol layers.
Align to top of symbol.
double mapUnitsPerPixel() const
Returns current map units per pixel.
A store for object properties.
Definition: qgsproperty.h:229
Fill style (eg solid, lines)
Definition: qgsproperty.h:73
QgsRenderContext & renderContext()
Returns a reference to the context&#39;s render context.
Definition: qgssymbol.h:703
RenderRingFilter
Options for filtering rings when the line symbol layer is being used to render a polygon&#39;s rings...
std::unique_ptr< QgsPaintEffect > mPaintEffect
Definition for a property.
Definition: qgsproperty.h:46
HorizontalAnchorPoint
Symbol horizontal anchor points.
Gradient reference point 1 y.
virtual QColor dxfBrushColor(QgsSymbolRenderContext &context) const
Gets brush/fill color.
QMap< int, QgsPropertyDefinition > QgsPropertiesDefinition
Definition of available properties.
VerticalAnchorPoint
Symbol vertical anchor points.
static void createGeometryElement(QDomDocument &doc, QDomElement &element, const QString &geomFunc)
QgsExpressionContext & expressionContext()
Gets the expression context.
virtual Qt::PenStyle dxfPenStyle() const
Gets pen style.
virtual bool isCompatibleWithSymbol(QgsSymbol *symbol) const
Returns if the layer can be used below the specified symbol.
Line angle, or angle of hash lines for hash line symbols.
QSet< QString > referencedFields(const QgsExpressionContext &context=QgsExpressionContext()) const override
Returns the set of any fields referenced by the active properties from the collection.
Stroke style (eg solid, dashed)
Preserve aspect ratio between width and height.
Fill symbol.
Definition: qgssymbol.h:88
virtual QSet< QString > usedAttributes(const QgsRenderContext &context) const
Returns the set of attributes referenced by the layer.
Contains information about the context of a rendering operation.
double convertToPainterUnits(double size, QgsUnitTypes::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale()) const
Converts a size from the specified units to painter units (pixels).
const QgsMapToPixel & mapToPixel() const
Returns the context&#39;s map to pixel transform, which transforms between map coordinates and device coo...
RenderRingFilter mRingFilter
Property requires a string value.
Definition: qgsproperty.h:91
SymbolType type() const
Returns the symbol&#39;s type.
Definition: qgssymbol.h:121
Struct for storing maximum and minimum scales for measurements in map units.
virtual void stopRender(QgsSymbolRenderContext &context)=0
Called after a set of rendering operations has finished on the supplied render context.
void setMapUnitScale(const QgsMapUnitScale &scale) override
virtual double dxfAngle(QgsSymbolRenderContext &context) const
Gets angle.
virtual QColor dxfColor(QgsSymbolRenderContext &context) const
Gets color.
Distance between lines, or length of lines for hash line symbols.
Line style (eg solid/dashed)
Definition: qgsproperty.h:71
void setRingFilter(QgsLineSymbolLayer::RenderRingFilter filter)
Sets the line symbol layer&#39;s ring filter, which controls which rings are rendered when the line symbo...
SimplifyHints simplifyHints() const
Gets the simplification hints of the vector layer managed.
Align to vertical center of symbol.
Secondary color (eg for gradient fills)
bool isEmpty() const
Checks whether the container is empty.
Definition: qgsfields.cpp:128
Horizontal anchor point.
Definition: qgsproperty.h:75
virtual ~QgsSymbolLayer()
virtual void renderPolygonStroke(const QPolygonF &points, QList< QPolygonF > *rings, QgsSymbolRenderContext &context)
Renders the line symbol layer along the outline of polygon, using the given render context...
Length to average symbol angles over.
bool hasActiveProperties() const override
Returns true if the collection has any active properties, or false if all properties within the colle...
void stopRender(QgsSymbolRenderContext &context) override
Called after a set of rendering operations has finished on the supplied render context.
static QPointF _rotatedOffset(QPointF offset, double angle)
Adjusts a marker offset to account for rotation.
Shapeburst blur radius.
void toSld(QDomDocument &doc, QDomElement &element, const QgsStringMap &props) const override
static const QgsPropertiesDefinition & propertyDefinitions()
Returns the symbol layer property definitions.
virtual bool writeDxf(QgsDxfExport &e, double mmMapUnitScaleFactor, const QString &layerName, QgsSymbolRenderContext &context, QPointF shift=QPointF(0.0, 0.0)) const
write as DXF
virtual void stopFeatureRender(const QgsFeature &feature, QgsRenderContext &context)
Called after the layer has been rendered for a particular feature.
static bool isGeneralizableByDeviceBoundingBox(const QgsRectangle &envelope, float mapToPixelTol=1.0f)
Returns whether the device-envelope can be replaced by its BBOX when is applied the specified toleran...
Line cap style (eg round)
Definition: qgsproperty.h:74
Fill style (eg solid, dots)
QgsFields mFields
Whether symbol layer is enabled.
void setOutputUnit(QgsUnitTypes::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
Gradient reference point 2 is centroid.
A class to manager painter saving and restoring required for effect drawing.
QgsSymbol::SymbolType mType
Gradient reference point 2 x.
QgsPropertyCollection mDataDefinedProperties
QgsMapUnitScale mapUnitScale() const override
void setDataDefinedProperties(const QgsPropertyCollection &collection)
Sets the symbol layer&#39;s property collection, used for data defined overrides.
void setOutputUnit(QgsUnitTypes::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
Property
Data definable properties.
RenderUnit
Rendering size units.
Definition: qgsunittypes.h:145
virtual void setDataDefinedProperty(Property key, const QgsProperty &property)
Sets a data defined property for the layer.
void copyDataDefinedProperties(QgsSymbolLayer *destLayer) const
Copies all data defined properties of this layer to another symbol layer.
virtual void startRender(QgsSymbolRenderContext &context)=0
Called before a set of rendering operations commences on the supplied render context.
Horizontal distance between points.
void drawPreviewIcon(QgsSymbolRenderContext &context, QSize size) override
Vertical distance between points.
Double value between 0-1 (inclusive)
Definition: qgsproperty.h:59