QGIS API Documentation  2.9.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
qgsdiagramrendererv2.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsdiagramrendererv2.cpp
3  ---------------------
4  begin : March 2011
5  copyright : (C) 2011 by Marco Hugentobler
6  email : marco dot hugentobler at sourcepole dot ch
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 #include "qgsdiagramrendererv2.h"
16 #include "qgsvectorlayer.h"
17 #include "diagram/qgstextdiagram.h"
18 #include "diagram/qgspiediagram.h"
20 #include "qgsrendercontext.h"
21 
22 #include <QDomElement>
23 #include <QPainter>
24 
26  : placement( AroundPoint )
27  , placementFlags( OnLine )
28  , priority( 5 )
29  , obstacle( false )
30  , dist( 0.0 )
31  , renderer( 0 )
32  , palLayer( 0 )
33  , ct( 0 )
34  , xform( 0 )
35  , xPosColumn( -1 )
36  , yPosColumn( -1 )
37  , showAll( true )
38 {
39 }
40 
42 {
43  delete renderer;
44 }
45 
46 void QgsDiagramLayerSettings::readXML( const QDomElement& elem, const QgsVectorLayer* layer )
47 {
48  Q_UNUSED( layer )
49 
50  placement = ( Placement )elem.attribute( "placement" ).toInt();
51  placementFlags = ( LinePlacementFlags )elem.attribute( "linePlacementFlags" ).toInt();
52  priority = elem.attribute( "priority" ).toInt();
53  obstacle = elem.attribute( "obstacle" ).toInt();
54  dist = elem.attribute( "dist" ).toDouble();
55  xPosColumn = elem.attribute( "xPosColumn" ).toInt();
56  yPosColumn = elem.attribute( "yPosColumn" ).toInt();
57  showAll = ( elem.attribute( "showAll", "0" ) != "0" );
58 }
59 
60 void QgsDiagramLayerSettings::writeXML( QDomElement& layerElem, QDomDocument& doc, const QgsVectorLayer* layer ) const
61 {
62  Q_UNUSED( layer )
63 
64  QDomElement diagramLayerElem = doc.createElement( "DiagramLayerSettings" );
65  diagramLayerElem.setAttribute( "placement", placement );
66  diagramLayerElem.setAttribute( "linePlacementFlags", placementFlags );
67  diagramLayerElem.setAttribute( "priority", priority );
68  diagramLayerElem.setAttribute( "obstacle", obstacle );
69  diagramLayerElem.setAttribute( "dist", QString::number( dist ) );
70  diagramLayerElem.setAttribute( "xPosColumn", xPosColumn );
71  diagramLayerElem.setAttribute( "yPosColumn", yPosColumn );
72  diagramLayerElem.setAttribute( "showAll", showAll );
73  layerElem.appendChild( diagramLayerElem );
74 }
75 
76 void QgsDiagramSettings::readXML( const QDomElement& elem, const QgsVectorLayer* layer )
77 {
78  Q_UNUSED( layer );
79 
80  enabled = ( elem.attribute( "enabled", "1" ) != "0" );
81  font.fromString( elem.attribute( "font" ) );
82  backgroundColor.setNamedColor( elem.attribute( "backgroundColor" ) );
83  backgroundColor.setAlpha( elem.attribute( "backgroundAlpha" ).toInt() );
84  size.setWidth( elem.attribute( "width" ).toDouble() );
85  size.setHeight( elem.attribute( "height" ).toDouble() );
86  transparency = elem.attribute( "transparency", "0" ).toInt();
87  penColor.setNamedColor( elem.attribute( "penColor" ) );
88  int penAlpha = elem.attribute( "penAlpha", "255" ).toInt();
89  penColor.setAlpha( penAlpha );
90  penWidth = elem.attribute( "penWidth" ).toDouble();
91 
92  minScaleDenominator = elem.attribute( "minScaleDenominator", "-1" ).toDouble();
93  maxScaleDenominator = elem.attribute( "maxScaleDenominator", "-1" ).toDouble();
94  if ( elem.hasAttribute( "scaleBasedVisibility" ) )
95  {
96  scaleBasedVisibility = ( elem.attribute( "scaleBasedVisibility", "1" ) != "0" );
97  }
98  else
99  {
101  }
102 
103  //mm vs map units
104  if ( elem.attribute( "sizeType" ) == "MM" )
105  {
106  sizeType = MM;
107  }
108  else
109  {
110  sizeType = MapUnits;
111  }
112 
113  //label placement method
114  if ( elem.attribute( "labelPlacementMethod" ) == "Height" )
115  {
117  }
118  else
119  {
121  }
122 
123  // orientation
124  if ( elem.attribute( "diagramOrientation" ) == "Left" )
125  {
127  }
128  else if ( elem.attribute( "diagramOrientation" ) == "Right" )
129  {
131  }
132  else if ( elem.attribute( "diagramOrientation" ) == "Down" )
133  {
135  }
136  else
137  {
139  }
140 
141  // scale dependency
142  if ( elem.attribute( "scaleDependency" ) == "Diameter" )
143  {
144  scaleByArea = false;
145  }
146  else
147  {
148  scaleByArea = true;
149  }
150 
151  barWidth = elem.attribute( "barWidth" ).toDouble();
152 
153  angleOffset = elem.attribute( "angleOffset" ).toInt();
154 
155  minimumSize = elem.attribute( "minimumSize" ).toDouble();
156 
157  //colors
158  categoryColors.clear();
159  QDomNodeList attributes = elem.elementsByTagName( "attribute" );
160 
161  if ( attributes.length() > 0 )
162  {
163  for ( uint i = 0; i < attributes.length(); i++ )
164  {
165  QDomElement attrElem = attributes.at( i ).toElement();
166  QColor newColor( attrElem.attribute( "color" ) );
167  newColor.setAlpha( 255 - transparency );
168  categoryColors.append( newColor );
169  categoryAttributes.append( attrElem.attribute( "field" ) );
170  }
171  }
172  else
173  {
174  // Restore old format attributes and colors
175 
176  QStringList colorList = elem.attribute( "colors" ).split( "/" );
177  QStringList::const_iterator colorIt = colorList.constBegin();
178  for ( ; colorIt != colorList.constEnd(); ++colorIt )
179  {
180  QColor newColor( *colorIt );
181  newColor.setAlpha( 255 - transparency );
182  categoryColors.append( QColor( newColor ) );
183  }
184 
185  //attribute indices
186  categoryAttributes.clear();
187  QStringList catList = elem.attribute( "categories" ).split( "/" );
188  QStringList::const_iterator catIt = catList.constBegin();
189  for ( ; catIt != catList.constEnd(); ++catIt )
190  {
191  categoryAttributes.append( *catIt );
192  }
193  }
194 }
195 
196 void QgsDiagramSettings::writeXML( QDomElement& rendererElem, QDomDocument& doc, const QgsVectorLayer* layer ) const
197 {
198  Q_UNUSED( layer );
199 
200  QDomElement categoryElem = doc.createElement( "DiagramCategory" );
201  categoryElem.setAttribute( "enabled", enabled );
202  categoryElem.setAttribute( "font", font.toString() );
203  categoryElem.setAttribute( "backgroundColor", backgroundColor.name() );
204  categoryElem.setAttribute( "backgroundAlpha", backgroundColor.alpha() );
205  categoryElem.setAttribute( "width", QString::number( size.width() ) );
206  categoryElem.setAttribute( "height", QString::number( size.height() ) );
207  categoryElem.setAttribute( "penColor", penColor.name() );
208  categoryElem.setAttribute( "penAlpha", penColor.alpha() );
209  categoryElem.setAttribute( "penWidth", QString::number( penWidth ) );
210  categoryElem.setAttribute( "scaleBasedVisibility", scaleBasedVisibility );
211  categoryElem.setAttribute( "minScaleDenominator", QString::number( minScaleDenominator ) );
212  categoryElem.setAttribute( "maxScaleDenominator", QString::number( maxScaleDenominator ) );
213  categoryElem.setAttribute( "transparency", QString::number( transparency ) );
214 
215  // site type (mm vs. map units)
216  if ( sizeType == MM )
217  {
218  categoryElem.setAttribute( "sizeType", "MM" );
219  }
220  else
221  {
222  categoryElem.setAttribute( "sizeType", "MapUnits" );
223  }
224 
225  // label placement method (text diagram)
226  if ( labelPlacementMethod == Height )
227  {
228  categoryElem.setAttribute( "labelPlacementMethod", "Height" );
229  }
230  else
231  {
232  categoryElem.setAttribute( "labelPlacementMethod", "XHeight" );
233  }
234 
235  if ( scaleByArea )
236  {
237  categoryElem.setAttribute( "scaleDependency", "Area" );
238  }
239  else
240  {
241  categoryElem.setAttribute( "scaleDependency", "Diameter" );
242  }
243 
244  // orientation (histogram)
245  switch ( diagramOrientation )
246  {
247  case Left:
248  categoryElem.setAttribute( "diagramOrientation", "Left" );
249  break;
250 
251  case Right:
252  categoryElem.setAttribute( "diagramOrientation", "Right" );
253  break;
254 
255  case Down:
256  categoryElem.setAttribute( "diagramOrientation", "Down" );
257  break;
258 
259  case Up:
260  categoryElem.setAttribute( "diagramOrientation", "Up" );
261  break;
262 
263  default:
264  categoryElem.setAttribute( "diagramOrientation", "Up" );
265  break;
266  }
267 
268  categoryElem.setAttribute( "barWidth", QString::number( barWidth ) );
269  categoryElem.setAttribute( "minimumSize", QString::number( minimumSize ) );
270  categoryElem.setAttribute( "angleOffset", QString::number( angleOffset ) );
271 
272  QString colors;
273  int nCats = qMin( categoryColors.size(), categoryAttributes.size() );
274  for ( int i = 0; i < nCats; ++i )
275  {
276  QDomElement attributeElem = doc.createElement( "attribute" );
277 
278  attributeElem.setAttribute( "field", categoryAttributes.at( i ) );
279  attributeElem.setAttribute( "color", categoryColors.at( i ).name() );
280  categoryElem.appendChild( attributeElem );
281  }
282 
283  rendererElem.appendChild( categoryElem );
284 }
285 
287  : mDiagram( 0 )
288 {
289 }
290 
292 {
293  delete mDiagram;
294 }
295 
297 {
298  delete mDiagram;
299  mDiagram = d;
300 }
301 
303  : mDiagram( other.mDiagram ? other.mDiagram->clone() : 0 )
304 {
305 }
306 
307 void QgsDiagramRendererV2::renderDiagram( const QgsFeature& feature, QgsRenderContext& c, const QPointF& pos )
308 {
309  if ( !mDiagram )
310  {
311  return;
312  }
313 
315  if ( !diagramSettings( feature, c, s ) )
316  {
317  return;
318  }
319 
320  mDiagram->renderDiagram( feature, c, s, pos );
321 }
322 
324 {
326  if ( !diagramSettings( feature, c, s ) )
327  {
328  return QSizeF();
329  }
330 
331  QSizeF size = diagramSize( feature, c );
332  if ( s.sizeType == QgsDiagramSettings::MM )
333  {
334  convertSizeToMapUnits( size, c );
335  }
336  return size;
337 }
338 
340 {
341  if ( !size.isValid() )
342  {
343  return;
344  }
345 
346  double pixelToMap = context.scaleFactor() * context.mapToPixel().mapUnitsPerPixel();
347  size.rwidth() *= pixelToMap;
348  size.rheight() *= pixelToMap;
349 }
350 
351 int QgsDiagramRendererV2::dpiPaintDevice( const QPainter* painter )
352 {
353  if ( painter )
354  {
355  QPaintDevice* device = painter->device();
356  if ( device )
357  {
358  return device->logicalDpiX();
359  }
360  }
361  return -1;
362 }
363 
364 void QgsDiagramRendererV2::_readXML( const QDomElement& elem, const QgsVectorLayer* layer )
365 {
366  Q_UNUSED( layer )
367 
368  delete mDiagram;
369  QString diagramType = elem.attribute( "diagramType" );
370  if ( diagramType == "Pie" )
371  {
372  mDiagram = new QgsPieDiagram();
373  }
374  else if ( diagramType == "Text" )
375  {
376  mDiagram = new QgsTextDiagram();
377  }
378  else if ( diagramType == "Histogram" )
379  {
381  }
382  else
383  {
384  mDiagram = 0;
385  }
386 }
387 
388 void QgsDiagramRendererV2::_writeXML( QDomElement& rendererElem, QDomDocument& doc, const QgsVectorLayer* layer ) const
389 {
390  Q_UNUSED( doc );
391  Q_UNUSED( layer )
392 
393  if ( mDiagram )
394  {
395  rendererElem.setAttribute( "diagramType", mDiagram->diagramName() );
396  }
397 }
398 
400 {
401 }
402 
404 {
405 }
406 
408 {
409  return new QgsSingleCategoryDiagramRenderer( *this );
410 }
411 
413 {
414  Q_UNUSED( c );
415  s = mSettings;
416  return true;
417 }
418 
420 {
421  return mDiagram->diagramSize( feature.attributes(), c, mSettings );
422 }
423 
424 QList<QgsDiagramSettings> QgsSingleCategoryDiagramRenderer::diagramSettings() const
425 {
426  QList<QgsDiagramSettings> settingsList;
427  settingsList.push_back( mSettings );
428  return settingsList;
429 }
430 
431 void QgsSingleCategoryDiagramRenderer::readXML( const QDomElement& elem, const QgsVectorLayer* layer )
432 {
433  QDomElement categoryElem = elem.firstChildElement( "DiagramCategory" );
434  if ( categoryElem.isNull() )
435  {
436  return;
437  }
438 
439  mSettings.readXML( categoryElem, layer );
440  _readXML( elem, layer );
441 }
442 
443 void QgsSingleCategoryDiagramRenderer::writeXML( QDomElement& layerElem, QDomDocument& doc, const QgsVectorLayer* layer ) const
444 {
445  QDomElement rendererElem = doc.createElement( "SingleCategoryDiagramRenderer" );
446  mSettings.writeXML( rendererElem, doc, layer );
447  _writeXML( rendererElem, doc, layer );
448  layerElem.appendChild( rendererElem );
449 }
450 
451 
453 {
454  mInterpolationSettings.classificationAttributeIsExpression = false;
455 }
456 
458 {
459 }
460 
462 {
463  return new QgsLinearlyInterpolatedDiagramRenderer( *this );
464 }
465 
467 {
468  QList<QgsDiagramSettings> settingsList;
469  settingsList.push_back( mSettings );
470  return settingsList;
471 }
472 
474 {
475  s = mSettings;
476  s.size = diagramSize( feature, c );
477  return true;
478 }
479 
481 {
482  return mSettings.categoryAttributes;
483 }
484 
486 {
487  return mDiagram->diagramSize( feature, c, mSettings, mInterpolationSettings );
488 }
489 
490 void QgsLinearlyInterpolatedDiagramRenderer::readXML( const QDomElement& elem, const QgsVectorLayer* layer )
491 {
492  mInterpolationSettings.lowerValue = elem.attribute( "lowerValue" ).toDouble();
493  mInterpolationSettings.upperValue = elem.attribute( "upperValue" ).toDouble();
494  mInterpolationSettings.lowerSize.setWidth( elem.attribute( "lowerWidth" ).toDouble() );
495  mInterpolationSettings.lowerSize.setHeight( elem.attribute( "lowerHeight" ).toDouble() );
496  mInterpolationSettings.upperSize.setWidth( elem.attribute( "upperWidth" ).toDouble() );
497  mInterpolationSettings.upperSize.setHeight( elem.attribute( "upperHeight" ).toDouble() );
498  mInterpolationSettings.classificationAttributeIsExpression = elem.hasAttribute( "classificationAttributeExpression" );
499  if ( mInterpolationSettings.classificationAttributeIsExpression )
500  {
501  mInterpolationSettings.classificationAttributeExpression = elem.attribute( "classificationAttributeExpression" );
502  }
503  else
504  {
505  mInterpolationSettings.classificationAttribute = elem.attribute( "classificationAttribute" ).toInt();
506  }
507  QDomElement settingsElem = elem.firstChildElement( "DiagramCategory" );
508  if ( !settingsElem.isNull() )
509  {
510  mSettings.readXML( settingsElem, layer );
511  }
512  _readXML( elem, layer );
513 }
514 
515 void QgsLinearlyInterpolatedDiagramRenderer::writeXML( QDomElement& layerElem, QDomDocument& doc, const QgsVectorLayer* layer ) const
516 {
517  QDomElement rendererElem = doc.createElement( "LinearlyInterpolatedDiagramRenderer" );
518  rendererElem.setAttribute( "lowerValue", QString::number( mInterpolationSettings.lowerValue ) );
519  rendererElem.setAttribute( "upperValue", QString::number( mInterpolationSettings.upperValue ) );
520  rendererElem.setAttribute( "lowerWidth", QString::number( mInterpolationSettings.lowerSize.width() ) );
521  rendererElem.setAttribute( "lowerHeight", QString::number( mInterpolationSettings.lowerSize.height() ) );
522  rendererElem.setAttribute( "upperWidth", QString::number( mInterpolationSettings.upperSize.width() ) );
523  rendererElem.setAttribute( "upperHeight", QString::number( mInterpolationSettings.upperSize.height() ) );
524  if ( mInterpolationSettings.classificationAttributeIsExpression )
525  {
526  rendererElem.setAttribute( "classificationAttributeExpression", mInterpolationSettings.classificationAttributeExpression );
527  }
528  else
529  {
530  rendererElem.setAttribute( "classificationAttribute", mInterpolationSettings.classificationAttribute );
531  }
532  mSettings.writeXML( rendererElem, doc, layer );
533  _writeXML( rendererElem, doc, layer );
534  layerElem.appendChild( rendererElem );
535 }
double minimumSize
Scale diagrams smaller than mMinimumSize to mMinimumSize.
void writeXML(QDomElement &layerElem, QDomDocument &doc, const QgsVectorLayer *layer) const override
QgsDiagramRendererV2 * clone() const override
Returns new instance that is equivalent to this one.
void _readXML(const QDomElement &elem, const QgsVectorLayer *layer)
QList< QString > categoryAttributes
virtual QList< QgsDiagramSettings > diagramSettings() const =0
Returns list with all diagram settings in the renderer.
static int dpiPaintDevice(const QPainter *)
Returns the paint device dpi (or -1 in case of error.
void renderDiagram(const QgsFeature &feature, QgsRenderContext &c, const QPointF &pos)
double scaleFactor() const
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:113
virtual Q_DECL_DEPRECATED void renderDiagram(const QgsAttributes &att, QgsRenderContext &c, const QgsDiagramSettings &s, const QPointF &position)
Definition: qgsdiagram.cpp:110
void readXML(const QDomElement &elem, const QgsVectorLayer *layer)
QList< QgsDiagramSettings > diagramSettings() const override
Returns list with all diagram settings in the renderer.
Returns diagram settings for a feature.
virtual QSizeF diagramSize(const QgsFeature &features, const QgsRenderContext &c)=0
Returns size of the diagram (in painter units) or an invalid size in case of error.
void convertSizeToMapUnits(QSizeF &size, const QgsRenderContext &context) const
Converts size from mm to map units.
DiagramOrientation diagramOrientation
void readXML(const QDomElement &elem, const QgsVectorLayer *layer) override
virtual QSizeF sizeMapUnits(const QgsFeature &feature, const QgsRenderContext &c)
Returns size of the diagram for a feature in map units.
void readXML(const QDomElement &elem, const QgsVectorLayer *layer)
const QgsAttributes & attributes() const
Definition: qgsfeature.h:142
double mapUnitsPerPixel() const
Return current map units per pixel.
QgsDiagramRendererV2 * renderer
virtual QSizeF diagramSize(const QgsAttributes &attributes, const QgsRenderContext &c, const QgsDiagramSettings &s)=0
Returns the size in map units the diagram will use to render.
Base class for all diagram types.
Definition: qgsdiagram.h:34
virtual QString diagramName() const =0
void writeXML(QDomElement &layerElem, QDomDocument &doc, const QgsVectorLayer *layer) const override
void readXML(const QDomElement &elem, const QgsVectorLayer *layer) override
Contains information about the context of a rendering operation.
QList< QString > diagramAttributes() const override
Returns attribute indices needed for diagram rendering.
void writeXML(QDomElement &layerElem, QDomDocument &doc, const QgsVectorLayer *layer) const
QgsDiagramRendererV2 * clone() const override
Returns new instance that is equivalent to this one.
const QgsMapToPixel & mapToPixel() const
int classificationAttribute
Index of the classification attribute.
void setDiagram(QgsDiagram *d)
QSizeF diagramSize(const QgsFeature &, const QgsRenderContext &c) override
Returns size of the diagram (in painter units) or an invalid size in case of error.
Represents a vector layer which manages a vector based data sets.
double size
Definition: qgssvgcache.cpp:77
QList< QColor > categoryColors
void writeXML(QDomElement &rendererElem, QDomDocument &doc, const QgsVectorLayer *layer) const
QgsDiagram * mDiagram
Reference to the object that does the real diagram rendering.
QList< QgsDiagramSettings > diagramSettings() const override
Returns list with all diagram settings in the renderer.
void _writeXML(QDomElement &rendererElem, QDomDocument &doc, const QgsVectorLayer *layer) const
LabelPlacementMethod labelPlacementMethod
QSizeF diagramSize(const QgsFeature &, const QgsRenderContext &c) override
Returns size of the diagram (in painter units) or an invalid size in case of error.