QGIS API Documentation  3.4.3-Madeira (2f64a3c)
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 {
198  QgsSymbolLayer::initPropertyDefinitions();
199  return sPropertyDefinitions;
200 }
201 
203 {
204  delete mPaintEffect;
205 }
206 
208 {
209  if ( symbol->type() == QgsSymbol::Fill && mType == QgsSymbol::Line )
210  return true;
211 
212  return symbol->type() == mType;
213 }
214 
215 QSet<QString> QgsSymbolLayer::usedAttributes( const QgsRenderContext &context ) const
216 {
217  QSet<QString> columns = mDataDefinedProperties.referencedFields( context.expressionContext() );
218  return columns;
219 }
220 
221 QgsProperty propertyFromMap( const QgsStringMap &map, const QString &baseName )
222 {
223  QString prefix;
224  if ( !baseName.isEmpty() )
225  {
226  prefix.append( QStringLiteral( "%1_dd_" ).arg( baseName ) );
227  }
228 
229  if ( !map.contains( QStringLiteral( "%1expression" ).arg( prefix ) ) )
230  {
231  //requires at least the expression value
232  return QgsProperty();
233  }
234 
235  bool active = ( map.value( QStringLiteral( "%1active" ).arg( prefix ), QStringLiteral( "1" ) ) != QLatin1String( "0" ) );
236  QString expression = map.value( QStringLiteral( "%1expression" ).arg( prefix ) );
237  bool useExpression = ( map.value( QStringLiteral( "%1useexpr" ).arg( prefix ), QStringLiteral( "1" ) ) != QLatin1String( "0" ) );
238  QString field = map.value( QStringLiteral( "%1field" ).arg( prefix ), QString() );
239 
240  if ( useExpression )
241  return QgsProperty::fromExpression( expression, active );
242  else
243  return QgsProperty::fromField( field, active );
244 }
245 
246 // property string to type upgrade map
247 static const QMap< QString, QgsSymbolLayer::Property > OLD_PROPS
248 {
250  { "arrow_width", QgsSymbolLayer::PropertyArrowWidth },
251  { "arrow_start_width", QgsSymbolLayer::PropertyArrowStartWidth },
252  { "head_length", QgsSymbolLayer::PropertyArrowHeadLength },
253  { "head_thickness", QgsSymbolLayer::PropertyArrowHeadThickness },
254  { "offset", QgsSymbolLayer::PropertyOffset },
255  { "head_type", QgsSymbolLayer::PropertyArrowHeadType },
256  { "arrow_type", QgsSymbolLayer::PropertyArrowType },
257  { "width_field", QgsSymbolLayer::PropertyWidth },
258  { "height_field", QgsSymbolLayer::PropertyHeight },
259  { "rotation_field", QgsSymbolLayer::PropertyAngle },
260  { "outline_width_field", QgsSymbolLayer::PropertyStrokeWidth },
261  { "fill_color_field", QgsSymbolLayer::PropertyFillColor },
262  { "outline_color_field", QgsSymbolLayer::PropertyStrokeColor },
263  { "symbol_name_field", QgsSymbolLayer::PropertyName },
264  { "outline_width", QgsSymbolLayer::PropertyStrokeWidth },
265  { "outline_style", QgsSymbolLayer::PropertyStrokeStyle },
266  { "join_style", QgsSymbolLayer::PropertyJoinStyle },
267  { "fill_color", QgsSymbolLayer::PropertyFillColor },
268  { "outline_color", QgsSymbolLayer::PropertyStrokeColor },
269  { "width", QgsSymbolLayer::PropertyWidth },
270  { "height", QgsSymbolLayer::PropertyHeight },
271  { "symbol_name", QgsSymbolLayer::PropertyName },
272  { "angle", QgsSymbolLayer::PropertyAngle },
273  { "fill_style", QgsSymbolLayer::PropertyFillStyle },
274  { "color_border", QgsSymbolLayer::PropertyStrokeColor },
275  { "width_border", QgsSymbolLayer::PropertyStrokeWidth },
276  { "border_color", QgsSymbolLayer::PropertyStrokeColor },
277  { "border_style", QgsSymbolLayer::PropertyStrokeStyle },
279  { "gradient_type", QgsSymbolLayer::PropertyGradientType },
280  { "coordinate_mode", QgsSymbolLayer::PropertyCoordinateMode },
286  { "reference1_iscentroid", QgsSymbolLayer::PropertyGradientReference1IsCentroid },
287  { "reference2_iscentroid", QgsSymbolLayer::PropertyGradientReference2IsCentroid },
288  { "blur_radius", QgsSymbolLayer::PropertyBlurRadius },
292  { "svgFillColor", QgsSymbolLayer::PropertyFillColor },
293  { "svgOutlineColor", QgsSymbolLayer::PropertyStrokeColor },
294  { "svgOutlineWidth", QgsSymbolLayer::PropertyStrokeWidth },
295  { "svgFile", QgsSymbolLayer::PropertyFile },
296  { "lineangle", QgsSymbolLayer::PropertyLineAngle },
297  { "distance", QgsSymbolLayer::PropertyLineDistance },
298  { "distance_x", QgsSymbolLayer::PropertyDistanceX },
299  { "distance_y", QgsSymbolLayer::PropertyDistanceY },
300  { "displacement_x", QgsSymbolLayer::PropertyDisplacementX },
301  { "displacement_y", QgsSymbolLayer::PropertyDisplacementY },
302  { "file", QgsSymbolLayer::PropertyFile },
303  { "alpha", QgsSymbolLayer::PropertyOpacity },
304  { "customdash", QgsSymbolLayer::PropertyCustomDash },
305  { "line_style", QgsSymbolLayer::PropertyStrokeStyle },
306  { "joinstyle", QgsSymbolLayer::PropertyJoinStyle },
307  { "capstyle", QgsSymbolLayer::PropertyCapStyle },
308  { "placement", QgsSymbolLayer::PropertyPlacement },
309  { "interval", QgsSymbolLayer::PropertyInterval },
310  { "offset_along_line", QgsSymbolLayer::PropertyOffsetAlongLine },
311  { "name", QgsSymbolLayer::PropertyName },
312  { "size", QgsSymbolLayer::PropertySize },
317  { "rotation", QgsSymbolLayer::PropertyAngle },
318  { "horizontal_anchor_point", QgsSymbolLayer::PropertyHorizontalAnchor },
319  { "vertical_anchor_point", QgsSymbolLayer::PropertyVerticalAnchor },
320 };
321 
323 {
324  QgsStringMap::const_iterator propIt = stringMap.constBegin();
325  for ( ; propIt != stringMap.constEnd(); ++propIt )
326  {
327  QgsProperty prop;
328  QString propertyName;
329 
330  if ( propIt.key().endsWith( QLatin1String( "_dd_expression" ) ) )
331  {
332  //found a data defined property
333 
334  //get data defined property name by stripping "_dd_expression" from property key
335  propertyName = propIt.key().left( propIt.key().length() - 14 );
336 
337  prop = propertyFromMap( stringMap, propertyName );
338  }
339  else if ( propIt.key().endsWith( QLatin1String( "_expression" ) ) )
340  {
341  //old style data defined property, upgrade
342 
343  //get data defined property name by stripping "_expression" from property key
344  propertyName = propIt.key().left( propIt.key().length() - 11 );
345 
346  prop = QgsProperty::fromExpression( propIt.value() );
347  }
348 
349  if ( !prop || !OLD_PROPS.contains( propertyName ) )
350  continue;
351 
352  QgsSymbolLayer::Property key = static_cast< QgsSymbolLayer::Property >( OLD_PROPS.value( propertyName ) );
353 
354  if ( type() == QgsSymbol::Line )
355  {
356  //these keys had different meaning for line symbol layers
357  if ( propertyName == QLatin1String( "width" ) )
359  else if ( propertyName == QLatin1String( "color" ) )
361  }
362 
363  setDataDefinedProperty( key, prop );
364  }
365 }
366 
368 {
369  if ( !destLayer )
370  return;
371 
373 }
374 
376 {
377  if ( !destLayer || !mPaintEffect )
378  return;
379 
380  destLayer->setPaintEffect( mPaintEffect->clone() );
381 }
382 
384  : QgsSymbolLayer( QgsSymbol::Marker, locked )
385 {
386 
387 }
388 
390  : QgsSymbolLayer( QgsSymbol::Line, locked )
391 {
392 }
393 
395 {
396  return mRingFilter;
397 }
398 
400 {
401  mRingFilter = filter;
402 }
403 
405  : QgsSymbolLayer( QgsSymbol::Fill, locked )
406 {
407 }
408 
410 {
411  Q_UNUSED( context );
412 }
413 
415 {
416  startRender( context );
417  QgsPaintEffect *effect = paintEffect();
418  if ( effect && effect->enabled() )
419  {
420  QgsEffectPainter p( context.renderContext(), effect );
421  renderPoint( QPointF( size.width() / 2, size.height() / 2 ), context );
422  }
423  else
424  {
425  renderPoint( QPointF( size.width() / 2, size.height() / 2 ), context );
426  }
427  stopRender( context );
428 }
429 
430 void QgsMarkerSymbolLayer::markerOffset( QgsSymbolRenderContext &context, double &offsetX, double &offsetY ) const
431 {
432  markerOffset( context, mSize, mSize, mSizeUnit, mSizeUnit, offsetX, offsetY, mSizeMapUnitScale, mSizeMapUnitScale );
433 }
434 
435 void QgsMarkerSymbolLayer::markerOffset( QgsSymbolRenderContext &context, double width, double height, double &offsetX, double &offsetY ) const
436 {
437  markerOffset( context, width, height, mSizeUnit, mSizeUnit, offsetX, offsetY, mSizeMapUnitScale, mSizeMapUnitScale );
438 }
439 
440 void QgsMarkerSymbolLayer::markerOffset( QgsSymbolRenderContext &context, double width, double height,
442  double &offsetX, double &offsetY, const QgsMapUnitScale &widthMapUnitScale, const QgsMapUnitScale &heightMapUnitScale ) const
443 {
444  offsetX = mOffset.x();
445  offsetY = mOffset.y();
446 
448  {
451  if ( exprVal.isValid() )
452  {
453  QPointF offset = QgsSymbolLayerUtils::decodePoint( exprVal.toString() );
454  offsetX = offset.x();
455  offsetY = offset.y();
456  }
457  }
458 
459  offsetX = context.renderContext().convertToPainterUnits( offsetX, mOffsetUnit, mOffsetMapUnitScale );
460  offsetY = context.renderContext().convertToPainterUnits( offsetY, mOffsetUnit, mOffsetMapUnitScale );
461 
462  HorizontalAnchorPoint horizontalAnchorPoint = mHorizontalAnchorPoint;
463  VerticalAnchorPoint verticalAnchorPoint = mVerticalAnchorPoint;
465  {
467  if ( exprVal.isValid() )
468  {
469  horizontalAnchorPoint = decodeHorizontalAnchorPoint( exprVal.toString() );
470  }
471  }
473  {
475  if ( exprVal.isValid() )
476  {
477  verticalAnchorPoint = decodeVerticalAnchorPoint( exprVal.toString() );
478  }
479  }
480 
481  //correct horizontal position according to anchor point
482  if ( horizontalAnchorPoint == HCenter && verticalAnchorPoint == VCenter )
483  {
484  return;
485  }
486 
487  double anchorPointCorrectionX = context.renderContext().convertToPainterUnits( width, widthUnit, widthMapUnitScale ) / 2.0;
488  double anchorPointCorrectionY = context.renderContext().convertToPainterUnits( height, heightUnit, heightMapUnitScale ) / 2.0;
489  if ( horizontalAnchorPoint == Left )
490  {
491  offsetX += anchorPointCorrectionX;
492  }
493  else if ( horizontalAnchorPoint == Right )
494  {
495  offsetX -= anchorPointCorrectionX;
496  }
497 
498  //correct vertical position according to anchor point
499  if ( verticalAnchorPoint == Top )
500  {
501  offsetY += anchorPointCorrectionY;
502  }
503  else if ( verticalAnchorPoint == Bottom )
504  {
505  offsetY -= anchorPointCorrectionY;
506  }
507 }
508 
509 QPointF QgsMarkerSymbolLayer::_rotatedOffset( QPointF offset, double angle )
510 {
511  angle = DEG2RAD( angle );
512  double c = std::cos( angle ), s = std::sin( angle );
513  return QPointF( offset.x() * c - offset.y() * s, offset.x() * s + offset.y() * c );
514 }
515 
516 QgsMarkerSymbolLayer::HorizontalAnchorPoint QgsMarkerSymbolLayer::decodeHorizontalAnchorPoint( const QString &str )
517 {
518  if ( str.compare( QLatin1String( "left" ), Qt::CaseInsensitive ) == 0 )
519  {
521  }
522  else if ( str.compare( QLatin1String( "right" ), Qt::CaseInsensitive ) == 0 )
523  {
525  }
526  else
527  {
529  }
530 }
531 
532 QgsMarkerSymbolLayer::VerticalAnchorPoint QgsMarkerSymbolLayer::decodeVerticalAnchorPoint( const QString &str )
533 {
534  if ( str.compare( QLatin1String( "top" ), Qt::CaseInsensitive ) == 0 )
535  {
537  }
538  else if ( str.compare( QLatin1String( "bottom" ), Qt::CaseInsensitive ) == 0 )
539  {
541  }
542  else
543  {
545  }
546 }
547 
549 {
550  mSizeUnit = unit;
551  mOffsetUnit = unit;
552 }
553 
555 {
556  if ( mOffsetUnit != mSizeUnit )
557  {
559  }
560  return mOffsetUnit;
561 }
562 
564 {
565  mSizeMapUnitScale = scale;
566  mOffsetMapUnitScale = scale;
567 }
568 
570 {
571  if ( mSizeMapUnitScale == mOffsetMapUnitScale )
572  {
573  return mSizeMapUnitScale;
574  }
575  return QgsMapUnitScale();
576 }
577 
579 {
580  mWidthUnit = unit;
581 }
582 
584 {
585  return mWidthUnit;
586 }
587 
589 {
590  mWidthMapUnitScale = scale;
591 }
592 
594 {
595  return mWidthMapUnitScale;
596 }
597 
598 
600 {
601  QPolygonF points;
602  // we're adding 0.5 to get rid of blurred preview:
603  // drawing antialiased lines of width 1 at (x,0)-(x,100) creates 2px line
604  points << QPointF( 0, int( size.height() / 2 ) + 0.5 ) << QPointF( size.width(), int( size.height() / 2 ) + 0.5 );
605 
606  startRender( context );
607  QgsPaintEffect *effect = paintEffect();
608  if ( effect && effect->enabled() )
609  {
610  QgsEffectPainter p( context.renderContext(), effect );
611  renderPolyline( points, context );
612  }
613  else
614  {
615  renderPolyline( points, context );
616  }
617  stopRender( context );
618 }
619 
620 void QgsLineSymbolLayer::renderPolygonStroke( const QPolygonF &points, QList<QPolygonF> *rings, QgsSymbolRenderContext &context )
621 {
622  switch ( mRingFilter )
623  {
624  case AllRings:
625  case ExteriorRingOnly:
626  renderPolyline( points, context );
627  break;
628  case InteriorRingsOnly:
629  break;
630  }
631 
632  if ( rings )
633  {
634  switch ( mRingFilter )
635  {
636  case AllRings:
637  case InteriorRingsOnly:
638  {
639  for ( const QPolygonF &ring : qgis::as_const( *rings ) )
640  renderPolyline( ring, context );
641  }
642  break;
643  case ExteriorRingOnly:
644  break;
645  }
646  }
647 }
648 
650 {
651  Q_UNUSED( context );
652  return width() * e.mapUnitScaleFactor( e.symbologyScale(), widthUnit(), e.mapUnits(), context.renderContext().mapToPixel().mapUnitsPerPixel() );
653 }
654 
655 
657 {
658  QPolygonF poly = QRectF( QPointF( 0, 0 ), QPointF( size.width(), size.height() ) );
659  startRender( context );
660  QgsPaintEffect *effect = paintEffect();
661  if ( effect && effect->enabled() )
662  {
663  QgsEffectPainter p( context.renderContext(), effect );
664  renderPolygon( poly, nullptr, context );
665  }
666  else
667  {
668  renderPolygon( poly, nullptr, context );
669  }
670  stopRender( context );
671 }
672 
673 void QgsFillSymbolLayer::_renderPolygon( QPainter *p, const QPolygonF &points, const QList<QPolygonF> *rings, QgsSymbolRenderContext &context )
674 {
675  if ( !p )
676  {
677  return;
678  }
679 
680  // Disable 'Antialiasing' if the geometry was generalized in the current RenderContext (We known that it must have least #5 points).
681  if ( points.size() <= 5 &&
684  ( p->renderHints() & QPainter::Antialiasing ) )
685  {
686  p->setRenderHint( QPainter::Antialiasing, false );
687  p->drawRect( points.boundingRect() );
688  p->setRenderHint( QPainter::Antialiasing, true );
689  return;
690  }
691 
692  // polygons outlines are sometimes rendered wrongly with drawPolygon, when
693  // clipped (see #13343), so use drawPath instead.
694  if ( !rings && p->pen().style() == Qt::NoPen )
695  {
696  // simple polygon without holes
697  p->drawPolygon( points );
698  }
699  else
700  {
701  // polygon with holes must be drawn using painter path
702  QPainterPath path;
703  path.addPolygon( points );
704 
705  if ( rings )
706  {
707  QList<QPolygonF>::const_iterator it = rings->constBegin();
708  for ( ; it != rings->constEnd(); ++it )
709  {
710  QPolygonF ring = *it;
711  path.addPolygon( ring );
712  }
713  }
714 
715  p->drawPath( path );
716  }
717 }
718 
719 void QgsMarkerSymbolLayer::toSld( QDomDocument &doc, QDomElement &element, const QgsStringMap &props ) const
720 {
721  QDomElement symbolizerElem = doc.createElement( QStringLiteral( "se:PointSymbolizer" ) );
722  if ( !props.value( QStringLiteral( "uom" ), QString() ).isEmpty() )
723  symbolizerElem.setAttribute( QStringLiteral( "uom" ), props.value( QStringLiteral( "uom" ), QString() ) );
724  element.appendChild( symbolizerElem );
725 
726  // <Geometry>
727  QgsSymbolLayerUtils::createGeometryElement( doc, symbolizerElem, props.value( QStringLiteral( "geom" ), QString() ) );
728 
729  writeSldMarker( doc, symbolizerElem, props );
730 }
731 
732 
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.
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.
double symbologyScale() const
Returns the reference scale for output.
Definition: qgsdxfexport.h:150
QgsLineSymbolLayer(bool locked=false)
void setMapUnitScale(const QgsMapUnitScale &scale) override
const QgsVectorSimplifyMethod & vectorSimplifyMethod() const
Added in QGIS v2.4.
Gradient reference point 1 x.
QgsFields fields() const
Fields of the layer.
Definition: qgssymbol.h:653
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
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)
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.
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:570
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)
QgsSymbolLayer(QgsSymbol::SymbolType type, bool locked=false)
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:1097
bool prepare(const QgsExpressionContext &context=QgsExpressionContext()) const override
Prepares the collection against a specified expression context.
void setEnabled(bool enabled)
Sets whether the effect is enabled.
Align to bottom of symbol.
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;...
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.
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: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.
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.
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
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.
QgsMarkerSymbolLayer(bool locked=false)
Constructor for QgsMarkerSymbolLayer.
virtual QColor dxfColor(QgsSymbolRenderContext &context) const
Gets color.
QgsPaintEffect * mPaintEffect
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
Check whether the container is empty.
Definition: qgsfields.cpp:110
bool mEnabled
True if layer is enabled and should be drawn.
Horizontal anchor point.
Definition: qgsproperty.h:75
virtual ~QgsSymbolLayer()
virtual void renderPolygonStroke(const QPolygonF &points, QList< QPolygonF > *rings, QgsSymbolRenderContext &context)
QgsFillSymbolLayer(bool locked=false)
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:110
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