QGIS API Documentation  2.11.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties 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 #include "qgsscaleexpression.h"
30 #include "qgsdatadefined.h"
31 
32 #include <QDomDocument>
33 #include <QDomElement>
34 
36  : QgsFeatureRendererV2( "singleSymbol" )
37  , mSymbol( symbol )
38  , mScaleMethod( DEFAULT_SCALE_METHOD )
39  , mOrigSize( 0.0 )
40 {
41  Q_ASSERT( symbol );
42 }
43 
45 {
46 }
47 
49 {
50  context.expressionContext().setFeature( feature );
51  if ( !mRotation.data() && !mSizeScale.data() ) return mSymbol.data();
52 
53  const double rotation = mRotation.data() ? mRotation->evaluate( &context.expressionContext() ).toDouble() : 0;
54  const double sizeScale = mSizeScale.data() ? mSizeScale->evaluate( &context.expressionContext() ).toDouble() : 1.;
55 
56  if ( mTempSymbol->type() == QgsSymbolV2::Marker )
57  {
58  QgsMarkerSymbolV2* markerSymbol = static_cast<QgsMarkerSymbolV2*>( mTempSymbol.data() );
59  if ( mRotation.data() ) markerSymbol->setAngle( rotation );
60  markerSymbol->setSize( sizeScale * mOrigSize );
61  markerSymbol->setScaleMethod( mScaleMethod );
62  }
63  else if ( mTempSymbol->type() == QgsSymbolV2::Line )
64  {
65  QgsLineSymbolV2* lineSymbol = static_cast<QgsLineSymbolV2*>( mTempSymbol.data() );
66  lineSymbol->setWidth( sizeScale * mOrigSize );
67  }
68  else if ( mTempSymbol->type() == QgsSymbolV2::Fill )
69  {
70  QgsFillSymbolV2* fillSymbol = static_cast<QgsFillSymbolV2*>( mTempSymbol.data() );
71  if ( mRotation.data() ) fillSymbol->setAngle( rotation );
72  }
73 
74  return mTempSymbol.data();
75 }
76 
78 {
79  Q_UNUSED( context );
80  Q_UNUSED( feature );
81  return mSymbol.data();
82 }
83 
85 {
86  if ( !mSymbol.data() )
87  return;
88 
89  mSymbol->startRender( context, &fields );
90 
91  if ( mRotation.data() || mSizeScale.data() )
92  {
93  // we are going to need a temporary symbol
94  mTempSymbol.reset( mSymbol->clone() );
95 
96  int hints = 0;
97  if ( mRotation.data() )
99  if ( mSizeScale.data() )
101  mTempSymbol->setRenderHints( hints );
102 
103  mTempSymbol->startRender( context, &fields );
104 
105  if ( mSymbol->type() == QgsSymbolV2::Marker )
106  {
107  mOrigSize = static_cast<QgsMarkerSymbolV2*>( mSymbol.data() )->size();
108  }
109  else if ( mSymbol->type() == QgsSymbolV2::Line )
110  {
111  mOrigSize = static_cast<QgsLineSymbolV2*>( mSymbol.data() )->width();
112  }
113  else
114  {
115  mOrigSize = 0;
116  }
117  }
118 
119  return;
120 }
121 
123 {
124  if ( !mSymbol.data() ) return;
125 
126  mSymbol->stopRender( context );
127 
128  if ( mRotation.data() || mSizeScale.data() )
129  {
130  // we are going to need a temporary symbol
131  mTempSymbol->stopRender( context );
132  mTempSymbol.reset();
133  }
134 }
135 
137 {
138  QSet<QString> attributes;
139  if ( mSymbol.data() ) attributes.unite( mSymbol->usedAttributes() );
140  if ( mRotation.data() ) attributes.unite( mRotation->referencedColumns().toSet() );
141  if ( mSizeScale.data() ) attributes.unite( mSizeScale->referencedColumns().toSet() );
142  return attributes.toList();
143 }
144 
146 {
147  return mSymbol.data();
148 }
149 
151 {
152  Q_ASSERT( s );
153  mSymbol.reset( s );
154 }
155 
157 {
158  if ( mSymbol->type() == QgsSymbolV2::Marker )
159  {
160  QgsMarkerSymbolV2 * s = static_cast<QgsMarkerSymbolV2 *>( mSymbol.data() );
161  s->setDataDefinedAngle( QgsDataDefined( fieldOrExpression ) );
162  }
163 }
164 
166 {
167  if ( mSymbol->type() == QgsSymbolV2::Marker )
168  {
169  QgsMarkerSymbolV2 * s = static_cast<QgsMarkerSymbolV2 *>( mSymbol.data() );
170  QgsDataDefined ddAngle = s->dataDefinedAngle();
171  return ddAngle.useExpression() ? ddAngle.expressionString() : ddAngle.field();
172  }
173 
174  return QString();
175 }
176 
178 {
180 }
181 
183 {
185 }
186 
188 {
191 }
192 
194 {
195  return mSymbol.data() ? QString( "SINGLE: %1" ).arg( mSymbol->dump() ) : "";
196 }
197 
199 {
203  copyPaintEffect( r );
204  return r;
205 }
206 
208 {
209  QgsStringMap props;
210  QString errorMsg;
211  if ( mRotation.data() )
212  props[ "angle" ] = mRotation->expression();
213  if ( mSizeScale.data() )
214  props[ "scale" ] = mSizeScale->expression();
215 
216  QDomElement ruleElem = doc.createElement( "se:Rule" );
217  element.appendChild( ruleElem );
218 
219  QDomElement nameElem = doc.createElement( "se:Name" );
220  nameElem.appendChild( doc.createTextNode( "Single symbol" ) );
221  ruleElem.appendChild( nameElem );
222 
223  if ( mSymbol.data() ) mSymbol->toSld( doc, ruleElem, props );
224 }
225 
227 {
228  Q_UNUSED( context );
229  QgsSymbolV2List lst;
230  lst.append( mSymbol.data() );
231  return lst;
232 }
233 
234 
236 {
237  QDomElement symbolsElem = element.firstChildElement( "symbols" );
238  if ( symbolsElem.isNull() )
239  return NULL;
240 
241  QgsSymbolV2Map symbolMap = QgsSymbolLayerV2Utils::loadSymbols( symbolsElem );
242 
243  if ( !symbolMap.contains( "0" ) )
244  return NULL;
245 
246  QgsSingleSymbolRendererV2* r = new QgsSingleSymbolRendererV2( symbolMap.take( "0" ) );
247 
248  // delete symbols if there are any more
250 
251  QDomElement rotationElem = element.firstChildElement( "rotation" );
252  if ( !rotationElem.isNull() && !rotationElem.attribute( "field" ).isEmpty() )
253  {
254  convertSymbolRotation( r->mSymbol.data(), rotationElem.attribute( "field" ) );
255  }
256 
257  QDomElement sizeScaleElem = element.firstChildElement( "sizescale" );
258  if ( !sizeScaleElem.isNull() && !sizeScaleElem.attribute( "field" ).isEmpty() )
259  {
261  QgsSymbolLayerV2Utils::decodeScaleMethod( sizeScaleElem.attribute( "scalemethod" ) ),
262  sizeScaleElem.attribute( "field" ) );
263  }
264 
265  // TODO: symbol levels
266  return r;
267 }
268 
270 {
271  // XXX this renderer can handle only one Rule!
272 
273  // get the first Rule element
274  QDomElement ruleElem = element.firstChildElement( "Rule" );
275  if ( ruleElem.isNull() )
276  {
277  QgsDebugMsg( "no Rule elements found!" );
278  return NULL;
279  }
280 
281  QString label, description;
282  QgsSymbolLayerV2List layers;
283 
284  // retrieve the Rule element child nodes
285  QDomElement childElem = ruleElem.firstChildElement();
286  while ( !childElem.isNull() )
287  {
288  if ( childElem.localName() == "Name" )
289  {
290  // <se:Name> tag contains the rule identifier,
291  // so prefer title tag for the label property value
292  if ( label.isEmpty() )
293  label = childElem.firstChild().nodeValue();
294  }
295  else if ( childElem.localName() == "Description" )
296  {
297  // <se:Description> can contains a title and an abstract
298  QDomElement titleElem = childElem.firstChildElement( "Title" );
299  if ( !titleElem.isNull() )
300  {
301  label = titleElem.firstChild().nodeValue();
302  }
303 
304  QDomElement abstractElem = childElem.firstChildElement( "Abstract" );
305  if ( !abstractElem.isNull() )
306  {
307  description = abstractElem.firstChild().nodeValue();
308  }
309  }
310  else if ( childElem.localName() == "Abstract" )
311  {
312  // <sld:Abstract> (v1.0)
313  description = childElem.firstChild().nodeValue();
314  }
315  else if ( childElem.localName() == "Title" )
316  {
317  // <sld:Title> (v1.0)
318  label = childElem.firstChild().nodeValue();
319  }
320  else if ( childElem.localName().endsWith( "Symbolizer" ) )
321  {
322  // create symbol layers for this symbolizer
323  QgsSymbolLayerV2Utils::createSymbolLayerV2ListFromSld( childElem, geomType, layers );
324  }
325 
326  childElem = childElem.nextSiblingElement();
327  }
328 
329  if ( layers.size() == 0 )
330  return NULL;
331 
332  // now create the symbol
334  switch ( geomType )
335  {
336  case QGis::Line:
337  symbol = new QgsLineSymbolV2( layers );
338  break;
339 
340  case QGis::Polygon:
341  symbol = new QgsFillSymbolV2( layers );
342  break;
343 
344  case QGis::Point:
345  symbol = new QgsMarkerSymbolV2( layers );
346  break;
347 
348  default:
349  QgsDebugMsg( QString( "invalid geometry type: found %1" ).arg( geomType ) );
350  return NULL;
351  }
352 
353  // and finally return the new renderer
354  return new QgsSingleSymbolRendererV2( symbol );
355 }
356 
358 {
359  QDomElement rendererElem = doc.createElement( RENDERER_TAG_NAME );
360  rendererElem.setAttribute( "type", "singleSymbol" );
361  rendererElem.setAttribute( "symbollevels", ( mUsingSymbolLevels ? "1" : "0" ) );
362  rendererElem.setAttribute( "forceraster", ( mForceRaster ? "1" : "0" ) );
363 
365  symbols["0"] = mSymbol.data();
366  QDomElement symbolsElem = QgsSymbolLayerV2Utils::saveSymbols( symbols, "symbols", doc );
367  rendererElem.appendChild( symbolsElem );
368 
369  QDomElement rotationElem = doc.createElement( "rotation" );
370  if ( mRotation.data() )
372  rendererElem.appendChild( rotationElem );
373 
374  QDomElement sizeScaleElem = doc.createElement( "sizescale" );
375  if ( mSizeScale.data() )
377  sizeScaleElem.setAttribute( "scalemethod", QgsSymbolLayerV2Utils::encodeScaleMethod( mScaleMethod ) );
378  rendererElem.appendChild( sizeScaleElem );
379 
380  if ( mPaintEffect )
381  mPaintEffect->saveProperties( doc, rendererElem );
382 
383  return rendererElem;
384 }
385 
387 {
389  if ( mSymbol.data() )
390  {
392  lst << qMakePair( QString(), pix );
393  }
394  return lst;
395 }
396 
398 {
399  Q_UNUSED( scaleDenominator );
400  Q_UNUSED( rule );
402  lst << qMakePair( QString(), mSymbol.data() );
403  return lst;
404 }
405 
407 {
409  if ( mSymbol->type() == QgsSymbolV2::Marker )
410  {
411  const QgsMarkerSymbolV2 * symbol = static_cast<const QgsMarkerSymbolV2 *>( mSymbol.data() );
412  QgsDataDefined sizeDD = symbol->dataDefinedSize();
413  if ( sizeDD.isActive() && sizeDD.useExpression() )
414  {
415  QgsScaleExpression scaleExp( sizeDD.expressionString() );
416  if ( scaleExp.type() != QgsScaleExpression::Unknown )
417  {
418  QgsLegendSymbolItemV2 title( NULL, scaleExp.baseExpression(), 0 );
419  lst << title;
420  foreach ( double v, QgsSymbolLayerV2Utils::prettyBreaks( scaleExp.minValue(), scaleExp.maxValue(), 4 ) )
421  {
423  QgsMarkerSymbolV2 * s = static_cast<QgsMarkerSymbolV2 *>( si.symbol() );
424  s->setDataDefinedSize( 0 );
425  s->setSize( scaleExp.size( v ) );
426  lst << si;
427  }
428  return lst;
429  }
430  }
431  }
432 
433  lst << QgsLegendSymbolItemV2( mSymbol.data(), QString(), 0 );
434  return lst;
435 }
436 
438 {
439  if ( renderer->type() == "singleSymbol" )
440  {
441  return dynamic_cast<QgsSingleSymbolRendererV2*>( renderer->clone() );
442  }
443  if ( renderer->type() == "pointDisplacement" )
444  {
445  const QgsPointDisplacementRenderer* pointDisplacementRenderer = dynamic_cast<const QgsPointDisplacementRenderer*>( renderer );
446  if ( pointDisplacementRenderer )
447  return convertFromRenderer( pointDisplacementRenderer->embeddedRenderer() );
448  }
449  if ( renderer->type() == "invertedPolygonRenderer" )
450  {
451  const QgsInvertedPolygonRenderer* invertedPolygonRenderer = dynamic_cast<const QgsInvertedPolygonRenderer*>( renderer );
452  if ( invertedPolygonRenderer )
453  return convertFromRenderer( invertedPolygonRenderer->embeddedRenderer() );
454  }
455 
456  QgsRenderContext context;
457  QgsSymbolV2List symbols = const_cast<QgsFeatureRendererV2 *>( renderer )->symbols( context );
458  if ( symbols.size() > 0 )
459  {
460  return new QgsSingleSymbolRendererV2( symbols.at( 0 )->clone() );
461  }
462  return 0;
463 }
static QgsSymbolV2Map loadSymbols(QDomElement &element)
#define RENDERER_TAG_NAME
Definition: qgsrendererv2.h:48
void setDataDefinedAngle(const QgsDataDefined &dd)
Set data defined angle for whole symbol (including all symbol layers).
A container class for data source field mapping or expression.
static QList< double > prettyBreaks(double minimum, double maximum, int classes)
Computes a sequence of about 'classes' equally spaced round values which cover the range of values fr...
bool contains(const Key &key) const
QDomNode appendChild(const QDomNode &newChild)
virtual QDomElement save(QDomDocument &doc) override
store renderer info to XML element
virtual void stopRender(QgsRenderContext &context) override
QString attribute(const QString &name, const QString &defValue) const
QString field() const
Get the field which this QgsDataDefined represents.
QString nodeValue() const
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
void setDataDefinedSize(const QgsDataDefined &dd)
Set data defined size for whole symbol (including all symbol layers).
Class storing parameters of a scale expression, which is a subclass of QgsExpression for expressions ...
QgsDataDefined dataDefinedSize() const
Returns data defined size for whole symbol (including all symbol layers).
void setSizeScaleField(QString fieldOrExpression)
static QgsFeatureRendererV2 * createFromSld(QDomElement &element, QGis::GeometryType geomType)
const T & at(int i) const
QgsSymbolV2::ScaleMethod scaleMethod() const
QDomElement nextSiblingElement(const QString &tagName) const
Container of fields for a vector layer.
Definition: qgsfield.h:177
static QgsSingleSymbolRendererV2 * convertFromRenderer(const QgsFeatureRendererV2 *renderer)
creates a QgsSingleSymbolRendererV2 from an existing renderer.
QString expressionString() const
Returns the expression string of this QgsDataDefined.
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:162
virtual QgsSymbolV2 * symbolForFeature(QgsFeature &feature, QgsRenderContext &context) override
To be overridden.
virtual QgsFeatureRendererV2 * clone() const override
QgsPaintEffect * mPaintEffect
QgsSymbolV2::ScaleMethod mScaleMethod
void setWidth(double width)
int size() const
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)
void reset(T *other)
QString type() const
Definition: qgsrendererv2.h:82
static bool createSymbolLayerV2ListFromSld(QDomElement &element, QGis::GeometryType geomType, QgsSymbolLayerV2List &layers)
virtual QgsFeatureRendererV2 * clone() const =0
QString number(int n, int base)
void append(const T &value)
QString localName() const
QgsInvertedPolygonRenderer is a polygon-only feature renderer used to display features inverted...
void setAttribute(const QString &name, const QString &value)
#define DEFAULT_SCALE_METHOD
static QDomElement saveSymbols(QgsSymbolV2Map &symbols, QString tagName, QDomDocument &doc)
bool isEmpty() const
QgsSingleSymbolRendererV2(QgsSymbolV2 *symbol)
void setAngle(double angle)
virtual QList< QString > usedAttributes() override
void setSize(double size)
bool endsWith(const QString &s, Qt::CaseSensitivity cs) const
virtual Q_DECL_DEPRECATED QgsSymbolV2List symbols()
for symbol levels
QScopedPointer< QgsExpression > mSizeScale
static void convertSymbolSizeScale(QgsSymbolV2 *symbol, QgsSymbolV2::ScaleMethod method, const QString &field)
QgsFeatureRendererV2 * embeddedRenderer() const
bool useExpression() const
Returns if the field or the expression part is active.
QDomText createTextNode(const QString &value)
T * data() const
virtual QgsLegendSymbologyList legendSymbologyItems(QSize iconSize) override
return a list of symbology items for the legend
virtual QString dump() const override
for debugging
QgsExpressionContext & expressionContext()
Gets the expression context.
A renderer that automatically displaces points with the same position.
bool isNull() const
void setUsingSymbolLevels(bool usingSymbolLevels)
virtual bool saveProperties(QDomDocument &doc, QDomElement &element) const
Saves the current state of the effect to a DOM element.
Q_DECL_DEPRECATED 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
virtual QgsSymbolV2 * originalSymbolForFeature(QgsFeature &feature, QgsRenderContext &context) override
Return symbol for feature.
QDomNode firstChild() const
QgsDataDefined dataDefinedAngle() const
Returns data defined angle for whole symbol (including all symbol layers).
void copyPaintEffect(QgsFeatureRendererV2 *destRenderer) const
Copies paint effect of this renderer to another renderer.
QSet< T > & unite(const QSet< T > &other)
static QgsExpression * fieldOrExpressionToExpression(const QString &fieldOrExpression)
Return a new valid expression instance for given field or expression string.
virtual QgsLegendSymbolList legendSymbolItems(double scaleDenominator=-1, QString rule=QString()) override
return a list of item text / symbol
static QString encodeScaleMethod(QgsSymbolV2::ScaleMethod scaleMethod)
QDomElement firstChildElement(const QString &tagName) const
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)
QList< T > toList() const
static void clearSymbolMap(QgsSymbolV2Map &symbols)
static QgsSymbolV2::ScaleMethod decodeScaleMethod(QString str)
static QgsFeatureRendererV2 * create(QDomElement &element)
create renderer from XML element
QDomElement createElement(const QString &tagName)
static QPixmap symbolPreviewPixmap(QgsSymbolV2 *symbol, QSize size, QgsRenderContext *customContext=0)
virtual void startRender(QgsRenderContext &context, const QgsFields &fields) override
Needs to be called when a new render cycle is started.
The class stores information about one class/rule of a vector layer renderer in a unified way that ca...
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
QScopedPointer< QgsSymbolV2 > mTempSymbol
bool isActive() const
T take(const Key &key)
void setScaleMethod(QgsSymbolV2::ScaleMethod scaleMethod)
Q_DECL_DEPRECATED void setRotationField(QString fieldOrExpression) override
sets rotation field of renderer (if supported by the renderer)
QScopedPointer< QgsExpression > mRotation
static void convertSymbolRotation(QgsSymbolV2 *symbol, const QString &field)
virtual QgsLegendSymbolListV2 legendSymbolItemsV2() const override
Return a list of symbology items for the legend.