QGIS API Documentation  3.0.2-Girona (307d082)
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 
29 #include <QSize>
30 #include <QPainter>
31 #include <QPointF>
32 #include <QPolygonF>
33 
34 QgsPropertiesDefinition QgsSymbolLayer::sPropertyDefinitions;
35 
36 void QgsSymbolLayer::initPropertyDefinitions()
37 {
38  if ( !sPropertyDefinitions.isEmpty() )
39  return;
40 
41  QString origin = QStringLiteral( "symbol" );
42 
43  sPropertyDefinitions = QgsPropertiesDefinition
44  {
45  { QgsSymbolLayer::PropertySize, QgsPropertyDefinition( "size", QObject::tr( "Symbol size" ), QgsPropertyDefinition::Size, origin ) },
46  { QgsSymbolLayer::PropertyAngle, QgsPropertyDefinition( "angle", QObject::tr( "Rotation angle" ), QgsPropertyDefinition::Rotation, origin ) },
47  { QgsSymbolLayer::PropertyName, QgsPropertyDefinition( "name", QObject::tr( "Symbol name" ), QgsPropertyDefinition::String, origin ) },
48  { QgsSymbolLayer::PropertyFillColor, QgsPropertyDefinition( "fillColor", QObject::tr( "Symbol fill color" ), QgsPropertyDefinition::ColorWithAlpha, origin ) },
49  { QgsSymbolLayer::PropertyStrokeColor, QgsPropertyDefinition( "outlineColor", QObject::tr( "Symbol stroke color" ), QgsPropertyDefinition::ColorWithAlpha, origin ) },
50  { QgsSymbolLayer::PropertyStrokeWidth, QgsPropertyDefinition( "outlineWidth", QObject::tr( "Symbol stroke width" ), QgsPropertyDefinition::StrokeWidth, origin ) },
51  { QgsSymbolLayer::PropertyStrokeStyle, QgsPropertyDefinition( "outlineStyle", QObject::tr( "Symbol stroke style" ), QgsPropertyDefinition::LineStyle, origin )},
52  { QgsSymbolLayer::PropertyOffset, QgsPropertyDefinition( "offset", QObject::tr( "Symbol offset" ), QgsPropertyDefinition::Offset, origin )},
53  { QgsSymbolLayer::PropertyCharacter, QgsPropertyDefinition( "char", QObject::tr( "Marker character(s)" ), QgsPropertyDefinition::String, origin )},
54  { QgsSymbolLayer::PropertyWidth, QgsPropertyDefinition( "width", QObject::tr( "Symbol width" ), QgsPropertyDefinition::DoublePositive, origin )},
55  { QgsSymbolLayer::PropertyHeight, QgsPropertyDefinition( "height", QObject::tr( "Symbol height" ), QgsPropertyDefinition::DoublePositive, origin )},
56  { QgsSymbolLayer::PropertyPreserveAspectRatio, QgsPropertyDefinition( "preserveAspectRatio", QObject::tr( "Preserve aspect ratio between width and height" ), QgsPropertyDefinition::Boolean, origin )},
57  { QgsSymbolLayer::PropertyFillStyle, QgsPropertyDefinition( "fillStyle", QObject::tr( "Symbol fill style" ), QgsPropertyDefinition::FillStyle, origin )},
58  { QgsSymbolLayer::PropertyJoinStyle, QgsPropertyDefinition( "joinStyle", QObject::tr( "Outline join style" ), QgsPropertyDefinition::PenJoinStyle, origin )},
59  { QgsSymbolLayer::PropertySecondaryColor, QgsPropertyDefinition( "color2", QObject::tr( "Secondary fill color" ), QgsPropertyDefinition::ColorWithAlpha, origin )},
60  { QgsSymbolLayer::PropertyLineAngle, QgsPropertyDefinition( "lineAngle", QObject::tr( "Angle for line fills" ), QgsPropertyDefinition::Rotation, origin )},
61  { QgsSymbolLayer::PropertyGradientType, QgsPropertyDefinition( "gradientType", QgsPropertyDefinition::DataTypeString, QObject::tr( "Gradient type" ), QObject::tr( "string " ) + QLatin1String( "[<b>linear</b>|<b>radial</b>|<b>conical</b>]" ), origin )},
62  { QgsSymbolLayer::PropertyCoordinateMode, QgsPropertyDefinition( "gradientMode", QgsPropertyDefinition::DataTypeString, QObject::tr( "Gradient mode" ), QObject::tr( "string " ) + QLatin1String( "[<b>feature</b>|<b>viewport</b>]" ), origin )},
63  { QgsSymbolLayer::PropertyGradientSpread, QgsPropertyDefinition( "gradientSpread", QgsPropertyDefinition::DataTypeString, QObject::tr( "Gradient spread" ), QObject::tr( "string " ) + QLatin1String( "[<b>pad</b>|<b>repeat</b>|<b>reflect</b>]" ), origin )},
64  { QgsSymbolLayer::PropertyGradientReference1X, QgsPropertyDefinition( "gradientRef1X", QObject::tr( "Reference point 1 (X)" ), QgsPropertyDefinition::Double0To1, origin )},
65  { QgsSymbolLayer::PropertyGradientReference1Y, QgsPropertyDefinition( "gradientRef1Y", QObject::tr( "Reference point 1 (Y)" ), QgsPropertyDefinition::Double0To1, origin )},
66  { QgsSymbolLayer::PropertyGradientReference2X, QgsPropertyDefinition( "gradientRef2X", QObject::tr( "Reference point 2 (X)" ), QgsPropertyDefinition::Double0To1, origin )},
67  { QgsSymbolLayer::PropertyGradientReference2Y, QgsPropertyDefinition( "gradientRef2Y", QObject::tr( "Reference point 2 (Y)" ), QgsPropertyDefinition::Double0To1, origin )},
68  { QgsSymbolLayer::PropertyGradientReference1IsCentroid, QgsPropertyDefinition( "gradientRef1Centroid", QObject::tr( "Reference point 1 follows feature centroid" ), QgsPropertyDefinition::Boolean, origin )},
69  { QgsSymbolLayer::PropertyGradientReference2IsCentroid, QgsPropertyDefinition( "gradientRef2Centroid", QObject::tr( "Reference point 2 follows feature centroid" ), QgsPropertyDefinition::Boolean, origin )},
70  { QgsSymbolLayer::PropertyBlurRadius, QgsPropertyDefinition( "blurRadius", QgsPropertyDefinition::DataTypeNumeric, QObject::tr( "Blur radius" ), QObject::tr( "Integer between 0 and 18" ), origin )},
71  { QgsSymbolLayer::PropertyLineDistance, QgsPropertyDefinition( "lineDistance", QObject::tr( "Distance between lines" ), QgsPropertyDefinition::DoublePositive, origin )},
72  { QgsSymbolLayer::PropertyShapeburstUseWholeShape, QgsPropertyDefinition( "shapeburstWholeShape", QObject::tr( "Shade whole shape" ), QgsPropertyDefinition::Boolean, origin )},
73  { QgsSymbolLayer::PropertyShapeburstMaxDistance, QgsPropertyDefinition( "shapeburstMaxDist", QObject::tr( "Maximum distance for shapeburst fill" ), QgsPropertyDefinition::DoublePositive, origin )},
74  { QgsSymbolLayer::PropertyShapeburstIgnoreRings, QgsPropertyDefinition( "shapeburstIgnoreRings", QObject::tr( "Ignore rings in feature" ), QgsPropertyDefinition::Boolean, origin )},
75  { QgsSymbolLayer::PropertyFile, QgsPropertyDefinition( "file", QObject::tr( "Symbol file path" ), QgsPropertyDefinition::String, origin )},
76  { QgsSymbolLayer::PropertyDistanceX, QgsPropertyDefinition( "distanceX", QObject::tr( "Horizontal distance between markers" ), QgsPropertyDefinition::DoublePositive, origin )},
77  { QgsSymbolLayer::PropertyDistanceY, QgsPropertyDefinition( "distanceY", QObject::tr( "Vertical distance between markers" ), QgsPropertyDefinition::DoublePositive, origin )},
78  { QgsSymbolLayer::PropertyDisplacementX, QgsPropertyDefinition( "displacementX", QObject::tr( "Horizontal displacement between rows" ), QgsPropertyDefinition::DoublePositive, origin )},
79  { QgsSymbolLayer::PropertyDisplacementY, QgsPropertyDefinition( "displacementY", QObject::tr( "Vertical displacement between columns" ), QgsPropertyDefinition::DoublePositive, origin )},
80  { QgsSymbolLayer::PropertyOpacity, QgsPropertyDefinition( "alpha", QObject::tr( "Opacity" ), QgsPropertyDefinition::Opacity, origin )},
81  { QgsSymbolLayer::PropertyCustomDash, QgsPropertyDefinition( "customDash", QgsPropertyDefinition::DataTypeString, QObject::tr( "Custom dash pattern" ), QObject::tr( "[<b><dash>;<space></b>] e.g. '8;2;1;2'" ), origin )},
82  { QgsSymbolLayer::PropertyCapStyle, QgsPropertyDefinition( "capStyle", QObject::tr( "Line cap style" ), QgsPropertyDefinition::CapStyle, origin )},
83  { 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 )},
84  { QgsSymbolLayer::PropertyInterval, QgsPropertyDefinition( "interval", QObject::tr( "Marker interval" ), QgsPropertyDefinition::DoublePositive, origin )},
85  { QgsSymbolLayer::PropertyOffsetAlongLine, QgsPropertyDefinition( "offsetAlongLine", QObject::tr( "Offset along line" ), QgsPropertyDefinition::DoublePositive, origin )},
86  { QgsSymbolLayer::PropertyHorizontalAnchor, QgsPropertyDefinition( "hAnchor", QObject::tr( "Horizontal anchor point" ), QgsPropertyDefinition::HorizontalAnchor, origin )},
87  { QgsSymbolLayer::PropertyVerticalAnchor, QgsPropertyDefinition( "vAnchor", QObject::tr( "Vertical anchor point" ), QgsPropertyDefinition::VerticalAnchor, origin )},
88  { QgsSymbolLayer::PropertyLayerEnabled, QgsPropertyDefinition( "enabled", QObject::tr( "Layer enabled" ), QgsPropertyDefinition::Boolean, origin )},
89  { QgsSymbolLayer::PropertyArrowWidth, QgsPropertyDefinition( "arrowWidth", QObject::tr( "Arrow line width" ), QgsPropertyDefinition::StrokeWidth, origin )},
90  { QgsSymbolLayer::PropertyArrowStartWidth, QgsPropertyDefinition( "arrowStartWidth", QObject::tr( "Arrow line start width" ), QgsPropertyDefinition::StrokeWidth, origin )},
91  { QgsSymbolLayer::PropertyArrowHeadLength, QgsPropertyDefinition( "arrowHeadLength", QObject::tr( "Arrow head length" ), QgsPropertyDefinition::DoublePositive, origin )},
92  { QgsSymbolLayer::PropertyArrowHeadThickness, QgsPropertyDefinition( "arrowHeadThickness", QObject::tr( "Arrow head thickness" ), QgsPropertyDefinition::DoublePositive, origin )},
93  { QgsSymbolLayer::PropertyArrowHeadType, QgsPropertyDefinition( "arrowHeadType", QObject::tr( "Arrow head type" ), QgsPropertyDefinition::IntegerPositive, origin )},
94  { QgsSymbolLayer::PropertyArrowType, QgsPropertyDefinition( "arrowType", QObject::tr( "Arrow type" ), QgsPropertyDefinition::IntegerPositive, origin )},
95 
96  };
97 }
98 
100 {
101  dataDefinedProperties().setProperty( key, property );
102 }
103 
104 bool QgsSymbolLayer::writeDxf( QgsDxfExport &e, double mmMapUnitScaleFactor, const QString &layerName, QgsSymbolRenderContext &context, QPointF shift ) const
105 {
106  Q_UNUSED( e );
107  Q_UNUSED( mmMapUnitScaleFactor );
108  Q_UNUSED( layerName );
109  Q_UNUSED( context );
110  Q_UNUSED( shift );
111  return false;
112 }
113 
115 {
116  Q_UNUSED( e );
117  Q_UNUSED( context );
118  return 1.0;
119 }
120 
122 {
123  Q_UNUSED( e );
124  Q_UNUSED( context );
125  return 0.0;
126 }
127 
129 {
130  Q_UNUSED( context );
131  return color();
132 }
133 
135 {
136  Q_UNUSED( context );
137  return 0.0;
138 }
139 
141 {
142  Q_UNUSED( unit );
143  return QVector<qreal>();
144 }
145 
146 Qt::PenStyle QgsSymbolLayer::dxfPenStyle() const
147 {
148  return Qt::SolidLine;
149 }
150 
152 {
153  Q_UNUSED( context );
154  return color();
155 }
156 
157 Qt::BrushStyle QgsSymbolLayer::dxfBrushStyle() const
158 {
159  return Qt::NoBrush;
160 }
161 
163 {
164  return mPaintEffect;
165 }
166 
168 {
169  delete mPaintEffect;
170  mPaintEffect = effect;
171 }
172 
174  : mType( type )
175  , mEnabled( true )
176  , mLocked( locked )
177  , mRenderingPass( 0 )
178 
179 {
181  mPaintEffect->setEnabled( false );
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 {
197  QgsSymbolLayer::initPropertyDefinitions();
198  return sPropertyDefinitions;
199 }
200 
202 {
203  delete mPaintEffect;
204 }
205 
207 {
208  if ( symbol->type() == QgsSymbol::Fill && mType == QgsSymbol::Line )
209  return true;
210 
211  return symbol->type() == mType;
212 }
213 
214 QSet<QString> QgsSymbolLayer::usedAttributes( const QgsRenderContext &context ) const
215 {
216  QSet<QString> columns = mDataDefinedProperties.referencedFields( context.expressionContext() );
217  return columns;
218 }
219 
220 QgsProperty propertyFromMap( const QgsStringMap &map, const QString &baseName )
221 {
222  QString prefix;
223  if ( !baseName.isEmpty() )
224  {
225  prefix.append( QStringLiteral( "%1_dd_" ).arg( baseName ) );
226  }
227 
228  if ( !map.contains( QStringLiteral( "%1expression" ).arg( prefix ) ) )
229  {
230  //requires at least the expression value
231  return QgsProperty();
232  }
233 
234  bool active = ( map.value( QStringLiteral( "%1active" ).arg( prefix ), QStringLiteral( "1" ) ) != QLatin1String( "0" ) );
235  QString expression = map.value( QStringLiteral( "%1expression" ).arg( prefix ) );
236  bool useExpression = ( map.value( QStringLiteral( "%1useexpr" ).arg( prefix ), QStringLiteral( "1" ) ) != QLatin1String( "0" ) );
237  QString field = map.value( QStringLiteral( "%1field" ).arg( prefix ), QString() );
238 
239  if ( useExpression )
240  return QgsProperty::fromExpression( expression, active );
241  else
242  return QgsProperty::fromField( field, active );
243 }
244 
245 // property string to type upgrade map
246 static const QMap< QString, QgsSymbolLayer::Property > OLD_PROPS
247 {
249  { "arrow_width", QgsSymbolLayer::PropertyArrowWidth },
250  { "arrow_start_width", QgsSymbolLayer::PropertyArrowStartWidth },
251  { "head_length", QgsSymbolLayer::PropertyArrowHeadLength },
252  { "head_thickness", QgsSymbolLayer::PropertyArrowHeadThickness },
253  { "offset", QgsSymbolLayer::PropertyOffset },
254  { "head_type", QgsSymbolLayer::PropertyArrowHeadType },
255  { "arrow_type", QgsSymbolLayer::PropertyArrowType },
256  { "width_field", QgsSymbolLayer::PropertyWidth },
257  { "height_field", QgsSymbolLayer::PropertyHeight },
258  { "rotation_field", QgsSymbolLayer::PropertyAngle },
259  { "outline_width_field", QgsSymbolLayer::PropertyStrokeWidth },
260  { "fill_color_field", QgsSymbolLayer::PropertyFillColor },
261  { "outline_color_field", QgsSymbolLayer::PropertyStrokeColor },
262  { "symbol_name_field", QgsSymbolLayer::PropertyName },
263  { "outline_width", QgsSymbolLayer::PropertyStrokeWidth },
264  { "outline_style", QgsSymbolLayer::PropertyStrokeStyle },
265  { "join_style", QgsSymbolLayer::PropertyJoinStyle },
266  { "fill_color", QgsSymbolLayer::PropertyFillColor },
267  { "outline_color", QgsSymbolLayer::PropertyStrokeColor },
268  { "width", QgsSymbolLayer::PropertyWidth },
269  { "height", QgsSymbolLayer::PropertyHeight },
270  { "symbol_name", QgsSymbolLayer::PropertyName },
271  { "angle", QgsSymbolLayer::PropertyAngle },
272  { "fill_style", QgsSymbolLayer::PropertyFillStyle },
273  { "color_border", QgsSymbolLayer::PropertyStrokeColor },
274  { "width_border", QgsSymbolLayer::PropertyStrokeWidth },
275  { "border_color", QgsSymbolLayer::PropertyStrokeColor },
276  { "border_style", QgsSymbolLayer::PropertyStrokeStyle },
278  { "gradient_type", QgsSymbolLayer::PropertyGradientType },
279  { "coordinate_mode", QgsSymbolLayer::PropertyCoordinateMode },
285  { "reference1_iscentroid", QgsSymbolLayer::PropertyGradientReference1IsCentroid },
286  { "reference2_iscentroid", QgsSymbolLayer::PropertyGradientReference2IsCentroid },
287  { "blur_radius", QgsSymbolLayer::PropertyBlurRadius },
291  { "svgFillColor", QgsSymbolLayer::PropertyFillColor },
292  { "svgOutlineColor", QgsSymbolLayer::PropertyStrokeColor },
293  { "svgOutlineWidth", QgsSymbolLayer::PropertyStrokeWidth },
294  { "svgFile", QgsSymbolLayer::PropertyFile },
295  { "lineangle", QgsSymbolLayer::PropertyLineAngle },
296  { "distance", QgsSymbolLayer::PropertyLineDistance },
297  { "distance_x", QgsSymbolLayer::PropertyDistanceX },
298  { "distance_y", QgsSymbolLayer::PropertyDistanceY },
299  { "displacement_x", QgsSymbolLayer::PropertyDisplacementX },
300  { "displacement_y", QgsSymbolLayer::PropertyDisplacementY },
301  { "file", QgsSymbolLayer::PropertyFile },
302  { "alpha", QgsSymbolLayer::PropertyOpacity },
303  { "customdash", QgsSymbolLayer::PropertyCustomDash },
304  { "line_style", QgsSymbolLayer::PropertyStrokeStyle },
305  { "joinstyle", QgsSymbolLayer::PropertyJoinStyle },
306  { "capstyle", QgsSymbolLayer::PropertyCapStyle },
307  { "placement", QgsSymbolLayer::PropertyPlacement },
308  { "interval", QgsSymbolLayer::PropertyInterval },
309  { "offset_along_line", QgsSymbolLayer::PropertyOffsetAlongLine },
310  { "name", QgsSymbolLayer::PropertyName },
311  { "size", QgsSymbolLayer::PropertySize },
316  { "rotation", QgsSymbolLayer::PropertyAngle },
317  { "horizontal_anchor_point", QgsSymbolLayer::PropertyHorizontalAnchor },
318  { "vertical_anchor_point", QgsSymbolLayer::PropertyVerticalAnchor },
319 };
320 
322 {
323  QgsStringMap::const_iterator propIt = stringMap.constBegin();
324  for ( ; propIt != stringMap.constEnd(); ++propIt )
325  {
326  QgsProperty prop;
327  QString propertyName;
328 
329  if ( propIt.key().endsWith( QLatin1String( "_dd_expression" ) ) )
330  {
331  //found a data defined property
332 
333  //get data defined property name by stripping "_dd_expression" from property key
334  propertyName = propIt.key().left( propIt.key().length() - 14 );
335 
336  prop = propertyFromMap( stringMap, propertyName );
337  }
338  else if ( propIt.key().endsWith( QLatin1String( "_expression" ) ) )
339  {
340  //old style data defined property, upgrade
341 
342  //get data defined property name by stripping "_expression" from property key
343  propertyName = propIt.key().left( propIt.key().length() - 11 );
344 
345  prop = QgsProperty::fromExpression( propIt.value() );
346  }
347 
348  if ( !prop || !OLD_PROPS.contains( propertyName ) )
349  continue;
350 
351  QgsSymbolLayer::Property key = static_cast< QgsSymbolLayer::Property >( OLD_PROPS.value( propertyName ) );
352 
353  if ( type() == QgsSymbol::Line )
354  {
355  //these keys had different meaning for line symbol layers
356  if ( propertyName == QLatin1String( "width" ) )
358  else if ( propertyName == QLatin1String( "color" ) )
360  }
361 
362  setDataDefinedProperty( key, prop );
363  }
364 }
365 
367 {
368  if ( !destLayer )
369  return;
370 
372 }
373 
375 {
376  if ( !destLayer || !mPaintEffect )
377  return;
378 
379  destLayer->setPaintEffect( mPaintEffect->clone() );
380 }
381 
383  : QgsSymbolLayer( QgsSymbol::Marker, locked )
384 {
385 
386 }
387 
389  : QgsSymbolLayer( QgsSymbol::Line, locked )
390 {
391 }
392 
394  : QgsSymbolLayer( QgsSymbol::Fill, locked )
395 {
396 }
397 
399 {
400  Q_UNUSED( context );
401 }
402 
404 {
405  startRender( context );
406  QgsPaintEffect *effect = paintEffect();
407  if ( effect && effect->enabled() )
408  {
409  QgsEffectPainter p( context.renderContext(), effect );
410  renderPoint( QPointF( size.width() / 2, size.height() / 2 ), context );
411  }
412  else
413  {
414  renderPoint( QPointF( size.width() / 2, size.height() / 2 ), context );
415  }
416  stopRender( context );
417 }
418 
419 void QgsMarkerSymbolLayer::markerOffset( QgsSymbolRenderContext &context, double &offsetX, double &offsetY ) const
420 {
421  markerOffset( context, mSize, mSize, mSizeUnit, mSizeUnit, offsetX, offsetY, mSizeMapUnitScale, mSizeMapUnitScale );
422 }
423 
424 void QgsMarkerSymbolLayer::markerOffset( QgsSymbolRenderContext &context, double width, double height, double &offsetX, double &offsetY ) const
425 {
426  markerOffset( context, width, height, mSizeUnit, mSizeUnit, offsetX, offsetY, mSizeMapUnitScale, mSizeMapUnitScale );
427 }
428 
429 void QgsMarkerSymbolLayer::markerOffset( QgsSymbolRenderContext &context, double width, double height,
431  double &offsetX, double &offsetY, const QgsMapUnitScale &widthMapUnitScale, const QgsMapUnitScale &heightMapUnitScale ) const
432 {
433  offsetX = mOffset.x();
434  offsetY = mOffset.y();
435 
437  {
440  if ( exprVal.isValid() )
441  {
442  QPointF offset = QgsSymbolLayerUtils::decodePoint( exprVal.toString() );
443  offsetX = offset.x();
444  offsetY = offset.y();
445  }
446  }
447 
448  offsetX = context.renderContext().convertToPainterUnits( offsetX, mOffsetUnit, mOffsetMapUnitScale );
449  offsetY = context.renderContext().convertToPainterUnits( offsetY, mOffsetUnit, mOffsetMapUnitScale );
450 
451  HorizontalAnchorPoint horizontalAnchorPoint = mHorizontalAnchorPoint;
452  VerticalAnchorPoint verticalAnchorPoint = mVerticalAnchorPoint;
454  {
456  if ( exprVal.isValid() )
457  {
458  horizontalAnchorPoint = decodeHorizontalAnchorPoint( exprVal.toString() );
459  }
460  }
462  {
464  if ( exprVal.isValid() )
465  {
466  verticalAnchorPoint = decodeVerticalAnchorPoint( exprVal.toString() );
467  }
468  }
469 
470  //correct horizontal position according to anchor point
471  if ( horizontalAnchorPoint == HCenter && verticalAnchorPoint == VCenter )
472  {
473  return;
474  }
475 
476  double anchorPointCorrectionX = context.renderContext().convertToPainterUnits( width, widthUnit, widthMapUnitScale ) / 2.0;
477  double anchorPointCorrectionY = context.renderContext().convertToPainterUnits( height, heightUnit, heightMapUnitScale ) / 2.0;
478  if ( horizontalAnchorPoint == Left )
479  {
480  offsetX += anchorPointCorrectionX;
481  }
482  else if ( horizontalAnchorPoint == Right )
483  {
484  offsetX -= anchorPointCorrectionX;
485  }
486 
487  //correct vertical position according to anchor point
488  if ( verticalAnchorPoint == Top )
489  {
490  offsetY += anchorPointCorrectionY;
491  }
492  else if ( verticalAnchorPoint == Bottom )
493  {
494  offsetY -= anchorPointCorrectionY;
495  }
496 }
497 
498 QPointF QgsMarkerSymbolLayer::_rotatedOffset( QPointF offset, double angle )
499 {
500  angle = DEG2RAD( angle );
501  double c = std::cos( angle ), s = std::sin( angle );
502  return QPointF( offset.x() * c - offset.y() * s, offset.x() * s + offset.y() * c );
503 }
504 
505 QgsMarkerSymbolLayer::HorizontalAnchorPoint QgsMarkerSymbolLayer::decodeHorizontalAnchorPoint( const QString &str )
506 {
507  if ( str.compare( QLatin1String( "left" ), Qt::CaseInsensitive ) == 0 )
508  {
510  }
511  else if ( str.compare( QLatin1String( "right" ), Qt::CaseInsensitive ) == 0 )
512  {
514  }
515  else
516  {
518  }
519 }
520 
521 QgsMarkerSymbolLayer::VerticalAnchorPoint QgsMarkerSymbolLayer::decodeVerticalAnchorPoint( const QString &str )
522 {
523  if ( str.compare( QLatin1String( "top" ), Qt::CaseInsensitive ) == 0 )
524  {
526  }
527  else if ( str.compare( QLatin1String( "bottom" ), Qt::CaseInsensitive ) == 0 )
528  {
530  }
531  else
532  {
534  }
535 }
536 
538 {
539  mSizeUnit = unit;
540  mOffsetUnit = unit;
541 }
542 
544 {
545  if ( mOffsetUnit != mSizeUnit )
546  {
548  }
549  return mOffsetUnit;
550 }
551 
553 {
554  mSizeMapUnitScale = scale;
555  mOffsetMapUnitScale = scale;
556 }
557 
559 {
560  if ( mSizeMapUnitScale == mOffsetMapUnitScale )
561  {
562  return mSizeMapUnitScale;
563  }
564  return QgsMapUnitScale();
565 }
566 
568 {
569  mWidthUnit = unit;
570 }
571 
573 {
574  return mWidthUnit;
575 }
576 
578 {
579  mWidthMapUnitScale = scale;
580 }
581 
583 {
584  return mWidthMapUnitScale;
585 }
586 
587 
589 {
590  QPolygonF points;
591  // we're adding 0.5 to get rid of blurred preview:
592  // drawing antialiased lines of width 1 at (x,0)-(x,100) creates 2px line
593  points << QPointF( 0, int( size.height() / 2 ) + 0.5 ) << QPointF( size.width(), int( size.height() / 2 ) + 0.5 );
594 
595  startRender( context );
596  QgsPaintEffect *effect = paintEffect();
597  if ( effect && effect->enabled() )
598  {
599  QgsEffectPainter p( context.renderContext(), effect );
600  renderPolyline( points, context );
601  }
602  else
603  {
604  renderPolyline( points, context );
605  }
606  stopRender( context );
607 }
608 
609 void QgsLineSymbolLayer::renderPolygonStroke( const QPolygonF &points, QList<QPolygonF> *rings, QgsSymbolRenderContext &context )
610 {
611  renderPolyline( points, context );
612  if ( rings )
613  {
614  Q_FOREACH ( const QPolygonF &ring, *rings )
615  renderPolyline( ring, context );
616  }
617 }
618 
620 {
621  Q_UNUSED( context );
622  return width() * e.mapUnitScaleFactor( e.symbologyScale(), widthUnit(), e.mapUnits() );
623 }
624 
625 
627 {
628  QPolygonF poly = QRectF( QPointF( 0, 0 ), QPointF( size.width(), size.height() ) );
629  startRender( context );
630  QgsPaintEffect *effect = paintEffect();
631  if ( effect && effect->enabled() )
632  {
633  QgsEffectPainter p( context.renderContext(), effect );
634  renderPolygon( poly, nullptr, context );
635  }
636  else
637  {
638  renderPolygon( poly, nullptr, context );
639  }
640  stopRender( context );
641 }
642 
643 void QgsFillSymbolLayer::_renderPolygon( QPainter *p, const QPolygonF &points, const QList<QPolygonF> *rings, QgsSymbolRenderContext &context )
644 {
645  if ( !p )
646  {
647  return;
648  }
649 
650  // Disable 'Antialiasing' if the geometry was generalized in the current RenderContext (We known that it must have least #5 points).
651  if ( points.size() <= 5 &&
654  ( p->renderHints() & QPainter::Antialiasing ) )
655  {
656  p->setRenderHint( QPainter::Antialiasing, false );
657  p->drawRect( points.boundingRect() );
658  p->setRenderHint( QPainter::Antialiasing, true );
659  return;
660  }
661 
662  // polygons outlines are sometimes rendered wrongly with drawPolygon, when
663  // clipped (see #13343), so use drawPath instead.
664  if ( !rings && p->pen().style() == Qt::NoPen )
665  {
666  // simple polygon without holes
667  p->drawPolygon( points );
668  }
669  else
670  {
671  // polygon with holes must be drawn using painter path
672  QPainterPath path;
673  path.addPolygon( points );
674 
675  if ( rings )
676  {
677  QList<QPolygonF>::const_iterator it = rings->constBegin();
678  for ( ; it != rings->constEnd(); ++it )
679  {
680  QPolygonF ring = *it;
681  path.addPolygon( ring );
682  }
683  }
684 
685  p->drawPath( path );
686  }
687 }
688 
689 void QgsMarkerSymbolLayer::toSld( QDomDocument &doc, QDomElement &element, const QgsStringMap &props ) const
690 {
691  QDomElement symbolizerElem = doc.createElement( QStringLiteral( "se:PointSymbolizer" ) );
692  if ( !props.value( QStringLiteral( "uom" ), QLatin1String( "" ) ).isEmpty() )
693  symbolizerElem.setAttribute( QStringLiteral( "uom" ), props.value( QStringLiteral( "uom" ), QLatin1String( "" ) ) );
694  element.appendChild( symbolizerElem );
695 
696  // <Geometry>
697  QgsSymbolLayerUtils::createGeometryElement( doc, symbolizerElem, props.value( QStringLiteral( "geom" ), QLatin1String( "" ) ) );
698 
699  writeSldMarker( doc, symbolizerElem, props );
700 }
701 
702 
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
get dash pattern
Gradient reference point 1 is centroid.
double symbologyScale() const
Returns the reference scale for output.
Definition: qgsdxfexport.h:150
void setEnabled(const bool enabled)
Sets whether the effect is enabled.
QgsLineSymbolLayer(bool locked=false)
Positive integer values (including 0)
Definition: qgsproperty.h:55
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:534
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
virtual double dxfOffset(const QgsDxfExport &e, QgsSymbolRenderContext &context) const
get offset
static double mapUnitScaleFactor(double scale, QgsUnitTypes::RenderUnit symbolUnits, QgsUnitTypes::DistanceUnit mapUnits)
Calculates a scaling factor to convert from map units to a specified symbol unit. ...
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
get 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
get line width
QMap< QString, QString > QgsStringMap
Definition: qgis.h:479
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)
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:1055
bool prepare(const QgsExpressionContext &context=QgsExpressionContext()) const override
Prepares the collection against a specified expression context.
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
get brush/fill style
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.
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:453
Definition for a property.
Definition: qgsproperty.h:46
HorizontalAnchorPoint
Symbol horizontal anchor points.
Gradient reference point 1 y.
virtual QColor dxfBrushColor(QgsSymbolRenderContext &context) const
get 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
get 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).
Property requires a string value.
Definition: qgsproperty.h:91
SymbolType type() const
Definition: qgssymbol.h:113
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
get angle
QgsMarkerSymbolLayer(bool locked=false)
Constructor for QgsMarkerSymbolLayer.
virtual QColor dxfColor(QgsSymbolRenderContext &context) const
get color
QgsPaintEffect * mPaintEffect
Line style (eg solid/dashed)
Definition: qgsproperty.h:71
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:100
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