QGIS API Documentation  3.18.1-Zürich (202f1bf7e5)
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 
24 {
25  setSubSymbol( new QgsLineSymbol() );
26 }
27 
29 {
31  mDistanceUnit = unit;
32 }
33 
35 {
36  if ( QgsMarkerSymbolLayer::outputUnit() == mDistanceUnit )
37  {
38  return mDistanceUnit;
39  }
41 }
42 
44 {
46  mDistanceMapUnitScale = scale;
47 }
48 
50 {
51  if ( QgsMarkerSymbolLayer::mapUnitScale() == mDistanceMapUnitScale )
52  {
53  return mDistanceMapUnitScale;
54  }
55  return QgsMapUnitScale();
56 }
57 
58 QgsSymbolLayer *QgsVectorFieldSymbolLayer::create( const QVariantMap &properties )
59 {
61  if ( properties.contains( QStringLiteral( "x_attribute" ) ) )
62  {
63  symbolLayer->setXAttribute( properties[QStringLiteral( "x_attribute" )].toString() );
64  }
65  if ( properties.contains( QStringLiteral( "y_attribute" ) ) )
66  {
67  symbolLayer->setYAttribute( properties[QStringLiteral( "y_attribute" )].toString() );
68  }
69  if ( properties.contains( QStringLiteral( "distance_unit" ) ) )
70  {
71  symbolLayer->setDistanceUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "distance_unit" )].toString() ) );
72  }
73  if ( properties.contains( QStringLiteral( "distance_map_unit_scale" ) ) )
74  {
75  symbolLayer->setDistanceMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "distance_map_unit_scale" )].toString() ) );
76  }
77  if ( properties.contains( QStringLiteral( "scale" ) ) )
78  {
79  symbolLayer->setScale( properties[QStringLiteral( "scale" )].toDouble() );
80  }
81  if ( properties.contains( QStringLiteral( "vector_field_type" ) ) )
82  {
83  symbolLayer->setVectorFieldType( static_cast< VectorFieldType >( properties[QStringLiteral( "vector_field_type" )].toInt() ) );
84  }
85  if ( properties.contains( QStringLiteral( "angle_orientation" ) ) )
86  {
87  symbolLayer->setAngleOrientation( static_cast< AngleOrientation >( properties[QStringLiteral( "angle_orientation" )].toInt() ) );
88  }
89  if ( properties.contains( QStringLiteral( "angle_units" ) ) )
90  {
91  symbolLayer->setAngleUnits( static_cast< AngleUnits >( properties[QStringLiteral( "angle_units" )].toInt() ) );
92  }
93  if ( properties.contains( QStringLiteral( "size" ) ) )
94  {
95  symbolLayer->setSize( properties[QStringLiteral( "size" )].toDouble() );
96  }
97  if ( properties.contains( QStringLiteral( "size_unit" ) ) )
98  {
99  symbolLayer->setSizeUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "size_unit" )].toString() ) );
100  }
101  if ( properties.contains( QStringLiteral( "size_map_unit_scale" ) ) )
102  {
103  symbolLayer->setSizeMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "size_map_unit_scale" )].toString() ) );
104  }
105  if ( properties.contains( QStringLiteral( "offset" ) ) )
106  {
107  symbolLayer->setOffset( QgsSymbolLayerUtils::decodePoint( properties[QStringLiteral( "offset" )].toString() ) );
108  }
109  if ( properties.contains( QStringLiteral( "offset_unit" ) ) )
110  {
111  symbolLayer->setOffsetUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "offset_unit" )].toString() ) );
112  }
113  if ( properties.contains( QStringLiteral( "offset_map_unit_scale" ) ) )
114  {
115  symbolLayer->setOffsetMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "offset_map_unit_scale" )].toString() ) );
116  }
117  return symbolLayer;
118 }
119 
121 {
122  if ( symbol->type() == QgsSymbol::Line )
123  {
124  mLineSymbol.reset( static_cast<QgsLineSymbol *>( symbol ) );
125  return true;
126  }
127  return false;
128 }
129 
131 {
132  if ( !mLineSymbol )
133  {
134  return;
135  }
136 
137  const QgsRenderContext &ctx = context.renderContext();
138 
139  if ( !context.feature() )
140  {
141  //preview
142  QPolygonF line;
143  line << QPointF( 0, 50 );
144  line << QPointF( 100, 50 );
145  mLineSymbol->renderPolyline( line, nullptr, context.renderContext() );
146  return;
147  }
148 
149  const QgsFeature f( *context.feature() );
150 
151  double xComponent = 0;
152  double yComponent = 0;
153 
154  double xVal = 0;
155  if ( mXIndex != -1 )
156  {
157  xVal = f.attribute( mXIndex ).toDouble();
158  }
159  double yVal = 0;
160  if ( mYIndex != -1 )
161  {
162  yVal = f.attribute( mYIndex ).toDouble();
163  }
164 
165  const QgsMapToPixel &m2p = ctx.mapToPixel();
166  const double mapRotation = m2p.mapRotation();
167 
168  QPolygonF line;
169  line << point;
170 
171  QPointF destPoint;
172  switch ( mVectorFieldType )
173  {
174  case Cartesian:
175  {
176  destPoint = QPointF( point.x() + mScale * ctx.convertToPainterUnits( xVal, mDistanceUnit, mDistanceMapUnitScale ),
177  point.y() - mScale * ctx.convertToPainterUnits( yVal, mDistanceUnit, mDistanceMapUnitScale ) );
178  break;
179  }
180 
181  case Polar:
182  {
183  convertPolarToCartesian( xVal, yVal, xComponent, yComponent );
184  destPoint = QPointF( point.x() + mScale * ctx.convertToPainterUnits( xComponent, mDistanceUnit, mDistanceMapUnitScale ),
185  point.y() - mScale * ctx.convertToPainterUnits( yComponent, mDistanceUnit, mDistanceMapUnitScale ) );
186  break;
187  }
188 
189  case Height:
190  {
191  destPoint = QPointF( point.x(), point.y() - ( mScale * ctx.convertToPainterUnits( yVal, mDistanceUnit, mDistanceMapUnitScale ) ) );
192  break;
193  }
194  }
195 
196  if ( !qgsDoubleNear( mapRotation, 0.0 ) && mVectorFieldType != Height )
197  {
198  const double radians = mapRotation * M_PI / 180.0;
199  destPoint = QPointF( cos( radians ) * ( destPoint.x() - point.x() ) - sin( radians ) * ( destPoint.y() - point.y() ) + point.x(),
200  sin( radians ) * ( destPoint.x() - point.x() ) + cos( radians ) * ( destPoint.y() - point.y() ) + point.y() );
201  }
202 
203  line << destPoint;
204  mLineSymbol->renderPolyline( line, &f, context.renderContext() );
205 }
206 
208 {
209  if ( mLineSymbol )
210  {
211  mLineSymbol->startRender( context.renderContext(), context.fields() );
212  }
213 
214  QgsFields fields = context.fields();
215  if ( !fields.isEmpty() )
216  {
217  mXIndex = fields.lookupField( mXAttribute );
218  mYIndex = fields.lookupField( mYAttribute );
219  }
220  else
221  {
222  mXIndex = -1;
223  mYIndex = -1;
224  }
225 }
226 
228 {
229  if ( mLineSymbol )
230  {
231  mLineSymbol->stopRender( context.renderContext() );
232  }
233 }
234 
236 {
238  if ( mLineSymbol )
239  {
240  clonedLayer->setSubSymbol( mLineSymbol->clone() );
241  }
242  return static_cast< QgsVectorFieldSymbolLayer * >( clonedLayer );
243 }
244 
246 {
247  QVariantMap properties;
248  properties[QStringLiteral( "x_attribute" )] = mXAttribute;
249  properties[QStringLiteral( "y_attribute" )] = mYAttribute;
250  properties[QStringLiteral( "distance_unit" )] = QgsUnitTypes::encodeUnit( mDistanceUnit );
251  properties[QStringLiteral( "distance_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mDistanceMapUnitScale );
252  properties[QStringLiteral( "scale" )] = QString::number( mScale );
253  properties[QStringLiteral( "vector_field_type" )] = QString::number( mVectorFieldType );
254  properties[QStringLiteral( "angle_orientation" )] = QString::number( mAngleOrientation );
255  properties[QStringLiteral( "angle_units" )] = QString::number( mAngleUnits );
256  properties[QStringLiteral( "size" )] = QString::number( mSize );
257  properties[QStringLiteral( "size_unit" )] = QgsUnitTypes::encodeUnit( mSizeUnit );
258  properties[QStringLiteral( "size_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mSizeMapUnitScale );
259  properties[QStringLiteral( "offset" )] = QgsSymbolLayerUtils::encodePoint( mOffset );
260  properties[QStringLiteral( "offset_unit" )] = QgsUnitTypes::encodeUnit( mOffsetUnit );
261  properties[QStringLiteral( "offset_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mOffsetMapUnitScale );
262  return properties;
263 }
264 
266 {
267  return mDistanceUnit == QgsUnitTypes::RenderMapUnits || mDistanceUnit == QgsUnitTypes::RenderMetersInMapUnits
270 }
271 
272 void QgsVectorFieldSymbolLayer::toSld( QDomDocument &doc, QDomElement &element, const QVariantMap &props ) const
273 {
274  element.appendChild( doc.createComment( QStringLiteral( "VectorField not implemented yet..." ) ) );
275  mLineSymbol->toSld( doc, element, props );
276 }
277 
279 {
280  Q_UNUSED( element )
281  return nullptr;
282 }
283 
285 {
286  if ( mLineSymbol )
287  {
288  mLineSymbol->drawPreviewIcon( context.renderContext().painter(), size );
289  }
290 }
291 
292 QSet<QString> QgsVectorFieldSymbolLayer::usedAttributes( const QgsRenderContext &context ) const
293 {
294  QSet<QString> attributes = QgsMarkerSymbolLayer::usedAttributes( context );
295  if ( !mXAttribute.isEmpty() )
296  {
297  attributes.insert( mXAttribute );
298  }
299  if ( !mYAttribute.isEmpty() )
300  {
301  attributes.insert( mYAttribute );
302  }
303  if ( mLineSymbol )
304  {
305  attributes.unite( mLineSymbol->usedAttributes( context ) );
306  }
307  return attributes;
308 }
309 
311 {
313  return true;
314  if ( mLineSymbol && mLineSymbol->hasDataDefinedProperties() )
315  return true;
316  return false;
317 }
318 
319 void QgsVectorFieldSymbolLayer::convertPolarToCartesian( double length, double angle, double &x, double &y ) const
320 {
321  //convert angle to degree and to north orientation
322  if ( mAngleOrientation == CounterclockwiseFromEast )
323  {
324  if ( angle <= 90 )
325  {
326  angle = 90 - angle;
327  }
328  else
329  {
330  angle = 360 - angle + 90;
331  }
332  }
333 
334  if ( mAngleUnits == Degrees )
335  {
336  angle = angle * M_PI / 180.0;
337  }
338 
339  x = length * std::sin( angle );
340  y = length * std::cos( angle );
341 }
342 
343 void QgsVectorFieldSymbolLayer::setColor( const QColor &color )
344 {
345  if ( mLineSymbol )
346  mLineSymbol->setColor( color );
347 
348  mColor = color;
349 }
350 
352 {
353  return mLineSymbol ? mLineSymbol->color() : mColor;
354 }
355 
356 
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:56
QVariant attribute(const QString &name) const
Lookup attribute value from attribute name.
Definition: qgsfeature.cpp:287
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:344
A line symbol type, for rendering LineString and MultiLineString geometries.
Definition: qgssymbol.h:1204
Perform transforms between map coordinates and device coordinates.
Definition: qgsmaptopixel.h:39
double mapRotation() const
Returns 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.
const QgsMapToPixel & mapToPixel() const
Returns the context's map to pixel transform, which transforms between map coordinates and device coo...
double convertToPainterUnits(double size, QgsUnitTypes::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale()) const
Converts a size from the specified units to painter units (pixels).
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 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.
virtual bool setSubSymbol(QgsSymbol *symbol)
Sets layer's subsymbol. takes ownership of the passed symbol.
QgsFields fields() const
Fields of the layer.
Definition: qgssymbol.h:900
QgsRenderContext & renderContext()
Returns a reference to the context's render context.
Definition: qgssymbol.h:794
const QgsFeature * feature() const
Returns the current feature being rendered.
Definition: qgssymbol.h:875
Abstract base class for all rendered symbols.
Definition: qgssymbol.h:65
SymbolType type() const
Returns the symbol's type.
Definition: qgssymbol.h:138
@ Line
Line symbol.
Definition: qgssymbol.h:89
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:167
@ RenderUnknownUnit
Mixed or unknown units.
Definition: qgsunittypes.h:174
@ RenderMetersInMapUnits
Meters value as Map units.
Definition: qgsunittypes.h:175
@ RenderMapUnits
Map units.
Definition: qgsunittypes.h:169
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
The fill color.
QgsUnitTypes::RenderUnit outputUnit() const override
Returns the units to use for sizes and widths within the symbol layer.
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.
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
The fill color.
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:316