QGIS API Documentation  2.8.2-Wien
 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 
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  , mAngle( 0 )
216  , mSize( 2.0 )
217  , mSizeUnit( QgsSymbolV2::MM )
218  , mOffsetUnit( QgsSymbolV2::MM )
219  , mScaleMethod( QgsSymbolV2::ScaleArea )
220  , mHorizontalAnchorPoint( HCenter )
221  , mVerticalAnchorPoint( VCenter )
222 {
223  mOffsetExpression = NULL;
224  mHorizontalAnchorExpression = NULL;
225  mVerticalAnchorExpression = NULL;
226 }
227 
229  : QgsSymbolLayerV2( QgsSymbolV2::Line, locked )
230  , mWidth( 0 )
231  , mWidthUnit( QgsSymbolV2::MM )
232  , mOffset( 0 )
233  , mOffsetUnit( QgsSymbolV2::MM )
234 {
235 }
236 
238  : QgsSymbolLayerV2( QgsSymbolV2::Fill, locked )
239  , mAngle( 0.0 )
240 {
241 }
242 
244 {
245  Q_UNUSED( context );
246  mOffsetExpression = expression( "offset" );
247  mHorizontalAnchorExpression = expression( "horizontal_anchor_point" );
248  mVerticalAnchorExpression = expression( "vertical_anchor_point" );
249 }
250 
252 {
253  startRender( context );
254  renderPoint( QPointF( size.width() / 2, size.height() / 2 ), context );
255  stopRender( context );
256 }
257 
258 void QgsMarkerSymbolLayerV2::markerOffset( const QgsSymbolV2RenderContext& context, double& offsetX, double& offsetY ) const
259 {
261 }
262 
263 void QgsMarkerSymbolLayerV2::markerOffset( const QgsSymbolV2RenderContext& context, double width, double height, double& offsetX, double& offsetY ) const
264 {
265  markerOffset( context, width, height, mSizeUnit, mSizeUnit, offsetX, offsetY, mSizeMapUnitScale, mSizeMapUnitScale );
266 }
267 
268 void QgsMarkerSymbolLayerV2::markerOffset( const QgsSymbolV2RenderContext& context, double width, double height,
269  QgsSymbolV2::OutputUnit widthUnit, QgsSymbolV2::OutputUnit heightUnit,
270  double& offsetX, double& offsetY, const QgsMapUnitScale& widthMapUnitScale, const QgsMapUnitScale& heightMapUnitScale ) const
271 {
272  offsetX = mOffset.x();
273  offsetY = mOffset.y();
274 
275  if ( mOffsetExpression )
276  {
277  QPointF offset = QgsSymbolLayerV2Utils::decodePoint( mOffsetExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString() );
278  offsetX = offset.x();
279  offsetY = offset.y();
280  }
281 
284 
287  if ( mHorizontalAnchorExpression )
288  {
289  horizontalAnchorPoint = decodeHorizontalAnchorPoint( mHorizontalAnchorExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString() );
290  }
291  if ( mVerticalAnchorExpression )
292  {
293  verticalAnchorPoint = decodeVerticalAnchorPoint( mVerticalAnchorExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString() );
294  }
295 
296  //correct horizontal position according to anchor point
297  if ( horizontalAnchorPoint == HCenter && verticalAnchorPoint == VCenter )
298  {
299  return;
300  }
301 
302  double anchorPointCorrectionX = width * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), widthUnit, widthMapUnitScale ) / 2.0;
303  double anchorPointCorrectionY = height * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), heightUnit, heightMapUnitScale ) / 2.0;
304  if ( horizontalAnchorPoint == Left )
305  {
306  offsetX += anchorPointCorrectionX;
307  }
308  else if ( horizontalAnchorPoint == Right )
309  {
310  offsetX -= anchorPointCorrectionX;
311  }
312 
313  //correct vertical position according to anchor point
314  if ( verticalAnchorPoint == Top )
315  {
316  offsetY += anchorPointCorrectionY;
317  }
318  else if ( verticalAnchorPoint == Bottom )
319  {
320  offsetY -= anchorPointCorrectionY;
321  }
322 }
323 
324 QPointF QgsMarkerSymbolLayerV2::_rotatedOffset( const QPointF& offset, double angle )
325 {
326  angle = DEG2RAD( angle );
327  double c = cos( angle ), s = sin( angle );
328  return QPointF( offset.x() * c - offset.y() * s, offset.x() * s + offset.y() * c );
329 }
330 
331 QgsMarkerSymbolLayerV2::HorizontalAnchorPoint QgsMarkerSymbolLayerV2::decodeHorizontalAnchorPoint( const QString& str )
332 {
333  if ( str.compare( "left", Qt::CaseInsensitive ) == 0 )
334  {
336  }
337  else if ( str.compare( "right", Qt::CaseInsensitive ) == 0 )
338  {
340  }
341  else
342  {
344  }
345 }
346 
347 QgsMarkerSymbolLayerV2::VerticalAnchorPoint QgsMarkerSymbolLayerV2::decodeVerticalAnchorPoint( const QString& str )
348 {
349  if ( str.compare( "top", Qt::CaseInsensitive ) == 0 )
350  {
352  }
353  else if ( str.compare( "bottom", Qt::CaseInsensitive ) == 0 )
354  {
356  }
357  else
358  {
360  }
361 }
362 
364 {
365  mSizeUnit = unit;
366  mOffsetUnit = unit;
367 }
368 
370 {
371  if ( mOffsetUnit != mSizeUnit )
372  {
373  return QgsSymbolV2::Mixed;
374  }
375  return mOffsetUnit;
376 }
377 
379 {
380  mSizeMapUnitScale = scale;
381  mOffsetMapUnitScale = scale;
382 }
383 
385 {
387  {
388  return mSizeMapUnitScale;
389  }
390  return QgsMapUnitScale();
391 }
392 
394 {
395  mWidthUnit = unit;
396 }
397 
399 {
400  return mWidthUnit;
401 }
402 
404 {
405  mWidthMapUnitScale = scale;
406 }
407 
409 {
410  return mWidthMapUnitScale;
411 }
412 
413 
415 {
416  QPolygonF points;
417  // we're adding 0.5 to get rid of blurred preview:
418  // drawing antialiased lines of width 1 at (x,0)-(x,100) creates 2px line
419  points << QPointF( 0, int( size.height() / 2 ) + 0.5 ) << QPointF( size.width(), int( size.height() / 2 ) + 0.5 );
420 
421  startRender( context );
422  renderPolyline( points, context );
423  stopRender( context );
424 }
425 
426 void QgsLineSymbolLayerV2::renderPolygonOutline( const QPolygonF& points, QList<QPolygonF>* rings, QgsSymbolV2RenderContext& context )
427 {
428  renderPolyline( points, context );
429  if ( rings )
430  {
431  foreach ( const QPolygonF& ring, *rings )
432  renderPolyline( ring, context );
433  }
434 }
435 
437 {
438  Q_UNUSED( context );
440 }
441 
442 
444 {
445  QPolygonF poly = QRectF( QPointF( 0, 0 ), QPointF( size.width(), size.height() ) );
446  startRender( context );
447  renderPolygon( poly, NULL, context );
448  stopRender( context );
449 }
450 
451 void QgsFillSymbolLayerV2::_renderPolygon( QPainter* p, const QPolygonF& points, const QList<QPolygonF>* rings, QgsSymbolV2RenderContext& context )
452 {
453  if ( !p )
454  {
455  return;
456  }
457 
458  // Disable 'Antialiasing' if the geometry was generalized in the current RenderContext (We known that it must have least #5 points).
459  if ( points.size() <= 5 &&
462  ( p->renderHints() & QPainter::Antialiasing ) )
463  {
464  p->setRenderHint( QPainter::Antialiasing, false );
465  p->drawRect( points.boundingRect() );
466  p->setRenderHint( QPainter::Antialiasing, true );
467  return;
468  }
469 
470  if ( rings == NULL )
471  {
472  // simple polygon without holes
473  p->drawPolygon( points );
474  }
475  else
476  {
477  // polygon with holes must be drawn using painter path
478  QPainterPath path;
479  QPolygonF outerRing = points;
480  path.addPolygon( outerRing );
481 
482  QList<QPolygonF>::const_iterator it = rings->constBegin();
483  for ( ; it != rings->constEnd(); ++it )
484  {
485  QPolygonF ring = *it;
486  path.addPolygon( ring );
487  }
488 
489  p->drawPath( path );
490  }
491 }
492 
493 void QgsMarkerSymbolLayerV2::toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
494 {
495  QDomElement symbolizerElem = doc.createElement( "se:PointSymbolizer" );
496  if ( !props.value( "uom", "" ).isEmpty() )
497  symbolizerElem.setAttribute( "uom", props.value( "uom", "" ) );
498  element.appendChild( symbolizerElem );
499 
500  // <Geometry>
501  QgsSymbolLayerV2Utils::createGeometryElement( doc, symbolizerElem, props.value( "geom", "" ) );
502 
503  writeSldMarker( doc, symbolizerElem, props );
504 }
505 
506