KDChartStackedBarDiagram_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 <QModelIndex>
00031 
00032 #include "KDChartBarDiagram.h"
00033 #include "KDChartTextAttributes.h"
00034 #include "KDChartAttributesModel.h"
00035 #include "KDChartAbstractCartesianDiagram.h"
00036 #include "KDChartStackedBarDiagram_p.h"
00037 
00038 using namespace KDChart;
00039 
00040 StackedBarDiagram::StackedBarDiagram( BarDiagram* d )
00041     : BarDiagramType( d )
00042 {
00043 }
00044 
00045 BarDiagram::BarType StackedBarDiagram::type() const
00046 {
00047     return BarDiagram::Stacked;
00048 }
00049 
00050 const QPair<QPointF, QPointF> StackedBarDiagram::calculateDataBoundaries() const
00051 {
00052     const int rowCount = compressor().modelDataRows();
00053     const int colCount = compressor().modelDataColumns();
00054 
00055     double xMin = 0;
00056     double xMax = diagram()->model() ? diagram()->model()->rowCount( diagram()->rootIndex() ) : 0;
00057     double yMin = 0, yMax = 0;
00058 
00059     bool bStarting = true;
00060     for( int row = 0; row < rowCount; ++row )
00061     {
00062         // calculate sum of values per column - Find out stacked Min/Max
00063         double stackedValues = 0.0;
00064         double negativeStackedValues = 0.0;
00065         for ( int col = 0; col < colCount ; ++col )
00066         {
00067             const CartesianDiagramDataCompressor::CachePosition position( row, col );
00068             const CartesianDiagramDataCompressor::DataPoint point = compressor().data( position );
00069 
00070             if( point.value > 0.0 )
00071                 stackedValues += point.value;
00072             else
00073                 negativeStackedValues += point.value;
00074 
00075             // this is always true yMin can be 0 in case all values
00076             // are the same
00077             // same for yMax it can be zero if all values are negative
00078             if( bStarting ){
00079                 yMin = negativeStackedValues < 0.0 ? negativeStackedValues : stackedValues;
00080                 yMax = stackedValues > 0.0 ? stackedValues : negativeStackedValues;
00081                 bStarting = false;
00082             }else{
00083                 yMin = qMin( qMin( yMin, stackedValues ), negativeStackedValues );
00084                 yMax = qMax( qMax( yMax, stackedValues ), negativeStackedValues );
00085             }
00086         }
00087     }
00088     // special cases
00089     if (  yMax == yMin ) {
00090         if ( yMin == 0.0 )
00091             yMax = 0.1; //we need at least a range
00092         else if( yMax < 0.0 )
00093             yMax = 0.0; // they are the same and negative
00094         else if( yMin > 0.0 )
00095             yMin = 0.0; // they are the same but positive
00096     }
00097     const QPointF bottomLeft ( QPointF( xMin, yMin ) );
00098     const QPointF topRight ( QPointF( xMax, yMax ) );
00099 
00100     return QPair< QPointF, QPointF >( bottomLeft,  topRight );
00101 }
00102 
00103 void StackedBarDiagram::paint(  PaintContext* ctx )
00104 {
00105     reverseMapper().clear();
00106 
00107     const QPair<QPointF,QPointF> boundaries = diagram()->dataBoundaries(); // cached
00108 
00109     const QPointF boundLeft = ctx->coordinatePlane()->translate( boundaries.first ) ;
00110     const QPointF boundRight = ctx->coordinatePlane()->translate( boundaries.second );
00111 
00112     const int rowCount = compressor().modelDataRows();
00113     const int colCount = compressor().modelDataColumns();
00114 
00115     BarAttributes ba = diagram()->barAttributes( diagram()->model()->index( 0, 0, diagram()->rootIndex() ) );
00116     double barWidth = 0;
00117     double maxDepth = 0;
00118     double width = boundRight.x() - boundLeft.x();
00119     double groupWidth = width/ (rowCount + 2);
00120     double spaceBetweenBars = 0;
00121     double spaceBetweenGroups = 0;
00122 
00123     if ( ba.useFixedBarWidth() ) {
00124         barWidth = ba.fixedBarWidth();
00125         groupWidth += barWidth;
00126 
00127         // Pending Michel set a min and max value for the groupWidth
00128         // related to the area.width
00129         if ( groupWidth < 0 )
00130             groupWidth = 0;
00131 
00132         if ( groupWidth  * rowCount > width )
00133             groupWidth = width / rowCount;
00134     }
00135 
00136     // maxLimit: allow the space between bars to be larger until area.width()
00137     // is covered by the groups.
00138     double maxLimit = rowCount * (groupWidth + ((colCount-1) * ba.fixedDataValueGap()) );
00139 
00140 
00141     //Pending Michel: FixMe
00142     if ( ba.useFixedDataValueGap() ) {
00143         if ( width > maxLimit )
00144             spaceBetweenBars += ba.fixedDataValueGap();
00145         else
00146             spaceBetweenBars = ((width/rowCount) - groupWidth)/(colCount-1);
00147     }
00148 
00149     if ( ba.useFixedValueBlockGap() )
00150         spaceBetweenGroups += ba.fixedValueBlockGap();
00151 
00152     calculateValueAndGapWidths( rowCount, colCount,groupWidth,
00153                                 barWidth, spaceBetweenBars, spaceBetweenGroups );
00154 
00155     DataValueTextInfoList list;
00156     for( int col = 0; col < colCount; ++col )
00157     {
00158         double offset = spaceBetweenGroups;
00159         if( ba.useFixedBarWidth() )
00160             offset -= ba.fixedBarWidth();
00161         
00162         if( offset < 0 )
00163             offset = 0;
00164 
00165         for( int row = 0; row < rowCount; ++row )
00166         {
00167             const CartesianDiagramDataCompressor::CachePosition position( row, col );
00168             const CartesianDiagramDataCompressor::DataPoint p = compressor().data( position );
00169  
00170             const QModelIndex index = attributesModel()->mapToSource( p.index );
00171             ThreeDBarAttributes threeDAttrs = diagram()->threeDBarAttributes( index );
00172             const double value = p.value;
00173             double stackedValues = 0.0;
00174             double key = 0.0;
00175 
00176             if ( threeDAttrs.isEnabled() ) {
00177                 if ( barWidth > 0 )
00178                     barWidth =  (width - ((offset+(threeDAttrs.depth()))*rowCount))/ rowCount;
00179                 if ( barWidth <= 0 ) {
00180                     barWidth = 0;
00181                     maxDepth = offset - (width/rowCount);
00182                 }
00183             } else
00184                 barWidth =  (width - (offset*rowCount))/ rowCount ;
00185 
00186             for ( int k = col; k >= 0; --k )
00187             {
00188                 const CartesianDiagramDataCompressor::CachePosition position( row, k );
00189                 const CartesianDiagramDataCompressor::DataPoint point = compressor().data( position );
00190                 if( p.value >= 0.0 && point.value >= 0.0 || p.value < 0.0 && point.value < 0.0 )
00191                     stackedValues += point.value;
00192                 key = point.key;
00193             }
00194             QPointF point = ctx->coordinatePlane()->translate( QPointF( key, stackedValues ) );
00195             point.rx() += offset / 2;
00196             const QPointF previousPoint = ctx->coordinatePlane()->translate( QPointF( key, stackedValues - value ) );
00197             const double barHeight = previousPoint.y() - point.y();
00198 
00199             const QRectF rect( point, QSizeF( barWidth , barHeight ) );
00200             appendDataValueTextInfoToList( diagram(), list, index, PositionPoints( rect ),
00201                                               Position::NorthWest, Position::SouthEast,
00202                                               value );
00203             paintBars( ctx, index, rect, maxDepth );
00204         }
00205     }
00206     paintDataValueTextsAndMarkers( diagram(), ctx, list, false );
00207 }

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