QGIS API Documentation  3.9.0-Master (224899f119)
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>]" ) )},
97  { QgsSymbolLayer::PropertyArrowType, QgsPropertyDefinition( "arrowType", QgsPropertyDefinition::DataTypeString, QObject::tr( "Arrow type" ), QObject::tr( "string " ) + QLatin1String( "[<b>plain</b>|<b>lefthalf</b>|<b>righthalf</b>]" ) )},
98 
99  };
100 }
101 
103 {
104  dataDefinedProperties().setProperty( key, property );
105 }
106 
107 bool QgsSymbolLayer::writeDxf( QgsDxfExport &e, double mmMapUnitScaleFactor, const QString &layerName, QgsSymbolRenderContext &context, QPointF shift ) const
108 {
109  Q_UNUSED( e )
110  Q_UNUSED( mmMapUnitScaleFactor )
111  Q_UNUSED( layerName )
112  Q_UNUSED( context )
113  Q_UNUSED( shift )
114  return false;
115 }
116 
118 {
119  Q_UNUSED( e )
120  Q_UNUSED( context )
121  return 1.0;
122 }
123 
125 {
126  Q_UNUSED( e )
127  Q_UNUSED( context )
128  return 0.0;
129 }
130 
132 {
133  Q_UNUSED( context )
134  return color();
135 }
136 
138 {
139  Q_UNUSED( context )
140  return 0.0;
141 }
142 
144 {
145  Q_UNUSED( unit )
146  return QVector<qreal>();
147 }
148 
149 Qt::PenStyle QgsSymbolLayer::dxfPenStyle() const
150 {
151  return Qt::SolidLine;
152 }
153 
155 {
156  Q_UNUSED( context )
157  return color();
158 }
159 
160 Qt::BrushStyle QgsSymbolLayer::dxfBrushStyle() const
161 {
162  return Qt::NoBrush;
163 }
164 
166 {
167  return mPaintEffect.get();
168 }
169 
171 {
172  if ( effect == mPaintEffect.get() )
173  return;
174 
175  mPaintEffect.reset( effect );
176 }
177 
179  : mType( type )
180  , mLocked( locked )
181 {
182 }
183 
185 {
187 
188  if ( !context.fields().isEmpty() )
189  {
190  //QgsFields is implicitly shared, so it's cheap to make a copy
191  mFields = context.fields();
192  }
193 }
194 
196 {
198 }
199 
201 {
202  QgsSymbolLayer::initPropertyDefinitions();
203  return sPropertyDefinitions;
204 }
205 
207 
209 {
210  if ( symbol->type() == QgsSymbol::Fill && mType == QgsSymbol::Line )
211  return true;
212 
213  return symbol->type() == mType;
214 }
215 
217 {
219 }
220 
222 {
223  return mRenderingPass;
224 }
225 
226 QSet<QString> QgsSymbolLayer::usedAttributes( const QgsRenderContext &context ) const
227 {
228  QSet<QString> columns = mDataDefinedProperties.referencedFields( context.expressionContext() );
229  return columns;
230 }
231 
232 QgsProperty propertyFromMap( const QgsStringMap &map, const QString &baseName )
233 {
234  QString prefix;
235  if ( !baseName.isEmpty() )
236  {
237  prefix.append( QStringLiteral( "%1_dd_" ).arg( baseName ) );
238  }
239 
240  if ( !map.contains( QStringLiteral( "%1expression" ).arg( prefix ) ) )
241  {
242  //requires at least the expression value
243  return QgsProperty();
244  }
245 
246  bool active = ( map.value( QStringLiteral( "%1active" ).arg( prefix ), QStringLiteral( "1" ) ) != QLatin1String( "0" ) );
247  QString expression = map.value( QStringLiteral( "%1expression" ).arg( prefix ) );
248  bool useExpression = ( map.value( QStringLiteral( "%1useexpr" ).arg( prefix ), QStringLiteral( "1" ) ) != QLatin1String( "0" ) );
249  QString field = map.value( QStringLiteral( "%1field" ).arg( prefix ), QString() );
250 
251  if ( useExpression )
252  return QgsProperty::fromExpression( expression, active );
253  else
254  return QgsProperty::fromField( field, active );
255 }
256 
257 // property string to type upgrade map
258 static const QMap< QString, QgsSymbolLayer::Property > OLD_PROPS
259 {
261  { "arrow_width", QgsSymbolLayer::PropertyArrowWidth },
262  { "arrow_start_width", QgsSymbolLayer::PropertyArrowStartWidth },
263  { "head_length", QgsSymbolLayer::PropertyArrowHeadLength },
264  { "head_thickness", QgsSymbolLayer::PropertyArrowHeadThickness },
265  { "offset", QgsSymbolLayer::PropertyOffset },
266  { "head_type", QgsSymbolLayer::PropertyArrowHeadType },
267  { "arrow_type", QgsSymbolLayer::PropertyArrowType },
268  { "width_field", QgsSymbolLayer::PropertyWidth },
269  { "height_field", QgsSymbolLayer::PropertyHeight },
270  { "rotation_field", QgsSymbolLayer::PropertyAngle },
271  { "outline_width_field", QgsSymbolLayer::PropertyStrokeWidth },
272  { "fill_color_field", QgsSymbolLayer::PropertyFillColor },
273  { "outline_color_field", QgsSymbolLayer::PropertyStrokeColor },
274  { "symbol_name_field", QgsSymbolLayer::PropertyName },
275  { "outline_width", QgsSymbolLayer::PropertyStrokeWidth },
276  { "outline_style", QgsSymbolLayer::PropertyStrokeStyle },
277  { "join_style", QgsSymbolLayer::PropertyJoinStyle },
278  { "fill_color", QgsSymbolLayer::PropertyFillColor },
279  { "outline_color", QgsSymbolLayer::PropertyStrokeColor },
280  { "width", QgsSymbolLayer::PropertyWidth },
281  { "height", QgsSymbolLayer::PropertyHeight },
282  { "symbol_name", QgsSymbolLayer::PropertyName },
283  { "angle", QgsSymbolLayer::PropertyAngle },
284  { "fill_style", QgsSymbolLayer::PropertyFillStyle },
285  { "color_border", QgsSymbolLayer::PropertyStrokeColor },
286  { "width_border", QgsSymbolLayer::PropertyStrokeWidth },
287  { "border_color", QgsSymbolLayer::PropertyStrokeColor },
288  { "border_style", QgsSymbolLayer::PropertyStrokeStyle },
290  { "gradient_type", QgsSymbolLayer::PropertyGradientType },
291  { "coordinate_mode", QgsSymbolLayer::PropertyCoordinateMode },
297  { "reference1_iscentroid", QgsSymbolLayer::PropertyGradientReference1IsCentroid },
298  { "reference2_iscentroid", QgsSymbolLayer::PropertyGradientReference2IsCentroid },
299  { "blur_radius", QgsSymbolLayer::PropertyBlurRadius },
303  { "svgFillColor", QgsSymbolLayer::PropertyFillColor },
304  { "svgOutlineColor", QgsSymbolLayer::PropertyStrokeColor },
305  { "svgOutlineWidth", QgsSymbolLayer::PropertyStrokeWidth },
306  { "svgFile", QgsSymbolLayer::PropertyFile },
307  { "lineangle", QgsSymbolLayer::PropertyLineAngle },
308  { "distance", QgsSymbolLayer::PropertyLineDistance },
309  { "distance_x", QgsSymbolLayer::PropertyDistanceX },
310  { "distance_y", QgsSymbolLayer::PropertyDistanceY },
311  { "displacement_x", QgsSymbolLayer::PropertyDisplacementX },
312  { "displacement_y", QgsSymbolLayer::PropertyDisplacementY },
313  { "file", QgsSymbolLayer::PropertyFile },
314  { "alpha", QgsSymbolLayer::PropertyOpacity },
315  { "customdash", QgsSymbolLayer::PropertyCustomDash },
316  { "line_style", QgsSymbolLayer::PropertyStrokeStyle },
317  { "joinstyle", QgsSymbolLayer::PropertyJoinStyle },
318  { "capstyle", QgsSymbolLayer::PropertyCapStyle },
319  { "placement", QgsSymbolLayer::PropertyPlacement },
320  { "interval", QgsSymbolLayer::PropertyInterval },
321  { "offset_along_line", QgsSymbolLayer::PropertyOffsetAlongLine },
322  { "name", QgsSymbolLayer::PropertyName },
323  { "size", QgsSymbolLayer::PropertySize },
328  { "rotation", QgsSymbolLayer::PropertyAngle },
329  { "horizontal_anchor_point", QgsSymbolLayer::PropertyHorizontalAnchor },
330  { "vertical_anchor_point", QgsSymbolLayer::PropertyVerticalAnchor },
331 };
332 
334 {
335  QgsStringMap::const_iterator propIt = stringMap.constBegin();
336  for ( ; propIt != stringMap.constEnd(); ++propIt )
337  {
338  QgsProperty prop;
339  QString propertyName;
340 
341  if ( propIt.key().endsWith( QLatin1String( "_dd_expression" ) ) )
342  {
343  //found a data defined property
344 
345  //get data defined property name by stripping "_dd_expression" from property key
346  propertyName = propIt.key().left( propIt.key().length() - 14 );
347 
348  prop = propertyFromMap( stringMap, propertyName );
349  }
350  else if ( propIt.key().endsWith( QLatin1String( "_expression" ) ) )
351  {
352  //old style data defined property, upgrade
353 
354  //get data defined property name by stripping "_expression" from property key
355  propertyName = propIt.key().left( propIt.key().length() - 11 );
356 
357  prop = QgsProperty::fromExpression( propIt.value() );
358  }
359 
360  if ( !prop || !OLD_PROPS.contains( propertyName ) )
361  continue;
362 
363  QgsSymbolLayer::Property key = static_cast< QgsSymbolLayer::Property >( OLD_PROPS.value( propertyName ) );
364 
365  if ( type() == QgsSymbol::Line )
366  {
367  //these keys had different meaning for line symbol layers
368  if ( propertyName == QLatin1String( "width" ) )
370  else if ( propertyName == QLatin1String( "color" ) )
372  }
373 
374  setDataDefinedProperty( key, prop );
375  }
376 }
377 
379 {
380  if ( !destLayer )
381  return;
382 
384 }
385 
387 {
388  if ( !destLayer || !mPaintEffect )
389  return;
390 
392  destLayer->setPaintEffect( mPaintEffect->clone() );
393  else
394  destLayer->setPaintEffect( nullptr );
395 }
396 
398  : QgsSymbolLayer( QgsSymbol::Marker, locked )
399 {
400 
401 }
402 
404  : QgsSymbolLayer( QgsSymbol::Line, locked )
405 {
406 }
407 
409 {
410  return mRingFilter;
411 }
412 
414 {
415  mRingFilter = filter;
416 }
417 
419  : QgsSymbolLayer( QgsSymbol::Fill, locked )
420 {
421 }
422 
424 {
425  Q_UNUSED( context )
426 }
427 
429 {
430  Q_UNUSED( context )
431 }
432 
434 {
435  startRender( context );
436  QgsPaintEffect *effect = paintEffect();
437  if ( effect && effect->enabled() )
438  {
439  QgsEffectPainter p( context.renderContext(), effect );
440  renderPoint( QPointF( size.width() / 2, size.height() / 2 ), context );
441  }
442  else
443  {
444  renderPoint( QPointF( size.width() / 2, size.height() / 2 ), context );
445  }
446  stopRender( context );
447 }
448 
449 void QgsMarkerSymbolLayer::markerOffset( QgsSymbolRenderContext &context, double &offsetX, double &offsetY ) const
450 {
451  markerOffset( context, mSize, mSize, mSizeUnit, mSizeUnit, offsetX, offsetY, mSizeMapUnitScale, mSizeMapUnitScale );
452 }
453 
454 void QgsMarkerSymbolLayer::markerOffset( QgsSymbolRenderContext &context, double width, double height, double &offsetX, double &offsetY ) const
455 {
456  markerOffset( context, width, height, mSizeUnit, mSizeUnit, offsetX, offsetY, mSizeMapUnitScale, mSizeMapUnitScale );
457 }
458 
459 void QgsMarkerSymbolLayer::markerOffset( QgsSymbolRenderContext &context, double width, double height,
461  double &offsetX, double &offsetY, const QgsMapUnitScale &widthMapUnitScale, const QgsMapUnitScale &heightMapUnitScale ) const
462 {
463  offsetX = mOffset.x();
464  offsetY = mOffset.y();
465 
467  {
470  bool ok = false;
471  const QPointF offset = QgsSymbolLayerUtils::toPoint( exprVal, &ok );
472  if ( ok )
473  {
474  offsetX = offset.x();
475  offsetY = offset.y();
476  }
477  }
478 
479  offsetX = context.renderContext().convertToPainterUnits( offsetX, mOffsetUnit, mOffsetMapUnitScale );
480  offsetY = context.renderContext().convertToPainterUnits( offsetY, mOffsetUnit, mOffsetMapUnitScale );
481 
482  HorizontalAnchorPoint horizontalAnchorPoint = mHorizontalAnchorPoint;
483  VerticalAnchorPoint verticalAnchorPoint = mVerticalAnchorPoint;
485  {
487  if ( exprVal.isValid() )
488  {
489  horizontalAnchorPoint = decodeHorizontalAnchorPoint( exprVal.toString() );
490  }
491  }
493  {
495  if ( exprVal.isValid() )
496  {
497  verticalAnchorPoint = decodeVerticalAnchorPoint( exprVal.toString() );
498  }
499  }
500 
501  //correct horizontal position according to anchor point
502  if ( horizontalAnchorPoint == HCenter && verticalAnchorPoint == VCenter )
503  {
504  return;
505  }
506 
507  double anchorPointCorrectionX = context.renderContext().convertToPainterUnits( width, widthUnit, widthMapUnitScale ) / 2.0;
508  double anchorPointCorrectionY = context.renderContext().convertToPainterUnits( height, heightUnit, heightMapUnitScale ) / 2.0;
509  if ( horizontalAnchorPoint == Left )
510  {
511  offsetX += anchorPointCorrectionX;
512  }
513  else if ( horizontalAnchorPoint == Right )
514  {
515  offsetX -= anchorPointCorrectionX;
516  }
517 
518  //correct vertical position according to anchor point
519  if ( verticalAnchorPoint == Top )
520  {
521  offsetY += anchorPointCorrectionY;
522  }
523  else if ( verticalAnchorPoint == Bottom )
524  {
525  offsetY -= anchorPointCorrectionY;
526  }
527 }
528 
529 QPointF QgsMarkerSymbolLayer::_rotatedOffset( QPointF offset, double angle )
530 {
531  angle = DEG2RAD( angle );
532  double c = std::cos( angle ), s = std::sin( angle );
533  return QPointF( offset.x() * c - offset.y() * s, offset.x() * s + offset.y() * c );
534 }
535 
536 QgsMarkerSymbolLayer::HorizontalAnchorPoint QgsMarkerSymbolLayer::decodeHorizontalAnchorPoint( const QString &str )
537 {
538  if ( str.compare( QLatin1String( "left" ), Qt::CaseInsensitive ) == 0 )
539  {
541  }
542  else if ( str.compare( QLatin1String( "right" ), Qt::CaseInsensitive ) == 0 )
543  {
545  }
546  else
547  {
549  }
550 }
551 
552 QgsMarkerSymbolLayer::VerticalAnchorPoint QgsMarkerSymbolLayer::decodeVerticalAnchorPoint( const QString &str )
553 {
554  if ( str.compare( QLatin1String( "top" ), Qt::CaseInsensitive ) == 0 )
555  {
557  }
558  else if ( str.compare( QLatin1String( "bottom" ), Qt::CaseInsensitive ) == 0 )
559  {
561  }
562  else
563  {
565  }
566 }
567 
569 {
570  mSizeUnit = unit;
571  mOffsetUnit = unit;
572 }
573 
575 {
576  if ( mOffsetUnit != mSizeUnit )
577  {
579  }
580  return mOffsetUnit;
581 }
582 
584 {
585  mSizeMapUnitScale = scale;
586  mOffsetMapUnitScale = scale;
587 }
588 
590 {
591  if ( mSizeMapUnitScale == mOffsetMapUnitScale )
592  {
593  return mSizeMapUnitScale;
594  }
595  return QgsMapUnitScale();
596 }
597 
599 {
600  mWidthUnit = unit;
601 }
602 
604 {
605  return mWidthUnit;
606 }
607 
609 {
610  mWidthMapUnitScale = scale;
611 }
612 
614 {
615  return mWidthMapUnitScale;
616 }
617 
618 
620 {
621  QPolygonF points;
622  // we're adding 0.5 to get rid of blurred preview:
623  // drawing antialiased lines of width 1 at (x,0)-(x,100) creates 2px line
624  points << QPointF( 0, int( size.height() / 2 ) + 0.5 ) << QPointF( size.width(), int( size.height() / 2 ) + 0.5 );
625 
626  startRender( context );
627  QgsPaintEffect *effect = paintEffect();
628  if ( effect && effect->enabled() )
629  {
630  QgsEffectPainter p( context.renderContext(), effect );
631  renderPolyline( points, context );
632  }
633  else
634  {
635  renderPolyline( points, context );
636  }
637  stopRender( context );
638 }
639 
640 void QgsLineSymbolLayer::renderPolygonStroke( const QPolygonF &points, QList<QPolygonF> *rings, QgsSymbolRenderContext &context )
641 {
642  switch ( mRingFilter )
643  {
644  case AllRings:
645  case ExteriorRingOnly:
646  renderPolyline( points, context );
647  break;
648  case InteriorRingsOnly:
649  break;
650  }
651 
652  if ( rings )
653  {
654  switch ( mRingFilter )
655  {
656  case AllRings:
657  case InteriorRingsOnly:
658  {
659  for ( const QPolygonF &ring : qgis::as_const( *rings ) )
660  renderPolyline( ring, context );
661  }
662  break;
663  case ExteriorRingOnly:
664  break;
665  }
666  }
667 }
668 
669 double QgsLineSymbolLayer::width( const QgsRenderContext &context ) const
670 {
671  return context.convertToPainterUnits( mWidth, mWidthUnit, mWidthMapUnitScale );
672 }
673 
675 {
676  Q_UNUSED( context )
677  return width() * e.mapUnitScaleFactor( e.symbologyScale(), widthUnit(), e.mapUnits(), context.renderContext().mapToPixel().mapUnitsPerPixel() );
678 }
679 
680 
682 {
683  QPolygonF poly = QRectF( QPointF( 0, 0 ), QPointF( size.width(), size.height() ) );
684  startRender( context );
685  QgsPaintEffect *effect = paintEffect();
686  if ( effect && effect->enabled() )
687  {
688  QgsEffectPainter p( context.renderContext(), effect );
689  renderPolygon( poly, nullptr, context );
690  }
691  else
692  {
693  renderPolygon( poly, nullptr, context );
694  }
695  stopRender( context );
696 }
697 
698 void QgsFillSymbolLayer::_renderPolygon( QPainter *p, const QPolygonF &points, const QList<QPolygonF> *rings, QgsSymbolRenderContext &context )
699 {
700  if ( !p )
701  {
702  return;
703  }
704 
705  // Disable 'Antialiasing' if the geometry was generalized in the current RenderContext (We known that it must have least #5 points).
706  if ( points.size() <= 5 &&
709  ( p->renderHints() & QPainter::Antialiasing ) )
710  {
711  p->setRenderHint( QPainter::Antialiasing, false );
712  p->drawRect( points.boundingRect() );
713  p->setRenderHint( QPainter::Antialiasing, true );
714  return;
715  }
716 
717  // polygons outlines are sometimes rendered wrongly with drawPolygon, when
718  // clipped (see #13343), so use drawPath instead.
719  if ( !rings && p->pen().style() == Qt::NoPen )
720  {
721  // simple polygon without holes
722  p->drawPolygon( points );
723  }
724  else
725  {
726  // polygon with holes must be drawn using painter path
727  QPainterPath path;
728  path.addPolygon( points );
729 
730  if ( rings )
731  {
732  QList<QPolygonF>::const_iterator it = rings->constBegin();
733  for ( ; it != rings->constEnd(); ++it )
734  {
735  QPolygonF ring = *it;
736  path.addPolygon( ring );
737  }
738  }
739 
740  p->drawPath( path );
741  }
742 }
743 
744 void QgsMarkerSymbolLayer::toSld( QDomDocument &doc, QDomElement &element, const QgsStringMap &props ) const
745 {
746  QDomElement symbolizerElem = doc.createElement( QStringLiteral( "se:PointSymbolizer" ) );
747  if ( !props.value( QStringLiteral( "uom" ), QString() ).isEmpty() )
748  symbolizerElem.setAttribute( QStringLiteral( "uom" ), props.value( QStringLiteral( "uom" ), QString() ) );
749  element.appendChild( symbolizerElem );
750 
751  // <Geometry>
752  QgsSymbolLayerUtils::createGeometryElement( doc, symbolizerElem, props.value( QStringLiteral( "geom" ), QString() ) );
753 
754  writeSldMarker( doc, symbolizerElem, props );
755 }
756 
757 
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:154
void setRenderingPass(int renderingPass)
Specifies the rendering pass in which this symbol layer should be rendered.
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:773
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:61
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
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.
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:121
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:86
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:597
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:83
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:1167
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;...
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:667
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:87
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:120
Struct for storing maximum and minimum scales for measurements in map units.
virtual void stopRender(QgsSymbolRenderContext &context)=0
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
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
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:113
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
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