1 /***************************************************************************
2 qgssymbollayer.cpp
3 ---------------------
4 begin : November 2009
5 copyright : (C) 2009 by Martin Dobias
6 email : wonder dot sk at gmail dot com
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15
16 #include "qgssymbollayer.h"
17 #include "qgsclipper.h"
18 #include "qgsexpression.h"
19 #include "qgsrendercontext.h"
20 #include "qgsvectorlayer.h"
21 #include "qgsdxfexport.h"
22 #include "qgsgeometrysimplifier.h"
23 #include "qgspainteffect.h"
24 #include "qgseffectstack.h"
25 #include "qgspainteffectregistry.h"
26 #include "qgsproperty.h"
27 #include "qgsexpressioncontext.h"
28 #include "qgssymbollayerutils.h"
29 #include "qgsapplication.h"
30 #include "qgsmultipoint.h"
31 #include "qgslegendpatchshape.h"
32 #include "qgsstyle.h"
33 #include "qgsexpressioncontextutils.h"
34 #include "qgssymbol.h"
35 #include "qgssymbollayerreference.h"
36
37 #include <QSize>
38 #include <QPainter>
39 #include <QPointF>
40 #include <QPolygonF>
41
42 QgsPropertiesDefinition QgsSymbolLayer::sPropertyDefinitions;
43
initPropertyDefinitions()44 void QgsSymbolLayer::initPropertyDefinitions()
45 {
46 if ( !sPropertyDefinitions.isEmpty() )
47 return;
48
49 QString origin = QStringLiteral( "symbol" );
50
51 sPropertyDefinitions = QgsPropertiesDefinition
52 {
53 { QgsSymbolLayer::PropertySize, QgsPropertyDefinition( "size", QObject::tr( "Symbol size" ), QgsPropertyDefinition::Size, origin ) },
54 { QgsSymbolLayer::PropertyAngle, QgsPropertyDefinition( "angle", QObject::tr( "Rotation angle" ), QgsPropertyDefinition::Rotation, origin ) },
55 { QgsSymbolLayer::PropertyName, QgsPropertyDefinition( "name", QObject::tr( "Symbol name" ), QgsPropertyDefinition::String, origin ) },
56 { QgsSymbolLayer::PropertyFillColor, QgsPropertyDefinition( "fillColor", QObject::tr( "Symbol fill color" ), QgsPropertyDefinition::ColorWithAlpha, origin ) },
57 { QgsSymbolLayer::PropertyStrokeColor, QgsPropertyDefinition( "outlineColor", QObject::tr( "Symbol stroke color" ), QgsPropertyDefinition::ColorWithAlpha, origin ) },
58 { QgsSymbolLayer::PropertyStrokeWidth, QgsPropertyDefinition( "outlineWidth", QObject::tr( "Symbol stroke width" ), QgsPropertyDefinition::StrokeWidth, origin ) },
59 { QgsSymbolLayer::PropertyStrokeStyle, QgsPropertyDefinition( "outlineStyle", QObject::tr( "Symbol stroke style" ), QgsPropertyDefinition::LineStyle, origin )},
60 { QgsSymbolLayer::PropertyOffset, QgsPropertyDefinition( "offset", QObject::tr( "Symbol offset" ), QgsPropertyDefinition::Offset, origin )},
61 { QgsSymbolLayer::PropertyCharacter, QgsPropertyDefinition( "char", QObject::tr( "Marker character(s)" ), QgsPropertyDefinition::String, origin )},
62 { QgsSymbolLayer::PropertyFontFamily, QgsPropertyDefinition( "fontFamily", QObject::tr( "Font family" ), QgsPropertyDefinition::String, origin )},
63 { QgsSymbolLayer::PropertyFontStyle, QgsPropertyDefinition( "fontStyle", QObject::tr( "Font style" ), QgsPropertyDefinition::String, origin )},
64 { QgsSymbolLayer::PropertyWidth, QgsPropertyDefinition( "width", QObject::tr( "Symbol width" ), QgsPropertyDefinition::DoublePositive, origin )},
65 { QgsSymbolLayer::PropertyHeight, QgsPropertyDefinition( "height", QObject::tr( "Symbol height" ), QgsPropertyDefinition::DoublePositive, origin )},
66 { QgsSymbolLayer::PropertyPreserveAspectRatio, QgsPropertyDefinition( "preserveAspectRatio", QObject::tr( "Preserve aspect ratio between width and height" ), QgsPropertyDefinition::Boolean, origin )},
67 { QgsSymbolLayer::PropertyFillStyle, QgsPropertyDefinition( "fillStyle", QObject::tr( "Symbol fill style" ), QgsPropertyDefinition::FillStyle, origin )},
68 { QgsSymbolLayer::PropertyJoinStyle, QgsPropertyDefinition( "joinStyle", QObject::tr( "Outline join style" ), QgsPropertyDefinition::PenJoinStyle, origin )},
69 { QgsSymbolLayer::PropertySecondaryColor, QgsPropertyDefinition( "color2", QObject::tr( "Secondary fill color" ), QgsPropertyDefinition::ColorWithAlpha, origin )},
70 { QgsSymbolLayer::PropertyLineAngle, QgsPropertyDefinition( "lineAngle", QObject::tr( "Angle for line fills" ), QgsPropertyDefinition::Rotation, origin )},
71 { QgsSymbolLayer::PropertyGradientType, QgsPropertyDefinition( "gradientType", QgsPropertyDefinition::DataTypeString, QObject::tr( "Gradient type" ), QObject::tr( "string " ) + QLatin1String( "[<b>linear</b>|<b>radial</b>|<b>conical</b>]" ), origin )},
72 { QgsSymbolLayer::PropertyCoordinateMode, QgsPropertyDefinition( "gradientMode", QgsPropertyDefinition::DataTypeString, QObject::tr( "Gradient mode" ), QObject::tr( "string " ) + QLatin1String( "[<b>feature</b>|<b>viewport</b>]" ), origin )},
73 { QgsSymbolLayer::PropertyGradientSpread, QgsPropertyDefinition( "gradientSpread", QgsPropertyDefinition::DataTypeString, QObject::tr( "Gradient spread" ), QObject::tr( "string " ) + QLatin1String( "[<b>pad</b>|<b>repeat</b>|<b>reflect</b>]" ), origin )},
74 { QgsSymbolLayer::PropertyGradientReference1X, QgsPropertyDefinition( "gradientRef1X", QObject::tr( "Reference point 1 (X)" ), QgsPropertyDefinition::Double0To1, origin )},
75 { QgsSymbolLayer::PropertyGradientReference1Y, QgsPropertyDefinition( "gradientRef1Y", QObject::tr( "Reference point 1 (Y)" ), QgsPropertyDefinition::Double0To1, origin )},
76 { QgsSymbolLayer::PropertyGradientReference2X, QgsPropertyDefinition( "gradientRef2X", QObject::tr( "Reference point 2 (X)" ), QgsPropertyDefinition::Double0To1, origin )},
77 { QgsSymbolLayer::PropertyGradientReference2Y, QgsPropertyDefinition( "gradientRef2Y", QObject::tr( "Reference point 2 (Y)" ), QgsPropertyDefinition::Double0To1, origin )},
78 { QgsSymbolLayer::PropertyGradientReference1IsCentroid, QgsPropertyDefinition( "gradientRef1Centroid", QObject::tr( "Reference point 1 follows feature centroid" ), QgsPropertyDefinition::Boolean, origin )},
79 { QgsSymbolLayer::PropertyGradientReference2IsCentroid, QgsPropertyDefinition( "gradientRef2Centroid", QObject::tr( "Reference point 2 follows feature centroid" ), QgsPropertyDefinition::Boolean, origin )},
80 { QgsSymbolLayer::PropertyBlurRadius, QgsPropertyDefinition( "blurRadius", QgsPropertyDefinition::DataTypeNumeric, QObject::tr( "Blur radius" ), QObject::tr( "Integer between 0 and 18" ), origin )},
81 { QgsSymbolLayer::PropertyLineDistance, QgsPropertyDefinition( "lineDistance", QObject::tr( "Distance between lines" ), QgsPropertyDefinition::DoublePositive, origin )},
82 { QgsSymbolLayer::PropertyShapeburstUseWholeShape, QgsPropertyDefinition( "shapeburstWholeShape", QObject::tr( "Shade whole shape" ), QgsPropertyDefinition::Boolean, origin )},
83 { QgsSymbolLayer::PropertyShapeburstMaxDistance, QgsPropertyDefinition( "shapeburstMaxDist", QObject::tr( "Maximum distance for shapeburst fill" ), QgsPropertyDefinition::DoublePositive, origin )},
84 { QgsSymbolLayer::PropertyShapeburstIgnoreRings, QgsPropertyDefinition( "shapeburstIgnoreRings", QObject::tr( "Ignore rings in feature" ), QgsPropertyDefinition::Boolean, origin )},
85 { QgsSymbolLayer::PropertyFile, QgsPropertyDefinition( "file", QObject::tr( "Symbol file path" ), QgsPropertyDefinition::String, origin )},
86 { QgsSymbolLayer::PropertyDistanceX, QgsPropertyDefinition( "distanceX", QObject::tr( "Horizontal distance between markers" ), QgsPropertyDefinition::DoublePositive, origin )},
87 { QgsSymbolLayer::PropertyDistanceY, QgsPropertyDefinition( "distanceY", QObject::tr( "Vertical distance between markers" ), QgsPropertyDefinition::DoublePositive, origin )},
88 { QgsSymbolLayer::PropertyDisplacementX, QgsPropertyDefinition( "displacementX", QObject::tr( "Horizontal displacement between rows" ), QgsPropertyDefinition::DoublePositive, origin )},
89 { QgsSymbolLayer::PropertyDisplacementY, QgsPropertyDefinition( "displacementY", QObject::tr( "Vertical displacement between columns" ), QgsPropertyDefinition::DoublePositive, origin )},
90 { QgsSymbolLayer::PropertyOffsetX, QgsPropertyDefinition( "offsetX", QObject::tr( "Horizontal offset" ), QgsPropertyDefinition::Double, origin )},
91 { QgsSymbolLayer::PropertyOffsetY, QgsPropertyDefinition( "offsetY", QObject::tr( "Vertical offset" ), QgsPropertyDefinition::Double, origin )},
92 { QgsSymbolLayer::PropertyOpacity, QgsPropertyDefinition( "alpha", QObject::tr( "Opacity" ), QgsPropertyDefinition::Opacity, origin )},
93 { QgsSymbolLayer::PropertyCustomDash, QgsPropertyDefinition( "customDash", QgsPropertyDefinition::DataTypeString, QObject::tr( "Custom dash pattern" ), QObject::tr( "[<b><dash>;<space></b>] e.g. '8;2;1;2'" ), origin )},
94 { QgsSymbolLayer::PropertyCapStyle, QgsPropertyDefinition( "capStyle", QObject::tr( "Line cap style" ), QgsPropertyDefinition::CapStyle, origin )},
95 { QgsSymbolLayer::PropertyPlacement, QgsPropertyDefinition( "placement", QgsPropertyDefinition::DataTypeString, QObject::tr( "Marker placement" ), QObject::tr( "string " ) + "[<b>interval</b>|<b>vertex</b>|<b>lastvertex</b>|<b>firstvertex</b>|<b>centerpoint</b>|<b>curvepoint</b>|<b>segmentcenter</b>]", origin )},
96 { QgsSymbolLayer::PropertyInterval, QgsPropertyDefinition( "interval", QObject::tr( "Marker interval" ), QgsPropertyDefinition::DoublePositive, origin )},
97 { QgsSymbolLayer::PropertyOffsetAlongLine, QgsPropertyDefinition( "offsetAlongLine", QObject::tr( "Offset along line" ), QgsPropertyDefinition::DoublePositive, origin )},
98 { QgsSymbolLayer::PropertyAverageAngleLength, QgsPropertyDefinition( "averageAngleLength", QObject::tr( "Average line angles over" ), QgsPropertyDefinition::DoublePositive, origin )},
99 { QgsSymbolLayer::PropertyHorizontalAnchor, QgsPropertyDefinition( "hAnchor", QObject::tr( "Horizontal anchor point" ), QgsPropertyDefinition::HorizontalAnchor, origin )},
100 { QgsSymbolLayer::PropertyVerticalAnchor, QgsPropertyDefinition( "vAnchor", QObject::tr( "Vertical anchor point" ), QgsPropertyDefinition::VerticalAnchor, origin )},
101 { QgsSymbolLayer::PropertyLayerEnabled, QgsPropertyDefinition( "enabled", QObject::tr( "Layer enabled" ), QgsPropertyDefinition::Boolean, origin )},
102 { QgsSymbolLayer::PropertyArrowWidth, QgsPropertyDefinition( "arrowWidth", QObject::tr( "Arrow line width" ), QgsPropertyDefinition::StrokeWidth, origin )},
103 { QgsSymbolLayer::PropertyArrowStartWidth, QgsPropertyDefinition( "arrowStartWidth", QObject::tr( "Arrow line start width" ), QgsPropertyDefinition::StrokeWidth, origin )},
104 { QgsSymbolLayer::PropertyArrowHeadLength, QgsPropertyDefinition( "arrowHeadLength", QObject::tr( "Arrow head length" ), QgsPropertyDefinition::DoublePositive, origin )},
105 { QgsSymbolLayer::PropertyArrowHeadThickness, QgsPropertyDefinition( "arrowHeadThickness", QObject::tr( "Arrow head thickness" ), QgsPropertyDefinition::DoublePositive, origin )},
106 { QgsSymbolLayer::PropertyArrowHeadType, QgsPropertyDefinition( "arrowHeadType", QgsPropertyDefinition::DataTypeString, QObject::tr( "Arrow head type" ), QObject::tr( "string " ) + QLatin1String( "[<b>single</b>|<b>reversed</b>|<b>double</b>]" ), origin )},
107 { QgsSymbolLayer::PropertyArrowType, QgsPropertyDefinition( "arrowType", QgsPropertyDefinition::DataTypeString, QObject::tr( "Arrow type" ), QObject::tr( "string " ) + QLatin1String( "[<b>plain</b>|<b>lefthalf</b>|<b>righthalf</b>]" ), origin )},
108 { QgsSymbolLayer::PropertyPointCount, QgsPropertyDefinition( "pointCount", QObject::tr( "Point count" ), QgsPropertyDefinition::IntegerPositive, origin )},
109 { QgsSymbolLayer::PropertyRandomSeed, QgsPropertyDefinition( "randomSeed", QgsPropertyDefinition::DataTypeNumeric, QObject::tr( "Random number seed" ), QObject::tr( "integer > 0, or 0 for completely random sequence" ), origin )},
110 { QgsSymbolLayer::PropertyClipPoints, QgsPropertyDefinition( "clipPoints", QObject::tr( "Clip markers" ), QgsPropertyDefinition::Boolean, origin )},
111 { QgsSymbolLayer::PropertyClipPoints, QgsPropertyDefinition( "densityArea", QObject::tr( "Density area" ), QgsPropertyDefinition::DoublePositive, origin )},
112 { QgsSymbolLayer::PropertyDashPatternOffset, QgsPropertyDefinition( "dashPatternOffset", QObject::tr( "Dash pattern offset" ), QgsPropertyDefinition::DoublePositive, origin )},
113 { QgsSymbolLayer::PropertyTrimStart, QgsPropertyDefinition( "trimStart", QObject::tr( "Start trim distance" ), QgsPropertyDefinition::DoublePositive, origin )},
114 { QgsSymbolLayer::PropertyTrimEnd, QgsPropertyDefinition( "trimEnd", QObject::tr( "End trim distance" ), QgsPropertyDefinition::DoublePositive, origin )},
115 { QgsSymbolLayer::PropertyLineStartWidthValue, QgsPropertyDefinition( "lineStartWidthValue", QObject::tr( "Line start width value" ), QgsPropertyDefinition::Double, origin )},
116 { QgsSymbolLayer::PropertyLineEndWidthValue, QgsPropertyDefinition( "lineEndWidthValue", QObject::tr( "Line end width value" ), QgsPropertyDefinition::Double, origin )},
117 { QgsSymbolLayer::PropertyLineStartColorValue, QgsPropertyDefinition( "lineStartColorValue", QObject::tr( "Line start color value" ), QgsPropertyDefinition::Double, origin )},
118 { QgsSymbolLayer::PropertyLineEndColorValue, QgsPropertyDefinition( "lineEndColorValue", QObject::tr( "Line end color value" ), QgsPropertyDefinition::Double, origin )},
119 };
120 }
121
setDataDefinedProperty(QgsSymbolLayer::Property key,const QgsProperty & property)122 void QgsSymbolLayer::setDataDefinedProperty( QgsSymbolLayer::Property key, const QgsProperty &property )
123 {
124 dataDefinedProperties().setProperty( key, property );
125 }
126
startFeatureRender(const QgsFeature & feature,QgsRenderContext & context)127 void QgsSymbolLayer::startFeatureRender( const QgsFeature &feature, QgsRenderContext &context )
128 {
129 if ( QgsSymbol *lSubSymbol = subSymbol() )
130 lSubSymbol->startFeatureRender( feature, context );
131 }
132
stopFeatureRender(const QgsFeature & feature,QgsRenderContext & context)133 void QgsSymbolLayer::stopFeatureRender( const QgsFeature &feature, QgsRenderContext &context )
134 {
135 if ( QgsSymbol *lSubSymbol = subSymbol() )
136 lSubSymbol->stopFeatureRender( feature, context );
137 }
138
subSymbol()139 QgsSymbol *QgsSymbolLayer::subSymbol()
140 {
141 return nullptr;
142 }
143
setSubSymbol(QgsSymbol * symbol)144 bool QgsSymbolLayer::setSubSymbol( QgsSymbol *symbol )
145 {
146 delete symbol;
147 return false;
148 }
149
writeDxf(QgsDxfExport & e,double mmMapUnitScaleFactor,const QString & layerName,QgsSymbolRenderContext & context,QPointF shift) const150 bool QgsSymbolLayer::writeDxf( QgsDxfExport &e, double mmMapUnitScaleFactor, const QString &layerName, QgsSymbolRenderContext &context, QPointF shift ) const
151 {
152 Q_UNUSED( e )
153 Q_UNUSED( mmMapUnitScaleFactor )
154 Q_UNUSED( layerName )
155 Q_UNUSED( context )
156 Q_UNUSED( shift )
157 return false;
158 }
159
dxfWidth(const QgsDxfExport & e,QgsSymbolRenderContext & context) const160 double QgsSymbolLayer::dxfWidth( const QgsDxfExport &e, QgsSymbolRenderContext &context ) const
161 {
162 Q_UNUSED( e )
163 Q_UNUSED( context )
164 return 1.0;
165 }
166
dxfOffset(const QgsDxfExport & e,QgsSymbolRenderContext & context) const167 double QgsSymbolLayer::dxfOffset( const QgsDxfExport &e, QgsSymbolRenderContext &context ) const
168 {
169 Q_UNUSED( e )
170 Q_UNUSED( context )
171 return 0.0;
172 }
173
dxfColor(QgsSymbolRenderContext & context) const174 QColor QgsSymbolLayer::dxfColor( QgsSymbolRenderContext &context ) const
175 {
176 Q_UNUSED( context )
177 return color();
178 }
179
dxfAngle(QgsSymbolRenderContext & context) const180 double QgsSymbolLayer::dxfAngle( QgsSymbolRenderContext &context ) const
181 {
182 Q_UNUSED( context )
183 return 0.0;
184 }
185
dxfCustomDashPattern(QgsUnitTypes::RenderUnit & unit) const186 QVector<qreal> QgsSymbolLayer::dxfCustomDashPattern( QgsUnitTypes::RenderUnit &unit ) const
187 {
188 Q_UNUSED( unit )
189 return QVector<qreal>();
190 }
191
dxfPenStyle() const192 Qt::PenStyle QgsSymbolLayer::dxfPenStyle() const
193 {
194 return Qt::SolidLine;
195 }
196
dxfBrushColor(QgsSymbolRenderContext & context) const197 QColor QgsSymbolLayer::dxfBrushColor( QgsSymbolRenderContext &context ) const
198 {
199 Q_UNUSED( context )
200 return color();
201 }
202
dxfBrushStyle() const203 Qt::BrushStyle QgsSymbolLayer::dxfBrushStyle() const
204 {
205 return Qt::NoBrush;
206 }
207
paintEffect() const208 QgsPaintEffect *QgsSymbolLayer::paintEffect() const
209 {
210 return mPaintEffect.get();
211 }
212
setPaintEffect(QgsPaintEffect * effect)213 void QgsSymbolLayer::setPaintEffect( QgsPaintEffect *effect )
214 {
215 if ( effect == mPaintEffect.get() )
216 return;
217
218 mPaintEffect.reset( effect );
219 }
220
QgsSymbolLayer(Qgis::SymbolType type,bool locked)221 QgsSymbolLayer::QgsSymbolLayer( Qgis::SymbolType type, bool locked )
222 : mType( type )
223 , mLocked( locked )
224 {
225 }
226
flags() const227 Qgis::SymbolLayerFlags QgsSymbolLayer::flags() const
228 {
229 return Qgis::SymbolLayerFlags();
230 }
231
prepareExpressions(const QgsSymbolRenderContext & context)232 void QgsSymbolLayer::prepareExpressions( const QgsSymbolRenderContext &context )
233 {
234 mDataDefinedProperties.prepare( context.renderContext().expressionContext() );
235
236 if ( !context.fields().isEmpty() )
237 {
238 //QgsFields is implicitly shared, so it's cheap to make a copy
239 mFields = context.fields();
240 }
241 }
242
hasDataDefinedProperties() const243 bool QgsSymbolLayer::hasDataDefinedProperties() const
244 {
245 return mDataDefinedProperties.hasActiveProperties();
246 }
247
propertyDefinitions()248 const QgsPropertiesDefinition &QgsSymbolLayer::propertyDefinitions()
249 {
250 QgsSymbolLayer::initPropertyDefinitions();
251 return sPropertyDefinitions;
252 }
253
254 QgsSymbolLayer::~QgsSymbolLayer() = default;
255
isCompatibleWithSymbol(QgsSymbol * symbol) const256 bool QgsSymbolLayer::isCompatibleWithSymbol( QgsSymbol *symbol ) const
257 {
258 if ( symbol->type() == Qgis::SymbolType::Fill && mType == Qgis::SymbolType::Line )
259 return true;
260
261 return symbol->type() == mType;
262 }
263
canCauseArtifactsBetweenAdjacentTiles() const264 bool QgsSymbolLayer::canCauseArtifactsBetweenAdjacentTiles() const
265 {
266 return false;
267 }
268
usesMapUnits() const269 bool QgsSymbolLayer::usesMapUnits() const
270 {
271 return false;
272 }
273
setRenderingPass(int renderingPass)274 void QgsSymbolLayer::setRenderingPass( int renderingPass )
275 {
276 mRenderingPass = renderingPass;
277 }
278
renderingPass() const279 int QgsSymbolLayer::renderingPass() const
280 {
281 return mRenderingPass;
282 }
283
usedAttributes(const QgsRenderContext & context) const284 QSet<QString> QgsSymbolLayer::usedAttributes( const QgsRenderContext &context ) const
285 {
286 // calling referencedFields() with ignoreContext=true because in our expression context
287 // we do not have valid QgsFields yet - because of that the field names from expressions
288 // wouldn't get reported
289 QSet<QString> columns = mDataDefinedProperties.referencedFields( context.expressionContext(), true );
290 return columns;
291 }
292
propertyFromMap(const QVariantMap & map,const QString & baseName)293 QgsProperty propertyFromMap( const QVariantMap &map, const QString &baseName )
294 {
295 QString prefix;
296 if ( !baseName.isEmpty() )
297 {
298 prefix.append( QStringLiteral( "%1_dd_" ).arg( baseName ) );
299 }
300
301 if ( !map.contains( QStringLiteral( "%1expression" ).arg( prefix ) ) )
302 {
303 //requires at least the expression value
304 return QgsProperty();
305 }
306
307 bool active = ( map.value( QStringLiteral( "%1active" ).arg( prefix ), QStringLiteral( "1" ) ) != QLatin1String( "0" ) );
308 QString expression = map.value( QStringLiteral( "%1expression" ).arg( prefix ) ).toString();
309 bool useExpression = ( map.value( QStringLiteral( "%1useexpr" ).arg( prefix ), QStringLiteral( "1" ) ) != QLatin1String( "0" ) );
310 QString field = map.value( QStringLiteral( "%1field" ).arg( prefix ), QString() ).toString();
311
312 if ( useExpression )
313 return QgsProperty::fromExpression( expression, active );
314 else
315 return QgsProperty::fromField( field, active );
316 }
317
restoreOldDataDefinedProperties(const QVariantMap & stringMap)318 void QgsSymbolLayer::restoreOldDataDefinedProperties( const QVariantMap &stringMap )
319 {
320 // property string to type upgrade map
321 static const QMap< QString, QgsSymbolLayer::Property > OLD_PROPS
322 {
323 { "color", QgsSymbolLayer::PropertyFillColor },
324 { "arrow_width", QgsSymbolLayer::PropertyArrowWidth },
325 { "arrow_start_width", QgsSymbolLayer::PropertyArrowStartWidth },
326 { "head_length", QgsSymbolLayer::PropertyArrowHeadLength },
327 { "head_thickness", QgsSymbolLayer::PropertyArrowHeadThickness },
328 { "offset", QgsSymbolLayer::PropertyOffset },
329 { "head_type", QgsSymbolLayer::PropertyArrowHeadType },
330 { "arrow_type", QgsSymbolLayer::PropertyArrowType },
331 { "width_field", QgsSymbolLayer::PropertyWidth },
332 { "height_field", QgsSymbolLayer::PropertyHeight },
333 { "rotation_field", QgsSymbolLayer::PropertyAngle },
334 { "outline_width_field", QgsSymbolLayer::PropertyStrokeWidth },
335 { "fill_color_field", QgsSymbolLayer::PropertyFillColor },
336 { "outline_color_field", QgsSymbolLayer::PropertyStrokeColor },
337 { "symbol_name_field", QgsSymbolLayer::PropertyName },
338 { "outline_width", QgsSymbolLayer::PropertyStrokeWidth },
339 { "outline_style", QgsSymbolLayer::PropertyStrokeStyle },
340 { "join_style", QgsSymbolLayer::PropertyJoinStyle },
341 { "fill_color", QgsSymbolLayer::PropertyFillColor },
342 { "outline_color", QgsSymbolLayer::PropertyStrokeColor },
343 { "width", QgsSymbolLayer::PropertyWidth },
344 { "height", QgsSymbolLayer::PropertyHeight },
345 { "symbol_name", QgsSymbolLayer::PropertyName },
346 { "angle", QgsSymbolLayer::PropertyAngle },
347 { "fill_style", QgsSymbolLayer::PropertyFillStyle },
348 { "color_border", QgsSymbolLayer::PropertyStrokeColor },
349 { "width_border", QgsSymbolLayer::PropertyStrokeWidth },
350 { "border_color", QgsSymbolLayer::PropertyStrokeColor },
351 { "border_style", QgsSymbolLayer::PropertyStrokeStyle },
352 { "color2", QgsSymbolLayer::PropertySecondaryColor },
353 { "gradient_type", QgsSymbolLayer::PropertyGradientType },
354 { "coordinate_mode", QgsSymbolLayer::PropertyCoordinateMode },
355 { "spread", QgsSymbolLayer::PropertyGradientSpread },
356 { "reference1_x", QgsSymbolLayer::PropertyGradientReference1X },
357 { "reference1_y", QgsSymbolLayer::PropertyGradientReference1Y },
358 { "reference2_x", QgsSymbolLayer::PropertyGradientReference2X },
359 { "reference2_y", QgsSymbolLayer::PropertyGradientReference2Y },
360 { "reference1_iscentroid", QgsSymbolLayer::PropertyGradientReference1IsCentroid },
361 { "reference2_iscentroid", QgsSymbolLayer::PropertyGradientReference2IsCentroid },
362 { "blur_radius", QgsSymbolLayer::PropertyBlurRadius },
363 { "use_whole_shape", QgsSymbolLayer::PropertyShapeburstUseWholeShape },
364 { "max_distance", QgsSymbolLayer::PropertyShapeburstMaxDistance },
365 { "ignore_rings", QgsSymbolLayer::PropertyShapeburstIgnoreRings },
366 { "svgFillColor", QgsSymbolLayer::PropertyFillColor },
367 { "svgOutlineColor", QgsSymbolLayer::PropertyStrokeColor },
368 { "svgOutlineWidth", QgsSymbolLayer::PropertyStrokeWidth },
369 { "svgFile", QgsSymbolLayer::PropertyFile },
370 { "lineangle", QgsSymbolLayer::PropertyLineAngle },
371 { "distance", QgsSymbolLayer::PropertyLineDistance },
372 { "distance_x", QgsSymbolLayer::PropertyDistanceX },
373 { "distance_y", QgsSymbolLayer::PropertyDistanceY },
374 { "displacement_x", QgsSymbolLayer::PropertyDisplacementX },
375 { "displacement_y", QgsSymbolLayer::PropertyDisplacementY },
376 { "file", QgsSymbolLayer::PropertyFile },
377 { "alpha", QgsSymbolLayer::PropertyOpacity },
378 { "customdash", QgsSymbolLayer::PropertyCustomDash },
379 { "line_style", QgsSymbolLayer::PropertyStrokeStyle },
380 { "joinstyle", QgsSymbolLayer::PropertyJoinStyle },
381 { "capstyle", QgsSymbolLayer::PropertyCapStyle },
382 { "placement", QgsSymbolLayer::PropertyPlacement },
383 { "interval", QgsSymbolLayer::PropertyInterval },
384 { "offset_along_line", QgsSymbolLayer::PropertyOffsetAlongLine },
385 { "name", QgsSymbolLayer::PropertyName },
386 { "size", QgsSymbolLayer::PropertySize },
387 { "fill", QgsSymbolLayer::PropertyFillColor },
388 { "outline", QgsSymbolLayer::PropertyStrokeColor },
389 { "char", QgsSymbolLayer::PropertyCharacter },
390 { "enabled", QgsSymbolLayer::PropertyLayerEnabled },
391 { "rotation", QgsSymbolLayer::PropertyAngle },
392 { "horizontal_anchor_point", QgsSymbolLayer::PropertyHorizontalAnchor },
393 { "vertical_anchor_point", QgsSymbolLayer::PropertyVerticalAnchor },
394 };
395
396 QVariantMap::const_iterator propIt = stringMap.constBegin();
397 for ( ; propIt != stringMap.constEnd(); ++propIt )
398 {
399 std::unique_ptr<QgsProperty> prop;
400 QString propertyName;
401
402 if ( propIt.key().endsWith( QLatin1String( "_dd_expression" ) ) )
403 {
404 //found a data defined property
405
406 //get data defined property name by stripping "_dd_expression" from property key
407 propertyName = propIt.key().left( propIt.key().length() - 14 );
408
409 prop = std::make_unique<QgsProperty>( propertyFromMap( stringMap, propertyName ) );
410 }
411 else if ( propIt.key().endsWith( QLatin1String( "_expression" ) ) )
412 {
413 //old style data defined property, upgrade
414
415 //get data defined property name by stripping "_expression" from property key
416 propertyName = propIt.key().left( propIt.key().length() - 11 );
417
418 prop = std::make_unique<QgsProperty>( QgsProperty::fromExpression( propIt.value().toString() ) );
419 }
420
421 if ( !prop || !OLD_PROPS.contains( propertyName ) )
422 continue;
423
424 QgsSymbolLayer::Property key = static_cast< QgsSymbolLayer::Property >( OLD_PROPS.value( propertyName ) );
425
426 if ( type() == Qgis::SymbolType::Line )
427 {
428 //these keys had different meaning for line symbol layers
429 if ( propertyName == QLatin1String( "width" ) )
430 key = QgsSymbolLayer::PropertyStrokeWidth;
431 else if ( propertyName == QLatin1String( "color" ) )
432 key = QgsSymbolLayer::PropertyStrokeColor;
433 }
434
435 setDataDefinedProperty( key, QgsProperty( *prop.get() ) );
436 }
437 }
438
copyDataDefinedProperties(QgsSymbolLayer * destLayer) const439 void QgsSymbolLayer::copyDataDefinedProperties( QgsSymbolLayer *destLayer ) const
440 {
441 if ( !destLayer )
442 return;
443
444 destLayer->setDataDefinedProperties( mDataDefinedProperties );
445 }
446
copyPaintEffect(QgsSymbolLayer * destLayer) const447 void QgsSymbolLayer::copyPaintEffect( QgsSymbolLayer *destLayer ) const
448 {
449 if ( !destLayer || !mPaintEffect )
450 return;
451
452 if ( !QgsPaintEffectRegistry::isDefaultStack( mPaintEffect.get() ) )
453 destLayer->setPaintEffect( mPaintEffect->clone() );
454 else
455 destLayer->setPaintEffect( nullptr );
456 }
457
QgsMarkerSymbolLayer(bool locked)458 QgsMarkerSymbolLayer::QgsMarkerSymbolLayer( bool locked )
459 : QgsSymbolLayer( Qgis::SymbolType::Marker, locked )
460 {
461
462 }
463
QgsLineSymbolLayer(bool locked)464 QgsLineSymbolLayer::QgsLineSymbolLayer( bool locked )
465 : QgsSymbolLayer( Qgis::SymbolType::Line, locked )
466 {
467 }
468
ringFilter() const469 QgsLineSymbolLayer::RenderRingFilter QgsLineSymbolLayer::ringFilter() const
470 {
471 return mRingFilter;
472 }
473
setRingFilter(const RenderRingFilter filter)474 void QgsLineSymbolLayer::setRingFilter( const RenderRingFilter filter )
475 {
476 mRingFilter = filter;
477 }
478
QgsFillSymbolLayer(bool locked)479 QgsFillSymbolLayer::QgsFillSymbolLayer( bool locked )
480 : QgsSymbolLayer( Qgis::SymbolType::Fill, locked )
481 {
482 }
483
startRender(QgsSymbolRenderContext & context)484 void QgsMarkerSymbolLayer::startRender( QgsSymbolRenderContext &context )
485 {
486 Q_UNUSED( context )
487 }
488
stopRender(QgsSymbolRenderContext & context)489 void QgsMarkerSymbolLayer::stopRender( QgsSymbolRenderContext &context )
490 {
491 Q_UNUSED( context )
492 }
493
drawPreviewIcon(QgsSymbolRenderContext & context,QSize size)494 void QgsMarkerSymbolLayer::drawPreviewIcon( QgsSymbolRenderContext &context, QSize size )
495 {
496 startRender( context );
497 QgsPaintEffect *effect = paintEffect();
498
499 QPolygonF points = context.patchShape() ? context.patchShape()->toQPolygonF( Qgis::SymbolType::Marker, size ).value( 0 ).value( 0 )
500 : QgsStyle::defaultStyle()->defaultPatchAsQPolygonF( Qgis::SymbolType::Marker, size ).value( 0 ).value( 0 );
501
502 std::unique_ptr< QgsEffectPainter > effectPainter;
503 if ( effect && effect->enabled() )
504 effectPainter = std::make_unique< QgsEffectPainter >( context.renderContext(), effect );
505
506 for ( QPointF point : std::as_const( points ) )
507 renderPoint( point, context );
508
509 effectPainter.reset();
510
511 stopRender( context );
512 }
513
markerOffset(QgsSymbolRenderContext & context,double & offsetX,double & offsetY) const514 void QgsMarkerSymbolLayer::markerOffset( QgsSymbolRenderContext &context, double &offsetX, double &offsetY ) const
515 {
516 markerOffset( context, mSize, mSize, mSizeUnit, mSizeUnit, offsetX, offsetY, mSizeMapUnitScale, mSizeMapUnitScale );
517 }
518
markerOffset(QgsSymbolRenderContext & context,double width,double height,double & offsetX,double & offsetY) const519 void QgsMarkerSymbolLayer::markerOffset( QgsSymbolRenderContext &context, double width, double height, double &offsetX, double &offsetY ) const
520 {
521 markerOffset( context, width, height, mSizeUnit, mSizeUnit, offsetX, offsetY, mSizeMapUnitScale, mSizeMapUnitScale );
522 }
523
markerOffset(QgsSymbolRenderContext & context,double width,double height,QgsUnitTypes::RenderUnit widthUnit,QgsUnitTypes::RenderUnit heightUnit,double & offsetX,double & offsetY,const QgsMapUnitScale & widthMapUnitScale,const QgsMapUnitScale & heightMapUnitScale) const524 void QgsMarkerSymbolLayer::markerOffset( QgsSymbolRenderContext &context, double width, double height,
525 QgsUnitTypes::RenderUnit widthUnit, QgsUnitTypes::RenderUnit heightUnit,
526 double &offsetX, double &offsetY, const QgsMapUnitScale &widthMapUnitScale, const QgsMapUnitScale &heightMapUnitScale ) const
527 {
528 offsetX = mOffset.x();
529 offsetY = mOffset.y();
530
531 if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyOffset ) )
532 {
533 context.setOriginalValueVariable( QgsSymbolLayerUtils::encodePoint( mOffset ) );
534 QVariant exprVal = mDataDefinedProperties.value( QgsSymbolLayer::PropertyOffset, context.renderContext().expressionContext() );
535 bool ok = false;
536 const QPointF offset = QgsSymbolLayerUtils::toPoint( exprVal, &ok );
537 if ( ok )
538 {
539 offsetX = offset.x();
540 offsetY = offset.y();
541 }
542 }
543
544 offsetX = context.renderContext().convertToPainterUnits( offsetX, mOffsetUnit, mOffsetMapUnitScale );
545 offsetY = context.renderContext().convertToPainterUnits( offsetY, mOffsetUnit, mOffsetMapUnitScale );
546
547 HorizontalAnchorPoint horizontalAnchorPoint = mHorizontalAnchorPoint;
548 VerticalAnchorPoint verticalAnchorPoint = mVerticalAnchorPoint;
549 if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyHorizontalAnchor ) )
550 {
551 QVariant exprVal = mDataDefinedProperties.value( QgsSymbolLayer::PropertyHorizontalAnchor, context.renderContext().expressionContext() );
552 if ( !exprVal.isNull() )
553 {
554 horizontalAnchorPoint = decodeHorizontalAnchorPoint( exprVal.toString() );
555 }
556 }
557 if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyVerticalAnchor ) )
558 {
559 QVariant exprVal = mDataDefinedProperties.value( QgsSymbolLayer::PropertyVerticalAnchor, context.renderContext().expressionContext() );
560 if ( !exprVal.isNull() )
561 {
562 verticalAnchorPoint = decodeVerticalAnchorPoint( exprVal.toString() );
563 }
564 }
565
566 //correct horizontal position according to anchor point
567 if ( horizontalAnchorPoint == HCenter && verticalAnchorPoint == VCenter )
568 {
569 return;
570 }
571
572 double anchorPointCorrectionX = context.renderContext().convertToPainterUnits( width, widthUnit, widthMapUnitScale ) / 2.0;
573 if ( widthUnit == QgsUnitTypes::RenderMetersInMapUnits && context.renderContext().flags() & Qgis::RenderContextFlag::RenderSymbolPreview )
574 {
575 // rendering for symbol previews -- an size in meters in map units can't be calculated, so treat the size as millimeters
576 // and clamp it to a reasonable range. It's the best we can do in this situation!
577 anchorPointCorrectionX = std::min( std::max( context.renderContext().convertToPainterUnits( width, QgsUnitTypes::RenderMillimeters ), 3.0 ), 100.0 ) / 2.0;
578 }
579
580 double anchorPointCorrectionY = context.renderContext().convertToPainterUnits( height, heightUnit, heightMapUnitScale ) / 2.0;
581 if ( heightUnit == QgsUnitTypes::RenderMetersInMapUnits && context.renderContext().flags() & Qgis::RenderContextFlag::RenderSymbolPreview )
582 {
583 // rendering for symbol previews -- an size in meters in map units can't be calculated, so treat the size as millimeters
584 // and clamp it to a reasonable range. It's the best we can do in this situation!
585 anchorPointCorrectionY = std::min( std::max( context.renderContext().convertToPainterUnits( height, QgsUnitTypes::RenderMillimeters ), 3.0 ), 100.0 ) / 2.0;
586 }
587
588 if ( horizontalAnchorPoint == Left )
589 {
590 offsetX += anchorPointCorrectionX;
591 }
592 else if ( horizontalAnchorPoint == Right )
593 {
594 offsetX -= anchorPointCorrectionX;
595 }
596
597 //correct vertical position according to anchor point
598 if ( verticalAnchorPoint == Top )
599 {
600 offsetY += anchorPointCorrectionY;
601 }
602 else if ( verticalAnchorPoint == Bottom )
603 {
604 offsetY -= anchorPointCorrectionY;
605 }
606 }
607
_rotatedOffset(QPointF offset,double angle)608 QPointF QgsMarkerSymbolLayer::_rotatedOffset( QPointF offset, double angle )
609 {
610 angle = DEG2RAD( angle );
611 double c = std::cos( angle ), s = std::sin( angle );
612 return QPointF( offset.x() * c - offset.y() * s, offset.x() * s + offset.y() * c );
613 }
614
decodeHorizontalAnchorPoint(const QString & str)615 QgsMarkerSymbolLayer::HorizontalAnchorPoint QgsMarkerSymbolLayer::decodeHorizontalAnchorPoint( const QString &str )
616 {
617 if ( str.compare( QLatin1String( "left" ), Qt::CaseInsensitive ) == 0 )
618 {
619 return QgsMarkerSymbolLayer::Left;
620 }
621 else if ( str.compare( QLatin1String( "right" ), Qt::CaseInsensitive ) == 0 )
622 {
623 return QgsMarkerSymbolLayer::Right;
624 }
625 else
626 {
627 return QgsMarkerSymbolLayer::HCenter;
628 }
629 }
630
decodeVerticalAnchorPoint(const QString & str)631 QgsMarkerSymbolLayer::VerticalAnchorPoint QgsMarkerSymbolLayer::decodeVerticalAnchorPoint( const QString &str )
632 {
633 if ( str.compare( QLatin1String( "top" ), Qt::CaseInsensitive ) == 0 )
634 {
635 return QgsMarkerSymbolLayer::Top;
636 }
637 else if ( str.compare( QLatin1String( "bottom" ), Qt::CaseInsensitive ) == 0 )
638 {
639 return QgsMarkerSymbolLayer::Bottom;
640 }
641 else
642 {
643 return QgsMarkerSymbolLayer::VCenter;
644 }
645 }
646
setOutputUnit(QgsUnitTypes::RenderUnit unit)647 void QgsMarkerSymbolLayer::setOutputUnit( QgsUnitTypes::RenderUnit unit )
648 {
649 mSizeUnit = unit;
650 mOffsetUnit = unit;
651 }
652
outputUnit() const653 QgsUnitTypes::RenderUnit QgsMarkerSymbolLayer::outputUnit() const
654 {
655 if ( mOffsetUnit != mSizeUnit )
656 {
657 return QgsUnitTypes::RenderUnknownUnit;
658 }
659 return mOffsetUnit;
660 }
661
setMapUnitScale(const QgsMapUnitScale & scale)662 void QgsMarkerSymbolLayer::setMapUnitScale( const QgsMapUnitScale &scale )
663 {
664 mSizeMapUnitScale = scale;
665 mOffsetMapUnitScale = scale;
666 }
667
mapUnitScale() const668 QgsMapUnitScale QgsMarkerSymbolLayer::mapUnitScale() const
669 {
670 if ( mSizeMapUnitScale == mOffsetMapUnitScale )
671 {
672 return mSizeMapUnitScale;
673 }
674 return QgsMapUnitScale();
675 }
676
setOutputUnit(QgsUnitTypes::RenderUnit unit)677 void QgsLineSymbolLayer::setOutputUnit( QgsUnitTypes::RenderUnit unit )
678 {
679 mWidthUnit = unit;
680 }
681
outputUnit() const682 QgsUnitTypes::RenderUnit QgsLineSymbolLayer::outputUnit() const
683 {
684 return mWidthUnit;
685 }
686
setMapUnitScale(const QgsMapUnitScale & scale)687 void QgsLineSymbolLayer::setMapUnitScale( const QgsMapUnitScale &scale )
688 {
689 mWidthMapUnitScale = scale;
690 }
691
mapUnitScale() const692 QgsMapUnitScale QgsLineSymbolLayer::mapUnitScale() const
693 {
694 return mWidthMapUnitScale;
695 }
696
697
drawPreviewIcon(QgsSymbolRenderContext & context,QSize size)698 void QgsLineSymbolLayer::drawPreviewIcon( QgsSymbolRenderContext &context, QSize size )
699 {
700 const QList< QList< QPolygonF > > points = context.patchShape() ? context.patchShape()->toQPolygonF( Qgis::SymbolType::Line, size )
701 : QgsStyle::defaultStyle()->defaultPatchAsQPolygonF( Qgis::SymbolType::Line, size );
702 startRender( context );
703 QgsPaintEffect *effect = paintEffect();
704
705 std::unique_ptr< QgsEffectPainter > effectPainter;
706 if ( effect && effect->enabled() )
707 effectPainter = std::make_unique< QgsEffectPainter >( context.renderContext(), effect );
708
709 for ( const QList< QPolygonF > &line : points )
710 renderPolyline( line.value( 0 ), context );
711
712 effectPainter.reset();
713
714 stopRender( context );
715 }
716
renderPolygonStroke(const QPolygonF & points,const QVector<QPolygonF> * rings,QgsSymbolRenderContext & context)717 void QgsLineSymbolLayer::renderPolygonStroke( const QPolygonF &points, const QVector<QPolygonF> *rings, QgsSymbolRenderContext &context )
718 {
719 QgsExpressionContextScope *scope = nullptr;
720 std::unique_ptr< QgsExpressionContextScopePopper > scopePopper;
721 if ( hasDataDefinedProperties() )
722 {
723 scope = new QgsExpressionContextScope();
724 scopePopper = std::make_unique< QgsExpressionContextScopePopper >( context.renderContext().expressionContext(), scope );
725 }
726
727 switch ( mRingFilter )
728 {
729 case AllRings:
730 case ExteriorRingOnly:
731 {
732 if ( scope )
733 scope->addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_GEOMETRY_RING_NUM, 0, true ) );
734 renderPolyline( points, context );
735 break;
736 }
737 case InteriorRingsOnly:
738 break;
739 }
740
741 if ( rings )
742 {
743 switch ( mRingFilter )
744 {
745 case AllRings:
746 case InteriorRingsOnly:
747 {
748 int ringIndex = 1;
749 for ( const QPolygonF &ring : std::as_const( *rings ) )
750 {
751 if ( scope )
752 scope->addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_GEOMETRY_RING_NUM, ringIndex, true ) );
753
754 renderPolyline( ring, context );
755 ringIndex++;
756 }
757 }
758 break;
759 case ExteriorRingOnly:
760 break;
761 }
762 }
763 }
764
width(const QgsRenderContext & context) const765 double QgsLineSymbolLayer::width( const QgsRenderContext &context ) const
766 {
767 return context.convertToPainterUnits( mWidth, mWidthUnit, mWidthMapUnitScale );
768 }
769
dxfWidth(const QgsDxfExport & e,QgsSymbolRenderContext & context) const770 double QgsLineSymbolLayer::dxfWidth( const QgsDxfExport &e, QgsSymbolRenderContext &context ) const
771 {
772 Q_UNUSED( context )
773 return width() * e.mapUnitScaleFactor( e.symbologyScale(), widthUnit(), e.mapUnits(), context.renderContext().mapToPixel().mapUnitsPerPixel() );
774 }
775
776
drawPreviewIcon(QgsSymbolRenderContext & context,QSize size)777 void QgsFillSymbolLayer::drawPreviewIcon( QgsSymbolRenderContext &context, QSize size )
778 {
779 const QList< QList< QPolygonF > > polys = context.patchShape() ? context.patchShape()->toQPolygonF( Qgis::SymbolType::Fill, size )
780 : QgsStyle::defaultStyle()->defaultPatchAsQPolygonF( Qgis::SymbolType::Fill, size );
781
782 startRender( context );
783 QgsPaintEffect *effect = paintEffect();
784
785 std::unique_ptr< QgsEffectPainter > effectPainter;
786 if ( effect && effect->enabled() )
787 effectPainter = std::make_unique< QgsEffectPainter >( context.renderContext(), effect );
788
789 for ( const QList< QPolygonF > &poly : polys )
790 {
791 QVector< QPolygonF > rings;
792 for ( int i = 1; i < poly.size(); ++i )
793 rings << poly.at( i );
794 renderPolygon( poly.value( 0 ), &rings, context );
795 }
796
797 effectPainter.reset();
798
799 stopRender( context );
800 }
801
_renderPolygon(QPainter * p,const QPolygonF & points,const QVector<QPolygonF> * rings,QgsSymbolRenderContext & context)802 void QgsFillSymbolLayer::_renderPolygon( QPainter *p, const QPolygonF &points, const QVector<QPolygonF> *rings, QgsSymbolRenderContext &context )
803 {
804 if ( !p )
805 {
806 return;
807 }
808
809 // Disable 'Antialiasing' if the geometry was generalized in the current RenderContext (We known that it must have least #5 points).
810 if ( points.size() <= 5 &&
811 ( context.renderContext().vectorSimplifyMethod().simplifyHints() & QgsVectorSimplifyMethod::AntialiasingSimplification ) &&
812 QgsAbstractGeometrySimplifier::isGeneralizableByDeviceBoundingBox( points, context.renderContext().vectorSimplifyMethod().threshold() ) &&
813 ( p->renderHints() & QPainter::Antialiasing ) )
814 {
815 p->setRenderHint( QPainter::Antialiasing, false );
816 p->drawRect( points.boundingRect() );
817 p->setRenderHint( QPainter::Antialiasing, true );
818 return;
819 }
820
821 // polygons outlines are sometimes rendered wrongly with drawPolygon, when
822 // clipped (see #13343), so use drawPath instead.
823 if ( !rings && p->pen().style() == Qt::NoPen )
824 {
825 // simple polygon without holes
826 p->drawPolygon( points );
827 }
828 else
829 {
830 // polygon with holes must be drawn using painter path
831 QPainterPath path;
832 path.addPolygon( points );
833
834 if ( rings )
835 {
836 for ( auto it = rings->constBegin(); it != rings->constEnd(); ++it )
837 {
838 QPolygonF ring = *it;
839 path.addPolygon( ring );
840 }
841 }
842
843 p->drawPath( path );
844 }
845 }
846
toSld(QDomDocument & doc,QDomElement & element,const QVariantMap & props) const847 void QgsMarkerSymbolLayer::toSld( QDomDocument &doc, QDomElement &element, const QVariantMap &props ) const
848 {
849 QDomElement symbolizerElem = doc.createElement( QStringLiteral( "se:PointSymbolizer" ) );
850 if ( !props.value( QStringLiteral( "uom" ), QString() ).toString().isEmpty() )
851 symbolizerElem.setAttribute( QStringLiteral( "uom" ), props.value( QStringLiteral( "uom" ), QString() ).toString() );
852 element.appendChild( symbolizerElem );
853
854 // <Geometry>
855 QgsSymbolLayerUtils::createGeometryElement( doc, symbolizerElem, props.value( QStringLiteral( "geom" ), QString() ).toString() );
856
857 writeSldMarker( doc, symbolizerElem, props );
858 }
859
masks() const860 QList<QgsSymbolLayerReference> QgsSymbolLayer::masks() const
861 {
862 return {};
863 }
864
865