QGIS API Documentation  2.4.0-Chugiak
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
qgssinglesymbolrendererv2.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgssinglesymbolrendererv2.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 
17 
18 #include "qgssymbolv2.h"
19 #include "qgssymbollayerv2utils.h"
20 
21 #include "qgslogger.h"
22 #include "qgsfeature.h"
23 #include "qgsvectorlayer.h"
24 #include "qgssymbollayerv2.h"
25 #include "qgsogcutils.h"
26 
27 #include <QDomDocument>
28 #include <QDomElement>
29 
31  : QgsFeatureRendererV2( "singleSymbol" )
32  , mSymbol( symbol )
33  , mScaleMethod( DEFAULT_SCALE_METHOD )
34 {
35  Q_ASSERT( symbol );
36 }
37 
39 {
40 }
41 
43 {
44  if ( !mRotation.data() && !mSizeScale.data() ) return mSymbol.data();
45 
46  const double rotation = mRotation.data() ? mRotation->evaluate( feature ).toDouble() : 0;
47  const double sizeScale = mSizeScale.data() ? mSizeScale->evaluate( feature ).toDouble() : 1.;
48 
49  if ( mTempSymbol->type() == QgsSymbolV2::Marker )
50  {
51  QgsMarkerSymbolV2* markerSymbol = static_cast<QgsMarkerSymbolV2*>( mTempSymbol.data() );
52  if ( mRotation.data() ) markerSymbol->setAngle( rotation );
53  markerSymbol->setSize( sizeScale * mOrigSize );
54  markerSymbol->setScaleMethod( mScaleMethod );
55  }
56  else if ( mTempSymbol->type() == QgsSymbolV2::Line )
57  {
58  QgsLineSymbolV2* lineSymbol = static_cast<QgsLineSymbolV2*>( mTempSymbol.data() );
59  lineSymbol->setWidth( sizeScale * mOrigSize );
60  }
61  else if ( mTempSymbol->type() == QgsSymbolV2::Fill )
62  {
63  QgsFillSymbolV2* fillSymbol = static_cast<QgsFillSymbolV2*>( mTempSymbol.data() );
64  if ( mRotation.data() ) fillSymbol->setAngle( rotation );
65  }
66 
67  return mTempSymbol.data();
68 }
69 
71 {
72  if ( !mSymbol.data() ) return;
73 
74  mSymbol->startRender( context, &fields );
75 
76  if ( mRotation.data() || mSizeScale.data() )
77  {
78  // we are going to need a temporary symbol
79  mTempSymbol.reset( mSymbol->clone() );
80 
81  int hints = 0;
82  if ( mRotation.data() )
84  if ( mSizeScale.data() )
86  mTempSymbol->setRenderHints( hints );
87 
88  mTempSymbol->startRender( context, &fields );
89 
90  if ( mSymbol->type() == QgsSymbolV2::Marker )
91  {
92  mOrigSize = static_cast<QgsMarkerSymbolV2*>( mSymbol.data() )->size();
93  }
94  else if ( mSymbol->type() == QgsSymbolV2::Line )
95  {
96  mOrigSize = static_cast<QgsLineSymbolV2*>( mSymbol.data() )->width();
97  }
98  else
99  {
100  mOrigSize = 0;
101  }
102  }
103 }
104 
106 {
107  if ( !mSymbol.data() ) return;
108 
109  mSymbol->stopRender( context );
110 
111  if ( mRotation.data() || mSizeScale.data() )
112  {
113  // we are going to need a temporary symbol
114  mTempSymbol->stopRender( context );
115  mTempSymbol.reset();
116  }
117 }
118 
120 {
121  QSet<QString> attributes;
122  if ( mSymbol.data() ) attributes.unite( mSymbol->usedAttributes() );
123  if ( mRotation.data() ) attributes.unite( mRotation->referencedColumns().toSet() );
124  if ( mSizeScale.data() ) attributes.unite( mSizeScale->referencedColumns().toSet() );
125  return attributes.toList();
126 }
127 
129 {
130  return mSymbol.data();
131 }
132 
134 {
135  Q_ASSERT( s );
136  mSymbol.reset( s );
137 }
138 
139 void QgsSingleSymbolRendererV2::setRotationField( QString fieldOrExpression )
140 {
142 }
143 
145 {
146  return mRotation.data() ? QgsSymbolLayerV2Utils::fieldOrExpressionFromExpression( mRotation.data() ) : QString();
147 }
148 
149 void QgsSingleSymbolRendererV2::setSizeScaleField( QString fieldOrExpression )
150 {
152 }
153 
155 {
157 }
158 
160 {
163 }
164 
166 {
167  return mSymbol.data() ? QString( "SINGLE: %1" ).arg( mSymbol->dump() ) : "" ;
168 }
169 
171 {
176  r->setScaleMethod( scaleMethod() );
177  return r;
178 }
179 
180 void QgsSingleSymbolRendererV2::toSld( QDomDocument& doc, QDomElement &element ) const
181 {
182  QgsStringMap props;
183  QString errorMsg;
184  if ( mRotation.data() )
185  props[ "angle" ] = mRotation->expression();
186  if ( mSizeScale.data() )
187  props[ "scale" ] = mSizeScale->expression();
188 
189  QDomElement ruleElem = doc.createElement( "se:Rule" );
190  element.appendChild( ruleElem );
191 
192  QDomElement nameElem = doc.createElement( "se:Name" );
193  nameElem.appendChild( doc.createTextNode( "Single symbol" ) );
194  ruleElem.appendChild( nameElem );
195 
196  if ( mSymbol.data() ) mSymbol->toSld( doc, ruleElem, props );
197 }
198 
200 {
201  QgsSymbolV2List lst;
202  lst.append( mSymbol.data() );
203  return lst;
204 }
205 
207 {
208  QDomElement symbolsElem = element.firstChildElement( "symbols" );
209  if ( symbolsElem.isNull() )
210  return NULL;
211 
212  QgsSymbolV2Map symbolMap = QgsSymbolLayerV2Utils::loadSymbols( symbolsElem );
213 
214  if ( !symbolMap.contains( "0" ) )
215  return NULL;
216 
217  QgsSingleSymbolRendererV2* r = new QgsSingleSymbolRendererV2( symbolMap.take( "0" ) );
218 
219  // delete symbols if there are any more
221 
222  QDomElement rotationElem = element.firstChildElement( "rotation" );
223  if ( !rotationElem.isNull() )
224  r->setRotationField( rotationElem.attribute( "field" ) );
225 
226  QDomElement sizeScaleElem = element.firstChildElement( "sizescale" );
227  if ( !sizeScaleElem.isNull() )
228  {
229  r->setSizeScaleField( sizeScaleElem.attribute( "field" ) );
230  r->setScaleMethod( QgsSymbolLayerV2Utils::decodeScaleMethod( sizeScaleElem.attribute( "scalemethod" ) ) );
231  }
232 
233  // TODO: symbol levels
234  return r;
235 }
236 
238 {
239  // XXX this renderer can handle only one Rule!
240 
241  // get the first Rule element
242  QDomElement ruleElem = element.firstChildElement( "Rule" );
243  if ( ruleElem.isNull() )
244  {
245  QgsDebugMsg( "no Rule elements found!" );
246  return NULL;
247  }
248 
249  QString label, description;
250  QgsSymbolLayerV2List layers;
251 
252  // retrieve the Rule element child nodes
253  QDomElement childElem = ruleElem.firstChildElement();
254  while ( !childElem.isNull() )
255  {
256  if ( childElem.localName() == "Name" )
257  {
258  // <se:Name> tag contains the rule identifier,
259  // so prefer title tag for the label property value
260  if ( label.isEmpty() )
261  label = childElem.firstChild().nodeValue();
262  }
263  else if ( childElem.localName() == "Description" )
264  {
265  // <se:Description> can contains a title and an abstract
266  QDomElement titleElem = childElem.firstChildElement( "Title" );
267  if ( !titleElem.isNull() )
268  {
269  label = titleElem.firstChild().nodeValue();
270  }
271 
272  QDomElement abstractElem = childElem.firstChildElement( "Abstract" );
273  if ( !abstractElem.isNull() )
274  {
275  description = abstractElem.firstChild().nodeValue();
276  }
277  }
278  else if ( childElem.localName() == "Abstract" )
279  {
280  // <sld:Abstract> (v1.0)
281  description = childElem.firstChild().nodeValue();
282  }
283  else if ( childElem.localName() == "Title" )
284  {
285  // <sld:Title> (v1.0)
286  label = childElem.firstChild().nodeValue();
287  }
288  else if ( childElem.localName().endsWith( "Symbolizer" ) )
289  {
290  // create symbol layers for this symbolizer
291  QgsSymbolLayerV2Utils::createSymbolLayerV2ListFromSld( childElem, geomType, layers );
292  }
293 
294  childElem = childElem.nextSiblingElement();
295  }
296 
297  if ( layers.size() == 0 )
298  return NULL;
299 
300  // now create the symbol
302  switch ( geomType )
303  {
304  case QGis::Line:
305  symbol = new QgsLineSymbolV2( layers );
306  break;
307 
308  case QGis::Polygon:
309  symbol = new QgsFillSymbolV2( layers );
310  break;
311 
312  case QGis::Point:
313  symbol = new QgsMarkerSymbolV2( layers );
314  break;
315 
316  default:
317  QgsDebugMsg( QString( "invalid geometry type: found %1" ).arg( geomType ) );
318  return NULL;
319  }
320 
321  // and finally return the new renderer
322  return new QgsSingleSymbolRendererV2( symbol );
323 }
324 
325 QDomElement QgsSingleSymbolRendererV2::save( QDomDocument& doc )
326 {
327  QDomElement rendererElem = doc.createElement( RENDERER_TAG_NAME );
328  rendererElem.setAttribute( "type", "singleSymbol" );
329  rendererElem.setAttribute( "symbollevels", ( mUsingSymbolLevels ? "1" : "0" ) );
330 
332  symbols["0"] = mSymbol.data();
333  QDomElement symbolsElem = QgsSymbolLayerV2Utils::saveSymbols( symbols, "symbols", doc );
334  rendererElem.appendChild( symbolsElem );
335 
336  QDomElement rotationElem = doc.createElement( "rotation" );
337  if ( mRotation.data() )
338  rotationElem.setAttribute( "field", QgsSymbolLayerV2Utils::fieldOrExpressionFromExpression( mRotation.data() ) );
339  rendererElem.appendChild( rotationElem );
340 
341  QDomElement sizeScaleElem = doc.createElement( "sizescale" );
342  if ( mSizeScale.data() )
343  sizeScaleElem.setAttribute( "field", QgsSymbolLayerV2Utils::fieldOrExpressionFromExpression( mSizeScale.data() ) );
344  sizeScaleElem.setAttribute( "scalemethod", QgsSymbolLayerV2Utils::encodeScaleMethod( mScaleMethod ) );
345  rendererElem.appendChild( sizeScaleElem );
346 
347  return rendererElem;
348 }
349 
351 {
353  if ( mSymbol.data() )
354  {
355  QPixmap pix = QgsSymbolLayerV2Utils::symbolPreviewPixmap( mSymbol.data(), iconSize );
356  lst << qMakePair( QString(), pix );
357  }
358  return lst;
359 }
360 
362 {
363  Q_UNUSED( scaleDenominator );
364  Q_UNUSED( rule );
366  lst << qMakePair( QString(), mSymbol.data() );
367  return lst;
368 }
QMap< QString, QgsSymbolV2 * > QgsSymbolV2Map
Definition: qgsrendererv2.h:38
virtual void startRender(QgsRenderContext &context, const QgsFields &fields)
static QgsSymbolV2Map loadSymbols(QDomElement &element)
#define RENDERER_TAG_NAME
Definition: qgsrendererv2.h:43
GeometryType
Definition: qgis.h:155
QList< QgsSymbolV2 * > QgsSymbolV2List
Definition: qgsrendererv2.h:37
virtual QDomElement save(QDomDocument &doc)
store renderer info to XML element
#define QgsDebugMsg(str)
Definition: qgslogger.h:36
void setSizeScaleField(QString fieldOrExpression)
static QgsFeatureRendererV2 * createFromSld(QDomElement &element, QGis::GeometryType geomType)
QgsSymbolV2::ScaleMethod scaleMethod() const
Container of fields for a vector layer.
Definition: qgsfield.h:161
QScopedPointer< QgsSymbolV2 > mSymbol
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:113
virtual void stopRender(QgsRenderContext &context)
QMap< QString, QString > QgsStringMap
Definition: qgis.h:416
QgsSymbolV2::ScaleMethod mScaleMethod
void setWidth(double width)
void setAngle(double angle)
virtual void toSld(QDomDocument &doc, QDomElement &element) const
used from subclasses to create SLD Rule elements following SLD v1.1 specs
static bool createSymbolLayerV2ListFromSld(QDomElement &element, QGis::GeometryType geomType, QgsSymbolLayerV2List &layers)
virtual QgsLegendSymbolList legendSymbolItems(double scaleDenominator=-1, QString rule=QString())
return a list of item text / symbol
#define DEFAULT_SCALE_METHOD
void setRotationField(QString fieldOrExpression)
static QDomElement saveSymbols(QgsSymbolV2Map &symbols, QString tagName, QDomDocument &doc)
QgsSingleSymbolRendererV2(QgsSymbolV2 *symbol)
void setAngle(double angle)
void setSize(double size)
QScopedPointer< QgsExpression > mSizeScale
virtual QString dump() const
for debugging
QList< QPair< QString, QPixmap > > QgsLegendSymbologyList
virtual QgsFeatureRendererV2 * clone()
void setUsingSymbolLevels(bool usingSymbolLevels)
void setScaleMethod(QgsSymbolV2::ScaleMethod scaleMethod)
Contains information about the context of a rendering operation.
virtual QgsLegendSymbologyList legendSymbologyItems(QSize iconSize)
return a list of symbology items for the legend
static QgsExpression * fieldOrExpressionToExpression(const QString &fieldOrExpression)
Return a new valid expression instance for given field or expression string.
QList< QgsSymbolLayerV2 * > QgsSymbolLayerV2List
Definition: qgssymbolv2.h:39
static QString encodeScaleMethod(QgsSymbolV2::ScaleMethod scaleMethod)
static QString fieldOrExpressionFromExpression(QgsExpression *expression)
Return a field name if the whole expression is just a name of the field .
bool usingSymbolLevels() const
void setScaleMethodToSymbol(QgsSymbolV2 *symbol, int scaleMethod)
virtual QgsSymbolV2List symbols()
for symbol levels
static QPixmap symbolPreviewPixmap(QgsSymbolV2 *symbol, QSize size)
static void clearSymbolMap(QgsSymbolV2Map &symbols)
static QgsSymbolV2::ScaleMethod decodeScaleMethod(QString str)
static QgsFeatureRendererV2 * create(QDomElement &element)
create renderer from XML element
virtual QgsSymbolV2 * symbolForFeature(QgsFeature &feature)
to be overridden
double size
Definition: qgssvgcache.cpp:77
QList< QPair< QString, QgsSymbolV2 * > > QgsLegendSymbolList
Definition: qgsrendererv2.h:41
QScopedPointer< QgsSymbolV2 > mTempSymbol
virtual QList< QString > usedAttributes()
void setScaleMethod(QgsSymbolV2::ScaleMethod scaleMethod)
QScopedPointer< QgsExpression > mRotation