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