QGIS API Documentation 3.37.0-Master (fdefdf9c27f)
qgslinesymbol.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgslinesymbol.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 "qgslinesymbol.h"
17#include "qgslinesymbollayer.h"
19#include "qgssymbollayerutils.h"
20#include "qgspainteffect.h"
21
22QgsLineSymbol *QgsLineSymbol::createSimple( const QVariantMap &properties )
23{
25 if ( !sl )
26 return nullptr;
27
28 QgsSymbolLayerList layers;
29 layers.append( sl );
30 return new QgsLineSymbol( layers );
31}
32
34 : QgsSymbol( Qgis::SymbolType::Line, layers )
35{
36 if ( mLayers.isEmpty() )
37 mLayers.append( new QgsSimpleLineSymbolLayer() );
38}
39
40void QgsLineSymbol::setWidth( double w ) const
41{
42 const double origWidth = width();
43
44 const auto constMLayers = mLayers;
45 for ( QgsSymbolLayer *layer : constMLayers )
46 {
47 QgsLineSymbolLayer *lineLayer = dynamic_cast<QgsLineSymbolLayer *>( layer );
48 if ( lineLayer )
49 {
50 if ( qgsDoubleNear( lineLayer->width(), origWidth ) )
51 {
52 lineLayer->setWidth( w );
53 }
54 else if ( !qgsDoubleNear( origWidth, 0.0 ) )
55 {
56 // proportionally scale the width
57 lineLayer->setWidth( lineLayer->width() * w / origWidth );
58 }
59 // also scale offset to maintain relative position
60 if ( !qgsDoubleNear( origWidth, 0.0 ) && !qgsDoubleNear( lineLayer->offset(), 0.0 ) )
61 lineLayer->setOffset( lineLayer->offset() * w / origWidth );
62 }
63 else
64 {
65 QgsGeometryGeneratorSymbolLayer *geomGeneratorLayer = dynamic_cast<QgsGeometryGeneratorSymbolLayer *>( layer );
66 if ( geomGeneratorLayer && geomGeneratorLayer->symbolType() == Qgis::SymbolType::Line )
67 {
68 QgsLineSymbol *lineSymbol = qgis::down_cast<QgsLineSymbol *>( geomGeneratorLayer->subSymbol() );
69 if ( qgsDoubleNear( lineSymbol->width(), origWidth ) )
70 {
71 lineSymbol->setWidth( w );
72 }
73 else if ( !qgsDoubleNear( origWidth, 0.0 ) )
74 {
75 // proportionally scale the width
76 lineSymbol->setWidth( lineSymbol->width() * w / origWidth );
77 }
78 }
79 }
80 }
81}
82
84{
85 const auto constLLayers = mLayers;
86 for ( QgsSymbolLayer *layer : constLLayers )
87 {
89 continue;
90
91 QgsLineSymbolLayer *lineLayer = static_cast<QgsLineSymbolLayer *>( layer );
92 lineLayer->setWidthUnit( unit );
93 }
94}
95
97{
98 double maxWidth = 0;
99 if ( mLayers.isEmpty() )
100 return maxWidth;
101
102 const auto constMLayers = mLayers;
103 for ( QgsSymbolLayer *symbolLayer : constMLayers )
104 {
105 const QgsLineSymbolLayer *lineLayer = dynamic_cast<QgsLineSymbolLayer *>( symbolLayer );
106 if ( lineLayer )
107 {
108 const double width = lineLayer->width();
109 if ( width > maxWidth )
110 maxWidth = width;
111 }
112 else
113 {
114 QgsGeometryGeneratorSymbolLayer *geomGeneratorLayer = dynamic_cast<QgsGeometryGeneratorSymbolLayer *>( symbolLayer );
115 if ( geomGeneratorLayer && geomGeneratorLayer->symbolType() == Qgis::SymbolType::Line )
116 {
117 QgsLineSymbol *lineSymbol = qgis::down_cast<QgsLineSymbol *>( geomGeneratorLayer->subSymbol() );
118 const double width = lineSymbol->width();
119 if ( width > maxWidth )
120 maxWidth = width;
121 }
122 }
123 }
124 return maxWidth;
125}
126
127double QgsLineSymbol::width( const QgsRenderContext &context ) const
128{
129 // return width of the largest symbol
130 double maxWidth = 0;
131 for ( QgsSymbolLayer *layer : mLayers )
132 {
134 continue;
135 const QgsLineSymbolLayer *lineLayer = static_cast<const QgsLineSymbolLayer *>( layer );
136 const double layerWidth = lineLayer->width( context );
137 maxWidth = std::max( maxWidth, layerWidth );
138 }
139 return maxWidth;
140}
141
143{
144 const double symbolWidth = width();
145
146 const auto constMLayers = mLayers;
147 for ( QgsSymbolLayer *layer : constMLayers )
148 {
149 QgsLineSymbolLayer *lineLayer = dynamic_cast<QgsLineSymbolLayer *>( layer );
150
151 if ( lineLayer )
152 {
153 if ( !property )
154 {
157 }
158 else
159 {
160 if ( qgsDoubleNear( symbolWidth, 0.0 ) || qgsDoubleNear( lineLayer->width(), symbolWidth ) )
161 {
163 }
164 else
165 {
166 lineLayer->setDataDefinedProperty( QgsSymbolLayer::Property::StrokeWidth, QgsSymbolLayerUtils::scaleWholeSymbol( lineLayer->width() / symbolWidth, property ) );
167 }
168
169 if ( !qgsDoubleNear( lineLayer->offset(), 0.0 ) )
170 {
171 lineLayer->setDataDefinedProperty( QgsSymbolLayer::Property::Offset, QgsSymbolLayerUtils::scaleWholeSymbol( lineLayer->offset() / symbolWidth, property ) );
172 }
173 }
174 }
175 }
176}
177
179{
180 const double symbolWidth = width();
181
182 QgsProperty symbolDD;
183
184 // find the base of the "en masse" pattern
185 for ( QgsSymbolLayerList::const_iterator it = mLayers.begin(); it != mLayers.end(); ++it )
186 {
187 const QgsLineSymbolLayer *layer = dynamic_cast<const QgsLineSymbolLayer *>( *it );
188 if ( layer && qgsDoubleNear( layer->width(), symbolWidth ) && layer->dataDefinedProperties().isActive( QgsSymbolLayer::Property::StrokeWidth ) )
189 {
190 symbolDD = layer->dataDefinedProperties().property( QgsSymbolLayer::Property::StrokeWidth );
191 break;
192 }
193 }
194
195 if ( !symbolDD )
196 return QgsProperty();
197
198 // check that all layers width expressions match the "en masse" pattern
199 const auto constMLayers = mLayers;
200 for ( QgsSymbolLayer *layer : constMLayers )
201 {
203 continue;
204 const QgsLineSymbolLayer *lineLayer = static_cast<const QgsLineSymbolLayer *>( layer );
205
208
209 if ( qgsDoubleNear( lineLayer->width(), symbolWidth ) )
210 {
211 if ( !layerWidthDD || layerWidthDD != symbolDD )
212 return QgsProperty();
213 }
214 else
215 {
216 if ( qgsDoubleNear( symbolWidth, 0.0 ) )
217 return QgsProperty();
218
219 const QgsProperty scaledDD( QgsSymbolLayerUtils::scaleWholeSymbol( lineLayer->width() / symbolWidth, symbolDD ) );
220 if ( !layerWidthDD || layerWidthDD != scaledDD )
221 return QgsProperty();
222 }
223
224 const QgsProperty scaledOffsetDD( QgsSymbolLayerUtils::scaleWholeSymbol( lineLayer->offset() / symbolWidth, symbolDD ) );
225 if ( layerOffsetDD && layerOffsetDD != scaledOffsetDD )
226 return QgsProperty();
227 }
228
229 return symbolDD;
230}
231
232void QgsLineSymbol::renderPolyline( const QPolygonF &points, const QgsFeature *f, QgsRenderContext &context, int layerIdx, bool selected )
233{
235 : mOpacity;
236
237 //save old painter
238 QPainter *renderPainter = context.painter();
239 QgsSymbolRenderContext symbolContext( context, Qgis::RenderUnit::Unknown, opacity, selected, mRenderHints, f );
241 symbolContext.setGeometryPartCount( symbolRenderContext()->geometryPartCount() );
242 symbolContext.setGeometryPartNum( symbolRenderContext()->geometryPartNum() );
243
244 if ( layerIdx != -1 )
245 {
246 QgsSymbolLayer *symbolLayer = mLayers.value( layerIdx );
248 {
250 {
251 QgsLineSymbolLayer *lineLayer = static_cast<QgsLineSymbolLayer *>( symbolLayer );
252 renderPolylineUsingLayer( lineLayer, points, symbolContext );
253 }
254 else
255 renderUsingLayer( symbolLayer, symbolContext, Qgis::GeometryType::Line, &points );
256 }
257 return;
258 }
259
260 const auto constMLayers = mLayers;
261 for ( QgsSymbolLayer *symbolLayer : constMLayers )
262 {
263 if ( context.renderingStopped() )
264 break;
265
266 if ( !symbolLayer->enabled() || !context.isSymbolLayerEnabled( symbolLayer ) )
267 continue;
268
270 {
271 QgsLineSymbolLayer *lineLayer = static_cast<QgsLineSymbolLayer *>( symbolLayer );
272 renderPolylineUsingLayer( lineLayer, points, symbolContext );
273 }
274 else
275 {
276 renderUsingLayer( symbolLayer, symbolContext, Qgis::GeometryType::Line, &points );
277 }
278 }
279
280 context.setPainter( renderPainter );
281}
282
283void QgsLineSymbol::renderPolylineUsingLayer( QgsLineSymbolLayer *layer, const QPolygonF &points, QgsSymbolRenderContext &context )
284{
285 if ( layer->dataDefinedProperties().hasActiveProperties() && !layer->dataDefinedProperties().valueAsBool( QgsSymbolLayer::Property::LayerEnabled, context.renderContext().expressionContext(), true ) )
286 return;
287
288 QgsPaintEffect *effect = layer->paintEffect();
289 if ( effect && effect->enabled() )
290 {
291 QgsEffectPainter p( context.renderContext() );
292 p->translate( points.boundingRect().topLeft() );
293 p.setEffect( effect );
294 layer->renderPolyline( points.translated( -points.boundingRect().topLeft() ), context );
295 }
296 else
297 {
298 layer->renderPolyline( points, context );
299 }
300}
301
302
304{
305 QgsLineSymbol *cloneSymbol = new QgsLineSymbol( cloneLayers() );
306 cloneSymbol->setOpacity( mOpacity );
308 cloneSymbol->setLayer( mLayer );
311 cloneSymbol->setForceRHR( mForceRHR );
313 cloneSymbol->setFlags( mSymbolFlags );
315 return cloneSymbol;
316}
The Qgis class provides global constants for use throughout the application.
Definition: qgis.h:54
RenderUnit
Rendering size units.
Definition: qgis.h:4255
@ Unknown
Mixed or unknown units.
@ Line
Line symbol.
double valueAsDouble(int key, const QgsExpressionContext &context, double defaultValue=0.0, bool *ok=nullptr) const
Calculates the current value of the property with the specified key and interprets it as a double.
A class to manager painter saving and restoring required for effect drawing.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition: qgsfeature.h:56
Qgis::SymbolType symbolType() const
Access the symbol type.
QgsSymbol * subSymbol() override
Returns the symbol's sub symbol, if present.
virtual void setWidth(double width)
Sets the width of the line symbol layer.
void setOffset(double offset)
Sets the line's offset.
void setWidthUnit(Qgis::RenderUnit unit)
Sets the units for the line's width.
virtual double width() const
Returns the estimated width for the line symbol layer.
double offset() const
Returns the line's offset.
A line symbol type, for rendering LineString and MultiLineString geometries.
Definition: qgslinesymbol.h:30
void setWidthUnit(Qgis::RenderUnit unit) const
Sets the width units for the whole symbol (including all symbol layers).
void setDataDefinedWidth(const QgsProperty &property) const
Set data defined width for whole symbol (including all symbol layers).
QgsLineSymbol * clone() const override
Returns a deep copy of this symbol.
void setWidth(double width) const
Sets the width for the whole line symbol.
void renderPolyline(const QPolygonF &points, const QgsFeature *f, QgsRenderContext &context, int layer=-1, bool selected=false)
Renders the symbol along the line joining points, using the given render context.
double width() const
Returns the estimated width for the whole symbol, which is the maximum width of all marker symbol lay...
static QgsLineSymbol * createSimple(const QVariantMap &properties)
Create a line symbol with one symbol layer: SimpleLine with specified properties.
QgsLineSymbol(const QgsSymbolLayerList &layers=QgsSymbolLayerList())
Constructor for QgsLineSymbol, with the specified list of initial symbol layers.
QgsProperty dataDefinedWidth() const
Returns data defined width for whole symbol (including all symbol layers).
Qgis::LayerType type
Definition: qgsmaplayer.h:82
Base class for visual effects which can be applied to QPicture drawings.
bool enabled() const
Returns whether the effect is enabled.
bool hasActiveProperties() const final
Returns true if the collection has any active properties, or false if all properties within the colle...
QgsProperty property(int key) const final
Returns a matching property from the collection, if one exists.
A store for object properties.
Definition: qgsproperty.h:228
Contains information about the context of a rendering operation.
QPainter * painter()
Returns the destination QPainter for the render operation.
QgsExpressionContext & expressionContext()
Gets the expression context.
void setPainter(QPainter *p)
Sets the destination QPainter for the render operation.
bool isSymbolLayerEnabled(const QgsSymbolLayer *layer) const
When rendering a map layer in a second pass (for selective masking), some symbol layers may be disabl...
bool renderingStopped() const
Returns true if the rendering operation has been stopped and any ongoing rendering should be canceled...
A simple line symbol layer, which renders lines using a line in a variety of styles (e....
static QgsSymbolLayer * create(const QVariantMap &properties=QVariantMap())
Creates a new QgsSimpleLineSymbolLayer, using the settings serialized in the properties map (correspo...
Qgis::SymbolType type() const
@ StrokeWidth
Stroke width.
@ Offset
Symbol offset.
@ LayerEnabled
Whether symbol layer is enabled.
bool enabled() const
Returns true if symbol layer is enabled and will be drawn.
virtual void setDataDefinedProperty(Property key, const QgsProperty &property)
Sets a data defined property for the layer.
QgsPropertyCollection & dataDefinedProperties()
Returns a reference to the symbol layer's property collection, used for data defined overrides.
void setOriginalGeometryType(Qgis::GeometryType type)
Sets the geometry type for the original feature geometry being rendered.
void setGeometryPartCount(int count)
Sets the part count of current geometry.
void setGeometryPartNum(int num)
Sets the part number of current geometry.
QgsRenderContext & renderContext()
Returns a reference to the context's render context.
Abstract base class for all rendered symbols.
Definition: qgssymbol.h:94
void setDataDefinedProperties(const QgsPropertyCollection &collection)
Sets the symbol's property collection, used for data defined overrides.
Definition: qgssymbol.h:635
void renderUsingLayer(QgsSymbolLayer *layer, QgsSymbolRenderContext &context, Qgis::GeometryType geometryType=Qgis::GeometryType::Unknown, const QPolygonF *points=nullptr, const QVector< QPolygonF > *rings=nullptr)
Renders a context using a particular symbol layer without passing in a geometry.
Definition: qgssymbol.cpp:1180
Qgis::SymbolFlags mSymbolFlags
Symbol flags.
Definition: qgssymbol.h:794
QgsSymbolLayerList cloneLayers() const
Retrieve a cloned list of all layers that make up this symbol.
Definition: qgssymbol.cpp:1164
QgsSymbolRenderContext * symbolRenderContext()
Returns the symbol render context.
Definition: qgssymbol.cpp:1841
QgsSymbolLayer * symbolLayer(int layer)
Returns the symbol layer at the specified index.
Definition: qgssymbol.cpp:760
QgsPropertyCollection & dataDefinedProperties()
Returns a reference to the symbol's property collection, used for data defined overrides.
Definition: qgssymbol.h:620
qreal mOpacity
Symbol opacity (in the range 0 - 1)
Definition: qgssymbol.h:785
Q_DECL_DEPRECATED const QgsVectorLayer * mLayer
Definition: qgssymbol.h:801
bool mClipFeaturesToExtent
Definition: qgssymbol.h:796
qreal opacity() const
Returns the opacity for the symbol.
Definition: qgssymbol.h:495
void setFlags(Qgis::SymbolFlags flags)
Sets flags for the symbol.
Definition: qgssymbol.h:522
void setOpacity(qreal opacity)
Sets the opacity for the symbol.
Definition: qgssymbol.h:502
Qgis::SymbolRenderHints mRenderHints
Definition: qgssymbol.h:787
bool mForceRHR
Definition: qgssymbol.h:797
QgsSymbolLayerList mLayers
Definition: qgssymbol.h:782
Q_DECL_DEPRECATED const QgsVectorLayer * layer() const
Definition: qgssymbol.cpp:1253
QgsSymbolAnimationSettings mAnimationSettings
Definition: qgssymbol.h:799
void setAnimationSettings(const QgsSymbolAnimationSettings &settings)
Sets a the symbol animation settings.
Definition: qgssymbol.cpp:700
Q_DECL_DEPRECATED void setLayer(const QgsVectorLayer *layer)
Definition: qgssymbol.cpp:1246
void setClipFeaturesToExtent(bool clipFeaturesToExtent)
Sets whether features drawn by the symbol should be clipped to the render context's extent.
Definition: qgssymbol.h:540
void setForceRHR(bool force)
Sets whether polygon features drawn by the symbol should be reoriented to follow the standard right-h...
Definition: qgssymbol.h:561
#define Q_NOWARN_DEPRECATED_POP
Definition: qgis.h:5776
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:5775
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:5207
QList< QgsSymbolLayer * > QgsSymbolLayerList
Definition: qgssymbol.h:30