QGIS API Documentation  2.99.0-Master (dcec6bb)
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 
23  : mXAttribute( QLatin1String( "" ) )
24  , mYAttribute( QLatin1String( "" ) )
25  , mDistanceUnit( QgsUnitTypes::RenderMillimeters )
26  , mScale( 1.0 )
27  , mVectorFieldType( Cartesian )
28  , mAngleOrientation( ClockwiseFromNorth )
29  , mAngleUnits( Degrees )
30  , mLineSymbol( nullptr )
31  , mXIndex( -1 )
32  , mYIndex( -1 )
33 {
34  setSubSymbol( new QgsLineSymbol() );
35 }
36 
38 {
40  mDistanceUnit = unit;
41 }
42 
44 {
45  if ( QgsMarkerSymbolLayer::outputUnit() == mDistanceUnit )
46  {
47  return mDistanceUnit;
48  }
50 }
51 
53 {
55  mDistanceMapUnitScale = scale;
56 }
57 
59 {
60  if ( QgsMarkerSymbolLayer::mapUnitScale() == mDistanceMapUnitScale )
61  {
62  return mDistanceMapUnitScale;
63  }
64  return QgsMapUnitScale();
65 }
66 
68 {
70  if ( properties.contains( QStringLiteral( "x_attribute" ) ) )
71  {
72  symbolLayer->setXAttribute( properties[QStringLiteral( "x_attribute" )] );
73  }
74  if ( properties.contains( QStringLiteral( "y_attribute" ) ) )
75  {
76  symbolLayer->setYAttribute( properties[QStringLiteral( "y_attribute" )] );
77  }
78  if ( properties.contains( QStringLiteral( "distance_unit" ) ) )
79  {
80  symbolLayer->setDistanceUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "distance_unit" )] ) );
81  }
82  if ( properties.contains( QStringLiteral( "distance_map_unit_scale" ) ) )
83  {
84  symbolLayer->setDistanceMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "distance_map_unit_scale" )] ) );
85  }
86  if ( properties.contains( QStringLiteral( "scale" ) ) )
87  {
88  symbolLayer->setScale( properties[QStringLiteral( "scale" )].toDouble() );
89  }
90  if ( properties.contains( QStringLiteral( "vector_field_type" ) ) )
91  {
92  symbolLayer->setVectorFieldType( static_cast< VectorFieldType >( properties[QStringLiteral( "vector_field_type" )].toInt() ) );
93  }
94  if ( properties.contains( QStringLiteral( "angle_orientation" ) ) )
95  {
96  symbolLayer->setAngleOrientation( static_cast< AngleOrientation >( properties[QStringLiteral( "angle_orientation" )].toInt() ) );
97  }
98  if ( properties.contains( QStringLiteral( "angle_units" ) ) )
99  {
100  symbolLayer->setAngleUnits( static_cast< AngleUnits >( properties[QStringLiteral( "angle_units" )].toInt() ) );
101  }
102  if ( properties.contains( QStringLiteral( "size" ) ) )
103  {
104  symbolLayer->setSize( properties[QStringLiteral( "size" )].toDouble() );
105  }
106  if ( properties.contains( QStringLiteral( "size_unit" ) ) )
107  {
108  symbolLayer->setSizeUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "size_unit" )] ) );
109  }
110  if ( properties.contains( QStringLiteral( "size_map_unit_scale" ) ) )
111  {
112  symbolLayer->setSizeMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "size_map_unit_scale" )] ) );
113  }
114  if ( properties.contains( QStringLiteral( "offset" ) ) )
115  {
116  symbolLayer->setOffset( QgsSymbolLayerUtils::decodePoint( properties[QStringLiteral( "offset" )] ) );
117  }
118  if ( properties.contains( QStringLiteral( "offset_unit" ) ) )
119  {
120  symbolLayer->setOffsetUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "offset_unit" )] ) );
121  }
122  if ( properties.contains( QStringLiteral( "offset_map_unit_scale" ) ) )
123  {
124  symbolLayer->setOffsetMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "offset_map_unit_scale" )] ) );
125  }
126  return symbolLayer;
127 }
128 
130 {
131  if ( symbol->type() == QgsSymbol::Line )
132  {
133  mLineSymbol.reset( static_cast<QgsLineSymbol *>( symbol ) );
134  return true;
135  }
136  return false;
137 }
138 
140 {
141  if ( !mLineSymbol )
142  {
143  return;
144  }
145 
146  const QgsRenderContext &ctx = context.renderContext();
147 
148  const QgsFeature *f = context.feature();
149  if ( !f )
150  {
151  //preview
152  QPolygonF line;
153  line << QPointF( 0, 50 );
154  line << QPointF( 100, 50 );
155  mLineSymbol->renderPolyline( line, nullptr, context.renderContext() );
156  }
157 
158  double xComponent = 0;
159  double yComponent = 0;
160 
161  double xVal = 0;
162  if ( f && mXIndex != -1 )
163  {
164  xVal = f->attribute( mXIndex ).toDouble();
165  }
166  double yVal = 0;
167  if ( f && mYIndex != -1 )
168  {
169  yVal = f->attribute( mYIndex ).toDouble();
170  }
171 
172  switch ( mVectorFieldType )
173  {
174  case Cartesian:
175  xComponent = ctx.convertToPainterUnits( xVal, mDistanceUnit, mDistanceMapUnitScale );
176  yComponent = ctx.convertToPainterUnits( yVal, mDistanceUnit, mDistanceMapUnitScale );
177  break;
178  case Polar:
179  convertPolarToCartesian( xVal, yVal, xComponent, yComponent );
180  xComponent = ctx.convertToPainterUnits( xComponent, mDistanceUnit, mDistanceMapUnitScale );
181  yComponent = ctx.convertToPainterUnits( yComponent, mDistanceUnit, mDistanceMapUnitScale );
182  break;
183  case Height:
184  xComponent = 0;
185  yComponent = ctx.convertToPainterUnits( yVal, mDistanceUnit, mDistanceMapUnitScale );
186  break;
187  default:
188  break;
189  }
190 
191  xComponent *= mScale;
192  yComponent *= mScale;
193 
194  QPolygonF line;
195  line << point;
196  line << QPointF( point.x() + xComponent, point.y() - yComponent );
197  mLineSymbol->renderPolyline( line, f, context.renderContext() );
198 }
199 
201 {
202  if ( mLineSymbol )
203  {
204  mLineSymbol->startRender( context.renderContext(), context.fields() );
205  }
206 
207  QgsFields fields = context.fields();
208  if ( !fields.isEmpty() )
209  {
210  mXIndex = fields.lookupField( mXAttribute );
211  mYIndex = fields.lookupField( mYAttribute );
212  }
213  else
214  {
215  mXIndex = -1;
216  mYIndex = -1;
217  }
218 }
219 
221 {
222  if ( mLineSymbol )
223  {
224  mLineSymbol->stopRender( context.renderContext() );
225  }
226 }
227 
229 {
231  if ( mLineSymbol )
232  {
233  clonedLayer->setSubSymbol( mLineSymbol->clone() );
234  }
235  return static_cast< QgsVectorFieldSymbolLayer * >( clonedLayer );
236 }
237 
239 {
241  properties[QStringLiteral( "x_attribute" )] = mXAttribute;
242  properties[QStringLiteral( "y_attribute" )] = mYAttribute;
243  properties[QStringLiteral( "distance_unit" )] = QgsUnitTypes::encodeUnit( mDistanceUnit );
244  properties[QStringLiteral( "distance_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mDistanceMapUnitScale );
245  properties[QStringLiteral( "scale" )] = QString::number( mScale );
246  properties[QStringLiteral( "vector_field_type" )] = QString::number( mVectorFieldType );
247  properties[QStringLiteral( "angle_orientation" )] = QString::number( mAngleOrientation );
248  properties[QStringLiteral( "angle_units" )] = QString::number( mAngleUnits );
249  properties[QStringLiteral( "size" )] = QString::number( mSize );
250  properties[QStringLiteral( "size_unit" )] = QgsUnitTypes::encodeUnit( mSizeUnit );
251  properties[QStringLiteral( "size_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mSizeMapUnitScale );
252  properties[QStringLiteral( "offset" )] = QgsSymbolLayerUtils::encodePoint( mOffset );
253  properties[QStringLiteral( "offset_unit" )] = QgsUnitTypes::encodeUnit( mOffsetUnit );
254  properties[QStringLiteral( "offset_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mOffsetMapUnitScale );
255  return properties;
256 }
257 
258 void QgsVectorFieldSymbolLayer::toSld( QDomDocument &doc, QDomElement &element, const QgsStringMap &props ) const
259 {
260  element.appendChild( doc.createComment( QStringLiteral( "VectorField not implemented yet..." ) ) );
261  mLineSymbol->toSld( doc, element, props );
262 }
263 
265 {
266  Q_UNUSED( element );
267  return nullptr;
268 }
269 
271 {
272  if ( mLineSymbol )
273  {
274  mLineSymbol->drawPreviewIcon( context.renderContext().painter(), size );
275  }
276 }
277 
278 QSet<QString> QgsVectorFieldSymbolLayer::usedAttributes( const QgsRenderContext &context ) const
279 {
280  QSet<QString> attributes = QgsMarkerSymbolLayer::usedAttributes( context );
281  if ( !mXAttribute.isEmpty() )
282  {
283  attributes.insert( mXAttribute );
284  }
285  if ( !mYAttribute.isEmpty() )
286  {
287  attributes.insert( mYAttribute );
288  }
289  if ( mLineSymbol )
290  {
291  attributes.unite( mLineSymbol->usedAttributes( context ) );
292  }
293  return attributes;
294 }
295 
296 void QgsVectorFieldSymbolLayer::convertPolarToCartesian( double length, double angle, double &x, double &y ) const
297 {
298  //convert angle to degree and to north orientation
299  if ( mAngleOrientation == CounterclockwiseFromEast )
300  {
301  if ( angle <= 90 )
302  {
303  angle = 90 - angle;
304  }
305  else
306  {
307  angle = 360 - angle + 90;
308  }
309  }
310 
311  if ( mAngleUnits == Degrees )
312  {
313  angle = angle * M_PI / 180.0;
314  }
315 
316  x = length * sin( angle );
317  y = length * cos( angle );
318 }
319 
321 {
322  if ( mLineSymbol )
323  mLineSymbol->setColor( color );
324 
325  mColor = color;
326 }
327 
329 {
330  return mLineSymbol ? mLineSymbol->color() : mColor;
331 }
332 
333 
QgsVectorFieldSymbolLayer * clone() const override
Shall be reimplemented by subclasses to create a deep copy of the instance.
int lookupField(const QString &fieldName) const
Look up field&#39;s index from the field name.
Definition: qgsfields.cpp:289
void setOffset(QPointF offset)
Sets the marker&#39;s offset, which is the horizontal and vertical displacement which the rendered marker...
QgsMapUnitScale mapUnitScale() const override
QgsMapUnitScale mapUnitScale() const override
void setXAttribute(const QString &attribute)
void setOffsetUnit(QgsUnitTypes::RenderUnit unit)
Sets the units for the symbol&#39;s offset.
void setYAttribute(const QString &attribute)
QgsFields fields() const
Fields of the layer.
Definition: qgssymbol.h:496
QgsUnitTypes::RenderUnit outputUnit() const override
Returns the units to use for sizes and widths within the symbol layer.
void setAngleUnits(AngleUnits units)
void setDistanceUnit(QgsUnitTypes::RenderUnit unit)
Sets the units for the distance.
QgsUnitTypes::RenderUnit mSizeUnit
Marker size unit.
Helper functions for various unit types.
Definition: qgsunittypes.h:36
static QPointF decodePoint(const QString &string)
Decodes a QSizeF from a string.
void renderPoint(QPointF point, QgsSymbolRenderContext &context) override
Renders a marker at the specified point.
static QString encodeMapUnitScale(const QgsMapUnitScale &mapUnitScale)
Container of fields for a vector layer.
Definition: qgsfields.h:41
void setOffsetMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale for the symbol&#39;s offset.
QPointF mOffset
Marker offset.
Line symbol.
Definition: qgssymbol.h:85
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:61
static QgsSymbolLayer * create(const QgsStringMap &properties=QgsStringMap())
QMap< QString, QString > QgsStringMap
Definition: qgis.h:340
static QString encodePoint(QPointF point)
Encodes a QPointF to a string.
A symbol layer class for displaying displacement arrows based on point layer attributes.
virtual bool setSubSymbol(QgsSymbol *symbol)
set layer&#39;s subsymbol. takes ownership of the passed symbol
void setOutputUnit(QgsUnitTypes::RenderUnit unit) override
Sets 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.
QgsUnitTypes::RenderUnit mOffsetUnit
Offset units.
void drawPreviewIcon(QgsSymbolRenderContext &context, QSize size) override
double size() const
Returns the symbol size.
void toSld(QDomDocument &doc, QDomElement &element, const QgsStringMap &props) const override
QgsStringMap properties() const override
Should be reimplemented by subclasses to return a string map that contains the configuration informat...
void setSize(double size)
Sets the symbol size.
void setSizeMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale for the symbol&#39;s size.
#define M_PI
void setMapUnitScale(const QgsMapUnitScale &scale) override
void setDistanceMapUnitScale(const QgsMapUnitScale &scale)
QgsMapUnitScale mSizeMapUnitScale
Marker size map unit scale.
QgsRenderContext & renderContext()
Definition: qgssymbol.h:425
virtual QColor color() const override
The fill color.
void startRender(QgsSymbolRenderContext &context) override
static Q_INVOKABLE QString encodeUnit(QgsUnitTypes::DistanceUnit unit)
Encodes a distance unit to a string.
void setColor(const QColor &color) override
The fill color.
QSet< QString > usedAttributes(const QgsRenderContext &context) const override
Returns the set of attributes referenced by the layer.
void setSizeUnit(QgsUnitTypes::RenderUnit unit)
Sets the units for the symbol&#39;s size.
bool setSubSymbol(QgsSymbol *symbol) override
set layer&#39;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.
Contains information about the context of a rendering operation.
double convertToPainterUnits(double size, QgsUnitTypes::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale()) const
Converts a size from the specified units to painter units (pixels).
QPainter * painter()
Returns the destination QPainter for the render operation.
SymbolType type() const
Definition: qgssymbol.h:112
Struct for storing maximum and minimum scales for measurements in map units.
void setMapUnitScale(const QgsMapUnitScale &scale) override
const QgsFeature * feature() const
Current feature being rendered - may be null.
Definition: qgssymbol.h:473
static Q_INVOKABLE RenderUnit decodeRenderUnit(const QString &string, bool *ok=0)
Decodes a render unit from a string.
void stopRender(QgsSymbolRenderContext &context) override
bool isEmpty() const
Check whether the container is empty.
Definition: qgsfields.cpp:110
double mSize
Marker size.
void setAngleOrientation(AngleOrientation orientation)
static QgsMapUnitScale decodeMapUnitScale(const QString &str)
QgsMapUnitScale mOffsetMapUnitScale
Offset map unit scale.
QgsUnitTypes::RenderUnit outputUnit() const override
Returns the units to use for sizes and widths within the symbol layer.
QVariant attribute(const QString &name) const
Lookup attribute value from attribute name.
Definition: qgsfeature.cpp:255
void setVectorFieldType(VectorFieldType type)
void setOutputUnit(QgsUnitTypes::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
RenderUnit
Rendering size units.
Definition: qgsunittypes.h:95
static QgsSymbolLayer * createFromSld(QDomElement &element)