QGIS API Documentation  2.0.1-Dufour
 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 
22 #include <QSize>
23 #include <QPainter>
24 #include <QPointF>
25 #include <QPolygonF>
26 
27 const QgsExpression* QgsSymbolLayerV2::dataDefinedProperty( const QString& property ) const
28 {
29  QMap< QString, QgsExpression* >::const_iterator it = mDataDefinedProperties.find( property );
30  if ( it != mDataDefinedProperties.constEnd() )
31  {
32  return it.value();
33  }
34  return 0;
35 }
36 
37 QgsExpression* QgsSymbolLayerV2::expression( const QString& property )
38 {
39  QMap< QString, QgsExpression* >::iterator it = mDataDefinedProperties.find( property );
40  if ( it != mDataDefinedProperties.end() )
41  {
42  return it.value();
43  }
44  return 0;
45 }
46 
47 QString QgsSymbolLayerV2::dataDefinedPropertyString( const QString& property ) const
48 {
49  const QgsExpression* ex = dataDefinedProperty( property );
50  return ex ? ex->expression() : QString();
51 }
52 
53 void QgsSymbolLayerV2::setDataDefinedProperty( const QString& property, const QString& expressionString )
54 {
55  removeDataDefinedProperty( property );
56  mDataDefinedProperties.insert( property, new QgsExpression( expressionString ) );
57 }
58 
59 void QgsSymbolLayerV2::removeDataDefinedProperty( const QString& property )
60 {
61  QMap< QString, QgsExpression* >::iterator it = mDataDefinedProperties.find( property );
62  if ( it != mDataDefinedProperties.end() )
63  {
64  delete( it.value() );
65  mDataDefinedProperties.erase( it );
66  }
67 }
68 
70 {
71  QMap< QString, QgsExpression* >::iterator it = mDataDefinedProperties.begin();
72  for ( ; it != mDataDefinedProperties.constEnd(); ++it )
73  {
74  delete( it.value() );
75  }
76  mDataDefinedProperties.clear();
77 }
78 
80 {
81  if ( !vl )
82  {
83  return;
84  }
85 
86  const QgsFields& fields = vl->pendingFields();
87  QMap< QString, QgsExpression* >::iterator it = mDataDefinedProperties.begin();
88  for ( ; it != mDataDefinedProperties.end(); ++it )
89  {
90  if ( it.value() )
91  {
92  it.value()->prepare( fields );
93  }
94  }
95 }
96 
97 QSet<QString> QgsSymbolLayerV2::usedAttributes() const
98 {
99  QStringList columns;
100 
101  QMap< QString, QgsExpression* >::const_iterator ddIt = mDataDefinedProperties.constBegin();
102  for ( ; ddIt != mDataDefinedProperties.constEnd(); ++ddIt )
103  {
104  if ( ddIt.value() )
105  {
106  columns.append( ddIt.value()->referencedColumns() );
107  }
108  }
109 
110  QSet<QString> attributes;
111  QStringList::const_iterator it = columns.constBegin();
112  for ( ; it != columns.constEnd(); ++it )
113  {
114  attributes.insert( *it );
115  }
116 
117  return attributes;
118 }
119 
121 {
122  QMap< QString, QgsExpression* >::const_iterator ddIt = mDataDefinedProperties.constBegin();
123  for ( ; ddIt != mDataDefinedProperties.constEnd(); ++ddIt )
124  {
125  if ( ddIt.value() )
126  {
127  stringMap.insert( ddIt.key() + "_expression", ddIt.value()->expression() );
128  }
129  }
130 }
131 
133 {
134  if ( !destLayer )
135  return;
136 
137  destLayer->removeDataDefinedProperties();
138 
139  QMap< QString, QgsExpression* >::const_iterator ddIt = mDataDefinedProperties.constBegin();
140  for ( ; ddIt != mDataDefinedProperties.constEnd(); ++ddIt )
141  {
142  if ( ddIt.value() )
143  {
144  destLayer->setDataDefinedProperty( ddIt.key(), ddIt.value()->expression() );
145  }
146  }
147 }
148 
149 
151  : QgsSymbolLayerV2( QgsSymbolV2::Marker, locked ), mSizeUnit( QgsSymbolV2::MM ), mOffsetUnit( QgsSymbolV2::MM )
152 {
153 }
154 
156  : QgsSymbolLayerV2( QgsSymbolV2::Line, locked ), mWidthUnit( QgsSymbolV2::MM )
157 {
158 }
159 
161  : QgsSymbolLayerV2( QgsSymbolV2::Fill, locked ), mAngle( 0.0 )
162 {
163 }
164 
166 {
167  startRender( context );
168  renderPoint( QPointF( size.width() / 2, size.height() / 2 ), context );
169  stopRender( context );
170 }
171 
173 {
174  mSizeUnit = unit;
175  mOffsetUnit = unit;
176 }
177 
178 void QgsMarkerSymbolLayerV2::markerOffset( QgsSymbolV2RenderContext& context, double& offsetX, double& offsetY )
179 {
180  offsetX = mOffset.x();
181  offsetY = mOffset.y();
182 
183  QgsExpression* offsetExpression = expression( "offset" );
184  if ( offsetExpression )
185  {
186  QPointF offset = QgsSymbolLayerV2Utils::decodePoint( offsetExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString() );
187  offsetX = offset.x();
188  offsetY = offset.y();
189  }
190 
193 }
194 
195 QPointF QgsMarkerSymbolLayerV2::_rotatedOffset( const QPointF& offset, double angle )
196 {
197  angle = DEG2RAD( angle );
198  double c = cos( angle ), s = sin( angle );
199  return QPointF( offset.x() * c - offset.y() * s, offset.x() * s + offset.y() * c );
200 }
201 
203 {
205  if ( mOffsetUnit != unit )
206  {
207  return QgsSymbolV2::Mixed;
208  }
209  return unit;
210 }
211 
213 {
214  QPolygonF points;
215  // we're adding 0.5 to get rid of blurred preview:
216  // drawing antialiased lines of width 1 at (x,0)-(x,100) creates 2px line
217  points << QPointF( 0, size.height() / 2 + 0.5 ) << QPointF( size.width(), size.height() / 2 + 0.5 );
218 
219  startRender( context );
220  renderPolyline( points, context );
221  stopRender( context );
222 }
223 
224 void QgsLineSymbolLayerV2::renderPolygonOutline( const QPolygonF& points, QList<QPolygonF>* rings, QgsSymbolV2RenderContext& context )
225 {
226  renderPolyline( points, context );
227  if ( rings )
228  {
229  foreach ( const QPolygonF& ring, *rings )
230  renderPolyline( ring, context );
231  }
232 }
233 
234 
236 {
237  QPolygonF poly = QRectF( QPointF( 0, 0 ), QPointF( size.width() - 1, size.height() - 1 ) );
238  startRender( context );
239  renderPolygon( poly, NULL, context );
240  stopRender( context );
241 }
242 
243 void QgsFillSymbolLayerV2::_renderPolygon( QPainter* p, const QPolygonF& points, const QList<QPolygonF>* rings )
244 {
245  if ( !p )
246  {
247  return;
248  }
249 
250  if ( rings == NULL )
251  {
252  // simple polygon without holes
253  p->drawPolygon( points );
254  }
255  else
256  {
257  // polygon with holes must be drawn using painter path
258  QPainterPath path;
259  QPolygonF outerRing = points;
260  path.addPolygon( outerRing );
261 
262  QList<QPolygonF>::const_iterator it = rings->constBegin();
263  for ( ; it != rings->constEnd(); ++it )
264  {
265  QPolygonF ring = *it;
266  path.addPolygon( ring );
267  }
268 
269  p->drawPath( path );
270  }
271 }
272 
273 void QgsMarkerSymbolLayerV2::toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
274 {
275  QDomElement symbolizerElem = doc.createElement( "se:PointSymbolizer" );
276  if ( !props.value( "uom", "" ).isEmpty() )
277  symbolizerElem.setAttribute( "uom", props.value( "uom", "" ) );
278  element.appendChild( symbolizerElem );
279 
280  // <Geometry>
281  QgsSymbolLayerV2Utils::createGeometryElement( doc, symbolizerElem, props.value( "geom", "" ) );
282 
283  writeSldMarker( doc, symbolizerElem, props );
284 }