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