QGIS API Documentation 3.37.0-Master (fdefdf9c27f)
qgsvectorfieldsymbollayer.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsvectorfieldsymbollayer.cpp
3 -----------------------------
4 begin : Octorer 25, 2011
5 copyright : (C) 2011 by Marco Hugentobler
6 email : marco dot hugentobler at sourcepole dot ch
7 ***************************************************************************/
8
9/***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
19#include "qgsunittypes.h"
20#include "qgssymbollayerutils.h"
21#include "qgslinesymbol.h"
22
24{
26}
27
29
31{
33 mDistanceUnit = unit;
34 if ( mLineSymbol )
35 mLineSymbol->setOutputUnit( unit );
36}
37
39{
40 if ( QgsMarkerSymbolLayer::outputUnit() == mDistanceUnit )
41 {
42 return mDistanceUnit;
43 }
45}
46
48{
50 mDistanceMapUnitScale = scale;
51}
52
54{
55 if ( QgsMarkerSymbolLayer::mapUnitScale() == mDistanceMapUnitScale )
56 {
57 return mDistanceMapUnitScale;
58 }
59 return QgsMapUnitScale();
60}
61
62QgsSymbolLayer *QgsVectorFieldSymbolLayer::create( const QVariantMap &properties )
63{
65 if ( properties.contains( QStringLiteral( "x_attribute" ) ) )
66 {
67 symbolLayer->setXAttribute( properties[QStringLiteral( "x_attribute" )].toString() );
68 }
69 if ( properties.contains( QStringLiteral( "y_attribute" ) ) )
70 {
71 symbolLayer->setYAttribute( properties[QStringLiteral( "y_attribute" )].toString() );
72 }
73 if ( properties.contains( QStringLiteral( "distance_unit" ) ) )
74 {
75 symbolLayer->setDistanceUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "distance_unit" )].toString() ) );
76 }
77 if ( properties.contains( QStringLiteral( "distance_map_unit_scale" ) ) )
78 {
79 symbolLayer->setDistanceMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "distance_map_unit_scale" )].toString() ) );
80 }
81 if ( properties.contains( QStringLiteral( "scale" ) ) )
82 {
83 symbolLayer->setScale( properties[QStringLiteral( "scale" )].toDouble() );
84 }
85 if ( properties.contains( QStringLiteral( "vector_field_type" ) ) )
86 {
87 symbolLayer->setVectorFieldType( static_cast< VectorFieldType >( properties[QStringLiteral( "vector_field_type" )].toInt() ) );
88 }
89 if ( properties.contains( QStringLiteral( "angle_orientation" ) ) )
90 {
91 symbolLayer->setAngleOrientation( static_cast< AngleOrientation >( properties[QStringLiteral( "angle_orientation" )].toInt() ) );
92 }
93 if ( properties.contains( QStringLiteral( "angle_units" ) ) )
94 {
95 symbolLayer->setAngleUnits( static_cast< AngleUnits >( properties[QStringLiteral( "angle_units" )].toInt() ) );
96 }
97 if ( properties.contains( QStringLiteral( "size" ) ) )
98 {
99 symbolLayer->setSize( properties[QStringLiteral( "size" )].toDouble() );
100 }
101 if ( properties.contains( QStringLiteral( "size_unit" ) ) )
102 {
103 symbolLayer->setSizeUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "size_unit" )].toString() ) );
104 }
105 if ( properties.contains( QStringLiteral( "size_map_unit_scale" ) ) )
106 {
107 symbolLayer->setSizeMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "size_map_unit_scale" )].toString() ) );
108 }
109 if ( properties.contains( QStringLiteral( "offset" ) ) )
110 {
111 symbolLayer->setOffset( QgsSymbolLayerUtils::decodePoint( properties[QStringLiteral( "offset" )].toString() ) );
112 }
113 if ( properties.contains( QStringLiteral( "offset_unit" ) ) )
114 {
115 symbolLayer->setOffsetUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "offset_unit" )].toString() ) );
116 }
117 if ( properties.contains( QStringLiteral( "offset_map_unit_scale" ) ) )
118 {
119 symbolLayer->setOffsetMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "offset_map_unit_scale" )].toString() ) );
120 }
121 return symbolLayer;
122}
123
125{
126 if ( symbol->type() == Qgis::SymbolType::Line )
127 {
128 mLineSymbol.reset( static_cast<QgsLineSymbol *>( symbol ) );
129 return true;
130 }
131 return false;
132}
133
135{
136 return mLineSymbol.get();
137}
138
140{
141 if ( !mLineSymbol )
142 {
143 return;
144 }
145
146 const QgsRenderContext &ctx = context.renderContext();
147
148 const bool prevIsSubsymbol = context.renderContext().flags() & Qgis::RenderContextFlag::RenderingSubSymbol;
150
151 if ( !context.feature() )
152 {
153 //preview
154 QPolygonF line;
155 line << QPointF( 0, 50 );
156 line << QPointF( 100, 50 );
157 mLineSymbol->renderPolyline( line, nullptr, context.renderContext() );
159 return;
160 }
161
162 const QgsFeature f( *context.feature() );
163
164 double xComponent = 0;
165 double yComponent = 0;
166
167 double xVal = 0;
168 if ( mXIndex != -1 )
169 {
170 xVal = f.attribute( mXIndex ).toDouble();
171 }
172 double yVal = 0;
173 if ( mYIndex != -1 )
174 {
175 yVal = f.attribute( mYIndex ).toDouble();
176 }
177
178 const QgsMapToPixel &m2p = ctx.mapToPixel();
179 const double mapRotation = m2p.mapRotation();
180
181 QPolygonF line;
182 line << point;
183
184 QPointF destPoint;
185 switch ( mVectorFieldType )
186 {
187 case Cartesian:
188 {
189 destPoint = QPointF( point.x() + mScale * ctx.convertToPainterUnits( xVal, mDistanceUnit, mDistanceMapUnitScale ),
190 point.y() - mScale * ctx.convertToPainterUnits( yVal, mDistanceUnit, mDistanceMapUnitScale ) );
191 break;
192 }
193
194 case Polar:
195 {
196 convertPolarToCartesian( xVal, yVal, xComponent, yComponent );
197 destPoint = QPointF( point.x() + mScale * ctx.convertToPainterUnits( xComponent, mDistanceUnit, mDistanceMapUnitScale ),
198 point.y() - mScale * ctx.convertToPainterUnits( yComponent, mDistanceUnit, mDistanceMapUnitScale ) );
199 break;
200 }
201
202 case Height:
203 {
204 destPoint = QPointF( point.x(), point.y() - ( mScale * ctx.convertToPainterUnits( yVal, mDistanceUnit, mDistanceMapUnitScale ) ) );
205 break;
206 }
207 }
208
209 if ( !qgsDoubleNear( mapRotation, 0.0 ) && mVectorFieldType != Height )
210 {
211 const double radians = mapRotation * M_PI / 180.0;
212 destPoint = QPointF( cos( radians ) * ( destPoint.x() - point.x() ) - sin( radians ) * ( destPoint.y() - point.y() ) + point.x(),
213 sin( radians ) * ( destPoint.x() - point.x() ) + cos( radians ) * ( destPoint.y() - point.y() ) + point.y() );
214 }
215
216 line << destPoint;
217
218 mLineSymbol->renderPolyline( line, &f, context.renderContext() );
220}
221
223{
224 if ( mLineSymbol )
225 {
226 mLineSymbol->startRender( context.renderContext(), context.fields() );
227 }
228
229 const QgsFields fields = context.fields();
230 if ( !fields.isEmpty() )
231 {
232 mXIndex = fields.lookupField( mXAttribute );
233 mYIndex = fields.lookupField( mYAttribute );
234 }
235 else
236 {
237 mXIndex = -1;
238 mYIndex = -1;
239 }
240}
241
243{
244 if ( mLineSymbol )
245 {
246 mLineSymbol->stopRender( context.renderContext() );
247 }
248}
249
251{
253 if ( mLineSymbol )
254 {
255 clonedLayer->setSubSymbol( mLineSymbol->clone() );
256 }
257 return static_cast< QgsVectorFieldSymbolLayer * >( clonedLayer );
258}
259
261{
262 QVariantMap properties;
263 properties[QStringLiteral( "x_attribute" )] = mXAttribute;
264 properties[QStringLiteral( "y_attribute" )] = mYAttribute;
265 properties[QStringLiteral( "distance_unit" )] = QgsUnitTypes::encodeUnit( mDistanceUnit );
266 properties[QStringLiteral( "distance_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mDistanceMapUnitScale );
267 properties[QStringLiteral( "scale" )] = QString::number( mScale );
268 properties[QStringLiteral( "vector_field_type" )] = QString::number( mVectorFieldType );
269 properties[QStringLiteral( "angle_orientation" )] = QString::number( mAngleOrientation );
270 properties[QStringLiteral( "angle_units" )] = QString::number( mAngleUnits );
271 properties[QStringLiteral( "size" )] = QString::number( mSize );
272 properties[QStringLiteral( "size_unit" )] = QgsUnitTypes::encodeUnit( mSizeUnit );
273 properties[QStringLiteral( "size_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mSizeMapUnitScale );
274 properties[QStringLiteral( "offset" )] = QgsSymbolLayerUtils::encodePoint( mOffset );
275 properties[QStringLiteral( "offset_unit" )] = QgsUnitTypes::encodeUnit( mOffsetUnit );
276 properties[QStringLiteral( "offset_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mOffsetMapUnitScale );
277 return properties;
278}
279
281{
282 return mDistanceUnit == Qgis::RenderUnit::MapUnits || mDistanceUnit == Qgis::RenderUnit::MetersInMapUnits
285}
286
287void QgsVectorFieldSymbolLayer::toSld( QDomDocument &doc, QDomElement &element, const QVariantMap &props ) const
288{
289 element.appendChild( doc.createComment( QStringLiteral( "VectorField not implemented yet..." ) ) );
290 mLineSymbol->toSld( doc, element, props );
291}
292
294{
295 Q_UNUSED( element )
296 return nullptr;
297}
298
300{
301 if ( mLineSymbol )
302 {
303 mLineSymbol->drawPreviewIcon( context.renderContext().painter(), size );
304 }
305}
306
308{
309 QSet<QString> attributes = QgsMarkerSymbolLayer::usedAttributes( context );
310 if ( !mXAttribute.isEmpty() )
311 {
312 attributes.insert( mXAttribute );
313 }
314 if ( !mYAttribute.isEmpty() )
315 {
316 attributes.insert( mYAttribute );
317 }
318 if ( mLineSymbol )
319 {
320 attributes.unite( mLineSymbol->usedAttributes( context ) );
321 }
322 return attributes;
323}
324
326{
328 return true;
329 if ( mLineSymbol && mLineSymbol->hasDataDefinedProperties() )
330 return true;
331 return false;
332}
333
334void QgsVectorFieldSymbolLayer::convertPolarToCartesian( double length, double angle, double &x, double &y ) const
335{
336 //convert angle to degree and to north orientation
337 if ( mAngleOrientation == CounterclockwiseFromEast )
338 {
339 if ( angle <= 90 )
340 {
341 angle = 90 - angle;
342 }
343 else
344 {
345 angle = 360 - angle + 90;
346 }
347 }
348
349 if ( mAngleUnits == Degrees )
350 {
351 angle = angle * M_PI / 180.0;
352 }
353
354 x = length * std::sin( angle );
355 y = length * std::cos( angle );
356}
357
358void QgsVectorFieldSymbolLayer::setColor( const QColor &color )
359{
360 if ( mLineSymbol )
361 mLineSymbol->setColor( color );
362
363 mColor = color;
364}
365
367{
368 return mLineSymbol ? mLineSymbol->color() : mColor;
369}
370
371
RenderUnit
Rendering size units.
Definition: qgis.h:4255
@ Unknown
Mixed or unknown units.
@ MapUnits
Map units.
@ MetersInMapUnits
Meters value as Map units.
@ RenderingSubSymbol
Set whenever a sub-symbol of a parent symbol is currently being rendered. Can be used during symbol a...
@ Line
Line symbol.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition: qgsfeature.h:56
QVariant attribute(const QString &name) const
Lookup attribute value by attribute name.
Definition: qgsfeature.cpp:335
Container of fields for a vector layer.
Definition: qgsfields.h:45
bool isEmpty() const
Checks whether the container is empty.
Definition: qgsfields.cpp:128
int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
Definition: qgsfields.cpp:359
A line symbol type, for rendering LineString and MultiLineString geometries.
Definition: qgslinesymbol.h:30
Perform transforms between map coordinates and device coordinates.
Definition: qgsmaptopixel.h:39
double mapRotation() const
Returns the current map rotation in degrees (clockwise).
Struct for storing maximum and minimum scales for measurements in map units.
double mSize
Marker size.
virtual void setSize(double size)
Sets the symbol size.
Qgis::RenderUnit mOffsetUnit
Offset units.
void setOffsetUnit(Qgis::RenderUnit unit)
Sets the units for the symbol's offset.
Qgis::RenderUnit outputUnit() const override
Returns the units to use for sizes and widths within the symbol layer.
QPointF mOffset
Marker offset.
QgsMapUnitScale mapUnitScale() const override
void setOffset(QPointF offset)
Sets the marker's offset, which is the horizontal and vertical displacement which the rendered marker...
void setSizeMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale for the symbol's size.
double size() const
Returns the symbol size.
QgsMapUnitScale mOffsetMapUnitScale
Offset map unit scale.
QgsMapUnitScale mSizeMapUnitScale
Marker size map unit scale.
Qgis::RenderUnit mSizeUnit
Marker size unit.
void setOutputUnit(Qgis::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
void setSizeUnit(Qgis::RenderUnit unit)
Sets the units for the symbol's size.
void setOffsetMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale for the symbol's offset.
double angle() const
Returns the rotation angle for the marker, in degrees clockwise from north.
void setMapUnitScale(const QgsMapUnitScale &scale) override
Contains information about the context of a rendering operation.
double convertToPainterUnits(double size, Qgis::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale(), Qgis::RenderSubcomponentProperty property=Qgis::RenderSubcomponentProperty::Generic) const
Converts a size from the specified units to painter units (pixels).
QPainter * painter()
Returns the destination QPainter for the render operation.
void setFlag(Qgis::RenderContextFlag flag, bool on=true)
Enable or disable a particular flag (other flags are not affected)
const QgsMapToPixel & mapToPixel() const
Returns the context's map to pixel transform, which transforms between map coordinates and device coo...
Qgis::RenderContextFlags flags() const
Returns combination of flags used for rendering.
static QString encodeMapUnitScale(const QgsMapUnitScale &mapUnitScale)
static QgsMapUnitScale decodeMapUnitScale(const QString &str)
static QString encodePoint(QPointF point)
Encodes a QPointF to a string.
static QPointF decodePoint(const QString &string)
Decodes a QSizeF from a string.
virtual bool setSubSymbol(QgsSymbol *symbol)
Sets layer's subsymbol. takes ownership of the passed symbol.
virtual QSet< QString > usedAttributes(const QgsRenderContext &context) const
Returns the set of attributes referenced by the layer.
virtual bool hasDataDefinedProperties() const
Returns true if the symbol layer (or any of its sub-symbols) contains data defined properties.
const QgsFeature * feature() const
Returns the current feature being rendered.
QgsFields fields() const
Fields of the layer.
QgsRenderContext & renderContext()
Returns a reference to the context's render context.
Abstract base class for all rendered symbols.
Definition: qgssymbol.h:94
Qgis::SymbolType type() const
Returns the symbol's type.
Definition: qgssymbol.h:156
static Q_INVOKABLE Qgis::RenderUnit decodeRenderUnit(const QString &string, bool *ok=nullptr)
Decodes a render unit from a string.
static Q_INVOKABLE QString encodeUnit(Qgis::DistanceUnit unit)
Encodes a distance unit to a string.
A symbol layer class for displaying displacement arrows based on point layer attributes.
QSet< QString > usedAttributes(const QgsRenderContext &context) const override
Returns the set of attributes referenced by the layer.
bool setSubSymbol(QgsSymbol *symbol) override
Sets layer's subsymbol. takes ownership of the passed symbol.
QColor color() const override
Returns the "representative" color of the symbol layer.
QgsSymbol * subSymbol() override
Returns the symbol's sub symbol, if present.
void setMapUnitScale(const QgsMapUnitScale &scale) override
void setYAttribute(const QString &attribute)
void setAngleUnits(AngleUnits units)
void setVectorFieldType(VectorFieldType type)
void setDistanceUnit(Qgis::RenderUnit unit)
Sets the units for the distance.
~QgsVectorFieldSymbolLayer() override
bool hasDataDefinedProperties() const override
Returns true if the symbol layer (or any of its sub-symbols) contains data defined properties.
void startRender(QgsSymbolRenderContext &context) override
Called before a set of rendering operations commences on the supplied render context.
void setAngleOrientation(AngleOrientation orientation)
Qgis::RenderUnit outputUnit() const override
Returns the units to use for sizes and widths within the symbol layer.
QVariantMap properties() const override
Should be reimplemented by subclasses to return a string map that contains the configuration informat...
void stopRender(QgsSymbolRenderContext &context) override
Called after a set of rendering operations has finished on the supplied render context.
QgsVectorFieldSymbolLayer * clone() const override
Shall be reimplemented by subclasses to create a deep copy of the instance.
void setOutputUnit(Qgis::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
static QgsSymbolLayer * create(const QVariantMap &properties=QVariantMap())
Creates the symbol layer.
QgsMapUnitScale mapUnitScale() const override
void setXAttribute(const QString &attribute)
void setDistanceMapUnitScale(const QgsMapUnitScale &scale)
bool usesMapUnits() const override
Returns true if the symbol layer has any components which use map unit based sizes.
static QgsSymbolLayer * createFromSld(QDomElement &element)
void setColor(const QColor &color) override
Sets the "representative" color for the symbol layer.
void toSld(QDomDocument &doc, QDomElement &element, const QVariantMap &props) const override
Saves the symbol layer as SLD.
void renderPoint(QPointF point, QgsSymbolRenderContext &context) override
Renders a marker at the specified point.
void drawPreviewIcon(QgsSymbolRenderContext &context, QSize size) override
double ANALYSIS_EXPORT angle(QgsPoint *p1, QgsPoint *p2, QgsPoint *p3, QgsPoint *p4)
Calculates the angle between two segments (in 2 dimension, z-values are ignored)
Definition: MathUtils.cpp:716
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