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 #include <QDebug>
00027 #include <QPainter>
00028 #include <QStack>
00029
00030 #include "KDChartAttributesModel.h"
00031 #include "KDChartPaintContext.h"
00032 #include "KDChartPieDiagram.h"
00033 #include "KDChartPieDiagram_p.h"
00034 #include "KDChartPieAttributes.h"
00035 #include "KDChartThreeDPieAttributes.h"
00036 #include "KDChartPainterSaver_p.h"
00037 #include "KDChartDataValueAttributes.h"
00038
00039 #include <KDABLibFakes>
00040
00041
00042 using namespace KDChart;
00043
00044 PieDiagram::Private::Private()
00045 {
00046 }
00047
00048 PieDiagram::Private::~Private() {}
00049
00050 #define d d_func()
00051
00052 PieDiagram::PieDiagram( QWidget* parent, PolarCoordinatePlane* plane ) :
00053 AbstractPieDiagram( new Private(), parent, plane )
00054 {
00055 init();
00056 }
00057
00058 PieDiagram::~PieDiagram()
00059 {
00060 }
00061
00062 void PieDiagram::init()
00063 {
00064 }
00065
00069 PieDiagram * PieDiagram::clone() const
00070 {
00071 return new PieDiagram( new Private( *d ) );
00072 }
00073
00074 const QPair<QPointF, QPointF> PieDiagram::calculateDataBoundaries () const
00075 {
00076 if ( !checkInvariants( true ) ) return QPair<QPointF, QPointF>( QPointF( 0, 0 ), QPointF( 0, 0 ) );
00077
00078 const PieAttributes attrs( pieAttributes( model()->index( 0, 0, rootIndex() ) ) );
00079
00080 QPointF bottomLeft ( QPointF( 0, 0 ) );
00081 QPointF topRight;
00082
00083
00084 if ( attrs.explode() ) {
00085 const int colCount = columnCount();
00086 qreal maxExplode = 0.0;
00087 for( int j = 0; j < colCount; ++j ){
00088 const PieAttributes columnAttrs( pieAttributes( model()->index( 0, j, rootIndex() ) ) );
00089 maxExplode = qMax( maxExplode, columnAttrs.explodeFactor() );
00090 }
00091 topRight = QPointF( 1.0+maxExplode, 1.0+maxExplode );
00092 }else{
00093 topRight = QPointF( 1.0, 1.0 );
00094 }
00095 return QPair<QPointF, QPointF> ( bottomLeft, topRight );
00096 }
00097
00098
00099 void PieDiagram::paintEvent( QPaintEvent* )
00100 {
00101 QPainter painter ( viewport() );
00102 PaintContext ctx;
00103 ctx.setPainter ( &painter );
00104 ctx.setRectangle( QRectF ( 0, 0, width(), height() ) );
00105 paint ( &ctx );
00106 }
00107
00108 void PieDiagram::resizeEvent ( QResizeEvent*)
00109 {
00110 }
00111
00112 void PieDiagram::resize ( const QSizeF& )
00113 {
00114 }
00115
00116 static QRectF buildReferenceRect( const PolarCoordinatePlane* plane )
00117 {
00118 QRectF contentsRect;
00119
00120 QPointF referencePointAtTop = plane->translate( QPointF( 1, 0 ) );
00121 QPointF temp = plane->translate( QPointF( 0, 0 ) ) - referencePointAtTop;
00122 const double offset = temp.y();
00123 referencePointAtTop.setX( referencePointAtTop.x() - offset );
00124 contentsRect.setTopLeft( referencePointAtTop );
00125 contentsRect.setBottomRight( referencePointAtTop + QPointF( 2*offset, 2*offset) );
00126
00127 return contentsRect;
00128 }
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172 void PieDiagram::paint( PaintContext* ctx )
00173 {
00174
00175
00176 if ( !checkInvariants(true) )
00177 return;
00178
00179 const PieAttributes attrs( pieAttributes() );
00180 const ThreeDPieAttributes threeDAttrs( threeDPieAttributes( model()->index( 0, 0, rootIndex() ) ) );
00181
00182 const int colCount = columnCount();
00183
00184 QRectF contentsRect( buildReferenceRect( polarCoordinatePlane() ) );
00185 contentsRect = ctx->rectangle();
00186
00187
00188 if( contentsRect.isEmpty() )
00189 return;
00190
00191 DataValueTextInfoList list;
00192 const qreal sum = valueTotals();
00193
00194 if( sum == 0.0 )
00195 return;
00196
00197 d->startAngles.resize( colCount );
00198 d->angleLens.resize( colCount );
00199
00200
00201 d->size = qMin( contentsRect.width(), contentsRect.height() );
00202
00203
00204
00205 qreal maxExplode = 0.0;
00206 for( int j = 0; j < colCount; ++j ){
00207 const PieAttributes columnAttrs( pieAttributes( model()->index( 0, j, rootIndex() ) ) );
00208 maxExplode = qMax( maxExplode, columnAttrs.explodeFactor() );
00209 }
00210 d->size /= ( 1.0 + 2.0 * maxExplode );
00211
00212
00213 qreal sizeFor3DEffect = 0.0;
00214 if ( ! threeDAttrs.isEnabled() ) {
00215
00216 qreal x = ( contentsRect.width() == d->size ) ? 0.0 : ( ( contentsRect.width() - d->size ) / 2.0 );
00217 qreal y = ( contentsRect.height() == d->size ) ? 0.0 : ( ( contentsRect.height() - d->size ) / 2.0 );
00218 d->position = QRectF( x, y, d->size, d->size );
00219 d->position.translate( contentsRect.left(), contentsRect.top() );
00220 } else {
00221
00222 qreal x = ( contentsRect.width() == d->size ) ? 0.0 : ( ( contentsRect.width() - d->size ) / 2.0 );
00223 qreal height = d->size;
00224
00225
00226 if ( threeDAttrs.depth() >= 0.0 ) {
00227
00228 sizeFor3DEffect = threeDAttrs.depth();
00229 height = d->size - sizeFor3DEffect;
00230 } else {
00231
00232 sizeFor3DEffect = - threeDAttrs.depth() / 100.0 * height;
00233 height = d->size - sizeFor3DEffect;
00234 }
00235 qreal y = ( contentsRect.height() == height ) ? 0.0 : ( ( contentsRect.height() - height - sizeFor3DEffect ) / 2.0 );
00236
00237 d->position = QRectF( contentsRect.left() + x, contentsRect.top() + y,
00238 d->size, height );
00239
00240 }
00241
00242 const PolarCoordinatePlane * plane = polarCoordinatePlane();
00243 const qreal sectorsPerValue = 360.0 / sum;
00244 qreal currentValue = plane ? plane->startPosition() : 0.0;
00245
00246 bool atLeastOneValue = false;
00247 QVariant vValY;
00248 for ( int iColumn = 0; iColumn < colCount; ++iColumn ) {
00249
00250 bool bOK;
00251 const double cellValue = qAbs( model()->data( model()->index( 0, iColumn, rootIndex() ) )
00252 .toDouble( &bOK ) );
00253
00254 if( bOK ){
00255 d->startAngles[ iColumn ] = currentValue;
00256 d->angleLens[ iColumn ] = cellValue * sectorsPerValue;
00257 atLeastOneValue = true;
00258 } else {
00259 d->angleLens[ iColumn ] = 0.0;
00260 if ( iColumn > 0.0 )
00261 d->startAngles[ iColumn ] = d->startAngles[ iColumn - 1 ];
00262 else
00263 d->startAngles[ iColumn ] = currentValue;
00264 }
00265
00266
00267
00268
00269 currentValue = d->startAngles[ iColumn ] + d->angleLens[ iColumn ];
00270 }
00271
00272
00273
00274 if( ! atLeastOneValue )
00275 return;
00276
00277
00278
00279
00280 int backmostpie = findPieAt( 90, colCount );
00281
00282 int frontmostpie = findPieAt( 270, colCount );
00283
00284 int rightmostpie = findPieAt( 0, colCount );
00285 int leftmostpie = findPieAt( 180, colCount );
00286
00287
00288 int currentLeftPie = backmostpie;
00289 int currentRightPie = backmostpie;
00290
00291 drawOnePie( ctx->painter(), 0, backmostpie, granularity(), sizeFor3DEffect );
00292
00293 if( backmostpie == frontmostpie )
00294 {
00295 if( backmostpie == leftmostpie )
00296 currentLeftPie = findLeftPie( currentLeftPie, colCount );
00297 if( backmostpie == rightmostpie )
00298 currentRightPie = findRightPie( currentRightPie, colCount );
00299 }
00300 while( currentLeftPie != frontmostpie )
00301 {
00302 if( currentLeftPie != backmostpie )
00303 drawOnePie( ctx->painter(), 0, currentLeftPie, granularity(), sizeFor3DEffect );
00304 currentLeftPie = findLeftPie( currentLeftPie, colCount );
00305 }
00306 while( currentRightPie != frontmostpie )
00307 {
00308 if( currentRightPie != backmostpie )
00309 drawOnePie( ctx->painter(), 0, currentRightPie, granularity(), sizeFor3DEffect );
00310 currentRightPie = findRightPie( currentRightPie, colCount );
00311 }
00312
00313
00314 if( backmostpie != frontmostpie || ! threeDPieAttributes().isEnabled() )
00315 {
00316 drawOnePie( ctx->painter(), 0, frontmostpie, granularity(), sizeFor3DEffect );
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336 }
00337 }
00338
00339 #if defined ( Q_WS_WIN)
00340 #define trunc(x) ((int)(x))
00341 #endif
00342
00343 QRectF PieDiagram::piePosition( uint dataset, uint pie ) const
00344 {
00345 Q_UNUSED( dataset );
00346 qreal angleLen = d->angleLens[ pie ];
00347 qreal startAngle = d->startAngles[ pie ];
00348 QModelIndex index( model()->index( 0, pie, rootIndex() ) );
00349 const PieAttributes attrs( pieAttributes( index ) );
00350 const ThreeDPieAttributes threeDAttrs( threeDPieAttributes( index ) );
00351
00352 QRectF drawPosition( d->position );
00353
00354 if ( attrs.explode() ) {
00355 qreal explodeAngle = ( startAngle + angleLen / 2.0 );
00356 qreal explodeAngleRad = DEGTORAD( explodeAngle );
00357 qreal cosAngle = cos( explodeAngleRad );
00358 qreal sinAngle = -sin( explodeAngleRad );
00359 qreal explodeX = attrs.explodeFactor() * d->size * cosAngle;
00360 qreal explodeY = attrs.explodeFactor() * d->size * sinAngle;
00361 drawPosition.translate( explodeX, explodeY );
00362 }else{
00363 drawPosition = d->position;
00364 }
00365 return drawPosition;
00366 }
00367
00376 void PieDiagram::drawOnePie( QPainter* painter,
00377 uint dataset, uint pie,
00378 qreal granularity,
00379 qreal threeDPieHeight )
00380 {
00381 Q_UNUSED( threeDPieHeight );
00382
00383 const qreal angleLen = d->angleLens[ pie ];
00384 if ( angleLen ) {
00385 const QModelIndex index( model()->index( 0, pie, rootIndex() ) );
00386 const PieAttributes attrs( pieAttributes( index ) );
00387 const ThreeDPieAttributes threeDAttrs( threeDPieAttributes( index ) );
00388
00389 const QRectF drawPosition = piePosition( dataset, pie );
00390
00391 draw3DEffect( painter,
00392 drawPosition, dataset, pie,
00393 granularity,
00394 threeDAttrs,
00395 attrs.explode() );
00396
00397 drawPieSurface( painter, dataset, pie, granularity );
00398 }
00399 }
00400
00408 void PieDiagram::drawPieSurface( QPainter* painter,
00409 uint dataset, uint pie,
00410 qreal granularity )
00411 {
00412
00413 qreal angleLen = d->angleLens[ pie ];
00414 if ( angleLen ) {
00415 qreal startAngle = d->startAngles[ pie ];
00416
00417 QModelIndex index( model()->index( 0, pie, rootIndex() ) );
00418 const PieAttributes attrs( pieAttributes( index ) );
00419 const ThreeDPieAttributes threeDAttrs( threeDPieAttributes( index ) );
00420
00421 QRectF drawPosition = piePosition( dataset, pie );
00422
00423 QPen pen = this->pen( index );
00424 painter->setRenderHint ( QPainter::Antialiasing );
00425 painter->setBrush( brush( index ) );
00426
00427
00428
00429
00430 if ( angleLen == 360 ) {
00431
00432 painter->drawEllipse( drawPosition );
00433 } else {
00434
00435
00436 const int arcPoints = static_cast<int>(trunc( angleLen / granularity ));
00437 QPolygonF poly( arcPoints+2 );
00438 qreal degree=0.0;
00439 int iPoint = 0;
00440 bool perfectMatch = false;
00441
00442 while ( degree <= angleLen ){
00443 poly[ iPoint ] = pointOnCircle( drawPosition, startAngle + degree );
00444
00445 perfectMatch = (degree == angleLen);
00446 degree += granularity;
00447 ++iPoint;
00448 }
00449 int last = poly.size();
00450
00451 if( ! perfectMatch ){
00452 poly[ iPoint ] = pointOnCircle( drawPosition, startAngle + angleLen );
00453
00454
00455 poly.append( drawPosition.center() );
00456 }else{
00457 poly[ iPoint ] = drawPosition.center();
00458 }
00459
00460
00461 const qreal sum = valueTotals();
00462 painter->drawPolygon( poly );
00463
00464 QLineF centerLine( drawPosition.center(),
00465 QPointF( (poly[ last - 2].x() + poly.first().x())/2,
00466 ( poly.first().y() + poly[last-2].y() )/2 ) );
00467 QPointF valuePos( ( centerLine.x1() + centerLine.x2() )/2,
00468 ( centerLine.y1() + centerLine.y2() )/2 ) ;
00469
00470 paintDataValueText( painter, index, valuePos, angleLen*sum / 360 );
00471
00472 }
00473 }
00474 }
00475
00476
00486 void PieDiagram::draw3DEffect( QPainter* painter,
00487 const QRectF& drawPosition,
00488 uint dataset, uint pie,
00489 qreal granularity,
00490 const ThreeDPieAttributes& threeDAttrs,
00491 bool )
00492 {
00493 Q_UNUSED( dataset );
00494
00495 if( ! threeDAttrs.isEnabled() )
00496 return;
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506 if( threeDAttrs.useShadowColors() ){
00507 const QPen pen = this->pen( model()->index( 0, pie, rootIndex() ) );
00508 painter->setBrush( QBrush( pen.color() ) );
00509 }
00510
00511
00512
00513 qreal startAngle = d->startAngles[ pie ];
00514 qreal endAngle = startAngle + d->angleLens[ pie ];
00515
00516 while ( startAngle >= 360 )
00517 startAngle -= 360;
00518 while ( endAngle >= 360 )
00519 endAngle -= 360;
00520 Q_ASSERT( startAngle >= 0 && startAngle <= 360 );
00521 Q_ASSERT( endAngle >= 0 && endAngle <= 360 );
00522
00523
00524
00525 if ( startAngle == endAngle ||
00526 startAngle == endAngle - 360 ) {
00527 drawArcEffectSegment( painter, drawPosition,
00528 threeDAttrs.depth(),
00529 180, 360, granularity );
00530 } else if ( startAngle <= 90 ) {
00531 if ( endAngle <= 90 ) {
00532 if ( startAngle <= endAngle ) {
00534 drawStraightEffectSegment( painter, drawPosition,
00535 threeDAttrs.depth(), startAngle );
00536 drawUpperBrinkEffect( painter, drawPosition, endAngle );
00537 } else {
00539 drawStraightEffectSegment( painter, drawPosition,
00540 threeDAttrs.depth(), startAngle );
00541 drawUpperBrinkEffect( painter, drawPosition, endAngle );
00542 drawArcEffectSegment( painter, drawPosition,
00543 threeDAttrs.depth(),
00544 180, 360, granularity );
00545 }
00546 } else if ( endAngle <= 180 ) {
00549 drawStraightEffectSegment( painter, drawPosition,
00550 threeDAttrs.depth(), startAngle );
00551 drawStraightEffectSegment( painter, drawPosition,
00552 threeDAttrs.depth(), endAngle );
00553 } else if ( endAngle <= 270 ) {
00555 drawStraightEffectSegment( painter, drawPosition,
00556 threeDAttrs.depth(), startAngle );
00557 drawStraightEffectSegment( painter, drawPosition,
00558 threeDAttrs.depth(), endAngle );
00559 drawArcEffectSegment( painter, drawPosition,
00560 threeDAttrs.depth(),
00561 180, endAngle, granularity );
00562 } else {
00565 drawStraightEffectSegment( painter, drawPosition,
00566 threeDAttrs.depth(), startAngle );
00567 drawUpperBrinkEffect( painter, drawPosition, endAngle );
00568 drawArcEffectSegment( painter, drawPosition,
00569 threeDAttrs.depth(),
00570 180, endAngle, granularity );
00571 }
00572 } else if ( startAngle <= 180 ) {
00573 if ( endAngle <= 90 ) {
00574 drawArcEffectSegment( painter, drawPosition,
00575 threeDAttrs.depth(),
00576 180, 360, granularity );
00577 drawUpperBrinkEffect( painter, drawPosition, startAngle );
00578 drawUpperBrinkEffect( painter, drawPosition, endAngle );
00579 } else if ( endAngle <= 180 ) {
00580 if ( startAngle <= endAngle ) {
00583 drawStraightEffectSegment( painter, drawPosition,
00584 threeDAttrs.depth(), endAngle );
00585 drawUpperBrinkEffect( painter, drawPosition, startAngle );
00586 } else {
00589 drawStraightEffectSegment( painter, drawPosition,
00590 threeDAttrs.depth(), endAngle );
00591 drawUpperBrinkEffect( painter, drawPosition, startAngle );
00592 drawArcEffectSegment( painter, drawPosition,
00593 threeDAttrs.depth(),
00594 180, 360, granularity );
00595 }
00596 } else if ( endAngle <= 270 ) {
00597 drawStraightEffectSegment( painter, drawPosition,
00598 threeDAttrs.depth(), endAngle );
00599 drawUpperBrinkEffect( painter, drawPosition, startAngle );
00600 drawArcEffectSegment( painter, drawPosition,
00601 threeDAttrs.depth(),
00602 180, endAngle, granularity );
00603 } else {
00604 drawArcEffectSegment( painter, drawPosition,
00605 threeDAttrs.depth(),
00606 180, endAngle, granularity );
00607 drawUpperBrinkEffect( painter, drawPosition, startAngle );
00608 drawUpperBrinkEffect( painter, drawPosition, endAngle );
00609 }
00610 } else if ( startAngle <= 270 ) {
00611 if ( endAngle <= 90 ) {
00612 drawArcEffectSegment( painter, drawPosition,
00613 threeDAttrs.depth(),
00614 startAngle, 360, granularity );
00615 drawUpperBrinkEffect( painter, drawPosition, startAngle );
00616 drawUpperBrinkEffect( painter, drawPosition, endAngle );
00617 } else if ( endAngle <= 180 ) {
00618 drawStraightEffectSegment( painter, drawPosition,
00619 threeDAttrs.depth(), endAngle );
00620 drawUpperBrinkEffect( painter, drawPosition, startAngle );
00621 drawArcEffectSegment( painter, drawPosition,
00622 threeDAttrs.depth(),
00623 startAngle, 360, granularity );
00624 } else if ( endAngle <= 270 ) {
00625 if ( startAngle <= endAngle ) {
00628 drawStraightEffectSegment( painter, drawPosition,
00629 threeDAttrs.depth(), endAngle );
00630 drawUpperBrinkEffect( painter, drawPosition, startAngle );
00631 drawArcEffectSegment( painter, drawPosition,
00632 threeDAttrs.depth(),
00633 startAngle, endAngle, granularity );
00634 } else {
00637 drawStraightEffectSegment( painter, drawPosition,
00638 threeDAttrs.depth(), endAngle );
00639 drawUpperBrinkEffect( painter, drawPosition, startAngle );
00640 drawArcEffectSegment( painter, drawPosition,
00641 threeDAttrs.depth(),
00642 180, endAngle, granularity );
00643 drawArcEffectSegment( painter, drawPosition,
00644 threeDAttrs.depth(),
00645 startAngle, 360, granularity );
00646 }
00647 } else {
00648 drawArcEffectSegment( painter, drawPosition,
00649 threeDAttrs.depth(),
00650 startAngle, endAngle, granularity );
00651 drawUpperBrinkEffect( painter, drawPosition, startAngle );
00652 drawUpperBrinkEffect( painter, drawPosition, endAngle );
00653 }
00654 } else {
00655 if ( endAngle <= 90 ) {
00656 drawStraightEffectSegment( painter, drawPosition,
00657 threeDAttrs.depth(), startAngle );
00658 drawUpperBrinkEffect( painter, drawPosition, endAngle );
00659 drawArcEffectSegment( painter, drawPosition,
00660 threeDAttrs.depth(),
00661 startAngle, 360, granularity );
00662 } else if ( endAngle <= 180 ) {
00663 drawStraightEffectSegment( painter, drawPosition,
00664 threeDAttrs.depth(), startAngle );
00665 drawStraightEffectSegment( painter, drawPosition,
00666 threeDAttrs.depth(), endAngle );
00667 drawArcEffectSegment( painter, drawPosition,
00668 threeDAttrs.depth(),
00669 startAngle, 360, granularity );
00670 } else if ( endAngle <= 270 ) {
00671 drawStraightEffectSegment( painter, drawPosition,
00672 threeDAttrs.depth(), startAngle );
00673 drawStraightEffectSegment( painter, drawPosition,
00674 threeDAttrs.depth(), endAngle );
00675 drawArcEffectSegment( painter, drawPosition,
00676 threeDAttrs.depth(),
00677 180, endAngle, granularity );
00678 drawArcEffectSegment( painter, drawPosition,
00679 threeDAttrs.depth(),
00680 startAngle, 360, granularity );
00681 } else {
00682 if ( startAngle <= endAngle ) {
00685 drawStraightEffectSegment( painter, drawPosition,
00686 threeDAttrs.depth(), startAngle );
00687 drawUpperBrinkEffect( painter, drawPosition, endAngle );
00688 drawArcEffectSegment( painter, drawPosition,
00689 threeDAttrs.depth(),
00690 startAngle, endAngle, granularity );
00691 } else {
00694 drawStraightEffectSegment( painter, drawPosition,
00695 threeDAttrs.depth(), startAngle );
00696 drawUpperBrinkEffect( painter, drawPosition, endAngle );
00697 drawArcEffectSegment( painter, drawPosition,
00698 threeDAttrs.depth(),
00699 startAngle, 360, granularity );
00700 drawArcEffectSegment( painter, drawPosition,
00701 threeDAttrs.depth(),
00702 180, endAngle, granularity );
00703 }
00704 }
00705 }
00706 drawArcUpperBrinkEffectSegment( painter, drawPosition, startAngle, endAngle, granularity );
00707 }
00708
00709
00718 void PieDiagram::drawStraightEffectSegment( QPainter* painter,
00719 const QRectF& rect,
00720 qreal threeDHeight,
00721 qreal angle )
00722 {
00723 QPolygonF poly( 4 );
00724 const QPointF center = rect.center();
00725 const QPointF circlePoint = pointOnCircle( rect, angle );
00726 poly[0] = center;
00727 poly[1] = circlePoint;
00728 poly[2] = QPointF( circlePoint.x(), circlePoint.y() + threeDHeight );
00729 poly[3] = QPointF( center.x(), center.y() + threeDHeight );
00730 painter->drawPolygon( poly );
00731
00732
00733 }
00734
00742 void PieDiagram::drawUpperBrinkEffect( QPainter* painter,
00743 const QRectF& rect,
00744 qreal angle )
00745 {
00746 const QPointF center = rect.center();
00747 const QPointF circlePoint = pointOnCircle( rect, angle );
00748 painter->drawLine( center, circlePoint );
00749 }
00750
00760 void PieDiagram::drawArcEffectSegment( QPainter* painter,
00761 const QRectF& rect,
00762 qreal threeDHeight,
00763 qreal startAngle,
00764 qreal endAngle,
00765 qreal granularity )
00766 {
00767
00768 qreal startA = qMin( startAngle, endAngle );
00769 qreal endA = qMax( startAngle, endAngle );
00770
00771
00772 if( endA > 540 )
00773 drawArcEffectSegment( painter, rect, threeDHeight, 180, endA - 360, granularity );
00774 if( endA > 360 )
00775 endA = qMin( endA, 360.0 );
00776
00777 int numHalfPoints = static_cast<int>( trunc( ( endA - startA ) / granularity ) ) + 1;
00778
00779 QPolygonF poly( numHalfPoints );
00780
00781 qreal degree = endA;
00782 int iPoint = 0;
00783 bool perfectMatch = false;
00784 while ( degree >= startA ){
00785 poly[ numHalfPoints - iPoint - 1 ] = pointOnCircle( rect, degree );
00786
00787 perfectMatch = (degree == startA);
00788 degree -= granularity;
00789 ++iPoint;
00790 }
00791
00792 if( ! perfectMatch ){
00793 poly.prepend( pointOnCircle( rect, startA ) );
00794 ++numHalfPoints;
00795 }
00796
00797 poly.resize( numHalfPoints * 2 );
00798
00799
00800
00801 for ( int i = numHalfPoints - 1; i >= 0; --i ) {
00802 QPointF pointOnFirstArc( poly[ i ] );
00803 pointOnFirstArc.setY( pointOnFirstArc.y() + threeDHeight );
00804 poly[ numHalfPoints * 2 - i - 1 ] = pointOnFirstArc;
00805 }
00806
00807 painter->drawPolygon( poly );
00808
00809
00810 }
00811
00820 void PieDiagram::drawArcUpperBrinkEffectSegment( QPainter* painter,
00821 const QRectF& rect,
00822 qreal startAngle,
00823 qreal endAngle,
00824 qreal granularity )
00825 {
00826 if ( endAngle < startAngle )
00827 endAngle += 360;
00828
00829 const qreal startA = qMin( startAngle, endAngle );
00830 const qreal endA = qMax( startAngle, endAngle );
00831
00832 int numHalfPoints = static_cast<int>( trunc( ( endA - startA ) / granularity ) ) + 1;
00833
00834 QPolygonF poly( numHalfPoints );
00835
00836 qreal degree = endA;
00837 int iPoint = 0;
00838 bool perfectMatch = false;
00839 while ( degree >= startA ){
00840 poly[ numHalfPoints - iPoint - 1 ] = pointOnCircle( rect, degree );
00841
00842 perfectMatch = (degree == startA);
00843 degree -= granularity;
00844 ++iPoint;
00845 }
00846
00847 if( ! perfectMatch ){
00848 poly.prepend( pointOnCircle( rect, startA ) );
00849 ++numHalfPoints;
00850 }
00851
00852 painter->drawPolyline( poly );
00853
00854
00855 }
00856
00864 uint PieDiagram::findPieAt( qreal angle, int colCount )
00865 {
00866 for ( int i = 0; i < colCount; ++i ) {
00867 qreal endseg = d->startAngles[ i ] + d->angleLens[ i ];
00868 if ( ( d->startAngles[ i ] <= angle ) &&
00869 ( endseg >= angle ) )
00870
00871 return i;
00872 }
00873
00874
00875
00876 if ( angle < 360 )
00877 return findPieAt( angle + 360, colCount );
00878
00879 return 0;
00880 }
00881
00882
00890 uint PieDiagram::findLeftPie( uint pie, int colCount )
00891 {
00892 if ( pie == 0 )
00893 if ( colCount > 1 )
00894 return colCount - 1;
00895 else
00896 return 0;
00897 else {
00898 return pie - 1;
00899 }
00900 }
00901
00902
00910 uint PieDiagram::findRightPie( uint pie, int colCount )
00911 {
00912 int rightpie = pie + 1;
00913 if ( rightpie == colCount )
00914 rightpie = 0;
00915 return rightpie;
00916 }
00917
00918
00919
00920
00921
00922
00923
00924
00925
00926
00927
00928
00929
00930
00931
00932
00933
00934
00935
00936
00937
00938
00939
00940
00941
00942
00943
00944
00945
00946
00947
00948
00949
00950
00951
00956 QPointF PieDiagram::pointOnCircle( const QRectF& rect, qreal angle )
00957 {
00958 qreal angleRad = DEGTORAD( angle );
00959 qreal cosAngle = cos( angleRad );
00960 qreal sinAngle = -sin( angleRad );
00961 qreal posX = cosAngle * rect.width() / 2.0;
00962 qreal posY = sinAngle * rect.height() / 2.0;
00963 return QPointF( posX + rect.center().x(),
00964 posY + rect.center().y() );
00965
00966 }
00967
00968
00969 double PieDiagram::valueTotals() const
00970 {
00971 const int colCount = columnCount();
00972 double total = 0.0;
00973 for ( int j = 0; j < colCount; ++j ) {
00974 total += qAbs(model()->data( model()->index( 0, j, rootIndex() ) ).toDouble());
00975
00976 }
00977 return total;
00978 }
00979
00980
00981 double PieDiagram::numberOfValuesPerDataset() const
00982 {
00983 return model() ? model()->columnCount( rootIndex() ) : 0.0;
00984 }
00985
00986
00987 double PieDiagram::numberOfGridRings() const
00988 {
00989 return 1;
00990 }