QGIS API Documentation  2.7.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
qgssymbollayerv2.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgssymbollayerv2.cpp
3  ---------------------
4  begin : November 2009
5  copyright : (C) 2009 by Martin Dobias
6  email : wonder dot sk at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
16 #include "qgssymbollayerv2.h"
17 #include "qgsclipper.h"
18 #include "qgsexpression.h"
19 #include "qgsrendercontext.h"
20 #include "qgsvectorlayer.h"
21 #include "qgsdxfexport.h"
22 #include "qgsgeometrysimplifier.h"
23 
24 #include <QSize>
25 #include <QPainter>
26 #include <QPointF>
27 #include <QPolygonF>
28 
29 const QgsExpression* QgsSymbolLayerV2::dataDefinedProperty( const QString& property ) const
30 {
31  QMap< QString, QgsExpression* >::const_iterator it = mDataDefinedProperties.find( property );
32  if ( it != mDataDefinedProperties.constEnd() )
33  {
34  return it.value();
35  }
36  return 0;
37 }
38 
39 QgsExpression* QgsSymbolLayerV2::expression( const QString& property ) const
40 {
41  QMap< QString, QgsExpression* >::const_iterator it = mDataDefinedProperties.find( property );
42  if ( it != mDataDefinedProperties.constEnd() )
43  {
44  return it.value();
45  }
46  return 0;
47 }
48 
49 QString QgsSymbolLayerV2::dataDefinedPropertyString( const QString& property ) const
50 {
51  const QgsExpression* ex = dataDefinedProperty( property );
52  return ex ? ex->expression() : QString();
53 }
54 
55 void QgsSymbolLayerV2::setDataDefinedProperty( const QString& property, const QString& expressionString )
56 {
57  removeDataDefinedProperty( property );
58  mDataDefinedProperties.insert( property, new QgsExpression( expressionString ) );
59 }
60 
61 void QgsSymbolLayerV2::removeDataDefinedProperty( const QString& property )
62 {
63  QMap< QString, QgsExpression* >::iterator it = mDataDefinedProperties.find( property );
64  if ( it != mDataDefinedProperties.end() )
65  {
66  delete( it.value() );
67  mDataDefinedProperties.erase( it );
68  }
69 }
70 
72 {
73  QMap< QString, QgsExpression* >::iterator it = mDataDefinedProperties.begin();
74  for ( ; it != mDataDefinedProperties.constEnd(); ++it )
75  {
76  delete( it.value() );
77  }
78  mDataDefinedProperties.clear();
79 }
80 
82  double mmMapUnitScaleFactor,
83  const QString& layerName,
84  const QgsSymbolV2RenderContext* context,
85  const QgsFeature* f,
86  const QPointF& shift ) const
87 {
88  Q_UNUSED( e );
89  Q_UNUSED( mmMapUnitScaleFactor );
90  Q_UNUSED( layerName );
91  Q_UNUSED( context );
92  Q_UNUSED( f );
93  Q_UNUSED( shift );
94  return false;
95 }
96 
97 double QgsSymbolLayerV2::dxfWidth( const QgsDxfExport& e, const QgsSymbolV2RenderContext& context ) const
98 {
99  Q_UNUSED( e );
100  Q_UNUSED( context );
101  return 1.0;
102 }
103 
104 double QgsSymbolLayerV2::dxfOffset( const QgsDxfExport& e, const QgsSymbolV2RenderContext& context ) const
105 {
106  Q_UNUSED( e );
107  Q_UNUSED( context );
108  return 0.0;
109 }
110 
112 {
113  Q_UNUSED( context );
114  return color();
115 }
116 
118 {
119  Q_UNUSED( unit );
120  return QVector<qreal>();
121 }
122 
123 Qt::PenStyle QgsSymbolLayerV2::dxfPenStyle() const
124 {
125  return Qt::SolidLine;
126 }
127 
129 {
130  Q_UNUSED( context );
131  return color();
132 }
133 
134 Qt::BrushStyle QgsSymbolLayerV2::dxfBrushStyle() const
135 {
136  return Qt::NoBrush;
137 }
138 
139 void QgsSymbolLayerV2::prepareExpressions( const QgsFields* fields, double scale )
140 {
141  if ( !fields )
142  {
143  return;
144  }
145 
146  QMap< QString, QgsExpression* >::iterator it = mDataDefinedProperties.begin();
147  for ( ; it != mDataDefinedProperties.end(); ++it )
148  {
149  if ( it.value() )
150  {
151  it.value()->prepare( *fields );
152  if ( scale > 0 )
153  {
154  it.value()->setScale( scale );
155  }
156  }
157  }
158 }
159 
160 QSet<QString> QgsSymbolLayerV2::usedAttributes() const
161 {
162  QStringList columns;
163 
164  QMap< QString, QgsExpression* >::const_iterator ddIt = mDataDefinedProperties.constBegin();
165  for ( ; ddIt != mDataDefinedProperties.constEnd(); ++ddIt )
166  {
167  if ( ddIt.value() )
168  {
169  columns.append( ddIt.value()->referencedColumns() );
170  }
171  }
172 
173  QSet<QString> attributes;
174  QStringList::const_iterator it = columns.constBegin();
175  for ( ; it != columns.constEnd(); ++it )
176  {
177  attributes.insert( *it );
178  }
179 
180  return attributes;
181 }
182 
184 {
185  QMap< QString, QgsExpression* >::const_iterator ddIt = mDataDefinedProperties.constBegin();
186  for ( ; ddIt != mDataDefinedProperties.constEnd(); ++ddIt )
187  {
188  if ( ddIt.value() )
189  {
190  stringMap.insert( ddIt.key() + "_expression", ddIt.value()->expression() );
191  }
192  }
193 }
194 
196 {
197  if ( !destLayer )
198  return;
199 
200  destLayer->removeDataDefinedProperties();
201 
202  QMap< QString, QgsExpression* >::const_iterator ddIt = mDataDefinedProperties.constBegin();
203  for ( ; ddIt != mDataDefinedProperties.constEnd(); ++ddIt )
204  {
205  if ( ddIt.value() )
206  {
207  destLayer->setDataDefinedProperty( ddIt.key(), ddIt.value()->expression() );
208  }
209  }
210 }
211 
212 
214  : QgsSymbolLayerV2( QgsSymbolV2::Marker, locked )
215  , mSizeUnit( QgsSymbolV2::MM )
216  , mOffsetUnit( QgsSymbolV2::MM )
217  , mHorizontalAnchorPoint( HCenter )
218  , mVerticalAnchorPoint( VCenter )
219 {
220  mOffsetExpression = NULL;
221  mHorizontalAnchorExpression = NULL;
222  mVerticalAnchorExpression = NULL;
223 }
224 
226  : QgsSymbolLayerV2( QgsSymbolV2::Line, locked )
227  , mWidthUnit( QgsSymbolV2::MM )
228 {
229 }
230 
232  : QgsSymbolLayerV2( QgsSymbolV2::Fill, locked )
233  , mAngle( 0.0 )
234 {
235 }
236 
238 {
239  Q_UNUSED( context );
240  mOffsetExpression = expression( "offset" );
241  mHorizontalAnchorExpression = expression( "horizontal_anchor_point" );
242  mVerticalAnchorExpression = expression( "vertical_anchor_point" );
243 }
244 
246 {
247  startRender( context );
248  renderPoint( QPointF( size.width() / 2, size.height() / 2 ), context );
249  stopRender( context );
250 }
251 
252 void QgsMarkerSymbolLayerV2::markerOffset( const QgsSymbolV2RenderContext& context, double& offsetX, double& offsetY ) const
253 {
255 }
256 
257 void QgsMarkerSymbolLayerV2::markerOffset( const QgsSymbolV2RenderContext& context, double width, double height, double& offsetX, double& offsetY ) const
258 {
259  markerOffset( context, width, height, mSizeUnit, mSizeUnit, offsetX, offsetY, mSizeMapUnitScale, mSizeMapUnitScale );
260 }
261 
262 void QgsMarkerSymbolLayerV2::markerOffset( const QgsSymbolV2RenderContext& context, double width, double height,
263  QgsSymbolV2::OutputUnit widthUnit, QgsSymbolV2::OutputUnit heightUnit,
264  double& offsetX, double& offsetY, const QgsMapUnitScale& widthMapUnitScale, const QgsMapUnitScale& heightMapUnitScale ) const
265 {
266  offsetX = mOffset.x();
267  offsetY = mOffset.y();
268 
269  if ( mOffsetExpression )
270  {
271  QPointF offset = QgsSymbolLayerV2Utils::decodePoint( mOffsetExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString() );
272  offsetX = offset.x();
273  offsetY = offset.y();
274  }
275 
278 
281  if ( mHorizontalAnchorExpression )
282  {
283  horizontalAnchorPoint = decodeHorizontalAnchorPoint( mHorizontalAnchorExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString() );
284  }
285  if ( mVerticalAnchorExpression )
286  {
287  verticalAnchorPoint = decodeVerticalAnchorPoint( mVerticalAnchorExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString() );
288  }
289 
290  //correct horizontal position according to anchor point
291  if ( horizontalAnchorPoint == HCenter && verticalAnchorPoint == VCenter )
292  {
293  return;
294  }
295 
296  double anchorPointCorrectionX = width * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), widthUnit, widthMapUnitScale ) / 2.0;
297  double anchorPointCorrectionY = height * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), heightUnit, heightMapUnitScale ) / 2.0;
298  if ( horizontalAnchorPoint == Left )
299  {
300  offsetX += anchorPointCorrectionX;
301  }
302  else if ( horizontalAnchorPoint == Right )
303  {
304  offsetX -= anchorPointCorrectionX;
305  }
306 
307  //correct vertical position according to anchor point
308  if ( verticalAnchorPoint == Top )
309  {
310  offsetY += anchorPointCorrectionY;
311  }
312  else if ( verticalAnchorPoint == Bottom )
313  {
314  offsetY -= anchorPointCorrectionY;
315  }
316 }
317 
318 QPointF QgsMarkerSymbolLayerV2::_rotatedOffset( const QPointF& offset, double angle )
319 {
320  angle = DEG2RAD( angle );
321  double c = cos( angle ), s = sin( angle );
322  return QPointF( offset.x() * c - offset.y() * s, offset.x() * s + offset.y() * c );
323 }
324 
325 QgsMarkerSymbolLayerV2::HorizontalAnchorPoint QgsMarkerSymbolLayerV2::decodeHorizontalAnchorPoint( const QString& str )
326 {
327  if ( str.compare( "left", Qt::CaseInsensitive ) == 0 )
328  {
330  }
331  else if ( str.compare( "right", Qt::CaseInsensitive ) == 0 )
332  {
334  }
335  else
336  {
338  }
339 }
340 
341 QgsMarkerSymbolLayerV2::VerticalAnchorPoint QgsMarkerSymbolLayerV2::decodeVerticalAnchorPoint( const QString& str )
342 {
343  if ( str.compare( "top", Qt::CaseInsensitive ) == 0 )
344  {
346  }
347  else if ( str.compare( "bottom", Qt::CaseInsensitive ) == 0 )
348  {
350  }
351  else
352  {
354  }
355 }
356 
358 {
359  mSizeUnit = unit;
360  mOffsetUnit = unit;
361 }
362 
364 {
365  if ( mOffsetUnit != mSizeUnit )
366  {
367  return QgsSymbolV2::Mixed;
368  }
369  return mOffsetUnit;
370 }
371 
373 {
374  mSizeMapUnitScale = scale;
375  mOffsetMapUnitScale = scale;
376 }
377 
379 {
381  {
382  return mSizeMapUnitScale;
383  }
384  return QgsMapUnitScale();
385 }
386 
388 {
389  mWidthUnit = unit;
390 }
391 
393 {
394  return mWidthUnit;
395 }
396 
398 {
399  mWidthMapUnitScale = scale;
400 }
401 
403 {
404  return mWidthMapUnitScale;
405 }
406 
407 
409 {
410  QPolygonF points;
411  // we're adding 0.5 to get rid of blurred preview:
412  // drawing antialiased lines of width 1 at (x,0)-(x,100) creates 2px line
413  points << QPointF( 0, size.height() / 2 + 0.5 ) << QPointF( size.width(), size.height() / 2 + 0.5 );
414 
415  startRender( context );
416  renderPolyline( points, context );
417  stopRender( context );
418 }
419 
420 void QgsLineSymbolLayerV2::renderPolygonOutline( const QPolygonF& points, QList<QPolygonF>* rings, QgsSymbolV2RenderContext& context )
421 {
422  renderPolyline( points, context );
423  if ( rings )
424  {
425  foreach ( const QPolygonF& ring, *rings )
426  renderPolyline( ring, context );
427  }
428 }
429 
431 {
432  Q_UNUSED( context );
434 }
435 
436 
438 {
439  QPolygonF poly = QRectF( QPointF( 0, 0 ), QPointF( size.width(), size.height() ) );
440  startRender( context );
441  renderPolygon( poly, NULL, context );
442  stopRender( context );
443 }
444 
445 void QgsFillSymbolLayerV2::_renderPolygon( QPainter* p, const QPolygonF& points, const QList<QPolygonF>* rings, QgsSymbolV2RenderContext& context )
446 {
447  if ( !p )
448  {
449  return;
450  }
451 
452  // Disable 'Antialiasing' if the geometry was generalized in the current RenderContext (We known that it must have least #5 points).
453  if ( points.size() <= 5 &&
456  ( p->renderHints() & QPainter::Antialiasing ) )
457  {
458  p->setRenderHint( QPainter::Antialiasing, false );
459  p->drawRect( points.boundingRect() );
460  p->setRenderHint( QPainter::Antialiasing, true );
461  return;
462  }
463 
464  if ( rings == NULL )
465  {
466  // simple polygon without holes
467  p->drawPolygon( points );
468  }
469  else
470  {
471  // polygon with holes must be drawn using painter path
472  QPainterPath path;
473  QPolygonF outerRing = points;
474  path.addPolygon( outerRing );
475 
476  QList<QPolygonF>::const_iterator it = rings->constBegin();
477  for ( ; it != rings->constEnd(); ++it )
478  {
479  QPolygonF ring = *it;
480  path.addPolygon( ring );
481  }
482 
483  p->drawPath( path );
484  }
485 }
486 
487 void QgsMarkerSymbolLayerV2::toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
488 {
489  QDomElement symbolizerElem = doc.createElement( "se:PointSymbolizer" );
490  if ( !props.value( "uom", "" ).isEmpty() )
491  symbolizerElem.setAttribute( "uom", props.value( "uom", "" ) );
492  element.appendChild( symbolizerElem );
493 
494  // <Geometry>
495  QgsSymbolLayerV2Utils::createGeometryElement( doc, symbolizerElem, props.value( "geom", "" ) );
496 
497  writeSldMarker( doc, symbolizerElem, props );
498 }
499 
500 
virtual QSet< QString > usedAttributes() const
static double mapUnitScaleFactor(double scaleDenominator, QgsSymbolV2::OutputUnit symbolUnits, QGis::UnitType mapUnits)
Class for parsing and evaluation of expressions (formerly called "search strings").
Definition: qgsexpression.h:87
VerticalAnchorPoint verticalAnchorPoint() const
virtual void removeDataDefinedProperties()
QgsSymbolV2::OutputUnit outputUnit() const override
QMap< QString, QgsExpression * > mDataDefinedProperties
float threshold() const
Gets the simplification threshold of the vector layer managed.
QgsMapUnitScale mSizeMapUnitScale
virtual Qt::PenStyle dxfPenStyle() const
virtual double dxfWidth(const QgsDxfExport &e, const QgsSymbolV2RenderContext &context) const
virtual double width() const
virtual double dxfOffset(const QgsDxfExport &e, const QgsSymbolV2RenderContext &context) const
HorizontalAnchorPoint horizontalAnchorPoint() const
const QString expression() const
Alias for dump()
QVariant evaluate(const QgsFeature *f=NULL)
Evaluate the feature and return the result.
const QgsVectorSimplifyMethod & vectorSimplifyMethod() const
Added in QGIS v2.4.
QGis::UnitType mapUnits() const
Definition: qgsdxfexport.h:54
#define DEG2RAD(x)
QgsSymbolV2::OutputUnit outputUnit() const override
static QPointF decodePoint(QString str)
Container of fields for a vector layer.
Definition: qgsfield.h:172
virtual void renderPolygon(const QPolygonF &points, QList< QPolygonF > *rings, QgsSymbolV2RenderContext &context)=0
QgsMapUnitScale mWidthMapUnitScale
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:113
virtual void removeDataDefinedProperty(const QString &property)
QMap< QString, QString > QgsStringMap
Definition: qgis.h:416
void setMapUnitScale(const QgsMapUnitScale &scale) override
virtual QString dataDefinedPropertyString(const QString &property) const
virtual void startRender(QgsSymbolV2RenderContext &context)=0
virtual QgsExpression * expression(const QString &property) const
virtual double dxfWidth(const QgsDxfExport &e, const QgsSymbolV2RenderContext &context) const override
virtual void writeSldMarker(QDomDocument &doc, QDomElement &element, QgsStringMap props) const
void setOutputUnit(QgsSymbolV2::OutputUnit unit) override
const QgsFeature * feature() const
Current feature being rendered - may be null.
Definition: qgssymbolv2.h:213
virtual void renderPoint(const QPointF &point, QgsSymbolV2RenderContext &context)=0
virtual QVector< qreal > dxfCustomDashPattern(QgsSymbolV2::OutputUnit &unit) const
The geometries can be rendered with 'AntiAliasing' disabled because of it is '1-pixel size'...
QgsMarkerSymbolLayerV2(bool locked=false)
QgsSymbolV2::OutputUnit mWidthUnit
virtual QColor color() const
HorizontalAnchorPoint mHorizontalAnchorPoint
virtual void renderPolygonOutline(const QPolygonF &points, QList< QPolygonF > *rings, QgsSymbolV2RenderContext &context)
virtual void prepareExpressions(const QgsFields *fields, double scale=-1.0)
virtual QColor dxfBrushColor(const QgsSymbolV2RenderContext &context) const
virtual QColor dxfColor(const QgsSymbolV2RenderContext &context) const
virtual bool writeDxf(QgsDxfExport &e, double mmMapUnitScaleFactor, const QString &layerName, const QgsSymbolV2RenderContext *context, const QgsFeature *f, const QPointF &shift=QPointF(0.0, 0.0)) const
virtual void toSld(QDomDocument &doc, QDomElement &element, QgsStringMap props) const override
double ANALYSIS_EXPORT angle(Point3D *p1, Point3D *p2, Point3D *p3, Point3D *p4)
Calculates the angle between two segments (in 2 dimension, z-values are ignored)
virtual void renderPolyline(const QPolygonF &points, QgsSymbolV2RenderContext &context)=0
double symbologyScaleDenominator() const
Definition: qgsdxfexport.h:51
void drawPreviewIcon(QgsSymbolV2RenderContext &context, QSize size) override
QgsFillSymbolLayerV2(bool locked=false)
void startRender(QgsSymbolV2RenderContext &context) override
static void createGeometryElement(QDomDocument &doc, QDomElement &element, QString geomFunc)
QgsMapUnitScale mapUnitScale() const override
virtual Qt::BrushStyle dxfBrushStyle() const
void setMapUnitScale(const QgsMapUnitScale &scale) override
static double lineWidthScaleFactor(const QgsRenderContext &c, QgsSymbolV2::OutputUnit u, const QgsMapUnitScale &scale=QgsMapUnitScale())
Returns the line width scale factor depending on the unit and the paint device.
QgsLineSymbolLayerV2(bool locked=false)
QgsMapUnitScale mapUnitScale() const override
virtual const QgsExpression * dataDefinedProperty(const QString &property) const
QgsRenderContext & renderContext()
Definition: qgssymbolv2.h:191
void drawPreviewIcon(QgsSymbolV2RenderContext &context, QSize size) override
SimplifyHints simplifyHints() const
Gets the simplification hints of the vector layer managed.
QgsSymbolV2::OutputUnit mOffsetUnit
VerticalAnchorPoint mVerticalAnchorPoint
QgsSymbolV2::OutputUnit mSizeUnit
QgsMapUnitScale mOffsetMapUnitScale
void markerOffset(const QgsSymbolV2RenderContext &context, double &offsetX, double &offsetY) const
void drawPreviewIcon(QgsSymbolV2RenderContext &context, QSize size) override
void _renderPolygon(QPainter *p, const QPolygonF &points, const QList< QPolygonF > *rings, QgsSymbolV2RenderContext &context)
Default method to render polygon.
static bool isGeneralizableByDeviceBoundingBox(const QgsRectangle &envelope, float mapToPixelTol=1.0f)
Returns whether the device-envelope can be replaced by its BBOX when is applied the specified toleran...
double size
Definition: qgssvgcache.cpp:77
void saveDataDefinedProperties(QgsStringMap &stringMap) const
Saves data defined properties to string map.
virtual void stopRender(QgsSymbolV2RenderContext &context)=0
void setOutputUnit(QgsSymbolV2::OutputUnit unit) override
QgsSymbolV2::OutputUnit widthUnit() const
void copyDataDefinedProperties(QgsSymbolLayerV2 *destLayer) const
Copies data defined properties of this layer to another symbol layer.
virtual void setDataDefinedProperty(const QString &property, const QString &expressionString)
static QPointF _rotatedOffset(const QPointF &offset, double angle)