QGIS API Documentation  2.8.2-Wien
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
qgspiediagram.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgspiediagram.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 "qgspiediagram.h"
16 #include "qgsdiagramrendererv2.h"
17 #include "qgsrendercontext.h"
18 #include "qgsexpression.h"
19 
20 #include <QPainter>
21 
22 
24 {
25  mCategoryBrush.setStyle( Qt::SolidPattern );
26  mPen.setStyle( Qt::SolidLine );
27 }
28 
30 {
31 }
32 
34 {
35  return new QgsPieDiagram( *this );
36 }
37 
39 {
40  Q_UNUSED( c );
41 
42  QVariant attrVal;
44  {
46  attrVal = expression->evaluate( feature );
47  }
48  else
49  {
50  attrVal = feature.attributes()[is.classificationAttribute];
51  }
52 
53  if ( !attrVal.isValid() )
54  {
55  return QSizeF(); //zero size if attribute is missing
56  }
57 
58  double scaledValue = attrVal.toDouble();
59  double scaledLowerValue = is.lowerValue;
60  double scaledUpperValue = is.upperValue;
61  double scaledLowerSizeWidth = is.lowerSize.width();
62  double scaledLowerSizeHeight = is.lowerSize.height();
63  double scaledUpperSizeWidth = is.upperSize.width();
64  double scaledUpperSizeHeight = is.upperSize.height();
65 
66  // interpolate the squared value if scale by area
67  if ( s.scaleByArea )
68  {
69  scaledValue = sqrt( scaledValue );
70  scaledLowerValue = sqrt( scaledLowerValue );
71  scaledUpperValue = sqrt( scaledUpperValue );
72  scaledLowerSizeWidth = sqrt( scaledLowerSizeWidth );
73  scaledLowerSizeHeight = sqrt( scaledLowerSizeHeight );
74  scaledUpperSizeWidth = sqrt( scaledUpperSizeWidth );
75  scaledUpperSizeHeight = sqrt( scaledUpperSizeHeight );
76  }
77 
78  //interpolate size
79  double scaledRatio = ( scaledValue - scaledLowerValue ) / ( scaledUpperValue - scaledLowerValue );
80 
81  QSizeF size = QSizeF( is.upperSize.width() * scaledRatio + is.lowerSize.width() * ( 1 - scaledRatio ),
82  is.upperSize.height() * scaledRatio + is.lowerSize.height() * ( 1 - scaledRatio ) );
83 
84  // Scale, if extension is smaller than the specified minimum
85  if ( size.width() <= s.minimumSize && size.height() <= s.minimumSize )
86  {
87  bool p = false; // preserve height == width
88  if ( size.width() == size.height() )
89  p = true;
90 
91  size.scale( s.minimumSize, s.minimumSize, Qt::KeepAspectRatio );
92 
93  // If height == width, recover here (overwrite floating point errors)
94  if ( p )
95  size.setWidth( size.height() );
96  }
97 
98  return size;
99 }
100 
101 QSizeF QgsPieDiagram::diagramSize( const QgsAttributes& attributes, const QgsRenderContext& c, const QgsDiagramSettings& s )
102 {
103  Q_UNUSED( c );
104  Q_UNUSED( attributes );
105  return s.size;
106 }
107 
108 int QgsPieDiagram::sCount = 0;
109 
110 void QgsPieDiagram::renderDiagram( const QgsFeature& feature, QgsRenderContext& c, const QgsDiagramSettings& s, const QPointF& position )
111 {
112  QPainter* p = c.painter();
113  if ( !p )
114  {
115  return;
116  }
117 
118  //get sum of values
119  QList<double> values;
120  double currentVal = 0;
121  double valSum = 0;
122  int valCount = 0;
123 
124  QList<QString>::const_iterator catIt = s.categoryAttributes.constBegin();
125  for ( ; catIt != s.categoryAttributes.constEnd(); ++catIt )
126  {
127  QgsExpression* expression = getExpression( *catIt, feature.fields() );
128  currentVal = expression->evaluate( feature ).toDouble();
129  values.push_back( currentVal );
130  valSum += currentVal;
131  if ( currentVal ) valCount++;
132  }
133 
134  //draw the slices
135  double totalAngle = 0;
136  double currentAngle;
137 
138  //convert from mm / map units to painter units
139  QSizeF spu = sizePainterUnits( s.size, s, c );
140  double w = spu.width();
141  double h = spu.height();
142 
143  double baseX = position.x();
144  double baseY = position.y() - h;
145 
146  mPen.setColor( s.penColor );
147  setPenWidth( mPen, s, c );
148  p->setPen( mPen );
149 
150  // there are some values > 0 available
151  if ( valSum > 0 )
152  {
153  QList<double>::const_iterator valIt = values.constBegin();
154  QList< QColor >::const_iterator colIt = s.categoryColors.constBegin();
155  for ( ; valIt != values.constEnd(); ++valIt, ++colIt )
156  {
157  if ( *valIt )
158  {
159  currentAngle = *valIt / valSum * 360 * 16;
160  mCategoryBrush.setColor( *colIt );
161  p->setBrush( mCategoryBrush );
162  // if only 1 value is > 0, draw a circle
163  if ( valCount == 1 )
164  {
165  p->drawEllipse( baseX, baseY, w, h );
166  }
167  else
168  {
169  p->drawPie( baseX, baseY, w, h, totalAngle + s.angleOffset, currentAngle );
170  }
171  totalAngle += currentAngle;
172  }
173  }
174  }
175  else // valSum > 0
176  {
177  // draw empty circle if no values are defined at all
178  mCategoryBrush.setColor( Qt::transparent );
179  p->setBrush( mCategoryBrush );
180  p->drawEllipse( baseX, baseY, w, h );
181  }
182 }