QGIS API Documentation  3.24.2-Tisler (13c1a02865)
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"
18 #include "qgssymbollayerutils.h"
19 #include "qgspainteffect.h"
20 
21 QgsLineSymbol *QgsLineSymbol::createSimple( const QVariantMap &properties )
22 {
24  if ( !sl )
25  return nullptr;
26 
27  QgsSymbolLayerList layers;
28  layers.append( sl );
29  return new QgsLineSymbol( layers );
30 }
31 
33  : QgsSymbol( Qgis::SymbolType::Line, layers )
34 {
35  if ( mLayers.isEmpty() )
36  mLayers.append( new QgsSimpleLineSymbolLayer() );
37 }
38 
39 void QgsLineSymbol::setWidth( double w )
40 {
41  const double origWidth = width();
42 
43  const auto constMLayers = mLayers;
44  for ( QgsSymbolLayer *layer : constMLayers )
45  {
46  QgsLineSymbolLayer *lineLayer = dynamic_cast<QgsLineSymbolLayer *>( layer );
47 
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  }
64 }
65 
67 {
68  const auto constLLayers = mLayers;
69  for ( QgsSymbolLayer *layer : constLLayers )
70  {
71  if ( layer->type() != Qgis::SymbolType::Line )
72  continue;
73 
74  QgsLineSymbolLayer *lineLayer = static_cast<QgsLineSymbolLayer *>( layer );
75  lineLayer->setWidthUnit( unit );
76  }
77 }
78 
79 double QgsLineSymbol::width() const
80 {
81  double maxWidth = 0;
82  if ( mLayers.isEmpty() )
83  return maxWidth;
84 
85  const auto constMLayers = mLayers;
86  for ( QgsSymbolLayer *symbolLayer : constMLayers )
87  {
88  const QgsLineSymbolLayer *lineLayer = dynamic_cast<QgsLineSymbolLayer *>( symbolLayer );
89  if ( lineLayer )
90  {
91  const double width = lineLayer->width();
92  if ( width > maxWidth )
93  maxWidth = width;
94  }
95  }
96  return maxWidth;
97 }
98 
99 double QgsLineSymbol::width( const QgsRenderContext &context ) const
100 {
101  // return width of the largest symbol
102  double maxWidth = 0;
103  for ( QgsSymbolLayer *layer : mLayers )
104  {
105  if ( layer->type() != Qgis::SymbolType::Line )
106  continue;
107  const QgsLineSymbolLayer *lineLayer = static_cast<const QgsLineSymbolLayer *>( layer );
108  const double layerWidth = lineLayer->width( context );
109  maxWidth = std::max( maxWidth, layerWidth );
110  }
111  return maxWidth;
112 }
113 
115 {
116  const double symbolWidth = width();
117 
118  const auto constMLayers = mLayers;
119  for ( QgsSymbolLayer *layer : constMLayers )
120  {
121  QgsLineSymbolLayer *lineLayer = dynamic_cast<QgsLineSymbolLayer *>( layer );
122 
123  if ( lineLayer )
124  {
125  if ( !property )
126  {
129  }
130  else
131  {
132  if ( qgsDoubleNear( symbolWidth, 0.0 ) || qgsDoubleNear( lineLayer->width(), symbolWidth ) )
133  {
135  }
136  else
137  {
138  lineLayer->setDataDefinedProperty( QgsSymbolLayer::PropertyStrokeWidth, QgsSymbolLayerUtils::scaleWholeSymbol( lineLayer->width() / symbolWidth, property ) );
139  }
140 
141  if ( !qgsDoubleNear( lineLayer->offset(), 0.0 ) )
142  {
143  lineLayer->setDataDefinedProperty( QgsSymbolLayer::PropertyOffset, QgsSymbolLayerUtils::scaleWholeSymbol( lineLayer->offset() / symbolWidth, property ) );
144  }
145  }
146  }
147  }
148 }
149 
151 {
152  const double symbolWidth = width();
153 
154  QgsProperty symbolDD;
155 
156  // find the base of the "en masse" pattern
157  for ( QgsSymbolLayerList::const_iterator it = mLayers.begin(); it != mLayers.end(); ++it )
158  {
159  const QgsLineSymbolLayer *layer = dynamic_cast<const QgsLineSymbolLayer *>( *it );
160  if ( layer && qgsDoubleNear( layer->width(), symbolWidth ) && layer->dataDefinedProperties().isActive( QgsSymbolLayer::PropertyStrokeWidth ) )
161  {
162  symbolDD = layer->dataDefinedProperties().property( QgsSymbolLayer::PropertyStrokeWidth );
163  break;
164  }
165  }
166 
167  if ( !symbolDD )
168  return QgsProperty();
169 
170  // check that all layers width expressions match the "en masse" pattern
171  const auto constMLayers = mLayers;
172  for ( QgsSymbolLayer *layer : constMLayers )
173  {
174  if ( layer->type() != Qgis::SymbolType::Line )
175  continue;
176  const QgsLineSymbolLayer *lineLayer = static_cast<const QgsLineSymbolLayer *>( layer );
177 
179  const QgsProperty layerOffsetDD = lineLayer->dataDefinedProperties().property( QgsSymbolLayer::PropertyOffset );
180 
181  if ( qgsDoubleNear( lineLayer->width(), symbolWidth ) )
182  {
183  if ( !layerWidthDD || layerWidthDD != symbolDD )
184  return QgsProperty();
185  }
186  else
187  {
188  if ( qgsDoubleNear( symbolWidth, 0.0 ) )
189  return QgsProperty();
190 
191  const QgsProperty scaledDD( QgsSymbolLayerUtils::scaleWholeSymbol( lineLayer->width() / symbolWidth, symbolDD ) );
192  if ( !layerWidthDD || layerWidthDD != scaledDD )
193  return QgsProperty();
194  }
195 
196  const QgsProperty scaledOffsetDD( QgsSymbolLayerUtils::scaleWholeSymbol( lineLayer->offset() / symbolWidth, symbolDD ) );
197  if ( layerOffsetDD && layerOffsetDD != scaledOffsetDD )
198  return QgsProperty();
199  }
200 
201  return symbolDD;
202 }
203 
204 void QgsLineSymbol::renderPolyline( const QPolygonF &points, const QgsFeature *f, QgsRenderContext &context, int layerIdx, bool selected )
205 {
207  : mOpacity;
208 
209  //save old painter
210  QPainter *renderPainter = context.painter();
211  QgsSymbolRenderContext symbolContext( context, QgsUnitTypes::RenderUnknownUnit, opacity, selected, mRenderHints, f );
213  symbolContext.setGeometryPartCount( symbolRenderContext()->geometryPartCount() );
214  symbolContext.setGeometryPartNum( symbolRenderContext()->geometryPartNum() );
215 
216  if ( layerIdx != -1 )
217  {
218  QgsSymbolLayer *symbolLayer = mLayers.value( layerIdx );
220  {
222  {
223  QgsLineSymbolLayer *lineLayer = static_cast<QgsLineSymbolLayer *>( symbolLayer );
224  renderPolylineUsingLayer( lineLayer, points, symbolContext );
225  }
226  else
227  renderUsingLayer( symbolLayer, symbolContext, QgsWkbTypes::LineGeometry, &points );
228  }
229  return;
230  }
231 
232  const auto constMLayers = mLayers;
233  for ( QgsSymbolLayer *symbolLayer : constMLayers )
234  {
235  if ( context.renderingStopped() )
236  break;
237 
238  if ( !symbolLayer->enabled() || !context.isSymbolLayerEnabled( symbolLayer ) )
239  continue;
240 
242  {
243  QgsLineSymbolLayer *lineLayer = static_cast<QgsLineSymbolLayer *>( symbolLayer );
244  renderPolylineUsingLayer( lineLayer, points, symbolContext );
245  }
246  else
247  {
248  renderUsingLayer( symbolLayer, symbolContext, QgsWkbTypes::LineGeometry, &points );
249  }
250  }
251 
252  context.setPainter( renderPainter );
253 }
254 
255 void QgsLineSymbol::renderPolylineUsingLayer( QgsLineSymbolLayer *layer, const QPolygonF &points, QgsSymbolRenderContext &context )
256 {
257  if ( layer->dataDefinedProperties().hasActiveProperties() && !layer->dataDefinedProperties().valueAsBool( QgsSymbolLayer::PropertyLayerEnabled, context.renderContext().expressionContext(), true ) )
258  return;
259 
260  QgsPaintEffect *effect = layer->paintEffect();
261  if ( effect && effect->enabled() )
262  {
263  QgsEffectPainter p( context.renderContext() );
264  p->translate( points.boundingRect().topLeft() );
265  p.setEffect( effect );
266  layer->renderPolyline( points.translated( -points.boundingRect().topLeft() ), context );
267  }
268  else
269  {
270  layer->renderPolyline( points, context );
271  }
272 }
273 
274 
276 {
277  QgsLineSymbol *cloneSymbol = new QgsLineSymbol( cloneLayers() );
278  cloneSymbol->setOpacity( mOpacity );
280  cloneSymbol->setLayer( mLayer );
283  cloneSymbol->setForceRHR( mForceRHR );
285  cloneSymbol->setFlags( mSymbolFlags );
286  return cloneSymbol;
287 }
The Qgis class provides global constants for use throughout the application.
Definition: qgis.h:64
@ 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
virtual void setWidth(double width)
Sets the width of the line symbol layer.
void setWidthUnit(QgsUnitTypes::RenderUnit unit)
Sets the units for the line's width.
void setOffset(double offset)
Sets the line's offset.
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
QgsLineSymbol * clone() const override
Returns a deep copy of this symbol.
void setWidthUnit(QgsUnitTypes::RenderUnit unit)
Sets the width units for the whole symbol (including all symbol layers).
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.
void setWidth(double width)
Sets the width for the whole line symbol.
void setDataDefinedWidth(const QgsProperty &property)
Set data defined width for whole symbol (including all symbol layers).
QgsProperty dataDefinedWidth() const
Returns data defined width for whole symbol (including all symbol layers).
QgsMapLayerType type
Definition: qgsmaplayer.h:80
Base class for visual effects which can be applied to QPicture drawings.
bool enabled() const
Returns whether the effect is enabled.
QgsProperty property(int key) const override
Returns a matching property from the collection, if one exists.
bool hasActiveProperties() const override
Returns true if the collection has any active properties, or false if all properties within the colle...
A store for object properties.
Definition: qgsproperty.h:231
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...
@ PropertyOffset
Symbol offset.
@ PropertyStrokeWidth
Stroke width.
@ PropertyLayerEnabled
Whether symbol layer is enabled.
Qgis::SymbolType type() const
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.
QgsRenderContext & renderContext()
Returns a reference to the context's render context.
void setGeometryPartCount(int count)
Sets the part count of current geometry.
void setGeometryPartNum(int num)
Sets the part number of current geometry.
void setOriginalGeometryType(QgsWkbTypes::GeometryType type)
Sets the geometry type for the original feature geometry being rendered.
Abstract base class for all rendered symbols.
Definition: qgssymbol.h:38
void setDataDefinedProperties(const QgsPropertyCollection &collection)
Sets the symbol's property collection, used for data defined overrides.
Definition: qgssymbol.h:558
Qgis::SymbolFlags mSymbolFlags
Symbol flags.
Definition: qgssymbol.h:719
QgsSymbolLayerList cloneLayers() const
Retrieve a cloned list of all layers that make up this symbol.
Definition: qgssymbol.cpp:790
QgsSymbolRenderContext * symbolRenderContext()
Returns the symbol render context.
Definition: qgssymbol.cpp:1467
QgsSymbolLayer * symbolLayer(int layer)
Returns the symbol layer at the specified index.
Definition: qgssymbol.cpp:420
@ PropertyOpacity
Opacity.
Definition: qgssymbol.h:76
void renderUsingLayer(QgsSymbolLayer *layer, QgsSymbolRenderContext &context, QgsWkbTypes::GeometryType geometryType=QgsWkbTypes::GeometryType::UnknownGeometry, 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:804
qreal mOpacity
Symbol opacity (in the range 0 - 1)
Definition: qgssymbol.h:710
Q_DECL_DEPRECATED const QgsVectorLayer * mLayer
Definition: qgssymbol.h:724
bool mClipFeaturesToExtent
Definition: qgssymbol.h:721
qreal opacity() const
Returns the opacity for the symbol.
Definition: qgssymbol.h:440
void setFlags(Qgis::SymbolFlags flags)
Sets flags for the symbol.
Definition: qgssymbol.h:467
QgsPropertyCollection & dataDefinedProperties()
Returns a reference to the symbol's property collection, used for data defined overrides.
Definition: qgssymbol.h:543
void setOpacity(qreal opacity)
Sets the opacity for the symbol.
Definition: qgssymbol.h:447
Qgis::SymbolRenderHints mRenderHints
Definition: qgssymbol.h:712
bool mForceRHR
Definition: qgssymbol.h:722
QgsSymbolLayerList mLayers
Definition: qgssymbol.h:707
Q_DECL_DEPRECATED const QgsVectorLayer * layer() const
Definition: qgssymbol.cpp:877
Q_DECL_DEPRECATED void setLayer(const QgsVectorLayer *layer)
Definition: qgssymbol.cpp:870
void setClipFeaturesToExtent(bool clipFeaturesToExtent)
Sets whether features drawn by the symbol should be clipped to the render context's extent.
Definition: qgssymbol.h:486
void setForceRHR(bool force)
Sets whether polygon features drawn by the symbol should be reoriented to follow the standard right-h...
Definition: qgssymbol.h:508
RenderUnit
Rendering size units.
Definition: qgsunittypes.h:168
@ RenderUnknownUnit
Mixed or unknown units.
Definition: qgsunittypes.h:175
#define Q_NOWARN_DEPRECATED_POP
Definition: qgis.h:2065
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:2064
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:1578
QList< QgsSymbolLayer * > QgsSymbolLayerList
Definition: qgssymbol.h:27