QGIS API Documentation 3.27.0-Master (1d7a28cfd2)
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 "qgsvectorlayer.h"
20#include "qgsunittypes.h"
21#include "qgssymbollayerutils.h"
22#include "qgslinesymbol.h"
23
25{
27}
28
30
32{
34 mDistanceUnit = unit;
35 if ( mLineSymbol )
36 mLineSymbol->setOutputUnit( unit );
37}
38
40{
41 if ( QgsMarkerSymbolLayer::outputUnit() == mDistanceUnit )
42 {
43 return mDistanceUnit;
44 }
46}
47
49{
51 mDistanceMapUnitScale = scale;
52}
53
55{
56 if ( QgsMarkerSymbolLayer::mapUnitScale() == mDistanceMapUnitScale )
57 {
58 return mDistanceMapUnitScale;
59 }
60 return QgsMapUnitScale();
61}
62
63QgsSymbolLayer *QgsVectorFieldSymbolLayer::create( const QVariantMap &properties )
64{
66 if ( properties.contains( QStringLiteral( "x_attribute" ) ) )
67 {
68 symbolLayer->setXAttribute( properties[QStringLiteral( "x_attribute" )].toString() );
69 }
70 if ( properties.contains( QStringLiteral( "y_attribute" ) ) )
71 {
72 symbolLayer->setYAttribute( properties[QStringLiteral( "y_attribute" )].toString() );
73 }
74 if ( properties.contains( QStringLiteral( "distance_unit" ) ) )
75 {
76 symbolLayer->setDistanceUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "distance_unit" )].toString() ) );
77 }
78 if ( properties.contains( QStringLiteral( "distance_map_unit_scale" ) ) )
79 {
80 symbolLayer->setDistanceMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "distance_map_unit_scale" )].toString() ) );
81 }
82 if ( properties.contains( QStringLiteral( "scale" ) ) )
83 {
84 symbolLayer->setScale( properties[QStringLiteral( "scale" )].toDouble() );
85 }
86 if ( properties.contains( QStringLiteral( "vector_field_type" ) ) )
87 {
88 symbolLayer->setVectorFieldType( static_cast< VectorFieldType >( properties[QStringLiteral( "vector_field_type" )].toInt() ) );
89 }
90 if ( properties.contains( QStringLiteral( "angle_orientation" ) ) )
91 {
92 symbolLayer->setAngleOrientation( static_cast< AngleOrientation >( properties[QStringLiteral( "angle_orientation" )].toInt() ) );
93 }
94 if ( properties.contains( QStringLiteral( "angle_units" ) ) )
95 {
96 symbolLayer->setAngleUnits( static_cast< AngleUnits >( properties[QStringLiteral( "angle_units" )].toInt() ) );
97 }
98 if ( properties.contains( QStringLiteral( "size" ) ) )
99 {
100 symbolLayer->setSize( properties[QStringLiteral( "size" )].toDouble() );
101 }
102 if ( properties.contains( QStringLiteral( "size_unit" ) ) )
103 {
104 symbolLayer->setSizeUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "size_unit" )].toString() ) );
105 }
106 if ( properties.contains( QStringLiteral( "size_map_unit_scale" ) ) )
107 {
108 symbolLayer->setSizeMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "size_map_unit_scale" )].toString() ) );
109 }
110 if ( properties.contains( QStringLiteral( "offset" ) ) )
111 {
112 symbolLayer->setOffset( QgsSymbolLayerUtils::decodePoint( properties[QStringLiteral( "offset" )].toString() ) );
113 }
114 if ( properties.contains( QStringLiteral( "offset_unit" ) ) )
115 {
116 symbolLayer->setOffsetUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "offset_unit" )].toString() ) );
117 }
118 if ( properties.contains( QStringLiteral( "offset_map_unit_scale" ) ) )
119 {
120 symbolLayer->setOffsetMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "offset_map_unit_scale" )].toString() ) );
121 }
122 return symbolLayer;
123}
124
126{
127 if ( symbol->type() == Qgis::SymbolType::Line )
128 {
129 mLineSymbol.reset( static_cast<QgsLineSymbol *>( symbol ) );
130 return true;
131 }
132 return false;
133}
134
136{
137 return mLineSymbol.get();
138}
139
141{
142 if ( !mLineSymbol )
143 {
144 return;
145 }
146
147 const QgsRenderContext &ctx = context.renderContext();
148
149 const bool prevIsSubsymbol = context.renderContext().flags() & Qgis::RenderContextFlag::RenderingSubSymbol;
151
152 if ( !context.feature() )
153 {
154 //preview
155 QPolygonF line;
156 line << QPointF( 0, 50 );
157 line << QPointF( 100, 50 );
158 mLineSymbol->renderPolyline( line, nullptr, context.renderContext() );
160 return;
161 }
162
163 const QgsFeature f( *context.feature() );
164
165 double xComponent = 0;
166 double yComponent = 0;
167
168 double xVal = 0;
169 if ( mXIndex != -1 )
170 {
171 xVal = f.attribute( mXIndex ).toDouble();
172 }
173 double yVal = 0;
174 if ( mYIndex != -1 )
175 {
176 yVal = f.attribute( mYIndex ).toDouble();
177 }
178
179 const QgsMapToPixel &m2p = ctx.mapToPixel();
180 const double mapRotation = m2p.mapRotation();
181
182 QPolygonF line;
183 line << point;
184
185 QPointF destPoint;
186 switch ( mVectorFieldType )
187 {
188 case Cartesian:
189 {
190 destPoint = QPointF( point.x() + mScale * ctx.convertToPainterUnits( xVal, mDistanceUnit, mDistanceMapUnitScale ),
191 point.y() - mScale * ctx.convertToPainterUnits( yVal, mDistanceUnit, mDistanceMapUnitScale ) );
192 break;
193 }
194
195 case Polar:
196 {
197 convertPolarToCartesian( xVal, yVal, xComponent, yComponent );
198 destPoint = QPointF( point.x() + mScale * ctx.convertToPainterUnits( xComponent, mDistanceUnit, mDistanceMapUnitScale ),
199 point.y() - mScale * ctx.convertToPainterUnits( yComponent, mDistanceUnit, mDistanceMapUnitScale ) );
200 break;
201 }
202
203 case Height:
204 {
205 destPoint = QPointF( point.x(), point.y() - ( mScale * ctx.convertToPainterUnits( yVal, mDistanceUnit, mDistanceMapUnitScale ) ) );
206 break;
207 }
208 }
209
210 if ( !qgsDoubleNear( mapRotation, 0.0 ) && mVectorFieldType != Height )
211 {
212 const double radians = mapRotation * M_PI / 180.0;
213 destPoint = QPointF( cos( radians ) * ( destPoint.x() - point.x() ) - sin( radians ) * ( destPoint.y() - point.y() ) + point.x(),
214 sin( radians ) * ( destPoint.x() - point.x() ) + cos( radians ) * ( destPoint.y() - point.y() ) + point.y() );
215 }
216
217 line << destPoint;
218
219 mLineSymbol->renderPolyline( line, &f, context.renderContext() );
221}
222
224{
225 if ( mLineSymbol )
226 {
227 mLineSymbol->startRender( context.renderContext(), context.fields() );
228 }
229
230 const QgsFields fields = context.fields();
231 if ( !fields.isEmpty() )
232 {
233 mXIndex = fields.lookupField( mXAttribute );
234 mYIndex = fields.lookupField( mYAttribute );
235 }
236 else
237 {
238 mXIndex = -1;
239 mYIndex = -1;
240 }
241}
242
244{
245 if ( mLineSymbol )
246 {
247 mLineSymbol->stopRender( context.renderContext() );
248 }
249}
250
252{
254 if ( mLineSymbol )
255 {
256 clonedLayer->setSubSymbol( mLineSymbol->clone() );
257 }
258 return static_cast< QgsVectorFieldSymbolLayer * >( clonedLayer );
259}
260
262{
263 QVariantMap properties;
264 properties[QStringLiteral( "x_attribute" )] = mXAttribute;
265 properties[QStringLiteral( "y_attribute" )] = mYAttribute;
266 properties[QStringLiteral( "distance_unit" )] = QgsUnitTypes::encodeUnit( mDistanceUnit );
267 properties[QStringLiteral( "distance_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mDistanceMapUnitScale );
268 properties[QStringLiteral( "scale" )] = QString::number( mScale );
269 properties[QStringLiteral( "vector_field_type" )] = QString::number( mVectorFieldType );
270 properties[QStringLiteral( "angle_orientation" )] = QString::number( mAngleOrientation );
271 properties[QStringLiteral( "angle_units" )] = QString::number( mAngleUnits );
272 properties[QStringLiteral( "size" )] = QString::number( mSize );
273 properties[QStringLiteral( "size_unit" )] = QgsUnitTypes::encodeUnit( mSizeUnit );
274 properties[QStringLiteral( "size_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mSizeMapUnitScale );
275 properties[QStringLiteral( "offset" )] = QgsSymbolLayerUtils::encodePoint( mOffset );
276 properties[QStringLiteral( "offset_unit" )] = QgsUnitTypes::encodeUnit( mOffsetUnit );
277 properties[QStringLiteral( "offset_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mOffsetMapUnitScale );
278 return properties;
279}
280
282{
283 return mDistanceUnit == QgsUnitTypes::RenderMapUnits || mDistanceUnit == QgsUnitTypes::RenderMetersInMapUnits
286}
287
288void QgsVectorFieldSymbolLayer::toSld( QDomDocument &doc, QDomElement &element, const QVariantMap &props ) const
289{
290 element.appendChild( doc.createComment( QStringLiteral( "VectorField not implemented yet..." ) ) );
291 mLineSymbol->toSld( doc, element, props );
292}
293
295{
296 Q_UNUSED( element )
297 return nullptr;
298}
299
301{
302 if ( mLineSymbol )
303 {
304 mLineSymbol->drawPreviewIcon( context.renderContext().painter(), size );
305 }
306}
307
309{
310 QSet<QString> attributes = QgsMarkerSymbolLayer::usedAttributes( context );
311 if ( !mXAttribute.isEmpty() )
312 {
313 attributes.insert( mXAttribute );
314 }
315 if ( !mYAttribute.isEmpty() )
316 {
317 attributes.insert( mYAttribute );
318 }
319 if ( mLineSymbol )
320 {
321 attributes.unite( mLineSymbol->usedAttributes( context ) );
322 }
323 return attributes;
324}
325
327{
329 return true;
330 if ( mLineSymbol && mLineSymbol->hasDataDefinedProperties() )
331 return true;
332 return false;
333}
334
335void QgsVectorFieldSymbolLayer::convertPolarToCartesian( double length, double angle, double &x, double &y ) const
336{
337 //convert angle to degree and to north orientation
338 if ( mAngleOrientation == CounterclockwiseFromEast )
339 {
340 if ( angle <= 90 )
341 {
342 angle = 90 - angle;
343 }
344 else
345 {
346 angle = 360 - angle + 90;
347 }
348 }
349
350 if ( mAngleUnits == Degrees )
351 {
352 angle = angle * M_PI / 180.0;
353 }
354
355 x = length * std::sin( angle );
356 y = length * std::cos( angle );
357}
358
359void QgsVectorFieldSymbolLayer::setColor( const QColor &color )
360{
361 if ( mLineSymbol )
362 mLineSymbol->setColor( color );
363
364 mColor = color;
365}
366
368{
369 return mLineSymbol ? mLineSymbol->color() : mColor;
370}
371
372
@ 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:349
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.
QgsUnitTypes::RenderUnit mOffsetUnit
Offset units.
void setSizeUnit(QgsUnitTypes::RenderUnit unit)
Sets the units for the symbol's size.
void setOutputUnit(QgsUnitTypes::RenderUnit unit) override
Sets 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.
QgsUnitTypes::RenderUnit mSizeUnit
Marker size unit.
void setOffsetUnit(QgsUnitTypes::RenderUnit unit)
Sets the units for the symbol's offset.
void setOffsetMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale for the symbol's offset.
QgsUnitTypes::RenderUnit outputUnit() const override
Returns the units to use for sizes and widths within the symbol layer.
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.
QPainter * painter()
Returns the destination QPainter for the render operation.
double convertToPainterUnits(double size, QgsUnitTypes::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale(), Qgis::RenderSubcomponentProperty property=Qgis::RenderSubcomponentProperty::Generic) const
Converts a size from the specified units to painter units (pixels).
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:93
Qgis::SymbolType type() const
Returns the symbol's type.
Definition: qgssymbol.h:152
static Q_INVOKABLE QString encodeUnit(QgsUnitTypes::DistanceUnit unit)
Encodes a distance unit to a string.
static Q_INVOKABLE QgsUnitTypes::RenderUnit decodeRenderUnit(const QString &string, bool *ok=nullptr)
Decodes a render unit from a string.
RenderUnit
Rendering size units.
Definition: qgsunittypes.h:168
@ RenderUnknownUnit
Mixed or unknown units.
Definition: qgsunittypes.h:175
@ RenderMetersInMapUnits
Meters value as Map units.
Definition: qgsunittypes.h:176
@ RenderMapUnits
Map units.
Definition: qgsunittypes.h:170
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.
QgsUnitTypes::RenderUnit outputUnit() const override
Returns the units to use for sizes and widths within 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(QgsUnitTypes::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)
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.
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.
void setOutputUnit(QgsUnitTypes::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
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:786
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:2507