Quantum GIS API Documentation  1.7.5-Wroclaw
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
qgsdiagram.cpp
Go to the documentation of this file.
1 #include "qgsdiagram.h"
2 #include "qgsdiagramrendererv2.h"
3 #include "qgsrendercontext.h"
4 
5 #include <QPainter>
6 
7 void QgsDiagram::setPenWidth( QPen& pen, const QgsDiagramSettings& s, const QgsRenderContext& c )
8 {
10  {
11  pen.setWidthF( s.penWidth * c.scaleFactor() );
12  }
13  else
14  {
15  pen.setWidthF( s.penWidth / c.mapToPixel().mapUnitsPerPixel() );
16  }
17 }
18 
19 QSizeF QgsDiagram::sizePainterUnits( const QSizeF& size, const QgsDiagramSettings& s, const QgsRenderContext& c )
20 {
22  {
23  return QSizeF( s.size.width() * c.scaleFactor(), s.size.height() * c.scaleFactor() );
24  }
25  else
26  {
27  return QSizeF( s.size.width() / c.mapToPixel().mapUnitsPerPixel(), s.size.height() / c.mapToPixel().mapUnitsPerPixel() );
28  }
29 }
30 
32 {
33  QFont f = s.font;
35  {
36  f.setPixelSize( s.font.pointSizeF() * 0.376 * c.scaleFactor() );
37  }
38  else
39  {
40  f.setPixelSize( s.font.pointSizeF() / c.mapToPixel().mapUnitsPerPixel() );
41  }
42 
43  return f;
44 }
45 
46 QgsTextDiagram::QgsTextDiagram(): mOrientation( Vertical ), mShape( Circle )
47 {
48  mPen.setWidthF( 2.0 );
49  mPen.setColor( QColor( 0, 0, 0 ) );
50  mPen.setCapStyle( Qt::FlatCap );
51  mBrush.setStyle( Qt::SolidPattern );
52 }
53 
55 {
56 }
57 
58 void QgsTextDiagram::renderDiagram( const QgsAttributeMap& att, QgsRenderContext& c, const QgsDiagramSettings& s, const QPointF& position )
59 {
60  QPainter* p = c.painter();
61  if ( !p )
62  {
63  return;
64  }
65 
66  double scaleDenominator = c.rendererScale();
67  if (( s.minScaleDenominator != -1 && scaleDenominator < s.minScaleDenominator )
68  || ( s.maxScaleDenominator != -1 && scaleDenominator > s.maxScaleDenominator ) )
69  {
70  return;
71  }
72 
73  //convert from mm / map units to painter units
74  QSizeF spu = sizePainterUnits( s.size, s, c );
75  double w = spu.width();
76  double h = spu.height();
77 
78  double baseX = position.x();
79  double baseY = position.y() - h;
80 
81  QList<QPointF> textPositions; //midpoints for text placement
82  int nCategories = s.categoryIndices.size();
83  for ( int i = 0; i < nCategories; ++i )
84  {
85  if ( mOrientation == Horizontal )
86  {
87  textPositions.push_back( QPointF( baseX + ( w / nCategories ) * i + w / nCategories / 2.0 , baseY + h / 2.0 ) );
88  }
89  else //vertical
90  {
91  textPositions.push_back( QPointF( baseX + w / 2.0, baseY + h / nCategories * i + w / nCategories / 2.0 ) );
92  }
93  }
94 
95  mPen.setColor( s.penColor );
96  setPenWidth( mPen, s, c );
97  p->setPen( mPen );
98  mBrush.setColor( s.backgroundColor );
99  p->setBrush( mBrush );
100 
101  //draw shapes and separator lines first
102  if ( mShape == Circle )
103  {
104  p->drawEllipse( baseX, baseY, w, h );
105 
106  //draw separator lines
107  QList<QPointF> intersect; //intersections between shape and separation lines
108  QPointF center( baseX + w / 2.0, baseY + h / 2.0 );
109  double r1 = w / 2.0; double r2 = h / 2.0;
110 
111  for ( int i = 1; i < nCategories; ++i )
112  {
113  if ( mOrientation == Horizontal )
114  {
115  lineEllipseIntersection( QPointF( baseX + w / nCategories * i, baseY ), QPointF( baseX + w / nCategories * i, baseY + h ), center, r1, r2, intersect );
116  }
117  else //vertical
118  {
119  lineEllipseIntersection( QPointF( baseX, baseY + h / nCategories * i ), QPointF( baseX + w, baseY + h / nCategories * i ), center, r1, r2, intersect );
120  }
121  if ( intersect.size() > 1 )
122  {
123  p->drawLine( intersect.at( 0 ), intersect.at( 1 ) );
124  }
125  }
126  }
127  else if ( mShape == Rectangle )
128  {
129  p->drawRect( QRectF( baseX, baseY, w, h ) );
130  for ( int i = 1; i < nCategories; ++i )
131  {
132  if ( mOrientation == Horizontal )
133  {
134  p->drawLine( QPointF( baseX + w / nCategories * i , baseY ), QPointF( baseX + w / nCategories * i, baseY + h ) );
135  }
136  else
137  {
138  p->drawLine( QPointF( baseX, baseY + h / nCategories * i ) , QPointF( baseX + w, baseY + h / nCategories * i ) );
139  }
140  }
141  }
142  else //triangle
143  {
144  QPolygonF triangle;
145  triangle << QPointF( baseX, baseY + h ) << QPointF( baseX + w, baseY + h ) << QPointF( baseX + w / 2.0, baseY );
146  p->drawPolygon( triangle );
147 
148  QLineF triangleEdgeLeft( baseX + w / 2.0, baseY, baseX, baseY + h );
149  QLineF triangleEdgeRight( baseX + w, baseY + h, baseX + w / 2.0, baseY );
150  QPointF intersectionPoint1, intersectionPoint2;
151 
152  for ( int i = 1; i < nCategories; ++i )
153  {
154  if ( mOrientation == Horizontal )
155  {
156  QLineF verticalLine( baseX + w / nCategories * i, baseY + h, baseX + w / nCategories * i, baseY );
157  if ( baseX + w / nCategories * i < baseX + w / 2.0 )
158  {
159  verticalLine.intersect( triangleEdgeLeft, &intersectionPoint1 );
160  }
161  else
162  {
163  verticalLine.intersect( triangleEdgeRight, &intersectionPoint1 );
164  }
165  p->drawLine( QPointF( baseX + w / nCategories * i, baseY + h ), intersectionPoint1 );
166  }
167  else //vertical
168  {
169  QLineF horizontalLine( baseX, baseY + h / nCategories * i, baseX + w, baseY + h / nCategories * i );
170  horizontalLine.intersect( triangleEdgeLeft, &intersectionPoint1 );
171  horizontalLine.intersect( triangleEdgeRight, &intersectionPoint2 );
172  p->drawLine( intersectionPoint1, intersectionPoint2 );
173  }
174  }
175  }
176 
177  //draw text
178  QFont sFont = scaledFont( s, c );
179  QFontMetricsF fontMetrics( sFont );
180  p->setFont( sFont );
181 
182  for ( int i = 0; i < textPositions.size(); ++i )
183  {
184  QString val = att[ s.categoryIndices.at( i )].toString();
185  //find out dimensions
186  double textHeight = fontMetrics.height();
187  double textWidth = fontMetrics.width( val );
188  mPen.setColor( s.categoryColors.at( i ) );
189  p->setPen( mPen );
190  QPointF position = textPositions.at( i );
191  p->drawText( QPointF( position.x() - textWidth / 2.0, position.y() + textHeight / 2.0 ), val );
192  }
193 }
194 
195 void QgsTextDiagram::lineEllipseIntersection( const QPointF& lineStart, const QPointF& lineEnd, const QPointF& ellipseMid, double r1, double r2, QList<QPointF>& result ) const
196 {
197  result.clear();
198 
199  double rrx = r1 * r1;
200  double rry = r2 * r2;
201  double x21 = lineEnd.x() - lineStart.x();
202  double y21 = lineEnd.y() - lineStart.y();
203  double x10 = lineStart.x() - ellipseMid.x();
204  double y10 = lineStart.y() - ellipseMid.y();
205  double a = x21 * x21 / rrx + y21 * y21 / rry;
206  double b = x21 * x10 / rrx + y21 * y10 / rry;
207  double c = x10 * x10 / rrx + y10 * y10 / rry;
208  double d = b * b - a * ( c - 1 );
209  if ( d > 0 )
210  {
211  double e = sqrt( d );
212  double u1 = ( -b - e ) / a;
213  double u2 = ( -b + e ) / a;
214  //work with a tolerance of 0.00001 because of limited numerical precision
215  if ( -0.00001 <= u1 && u1 < 1.00001 )
216  {
217  result.push_back( QPointF( lineStart.x() + x21 * u1, lineStart.y() + y21 * u1 ) );
218  }
219  if ( -0.00001 <= u2 && u2 <= 1.00001 )
220  {
221  result.push_back( QPointF( lineStart.x() + x21 * u2, lineStart.y() + y21 * u2 ) );
222  }
223  }
224 }
225 
227 {
228  mCategoryBrush.setStyle( Qt::SolidPattern );
229  mPen.setStyle( Qt::SolidLine );
230 }
231 
233 {
234 }
235 
236 void QgsPieDiagram::renderDiagram( const QgsAttributeMap& att, QgsRenderContext& c, const QgsDiagramSettings& s, const QPointF& position )
237 {
238  QPainter* p = c.painter();
239  if ( !p )
240  {
241  return;
242  }
243 
244  //get sum of values
245  QList<double> values;
246  double currentVal = 0;
247  double valSum = 0;
248 
249  QList<int>::const_iterator catIt = s.categoryIndices.constBegin();
250  for ( ; catIt != s.categoryIndices.constEnd(); ++catIt )
251  {
252  currentVal = att[*catIt].toDouble();
253  values.push_back( currentVal );
254  valSum += currentVal;
255  }
256 
257  //draw the slices
258  double totalAngle = 0;
259  double currentAngle;
260 
261  //convert from mm / map units to painter units
262  QSizeF spu = sizePainterUnits( s.size, s, c );
263  double w = spu.width();
264  double h = spu.height();
265 
266  double baseX = position.x();
267  double baseY = position.y() - h;
268 
269  mPen.setColor( s.penColor );
270  setPenWidth( mPen, s, c );
271  p->setPen( mPen );
272 
273  QList<double>::const_iterator valIt = values.constBegin();
274  QList< QColor >::const_iterator colIt = s.categoryColors.constBegin();
275  for ( ; valIt != values.constEnd(); ++valIt, ++colIt )
276  {
277  currentAngle = *valIt / valSum * 360 * 16;
278  mCategoryBrush.setColor( *colIt );
279  p->setBrush( mCategoryBrush );
280  p->drawPie( baseX, baseY, w, h, totalAngle, currentAngle );
281  totalAngle += currentAngle;
282  }
283 }