KD Chart 2  [rev.2.5.1]
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Pages
KDChartNormalLyingBarDiagram_p.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 ** Copyright (C) 2001-2013 Klaralvdalens Datakonsult AB. All rights reserved.
3 **
4 ** This file is part of the KD Chart library.
5 **
6 ** Licensees holding valid commercial KD Chart licenses may use this file in
7 ** accordance with the KD Chart Commercial License Agreement provided with
8 ** the Software.
9 **
10 **
11 ** This file may be distributed and/or modified under the terms of the
12 ** GNU General Public License version 2 and version 3 as published by the
13 ** Free Software Foundation and appearing in the file LICENSE.GPL.txt included.
14 **
15 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
16 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
17 **
18 ** Contact info@kdab.com if any conditions of this licensing are not
19 ** clear to you.
20 **
21 **********************************************************************/
22 
23 #include "KDChartNormalLyingBarDiagram_p.h"
24 
25 #include <QModelIndex>
26 
27 #include "KDChartBarDiagram.h"
28 #include "KDChartTextAttributes.h"
29 #include "KDChartAttributesModel.h"
31 
32 using namespace KDChart;
33 using namespace std;
34 
35 NormalLyingBarDiagram::NormalLyingBarDiagram( BarDiagram* d )
36  : BarDiagramType( d )
37 {
38 }
39 
40 BarDiagram::BarType NormalLyingBarDiagram::type() const
41 {
42  return BarDiagram::Normal;
43 }
44 
45 // TODO there is a lot of duplication between this and the non-lying bar diagram, fix it someday...
46 const QPair<QPointF, QPointF> NormalLyingBarDiagram::calculateDataBoundaries() const
47 {
48  const int rowCount = compressor().modelDataRows();
49  const int colCount = compressor().modelDataColumns();
50 
51  qreal xMin = 0.0;
52  qreal xMax = rowCount;
53  qreal yMin = 0.0;
54  qreal yMax = 0.0;
55 
56  bool isFirst = true;
57  for ( int column = 0; column < colCount; ++column ) {
58  for ( int row = 0; row < rowCount; ++row ) {
59  const CartesianDiagramDataCompressor::CachePosition position( row, column );
60  const CartesianDiagramDataCompressor::DataPoint point = compressor().data( position );
61  const qreal value = ISNAN( point.value ) ? 0.0 : point.value;
62  // this is always true yMin can be 0 in case all values
63  // are the same
64  // same for yMax it can be zero if all values are negative
65  if ( isFirst ) {
66  yMin = value;
67  yMax = value;
68  isFirst = false;
69  } else {
70  yMin = qMin( yMin, value );
71  yMax = qMax( yMax, value );
72  }
73  }
74  }
75 
76  // special cases
77  if ( yMax == yMin ) {
78  if ( yMin == 0.0 ) {
79  yMax = 0.1; // we need at least a range
80  } else if ( yMax < 0.0 ) {
81  yMax = 0.0; // they are the same and negative
82  } else if ( yMin > 0.0 ) {
83  yMin = 0.0; // they are the same but positive
84  }
85  }
86  const QPointF bottomLeft( QPointF( yMin, xMin ) );
87  const QPointF topRight( QPointF( yMax, xMax ) );
88 
89  return QPair< QPointF, QPointF >( bottomLeft, topRight );
90 }
91 
92 void NormalLyingBarDiagram::paint( PaintContext* ctx )
93 {
94  // FIXME: in all LyingBarDiagram types, the datasets are rendered top to bottom, but the abscissa
95  // (in that case Y axis) ticks are still bottom to top. So tick labels are in reverse order.
96  reverseMapper().clear();
97 
98  const QPair<QPointF,QPointF> boundaries = diagram()->dataBoundaries(); // cached
99 
100  const QPointF boundLeft = ctx->coordinatePlane()->translate( boundaries.first ) ;
101  const QPointF boundRight = ctx->coordinatePlane()->translate( boundaries.second );
102 
103  const int rowCount = attributesModel()->rowCount( attributesModelRootIndex() );
104  const int colCount = attributesModel()->columnCount( attributesModelRootIndex() );
105 
106  BarAttributes ba = diagram()->barAttributes();
107  qreal barWidth = 0;
108  qreal maxDepth = 0;
109  qreal width = boundLeft.y() - boundRight.y();
110  qreal groupWidth = width / rowCount;
111  qreal spaceBetweenBars = 0;
112  qreal spaceBetweenGroups = 0;
113 
114  if ( ba.useFixedBarWidth() ) {
115 
116  barWidth = ba.fixedBarWidth();
117  groupWidth += barWidth;
118 
119  // Pending Michel set a min and max value for the groupWidth
120  // related to the area.width
121  if ( groupWidth < 0 )
122  groupWidth = 0;
123 
124  if ( groupWidth * rowCount > width )
125  groupWidth = width / rowCount;
126  }
127 
128  // maxLimit: allow the space between bars to be larger until area.width()
129  // is covered by the groups.
130  qreal maxLimit = rowCount * ( groupWidth + ( colCount - 1 ) * ba.fixedDataValueGap() );
131 
132  //Pending Michel: FixMe
133  if ( ba.useFixedDataValueGap() ) {
134  if ( width > maxLimit )
135  spaceBetweenBars += ba.fixedDataValueGap();
136  else
137  spaceBetweenBars = ( width / rowCount - groupWidth ) / ( colCount - 1 );
138  }
139 
140  if ( ba.useFixedValueBlockGap() ) {
141  spaceBetweenGroups += ba.fixedValueBlockGap();
142  }
143 
144  calculateValueAndGapWidths( rowCount, colCount,groupWidth,
145  barWidth, spaceBetweenBars, spaceBetweenGroups );
146 
147  LabelPaintCache lpc;
148 
149  for ( int row = 0; row < rowCount; row++ ) {
150  qreal offset = -groupWidth / 2 + spaceBetweenGroups / 2;
151 
152  if ( ba.useFixedDataValueGap() ) {
153  if ( spaceBetweenBars > 0 ) {
154  if ( width > maxLimit ) {
155  offset -= ba.fixedDataValueGap();
156  } else {
157  offset -= ( width / rowCount - groupWidth ) / ( colCount - 1 );
158  }
159  } else {
160  offset += barWidth / 2;
161  }
162  }
163 
164  for ( int column = 0; column < colCount; column++ ) {
165  // paint one group
166  const CartesianDiagramDataCompressor::CachePosition position( row, column );
167  const CartesianDiagramDataCompressor::DataPoint point = compressor().data( position );
168  const QModelIndex sourceIndex = attributesModel()->mapToSource( point.index );
169  const qreal value = point.value;//attributesModel()->data( sourceIndex ).toReal();
170  QPointF topPoint = ctx->coordinatePlane()->translate( QPointF( value, rowCount - ( point.key + 0.5 ) ) );
171  QPointF bottomPoint = ctx->coordinatePlane()->translate( QPointF( 0, rowCount - point.key ) );
172  const qreal barHeight = topPoint.x() - bottomPoint.x();
173  topPoint.ry() += offset;
174  topPoint.rx() -= barHeight;
175  const QRectF rect( topPoint, QSizeF( barHeight, barWidth ) );
176  m_private->addLabel( &lpc, sourceIndex, 0, PositionPoints( rect ), Position::North,
177  Position::South, point.value );
178  paintBars( ctx, sourceIndex, rect, maxDepth );
179 
180  offset += barWidth + spaceBetweenBars;
181  }
182  }
183  m_private->paintDataValueTextsAndMarkers( ctx, lpc, false );
184 }

Klarälvdalens Datakonsult AB (KDAB)
Qt-related services and products
http://www.kdab.com/
http://www.kdab.com/products/kd-chart/