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 
105 {
106  Q_UNUSED( context );
107  return color();
108 }
109 
111 {
112  Q_UNUSED( unit );
113  return QVector<qreal>();
114 }
115 
116 Qt::PenStyle QgsSymbolLayerV2::dxfPenStyle() const
117 {
118  return Qt::SolidLine;
119 }
120 
122 {
123  Q_UNUSED( context );
124  return color();
125 }
126 
127 Qt::BrushStyle QgsSymbolLayerV2::dxfBrushStyle() const
128 {
129  return Qt::NoBrush;
130 }
131 
132 void QgsSymbolLayerV2::prepareExpressions( const QgsFields* fields, double scale )
133 {
134  if ( !fields )
135  {
136  return;
137  }
138 
139  QMap< QString, QgsExpression* >::iterator it = mDataDefinedProperties.begin();
140  for ( ; it != mDataDefinedProperties.end(); ++it )
141  {
142  if ( it.value() )
143  {
144  it.value()->prepare( *fields );
145  if ( scale > 0 )
146  {
147  it.value()->setScale( scale );
148  }
149  }
150  }
151 }
152 
153 QSet<QString> QgsSymbolLayerV2::usedAttributes() const
154 {
155  QStringList columns;
156 
157  QMap< QString, QgsExpression* >::const_iterator ddIt = mDataDefinedProperties.constBegin();
158  for ( ; ddIt != mDataDefinedProperties.constEnd(); ++ddIt )
159  {
160  if ( ddIt.value() )
161  {
162  columns.append( ddIt.value()->referencedColumns() );
163  }
164  }
165 
166  QSet<QString> attributes;
167  QStringList::const_iterator it = columns.constBegin();
168  for ( ; it != columns.constEnd(); ++it )
169  {
170  attributes.insert( *it );
171  }
172 
173  return attributes;
174 }
175 
177 {
178  QMap< QString, QgsExpression* >::const_iterator ddIt = mDataDefinedProperties.constBegin();
179  for ( ; ddIt != mDataDefinedProperties.constEnd(); ++ddIt )
180  {
181  if ( ddIt.value() )
182  {
183  stringMap.insert( ddIt.key() + "_expression", ddIt.value()->expression() );
184  }
185  }
186 }
187 
189 {
190  if ( !destLayer )
191  return;
192 
193  destLayer->removeDataDefinedProperties();
194 
195  QMap< QString, QgsExpression* >::const_iterator ddIt = mDataDefinedProperties.constBegin();
196  for ( ; ddIt != mDataDefinedProperties.constEnd(); ++ddIt )
197  {
198  if ( ddIt.value() )
199  {
200  destLayer->setDataDefinedProperty( ddIt.key(), ddIt.value()->expression() );
201  }
202  }
203 }
204 
205 
207  : QgsSymbolLayerV2( QgsSymbolV2::Marker, locked )
208  , mSizeUnit( QgsSymbolV2::MM )
209  , mOffsetUnit( QgsSymbolV2::MM )
210  , mHorizontalAnchorPoint( HCenter )
211  , mVerticalAnchorPoint( VCenter )
212 {
213  mOffsetExpression = NULL;
214  mHorizontalAnchorExpression = NULL;
215  mVerticalAnchorExpression = NULL;
216 }
217 
219  : QgsSymbolLayerV2( QgsSymbolV2::Line, locked )
220  , mWidthUnit( QgsSymbolV2::MM )
221 {
222 }
223 
225  : QgsSymbolLayerV2( QgsSymbolV2::Fill, locked )
226  , mAngle( 0.0 )
227 {
228 }
229 
231 {
232  Q_UNUSED( context );
233  mOffsetExpression = expression( "offset" );
234  mHorizontalAnchorExpression = expression( "horizontal_anchor_point" );
235  mVerticalAnchorExpression = expression( "vertical_anchor_point" );
236 }
237 
239 {
240  startRender( context );
241  renderPoint( QPointF( size.width() / 2, size.height() / 2 ), context );
242  stopRender( context );
243 }
244 
245 void QgsMarkerSymbolLayerV2::markerOffset( const QgsSymbolV2RenderContext& context, double& offsetX, double& offsetY ) const
246 {
248 }
249 
250 void QgsMarkerSymbolLayerV2::markerOffset( const QgsSymbolV2RenderContext& context, double width, double height, double& offsetX, double& offsetY ) const
251 {
252  markerOffset( context, width, height, mSizeUnit, mSizeUnit, offsetX, offsetY, mSizeMapUnitScale, mSizeMapUnitScale );
253 }
254 
255 void QgsMarkerSymbolLayerV2::markerOffset( const QgsSymbolV2RenderContext& context, double width, double height,
256  QgsSymbolV2::OutputUnit widthUnit, QgsSymbolV2::OutputUnit heightUnit,
257  double& offsetX, double& offsetY, const QgsMapUnitScale& widthMapUnitScale, const QgsMapUnitScale& heightMapUnitScale ) const
258 {
259  offsetX = mOffset.x();
260  offsetY = mOffset.y();
261 
262  if ( mOffsetExpression )
263  {
264  QPointF offset = QgsSymbolLayerV2Utils::decodePoint( mOffsetExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString() );
265  offsetX = offset.x();
266  offsetY = offset.y();
267  }
268 
271 
274  if ( mHorizontalAnchorExpression )
275  {
276  horizontalAnchorPoint = decodeHorizontalAnchorPoint( mHorizontalAnchorExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString() );
277  }
278  if ( mVerticalAnchorExpression )
279  {
280  verticalAnchorPoint = decodeVerticalAnchorPoint( mVerticalAnchorExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString() );
281  }
282 
283  //correct horizontal position according to anchor point
284  if ( horizontalAnchorPoint == HCenter && verticalAnchorPoint == VCenter )
285  {
286  return;
287  }
288 
289  double anchorPointCorrectionX = width * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), widthUnit, widthMapUnitScale ) / 2.0;
290  double anchorPointCorrectionY = height * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), heightUnit, heightMapUnitScale ) / 2.0;
291  if ( horizontalAnchorPoint == Left )
292  {
293  offsetX += anchorPointCorrectionX;
294  }
295  else if ( horizontalAnchorPoint == Right )
296  {
297  offsetX -= anchorPointCorrectionX;
298  }
299 
300  //correct vertical position according to anchor point
301  if ( verticalAnchorPoint == Top )
302  {
303  offsetY += anchorPointCorrectionY;
304  }
305  else if ( verticalAnchorPoint == Bottom )
306  {
307  offsetY -= anchorPointCorrectionY;
308  }
309 }
310 
311 QPointF QgsMarkerSymbolLayerV2::_rotatedOffset( const QPointF& offset, double angle )
312 {
313  angle = DEG2RAD( angle );
314  double c = cos( angle ), s = sin( angle );
315  return QPointF( offset.x() * c - offset.y() * s, offset.x() * s + offset.y() * c );
316 }
317 
318 QgsMarkerSymbolLayerV2::HorizontalAnchorPoint QgsMarkerSymbolLayerV2::decodeHorizontalAnchorPoint( const QString& str )
319 {
320  if ( str.compare( "left", Qt::CaseInsensitive ) == 0 )
321  {
323  }
324  else if ( str.compare( "right", Qt::CaseInsensitive ) == 0 )
325  {
327  }
328  else
329  {
331  }
332 }
333 
334 QgsMarkerSymbolLayerV2::VerticalAnchorPoint QgsMarkerSymbolLayerV2::decodeVerticalAnchorPoint( const QString& str )
335 {
336  if ( str.compare( "top", Qt::CaseInsensitive ) == 0 )
337  {
339  }
340  else if ( str.compare( "bottom", Qt::CaseInsensitive ) == 0 )
341  {
343  }
344  else
345  {
347  }
348 }
349 
351 {
352  mSizeUnit = unit;
353  mOffsetUnit = unit;
354 }
355 
357 {
358  if ( mOffsetUnit != mSizeUnit )
359  {
360  return QgsSymbolV2::Mixed;
361  }
362  return mOffsetUnit;
363 }
364 
366 {
367  mSizeMapUnitScale = scale;
368  mOffsetMapUnitScale = scale;
369 }
370 
372 {
374  {
375  return mSizeMapUnitScale;
376  }
377  return QgsMapUnitScale();
378 }
379 
381 {
382  mWidthUnit = unit;
383 }
384 
386 {
387  return mWidthUnit;
388 }
389 
391 {
392  mWidthMapUnitScale = scale;
393 }
394 
396 {
397  return mWidthMapUnitScale;
398 }
399 
400 
402 {
403  QPolygonF points;
404  // we're adding 0.5 to get rid of blurred preview:
405  // drawing antialiased lines of width 1 at (x,0)-(x,100) creates 2px line
406  points << QPointF( 0, size.height() / 2 + 0.5 ) << QPointF( size.width(), size.height() / 2 + 0.5 );
407 
408  startRender( context );
409  renderPolyline( points, context );
410  stopRender( context );
411 }
412 
413 void QgsLineSymbolLayerV2::renderPolygonOutline( const QPolygonF& points, QList<QPolygonF>* rings, QgsSymbolV2RenderContext& context )
414 {
415  renderPolyline( points, context );
416  if ( rings )
417  {
418  foreach ( const QPolygonF& ring, *rings )
419  renderPolyline( ring, context );
420  }
421 }
422 
424 {
425  Q_UNUSED( context );
426  return ( width() * e.mapUnitScaleFactor( e.symbologyScaleDenominator(), widthUnit(), e.mapUnits() ) );
427 }
428 
429 
431 {
432  QPolygonF poly = QRectF( QPointF( 0, 0 ), QPointF( size.width(), size.height() ) );
433  startRender( context );
434  renderPolygon( poly, NULL, context );
435  stopRender( context );
436 }
437 
438 void QgsFillSymbolLayerV2::_renderPolygon( QPainter* p, const QPolygonF& points, const QList<QPolygonF>* rings, QgsSymbolV2RenderContext& context )
439 {
440  if ( !p )
441  {
442  return;
443  }
444 
445  // Disable 'Antialiasing' if the geometry was generalized in the current RenderContext (We known that it must have least #5 points).
446  if ( points.size() <= 5 &&
449  ( p->renderHints() & QPainter::Antialiasing ) )
450  {
451  p->setRenderHint( QPainter::Antialiasing, false );
452  p->drawRect( points.boundingRect() );
453  p->setRenderHint( QPainter::Antialiasing, true );
454  return;
455  }
456 
457  if ( rings == NULL )
458  {
459  // simple polygon without holes
460  p->drawPolygon( points );
461  }
462  else
463  {
464  // polygon with holes must be drawn using painter path
465  QPainterPath path;
466  QPolygonF outerRing = points;
467  path.addPolygon( outerRing );
468 
469  QList<QPolygonF>::const_iterator it = rings->constBegin();
470  for ( ; it != rings->constEnd(); ++it )
471  {
472  QPolygonF ring = *it;
473  path.addPolygon( ring );
474  }
475 
476  p->drawPath( path );
477  }
478 }
479 
480 void QgsMarkerSymbolLayerV2::toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
481 {
482  QDomElement symbolizerElem = doc.createElement( "se:PointSymbolizer" );
483  if ( !props.value( "uom", "" ).isEmpty() )
484  symbolizerElem.setAttribute( "uom", props.value( "uom", "" ) );
485  element.appendChild( symbolizerElem );
486 
487  // <Geometry>
488  QgsSymbolLayerV2Utils::createGeometryElement( doc, symbolizerElem, props.value( "geom", "" ) );
489 
490  writeSldMarker( doc, symbolizerElem, props );
491 }
492 
493 
virtual QSet< QString > usedAttributes() const
static double mapUnitScaleFactor(double scaleDenominator, QgsSymbolV2::OutputUnit symbolUnits, QGis::UnitType mapUnits)
void drawPreviewIcon(QgsSymbolV2RenderContext &context, QSize size)
Class for parsing and evaluation of expressions (formerly called "search strings").
Definition: qgsexpression.h:87
VerticalAnchorPoint verticalAnchorPoint() const
virtual void removeDataDefinedProperties()
void setOutputUnit(QgsSymbolV2::OutputUnit unit)
QMap< QString, QgsExpression * > mDataDefinedProperties
float threshold() const
Gets the simplification threshold of the vector layer managed.
QgsMapUnitScale mSizeMapUnitScale
virtual Qt::PenStyle dxfPenStyle() const
QgsSymbolV2::OutputUnit outputUnit() const
virtual double dxfWidth(const QgsDxfExport &e, const QgsSymbolV2RenderContext &context) const
virtual double width() const
QgsSymbolV2::OutputUnit outputUnit() const
HorizontalAnchorPoint horizontalAnchorPoint() const
const QString expression() const
Alias for dump()
void setMapUnitScale(const QgsMapUnitScale &scale)
QVariant evaluate(const QgsFeature *f=NULL)
Evaluate the feature and return the result.
const QgsVectorSimplifyMethod & vectorSimplifyMethod() const
Added in QGIS v2.4.
void startRender(QgsSymbolV2RenderContext &context)
QGis::UnitType mapUnits() const
Definition: qgsdxfexport.h:54
#define DEG2RAD(x)
virtual void toSld(QDomDocument &doc, QDomElement &element, QgsStringMap props) const
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
void setOutputUnit(QgsSymbolV2::OutputUnit unit)
virtual void removeDataDefinedProperty(const QString &property)
QMap< QString, QString > QgsStringMap
Definition: qgis.h:412
virtual QString dataDefinedPropertyString(const QString &property) const
virtual void startRender(QgsSymbolV2RenderContext &context)=0
virtual QgsExpression * expression(const QString &property) const
virtual void writeSldMarker(QDomDocument &doc, QDomElement &element, QgsStringMap props) const
const QgsFeature * feature() const
Current feature being rendered - may be null.
Definition: qgssymbolv2.h:192
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
QgsMapUnitScale mapUnitScale() const
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
QgsMapUnitScale mapUnitScale() 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
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)
void drawPreviewIcon(QgsSymbolV2RenderContext &context, QSize size)
virtual void renderPolyline(const QPolygonF &points, QgsSymbolV2RenderContext &context)=0
double symbologyScaleDenominator() const
Definition: qgsdxfexport.h:51
void drawPreviewIcon(QgsSymbolV2RenderContext &context, QSize size)
QgsFillSymbolLayerV2(bool locked=false)
static void createGeometryElement(QDomDocument &doc, QDomElement &element, QString geomFunc)
virtual Qt::BrushStyle dxfBrushStyle() const
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)
virtual const QgsExpression * dataDefinedProperty(const QString &property) const
QgsRenderContext & renderContext()
Definition: qgssymbolv2.h:170
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 _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...
virtual double dxfWidth(const QgsDxfExport &e, const QgsSymbolV2RenderContext &context) const
double size
Definition: qgssvgcache.cpp:77
void saveDataDefinedProperties(QgsStringMap &stringMap) const
Saves data defined properties to string map.
virtual void stopRender(QgsSymbolV2RenderContext &context)=0
QgsSymbolV2::OutputUnit widthUnit() const
void copyDataDefinedProperties(QgsSymbolLayerV2 *destLayer) const
Copies data defined properties of this layer to another symbol layer.
void setMapUnitScale(const QgsMapUnitScale &scale)
virtual void setDataDefinedProperty(const QString &property, const QString &expressionString)
static QPointF _rotatedOffset(const QPointF &offset, double angle)