00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #include "KDChartRingPainter.h"
00030 #include "KDChartParams.h"
00031
00032 #include <qpainter.h>
00033 #include <qvaluestack.h>
00034
00035 #include <stdlib.h>
00036
00037 #define DEGTORAD(d) (d)*M_PI/180
00038
00052 KDChartRingPainter::KDChartRingPainter( KDChartParams* params ) :
00053 KDChartPainter( params )
00054 {
00055
00056
00057 }
00058
00059
00063 KDChartRingPainter::~KDChartRingPainter()
00064 {
00065
00066 }
00067
00068
00078 void KDChartRingPainter::paintData( QPainter* painter,
00079 KDChartTableDataBase* data,
00080 bool paint2nd,
00081 KDChartDataRegionList* regions )
00082 {
00083 uint chart = paint2nd ? 1 : 0;
00084
00085 QRect ourClipRect( _dataRect );
00086
00087 const QWMatrix & world = painter->worldMatrix();
00088 ourClipRect =
00089 #if COMPAT_QT_VERSION >= 0x030000
00090 world.mapRect( ourClipRect );
00091 #else
00092 world.map( ourClipRect );
00093 #endif
00094
00095 ourClipRect.setTop(ourClipRect.top()-1);
00096 ourClipRect.setLeft(ourClipRect.left()-1);
00097 ourClipRect.setBottom(ourClipRect.bottom()+1);
00098 ourClipRect.setRight(ourClipRect.right()+1);
00099 painter->setClipRect( ourClipRect );
00100
00101 uint datasetStart, datasetEnd;
00102 if ( params()->neverUsedSetChartSourceMode()
00103 || !params()->findDataset( KDChartParams::DataEntry,
00104 datasetStart,
00105 datasetEnd,
00106 chart ) ) {
00107 uint maxRow, maxRowMinus1;
00108 switch ( data->usedRows() ) {
00109 case 0:
00110 return ;
00111 case 1:
00112 maxRow = 0;
00113 maxRowMinus1 = 0;
00114 break;
00115 default:
00116 maxRow = data->usedRows() - 1;
00117 maxRowMinus1 = maxRow - 1;
00118 }
00119 datasetStart = paint2nd ? maxRow
00120 : 0;
00121 datasetEnd = paint2nd ? maxRow
00122 : ( ( KDChartParams::NoType
00123 == params()->additionalChartType() )
00124 ? maxRow
00125 : maxRowMinus1 );
00126 }
00127 uint datasetNum = abs( (int)( datasetEnd - datasetStart ) + 1 );
00128
00129
00130
00131
00132 if ( params()->numValues() != -1 )
00133 _numValues = params()->numValues();
00134 else
00135 _numValues = data->usedCols();
00136
00137
00138 _size = QMIN( _dataRect.width(), _dataRect.height() );
00139
00140
00141 if ( params()->explode() ) {
00142 double doubleSize = ( double ) _size;
00143 doubleSize /= ( 1.0 + params()->explodeFactor() * 2 );
00144 _size = ( int ) doubleSize;
00145 }
00146
00147 int x = ( _dataRect.width() == _size ) ? 0 : ( ( _dataRect.width() - _size ) / 2 );
00148 int y = ( _dataRect.height() == _size ) ? 0 : ( ( _dataRect.height() - _size ) / 2 );
00149 _position = QRect( x, y, _size, _size );
00150 _position.moveBy( _dataRect.left(), _dataRect.top() );
00151
00152
00153
00154 QMemArray<double> rowsums;
00155 double totalSum = 0.0;
00156 rowsums.resize( datasetEnd+1 );
00157 for( int d1 = (int)datasetStart; d1 <= (int)datasetEnd; d1++ ) {
00158 rowsums[d1] = data->rowAbsSum( d1 );
00159 totalSum += rowsums[d1];
00160 }
00161
00162 QMemArray<int> ringthicknesses;
00163 ringthicknesses.resize( datasetEnd+1 );
00164
00165
00166 int ringthickness = _size / ( datasetNum * 2 );
00167
00168
00169 if( ringthickness > ( _size/10 ) )
00170 ringthickness = _size / 10;
00171
00172 for( int d2 = (int)datasetStart; d2 <= (int)datasetEnd; d2++ )
00173 if( params()->relativeRingThickness() ) {
00174
00175
00176 ringthicknesses[d2] = (uint)floor( (rowsums[d2] / totalSum) *
00177 ( 2.0 * (double)ringthickness ) + 0.5 );
00178 } else {
00179 ringthicknesses[d2] = ringthickness;
00180 }
00181
00182 int currentouterradius = _size/2;
00183
00184
00185 for( int dataset = (int)datasetStart; dataset <= (int)datasetEnd; dataset++ ) {
00186 double sectorsPerValue = 5760.0 / rowsums[dataset];
00187
00188 double currentstartpos = (double)params()->ringStart() * 16.0;
00189
00190 QVariant vValY;
00191 for( int value = 0; value < _numValues; value++ ) {
00192
00193 double cellValue = 0.0;
00194 if( data->cellCoord( dataset, value, vValY, 1 ) &&
00195 QVariant::Double == vValY.type() ){
00196 cellValue = fabs( vValY.toDouble() );
00197
00198
00199
00200
00201
00202 QValueList<int> explodeList = params()->explodeValues();
00203 bool explode = params()->explode() &&
00204 ( dataset == (int)datasetStart ) &&
00205 ( ( explodeList.count() == 0 ) ||
00206 ( explodeList.find( value ) != explodeList.end() ) );
00207
00208 drawOneSegment( painter,
00209 currentouterradius,
00210 currentouterradius-ringthicknesses[dataset],
00211 currentstartpos,
00212 sectorsPerValue * cellValue,
00213 dataset, value, chart, explode, regions );
00214 }
00215 currentstartpos += sectorsPerValue * cellValue;
00216 }
00217 currentouterradius -= ringthicknesses[dataset];
00218 }
00219 }
00220
00221
00222
00223 void KDChartRingPainter::drawOneSegment( QPainter* painter,
00224 uint outerRadius,
00225 uint innerRadius,
00226 double startAngle,
00227 double angles,
00228 uint dataset,
00229 uint value,
00230 uint chart,
00231 bool explode,
00232 KDChartDataRegionList* regions )
00233 {
00234
00235 if( angles == 5760.0 )
00236 startAngle = 0.0;
00237
00238 painter->setPen( QPen( params()->outlineDataColor(),
00239 params()->outlineDataLineWidth() ) );
00240 painter->setBrush( params()->dataColor( value ) );
00241
00242 uint outerRadius2 = outerRadius * 2;
00243 uint innerRadius2 = innerRadius * 2;
00244
00245 QRect drawPosition = _position;
00246 if ( explode ) {
00247
00248 double explodeAngle = ( startAngle + angles / 2.0 ) / 16.0;
00249 double explodeAngleRad = DEGTORAD( explodeAngle );
00250 double cosAngle = cos( explodeAngleRad );
00251 double sinAngle = -sin( explodeAngleRad );
00252
00253
00254 double explodeFactor = 0.0;
00255 QMap<int,double> explodeFactors = params()->explodeFactors();
00256 if( !explodeFactors.contains( value ) )
00257 explodeFactor = params()->explodeFactor();
00258 else
00259 explodeFactor = explodeFactors[value];
00260
00261 double explodeX = explodeFactor * _size * cosAngle;
00262 double explodeY = explodeFactor * _size * sinAngle;
00263 drawPosition.moveBy( static_cast<int>( explodeX ), static_cast<int>( explodeY ) );
00264 }
00265
00266 QRect outerRect( drawPosition.x() +
00267 ( drawPosition.width() - outerRadius2 ) / 2,
00268 drawPosition.y() +
00269 ( drawPosition.height() - outerRadius2 ) / 2,
00270 outerRadius2, outerRadius2 );
00271 QRect innerRect( drawPosition.x() +
00272 ( drawPosition.width() - innerRadius2 ) / 2,
00273 drawPosition.y() +
00274 ( drawPosition.height() - innerRadius2 ) / 2,
00275 innerRadius2, innerRadius2 );
00276
00277
00278 QPointArray innerArc;
00279 makeArc( innerArc, innerRect, startAngle, angles );
00280
00281
00282 QPointArray outerArc;
00283 makeArc( outerArc, outerRect, startAngle, angles );
00284
00285
00286
00287 uint innerArcPoints = innerArc.size();
00288 uint outerArcPoints = outerArc.size();
00289 innerArc.resize( innerArcPoints + outerArcPoints );
00290 for ( int i = outerArcPoints - 1; i >= 0; i-- ) {
00291 innerArc.setPoint( innerArcPoints+outerArcPoints-i-1,
00292 outerArc.point( i ) );
00293 }
00294
00295 painter->drawPolygon( innerArc );
00296 if ( regions ) {
00297 KDChartDataRegion* datReg = new KDChartDataRegion( dataset,
00298 value,
00299 chart,
00300 innerArc );
00301
00302 const int aA = static_cast<int>( startAngle );
00303 const int aM = static_cast<int>( startAngle + angles / 2.0 );
00304 const int aZ = static_cast<int>( startAngle + angles );
00305
00306 datReg->points[ KDChartEnums::PosTopLeft ]
00307 = pointOnCircle( outerRect, aZ );
00308 datReg->points[ KDChartEnums::PosTopCenter ]
00309 = pointOnCircle( outerRect, aM );
00310 datReg->points[ KDChartEnums::PosTopRight ]
00311 = pointOnCircle( outerRect, aA );
00312
00313 datReg->points[ KDChartEnums::PosBottomLeft ]
00314 = pointOnCircle( innerRect, aZ );
00315 datReg->points[ KDChartEnums::PosBottomCenter ]
00316 = pointOnCircle( innerRect, aM );
00317 datReg->points[ KDChartEnums::PosBottomRight ]
00318 = pointOnCircle( innerRect, aA );
00319
00320 datReg->points[ KDChartEnums::PosCenterLeft ]
00321 = QPoint( ( datReg->points[ KDChartEnums::PosTopLeft ].x()
00322 + datReg->points[ KDChartEnums::PosBottomLeft ].x() ) / 2,
00323 ( datReg->points[ KDChartEnums::PosTopLeft ].y()
00324 + datReg->points[ KDChartEnums::PosBottomLeft ].y() ) / 2 );
00325 datReg->points[ KDChartEnums::PosCenter ]
00326 = QPoint( ( datReg->points[ KDChartEnums::PosTopCenter ].x()
00327 + datReg->points[ KDChartEnums::PosBottomCenter ].x() ) / 2,
00328 ( datReg->points[ KDChartEnums::PosTopCenter ].y()
00329 + datReg->points[ KDChartEnums::PosBottomCenter ].y() ) / 2 );
00330 datReg->points[ KDChartEnums::PosCenterRight ]
00331 = QPoint( ( datReg->points[ KDChartEnums::PosTopRight ].x()
00332 + datReg->points[ KDChartEnums::PosBottomRight ].x() ) / 2,
00333 ( datReg->points[ KDChartEnums::PosTopRight ].y()
00334 + datReg->points[ KDChartEnums::PosBottomRight ].y() ) / 2 );
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362 datReg->startAngle = static_cast<int>( startAngle );
00363 datReg->angleLen = static_cast<int>( angles );
00364 regions->append( datReg );
00365 }
00366 }
00367
00368
00382 QString KDChartRingPainter::fallbackLegendText( uint dataset ) const
00383 {
00384 return QObject::tr( "Item " ) + QString::number( dataset + 1 );
00385 }
00386
00387
00397 uint KDChartRingPainter::numLegendFallbackTexts( KDChartTableDataBase* data ) const
00398 {
00399 return data->usedCols();
00400 }