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