QGIS API Documentation  2.9.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 #include "qgspainteffect.h"
24 #include "qgseffectstack.h"
25 
26 #include <QSize>
27 #include <QPainter>
28 #include <QPointF>
29 #include <QPolygonF>
30 
31 const QgsExpression* QgsSymbolLayerV2::dataDefinedProperty( const QString& property ) const
32 {
33  QMap< QString, QgsExpression* >::const_iterator it = mDataDefinedProperties.find( property );
34  if ( it != mDataDefinedProperties.constEnd() )
35  {
36  return it.value();
37  }
38  return 0;
39 }
40 
41 QgsExpression* QgsSymbolLayerV2::expression( const QString& property ) const
42 {
43  QMap< QString, QgsExpression* >::const_iterator it = mDataDefinedProperties.find( property );
44  if ( it != mDataDefinedProperties.constEnd() )
45  {
46  return it.value();
47  }
48  return 0;
49 }
50 
51 QString QgsSymbolLayerV2::dataDefinedPropertyString( const QString& property ) const
52 {
53  const QgsExpression* ex = dataDefinedProperty( property );
54  return ex ? ex->expression() : QString();
55 }
56 
57 void QgsSymbolLayerV2::setDataDefinedProperty( const QString& property, const QString& expressionString )
58 {
59  removeDataDefinedProperty( property );
60  mDataDefinedProperties.insert( property, new QgsExpression( expressionString ) );
61 }
62 
63 void QgsSymbolLayerV2::removeDataDefinedProperty( const QString& property )
64 {
65  QMap< QString, QgsExpression* >::iterator it = mDataDefinedProperties.find( property );
66  if ( it != mDataDefinedProperties.end() )
67  {
68  delete( it.value() );
69  mDataDefinedProperties.erase( it );
70  }
71 }
72 
74 {
75  QMap< QString, QgsExpression* >::iterator it = mDataDefinedProperties.begin();
76  for ( ; it != mDataDefinedProperties.constEnd(); ++it )
77  {
78  delete( it.value() );
79  }
80  mDataDefinedProperties.clear();
81 }
82 
84  double mmMapUnitScaleFactor,
85  const QString& layerName,
86  const QgsSymbolV2RenderContext* context,
87  const QgsFeature* f,
88  const QPointF& shift ) const
89 {
90  Q_UNUSED( e );
91  Q_UNUSED( mmMapUnitScaleFactor );
92  Q_UNUSED( layerName );
93  Q_UNUSED( context );
94  Q_UNUSED( f );
95  Q_UNUSED( shift );
96  return false;
97 }
98 
99 double QgsSymbolLayerV2::dxfWidth( const QgsDxfExport& e, const QgsSymbolV2RenderContext& context ) const
100 {
101  Q_UNUSED( e );
102  Q_UNUSED( context );
103  return 1.0;
104 }
105 
106 double QgsSymbolLayerV2::dxfOffset( const QgsDxfExport& e, const QgsSymbolV2RenderContext& context ) const
107 {
108  Q_UNUSED( e );
109  Q_UNUSED( context );
110  return 0.0;
111 }
112 
114 {
115  Q_UNUSED( context );
116  return color();
117 }
118 
120 {
121  Q_UNUSED( unit );
122  return QVector<qreal>();
123 }
124 
125 Qt::PenStyle QgsSymbolLayerV2::dxfPenStyle() const
126 {
127  return Qt::SolidLine;
128 }
129 
131 {
132  Q_UNUSED( context );
133  return color();
134 }
135 
136 Qt::BrushStyle QgsSymbolLayerV2::dxfBrushStyle() const
137 {
138  return Qt::NoBrush;
139 }
140 
142 {
143  return mPaintEffect;
144 }
145 
147 {
148  delete mPaintEffect;
149  mPaintEffect = effect;
150 }
151 
153  : mType( type )
154  , mLocked( locked )
155  , mRenderingPass( 0 )
156  , mPaintEffect( 0 )
157 {
158  QgsEffectStack* stack = new QgsEffectStack();
159  stack->appendEffect( new QgsDrawSourceEffect() );
160  mPaintEffect = stack;
161  mPaintEffect->setEnabled( false );
162 }
163 
164 void QgsSymbolLayerV2::prepareExpressions( const QgsFields* fields, double scale )
165 {
166  if ( !fields )
167  {
168  return;
169  }
170 
171  QMap< QString, QgsExpression* >::iterator it = mDataDefinedProperties.begin();
172  for ( ; it != mDataDefinedProperties.end(); ++it )
173  {
174  if ( it.value() )
175  {
176  it.value()->prepare( *fields );
177  if ( scale > 0 )
178  {
179  it.value()->setScale( scale );
180  }
181  }
182  }
183 }
184 
186 {
188  delete mPaintEffect;
189 }
190 
191 QSet<QString> QgsSymbolLayerV2::usedAttributes() const
192 {
193  QStringList columns;
194 
195  QMap< QString, QgsExpression* >::const_iterator ddIt = mDataDefinedProperties.constBegin();
196  for ( ; ddIt != mDataDefinedProperties.constEnd(); ++ddIt )
197  {
198  if ( ddIt.value() )
199  {
200  columns.append( ddIt.value()->referencedColumns() );
201  }
202  }
203 
204  QSet<QString> attributes;
205  QStringList::const_iterator it = columns.constBegin();
206  for ( ; it != columns.constEnd(); ++it )
207  {
208  attributes.insert( *it );
209  }
210 
211  return attributes;
212 }
213 
215 {
216  QMap< QString, QgsExpression* >::const_iterator ddIt = mDataDefinedProperties.constBegin();
217  for ( ; ddIt != mDataDefinedProperties.constEnd(); ++ddIt )
218  {
219  if ( ddIt.value() )
220  {
221  stringMap.insert( ddIt.key() + "_expression", ddIt.value()->expression() );
222  }
223  }
224 }
225 
227 {
228  if ( !destLayer )
229  return;
230 
231  destLayer->removeDataDefinedProperties();
232 
233  QMap< QString, QgsExpression* >::const_iterator ddIt = mDataDefinedProperties.constBegin();
234  for ( ; ddIt != mDataDefinedProperties.constEnd(); ++ddIt )
235  {
236  if ( ddIt.value() )
237  {
238  destLayer->setDataDefinedProperty( ddIt.key(), ddIt.value()->expression() );
239  }
240  }
241 }
242 
244 {
245  if ( !destLayer || !mPaintEffect )
246  return;
247 
248  destLayer->setPaintEffect( mPaintEffect->clone() );
249 }
250 
252  : QgsSymbolLayerV2( QgsSymbolV2::Marker, locked )
253  , mAngle( 0 )
254  , mSize( 2.0 )
255  , mSizeUnit( QgsSymbolV2::MM )
256  , mOffsetUnit( QgsSymbolV2::MM )
257  , mScaleMethod( QgsSymbolV2::ScaleArea )
258  , mHorizontalAnchorPoint( HCenter )
259  , mVerticalAnchorPoint( VCenter )
260 {
261  mOffsetExpression = NULL;
262  mHorizontalAnchorExpression = NULL;
263  mVerticalAnchorExpression = NULL;
264 }
265 
267  : QgsSymbolLayerV2( QgsSymbolV2::Line, locked )
268  , mWidth( 0 )
269  , mWidthUnit( QgsSymbolV2::MM )
270  , mOffset( 0 )
271  , mOffsetUnit( QgsSymbolV2::MM )
272 {
273 }
274 
276  : QgsSymbolLayerV2( QgsSymbolV2::Fill, locked )
277  , mAngle( 0.0 )
278 {
279 }
280 
282 {
283  Q_UNUSED( context );
284  mOffsetExpression = expression( "offset" );
285  mHorizontalAnchorExpression = expression( "horizontal_anchor_point" );
286  mVerticalAnchorExpression = expression( "vertical_anchor_point" );
287 }
288 
290 {
291  startRender( context );
292  renderPoint( QPointF( size.width() / 2, size.height() / 2 ), context );
293  stopRender( context );
294 }
295 
296 void QgsMarkerSymbolLayerV2::markerOffset( const QgsSymbolV2RenderContext& context, double& offsetX, double& offsetY ) const
297 {
299 }
300 
301 void QgsMarkerSymbolLayerV2::markerOffset( const QgsSymbolV2RenderContext& context, double width, double height, double& offsetX, double& offsetY ) const
302 {
303  markerOffset( context, width, height, mSizeUnit, mSizeUnit, offsetX, offsetY, mSizeMapUnitScale, mSizeMapUnitScale );
304 }
305 
306 void QgsMarkerSymbolLayerV2::markerOffset( const QgsSymbolV2RenderContext& context, double width, double height,
307  QgsSymbolV2::OutputUnit widthUnit, QgsSymbolV2::OutputUnit heightUnit,
308  double& offsetX, double& offsetY, const QgsMapUnitScale& widthMapUnitScale, const QgsMapUnitScale& heightMapUnitScale ) const
309 {
310  offsetX = mOffset.x();
311  offsetY = mOffset.y();
312 
313  if ( mOffsetExpression )
314  {
315  QPointF offset = QgsSymbolLayerV2Utils::decodePoint( mOffsetExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString() );
316  offsetX = offset.x();
317  offsetY = offset.y();
318  }
319 
322 
325  if ( mHorizontalAnchorExpression )
326  {
327  horizontalAnchorPoint = decodeHorizontalAnchorPoint( mHorizontalAnchorExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString() );
328  }
329  if ( mVerticalAnchorExpression )
330  {
331  verticalAnchorPoint = decodeVerticalAnchorPoint( mVerticalAnchorExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString() );
332  }
333 
334  //correct horizontal position according to anchor point
335  if ( horizontalAnchorPoint == HCenter && verticalAnchorPoint == VCenter )
336  {
337  return;
338  }
339 
340  double anchorPointCorrectionX = width * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), widthUnit, widthMapUnitScale ) / 2.0;
341  double anchorPointCorrectionY = height * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), heightUnit, heightMapUnitScale ) / 2.0;
342  if ( horizontalAnchorPoint == Left )
343  {
344  offsetX += anchorPointCorrectionX;
345  }
346  else if ( horizontalAnchorPoint == Right )
347  {
348  offsetX -= anchorPointCorrectionX;
349  }
350 
351  //correct vertical position according to anchor point
352  if ( verticalAnchorPoint == Top )
353  {
354  offsetY += anchorPointCorrectionY;
355  }
356  else if ( verticalAnchorPoint == Bottom )
357  {
358  offsetY -= anchorPointCorrectionY;
359  }
360 }
361 
362 QPointF QgsMarkerSymbolLayerV2::_rotatedOffset( const QPointF& offset, double angle )
363 {
364  angle = DEG2RAD( angle );
365  double c = cos( angle ), s = sin( angle );
366  return QPointF( offset.x() * c - offset.y() * s, offset.x() * s + offset.y() * c );
367 }
368 
369 QgsMarkerSymbolLayerV2::HorizontalAnchorPoint QgsMarkerSymbolLayerV2::decodeHorizontalAnchorPoint( const QString& str )
370 {
371  if ( str.compare( "left", Qt::CaseInsensitive ) == 0 )
372  {
374  }
375  else if ( str.compare( "right", Qt::CaseInsensitive ) == 0 )
376  {
378  }
379  else
380  {
382  }
383 }
384 
385 QgsMarkerSymbolLayerV2::VerticalAnchorPoint QgsMarkerSymbolLayerV2::decodeVerticalAnchorPoint( const QString& str )
386 {
387  if ( str.compare( "top", Qt::CaseInsensitive ) == 0 )
388  {
390  }
391  else if ( str.compare( "bottom", Qt::CaseInsensitive ) == 0 )
392  {
394  }
395  else
396  {
398  }
399 }
400 
402 {
403  mSizeUnit = unit;
404  mOffsetUnit = unit;
405 }
406 
408 {
409  if ( mOffsetUnit != mSizeUnit )
410  {
411  return QgsSymbolV2::Mixed;
412  }
413  return mOffsetUnit;
414 }
415 
417 {
418  mSizeMapUnitScale = scale;
419  mOffsetMapUnitScale = scale;
420 }
421 
423 {
425  {
426  return mSizeMapUnitScale;
427  }
428  return QgsMapUnitScale();
429 }
430 
432 {
433  mWidthUnit = unit;
434 }
435 
437 {
438  return mWidthUnit;
439 }
440 
442 {
443  mWidthMapUnitScale = scale;
444 }
445 
447 {
448  return mWidthMapUnitScale;
449 }
450 
451 
453 {
454  QPolygonF points;
455  // we're adding 0.5 to get rid of blurred preview:
456  // drawing antialiased lines of width 1 at (x,0)-(x,100) creates 2px line
457  points << QPointF( 0, int( size.height() / 2 ) + 0.5 ) << QPointF( size.width(), int( size.height() / 2 ) + 0.5 );
458 
459  startRender( context );
460  renderPolyline( points, context );
461  stopRender( context );
462 }
463 
464 void QgsLineSymbolLayerV2::renderPolygonOutline( const QPolygonF& points, QList<QPolygonF>* rings, QgsSymbolV2RenderContext& context )
465 {
466  renderPolyline( points, context );
467  if ( rings )
468  {
469  foreach ( const QPolygonF& ring, *rings )
470  renderPolyline( ring, context );
471  }
472 }
473 
475 {
476  Q_UNUSED( context );
478 }
479 
480 
482 {
483  QPolygonF poly = QRectF( QPointF( 0, 0 ), QPointF( size.width(), size.height() ) );
484  startRender( context );
485  renderPolygon( poly, NULL, context );
486  stopRender( context );
487 }
488 
489 void QgsFillSymbolLayerV2::_renderPolygon( QPainter* p, const QPolygonF& points, const QList<QPolygonF>* rings, QgsSymbolV2RenderContext& context )
490 {
491  if ( !p )
492  {
493  return;
494  }
495 
496  // Disable 'Antialiasing' if the geometry was generalized in the current RenderContext (We known that it must have least #5 points).
497  if ( points.size() <= 5 &&
500  ( p->renderHints() & QPainter::Antialiasing ) )
501  {
502  p->setRenderHint( QPainter::Antialiasing, false );
503  p->drawRect( points.boundingRect() );
504  p->setRenderHint( QPainter::Antialiasing, true );
505  return;
506  }
507 
508  if ( rings == NULL )
509  {
510  // simple polygon without holes
511  p->drawPolygon( points );
512  }
513  else
514  {
515  // polygon with holes must be drawn using painter path
516  QPainterPath path;
517  QPolygonF outerRing = points;
518  path.addPolygon( outerRing );
519 
520  QList<QPolygonF>::const_iterator it = rings->constBegin();
521  for ( ; it != rings->constEnd(); ++it )
522  {
523  QPolygonF ring = *it;
524  path.addPolygon( ring );
525  }
526 
527  p->drawPath( path );
528  }
529 }
530 
531 void QgsMarkerSymbolLayerV2::toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
532 {
533  QDomElement symbolizerElem = doc.createElement( "se:PointSymbolizer" );
534  if ( !props.value( "uom", "" ).isEmpty() )
535  symbolizerElem.setAttribute( "uom", props.value( "uom", "" ) );
536  element.appendChild( symbolizerElem );
537 
538  // <Geometry>
539  QgsSymbolLayerV2Utils::createGeometryElement( doc, symbolizerElem, props.value( "geom", "" ) );
540 
541  writeSldMarker( doc, symbolizerElem, props );
542 }
543 
544 
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:86
VerticalAnchorPoint verticalAnchorPoint() const
virtual void removeDataDefinedProperties()
QgsSymbolV2::OutputUnit outputUnit() const override
QMap< QString, QgsExpression * > mDataDefinedProperties
void setEnabled(const bool enabled)
Sets whether the effect is enabled.
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)
Base class for visual effects which can be applied to QPicture drawings.
QgsSymbolV2::OutputUnit outputUnit() const override
QgsPaintEffect * mPaintEffect
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
void copyPaintEffect(QgsSymbolLayerV2 *destLayer) const
Copies paint effect of this layer to another symbol layer.
QgsSymbolLayerV2(QgsSymbolV2::SymbolType type, bool locked=false)
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:438
void setMapUnitScale(const QgsMapUnitScale &scale) override
virtual QgsPaintEffect * clone() const =0
Duplicates an effect by creating a deep copy of the effect.
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:241
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
A paint effect which consists of a stack of other chained paint effects.
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
void appendEffect(QgsPaintEffect *effect)
Appends an effect to the end of the stack.
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:219
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
A paint effect which draws the source picture with minor or no alterations.
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 setPaintEffect(QgsPaintEffect *effect)
Sets the current paint effect for the layer.
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.
QgsPaintEffect * paintEffect() const
Returns the current paint effect for the layer.
virtual void setDataDefinedProperty(const QString &property, const QString &expressionString)
static QPointF _rotatedOffset(const QPointF &offset, double angle)