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 "KDChartStackedLineDiagram_p.h" 00024 00025 #include <QAbstractItemModel> 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 StackedLineDiagram::StackedLineDiagram( LineDiagram* d ) 00037 : LineDiagramType( d ) 00038 { 00039 } 00040 00041 LineDiagram::LineType StackedLineDiagram::type() const 00042 { 00043 return LineDiagram::Stacked; 00044 } 00045 00046 const QPair<QPointF, QPointF> StackedLineDiagram::calculateDataBoundaries() const 00047 { 00048 const int rowCount = compressor().modelDataRows(); 00049 const int colCount = compressor().modelDataColumns(); 00050 const double xMin = 0; 00051 double xMax = diagram()->model() ? diagram()->model()->rowCount( diagram()->rootIndex() ) : 0; 00052 if ( !diagram()->centerDataPoints() && diagram()->model() ) 00053 xMax -= 1; 00054 double yMin = 0, yMax = 0; 00055 00056 bool bStarting = true; 00057 for( int row = 0; row < rowCount; ++row ) 00058 { 00059 // calculate sum of values per column - Find out stacked Min/Max 00060 double stackedValues = 0.0; 00061 double negativeStackedValues = 0.0; 00062 for( int col = datasetDimension() - 1; col < colCount; col += datasetDimension() ) { 00063 const CartesianDiagramDataCompressor::CachePosition position( row, col ); 00064 const CartesianDiagramDataCompressor::DataPoint point = compressor().data( position ); 00065 00066 if( ISNAN( point.value ) ) 00067 continue; 00068 00069 if( point.value >= 0.0 ) 00070 stackedValues += point.value; 00071 else 00072 negativeStackedValues += point.value; 00073 } 00074 00075 if( bStarting ){ 00076 yMin = stackedValues; 00077 yMax = stackedValues; 00078 bStarting = false; 00079 }else{ 00080 // take in account all stacked values 00081 yMin = qMin( qMin( yMin, negativeStackedValues ), stackedValues ); 00082 yMax = qMax( qMax( yMax, negativeStackedValues ), stackedValues ); 00083 } 00084 } 00085 00086 const QPointF bottomLeft( xMin, yMin ); 00087 const QPointF topRight( xMax, yMax ); 00088 00089 return QPair<QPointF, QPointF> ( bottomLeft, topRight ); 00090 } 00091 00092 void StackedLineDiagram::paint( PaintContext* ctx ) 00093 { 00094 reverseMapper().clear(); 00095 00096 const int columnCount = compressor().modelDataColumns(); 00097 const int rowCount = compressor().modelDataRows(); 00098 00099 // FIXME integrate column index retrieval to compressor: 00100 // int maxFound = 0; 00101 // { // find the last column number that is not hidden 00102 // for( int iColumn = datasetDimension() - 1; 00103 // iColumn < columnCount; 00104 // iColumn += datasetDimension() ) 00105 // if( ! diagram()->isHidden( iColumn ) ) 00106 // maxFound = iColumn; 00107 // } 00108 // maxFound = columnCount; 00109 // ^^^ temp 00110 00111 DataValueTextInfoList list; 00112 LineAttributesInfoList lineList; 00113 LineAttributes::MissingValuesPolicy policy = LineAttributes::MissingValuesAreBridged; 00114 00115 //FIXME(khz): add LineAttributes::MissingValuesPolicy support for LineDiagram::Stacked and ::Percent 00116 00117 QVector <double > percentSumValues; 00118 00119 QList<QPointF> bottomPoints; 00120 bool bFirstDataset = true; 00121 00122 for( int column = 0; column < columnCount; ++column ) 00123 { 00124 CartesianDiagramDataCompressor::CachePosition previousCellPosition; 00125 00126 //display area can be set by dataset ( == column) and/or by cell 00127 LineAttributes laPreviousCell; // by default no area is drawn 00128 QModelIndex indexPreviousCell; 00129 QList<QPolygonF> areas; 00130 QList<QPointF> points; 00131 00132 for ( int row = 0; row < rowCount; ++row ) { 00133 const CartesianDiagramDataCompressor::CachePosition position( row, column ); 00134 CartesianDiagramDataCompressor::DataPoint point = compressor().data( position ); 00135 const QModelIndex sourceIndex = attributesModel()->mapToSource( point.index ); 00136 00137 const LineAttributes laCell = diagram()->lineAttributes( sourceIndex ); 00138 const bool bDisplayCellArea = laCell.displayArea(); 00139 00140 const LineAttributes::MissingValuesPolicy policy = laCell.missingValuesPolicy(); 00141 00142 if( ISNAN( point.value ) && policy == LineAttributes::MissingValuesShownAsZero ) 00143 point.value = 0.0; 00144 00145 double stackedValues = 0, nextValues = 0, nextKey = 0; 00146 for ( int column2 = column; column2 >= 0; --column2 ) 00147 { 00148 const CartesianDiagramDataCompressor::CachePosition position( row, column2 ); 00149 const CartesianDiagramDataCompressor::DataPoint point = compressor().data( position ); 00150 const QModelIndex sourceIndex = attributesModel()->mapToSource( point.index ); 00151 if( !ISNAN( point.value ) ) 00152 { 00153 stackedValues += point.value; 00154 } 00155 else if( policy == LineAttributes::MissingValuesAreBridged ) 00156 { 00157 const double interpolation = interpolateMissingValue( position ); 00158 if( !ISNAN( interpolation ) ) 00159 stackedValues += interpolation; 00160 } 00161 00162 //qDebug() << valueForCell( iRow, iColumn2 ); 00163 if ( row + 1 < rowCount ){ 00164 const CartesianDiagramDataCompressor::CachePosition position( row + 1, column2 ); 00165 const CartesianDiagramDataCompressor::DataPoint point = compressor().data( position ); 00166 if( !ISNAN( point.value ) ) 00167 { 00168 nextValues += point.value; 00169 } 00170 else if( policy == LineAttributes::MissingValuesAreBridged ) 00171 { 00172 const double interpolation = interpolateMissingValue( position ); 00173 if( !ISNAN( interpolation ) ) 00174 nextValues += interpolation; 00175 } 00176 nextKey = point.key; 00177 } 00178 } 00179 //qDebug() << stackedValues << endl; 00180 const QPointF nextPoint = ctx->coordinatePlane()->translate( QPointF( diagram()->centerDataPoints() ? point.key + 0.5 : point.key, stackedValues ) ); 00181 points << nextPoint; 00182 00183 const QPointF ptNorthWest( nextPoint ); 00184 const QPointF ptSouthWest( 00185 bDisplayCellArea 00186 ? ( bFirstDataset 00187 ? ctx->coordinatePlane()->translate( QPointF( diagram()->centerDataPoints() ? point.key + 0.5 : point.key, 0.0 ) ) 00188 : bottomPoints.at( row ) 00189 ) 00190 : nextPoint ); 00191 QPointF ptNorthEast; 00192 QPointF ptSouthEast; 00193 00194 if ( row + 1 < rowCount ){ 00195 QPointF toPoint = ctx->coordinatePlane()->translate( QPointF( diagram()->centerDataPoints() ? nextKey + 0.5 : nextKey, nextValues ) ); 00196 lineList.append( LineAttributesInfo( sourceIndex, nextPoint, toPoint ) ); 00197 ptNorthEast = toPoint; 00198 ptSouthEast = 00199 bDisplayCellArea 00200 ? ( bFirstDataset 00201 ? ctx->coordinatePlane()->translate( QPointF( diagram()->centerDataPoints() ? nextKey + 0.5 : nextKey, 0.0 ) ) 00202 : bottomPoints.at( row + 1 ) 00203 ) 00204 : toPoint; 00205 if( areas.count() && laCell != laPreviousCell ){ 00206 paintAreas( ctx, indexPreviousCell, areas, laPreviousCell.transparency() ); 00207 areas.clear(); 00208 } 00209 if( bDisplayCellArea ){ 00210 QPolygonF poly; 00211 poly << ptNorthWest << ptNorthEast << ptSouthEast << ptSouthWest; 00212 areas << poly; 00213 laPreviousCell = laCell; 00214 indexPreviousCell = sourceIndex; 00215 }else{ 00216 //qDebug() << "no area shown for row"<<iRow<<" column"<<iColumn; 00217 } 00218 }else{ 00219 ptNorthEast = ptNorthWest; 00220 ptSouthEast = ptSouthWest; 00221 } 00222 00223 const PositionPoints pts( ptNorthWest, ptNorthEast, ptSouthEast, ptSouthWest ); 00224 if( !ISNAN( point.value ) ) 00225 appendDataValueTextInfoToList( diagram(), list, sourceIndex, &position, 00226 pts, Position::NorthWest, Position::SouthWest, 00227 point.value ); 00228 } 00229 if( areas.count() ){ 00230 paintAreas( ctx, indexPreviousCell, areas, laPreviousCell.transparency() ); 00231 areas.clear(); 00232 } 00233 bottomPoints = points; 00234 bFirstDataset = false; 00235 } 00236 paintElements( ctx, list, lineList, policy ); 00237 }