QGIS API Documentation 3.99.0-Master (21b3aa880ba)
Loading...
Searching...
No Matches
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
20#include "qgslinesymbol.h"
21#include "qgssldexportcontext.h"
22#include "qgssymbollayerutils.h"
23#include "qgsunittypes.h"
24
29
31
33{
35 mDistanceUnit = unit;
36 if ( mLineSymbol )
37 mLineSymbol->setOutputUnit( unit );
38}
39
41{
42 if ( QgsMarkerSymbolLayer::outputUnit() == mDistanceUnit )
43 {
44 return mDistanceUnit;
45 }
47}
48
54
56{
57 if ( QgsMarkerSymbolLayer::mapUnitScale() == mDistanceMapUnitScale )
58 {
59 return mDistanceMapUnitScale;
60 }
61 return QgsMapUnitScale();
62}
63
65{
67 if ( properties.contains( QStringLiteral( "x_attribute" ) ) )
68 {
69 symbolLayer->setXAttribute( properties[QStringLiteral( "x_attribute" )].toString() );
70 }
71 if ( properties.contains( QStringLiteral( "y_attribute" ) ) )
72 {
73 symbolLayer->setYAttribute( properties[QStringLiteral( "y_attribute" )].toString() );
74 }
75 if ( properties.contains( QStringLiteral( "distance_unit" ) ) )
76 {
77 symbolLayer->setDistanceUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "distance_unit" )].toString() ) );
78 }
79 if ( properties.contains( QStringLiteral( "distance_map_unit_scale" ) ) )
80 {
81 symbolLayer->setDistanceMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "distance_map_unit_scale" )].toString() ) );
82 }
83 if ( properties.contains( QStringLiteral( "scale" ) ) )
84 {
85 symbolLayer->setScale( properties[QStringLiteral( "scale" )].toDouble() );
86 }
87 if ( properties.contains( QStringLiteral( "vector_field_type" ) ) )
88 {
89 symbolLayer->setVectorFieldType( static_cast< VectorFieldType >( properties[QStringLiteral( "vector_field_type" )].toInt() ) );
90 }
91 if ( properties.contains( QStringLiteral( "angle_orientation" ) ) )
92 {
93 symbolLayer->setAngleOrientation( static_cast< AngleOrientation >( properties[QStringLiteral( "angle_orientation" )].toInt() ) );
94 }
95 if ( properties.contains( QStringLiteral( "angle_units" ) ) )
96 {
97 symbolLayer->setAngleUnits( static_cast< AngleUnits >( properties[QStringLiteral( "angle_units" )].toInt() ) );
98 }
99 if ( properties.contains( QStringLiteral( "size" ) ) )
100 {
101 symbolLayer->setSize( properties[QStringLiteral( "size" )].toDouble() );
102 }
103 if ( properties.contains( QStringLiteral( "size_unit" ) ) )
104 {
105 symbolLayer->setSizeUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "size_unit" )].toString() ) );
106 }
107 if ( properties.contains( QStringLiteral( "size_map_unit_scale" ) ) )
108 {
109 symbolLayer->setSizeMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "size_map_unit_scale" )].toString() ) );
110 }
111 if ( properties.contains( QStringLiteral( "offset" ) ) )
112 {
113 symbolLayer->setOffset( QgsSymbolLayerUtils::decodePoint( properties[QStringLiteral( "offset" )].toString() ) );
114 }
115 if ( properties.contains( QStringLiteral( "offset_unit" ) ) )
116 {
117 symbolLayer->setOffsetUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "offset_unit" )].toString() ) );
118 }
119 if ( properties.contains( QStringLiteral( "offset_map_unit_scale" ) ) )
120 {
121 symbolLayer->setOffsetMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "offset_map_unit_scale" )].toString() ) );
122 }
123 return symbolLayer;
124}
125
127{
128 if ( symbol->type() == Qgis::SymbolType::Line )
129 {
130 mLineSymbol.reset( static_cast<QgsLineSymbol *>( symbol ) );
131 return true;
132 }
133 return false;
134}
135
137{
138 return mLineSymbol.get();
139}
140
142{
143 if ( !mLineSymbol )
144 {
145 return;
146 }
147
148 const QgsRenderContext &ctx = context.renderContext();
149
150 const bool prevIsSubsymbol = context.renderContext().flags() & Qgis::RenderContextFlag::RenderingSubSymbol;
152
153 if ( !context.feature() )
154 {
155 //preview
156 QPolygonF line;
157 line << QPointF( 0, 50 );
158 line << QPointF( 100, 50 );
159 mLineSymbol->renderPolyline( line, nullptr, context.renderContext() );
161 return;
162 }
163
164 const QgsFeature f( *context.feature() );
165
166 double xComponent = 0;
167 double yComponent = 0;
168
169 double xVal = 0;
170 if ( mXIndex != -1 )
171 {
172 xVal = f.attribute( mXIndex ).toDouble();
173 }
174 double yVal = 0;
175 if ( mYIndex != -1 )
176 {
177 yVal = f.attribute( mYIndex ).toDouble();
178 }
179
180 const QgsMapToPixel &m2p = ctx.mapToPixel();
181 const double mapRotation = m2p.mapRotation();
182
183 QPolygonF line;
184 line << point;
185
186 QPointF destPoint;
187 switch ( mVectorFieldType )
188 {
189 case Cartesian:
190 {
191 destPoint = QPointF( point.x() + mScale * ctx.convertToPainterUnits( xVal, mDistanceUnit, mDistanceMapUnitScale ),
192 point.y() - mScale * ctx.convertToPainterUnits( yVal, mDistanceUnit, mDistanceMapUnitScale ) );
193 break;
194 }
195
196 case Polar:
197 {
198 convertPolarToCartesian( xVal, yVal, xComponent, yComponent );
199 destPoint = QPointF( point.x() + mScale * ctx.convertToPainterUnits( xComponent, mDistanceUnit, mDistanceMapUnitScale ),
200 point.y() - mScale * ctx.convertToPainterUnits( yComponent, mDistanceUnit, mDistanceMapUnitScale ) );
201 break;
202 }
203
204 case Height:
205 {
206 destPoint = QPointF( point.x(), point.y() - ( mScale * ctx.convertToPainterUnits( yVal, mDistanceUnit, mDistanceMapUnitScale ) ) );
207 break;
208 }
209 }
210
211 if ( !qgsDoubleNear( mapRotation, 0.0 ) && mVectorFieldType != Height )
212 {
213 const double radians = mapRotation * M_PI / 180.0;
214 destPoint = QPointF( cos( radians ) * ( destPoint.x() - point.x() ) - sin( radians ) * ( destPoint.y() - point.y() ) + point.x(),
215 sin( radians ) * ( destPoint.x() - point.x() ) + cos( radians ) * ( destPoint.y() - point.y() ) + point.y() );
216 }
217
218 line << destPoint;
219
220 mLineSymbol->renderPolyline( line, &f, context.renderContext() );
222}
223
225{
226 if ( mLineSymbol )
227 {
228 mLineSymbol->setRenderHints( mLineSymbol->renderHints() | Qgis::SymbolRenderHint::IsSymbolLayerSubSymbol );
229 mLineSymbol->startRender( context.renderContext(), context.fields() );
230 }
231
232 const QgsFields fields = context.fields();
233 if ( !fields.isEmpty() )
234 {
235 mXIndex = fields.lookupField( mXAttribute );
236 mYIndex = fields.lookupField( mYAttribute );
237 }
238 else
239 {
240 mXIndex = -1;
241 mYIndex = -1;
242 }
243}
244
246{
247 if ( mLineSymbol )
248 {
249 mLineSymbol->stopRender( context.renderContext() );
250 }
251}
252
254{
256 if ( mLineSymbol )
257 {
258 clonedLayer->setSubSymbol( mLineSymbol->clone() );
259 }
260 return static_cast< QgsVectorFieldSymbolLayer * >( clonedLayer );
261}
262
264{
265 QVariantMap properties;
266 properties[QStringLiteral( "x_attribute" )] = mXAttribute;
267 properties[QStringLiteral( "y_attribute" )] = mYAttribute;
268 properties[QStringLiteral( "distance_unit" )] = QgsUnitTypes::encodeUnit( mDistanceUnit );
269 properties[QStringLiteral( "distance_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mDistanceMapUnitScale );
270 properties[QStringLiteral( "scale" )] = QString::number( mScale );
271 properties[QStringLiteral( "vector_field_type" )] = QString::number( mVectorFieldType );
272 properties[QStringLiteral( "angle_orientation" )] = QString::number( mAngleOrientation );
273 properties[QStringLiteral( "angle_units" )] = QString::number( mAngleUnits );
274 properties[QStringLiteral( "size" )] = QString::number( mSize );
275 properties[QStringLiteral( "size_unit" )] = QgsUnitTypes::encodeUnit( mSizeUnit );
276 properties[QStringLiteral( "size_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mSizeMapUnitScale );
277 properties[QStringLiteral( "offset" )] = QgsSymbolLayerUtils::encodePoint( mOffset );
278 properties[QStringLiteral( "offset_unit" )] = QgsUnitTypes::encodeUnit( mOffsetUnit );
279 properties[QStringLiteral( "offset_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mOffsetMapUnitScale );
280 return properties;
281}
282
289
290void QgsVectorFieldSymbolLayer::toSld( QDomDocument &doc, QDomElement &element, const QVariantMap &props ) const
291{
292 QgsSldExportContext context;
293 context.setExtraProperties( props );
294 toSld( doc, element, context );
295}
296
297bool QgsVectorFieldSymbolLayer::toSld( QDomDocument &doc, QDomElement &element, QgsSldExportContext &context ) const
298{
299 context.pushError( QObject::tr( "Vector field symbol layers cannot be converted to SLD" ) );
300 mLineSymbol->toSld( doc, element, context );
301 return false;
302}
303
305{
306 Q_UNUSED( element )
307 return nullptr;
308}
309
311{
312 if ( mLineSymbol )
313 {
314 mLineSymbol->drawPreviewIcon( context.renderContext().painter(), size );
315 }
316}
317
319{
320 QSet<QString> attributes = QgsMarkerSymbolLayer::usedAttributes( context );
321 if ( !mXAttribute.isEmpty() )
322 {
323 attributes.insert( mXAttribute );
324 }
325 if ( !mYAttribute.isEmpty() )
326 {
327 attributes.insert( mYAttribute );
328 }
329 if ( mLineSymbol )
330 {
331 attributes.unite( mLineSymbol->usedAttributes( context ) );
332 }
333 return attributes;
334}
335
337{
339 return true;
340 if ( mLineSymbol && mLineSymbol->hasDataDefinedProperties() )
341 return true;
342 return false;
343}
344
345void QgsVectorFieldSymbolLayer::convertPolarToCartesian( double length, double angle, double &x, double &y ) const
346{
347 //convert angle to degree and to north orientation
348 if ( mAngleOrientation == CounterclockwiseFromEast )
349 {
350 if ( angle <= 90 )
351 {
352 angle = 90 - angle;
353 }
354 else
355 {
356 angle = 360 - angle + 90;
357 }
358 }
359
360 if ( mAngleUnits == Degrees )
361 {
362 angle = angle * M_PI / 180.0;
363 }
364
365 x = length * std::sin( angle );
366 y = length * std::cos( angle );
367}
368
370{
371 if ( mLineSymbol )
372 mLineSymbol->setColor( color );
373
374 mColor = color;
375}
376
378{
379 return mLineSymbol ? mLineSymbol->color() : mColor;
380}
381
382
@ IsSymbolLayerSubSymbol
Symbol is being rendered as a sub-symbol of a QgsSymbolLayer.
Definition qgis.h:771
RenderUnit
Rendering size units.
Definition qgis.h:5183
@ Unknown
Mixed or unknown units.
Definition qgis.h:5190
@ MapUnits
Map units.
Definition qgis.h:5185
@ MetersInMapUnits
Meters value as Map units.
Definition qgis.h:5191
@ RenderingSubSymbol
Set whenever a sub-symbol of a parent symbol is currently being rendered. Can be used during symbol a...
Definition qgis.h:2765
@ Line
Line symbol.
Definition qgis.h:612
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition qgsfeature.h:58
Q_INVOKABLE QVariant attribute(const QString &name) const
Lookup attribute value by attribute name.
Container of fields for a vector layer.
Definition qgsfields.h:46
bool isEmpty
Definition qgsfields.h:49
Q_INVOKABLE int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
A line symbol type, for rendering LineString and MultiLineString geometries.
Perform transforms between map coordinates and device coordinates.
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.
Holds SLD export options and other information related to SLD export of a QGIS layer style.
void setExtraProperties(const QVariantMap &properties)
Sets the open ended set of properties that can drive/inform the SLD encoding.
void pushError(const QString &error)
Pushes a error message generated during the conversion.
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.
QgsSymbolLayer(const QgsSymbolLayer &other)
Encapsulates the context in which a symbol is being rendered.
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:231
Qgis::SymbolType type() const
Returns the symbol's type.
Definition qgssymbol.h:294
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.
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.
Q_DECL_DEPRECATED 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
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).
Definition qgis.h:6607