QGIS API Documentation  2.99.0-Master (08c2e66)
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.
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)
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.
double convertToPainterUnits(double size, QgsUnitTypes::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale()) const
Converts a size from the specified units to painter units (pixels).
double size() const
Returns the symbol size.
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:39
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:72
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:136
static QgsSymbolLayer * create(const QgsStringMap &properties=QgsStringMap())
QMap< QString, QString > QgsStringMap
Definition: qgis.h:330
static QString encodePoint(QPointF point)
Encodes a QPointF to a string.
double angle() const
Returns the rotation angle for the marker, in degrees clockwise from north.
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.
QgsUnitTypes::RenderUnit mOffsetUnit
Offset units.
void drawPreviewIcon(QgsSymbolRenderContext &context, QSize size) override
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.
int lookupField(const QString &fieldName) const
Look up field&#39;s index from the field name.
Definition: qgsfields.cpp:289
QgsRenderContext & renderContext()
Definition: qgssymbol.h:396
virtual QColor color() const override
The fill color.
void startRender(QgsSymbolRenderContext &context) override
QgsFields fields() const
Fields of the layer.
Definition: qgssymbol.h:458
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
Contains information about the context of a rendering operation.
QPainter * painter()
Returns the destination QPainter for the render operation.
QVariant attribute(const QString &name) const
Lookup attribute value from attribute name.
Definition: qgsfeature.cpp:262
Struct for storing maximum and minimum scales for measurements in map units.
void setMapUnitScale(const QgsMapUnitScale &scale) override
virtual QSet< QString > usedAttributes(const QgsRenderContext &context) const
Returns the set of attributes referenced by the layer.
const QgsFeature * feature() const
Current feature being rendered - may be null.
Definition: qgssymbol.h:435
static Q_INVOKABLE RenderUnit decodeRenderUnit(const QString &string, bool *ok=0)
Decodes a render unit from a string.
SymbolType type() const
Definition: qgssymbol.h:99
void stopRender(QgsSymbolRenderContext &context) override
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.
bool isEmpty() const
Check whether the container is empty.
Definition: qgsfields.cpp:110
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:92
static QgsSymbolLayer * createFromSld(QDomElement &element)