QGIS API Documentation  2.7.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules 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"
28 
29 #include <QDomDocument>
30 #include <QDomElement>
31 
33  : QgsFeatureRendererV2( "singleSymbol" )
34  , mSymbol( symbol )
35  , mScaleMethod( DEFAULT_SCALE_METHOD )
36 {
37  Q_ASSERT( symbol );
38 }
39 
41 {
42 }
43 
45 {
46  if ( !mRotation.data() && !mSizeScale.data() ) return mSymbol.data();
47 
48  const double rotation = mRotation.data() ? mRotation->evaluate( feature ).toDouble() : 0;
49  const double sizeScale = mSizeScale.data() ? mSizeScale->evaluate( feature ).toDouble() : 1.;
50 
51  if ( mTempSymbol->type() == QgsSymbolV2::Marker )
52  {
53  QgsMarkerSymbolV2* markerSymbol = static_cast<QgsMarkerSymbolV2*>( mTempSymbol.data() );
54  if ( mRotation.data() ) markerSymbol->setAngle( rotation );
55  markerSymbol->setSize( sizeScale * mOrigSize );
56  markerSymbol->setScaleMethod( mScaleMethod );
57  }
58  else if ( mTempSymbol->type() == QgsSymbolV2::Line )
59  {
60  QgsLineSymbolV2* lineSymbol = static_cast<QgsLineSymbolV2*>( mTempSymbol.data() );
61  lineSymbol->setWidth( sizeScale * mOrigSize );
62  }
63  else if ( mTempSymbol->type() == QgsSymbolV2::Fill )
64  {
65  QgsFillSymbolV2* fillSymbol = static_cast<QgsFillSymbolV2*>( mTempSymbol.data() );
66  if ( mRotation.data() ) fillSymbol->setAngle( rotation );
67  }
68 
69  return mTempSymbol.data();
70 }
71 
73 {
74  Q_UNUSED( feature );
75  return mSymbol.data();
76 }
77 
79 {
80  if ( !mSymbol.data() ) return;
81 
82  mSymbol->startRender( context, &fields );
83 
84  if ( mRotation.data() || mSizeScale.data() )
85  {
86  // we are going to need a temporary symbol
87  mTempSymbol.reset( mSymbol->clone() );
88 
89  int hints = 0;
90  if ( mRotation.data() )
92  if ( mSizeScale.data() )
94  mTempSymbol->setRenderHints( hints );
95 
96  mTempSymbol->startRender( context, &fields );
97 
98  if ( mSymbol->type() == QgsSymbolV2::Marker )
99  {
100  mOrigSize = static_cast<QgsMarkerSymbolV2*>( mSymbol.data() )->size();
101  }
102  else if ( mSymbol->type() == QgsSymbolV2::Line )
103  {
104  mOrigSize = static_cast<QgsLineSymbolV2*>( mSymbol.data() )->width();
105  }
106  else
107  {
108  mOrigSize = 0;
109  }
110  }
111 }
112 
114 {
115  if ( !mSymbol.data() ) return;
116 
117  mSymbol->stopRender( context );
118 
119  if ( mRotation.data() || mSizeScale.data() )
120  {
121  // we are going to need a temporary symbol
122  mTempSymbol->stopRender( context );
123  mTempSymbol.reset();
124  }
125 }
126 
128 {
129  QSet<QString> attributes;
130  if ( mSymbol.data() ) attributes.unite( mSymbol->usedAttributes() );
131  if ( mRotation.data() ) attributes.unite( mRotation->referencedColumns().toSet() );
132  if ( mSizeScale.data() ) attributes.unite( mSizeScale->referencedColumns().toSet() );
133  return attributes.toList();
134 }
135 
137 {
138  return mSymbol.data();
139 }
140 
142 {
143  Q_ASSERT( s );
144  mSymbol.reset( s );
145 }
146 
147 void QgsSingleSymbolRendererV2::setRotationField( QString fieldOrExpression )
148 {
150 }
151 
153 {
154  return mRotation.data() ? QgsSymbolLayerV2Utils::fieldOrExpressionFromExpression( mRotation.data() ) : QString();
155 }
156 
157 void QgsSingleSymbolRendererV2::setSizeScaleField( QString fieldOrExpression )
158 {
160 }
161 
163 {
165 }
166 
168 {
171 }
172 
174 {
175  return mSymbol.data() ? QString( "SINGLE: %1" ).arg( mSymbol->dump() ) : "";
176 }
177 
179 {
184  r->setScaleMethod( scaleMethod() );
185  return r;
186 }
187 
188 void QgsSingleSymbolRendererV2::toSld( QDomDocument& doc, QDomElement &element ) const
189 {
190  QgsStringMap props;
191  QString errorMsg;
192  if ( mRotation.data() )
193  props[ "angle" ] = mRotation->expression();
194  if ( mSizeScale.data() )
195  props[ "scale" ] = mSizeScale->expression();
196 
197  QDomElement ruleElem = doc.createElement( "se:Rule" );
198  element.appendChild( ruleElem );
199 
200  QDomElement nameElem = doc.createElement( "se:Name" );
201  nameElem.appendChild( doc.createTextNode( "Single symbol" ) );
202  ruleElem.appendChild( nameElem );
203 
204  if ( mSymbol.data() ) mSymbol->toSld( doc, ruleElem, props );
205 }
206 
208 {
209  QgsSymbolV2List lst;
210  lst.append( mSymbol.data() );
211  return lst;
212 }
213 
215 {
216  QDomElement symbolsElem = element.firstChildElement( "symbols" );
217  if ( symbolsElem.isNull() )
218  return NULL;
219 
220  QgsSymbolV2Map symbolMap = QgsSymbolLayerV2Utils::loadSymbols( symbolsElem );
221 
222  if ( !symbolMap.contains( "0" ) )
223  return NULL;
224 
225  QgsSingleSymbolRendererV2* r = new QgsSingleSymbolRendererV2( symbolMap.take( "0" ) );
226 
227  // delete symbols if there are any more
229 
230  QDomElement rotationElem = element.firstChildElement( "rotation" );
231  if ( !rotationElem.isNull() )
232  r->setRotationField( rotationElem.attribute( "field" ) );
233 
234  QDomElement sizeScaleElem = element.firstChildElement( "sizescale" );
235  if ( !sizeScaleElem.isNull() )
236  {
237  r->setSizeScaleField( sizeScaleElem.attribute( "field" ) );
238  r->setScaleMethod( QgsSymbolLayerV2Utils::decodeScaleMethod( sizeScaleElem.attribute( "scalemethod" ) ) );
239  }
240 
241  // TODO: symbol levels
242  return r;
243 }
244 
246 {
247  // XXX this renderer can handle only one Rule!
248 
249  // get the first Rule element
250  QDomElement ruleElem = element.firstChildElement( "Rule" );
251  if ( ruleElem.isNull() )
252  {
253  QgsDebugMsg( "no Rule elements found!" );
254  return NULL;
255  }
256 
257  QString label, description;
258  QgsSymbolLayerV2List layers;
259 
260  // retrieve the Rule element child nodes
261  QDomElement childElem = ruleElem.firstChildElement();
262  while ( !childElem.isNull() )
263  {
264  if ( childElem.localName() == "Name" )
265  {
266  // <se:Name> tag contains the rule identifier,
267  // so prefer title tag for the label property value
268  if ( label.isEmpty() )
269  label = childElem.firstChild().nodeValue();
270  }
271  else if ( childElem.localName() == "Description" )
272  {
273  // <se:Description> can contains a title and an abstract
274  QDomElement titleElem = childElem.firstChildElement( "Title" );
275  if ( !titleElem.isNull() )
276  {
277  label = titleElem.firstChild().nodeValue();
278  }
279 
280  QDomElement abstractElem = childElem.firstChildElement( "Abstract" );
281  if ( !abstractElem.isNull() )
282  {
283  description = abstractElem.firstChild().nodeValue();
284  }
285  }
286  else if ( childElem.localName() == "Abstract" )
287  {
288  // <sld:Abstract> (v1.0)
289  description = childElem.firstChild().nodeValue();
290  }
291  else if ( childElem.localName() == "Title" )
292  {
293  // <sld:Title> (v1.0)
294  label = childElem.firstChild().nodeValue();
295  }
296  else if ( childElem.localName().endsWith( "Symbolizer" ) )
297  {
298  // create symbol layers for this symbolizer
299  QgsSymbolLayerV2Utils::createSymbolLayerV2ListFromSld( childElem, geomType, layers );
300  }
301 
302  childElem = childElem.nextSiblingElement();
303  }
304 
305  if ( layers.size() == 0 )
306  return NULL;
307 
308  // now create the symbol
310  switch ( geomType )
311  {
312  case QGis::Line:
313  symbol = new QgsLineSymbolV2( layers );
314  break;
315 
316  case QGis::Polygon:
317  symbol = new QgsFillSymbolV2( layers );
318  break;
319 
320  case QGis::Point:
321  symbol = new QgsMarkerSymbolV2( layers );
322  break;
323 
324  default:
325  QgsDebugMsg( QString( "invalid geometry type: found %1" ).arg( geomType ) );
326  return NULL;
327  }
328 
329  // and finally return the new renderer
330  return new QgsSingleSymbolRendererV2( symbol );
331 }
332 
333 QDomElement QgsSingleSymbolRendererV2::save( QDomDocument& doc )
334 {
335  QDomElement rendererElem = doc.createElement( RENDERER_TAG_NAME );
336  rendererElem.setAttribute( "type", "singleSymbol" );
337  rendererElem.setAttribute( "symbollevels", ( mUsingSymbolLevels ? "1" : "0" ) );
338 
340  symbols["0"] = mSymbol.data();
341  QDomElement symbolsElem = QgsSymbolLayerV2Utils::saveSymbols( symbols, "symbols", doc );
342  rendererElem.appendChild( symbolsElem );
343 
344  QDomElement rotationElem = doc.createElement( "rotation" );
345  if ( mRotation.data() )
346  rotationElem.setAttribute( "field", QgsSymbolLayerV2Utils::fieldOrExpressionFromExpression( mRotation.data() ) );
347  rendererElem.appendChild( rotationElem );
348 
349  QDomElement sizeScaleElem = doc.createElement( "sizescale" );
350  if ( mSizeScale.data() )
351  sizeScaleElem.setAttribute( "field", QgsSymbolLayerV2Utils::fieldOrExpressionFromExpression( mSizeScale.data() ) );
352  sizeScaleElem.setAttribute( "scalemethod", QgsSymbolLayerV2Utils::encodeScaleMethod( mScaleMethod ) );
353  rendererElem.appendChild( sizeScaleElem );
354 
355  return rendererElem;
356 }
357 
359 {
361  if ( mSymbol.data() )
362  {
363  QPixmap pix = QgsSymbolLayerV2Utils::symbolPreviewPixmap( mSymbol.data(), iconSize );
364  lst << qMakePair( QString(), pix );
365  }
366  return lst;
367 }
368 
370 {
371  Q_UNUSED( scaleDenominator );
372  Q_UNUSED( rule );
374  lst << qMakePair( QString(), mSymbol.data() );
375  return lst;
376 }
377 
379 {
381  lst << QgsLegendSymbolItemV2( mSymbol.data(), QString(), 0 );
382  return lst;
383 }
384 
386 {
387  if ( renderer->type() == "singleSymbol" )
388  {
389  return dynamic_cast<QgsSingleSymbolRendererV2*>( renderer->clone() );
390  }
391  if ( renderer->type() == "pointDisplacement" )
392  {
393  const QgsPointDisplacementRenderer* pointDisplacementRenderer = dynamic_cast<const QgsPointDisplacementRenderer*>( renderer );
394  return convertFromRenderer( pointDisplacementRenderer->embeddedRenderer() );
395  }
396  if ( renderer->type() == "invertedPolygonRenderer" )
397  {
398  const QgsInvertedPolygonRenderer* invertedPolygonRenderer = dynamic_cast<const QgsInvertedPolygonRenderer*>( renderer );
399  return convertFromRenderer( invertedPolygonRenderer->embeddedRenderer() );
400 
401  }
402 
403  QgsSymbolV2List symbols = const_cast<QgsFeatureRendererV2 *>( renderer )->symbols();
404  if ( symbols.size() > 0 )
405  {
406  return new QgsSingleSymbolRendererV2( symbols.at( 0 )->clone() );
407  }
408  return 0;
409 }
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:46
QList< QgsSymbolV2 * > QgsSymbolV2List
Definition: qgsrendererv2.h:37
virtual QDomElement save(QDomDocument &doc)
store renderer info to XML element
virtual QgsFeatureRendererV2 * clone() const
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
void setSizeScaleField(QString fieldOrExpression)
static QgsFeatureRendererV2 * createFromSld(QDomElement &element, QGis::GeometryType geomType)
virtual QgsLegendSymbolListV2 legendSymbolItemsV2() const
Return a list of symbology items for the legend.
QString rotationField() const
return rotation field name (or empty string if not set or not supported by renderer) ...
QgsSymbolV2::ScaleMethod scaleMethod() const
Container of fields for a vector layer.
Definition: qgsfield.h:172
static QgsSingleSymbolRendererV2 * convertFromRenderer(const QgsFeatureRendererV2 *renderer)
creates a QgsSingleSymbolRendererV2 from an existing renderer.
GeometryType
Definition: qgis.h:155
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:412
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
QString type() const
Definition: qgsrendererv2.h:80
static bool createSymbolLayerV2ListFromSld(QDomElement &element, QGis::GeometryType geomType, QgsSymbolLayerV2List &layers)
virtual QgsFeatureRendererV2 * clone() const =0
virtual QgsLegendSymbolList legendSymbolItems(double scaleDenominator=-1, QString rule=QString())
return a list of item text / symbol
QgsInvertedPolygonRenderer is a polygon-only feature renderer used to display features inverted...
#define DEFAULT_SCALE_METHOD
void setRotationField(QString fieldOrExpression)
sets rotation field of renderer (if supported by the renderer)
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
QgsFeatureRendererV2 * embeddedRenderer() const
A renderer that automatically displaces points with the same position.
void setUsingSymbolLevels(bool usingSymbolLevels)
void setScaleMethod(QgsSymbolV2::ScaleMethod scaleMethod)
Contains information about the context of a rendering operation.
const QgsFeatureRendererV2 * embeddedRenderer() const
virtual QgsLegendSymbologyList legendSymbologyItems(QSize iconSize)
return a list of symbology items for the legend
virtual QgsSymbolV2 * originalSymbolForFeature(QgsFeature &feature)
Return symbol for feature.
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 void clearSymbolMap(QgsSymbolV2Map &symbols)
static QgsSymbolV2::ScaleMethod decodeScaleMethod(QString str)
QList< QgsLegendSymbolItemV2 > QgsLegendSymbolListV2
static QgsFeatureRendererV2 * create(QDomElement &element)
create renderer from XML element
virtual QgsSymbolV2 * symbolForFeature(QgsFeature &feature)
to be overridden
static QPixmap symbolPreviewPixmap(QgsSymbolV2 *symbol, QSize size, QgsRenderContext *customContext=0)
double size
Definition: qgssvgcache.cpp:77
QList< QPair< QString, QgsSymbolV2 * > > QgsLegendSymbolList
Definition: qgsrendererv2.h:41
The class stores information about one class/rule of a vector layer renderer in a unified way that ca...
QScopedPointer< QgsSymbolV2 > mTempSymbol
virtual QList< QString > usedAttributes()
void setScaleMethod(QgsSymbolV2::ScaleMethod scaleMethod)
QScopedPointer< QgsExpression > mRotation