QGIS API Documentation  2.9.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  , mOrigSize( 0.0 )
37 {
38  Q_ASSERT( symbol );
39 }
40 
42 {
43 }
44 
46 {
47  if ( !mRotation.data() && !mSizeScale.data() ) return mSymbol.data();
48 
49  const double rotation = mRotation.data() ? mRotation->evaluate( feature ).toDouble() : 0;
50  const double sizeScale = mSizeScale.data() ? mSizeScale->evaluate( feature ).toDouble() : 1.;
51 
52  if ( mTempSymbol->type() == QgsSymbolV2::Marker )
53  {
54  QgsMarkerSymbolV2* markerSymbol = static_cast<QgsMarkerSymbolV2*>( mTempSymbol.data() );
55  if ( mRotation.data() ) markerSymbol->setAngle( rotation );
56  markerSymbol->setSize( sizeScale * mOrigSize );
57  markerSymbol->setScaleMethod( mScaleMethod );
58  }
59  else if ( mTempSymbol->type() == QgsSymbolV2::Line )
60  {
61  QgsLineSymbolV2* lineSymbol = static_cast<QgsLineSymbolV2*>( mTempSymbol.data() );
62  lineSymbol->setWidth( sizeScale * mOrigSize );
63  }
64  else if ( mTempSymbol->type() == QgsSymbolV2::Fill )
65  {
66  QgsFillSymbolV2* fillSymbol = static_cast<QgsFillSymbolV2*>( mTempSymbol.data() );
67  if ( mRotation.data() ) fillSymbol->setAngle( rotation );
68  }
69 
70  return mTempSymbol.data();
71 }
72 
74 {
75  Q_UNUSED( feature );
76  return mSymbol.data();
77 }
78 
80 {
81  if ( !mSymbol.data() ) return;
82 
83  mSymbol->startRender( context, &fields );
84 
85  if ( mRotation.data() || mSizeScale.data() )
86  {
87  // we are going to need a temporary symbol
88  mTempSymbol.reset( mSymbol->clone() );
89 
90  int hints = 0;
91  if ( mRotation.data() )
93  if ( mSizeScale.data() )
95  mTempSymbol->setRenderHints( hints );
96 
97  mTempSymbol->startRender( context, &fields );
98 
99  if ( mSymbol->type() == QgsSymbolV2::Marker )
100  {
101  mOrigSize = static_cast<QgsMarkerSymbolV2*>( mSymbol.data() )->size();
102  }
103  else if ( mSymbol->type() == QgsSymbolV2::Line )
104  {
105  mOrigSize = static_cast<QgsLineSymbolV2*>( mSymbol.data() )->width();
106  }
107  else
108  {
109  mOrigSize = 0;
110  }
111  }
112 }
113 
115 {
116  if ( !mSymbol.data() ) return;
117 
118  mSymbol->stopRender( context );
119 
120  if ( mRotation.data() || mSizeScale.data() )
121  {
122  // we are going to need a temporary symbol
123  mTempSymbol->stopRender( context );
124  mTempSymbol.reset();
125  }
126 }
127 
129 {
130  QSet<QString> attributes;
131  if ( mSymbol.data() ) attributes.unite( mSymbol->usedAttributes() );
132  if ( mRotation.data() ) attributes.unite( mRotation->referencedColumns().toSet() );
133  if ( mSizeScale.data() ) attributes.unite( mSizeScale->referencedColumns().toSet() );
134  return attributes.toList();
135 }
136 
138 {
139  return mSymbol.data();
140 }
141 
143 {
144  Q_ASSERT( s );
145  mSymbol.reset( s );
146 }
147 
148 void QgsSingleSymbolRendererV2::setRotationField( QString fieldOrExpression )
149 {
151 }
152 
154 {
155  return mRotation.data() ? QgsSymbolLayerV2Utils::fieldOrExpressionFromExpression( mRotation.data() ) : QString();
156 }
157 
158 void QgsSingleSymbolRendererV2::setSizeScaleField( QString fieldOrExpression )
159 {
161 }
162 
164 {
166 }
167 
169 {
172 }
173 
175 {
176  return mSymbol.data() ? QString( "SINGLE: %1" ).arg( mSymbol->dump() ) : "";
177 }
178 
180 {
185  r->setScaleMethod( scaleMethod() );
186  return r;
187 }
188 
189 void QgsSingleSymbolRendererV2::toSld( QDomDocument& doc, QDomElement &element ) const
190 {
191  QgsStringMap props;
192  QString errorMsg;
193  if ( mRotation.data() )
194  props[ "angle" ] = mRotation->expression();
195  if ( mSizeScale.data() )
196  props[ "scale" ] = mSizeScale->expression();
197 
198  QDomElement ruleElem = doc.createElement( "se:Rule" );
199  element.appendChild( ruleElem );
200 
201  QDomElement nameElem = doc.createElement( "se:Name" );
202  nameElem.appendChild( doc.createTextNode( "Single symbol" ) );
203  ruleElem.appendChild( nameElem );
204 
205  if ( mSymbol.data() ) mSymbol->toSld( doc, ruleElem, props );
206 }
207 
209 {
210  QgsSymbolV2List lst;
211  lst.append( mSymbol.data() );
212  return lst;
213 }
214 
216 {
217  QDomElement symbolsElem = element.firstChildElement( "symbols" );
218  if ( symbolsElem.isNull() )
219  return NULL;
220 
221  QgsSymbolV2Map symbolMap = QgsSymbolLayerV2Utils::loadSymbols( symbolsElem );
222 
223  if ( !symbolMap.contains( "0" ) )
224  return NULL;
225 
226  QgsSingleSymbolRendererV2* r = new QgsSingleSymbolRendererV2( symbolMap.take( "0" ) );
227 
228  // delete symbols if there are any more
230 
231  QDomElement rotationElem = element.firstChildElement( "rotation" );
232  if ( !rotationElem.isNull() )
233  r->setRotationField( rotationElem.attribute( "field" ) );
234 
235  QDomElement sizeScaleElem = element.firstChildElement( "sizescale" );
236  if ( !sizeScaleElem.isNull() )
237  {
238  r->setSizeScaleField( sizeScaleElem.attribute( "field" ) );
239  r->setScaleMethod( QgsSymbolLayerV2Utils::decodeScaleMethod( sizeScaleElem.attribute( "scalemethod" ) ) );
240  }
241 
242  // TODO: symbol levels
243  return r;
244 }
245 
247 {
248  // XXX this renderer can handle only one Rule!
249 
250  // get the first Rule element
251  QDomElement ruleElem = element.firstChildElement( "Rule" );
252  if ( ruleElem.isNull() )
253  {
254  QgsDebugMsg( "no Rule elements found!" );
255  return NULL;
256  }
257 
258  QString label, description;
259  QgsSymbolLayerV2List layers;
260 
261  // retrieve the Rule element child nodes
262  QDomElement childElem = ruleElem.firstChildElement();
263  while ( !childElem.isNull() )
264  {
265  if ( childElem.localName() == "Name" )
266  {
267  // <se:Name> tag contains the rule identifier,
268  // so prefer title tag for the label property value
269  if ( label.isEmpty() )
270  label = childElem.firstChild().nodeValue();
271  }
272  else if ( childElem.localName() == "Description" )
273  {
274  // <se:Description> can contains a title and an abstract
275  QDomElement titleElem = childElem.firstChildElement( "Title" );
276  if ( !titleElem.isNull() )
277  {
278  label = titleElem.firstChild().nodeValue();
279  }
280 
281  QDomElement abstractElem = childElem.firstChildElement( "Abstract" );
282  if ( !abstractElem.isNull() )
283  {
284  description = abstractElem.firstChild().nodeValue();
285  }
286  }
287  else if ( childElem.localName() == "Abstract" )
288  {
289  // <sld:Abstract> (v1.0)
290  description = childElem.firstChild().nodeValue();
291  }
292  else if ( childElem.localName() == "Title" )
293  {
294  // <sld:Title> (v1.0)
295  label = childElem.firstChild().nodeValue();
296  }
297  else if ( childElem.localName().endsWith( "Symbolizer" ) )
298  {
299  // create symbol layers for this symbolizer
300  QgsSymbolLayerV2Utils::createSymbolLayerV2ListFromSld( childElem, geomType, layers );
301  }
302 
303  childElem = childElem.nextSiblingElement();
304  }
305 
306  if ( layers.size() == 0 )
307  return NULL;
308 
309  // now create the symbol
311  switch ( geomType )
312  {
313  case QGis::Line:
314  symbol = new QgsLineSymbolV2( layers );
315  break;
316 
317  case QGis::Polygon:
318  symbol = new QgsFillSymbolV2( layers );
319  break;
320 
321  case QGis::Point:
322  symbol = new QgsMarkerSymbolV2( layers );
323  break;
324 
325  default:
326  QgsDebugMsg( QString( "invalid geometry type: found %1" ).arg( geomType ) );
327  return NULL;
328  }
329 
330  // and finally return the new renderer
331  return new QgsSingleSymbolRendererV2( symbol );
332 }
333 
334 QDomElement QgsSingleSymbolRendererV2::save( QDomDocument& doc )
335 {
336  QDomElement rendererElem = doc.createElement( RENDERER_TAG_NAME );
337  rendererElem.setAttribute( "type", "singleSymbol" );
338  rendererElem.setAttribute( "symbollevels", ( mUsingSymbolLevels ? "1" : "0" ) );
339 
341  symbols["0"] = mSymbol.data();
342  QDomElement symbolsElem = QgsSymbolLayerV2Utils::saveSymbols( symbols, "symbols", doc );
343  rendererElem.appendChild( symbolsElem );
344 
345  QDomElement rotationElem = doc.createElement( "rotation" );
346  if ( mRotation.data() )
347  rotationElem.setAttribute( "field", QgsSymbolLayerV2Utils::fieldOrExpressionFromExpression( mRotation.data() ) );
348  rendererElem.appendChild( rotationElem );
349 
350  QDomElement sizeScaleElem = doc.createElement( "sizescale" );
351  if ( mSizeScale.data() )
352  sizeScaleElem.setAttribute( "field", QgsSymbolLayerV2Utils::fieldOrExpressionFromExpression( mSizeScale.data() ) );
353  sizeScaleElem.setAttribute( "scalemethod", QgsSymbolLayerV2Utils::encodeScaleMethod( mScaleMethod ) );
354  rendererElem.appendChild( sizeScaleElem );
355 
356  return rendererElem;
357 }
358 
360 {
362  if ( mSymbol.data() )
363  {
364  QPixmap pix = QgsSymbolLayerV2Utils::symbolPreviewPixmap( mSymbol.data(), iconSize );
365  lst << qMakePair( QString(), pix );
366  }
367  return lst;
368 }
369 
371 {
372  Q_UNUSED( scaleDenominator );
373  Q_UNUSED( rule );
375  lst << qMakePair( QString(), mSymbol.data() );
376  return lst;
377 }
378 
380 {
382  lst << QgsLegendSymbolItemV2( mSymbol.data(), QString(), 0 );
383  return lst;
384 }
385 
387 {
388  if ( renderer->type() == "singleSymbol" )
389  {
390  return dynamic_cast<QgsSingleSymbolRendererV2*>( renderer->clone() );
391  }
392  if ( renderer->type() == "pointDisplacement" )
393  {
394  const QgsPointDisplacementRenderer* pointDisplacementRenderer = dynamic_cast<const QgsPointDisplacementRenderer*>( renderer );
395  if ( pointDisplacementRenderer )
396  return convertFromRenderer( pointDisplacementRenderer->embeddedRenderer() );
397  }
398  if ( renderer->type() == "invertedPolygonRenderer" )
399  {
400  const QgsInvertedPolygonRenderer* invertedPolygonRenderer = dynamic_cast<const QgsInvertedPolygonRenderer*>( renderer );
401  if ( invertedPolygonRenderer )
402  return convertFromRenderer( invertedPolygonRenderer->embeddedRenderer() );
403  }
404 
405  QgsSymbolV2List symbols = const_cast<QgsFeatureRendererV2 *>( renderer )->symbols();
406  if ( symbols.size() > 0 )
407  {
408  return new QgsSingleSymbolRendererV2( symbols.at( 0 )->clone() );
409  }
410  return 0;
411 }
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:418
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.