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:39
static QgsSymbolV2Map loadSymbols(QDomElement &element)
#define RENDERER_TAG_NAME
Definition: qgsrendererv2.h:47
QList< QgsSymbolV2 * > QgsSymbolV2List
Definition: qgsrendererv2.h:38
virtual QDomElement save(QDomDocument &doc) override
store renderer info to XML element
virtual void stopRender(QgsRenderContext &context) override
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
virtual QgsSymbolV2List symbols() override
for symbol levels
virtual QgsSymbolV2 * symbolForFeature(QgsFeature &feature) override
to be overridden
virtual QgsSymbolV2 * originalSymbolForFeature(QgsFeature &feature) override
Return symbol for feature.
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: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 QgsFeatureRendererV2 * clone() const override
QMap< QString, QString > QgsStringMap
Definition: qgis.h:416
QgsSymbolV2::ScaleMethod mScaleMethod
void setWidth(double width)
virtual void toSld(QDomDocument &doc, QDomElement &element) const override
used from subclasses to create SLD Rule elements following SLD v1.1 specs
void setAngle(double angle)
QString type() const
Definition: qgsrendererv2.h:81
static bool createSymbolLayerV2ListFromSld(QDomElement &element, QGis::GeometryType geomType, QgsSymbolLayerV2List &layers)
virtual QgsFeatureRendererV2 * clone() const =0
QgsInvertedPolygonRenderer is a polygon-only feature renderer used to display features inverted...
#define DEFAULT_SCALE_METHOD
static QDomElement saveSymbols(QgsSymbolV2Map &symbols, QString tagName, QDomDocument &doc)
QgsSingleSymbolRendererV2(QgsSymbolV2 *symbol)
void setAngle(double angle)
virtual QList< QString > usedAttributes() override
void setSize(double size)
QScopedPointer< QgsExpression > mSizeScale
QList< QPair< QString, QPixmap > > QgsLegendSymbologyList
QgsFeatureRendererV2 * embeddedRenderer() const
virtual QgsLegendSymbologyList legendSymbologyItems(QSize iconSize) override
return a list of symbology items for the legend
virtual QString dump() const override
for debugging
A renderer that automatically displaces points with the same position.
void setUsingSymbolLevels(bool usingSymbolLevels)
QString rotationField() const override
return rotation field name (or empty string if not set or not supported by renderer) ...
void setScaleMethod(QgsSymbolV2::ScaleMethod scaleMethod)
Contains information about the context of a rendering operation.
const QgsFeatureRendererV2 * embeddedRenderer() const
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
virtual QgsLegendSymbolList legendSymbolItems(double scaleDenominator=-1, QString rule=QString()) override
return a list of item text / symbol
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)
static void clearSymbolMap(QgsSymbolV2Map &symbols)
static QgsSymbolV2::ScaleMethod decodeScaleMethod(QString str)
QList< QgsLegendSymbolItemV2 > QgsLegendSymbolListV2
static QgsFeatureRendererV2 * create(QDomElement &element)
create renderer from XML element
static QPixmap symbolPreviewPixmap(QgsSymbolV2 *symbol, QSize size, QgsRenderContext *customContext=0)
double size
Definition: qgssvgcache.cpp:77
QList< QPair< QString, QgsSymbolV2 * > > QgsLegendSymbolList
Definition: qgsrendererv2.h:42
virtual void startRender(QgsRenderContext &context, const QgsFields &fields) override
The class stores information about one class/rule of a vector layer renderer in a unified way that ca...
QScopedPointer< QgsSymbolV2 > mTempSymbol
void setScaleMethod(QgsSymbolV2::ScaleMethod scaleMethod)
void setRotationField(QString fieldOrExpression) override
sets rotation field of renderer (if supported by the renderer)
QScopedPointer< QgsExpression > mRotation
virtual QgsLegendSymbolListV2 legendSymbolItemsV2() const override
Return a list of symbology items for the legend.