KD Chart 2 [rev.2.4]
|
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 00033 using namespace KDChart; 00034 using namespace std; 00035 00036 PercentLineDiagram::PercentLineDiagram( LineDiagram* d ) 00037 : LineDiagramType( d ) 00038 { 00039 } 00040 00041 LineDiagram::LineType PercentLineDiagram::type() const 00042 { 00043 return LineDiagram::Percent; 00044 } 00045 00046 const QPair<QPointF, QPointF> PercentLineDiagram::calculateDataBoundaries() const 00047 { 00048 const double xMin = 0.0; 00049 double xMax = diagram()->model() ? diagram()->model()->rowCount( diagram()->rootIndex() ) : 0; 00050 if ( !diagram()->centerDataPoints() && diagram()->model() ) 00051 xMax -= 1; 00052 const double yMin = 0.0; 00053 const double yMax = 100.0; 00054 00055 QPointF bottomLeft( QPointF( xMin, yMin ) ); 00056 QPointF topRight( QPointF( xMax, yMax ) ); 00057 return QPair<QPointF, QPointF> ( bottomLeft, topRight ); 00058 } 00059 00060 void PercentLineDiagram::paint( PaintContext* ctx ) 00061 { 00062 reverseMapper().clear(); 00063 00064 const int columnCount = compressor().modelDataColumns(); 00065 const int rowCount = compressor().modelDataRows(); 00066 00067 // FIXME integrade column index retrieval to compressor: 00068 int maxFound = 0; 00069 // { // find the last column number that is not hidden 00070 // for( int iColumn = datasetDimension() - 1; 00071 // iColumn < columnCount; 00072 // iColumn += datasetDimension() ) 00073 // if( ! diagram()->isHidden( iColumn ) ) 00074 // maxFound = iColumn; 00075 // } 00076 maxFound = columnCount; 00077 // ^^^ temp 00078 const int lastVisibleColumn = maxFound - 1; 00079 00080 DataValueTextInfoList list; 00081 LineAttributesInfoList lineList; 00082 LineAttributes::MissingValuesPolicy policy = LineAttributes::MissingValuesAreBridged; 00083 00084 //FIXME(khz): add LineAttributes::MissingValuesPolicy support for LineDiagram::Stacked and ::Percent 00085 00086 double maxValue = 100; // always 100% 00087 double sumValues = 0; 00088 QVector <double > 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 double 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 double 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 double 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 paintAreas( 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 appendDataValueTextInfoToList( diagram(), list, sourceIndex, &position, 00219 pts, Position::NorthWest, Position::SouthWest, 00220 point.value ); 00221 } 00222 } 00223 if( areas.count() ){ 00224 paintAreas( ctx, indexPreviousCell, areas, laPreviousCell.transparency() ); 00225 areas.clear(); 00226 } 00227 bottomPoints = points; 00228 bFirstDataset = false; 00229 } 00230 paintElements( ctx, list, lineList, policy ); 00231 }