QGIS API Documentation  2.4.0-Chugiak
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups 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 
81 bool QgsSymbolLayerV2::writeDxf( QgsDxfExport& e,
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 
121 void QgsSymbolLayerV2::prepareExpressions( const QgsFields* fields, double scale )
122 {
123  if ( !fields )
124  {
125  return;
126  }
127 
128  QMap< QString, QgsExpression* >::iterator it = mDataDefinedProperties.begin();
129  for ( ; it != mDataDefinedProperties.end(); ++it )
130  {
131  if ( it.value() )
132  {
133  it.value()->prepare( *fields );
134  if ( scale > 0 )
135  {
136  it.value()->setScale( scale );
137  }
138  }
139  }
140 }
141 
142 QSet<QString> QgsSymbolLayerV2::usedAttributes() const
143 {
144  QStringList columns;
145 
146  QMap< QString, QgsExpression* >::const_iterator ddIt = mDataDefinedProperties.constBegin();
147  for ( ; ddIt != mDataDefinedProperties.constEnd(); ++ddIt )
148  {
149  if ( ddIt.value() )
150  {
151  columns.append( ddIt.value()->referencedColumns() );
152  }
153  }
154 
155  QSet<QString> attributes;
156  QStringList::const_iterator it = columns.constBegin();
157  for ( ; it != columns.constEnd(); ++it )
158  {
159  attributes.insert( *it );
160  }
161 
162  return attributes;
163 }
164 
166 {
167  QMap< QString, QgsExpression* >::const_iterator ddIt = mDataDefinedProperties.constBegin();
168  for ( ; ddIt != mDataDefinedProperties.constEnd(); ++ddIt )
169  {
170  if ( ddIt.value() )
171  {
172  stringMap.insert( ddIt.key() + "_expression", ddIt.value()->expression() );
173  }
174  }
175 }
176 
178 {
179  if ( !destLayer )
180  return;
181 
182  destLayer->removeDataDefinedProperties();
183 
184  QMap< QString, QgsExpression* >::const_iterator ddIt = mDataDefinedProperties.constBegin();
185  for ( ; ddIt != mDataDefinedProperties.constEnd(); ++ddIt )
186  {
187  if ( ddIt.value() )
188  {
189  destLayer->setDataDefinedProperty( ddIt.key(), ddIt.value()->expression() );
190  }
191  }
192 }
193 
194 
196  : QgsSymbolLayerV2( QgsSymbolV2::Marker, locked ), mSizeUnit( QgsSymbolV2::MM ), mOffsetUnit( QgsSymbolV2::MM ),
197  mHorizontalAnchorPoint( HCenter ), mVerticalAnchorPoint( VCenter )
198 {
199  mOffsetExpression = NULL;
202 }
203 
205  : QgsSymbolLayerV2( QgsSymbolV2::Line, locked ), mWidthUnit( QgsSymbolV2::MM )
206 {
207 }
208 
210  : QgsSymbolLayerV2( QgsSymbolV2::Fill, locked ), mAngle( 0.0 )
211 {
212 }
213 
215 {
216  Q_UNUSED( context );
217  mOffsetExpression = expression( "offset" );
218  mHorizontalAnchorExpression = expression( "horizontal_anchor_point" );
219  mVerticalAnchorExpression = expression( "vertical_anchor_point" );
220 }
221 
223 {
224  startRender( context );
225  renderPoint( QPointF( size.width() / 2, size.height() / 2 ), context );
226  stopRender( context );
227 }
228 
229 void QgsMarkerSymbolLayerV2::markerOffset( const QgsSymbolV2RenderContext& context, double& offsetX, double& offsetY ) const
230 {
232 }
233 
234 void QgsMarkerSymbolLayerV2::markerOffset( const QgsSymbolV2RenderContext& context, double width, double height, double& offsetX, double& offsetY ) const
235 {
236  markerOffset( context, width, height, mSizeUnit, mSizeUnit, offsetX, offsetY, mSizeMapUnitScale, mSizeMapUnitScale );
237 }
238 
239 void QgsMarkerSymbolLayerV2::markerOffset( const QgsSymbolV2RenderContext& context, double width, double height,
240  QgsSymbolV2::OutputUnit widthUnit, QgsSymbolV2::OutputUnit heightUnit,
241  double& offsetX, double& offsetY, const QgsMapUnitScale& widthMapUnitScale, const QgsMapUnitScale& heightMapUnitScale ) const
242 {
243  offsetX = mOffset.x();
244  offsetY = mOffset.y();
245 
246  if ( mOffsetExpression )
247  {
248  QPointF offset = QgsSymbolLayerV2Utils::decodePoint( mOffsetExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString() );
249  offsetX = offset.x();
250  offsetY = offset.y();
251  }
252 
255 
259  {
260  horizontalAnchorPoint = decodeHorizontalAnchorPoint( mHorizontalAnchorExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString() );
261  }
263  {
264  verticalAnchorPoint = decodeVerticalAnchorPoint( mVerticalAnchorExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString() );
265  }
266 
267  //correct horizontal position according to anchor point
268  if ( horizontalAnchorPoint == HCenter && verticalAnchorPoint == VCenter )
269  {
270  return;
271  }
272 
273  double anchorPointCorrectionX = width * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), widthUnit, widthMapUnitScale ) / 2.0;
274  double anchorPointCorrectionY = height * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), heightUnit, heightMapUnitScale ) / 2.0;
275  if ( horizontalAnchorPoint == Left )
276  {
277  offsetX += anchorPointCorrectionX;
278  }
279  else if ( horizontalAnchorPoint == Right )
280  {
281  offsetX -= anchorPointCorrectionX;
282  }
283 
284  //correct vertical position according to anchor point
285  if ( verticalAnchorPoint == Top )
286  {
287  offsetY += anchorPointCorrectionY;
288  }
289  else if ( verticalAnchorPoint == Bottom )
290  {
291  offsetY -= anchorPointCorrectionY;
292  }
293 }
294 
295 QPointF QgsMarkerSymbolLayerV2::_rotatedOffset( const QPointF& offset, double angle )
296 {
297  angle = DEG2RAD( angle );
298  double c = cos( angle ), s = sin( angle );
299  return QPointF( offset.x() * c - offset.y() * s, offset.x() * s + offset.y() * c );
300 }
301 
303 {
304  if ( str.compare( "left", Qt::CaseInsensitive ) == 0 )
305  {
307  }
308  else if ( str.compare( "right", Qt::CaseInsensitive ) == 0 )
309  {
311  }
312  else
313  {
315  }
316 }
317 
319 {
320  if ( str.compare( "top", Qt::CaseInsensitive ) == 0 )
321  {
323  }
324  else if ( str.compare( "bottom", Qt::CaseInsensitive ) == 0 )
325  {
327  }
328  else
329  {
331  }
332 }
333 
335 {
336  mSizeUnit = unit;
337  mOffsetUnit = unit;
338 }
339 
341 {
342  if ( mOffsetUnit != mSizeUnit )
343  {
344  return QgsSymbolV2::Mixed;
345  }
346  return mOffsetUnit;
347 }
348 
350 {
351  mSizeMapUnitScale = scale;
352  mOffsetMapUnitScale = scale;
353 }
354 
356 {
358  {
359  return mSizeMapUnitScale;
360  }
361  return QgsMapUnitScale();
362 }
363 
365 {
366  mWidthUnit = unit;
367 }
368 
370 {
371  return mWidthUnit;
372 }
373 
375 {
376  mWidthMapUnitScale = scale;
377 }
378 
380 {
381  return mWidthMapUnitScale;
382 }
383 
384 
386 {
387  QPolygonF points;
388  // we're adding 0.5 to get rid of blurred preview:
389  // drawing antialiased lines of width 1 at (x,0)-(x,100) creates 2px line
390  points << QPointF( 0, size.height() / 2 + 0.5 ) << QPointF( size.width(), size.height() / 2 + 0.5 );
391 
392  startRender( context );
393  renderPolyline( points, context );
394  stopRender( context );
395 }
396 
397 void QgsLineSymbolLayerV2::renderPolygonOutline( const QPolygonF& points, QList<QPolygonF>* rings, QgsSymbolV2RenderContext& context )
398 {
399  renderPolyline( points, context );
400  if ( rings )
401  {
402  foreach ( const QPolygonF& ring, *rings )
403  renderPolyline( ring, context );
404  }
405 }
406 
407 double QgsLineSymbolLayerV2::dxfWidth( const QgsDxfExport& e, const QgsSymbolV2RenderContext& context ) const
408 {
409  Q_UNUSED( context );
410  return ( width() * e.mapUnitScaleFactor( e.symbologyScaleDenominator(), widthUnit(), e.mapUnits() ) );
411 }
412 
413 
415 {
416  QPolygonF poly = QRectF( QPointF( 0, 0 ), QPointF( size.width(), size.height() ) );
417  startRender( context );
418  renderPolygon( poly, NULL, context );
419  stopRender( context );
420 }
421 
422 void QgsFillSymbolLayerV2::_renderPolygon( QPainter* p, const QPolygonF& points, const QList<QPolygonF>* rings, QgsSymbolV2RenderContext& context )
423 {
424  if ( !p )
425  {
426  return;
427  }
428 
429  // Disable 'Antialiasing' if the geometry was generalized in the current RenderContext (We known that it must have least #5 points).
430  if ( points.size() <= 5 && ( context.renderContext().vectorSimplifyMethod().simplifyHints() & QgsVectorSimplifyMethod::AntialiasingSimplification ) && QgsAbstractGeometrySimplifier::canbeGeneralizedByDeviceBoundingBox( points, context.renderContext().vectorSimplifyMethod().threshold() ) && ( p->renderHints() & QPainter::Antialiasing ) )
431  {
432  p->setRenderHint( QPainter::Antialiasing, false );
433  p->drawRect( points.boundingRect() );
434  p->setRenderHint( QPainter::Antialiasing, true );
435  return;
436  }
437 
438  if ( rings == NULL )
439  {
440  // simple polygon without holes
441  p->drawPolygon( points );
442  }
443  else
444  {
445  // polygon with holes must be drawn using painter path
446  QPainterPath path;
447  QPolygonF outerRing = points;
448  path.addPolygon( outerRing );
449 
450  QList<QPolygonF>::const_iterator it = rings->constBegin();
451  for ( ; it != rings->constEnd(); ++it )
452  {
453  QPolygonF ring = *it;
454  path.addPolygon( ring );
455  }
456 
457  p->drawPath( path );
458  }
459 }
460 
461 void QgsMarkerSymbolLayerV2::toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
462 {
463  QDomElement symbolizerElem = doc.createElement( "se:PointSymbolizer" );
464  if ( !props.value( "uom", "" ).isEmpty() )
465  symbolizerElem.setAttribute( "uom", props.value( "uom", "" ) );
466  element.appendChild( symbolizerElem );
467 
468  // <Geometry>
469  QgsSymbolLayerV2Utils::createGeometryElement( doc, symbolizerElem, props.value( "geom", "" ) );
470 
471  writeSldMarker( doc, symbolizerElem, props );
472 }
473 
474 
virtual QSet< QString > usedAttributes() const
void drawPreviewIcon(QgsSymbolV2RenderContext &context, QSize size)
Class for parsing and evaluation of expressions (formerly called "search strings").
Definition: qgsexpression.h:89
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)
QgsExpression * mVerticalAnchorExpression
#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:161
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
QgsExpression * mOffsetExpression
void setOutputUnit(QgsSymbolV2::OutputUnit unit)
virtual void removeDataDefinedProperty(const QString &property)
QMap< QString, QString > QgsStringMap
Definition: qgis.h:416
static QgsMarkerSymbolLayerV2::HorizontalAnchorPoint decodeHorizontalAnchorPoint(const QString &str)
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:193
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)
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
void drawPreviewIcon(QgsSymbolV2RenderContext &context, QSize size)
QgsFillSymbolLayerV2(bool locked=false)
static void createGeometryElement(QDomDocument &doc, QDomElement &element, QString geomFunc)
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)
QgsExpression * mHorizontalAnchorExpression
virtual const QgsExpression * dataDefinedProperty(const QString &property) const
static QgsMarkerSymbolLayerV2::VerticalAnchorPoint decodeVerticalAnchorPoint(const QString &str)
QgsRenderContext & renderContext()
Definition: qgssymbolv2.h:168
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.
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
static bool canbeGeneralizedByDeviceBoundingBox(const QgsRectangle &envelope, float mapToPixelTol=1.0f)
Returns whether the device-envelope can be replaced by its BBOX when is applied the specified toleran...
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)