KD Chart 2  [rev.2.7]
KDChartNormalLyingBarDiagram_p.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 ** Copyright (C) 2001-2020 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  const qreal xMin = 0.0;
52  const 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  reverseMapper().clear();
95 
96  const QPair<QPointF,QPointF> boundaries = diagram()->dataBoundaries(); // cached
97 
98  const QPointF boundLeft = ctx->coordinatePlane()->translate( boundaries.first ) ;
99  const QPointF boundRight = ctx->coordinatePlane()->translate( boundaries.second );
100 
101  const int rowCount = attributesModel()->rowCount( attributesModelRootIndex() );
102  const int colCount = attributesModel()->columnCount( attributesModelRootIndex() );
103 
104  BarAttributes ba = diagram()->barAttributes();
105  qreal barWidth = 0;
106  qreal maxDepth = 0;
107  qreal width = boundLeft.y() - boundRight.y();
108  qreal groupWidth = width / rowCount;
109  qreal spaceBetweenBars = 0;
110  qreal spaceBetweenGroups = 0;
111 
112  if ( ba.useFixedBarWidth() ) {
113 
114  barWidth = ba.fixedBarWidth();
115  groupWidth += barWidth;
116 
117  // Pending Michel set a min and max value for the groupWidth
118  // related to the area.width
119  if ( groupWidth < 0 )
120  groupWidth = 0;
121 
122  if ( groupWidth * rowCount > width )
123  groupWidth = width / rowCount;
124  }
125 
126  // maxLimit: allow the space between bars to be larger until area.width()
127  // is covered by the groups.
128  qreal maxLimit = rowCount * ( groupWidth + ( colCount - 1 ) * ba.fixedDataValueGap() );
129 
130  //Pending Michel: FixMe
131  if ( ba.useFixedDataValueGap() ) {
132  if ( width > maxLimit )
133  spaceBetweenBars += ba.fixedDataValueGap();
134  else
135  spaceBetweenBars = ( width / rowCount - groupWidth ) / ( colCount - 1 );
136  }
137 
138  if ( ba.useFixedValueBlockGap() ) {
139  spaceBetweenGroups += ba.fixedValueBlockGap();
140  }
141 
142  calculateValueAndGapWidths( rowCount, colCount,groupWidth,
143  barWidth, spaceBetweenBars, spaceBetweenGroups );
144 
145  LabelPaintCache lpc;
146 
147  for ( int row = 0; row < rowCount; row++ ) {
148  qreal offset = -groupWidth / 2 + spaceBetweenGroups / 2;
149 
150  if ( ba.useFixedDataValueGap() ) {
151  if ( spaceBetweenBars > 0 ) {
152  if ( width > maxLimit ) {
153  offset -= ba.fixedDataValueGap();
154  } else {
155  offset -= ( width / rowCount - groupWidth ) / ( colCount - 1 );
156  }
157  } else {
158  offset += barWidth / 2;
159  }
160  }
161 
162  for ( int column = 0; column < colCount; column++ ) {
163  // paint one group
164  const CartesianDiagramDataCompressor::CachePosition position( row, column );
165  const CartesianDiagramDataCompressor::DataPoint point = compressor().data( position );
166  const QModelIndex sourceIndex = attributesModel()->mapToSource( point.index );
167 
168  QPointF dataPoint( 0, ( point.key + 0.5 ) );
169  const QPointF topLeft = ctx->coordinatePlane()->translate( dataPoint );
170  dataPoint.rx() += point.value;
171  const QPointF bottomRight = ctx->coordinatePlane()->translate( dataPoint ) +
172  QPointF( 0, barWidth );
173 
174  const QRectF rect = QRectF( topLeft, bottomRight ).translated( 1.0, offset );
175  m_private->addLabel( &lpc, sourceIndex, 0, PositionPoints( rect ), Position::North,
176  Position::South, point.value );
177  paintBars( ctx, sourceIndex, rect, maxDepth );
178 
179  offset += barWidth + spaceBetweenBars;
180  }
181  }
182  m_private->paintDataValueTextsAndMarkers( ctx, lpc, false );
183 }
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.
Stores the absolute target points of a Position.
static const Position & North

Klarälvdalens Datakonsult AB (KDAB)
"The Qt, C++ and OpenGL Experts"
https://www.kdab.com/

https://www.kdab.com/development-resources/qt-tools/kd-chart/