QGIS API Documentation  2.8.2-Wien
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups 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 }