KD Chart 2  [rev.2.6]
KDChartStackedLineDiagram_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 "KDChartStackedLineDiagram_p.h"
24 
25 #include <QAbstractItemModel>
26 
27 #include "KDChartBarDiagram.h"
28 #include "KDChartLineDiagram.h"
29 #include "KDChartTextAttributes.h"
30 #include "KDChartAttributesModel.h"
32 #include "PaintingHelpers_p.h"
33 
34 using namespace KDChart;
35 using namespace std;
36 
37 StackedLineDiagram::StackedLineDiagram( LineDiagram* d )
38  : LineDiagramType( d )
39 {
40 }
41 
42 LineDiagram::LineType StackedLineDiagram::type() const
43 {
44  return LineDiagram::Stacked;
45 }
46 
47 const QPair<QPointF, QPointF> StackedLineDiagram::calculateDataBoundaries() const
48 {
49  const int rowCount = compressor().modelDataRows();
50  const int colCount = compressor().modelDataColumns();
51  const qreal xMin = 0;
52  qreal xMax = diagram()->model() ? diagram()->model()->rowCount( diagram()->rootIndex() ) : 0;
53  if ( !diagram()->centerDataPoints() && diagram()->model() )
54  xMax -= 1;
55  qreal yMin = 0, yMax = 0;
56 
57  bool bStarting = true;
58  for ( int row = 0; row < rowCount; ++row )
59  {
60  // calculate sum of values per column - Find out stacked Min/Max
61  qreal stackedValues = 0.0;
62  qreal negativeStackedValues = 0.0;
63  for ( int col = datasetDimension() - 1; col < colCount; col += datasetDimension() ) {
64  const CartesianDiagramDataCompressor::CachePosition position( row, col );
65  const CartesianDiagramDataCompressor::DataPoint point = compressor().data( position );
66 
67  if ( ISNAN( point.value ) )
68  continue;
69 
70  if ( point.value >= 0.0 )
71  stackedValues += point.value;
72  else
73  negativeStackedValues += point.value;
74  }
75 
76  if ( bStarting ) {
77  yMin = stackedValues;
78  yMax = stackedValues;
79  bStarting = false;
80  } else {
81  // take in account all stacked values
82  yMin = qMin( qMin( yMin, negativeStackedValues ), stackedValues );
83  yMax = qMax( qMax( yMax, negativeStackedValues ), stackedValues );
84  }
85  }
86 
87  const QPointF bottomLeft( xMin, yMin );
88  const QPointF topRight( xMax, yMax );
89 
90  return QPair<QPointF, QPointF> ( bottomLeft, topRight );
91 }
92 
93 void StackedLineDiagram::paint( PaintContext* ctx )
94 {
95  reverseMapper().clear();
96 
97  const int columnCount = compressor().modelDataColumns();
98  const int rowCount = compressor().modelDataRows();
99 
100 // FIXME integrate column index retrieval to compressor:
101 // int maxFound = 0;
102 // { // find the last column number that is not hidden
103 // for ( int iColumn = datasetDimension() - 1;
104 // iColumn < columnCount;
105 // iColumn += datasetDimension() )
106 // if ( ! diagram()->isHidden( iColumn ) )
107 // maxFound = iColumn;
108 // }
109  //maxFound = columnCount;
110  // ^^^ temp
111 
112  LabelPaintCache lpc;
113  LineAttributesInfoList lineList;
114 
115  QVector< qreal > percentSumValues;
116 
117  QList<QPointF> bottomPoints;
118  bool bFirstDataset = true;
119 
120  for ( int column = 0; column < columnCount; ++column )
121  {
122  CartesianDiagramDataCompressor::CachePosition previousCellPosition;
123 
124  //display area can be set by dataset ( == column) and/or by cell
125  LineAttributes laPreviousCell; // by default no area is drawn
126  QModelIndex indexPreviousCell;
127  QList<QPolygonF> areas;
128  QList<QPointF> points;
129 
130  for ( int row = 0; row < rowCount; ++row ) {
131  const CartesianDiagramDataCompressor::CachePosition position( row, column );
132  CartesianDiagramDataCompressor::DataPoint point = compressor().data( position );
133  const QModelIndex sourceIndex = attributesModel()->mapToSource( point.index );
134 
135  const LineAttributes laCell = diagram()->lineAttributes( sourceIndex );
136  const bool bDisplayCellArea = laCell.displayArea();
137 
139 
140  if ( ISNAN( point.value ) && policy == LineAttributes::MissingValuesShownAsZero )
141  point.value = 0.0;
142 
143  qreal stackedValues = 0, nextValues = 0, nextKey = 0;
144  for ( int column2 = column; column2 >= 0; --column2 )
145  {
146  const CartesianDiagramDataCompressor::CachePosition position( row, column2 );
147  const CartesianDiagramDataCompressor::DataPoint point = compressor().data( position );
148  if ( !ISNAN( point.value ) )
149  {
150  stackedValues += point.value;
151  }
152  else if ( policy == LineAttributes::MissingValuesAreBridged )
153  {
154  const qreal interpolation = interpolateMissingValue( position );
155  if ( !ISNAN( interpolation ) )
156  stackedValues += interpolation;
157  }
158 
159  //qDebug() << valueForCell( iRow, iColumn2 );
160  if ( row + 1 < rowCount ) {
161  const CartesianDiagramDataCompressor::CachePosition position( row + 1, column2 );
162  const CartesianDiagramDataCompressor::DataPoint point = compressor().data( position );
163  if ( !ISNAN( point.value ) )
164  {
165  nextValues += point.value;
166  }
167  else if ( policy == LineAttributes::MissingValuesAreBridged )
168  {
169  const qreal interpolation = interpolateMissingValue( position );
170  if ( !ISNAN( interpolation ) )
171  nextValues += interpolation;
172  }
173  nextKey = point.key;
174  }
175  }
176  //qDebug() << stackedValues << endl;
177  const QPointF nextPoint = ctx->coordinatePlane()->translate( QPointF( diagram()->centerDataPoints() ? point.key + 0.5 : point.key, stackedValues ) );
178  points << nextPoint;
179 
180  const QPointF ptNorthWest( nextPoint );
181  const QPointF ptSouthWest(
182  bDisplayCellArea
183  ? ( bFirstDataset
184  ? ctx->coordinatePlane()->translate( QPointF( diagram()->centerDataPoints() ? point.key + 0.5 : point.key, 0.0 ) )
185  : bottomPoints.at( row )
186  )
187  : nextPoint );
188  QPointF ptNorthEast;
189  QPointF ptSouthEast;
190 
191  if ( row + 1 < rowCount ) {
192  QPointF toPoint = ctx->coordinatePlane()->translate( QPointF( diagram()->centerDataPoints() ? nextKey + 0.5 : nextKey, nextValues ) );
193  lineList.append( LineAttributesInfo( sourceIndex, nextPoint, toPoint ) );
194  ptNorthEast = toPoint;
195  ptSouthEast =
196  bDisplayCellArea
197  ? ( bFirstDataset
198  ? ctx->coordinatePlane()->translate( QPointF( diagram()->centerDataPoints() ? nextKey + 0.5 : nextKey, 0.0 ) )
199  : bottomPoints.at( row + 1 )
200  )
201  : toPoint;
202  if ( areas.count() && laCell != laPreviousCell ) {
203  PaintingHelpers::paintAreas( m_private, ctx, indexPreviousCell, areas, laPreviousCell.transparency() );
204  areas.clear();
205  }
206  if ( bDisplayCellArea ) {
207  QPolygonF poly;
208  poly << ptNorthWest << ptNorthEast << ptSouthEast << ptSouthWest;
209  areas << poly;
210  laPreviousCell = laCell;
211  indexPreviousCell = sourceIndex;
212  } else {
213  //qDebug() << "no area shown for row"<<iRow<<" column"<<iColumn;
214  }
215  } else {
216  ptNorthEast = ptNorthWest;
217  ptSouthEast = ptSouthWest;
218  }
219 
220  const PositionPoints pts( ptNorthWest, ptNorthEast, ptSouthEast, ptSouthWest );
221  if ( !ISNAN( point.value ) )
222  m_private->addLabel( &lpc, sourceIndex, &position, pts, Position::NorthWest,
223  Position::NorthWest, point.value );
224  }
225  if ( areas.count() ) {
226  PaintingHelpers::paintAreas( m_private, ctx, indexPreviousCell, areas, laPreviousCell.transparency() );
227  areas.clear();
228  }
229  bottomPoints = points;
230  bFirstDataset = false;
231  }
232  PaintingHelpers::paintElements( m_private, ctx, lpc, lineList );
233 }
KDChartEnums::PositionValue value() const
Returns an integer value corresponding to this Position.
void paintElements(AbstractDiagram::Private *diagramPrivate, PaintContext *ctx, const LabelPaintCache &lpc, const LineAttributesInfoList &lineList)
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 line charts.
void paintAreas(AbstractDiagram::Private *diagramPrivate, PaintContext *ctx, const QModelIndex &index, const QList< QPolygonF > &areas, uint opacity)
static const Position & NorthWest
LineDiagram defines a common line diagram.
Stores information about painting diagrams.
Stores the absolute target points of a Position.
MissingValuesPolicy
MissingValuesPolicy specifies how a missing value will be shown in a line diagram.
MissingValuesPolicy missingValuesPolicy() const

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