File indexing completed on 2024-12-15 04:02:27
0001 /* 0002 * SPDX-FileCopyrightText: 2001-2015 Klaralvdalens Datakonsult AB. All rights reserved. 0003 * 0004 * This file is part of the KD Chart library. 0005 * 0006 * SPDX-License-Identifier: GPL-2.0-or-later 0007 */ 0008 0009 #include "KChartPercentLineDiagram_p.h" 0010 0011 #include <QModelIndex> 0012 0013 #include "KChartBarDiagram.h" 0014 #include "KChartLineDiagram.h" 0015 #include "KChartTextAttributes.h" 0016 #include "KChartAttributesModel.h" 0017 #include "KChartAbstractCartesianDiagram.h" 0018 #include "PaintingHelpers_p.h" 0019 0020 using namespace KChart; 0021 using namespace std; 0022 0023 PercentLineDiagram::PercentLineDiagram( LineDiagram* d ) 0024 : LineDiagramType( d ) 0025 { 0026 } 0027 0028 LineDiagram::LineType PercentLineDiagram::type() const 0029 { 0030 return LineDiagram::Percent; 0031 } 0032 0033 const QPair<QPointF, QPointF> PercentLineDiagram::calculateDataBoundaries() const 0034 { 0035 const qreal xMin = 0.0; 0036 qreal xMax = diagram()->model() ? diagram()->model()->rowCount( diagram()->rootIndex() ) : 0; 0037 if ( !diagram()->centerDataPoints() && diagram()->model() ) 0038 xMax -= 1; 0039 const qreal yMin = 0.0; 0040 const qreal yMax = 100.0; 0041 0042 QPointF bottomLeft( QPointF( xMin, yMin ) ); 0043 QPointF topRight( QPointF( xMax, yMax ) ); 0044 return QPair<QPointF, QPointF> ( bottomLeft, topRight ); 0045 } 0046 0047 void PercentLineDiagram::paint( PaintContext* ctx ) 0048 { 0049 reverseMapper().clear(); 0050 0051 const int columnCount = compressor().modelDataColumns(); 0052 const int rowCount = compressor().modelDataRows(); 0053 0054 // FIXME integrade column index retrieval to compressor: 0055 int maxFound = 0; 0056 // { // find the last column number that is not hidden 0057 // for ( int iColumn = datasetDimension() - 1; 0058 // iColumn < columnCount; 0059 // iColumn += datasetDimension() ) 0060 // if ( ! diagram()->isHidden( iColumn ) ) 0061 // maxFound = iColumn; 0062 // } 0063 maxFound = columnCount; 0064 // ^^^ temp 0065 const int lastVisibleColumn = maxFound - 1; 0066 0067 LabelPaintCache lpc; 0068 LineAttributesInfoList lineList; 0069 0070 //FIXME(khz): add LineAttributes::MissingValuesPolicy support for LineDiagram::Stacked and ::Percent 0071 0072 qreal maxValue = 100; // always 100% 0073 qreal sumValues = 0; 0074 QVector <qreal > percentSumValues; 0075 0076 //calculate sum of values for each column and store 0077 for ( int row = 0; row < rowCount; ++row ) 0078 { 0079 for ( int col = 0; col < columnCount; ++col ) 0080 { 0081 const CartesianDiagramDataCompressor::CachePosition position( row, col ); 0082 CartesianDiagramDataCompressor::DataPoint point = compressor().data( position ); 0083 const QModelIndex sourceIndex = attributesModel()->mapToSource( point.index ); 0084 const LineAttributes laCell = diagram()->lineAttributes( sourceIndex ); 0085 const LineAttributes::MissingValuesPolicy policy = laCell.missingValuesPolicy(); 0086 if ( ISNAN( point.value ) && policy == LineAttributes::MissingValuesAreBridged ) 0087 point.value = interpolateMissingValue( position ); 0088 if ( point.value > 0 ) 0089 sumValues += point.value; 0090 if ( col == lastVisibleColumn ) 0091 { 0092 percentSumValues << sumValues ; 0093 sumValues = 0; 0094 } 0095 } 0096 } 0097 0098 QList<QPointF> bottomPoints; 0099 bool bFirstDataset = true; 0100 0101 for ( int column = 0; column < columnCount; ++column ) 0102 { 0103 //display area can be set by dataset ( == column) and/or by cell 0104 LineAttributes laPreviousCell; // by default no area is drawn 0105 QModelIndex indexPreviousCell; 0106 QList<QPolygonF> areas; 0107 QList<QPointF> points; 0108 0109 for ( int row = 0; row < rowCount; ++row ) 0110 { 0111 const CartesianDiagramDataCompressor::CachePosition position( row, column ); 0112 CartesianDiagramDataCompressor::DataPoint point = compressor().data( position ); 0113 const QModelIndex sourceIndex = attributesModel()->mapToSource( point.index ); 0114 const LineAttributes laCell = diagram()->lineAttributes( sourceIndex ); 0115 const bool bDisplayCellArea = laCell.displayArea(); 0116 0117 qreal stackedValues = 0, nextValues = 0, nextKey = 0; 0118 for ( int column2 = column; 0119 column2 >= 0;//datasetDimension() - 1; 0120 column2 -= 1 )//datasetDimension() ) 0121 { 0122 const CartesianDiagramDataCompressor::CachePosition position( row, column2 ); 0123 CartesianDiagramDataCompressor::DataPoint point = compressor().data( position ); 0124 0125 const LineAttributes::MissingValuesPolicy policy = laCell.missingValuesPolicy(); 0126 if ( ISNAN( point.value ) && policy == LineAttributes::MissingValuesAreBridged ) 0127 point.value = interpolateMissingValue( position ); 0128 0129 const qreal val = point.value; 0130 if ( val > 0 ) 0131 stackedValues += val; 0132 //qDebug() << valueForCell( iRow, iColumn2 ); 0133 if ( row + 1 < rowCount ) { 0134 const CartesianDiagramDataCompressor::CachePosition position( row + 1, column2 ); 0135 CartesianDiagramDataCompressor::DataPoint point = compressor().data( position ); 0136 0137 const LineAttributes::MissingValuesPolicy policy = laCell.missingValuesPolicy(); 0138 if ( ISNAN( point.value ) && policy == LineAttributes::MissingValuesAreBridged ) 0139 point.value = interpolateMissingValue( position ); 0140 0141 const qreal val = point.value; 0142 if ( val > 0 ) 0143 nextValues += val; 0144 nextKey = point.key; 0145 } 0146 } 0147 if ( percentSumValues.at( row ) != 0 ) 0148 stackedValues = stackedValues / percentSumValues.at( row ) * maxValue; 0149 else 0150 stackedValues = 0.0; 0151 //qDebug() << stackedValues << endl; 0152 QPointF nextPoint = ctx->coordinatePlane()->translate( QPointF( diagram()->centerDataPoints() ? point.key + 0.5 : point.key, stackedValues ) ); 0153 points << nextPoint; 0154 0155 const QPointF ptNorthWest( nextPoint ); 0156 const QPointF ptSouthWest( 0157 bDisplayCellArea 0158 ? ( bFirstDataset 0159 ? ctx->coordinatePlane()->translate( QPointF( diagram()->centerDataPoints() ? point.key + 0.5 : point.key, 0.0 ) ) 0160 : bottomPoints.at( row ) 0161 ) 0162 : nextPoint ); 0163 QPointF ptNorthEast; 0164 QPointF ptSouthEast; 0165 0166 if ( row + 1 < rowCount ) { 0167 if ( percentSumValues.at( row + 1 ) != 0 ) 0168 nextValues = nextValues / percentSumValues.at( row + 1 ) * maxValue; 0169 else 0170 nextValues = 0.0; 0171 QPointF toPoint = ctx->coordinatePlane()->translate( QPointF( diagram()->centerDataPoints() ? nextKey + 0.5 : nextKey, nextValues ) ); 0172 lineList.append( LineAttributesInfo( sourceIndex, nextPoint, toPoint ) ); 0173 ptNorthEast = toPoint; 0174 ptSouthEast = 0175 bDisplayCellArea 0176 ? ( bFirstDataset 0177 ? ctx->coordinatePlane()->translate( QPointF( diagram()->centerDataPoints() ? nextKey + 0.5 : nextKey, 0.0 ) ) 0178 : bottomPoints.at( row + 1 ) 0179 ) 0180 : toPoint; 0181 if ( areas.count() && laCell != laPreviousCell ) { 0182 PaintingHelpers::paintAreas( m_private, ctx, indexPreviousCell, areas, laPreviousCell.transparency() ); 0183 areas.clear(); 0184 } 0185 if ( bDisplayCellArea ) { 0186 QPolygonF poly; 0187 poly << ptNorthWest << ptNorthEast << ptSouthEast << ptSouthWest; 0188 areas << poly; 0189 laPreviousCell = laCell; 0190 indexPreviousCell = sourceIndex; 0191 } else { 0192 //qDebug() << "no area shown for row"<<iRow<<" column"<<iColumn; 0193 } 0194 } else { 0195 ptNorthEast = ptNorthWest; 0196 ptSouthEast = ptSouthWest; 0197 } 0198 0199 if ( !ISNAN( point.value ) ) 0200 { 0201 const PositionPoints pts( ptNorthWest, ptNorthEast, ptSouthEast, ptSouthWest ); 0202 m_private->addLabel( &lpc, sourceIndex, &position, pts, Position::NorthWest, 0203 Position::NorthWest, point.value ); 0204 } 0205 } 0206 if ( areas.count() ) { 0207 PaintingHelpers::paintAreas( m_private, ctx, indexPreviousCell, areas, laPreviousCell.transparency() ); 0208 areas.clear(); 0209 } 0210 bottomPoints = points; 0211 bFirstDataset = false; 0212 } 0213 PaintingHelpers::paintElements( m_private, ctx, lpc, lineList ); 0214 }