KDChartPercentLyingBarDiagram_p.cpp

Go to the documentation of this file.
00001 /* -*- Mode: C++ -*-
00002    KDChart - a multi-platform charting engine
00003    */
00004 
00005 /****************************************************************************
00006  ** Copyright (C) 2005-2007 Klarälvdalens Datakonsult AB.  All rights reserved.
00007  **
00008  ** This file is part of the KD Chart library.
00009  **
00010  ** This file may be distributed and/or modified under the terms of the
00011  ** GNU General Public License version 2 as published by the Free Software
00012  ** Foundation and appearing in the file LICENSE.GPL included in the
00013  ** packaging of this file.
00014  **
00015  ** Licensees holding valid commercial KD Chart licenses may use this file in
00016  ** accordance with the KD Chart Commercial License Agreement provided with
00017  ** the Software.
00018  **
00019  ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
00020  ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00021  **
00022  ** See http://www.kdab.net/kdchart for
00023  **   information about KD Chart Commercial License Agreements.
00024  **
00025  ** Contact info@kdab.net if any conditions of this
00026  ** licensing are not clear to you.
00027  **
00028  **********************************************************************/
00029 
00030 #include "KDChartPercentLyingBarDiagram_p.h"
00031 
00032 #include <QModelIndex>
00033 
00034 #include "KDChartBarDiagram.h"
00035 #include "KDChartTextAttributes.h"
00036 #include "KDChartAttributesModel.h"
00037 #include "KDChartAbstractCartesianDiagram.h"
00038 
00039 using namespace KDChart;
00040 
00041 PercentLyingBarDiagram::PercentLyingBarDiagram( BarDiagram* d )
00042     : BarDiagramType( d )
00043 {
00044 }
00045 
00046 BarDiagram::BarType PercentLyingBarDiagram::type() const
00047 {
00048     return BarDiagram::Percent;
00049 }
00050 
00051 const QPair<QPointF, QPointF> PercentLyingBarDiagram::calculateDataBoundaries() const
00052 {
00053     //const int rowCount = compressor().modelDataRows();
00054     //const int colCount = compressor().modelDataColumns();
00055 
00056     const double xMin = 0;
00057     const double xMax = diagram()->model() ? diagram()->model()->rowCount( diagram()->rootIndex() ) : 0;
00058     double yMin = 0.0, yMax = 100.0;
00059     /*for( int col = 0; col < colCount; ++col )
00060     {
00061         for( int row = 0; row < rowCount; ++row )
00062         {
00063             // Ordinate should begin at 0 the max value being the 100% pos
00064             const QModelIndex idx = diagram()->model()->index( row, col, diagram()->rootIndex() );
00065             // only positive values are handled
00066             double value = diagram()->model()->data( idx ).toDouble();
00067             if ( value > 0 )
00068                 yMax = qMax( yMax, value );
00069         }
00070     }*/
00071     // special cases
00072     if (  yMax == yMin ) {
00073         if ( yMin == 0.0 )
00074             yMax = 0.1; //we need at least a range
00075         else
00076             yMax = 0.0; // they are the same but negative
00077     }
00078     const QPointF bottomLeft( QPointF( yMin, xMin ) );
00079     const QPointF topRight( QPointF( yMax, xMax ) );
00080 
00081     //qDebug() << "BarDiagram::calculateDataBoundaries () returns ( " << bottomLeft << topRight <<")";
00082     return QPair< QPointF, QPointF >( bottomLeft,  topRight );
00083 }
00084 
00085 void PercentLyingBarDiagram::paint( PaintContext* ctx )
00086 {
00087     reverseMapper().clear();
00088 
00089     const QPair<QPointF,QPointF> boundaries = diagram()->dataBoundaries(); // cached
00090 
00091     const QPointF boundLeft = ctx->coordinatePlane()->translate( boundaries.first ) ;
00092     const QPointF boundRight = ctx->coordinatePlane()->translate( boundaries.second );
00093 
00094     const int rowCount = compressor().modelDataRows();
00095     const int colCount = compressor().modelDataColumns();
00096 
00097     BarAttributes ba = diagram()->barAttributes( diagram()->model()->index( 0, 0, diagram()->rootIndex() ) );
00098     double barWidth = 0;
00099     double maxDepth = 0;
00100     double width = boundLeft.y() - boundRight.y();
00101     QPointF testVector = boundRight - boundLeft;
00102     double groupWidth = width/ (rowCount + 2);
00103     double spaceBetweenBars = 0;
00104     double spaceBetweenGroups = 0;
00105 
00106     if ( ba.useFixedBarWidth() ) {
00107         barWidth = ba.fixedBarWidth();
00108         groupWidth += barWidth;
00109 
00110         // Pending Michel set a min and max value for the groupWidth
00111         // related to the area.width
00112         if ( groupWidth < 0 )
00113             groupWidth = 0;
00114 
00115         if ( groupWidth  * rowCount > width )
00116             groupWidth = width / rowCount;
00117     }
00118 
00119     // maxLimit: allow the space between bars to be larger until area.width()
00120     // is covered by the groups.
00121     double maxLimit = rowCount * (groupWidth + ((colCount-1) * ba.fixedDataValueGap()) );
00122 
00123 
00124     //Pending Michel: FixMe
00125     if ( ba.useFixedDataValueGap() ) {
00126         if ( width > maxLimit )
00127             spaceBetweenBars += ba.fixedDataValueGap();
00128         else
00129             spaceBetweenBars = ((ctx->rectangle().width()/rowCount) - groupWidth)/(colCount-1);
00130     }
00131 
00132     if ( ba.useFixedValueBlockGap() )
00133         spaceBetweenGroups += ba.fixedValueBlockGap();
00134 
00135     calculateValueAndGapWidths( rowCount, colCount,groupWidth,
00136                                 barWidth, spaceBetweenBars, spaceBetweenGroups );
00137     
00138     DataValueTextInfoList list;
00139     const double maxValue = 100.0; // always 100 %
00140     double sumValues = 0;
00141     QVector <double > sumValuesVector;
00142 
00143     //calculate sum of values for each column and store
00144     for( int row = 0; row < rowCount; ++row )
00145     {
00146         for( int col = 0; col < colCount; ++col )
00147         {
00148             const CartesianDiagramDataCompressor::CachePosition position( row, col );
00149             const CartesianDiagramDataCompressor::DataPoint point = compressor().data( position );
00150             //if ( point.value > 0 )
00151             sumValues += qMax( point.value, -point.value );
00152             if ( col == colCount - 1 ) {
00153                 sumValuesVector <<  sumValues ;
00154                 sumValues = 0;
00155             }
00156         }
00157     }
00158 
00159     // calculate stacked percent value
00160     for( int curRow = rowCount - 1; curRow >= 0; --curRow )
00161     {
00162         double offset = spaceBetweenGroups;
00163         if( ba.useFixedBarWidth() )
00164             offset -= ba.fixedBarWidth();
00165         
00166         if( offset < 0 )
00167             offset = 0;
00168 
00169         for( int col = 0; col < colCount ; ++col )
00170         {
00171                 double threeDOffset = 0.0;
00172             const CartesianDiagramDataCompressor::CachePosition position( curRow, col );
00173             const CartesianDiagramDataCompressor::DataPoint p = compressor().data( position );
00174             QModelIndex sourceIndex = attributesModel()->mapToSource( p.index );
00175             ThreeDBarAttributes threeDAttrs = diagram()->threeDBarAttributes( sourceIndex );
00176 
00177             if ( threeDAttrs.isEnabled() ){
00178                 if ( barWidth > 0 ) {
00179                     barWidth =  (width - ((offset+(threeDAttrs.depth()))*rowCount))/ rowCount;
00180                         threeDOffset = threeDAttrs.depth();
00181                 }
00182                 if ( barWidth <= 0 ) {
00183                     barWidth = 0.1;
00184                     threeDOffset = (width - (offset*rowCount))/ rowCount;
00185                 }
00186             }else{
00187                 barWidth = (width - (offset*rowCount))/ rowCount;
00188             }
00189 
00190             const double value = qMax( p.value, -p.value );
00191             double stackedValues = 0.0;
00192             double key = 0.0;
00193             
00194             // calculate stacked percent value
00195             // we only take in account positives values for now.
00196             for( int k = col; k >= 0 ; --k )
00197             {
00198                 const CartesianDiagramDataCompressor::CachePosition position( curRow, k );
00199                 const CartesianDiagramDataCompressor::DataPoint point = compressor().data( position );
00200                 stackedValues += qMax( point.value, -point.value );
00201                 key = point.key;
00202             }
00203 
00204             QPointF point, previousPoint;
00205             if(  sumValuesVector.at( curRow ) != 0 && value > 0 ) {
00206                 QPointF dataPoint( ( stackedValues / sumValuesVector.at( curRow ) * maxValue ), rowCount - key );
00207                 point = ctx->coordinatePlane()->translate( dataPoint );
00208                 point.ry() += offset / 2 + threeDOffset;
00209 
00210                 previousPoint = ctx->coordinatePlane()->translate( QPointF( ( ( stackedValues - value) / sumValuesVector.at( curRow ) * maxValue ), rowCount - key ) );
00211             }
00212             
00213             const double barHeight = point.x() - previousPoint.x();
00214             
00215             point.setX ( point.x() - barHeight );
00216 
00217             const QRectF rect( point, QSizeF( barHeight, barWidth ) );
00218             appendDataValueTextInfoToList( diagram(), list, sourceIndex, PositionPoints( rect ),
00219                                               Position::NorthEast, Position::SouthWest,
00220                                               value );
00221             paintBars( ctx, sourceIndex, rect, maxDepth );
00222         }
00223     }
00224     paintDataValueTextsAndMarkers(  diagram(),  ctx,  list,  false );
00225 }

Generated on Thu Mar 4 23:19:12 2010 for KD Chart 2 by  doxygen 1.5.4