QGIS API Documentation  3.4.15-Madeira (e83d02e274)
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 
30 #include <QSize>
31 #include <QPainter>
32 #include <QPointF>
33 #include <QPolygonF>
34 
35 QgsPropertiesDefinition QgsSymbolLayer::sPropertyDefinitions;
36 
37 void QgsSymbolLayer::initPropertyDefinitions()
38 {
39  if ( !sPropertyDefinitions.isEmpty() )
40  return;
41 
42  QString origin = QStringLiteral( "symbol" );
43 
44  sPropertyDefinitions = QgsPropertiesDefinition
45  {
46  { QgsSymbolLayer::PropertySize, QgsPropertyDefinition( "size", QObject::tr( "Symbol size" ), QgsPropertyDefinition::Size, origin ) },
47  { QgsSymbolLayer::PropertyAngle, QgsPropertyDefinition( "angle", QObject::tr( "Rotation angle" ), QgsPropertyDefinition::Rotation, origin ) },
48  { QgsSymbolLayer::PropertyName, QgsPropertyDefinition( "name", QObject::tr( "Symbol name" ), QgsPropertyDefinition::String, origin ) },
49  { QgsSymbolLayer::PropertyFillColor, QgsPropertyDefinition( "fillColor", QObject::tr( "Symbol fill color" ), QgsPropertyDefinition::ColorWithAlpha, origin ) },
50  { QgsSymbolLayer::PropertyStrokeColor, QgsPropertyDefinition( "outlineColor", QObject::tr( "Symbol stroke color" ), QgsPropertyDefinition::ColorWithAlpha, origin ) },
51  { QgsSymbolLayer::PropertyStrokeWidth, QgsPropertyDefinition( "outlineWidth", QObject::tr( "Symbol stroke width" ), QgsPropertyDefinition::StrokeWidth, origin ) },
52  { QgsSymbolLayer::PropertyStrokeStyle, QgsPropertyDefinition( "outlineStyle", QObject::tr( "Symbol stroke style" ), QgsPropertyDefinition::LineStyle, origin )},
53  { QgsSymbolLayer::PropertyOffset, QgsPropertyDefinition( "offset", QObject::tr( "Symbol offset" ), QgsPropertyDefinition::Offset, origin )},
54  { QgsSymbolLayer::PropertyCharacter, QgsPropertyDefinition( "char", QObject::tr( "Marker character(s)" ), QgsPropertyDefinition::String, origin )},
55  { QgsSymbolLayer::PropertyWidth, QgsPropertyDefinition( "width", QObject::tr( "Symbol width" ), QgsPropertyDefinition::DoublePositive, origin )},
56  { QgsSymbolLayer::PropertyHeight, QgsPropertyDefinition( "height", QObject::tr( "Symbol height" ), QgsPropertyDefinition::DoublePositive, origin )},
57  { QgsSymbolLayer::PropertyPreserveAspectRatio, QgsPropertyDefinition( "preserveAspectRatio", QObject::tr( "Preserve aspect ratio between width and height" ), QgsPropertyDefinition::Boolean, origin )},
58  { QgsSymbolLayer::PropertyFillStyle, QgsPropertyDefinition( "fillStyle", QObject::tr( "Symbol fill style" ), QgsPropertyDefinition::FillStyle, origin )},
59  { QgsSymbolLayer::PropertyJoinStyle, QgsPropertyDefinition( "joinStyle", QObject::tr( "Outline join style" ), QgsPropertyDefinition::PenJoinStyle, origin )},
60  { QgsSymbolLayer::PropertySecondaryColor, QgsPropertyDefinition( "color2", QObject::tr( "Secondary fill color" ), QgsPropertyDefinition::ColorWithAlpha, origin )},
61  { QgsSymbolLayer::PropertyLineAngle, QgsPropertyDefinition( "lineAngle", QObject::tr( "Angle for line fills" ), QgsPropertyDefinition::Rotation, origin )},
62  { QgsSymbolLayer::PropertyGradientType, QgsPropertyDefinition( "gradientType", QgsPropertyDefinition::DataTypeString, QObject::tr( "Gradient type" ), QObject::tr( "string " ) + QLatin1String( "[<b>linear</b>|<b>radial</b>|<b>conical</b>]" ), origin )},
63  { QgsSymbolLayer::PropertyCoordinateMode, QgsPropertyDefinition( "gradientMode", QgsPropertyDefinition::DataTypeString, QObject::tr( "Gradient mode" ), QObject::tr( "string " ) + QLatin1String( "[<b>feature</b>|<b>viewport</b>]" ), origin )},
64  { QgsSymbolLayer::PropertyGradientSpread, QgsPropertyDefinition( "gradientSpread", QgsPropertyDefinition::DataTypeString, QObject::tr( "Gradient spread" ), QObject::tr( "string " ) + QLatin1String( "[<b>pad</b>|<b>repeat</b>|<b>reflect</b>]" ), origin )},
65  { QgsSymbolLayer::PropertyGradientReference1X, QgsPropertyDefinition( "gradientRef1X", QObject::tr( "Reference point 1 (X)" ), QgsPropertyDefinition::Double0To1, origin )},
66  { QgsSymbolLayer::PropertyGradientReference1Y, QgsPropertyDefinition( "gradientRef1Y", QObject::tr( "Reference point 1 (Y)" ), QgsPropertyDefinition::Double0To1, origin )},
67  { QgsSymbolLayer::PropertyGradientReference2X, QgsPropertyDefinition( "gradientRef2X", QObject::tr( "Reference point 2 (X)" ), QgsPropertyDefinition::Double0To1, origin )},
68  { QgsSymbolLayer::PropertyGradientReference2Y, QgsPropertyDefinition( "gradientRef2Y", QObject::tr( "Reference point 2 (Y)" ), QgsPropertyDefinition::Double0To1, origin )},
69  { QgsSymbolLayer::PropertyGradientReference1IsCentroid, QgsPropertyDefinition( "gradientRef1Centroid", QObject::tr( "Reference point 1 follows feature centroid" ), QgsPropertyDefinition::Boolean, origin )},
70  { QgsSymbolLayer::PropertyGradientReference2IsCentroid, QgsPropertyDefinition( "gradientRef2Centroid", QObject::tr( "Reference point 2 follows feature centroid" ), QgsPropertyDefinition::Boolean, origin )},
71  { QgsSymbolLayer::PropertyBlurRadius, QgsPropertyDefinition( "blurRadius", QgsPropertyDefinition::DataTypeNumeric, QObject::tr( "Blur radius" ), QObject::tr( "Integer between 0 and 18" ), origin )},
72  { QgsSymbolLayer::PropertyLineDistance, QgsPropertyDefinition( "lineDistance", QObject::tr( "Distance between lines" ), QgsPropertyDefinition::DoublePositive, origin )},
73  { QgsSymbolLayer::PropertyShapeburstUseWholeShape, QgsPropertyDefinition( "shapeburstWholeShape", QObject::tr( "Shade whole shape" ), QgsPropertyDefinition::Boolean, origin )},
74  { QgsSymbolLayer::PropertyShapeburstMaxDistance, QgsPropertyDefinition( "shapeburstMaxDist", QObject::tr( "Maximum distance for shapeburst fill" ), QgsPropertyDefinition::DoublePositive, origin )},
75  { QgsSymbolLayer::PropertyShapeburstIgnoreRings, QgsPropertyDefinition( "shapeburstIgnoreRings", QObject::tr( "Ignore rings in feature" ), QgsPropertyDefinition::Boolean, origin )},
76  { QgsSymbolLayer::PropertyFile, QgsPropertyDefinition( "file", QObject::tr( "Symbol file path" ), QgsPropertyDefinition::String, origin )},
77  { QgsSymbolLayer::PropertyDistanceX, QgsPropertyDefinition( "distanceX", QObject::tr( "Horizontal distance between markers" ), QgsPropertyDefinition::DoublePositive, origin )},
78  { QgsSymbolLayer::PropertyDistanceY, QgsPropertyDefinition( "distanceY", QObject::tr( "Vertical distance between markers" ), QgsPropertyDefinition::DoublePositive, origin )},
79  { QgsSymbolLayer::PropertyDisplacementX, QgsPropertyDefinition( "displacementX", QObject::tr( "Horizontal displacement between rows" ), QgsPropertyDefinition::DoublePositive, origin )},
80  { QgsSymbolLayer::PropertyDisplacementY, QgsPropertyDefinition( "displacementY", QObject::tr( "Vertical displacement between columns" ), QgsPropertyDefinition::DoublePositive, origin )},
81  { QgsSymbolLayer::PropertyOpacity, QgsPropertyDefinition( "alpha", QObject::tr( "Opacity" ), QgsPropertyDefinition::Opacity, origin )},
82  { QgsSymbolLayer::PropertyCustomDash, QgsPropertyDefinition( "customDash", QgsPropertyDefinition::DataTypeString, QObject::tr( "Custom dash pattern" ), QObject::tr( "[<b><dash>;<space></b>] e.g. '8;2;1;2'" ), origin )},
83  { QgsSymbolLayer::PropertyCapStyle, QgsPropertyDefinition( "capStyle", QObject::tr( "Line cap style" ), QgsPropertyDefinition::CapStyle, origin )},
84  { 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>]", origin )},
85  { QgsSymbolLayer::PropertyInterval, QgsPropertyDefinition( "interval", QObject::tr( "Marker interval" ), QgsPropertyDefinition::DoublePositive, origin )},
86  { QgsSymbolLayer::PropertyOffsetAlongLine, QgsPropertyDefinition( "offsetAlongLine", QObject::tr( "Offset along line" ), QgsPropertyDefinition::DoublePositive, origin )},
87  { QgsSymbolLayer::PropertyHorizontalAnchor, QgsPropertyDefinition( "hAnchor", QObject::tr( "Horizontal anchor point" ), QgsPropertyDefinition::HorizontalAnchor, origin )},
88  { QgsSymbolLayer::PropertyVerticalAnchor, QgsPropertyDefinition( "vAnchor", QObject::tr( "Vertical anchor point" ), QgsPropertyDefinition::VerticalAnchor, origin )},
89  { QgsSymbolLayer::PropertyLayerEnabled, QgsPropertyDefinition( "enabled", QObject::tr( "Layer enabled" ), QgsPropertyDefinition::Boolean, origin )},
90  { QgsSymbolLayer::PropertyArrowWidth, QgsPropertyDefinition( "arrowWidth", QObject::tr( "Arrow line width" ), QgsPropertyDefinition::StrokeWidth, origin )},
91  { QgsSymbolLayer::PropertyArrowStartWidth, QgsPropertyDefinition( "arrowStartWidth", QObject::tr( "Arrow line start width" ), QgsPropertyDefinition::StrokeWidth, origin )},
92  { QgsSymbolLayer::PropertyArrowHeadLength, QgsPropertyDefinition( "arrowHeadLength", QObject::tr( "Arrow head length" ), QgsPropertyDefinition::DoublePositive, origin )},
93  { QgsSymbolLayer::PropertyArrowHeadThickness, QgsPropertyDefinition( "arrowHeadThickness", QObject::tr( "Arrow head thickness" ), QgsPropertyDefinition::DoublePositive, origin )},
94  { QgsSymbolLayer::PropertyArrowHeadType, QgsPropertyDefinition( "arrowHeadType", QgsPropertyDefinition::DataTypeString, QObject::tr( "Arrow head type" ), QObject::tr( "string " ) + QLatin1String( "[<b>single</b>|<b>reversed</b>|<b>double</b>]" ) )},
95  { QgsSymbolLayer::PropertyArrowType, QgsPropertyDefinition( "arrowType", QgsPropertyDefinition::DataTypeString, QObject::tr( "Arrow type" ), QObject::tr( "string " ) + QLatin1String( "[<b>plain</b>|<b>lefthalf</b>|<b>righthalf</b>]" ) )},
96 
97  };
98 }
99 
101 {
102  dataDefinedProperties().setProperty( key, property );
103 }
104 
105 bool QgsSymbolLayer::writeDxf( QgsDxfExport &e, double mmMapUnitScaleFactor, const QString &layerName, QgsSymbolRenderContext &context, QPointF shift ) const
106 {
107  Q_UNUSED( e );
108  Q_UNUSED( mmMapUnitScaleFactor );
109  Q_UNUSED( layerName );
110  Q_UNUSED( context );
111  Q_UNUSED( shift );
112  return false;
113 }
114 
116 {
117  Q_UNUSED( e );
118  Q_UNUSED( context );
119  return 1.0;
120 }
121 
123 {
124  Q_UNUSED( e );
125  Q_UNUSED( context );
126  return 0.0;
127 }
128 
130 {
131  Q_UNUSED( context );
132  return color();
133 }
134 
136 {
137  Q_UNUSED( context );
138  return 0.0;
139 }
140 
142 {
143  Q_UNUSED( unit );
144  return QVector<qreal>();
145 }
146 
147 Qt::PenStyle QgsSymbolLayer::dxfPenStyle() const
148 {
149  return Qt::SolidLine;
150 }
151 
153 {
154  Q_UNUSED( context );
155  return color();
156 }
157 
158 Qt::BrushStyle QgsSymbolLayer::dxfBrushStyle() const
159 {
160  return Qt::NoBrush;
161 }
162 
164 {
165  return mPaintEffect;
166 }
167 
169 {
170  delete mPaintEffect;
171  mPaintEffect = effect;
172 }
173 
175  : mType( type )
176  , mEnabled( true )
177  , mLocked( locked )
178  , mRenderingPass( 0 )
179 
180 {
182  mPaintEffect->setEnabled( false );
183 }
184 
186 {
188 
189  if ( !context.fields().isEmpty() )
190  {
191  //QgsFields is implicitly shared, so it's cheap to make a copy
192  mFields = context.fields();
193  }
194 }
195 
197 {
199 }
200 
202 {
203  QgsSymbolLayer::initPropertyDefinitions();
204  return sPropertyDefinitions;
205 }
206 
208 {
209  delete mPaintEffect;
210 }
211 
213 {
214  if ( symbol->type() == QgsSymbol::Fill && mType == QgsSymbol::Line )
215  return true;
216 
217  return symbol->type() == mType;
218 }
219 
220 QSet<QString> QgsSymbolLayer::usedAttributes( const QgsRenderContext &context ) const
221 {
222  QSet<QString> columns = mDataDefinedProperties.referencedFields( context.expressionContext() );
223  return columns;
224 }
225 
226 QgsProperty propertyFromMap( const QgsStringMap &map, const QString &baseName )
227 {
228  QString prefix;
229  if ( !baseName.isEmpty() )
230  {
231  prefix.append( QStringLiteral( "%1_dd_" ).arg( baseName ) );
232  }
233 
234  if ( !map.contains( QStringLiteral( "%1expression" ).arg( prefix ) ) )
235  {
236  //requires at least the expression value
237  return QgsProperty();
238  }
239 
240  bool active = ( map.value( QStringLiteral( "%1active" ).arg( prefix ), QStringLiteral( "1" ) ) != QLatin1String( "0" ) );
241  QString expression = map.value( QStringLiteral( "%1expression" ).arg( prefix ) );
242  bool useExpression = ( map.value( QStringLiteral( "%1useexpr" ).arg( prefix ), QStringLiteral( "1" ) ) != QLatin1String( "0" ) );
243  QString field = map.value( QStringLiteral( "%1field" ).arg( prefix ), QString() );
244 
245  if ( useExpression )
246  return QgsProperty::fromExpression( expression, active );
247  else
248  return QgsProperty::fromField( field, active );
249 }
250 
251 // property string to type upgrade map
252 static const QMap< QString, QgsSymbolLayer::Property > OLD_PROPS
253 {
255  { "arrow_width", QgsSymbolLayer::PropertyArrowWidth },
256  { "arrow_start_width", QgsSymbolLayer::PropertyArrowStartWidth },
257  { "head_length", QgsSymbolLayer::PropertyArrowHeadLength },
258  { "head_thickness", QgsSymbolLayer::PropertyArrowHeadThickness },
259  { "offset", QgsSymbolLayer::PropertyOffset },
260  { "head_type", QgsSymbolLayer::PropertyArrowHeadType },
261  { "arrow_type", QgsSymbolLayer::PropertyArrowType },
262  { "width_field", QgsSymbolLayer::PropertyWidth },
263  { "height_field", QgsSymbolLayer::PropertyHeight },
264  { "rotation_field", QgsSymbolLayer::PropertyAngle },
265  { "outline_width_field", QgsSymbolLayer::PropertyStrokeWidth },
266  { "fill_color_field", QgsSymbolLayer::PropertyFillColor },
267  { "outline_color_field", QgsSymbolLayer::PropertyStrokeColor },
268  { "symbol_name_field", QgsSymbolLayer::PropertyName },
269  { "outline_width", QgsSymbolLayer::PropertyStrokeWidth },
270  { "outline_style", QgsSymbolLayer::PropertyStrokeStyle },
271  { "join_style", QgsSymbolLayer::PropertyJoinStyle },
272  { "fill_color", QgsSymbolLayer::PropertyFillColor },
273  { "outline_color", QgsSymbolLayer::PropertyStrokeColor },
274  { "width", QgsSymbolLayer::PropertyWidth },
275  { "height", QgsSymbolLayer::PropertyHeight },
276  { "symbol_name", QgsSymbolLayer::PropertyName },
277  { "angle", QgsSymbolLayer::PropertyAngle },
278  { "fill_style", QgsSymbolLayer::PropertyFillStyle },
279  { "color_border", QgsSymbolLayer::PropertyStrokeColor },
280  { "width_border", QgsSymbolLayer::PropertyStrokeWidth },
281  { "border_color", QgsSymbolLayer::PropertyStrokeColor },
282  { "border_style", QgsSymbolLayer::PropertyStrokeStyle },
284  { "gradient_type", QgsSymbolLayer::PropertyGradientType },
285  { "coordinate_mode", QgsSymbolLayer::PropertyCoordinateMode },
291  { "reference1_iscentroid", QgsSymbolLayer::PropertyGradientReference1IsCentroid },
292  { "reference2_iscentroid", QgsSymbolLayer::PropertyGradientReference2IsCentroid },
293  { "blur_radius", QgsSymbolLayer::PropertyBlurRadius },
297  { "svgFillColor", QgsSymbolLayer::PropertyFillColor },
298  { "svgOutlineColor", QgsSymbolLayer::PropertyStrokeColor },
299  { "svgOutlineWidth", QgsSymbolLayer::PropertyStrokeWidth },
300  { "svgFile", QgsSymbolLayer::PropertyFile },
301  { "lineangle", QgsSymbolLayer::PropertyLineAngle },
302  { "distance", QgsSymbolLayer::PropertyLineDistance },
303  { "distance_x", QgsSymbolLayer::PropertyDistanceX },
304  { "distance_y", QgsSymbolLayer::PropertyDistanceY },
305  { "displacement_x", QgsSymbolLayer::PropertyDisplacementX },
306  { "displacement_y", QgsSymbolLayer::PropertyDisplacementY },
307  { "file", QgsSymbolLayer::PropertyFile },
308  { "alpha", QgsSymbolLayer::PropertyOpacity },
309  { "customdash", QgsSymbolLayer::PropertyCustomDash },
310  { "line_style", QgsSymbolLayer::PropertyStrokeStyle },
311  { "joinstyle", QgsSymbolLayer::PropertyJoinStyle },
312  { "capstyle", QgsSymbolLayer::PropertyCapStyle },
313  { "placement", QgsSymbolLayer::PropertyPlacement },
314  { "interval", QgsSymbolLayer::PropertyInterval },
315  { "offset_along_line", QgsSymbolLayer::PropertyOffsetAlongLine },
316  { "name", QgsSymbolLayer::PropertyName },
317  { "size", QgsSymbolLayer::PropertySize },
322  { "rotation", QgsSymbolLayer::PropertyAngle },
323  { "horizontal_anchor_point", QgsSymbolLayer::PropertyHorizontalAnchor },
324  { "vertical_anchor_point", QgsSymbolLayer::PropertyVerticalAnchor },
325 };
326 
328 {
329  QgsStringMap::const_iterator propIt = stringMap.constBegin();
330  for ( ; propIt != stringMap.constEnd(); ++propIt )
331  {
332  QgsProperty prop;
333  QString propertyName;
334 
335  if ( propIt.key().endsWith( QLatin1String( "_dd_expression" ) ) )
336  {
337  //found a data defined property
338 
339  //get data defined property name by stripping "_dd_expression" from property key
340  propertyName = propIt.key().left( propIt.key().length() - 14 );
341 
342  prop = propertyFromMap( stringMap, propertyName );
343  }
344  else if ( propIt.key().endsWith( QLatin1String( "_expression" ) ) )
345  {
346  //old style data defined property, upgrade
347 
348  //get data defined property name by stripping "_expression" from property key
349  propertyName = propIt.key().left( propIt.key().length() - 11 );
350 
351  prop = QgsProperty::fromExpression( propIt.value() );
352  }
353 
354  if ( !prop || !OLD_PROPS.contains( propertyName ) )
355  continue;
356 
357  QgsSymbolLayer::Property key = static_cast< QgsSymbolLayer::Property >( OLD_PROPS.value( propertyName ) );
358 
359  if ( type() == QgsSymbol::Line )
360  {
361  //these keys had different meaning for line symbol layers
362  if ( propertyName == QLatin1String( "width" ) )
364  else if ( propertyName == QLatin1String( "color" ) )
366  }
367 
368  setDataDefinedProperty( key, prop );
369  }
370 }
371 
373 {
374  if ( !destLayer )
375  return;
376 
378 }
379 
381 {
382  if ( !destLayer || !mPaintEffect )
383  return;
384 
385  destLayer->setPaintEffect( mPaintEffect->clone() );
386 }
387 
389  : QgsSymbolLayer( QgsSymbol::Marker, locked )
390 {
391 
392 }
393 
395  : QgsSymbolLayer( QgsSymbol::Line, locked )
396 {
397 }
398 
400 {
401  return mRingFilter;
402 }
403 
405 {
406  mRingFilter = filter;
407 }
408 
410  : QgsSymbolLayer( QgsSymbol::Fill, locked )
411 {
412 }
413 
415 {
416  Q_UNUSED( context );
417 }
418 
420 {
421  startRender( context );
422  QgsPaintEffect *effect = paintEffect();
423  if ( effect && effect->enabled() )
424  {
425  QgsEffectPainter p( context.renderContext(), effect );
426  renderPoint( QPointF( size.width() / 2, size.height() / 2 ), context );
427  }
428  else
429  {
430  renderPoint( QPointF( size.width() / 2, size.height() / 2 ), context );
431  }
432  stopRender( context );
433 }
434 
435 void QgsMarkerSymbolLayer::markerOffset( QgsSymbolRenderContext &context, double &offsetX, double &offsetY ) const
436 {
437  markerOffset( context, mSize, mSize, mSizeUnit, mSizeUnit, offsetX, offsetY, mSizeMapUnitScale, mSizeMapUnitScale );
438 }
439 
440 void QgsMarkerSymbolLayer::markerOffset( QgsSymbolRenderContext &context, double width, double height, double &offsetX, double &offsetY ) const
441 {
442  markerOffset( context, width, height, mSizeUnit, mSizeUnit, offsetX, offsetY, mSizeMapUnitScale, mSizeMapUnitScale );
443 }
444 
445 void QgsMarkerSymbolLayer::markerOffset( QgsSymbolRenderContext &context, double width, double height,
447  double &offsetX, double &offsetY, const QgsMapUnitScale &widthMapUnitScale, const QgsMapUnitScale &heightMapUnitScale ) const
448 {
449  offsetX = mOffset.x();
450  offsetY = mOffset.y();
451 
453  {
456  if ( exprVal.isValid() )
457  {
458  QPointF offset = QgsSymbolLayerUtils::decodePoint( exprVal.toString() );
459  offsetX = offset.x();
460  offsetY = offset.y();
461  }
462  }
463 
464  offsetX = context.renderContext().convertToPainterUnits( offsetX, mOffsetUnit, mOffsetMapUnitScale );
465  offsetY = context.renderContext().convertToPainterUnits( offsetY, mOffsetUnit, mOffsetMapUnitScale );
466 
467  HorizontalAnchorPoint horizontalAnchorPoint = mHorizontalAnchorPoint;
468  VerticalAnchorPoint verticalAnchorPoint = mVerticalAnchorPoint;
470  {
472  if ( exprVal.isValid() )
473  {
474  horizontalAnchorPoint = decodeHorizontalAnchorPoint( exprVal.toString() );
475  }
476  }
478  {
480  if ( exprVal.isValid() )
481  {
482  verticalAnchorPoint = decodeVerticalAnchorPoint( exprVal.toString() );
483  }
484  }
485 
486  //correct horizontal position according to anchor point
487  if ( horizontalAnchorPoint == HCenter && verticalAnchorPoint == VCenter )
488  {
489  return;
490  }
491 
492  double anchorPointCorrectionX = context.renderContext().convertToPainterUnits( width, widthUnit, widthMapUnitScale ) / 2.0;
493  double anchorPointCorrectionY = context.renderContext().convertToPainterUnits( height, heightUnit, heightMapUnitScale ) / 2.0;
494  if ( horizontalAnchorPoint == Left )
495  {
496  offsetX += anchorPointCorrectionX;
497  }
498  else if ( horizontalAnchorPoint == Right )
499  {
500  offsetX -= anchorPointCorrectionX;
501  }
502 
503  //correct vertical position according to anchor point
504  if ( verticalAnchorPoint == Top )
505  {
506  offsetY += anchorPointCorrectionY;
507  }
508  else if ( verticalAnchorPoint == Bottom )
509  {
510  offsetY -= anchorPointCorrectionY;
511  }
512 }
513 
514 QPointF QgsMarkerSymbolLayer::_rotatedOffset( QPointF offset, double angle )
515 {
516  angle = DEG2RAD( angle );
517  double c = std::cos( angle ), s = std::sin( angle );
518  return QPointF( offset.x() * c - offset.y() * s, offset.x() * s + offset.y() * c );
519 }
520 
521 QgsMarkerSymbolLayer::HorizontalAnchorPoint QgsMarkerSymbolLayer::decodeHorizontalAnchorPoint( const QString &str )
522 {
523  if ( str.compare( QLatin1String( "left" ), Qt::CaseInsensitive ) == 0 )
524  {
526  }
527  else if ( str.compare( QLatin1String( "right" ), Qt::CaseInsensitive ) == 0 )
528  {
530  }
531  else
532  {
534  }
535 }
536 
537 QgsMarkerSymbolLayer::VerticalAnchorPoint QgsMarkerSymbolLayer::decodeVerticalAnchorPoint( const QString &str )
538 {
539  if ( str.compare( QLatin1String( "top" ), Qt::CaseInsensitive ) == 0 )
540  {
542  }
543  else if ( str.compare( QLatin1String( "bottom" ), Qt::CaseInsensitive ) == 0 )
544  {
546  }
547  else
548  {
550  }
551 }
552 
554 {
555  mSizeUnit = unit;
556  mOffsetUnit = unit;
557 }
558 
560 {
561  if ( mOffsetUnit != mSizeUnit )
562  {
564  }
565  return mOffsetUnit;
566 }
567 
569 {
570  mSizeMapUnitScale = scale;
571  mOffsetMapUnitScale = scale;
572 }
573 
575 {
576  if ( mSizeMapUnitScale == mOffsetMapUnitScale )
577  {
578  return mSizeMapUnitScale;
579  }
580  return QgsMapUnitScale();
581 }
582 
584 {
585  mWidthUnit = unit;
586 }
587 
589 {
590  return mWidthUnit;
591 }
592 
594 {
595  mWidthMapUnitScale = scale;
596 }
597 
599 {
600  return mWidthMapUnitScale;
601 }
602 
603 
605 {
606  QPolygonF points;
607  // we're adding 0.5 to get rid of blurred preview:
608  // drawing antialiased lines of width 1 at (x,0)-(x,100) creates 2px line
609  points << QPointF( 0, int( size.height() / 2 ) + 0.5 ) << QPointF( size.width(), int( size.height() / 2 ) + 0.5 );
610 
611  startRender( context );
612  QgsPaintEffect *effect = paintEffect();
613  if ( effect && effect->enabled() )
614  {
615  QgsEffectPainter p( context.renderContext(), effect );
616  renderPolyline( points, context );
617  }
618  else
619  {
620  renderPolyline( points, context );
621  }
622  stopRender( context );
623 }
624 
625 void QgsLineSymbolLayer::renderPolygonStroke( const QPolygonF &points, QList<QPolygonF> *rings, QgsSymbolRenderContext &context )
626 {
627  switch ( mRingFilter )
628  {
629  case AllRings:
630  case ExteriorRingOnly:
631  renderPolyline( points, context );
632  break;
633  case InteriorRingsOnly:
634  break;
635  }
636 
637  if ( rings )
638  {
639  switch ( mRingFilter )
640  {
641  case AllRings:
642  case InteriorRingsOnly:
643  {
644  for ( const QPolygonF &ring : qgis::as_const( *rings ) )
645  renderPolyline( ring, context );
646  }
647  break;
648  case ExteriorRingOnly:
649  break;
650  }
651  }
652 }
653 
654 double QgsLineSymbolLayer::width( const QgsRenderContext &context ) const
655 {
656  return context.convertToPainterUnits( mWidth, mWidthUnit, mWidthMapUnitScale );
657 }
658 
660 {
661  Q_UNUSED( context );
662  return width() * e.mapUnitScaleFactor( e.symbologyScale(), widthUnit(), e.mapUnits(), context.renderContext().mapToPixel().mapUnitsPerPixel() );
663 }
664 
665 
667 {
668  QPolygonF poly = QRectF( QPointF( 0, 0 ), QPointF( size.width(), size.height() ) );
669  startRender( context );
670  QgsPaintEffect *effect = paintEffect();
671  if ( effect && effect->enabled() )
672  {
673  QgsEffectPainter p( context.renderContext(), effect );
674  renderPolygon( poly, nullptr, context );
675  }
676  else
677  {
678  renderPolygon( poly, nullptr, context );
679  }
680  stopRender( context );
681 }
682 
683 void QgsFillSymbolLayer::_renderPolygon( QPainter *p, const QPolygonF &points, const QList<QPolygonF> *rings, QgsSymbolRenderContext &context )
684 {
685  if ( !p )
686  {
687  return;
688  }
689 
690  // Disable 'Antialiasing' if the geometry was generalized in the current RenderContext (We known that it must have least #5 points).
691  if ( points.size() <= 5 &&
694  ( p->renderHints() & QPainter::Antialiasing ) )
695  {
696  p->setRenderHint( QPainter::Antialiasing, false );
697  p->drawRect( points.boundingRect() );
698  p->setRenderHint( QPainter::Antialiasing, true );
699  return;
700  }
701 
702  // polygons outlines are sometimes rendered wrongly with drawPolygon, when
703  // clipped (see #13343), so use drawPath instead.
704  if ( !rings && p->pen().style() == Qt::NoPen )
705  {
706  // simple polygon without holes
707  p->drawPolygon( points );
708  }
709  else
710  {
711  // polygon with holes must be drawn using painter path
712  QPainterPath path;
713  path.addPolygon( points );
714 
715  if ( rings )
716  {
717  QList<QPolygonF>::const_iterator it = rings->constBegin();
718  for ( ; it != rings->constEnd(); ++it )
719  {
720  QPolygonF ring = *it;
721  path.addPolygon( ring );
722  }
723  }
724 
725  p->drawPath( path );
726  }
727 }
728 
729 void QgsMarkerSymbolLayer::toSld( QDomDocument &doc, QDomElement &element, const QgsStringMap &props ) const
730 {
731  QDomElement symbolizerElem = doc.createElement( QStringLiteral( "se:PointSymbolizer" ) );
732  if ( !props.value( QStringLiteral( "uom" ), QString() ).isEmpty() )
733  symbolizerElem.setAttribute( QStringLiteral( "uom" ), props.value( QStringLiteral( "uom" ), QString() ) );
734  element.appendChild( symbolizerElem );
735 
736  // <Geometry>
737  QgsSymbolLayerUtils::createGeometryElement( doc, symbolizerElem, props.value( QStringLiteral( "geom" ), QString() ) );
738 
739  writeSldMarker( doc, symbolizerElem, props );
740 }
741 
742 
void setProperty(int key, const QgsProperty &property)
Adds a property to the collection and takes ownership of it.
QgsMapUnitScale mapUnitScale() const override
Gradient reference point 1 is centroid.
QgsLineSymbolLayer(bool locked=false)
float threshold() const
Gets the simplification threshold of the vector layer managed.
void setMapUnitScale(const QgsMapUnitScale &scale) override
Gradient reference point 1 x.
QgsUnitTypes::RenderUnit outputUnit() const override
Returns the units to use for sizes and widths within the symbol layer.
virtual Qt::PenStyle dxfPenStyle() const
Gets pen style.
double symbologyScale() const
Returns the reference scale for output.
Definition: qgsdxfexport.h:150
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
RenderRingFilter ringFilter() const
Returns the line symbol layer&#39;s ring filter, which controls which rings are rendered when the line sy...
const QgsVectorSimplifyMethod & vectorSimplifyMethod() const
Added in QGIS v2.4.
virtual bool isCompatibleWithSymbol(QgsSymbol *symbol) const
Returns if the layer can be used below the specified symbol.
Align to right side of symbol.
virtual void prepareExpressions(const QgsSymbolRenderContext &context)
Prepares all data defined property expressions for evaluation.
double convertToPainterUnits(double size, QgsUnitTypes::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale()) const
Converts a size from the specified units to painter units (pixels).
void startRender(QgsSymbolRenderContext &context) override
virtual double dxfOffset(const QgsDxfExport &e, QgsSymbolRenderContext &context) const
Gets offset.
static QgsProperty fromField(const QString &fieldName, bool isActive=true)
Returns a new FieldBasedProperty created from the specified field name.
static QPointF decodePoint(const QString &string)
Decodes a QSizeF from a string.
#define DEG2RAD(x)
bool enabled() const
Returns whether the effect is enabled.
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 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
virtual QVector< qreal > dxfCustomDashPattern(QgsUnitTypes::RenderUnit &unit) const
Gets dash pattern.
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:577
static QString encodePoint(QPointF point)
Encodes a QPointF to a string.
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
virtual QgsPaintEffect * clone() const =0
Duplicates an effect by creating a deep copy of the effect.
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)
double angle() const
QgsSymbolLayer(QgsSymbol::SymbolType type, bool locked=false)
void markerOffset(QgsSymbolRenderContext &context, double &offsetX, double &offsetY) const
Calculates the required marker offset, including both the symbol offset and any displacement required...
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:1091
bool prepare(const QgsExpressionContext &context=QgsExpressionContext()) const override
Prepares the collection against a specified expression context.
virtual QColor dxfBrushColor(QgsSymbolRenderContext &context) const
Gets brush/fill color.
void setEnabled(bool enabled)
Sets whether the effect is enabled.
Align to bottom of symbol.
QgsUnitTypes::DistanceUnit mapUnits() const
Retrieve map units.
void copyDataDefinedProperties(QgsSymbolLayer *destLayer) const
Copies all data defined properties of this layer to another symbol layer.
static QgsPaintEffect * defaultStack()
Returns a new effect stack consisting of a sensible selection of default effects. ...
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 bool hasDataDefinedProperties() const
Returns true if the symbol layer (or any of its sub-symbols) contains data defined properties...
QgsSymbol::SymbolType type() const
QgsPropertyCollection & dataDefinedProperties()
Returns a reference to the symbol layer&#39;s property collection, used for data defined overrides...
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
Filename, eg for svg files.
Align to left side of symbol.
void drawPreviewIcon(QgsSymbolRenderContext &context, QSize size) override
Shapeburst fill from edge distance.
double mapUnitsPerPixel() const
Returns current map units per pixel.
void setPaintEffect(QgsPaintEffect *effect)
Sets the current paint effect for the layer.
virtual bool writeDxf(QgsDxfExport &e, double mmMapUnitScaleFactor, const QString &layerName, QgsSymbolRenderContext &context, QPointF shift=QPointF(0.0, 0.0)) const
write as DXF
Character, eg for font marker symbol layers.
Align to top of symbol.
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:572
RenderRingFilter
Options for filtering rings when the line symbol layer is being used to render a polygon&#39;s rings...
Definition for a property.
Definition: qgsproperty.h:46
HorizontalAnchorPoint
Symbol horizontal anchor points.
Gradient reference point 1 y.
QMap< int, QgsPropertyDefinition > QgsPropertiesDefinition
Definition of available properties.
VerticalAnchorPoint
Symbol vertical anchor points.
static void createGeometryElement(QDomDocument &doc, QDomElement &element, const QString &geomFunc)
QgsFields fields() const
Fields of the layer.
Definition: qgssymbol.h:653
QgsExpressionContext & expressionContext()
Gets the expression context.
virtual double width() const
Returns the estimated width for the line symbol layer.
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
Contains information about the context of a rendering operation.
virtual double dxfAngle(QgsSymbolRenderContext &context) const
Gets angle.
RenderRingFilter mRingFilter
Property requires a string value.
Definition: qgsproperty.h:91
Struct for storing maximum and minimum scales for measurements in map units.
virtual void stopRender(QgsSymbolRenderContext &context)=0
void setMapUnitScale(const QgsMapUnitScale &scale) override
QgsMarkerSymbolLayer(bool locked=false)
Constructor for QgsMarkerSymbolLayer.
QgsPaintEffect * mPaintEffect
virtual QSet< QString > usedAttributes(const QgsRenderContext &context) const
Returns the set of attributes referenced by the layer.
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...
QgsPaintEffect * paintEffect() const
Returns the current paint effect for the layer.
SimplifyHints simplifyHints() const
Gets the simplification hints of the vector layer managed.
virtual double dxfWidth(const QgsDxfExport &e, QgsSymbolRenderContext &context) const
Gets line width.
SymbolType type() const
Returns the symbol&#39;s type.
Definition: qgssymbol.h:120
Align to vertical center of symbol.
Secondary color (eg for gradient fills)
bool mEnabled
True if layer is enabled and should be drawn.
Horizontal anchor point.
Definition: qgsproperty.h:75
virtual ~QgsSymbolLayer()
const QgsMapToPixel & mapToPixel() const
Returns the context&#39;s map to pixel transform, which transforms between map coordinates and device coo...
virtual void renderPolygonStroke(const QPolygonF &points, QList< QPolygonF > *rings, QgsSymbolRenderContext &context)
bool hasActiveProperties() const override
Returns true if the collection has any active properties, or false if all properties within the colle...
QgsFillSymbolLayer(bool locked=false)
void copyPaintEffect(QgsSymbolLayer *destLayer) const
Copies paint effect of this layer to another symbol layer.
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.
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)
bool isEmpty() const
Checks whether the container is empty.
Definition: qgsfields.cpp:128
virtual QColor color() const
The fill color.
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.
virtual Qt::BrushStyle dxfBrushStyle() const
Gets brush/fill style.
RenderUnit
Rendering size units.
Definition: qgsunittypes.h:110
virtual void setDataDefinedProperty(Property key, const QgsProperty &property)
Sets a data defined property for the layer.
virtual void startRender(QgsSymbolRenderContext &context)=0
Horizontal distance between points.
virtual QColor dxfColor(QgsSymbolRenderContext &context) const
Gets color.
void drawPreviewIcon(QgsSymbolRenderContext &context, QSize size) override
Vertical distance between points.
Double value between 0-1 (inclusive)
Definition: qgsproperty.h:59