KD Chart 2  [rev.2.6]
KDChartNormalBarDiagram_p.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 ** Copyright (C) 2001-2019 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 "KDChartNormalBarDiagram_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 NormalBarDiagram::NormalBarDiagram( BarDiagram* d )
36  : BarDiagramType( d )
37 {
38 }
39 
40 BarDiagram::BarType NormalBarDiagram::type() const
41 {
42  return BarDiagram::Normal;
43 }
44 
45 const QPair<QPointF, QPointF> NormalBarDiagram::calculateDataBoundaries() const
46 {
47  const int rowCount = compressor().modelDataRows();
48  const int colCount = compressor().modelDataColumns();
49 
50  const qreal xMin = 0.0;
51  const qreal xMax = rowCount;
52  qreal yMin = 0.0;
53  qreal yMax = 0.0;
54 
55  qreal usedDepth = 0;
56 
57  bool isFirst = true;
58  for ( int column = 0; column < colCount; ++column ) {
59  for ( int row = 0; row < rowCount; ++row ) {
60  const CartesianDiagramDataCompressor::CachePosition position( row, column );
61  const CartesianDiagramDataCompressor::DataPoint point = compressor().data( position );
62  const qreal value = ISNAN( point.value ) ? 0.0 : point.value;
63 
64  QModelIndex sourceIndex = attributesModel()->mapToSource( point.index );
65  ThreeDBarAttributes threeDAttrs = diagram()->threeDBarAttributes( sourceIndex );
66 
67  if ( threeDAttrs.isEnabled() )
68  usedDepth = qMax( usedDepth, threeDAttrs.depth() );
69 
70  // this is always true yMin can be 0 in case all values
71  // are the same
72  // same for yMax it can be zero if all values are negative
73  if ( isFirst ) {
74  yMin = value;
75  yMax = value;
76  isFirst = false;
77  } else {
78  yMin = qMin( yMin, value );
79  yMax = qMax( yMax, value );
80  }
81  }
82  }
83 
84  // special cases
85  if ( yMax == yMin ) {
86  if ( yMin == 0.0 ) {
87  yMax = 0.1; // we need at least a range
88  } else if ( yMax < 0.0 ) {
89  yMax = 0.0; // extend the range to zero
90  } else if ( yMin > 0.0 ) {
91  yMin = 0.0; // dito
92  }
93  }
94 
95  return QPair< QPointF, QPointF >( QPointF( xMin, yMin ), QPointF( xMax, yMax ) );
96 }
97 
98 void NormalBarDiagram::paint( PaintContext* ctx )
99 {
100  reverseMapper().clear();
101 
102  const QPair<QPointF,QPointF> boundaries = diagram()->dataBoundaries(); // cached
103 
104  const QPointF boundLeft = ctx->coordinatePlane()->translate( boundaries.first ) ;
105  const QPointF boundRight = ctx->coordinatePlane()->translate( boundaries.second );
106 
107  const int rowCount = attributesModel()->rowCount(attributesModelRootIndex());
108  const int colCount = attributesModel()->columnCount(attributesModelRootIndex());
109 
110  BarAttributes ba = diagram()->barAttributes();
111  ThreeDBarAttributes threeDAttrs = diagram()->threeDBarAttributes();
112 
113  //we need some margin (hence the 2.5) for the three dimensional depth
114  const qreal threeDepthMargin = ( threeDAttrs.isEnabled() ) ? 2.5 * threeDAttrs.depth() : 0;
115 
116  qreal barWidth = 0;
117  qreal maxDepth = 0;
118  qreal width = boundRight.x() - boundLeft.x() - threeDepthMargin;
119  qreal groupWidth = width / rowCount;
120  qreal spaceBetweenBars = 0;
121  qreal spaceBetweenGroups = 0;
122 
123  if ( ba.useFixedBarWidth() ) {
124 
125  barWidth = ba.fixedBarWidth();
126  groupWidth += barWidth;
127 
128  // Pending Michel set a min and max value for the groupWidth
129  // related to the area.width
130  if ( groupWidth < 0 )
131  groupWidth = 0;
132 
133  if ( groupWidth * rowCount > width )
134  groupWidth = width / rowCount;
135  }
136 
137  // maxLimit: allow the space between bars to be larger until area.width()
138  // is covered by the groups.
139  qreal maxLimit = rowCount * ( groupWidth + ( ( colCount - 1 ) * ba.fixedDataValueGap() ) );
140 
141  //Pending Michel: FixMe
142  if ( ba.useFixedDataValueGap() ) {
143  if ( width > maxLimit ) {
144  spaceBetweenBars += ba.fixedDataValueGap();
145  } else {
146  spaceBetweenBars = ( ( width / rowCount ) - groupWidth ) / ( colCount - 1 );
147  }
148  }
149 
150  if ( ba.useFixedValueBlockGap() ) {
151  spaceBetweenGroups += ba.fixedValueBlockGap();
152  }
153 
154  calculateValueAndGapWidths( rowCount, colCount, groupWidth,
155  barWidth, spaceBetweenBars, spaceBetweenGroups );
156 
157  LabelPaintCache lpc;
158 
159  for ( int row = 0; row < rowCount; ++row ) {
160  qreal offset = -groupWidth / 2 + spaceBetweenGroups / 2;
161 
162  if ( ba.useFixedDataValueGap() ) {
163  if ( spaceBetweenBars > 0 ) {
164  if ( width > maxLimit ) {
165  offset -= ba.fixedDataValueGap();
166  } else {
167  offset -= ( ( width / rowCount ) - groupWidth ) / ( colCount - 1 );
168  }
169  } else {
170  offset += barWidth / 2;
171  }
172  }
173 
174  for ( int column = 0; column < colCount; ++column ) {
175  // paint one group
176  const CartesianDiagramDataCompressor::CachePosition position( row, column );
177  const CartesianDiagramDataCompressor::DataPoint point = compressor().data( position );
178  const QModelIndex sourceIndex = attributesModel()->mapToSource( point.index );
179  const qreal value = point.value;//attributesModel()->data( sourceIndex ).toReal();
180  if ( ! point.hidden && !ISNAN( value ) ) {
181  QPointF topPoint = ctx->coordinatePlane()->translate( QPointF( point.key + 0.5, value ) );
182  QPointF bottomPoint = ctx->coordinatePlane()->translate( QPointF( point.key, 0 ) );
183 
184  if ( threeDAttrs.isEnabled() ) {
185  const qreal usedDepth = threeDAttrs.depth() / 4;
186  topPoint.setY( topPoint.y() + usedDepth + 1.0 );
187  }
188 
189  const qreal barHeight = bottomPoint.y() - topPoint.y();
190  topPoint.setX( topPoint.x() + offset );
191  const QRectF rect( topPoint, QSizeF( barWidth, barHeight ) );
192  m_private->addLabel( &lpc, sourceIndex, 0, PositionPoints( rect ), Position::North,
193  Position::South, point.value );
194  paintBars( ctx, sourceIndex, rect, maxDepth );
195  }
196  offset += barWidth + spaceBetweenBars;
197  }
198  }
199  m_private->paintDataValueTextsAndMarkers( ctx, lpc, false );
200 }
KDChartEnums::PositionValue value() const
Returns an integer value corresponding to this Position.
virtual const QPointF translate(const QPointF &diagramPoint) const =0
Translate the given point in value space coordinates to a position in pixel space.
AbstractCoordinatePlane * coordinatePlane() const
Set of attributes for changing the appearance of bar charts.
static const Position & South
BarDiagram defines a common bar diagram.
Stores information about painting diagrams.
A set of 3D bar attributes.
Stores the absolute target points of a Position.
static const Position & North

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