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