KD Chart 2
[rev.2.5]
|
00001 /**************************************************************************** 00002 ** Copyright (C) 2001-2012 Klaralvdalens Datakonsult AB. All rights reserved. 00003 ** 00004 ** This file is part of the KD Chart library. 00005 ** 00006 ** Licensees holding valid commercial KD Chart licenses may use this file in 00007 ** accordance with the KD Chart Commercial License Agreement provided with 00008 ** the Software. 00009 ** 00010 ** 00011 ** This file may be distributed and/or modified under the terms of the 00012 ** GNU General Public License version 2 and version 3 as published by the 00013 ** Free Software Foundation and appearing in the file LICENSE.GPL.txt included. 00014 ** 00015 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE 00016 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 00017 ** 00018 ** Contact info@kdab.com if any conditions of this licensing are not 00019 ** clear to you. 00020 ** 00021 **********************************************************************/ 00022 00023 #include "KDChartPercentLineDiagram_p.h" 00024 00025 #include <QModelIndex> 00026 00027 #include "KDChartBarDiagram.h" 00028 #include "KDChartLineDiagram.h" 00029 #include "KDChartTextAttributes.h" 00030 #include "KDChartAttributesModel.h" 00031 #include "KDChartAbstractCartesianDiagram.h" 00032 #include "PaintingHelpers_p.h" 00033 00034 using namespace KDChart; 00035 using namespace std; 00036 00037 PercentLineDiagram::PercentLineDiagram( LineDiagram* d ) 00038 : LineDiagramType( d ) 00039 { 00040 } 00041 00042 LineDiagram::LineType PercentLineDiagram::type() const 00043 { 00044 return LineDiagram::Percent; 00045 } 00046 00047 const QPair<QPointF, QPointF> PercentLineDiagram::calculateDataBoundaries() const 00048 { 00049 const qreal xMin = 0.0; 00050 qreal xMax = diagram()->model() ? diagram()->model()->rowCount( diagram()->rootIndex() ) : 0; 00051 if ( !diagram()->centerDataPoints() && diagram()->model() ) 00052 xMax -= 1; 00053 const qreal yMin = 0.0; 00054 const qreal yMax = 100.0; 00055 00056 QPointF bottomLeft( QPointF( xMin, yMin ) ); 00057 QPointF topRight( QPointF( xMax, yMax ) ); 00058 return QPair<QPointF, QPointF> ( bottomLeft, topRight ); 00059 } 00060 00061 void PercentLineDiagram::paint( PaintContext* ctx ) 00062 { 00063 reverseMapper().clear(); 00064 00065 const int columnCount = compressor().modelDataColumns(); 00066 const int rowCount = compressor().modelDataRows(); 00067 00068 // FIXME integrade column index retrieval to compressor: 00069 int maxFound = 0; 00070 // { // find the last column number that is not hidden 00071 // for( int iColumn = datasetDimension() - 1; 00072 // iColumn < columnCount; 00073 // iColumn += datasetDimension() ) 00074 // if( ! diagram()->isHidden( iColumn ) ) 00075 // maxFound = iColumn; 00076 // } 00077 maxFound = columnCount; 00078 // ^^^ temp 00079 const int lastVisibleColumn = maxFound - 1; 00080 00081 LabelPaintCache lpc; 00082 LineAttributesInfoList lineList; 00083 00084 //FIXME(khz): add LineAttributes::MissingValuesPolicy support for LineDiagram::Stacked and ::Percent 00085 00086 qreal maxValue = 100; // always 100% 00087 qreal sumValues = 0; 00088 QVector <qreal > percentSumValues; 00089 00090 //calculate sum of values for each column and store 00091 for ( int row = 0; row < rowCount; ++row ) 00092 { 00093 for( int col = 0; col < columnCount; ++col ) 00094 { 00095 const CartesianDiagramDataCompressor::CachePosition position( row, col ); 00096 CartesianDiagramDataCompressor::DataPoint point = compressor().data( position ); 00097 const QModelIndex sourceIndex = attributesModel()->mapToSource( point.index ); 00098 const LineAttributes laCell = diagram()->lineAttributes( sourceIndex ); 00099 const LineAttributes::MissingValuesPolicy policy = laCell.missingValuesPolicy(); 00100 if( ISNAN( point.value ) && policy == LineAttributes::MissingValuesAreBridged ) 00101 point.value = interpolateMissingValue( position ); 00102 if ( point.value > 0 ) 00103 sumValues += point.value; 00104 if ( col == lastVisibleColumn ) 00105 { 00106 percentSumValues << sumValues ; 00107 sumValues = 0; 00108 } 00109 } 00110 } 00111 00112 QList<QPointF> bottomPoints; 00113 bool bFirstDataset = true; 00114 00115 for( int column = 0; column < columnCount; ++column ) 00116 { 00117 //display area can be set by dataset ( == column) and/or by cell 00118 LineAttributes laPreviousCell; // by default no area is drawn 00119 QModelIndex indexPreviousCell; 00120 QList<QPolygonF> areas; 00121 QList<QPointF> points; 00122 00123 for( int row = 0; row < rowCount; ++row ) 00124 { 00125 const CartesianDiagramDataCompressor::CachePosition position( row, column ); 00126 CartesianDiagramDataCompressor::DataPoint point = compressor().data( position ); 00127 const QModelIndex sourceIndex = attributesModel()->mapToSource( point.index ); 00128 const LineAttributes laCell = diagram()->lineAttributes( sourceIndex ); 00129 const bool bDisplayCellArea = laCell.displayArea(); 00130 00131 qreal stackedValues = 0, nextValues = 0, nextKey = 0; 00132 for ( int column2 = column; 00133 column2 >= 0;//datasetDimension() - 1; 00134 column2 -= 1 )//datasetDimension() ) 00135 { 00136 const CartesianDiagramDataCompressor::CachePosition position( row, column2 ); 00137 CartesianDiagramDataCompressor::DataPoint point = compressor().data( position ); 00138 00139 const QModelIndex sourceIndex = attributesModel()->mapToSource( point.index ); 00140 const LineAttributes::MissingValuesPolicy policy = laCell.missingValuesPolicy(); 00141 if( ISNAN( point.value ) && policy == LineAttributes::MissingValuesAreBridged ) 00142 point.value = interpolateMissingValue( position ); 00143 00144 const qreal val = point.value; 00145 if( val > 0 ) 00146 stackedValues += val; 00147 //qDebug() << valueForCell( iRow, iColumn2 ); 00148 if ( row + 1 < rowCount ){ 00149 const CartesianDiagramDataCompressor::CachePosition position( row + 1, column2 ); 00150 CartesianDiagramDataCompressor::DataPoint point = compressor().data( position ); 00151 00152 const QModelIndex sourceIndex = attributesModel()->mapToSource( point.index ); 00153 const LineAttributes::MissingValuesPolicy policy = laCell.missingValuesPolicy(); 00154 if( ISNAN( point.value ) && policy == LineAttributes::MissingValuesAreBridged ) 00155 point.value = interpolateMissingValue( position ); 00156 00157 const qreal val = point.value; 00158 if( val > 0 ) 00159 nextValues += val; 00160 nextKey = point.key; 00161 } 00162 } 00163 if ( percentSumValues.at( row ) != 0 ) 00164 stackedValues = stackedValues / percentSumValues.at( row ) * maxValue; 00165 else 00166 stackedValues = 0.0; 00167 //qDebug() << stackedValues << endl; 00168 QPointF nextPoint = ctx->coordinatePlane()->translate( QPointF( diagram()->centerDataPoints() ? point.key + 0.5 : point.key, stackedValues ) ); 00169 points << nextPoint; 00170 00171 const QPointF ptNorthWest( nextPoint ); 00172 const QPointF ptSouthWest( 00173 bDisplayCellArea 00174 ? ( bFirstDataset 00175 ? ctx->coordinatePlane()->translate( QPointF( diagram()->centerDataPoints() ? point.key + 0.5 : point.key, 0.0 ) ) 00176 : bottomPoints.at( row ) 00177 ) 00178 : nextPoint ); 00179 QPointF ptNorthEast; 00180 QPointF ptSouthEast; 00181 00182 if ( row + 1 < rowCount ){ 00183 if ( percentSumValues.at( row + 1 ) != 0 ) 00184 nextValues = nextValues / percentSumValues.at( row + 1 ) * maxValue; 00185 else 00186 nextValues = 0.0; 00187 QPointF toPoint = ctx->coordinatePlane()->translate( QPointF( diagram()->centerDataPoints() ? nextKey + 0.5 : nextKey, nextValues ) ); 00188 lineList.append( LineAttributesInfo( sourceIndex, nextPoint, toPoint ) ); 00189 ptNorthEast = toPoint; 00190 ptSouthEast = 00191 bDisplayCellArea 00192 ? ( bFirstDataset 00193 ? ctx->coordinatePlane()->translate( QPointF( diagram()->centerDataPoints() ? nextKey + 0.5 : nextKey, 0.0 ) ) 00194 : bottomPoints.at( row + 1 ) 00195 ) 00196 : toPoint; 00197 if( areas.count() && laCell != laPreviousCell ){ 00198 PaintingHelpers::paintAreas( m_private, ctx, indexPreviousCell, areas, laPreviousCell.transparency() ); 00199 areas.clear(); 00200 } 00201 if( bDisplayCellArea ){ 00202 QPolygonF poly; 00203 poly << ptNorthWest << ptNorthEast << ptSouthEast << ptSouthWest; 00204 areas << poly; 00205 laPreviousCell = laCell; 00206 indexPreviousCell = sourceIndex; 00207 }else{ 00208 //qDebug() << "no area shown for row"<<iRow<<" column"<<iColumn; 00209 } 00210 }else{ 00211 ptNorthEast = ptNorthWest; 00212 ptSouthEast = ptSouthWest; 00213 } 00214 00215 if( !ISNAN( point.value ) ) 00216 { 00217 const PositionPoints pts( ptNorthWest, ptNorthEast, ptSouthEast, ptSouthWest ); 00218 addLabel( &lpc, sourceIndex, &position, pts, Position::NorthWest, 00219 Position::SouthWest, point.value ); 00220 } 00221 } 00222 if( areas.count() ){ 00223 PaintingHelpers::paintAreas( m_private, ctx, indexPreviousCell, areas, laPreviousCell.transparency() ); 00224 areas.clear(); 00225 } 00226 bottomPoints = points; 00227 bFirstDataset = false; 00228 } 00229 PaintingHelpers::paintElements( m_private, ctx, lpc, lineList ); 00230 }