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