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
00066 PieDiagram * PieDiagram::clone() const
00067 {
00068 return new PieDiagram( new Private( *d ) );
00069 }
00070
00071 const QPair<QPointF, QPointF> PieDiagram::calculateDataBoundaries () const
00072 {
00073 if ( !checkInvariants( true ) ) return QPair<QPointF, QPointF>( QPointF( 0, 0 ), QPointF( 0, 0 ) );
00074
00075 const PieAttributes attrs( pieAttributes( model()->index( 0, 0, rootIndex() ) ) );
00076
00077 QPointF bottomLeft ( QPointF( 0, 0 ) );
00078 QPointF topRight;
00079
00080
00081 if ( attrs.explode() ) {
00082 const int colCount = columnCount();
00083 qreal maxExplode = 0.0;
00084 for( int j = 0; j < colCount; ++j ){
00085 const PieAttributes columnAttrs( pieAttributes( model()->index( 0, j, rootIndex() ) ) );
00086 maxExplode = qMax( maxExplode, columnAttrs.explodeFactor() );
00087 }
00088 topRight = QPointF( 1.0+maxExplode, 1.0+maxExplode );
00089 }else{
00090 topRight = QPointF( 1.0, 1.0 );
00091 }
00092 return QPair<QPointF, QPointF> ( bottomLeft, topRight );
00093 }
00094
00095
00096 void PieDiagram::paintEvent( QPaintEvent* )
00097 {
00098 QPainter painter ( viewport() );
00099 PaintContext ctx;
00100 ctx.setPainter ( &painter );
00101 ctx.setRectangle( QRectF ( 0, 0, width(), height() ) );
00102 paint ( &ctx );
00103 }
00104
00105 void PieDiagram::resizeEvent ( QResizeEvent*)
00106 {
00107 }
00108
00109 void PieDiagram::resize ( const QSizeF& )
00110 {
00111 }
00112
00113 static QRectF buildReferenceRect( const PolarCoordinatePlane* plane )
00114 {
00115 QRectF contentsRect;
00116
00117 QPointF referencePointAtTop = plane->translate( QPointF( 1, 0 ) );
00118 QPointF temp = plane->translate( QPointF( 0, 0 ) ) - referencePointAtTop;
00119 const double offset = temp.y();
00120 referencePointAtTop.setX( referencePointAtTop.x() - offset );
00121 contentsRect.setTopLeft( referencePointAtTop );
00122 contentsRect.setBottomRight( referencePointAtTop + QPointF( 2*offset, 2*offset) );
00123
00124 return contentsRect;
00125 }
00126
00127
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 void PieDiagram::paint( PaintContext* ctx )
00170 {
00171
00172
00173 if ( !checkInvariants(true) )
00174 return;
00175
00176 const PieAttributes attrs( pieAttributes() );
00177 const ThreeDPieAttributes threeDAttrs( threeDPieAttributes( model()->index( 0, 0, rootIndex() ) ) );
00178
00179 const int colCount = columnCount();
00180
00181 QRectF contentsRect( buildReferenceRect( polarCoordinatePlane() ) );
00182 contentsRect = ctx->rectangle();
00183
00184
00185 if( contentsRect.isEmpty() )
00186 return;
00187
00188 DataValueTextInfoList list;
00189 const qreal sum = valueTotals();
00190
00191 if( sum == 0.0 )
00192 return;
00193
00194 d->startAngles.resize( colCount );
00195 d->angleLens.resize( colCount );
00196
00197
00198 d->size = qMin( contentsRect.width(), contentsRect.height() );
00199
00200
00201
00202 qreal maxExplode = 0.0;
00203 for( int j = 0; j < colCount; ++j ){
00204 const PieAttributes columnAttrs( pieAttributes( model()->index( 0, j, rootIndex() ) ) );
00205 maxExplode = qMax( maxExplode, columnAttrs.explodeFactor() );
00206 }
00207 d->size /= ( 1.0 + 2.0 * maxExplode );
00208
00209
00210 qreal sizeFor3DEffect = 0.0;
00211 if ( ! threeDAttrs.isEnabled() ) {
00212
00213 qreal x = ( contentsRect.width() == d->size ) ? 0.0 : ( ( contentsRect.width() - d->size ) / 2.0 );
00214 qreal y = ( contentsRect.height() == d->size ) ? 0.0 : ( ( contentsRect.height() - d->size ) / 2.0 );
00215 d->position = QRectF( x, y, d->size, d->size );
00216 d->position.translate( contentsRect.left(), contentsRect.top() );
00217 } else {
00218
00219 qreal x = ( contentsRect.width() == d->size ) ? 0.0 : ( ( contentsRect.width() - d->size ) / 2.0 );
00220 qreal height = d->size;
00221
00222
00223 if ( threeDAttrs.depth() >= 0.0 ) {
00224
00225 sizeFor3DEffect = threeDAttrs.depth();
00226 height = d->size - sizeFor3DEffect;
00227 } else {
00228
00229 sizeFor3DEffect = - threeDAttrs.depth() / 100.0 * height;
00230 height = d->size - sizeFor3DEffect;
00231 }
00232 qreal y = ( contentsRect.height() == height ) ? 0.0 : ( ( contentsRect.height() - height - sizeFor3DEffect ) / 2.0 );
00233
00234 d->position = QRectF( contentsRect.left() + x, contentsRect.top() + y,
00235 d->size, height );
00236
00237 }
00238
00239 const PolarCoordinatePlane * plane = polarCoordinatePlane();
00240 const qreal sectorsPerValue = 360.0 / sum;
00241 qreal currentValue = plane ? plane->startPosition() : 0.0;
00242
00243 bool atLeastOneValue = false;
00244 QVariant vValY;
00245 for ( int iColumn = 0; iColumn < colCount; ++iColumn ) {
00246
00247 bool bOK;
00248 const double cellValue = qAbs( model()->data( model()->index( 0, iColumn, rootIndex() ) )
00249 .toDouble( &bOK ) );
00250
00251 if( bOK ){
00252 d->startAngles[ iColumn ] = currentValue;
00253 d->angleLens[ iColumn ] = cellValue * sectorsPerValue;
00254 atLeastOneValue = true;
00255 } else {
00256 d->angleLens[ iColumn ] = 0.0;
00257 if ( iColumn > 0.0 )
00258 d->startAngles[ iColumn ] = d->startAngles[ iColumn - 1 ];
00259 else
00260 d->startAngles[ iColumn ] = currentValue;
00261 }
00262
00263
00264
00265
00266 currentValue = d->startAngles[ iColumn ] + d->angleLens[ iColumn ];
00267 }
00268
00269
00270
00271 if( ! atLeastOneValue )
00272 return;
00273
00274
00275
00276
00277 int backmostpie = findPieAt( 90, colCount );
00278
00279 int frontmostpie = findPieAt( 270, colCount );
00280
00281 int rightmostpie = findPieAt( 0, colCount );
00282 int leftmostpie = findPieAt( 180, colCount );
00283
00284
00285 int currentLeftPie = backmostpie;
00286 int currentRightPie = backmostpie;
00287
00288 drawOnePie( ctx->painter(), 0, backmostpie, granularity(), sizeFor3DEffect );
00289
00290 if( backmostpie == frontmostpie )
00291 {
00292 if( backmostpie == leftmostpie )
00293 currentLeftPie = findLeftPie( currentLeftPie, colCount );
00294 if( backmostpie == rightmostpie )
00295 currentRightPie = findRightPie( currentRightPie, colCount );
00296 }
00297 while( currentLeftPie != frontmostpie )
00298 {
00299 if( currentLeftPie != backmostpie )
00300 drawOnePie( ctx->painter(), 0, currentLeftPie, granularity(), sizeFor3DEffect );
00301 currentLeftPie = findLeftPie( currentLeftPie, colCount );
00302 }
00303 while( currentRightPie != frontmostpie )
00304 {
00305 if( currentRightPie != backmostpie )
00306 drawOnePie( ctx->painter(), 0, currentRightPie, granularity(), sizeFor3DEffect );
00307 currentRightPie = findRightPie( currentRightPie, colCount );
00308 }
00309
00310
00311 if( backmostpie != frontmostpie || ! threeDPieAttributes().isEnabled() )
00312 {
00313 drawOnePie( ctx->painter(), 0, frontmostpie, granularity(), sizeFor3DEffect );
00314
00315 } else if( threeDPieAttributes().isEnabled() ) {
00316 drawPieSurface( ctx->painter(), 0, frontmostpie, granularity() );
00317 const QModelIndex index = model()->index( 0, frontmostpie, rootIndex() );
00318 QPen pen = this->pen( index );
00319 ctx->painter()->setRenderHint ( QPainter::Antialiasing );
00320 ctx->painter()->setBrush( brush( index ) );
00321 if ( threeDAttrs.isEnabled() )
00322 pen.setColor( QColor( 0, 0, 0 ) );
00323 ctx->painter()->setPen( pen );
00324
00325 qreal startAngle = d->startAngles[ frontmostpie ];
00326 if( startAngle > 360 )
00327 startAngle -= 360;
00328
00329 qreal endAngle = startAngle + d->angleLens[ frontmostpie ];
00330 startAngle = qMax( startAngle, 180.0 );
00331
00332 drawArcEffectSegment( ctx->painter(), piePosition( 0, frontmostpie),
00333 sizeFor3DEffect, startAngle, endAngle, granularity() );
00334 }
00335 }
00336
00337 #if defined ( Q_WS_WIN)
00338 #define trunc(x) ((int)(x))
00339 #endif
00340
00341 QRectF PieDiagram::piePosition( uint dataset, uint pie ) const
00342 {
00343 qreal angleLen = d->angleLens[ pie ];
00344 qreal startAngle = d->startAngles[ pie ];
00345 QModelIndex index( model()->index( 0, pie, rootIndex() ) );
00346 const PieAttributes attrs( pieAttributes( index ) );
00347 const ThreeDPieAttributes threeDAttrs( threeDPieAttributes( index ) );
00348
00349 QRectF drawPosition( d->position );
00350
00351 if ( attrs.explode() ) {
00352 qreal explodeAngle = ( startAngle + angleLen / 2.0 );
00353 qreal explodeAngleRad = DEGTORAD( explodeAngle );
00354 qreal cosAngle = cos( explodeAngleRad );
00355 qreal sinAngle = -sin( explodeAngleRad );
00356 qreal explodeX = attrs.explodeFactor() * d->size * cosAngle;
00357 qreal explodeY = attrs.explodeFactor() * d->size * sinAngle;
00358 drawPosition.translate( explodeX, explodeY );
00359 }else{
00360 drawPosition = d->position;
00361 }
00362 return drawPosition;
00363 }
00364
00373 void PieDiagram::drawOnePie( QPainter* painter,
00374 uint dataset, uint pie,
00375 qreal granularity,
00376 qreal threeDPieHeight )
00377 {
00378
00379 qreal angleLen = d->angleLens[ pie ];
00380 if ( angleLen ) {
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391 QModelIndex index( model()->index( 0, pie, rootIndex() ) );
00392 const PieAttributes attrs( pieAttributes( index ) );
00393 const ThreeDPieAttributes threeDAttrs( threeDPieAttributes( index ) );
00394
00395 QRectF drawPosition = piePosition( dataset, pie );
00396
00397 draw3DEffect( painter,
00398 drawPosition, dataset, pie,
00399 granularity,
00400 threeDAttrs,
00401 attrs.explode() );
00402
00403 drawPieSurface( painter, dataset, pie, granularity );
00404 }
00405 }
00406
00414 void PieDiagram::drawPieSurface( QPainter* painter,
00415 uint dataset, uint pie,
00416 qreal granularity )
00417 {
00418
00419 qreal angleLen = d->angleLens[ pie ];
00420 if ( angleLen ) {
00421 qreal startAngle = d->startAngles[ pie ];
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431 QModelIndex index( model()->index( 0, pie, rootIndex() ) );
00432 const PieAttributes attrs( pieAttributes( index ) );
00433 const ThreeDPieAttributes threeDAttrs( threeDPieAttributes( index ) );
00434
00435 QRectF drawPosition = piePosition( dataset, pie );
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450 QPen pen = this->pen( index );
00451 PainterSaver painterSaver( painter );
00452 painter->setRenderHint ( QPainter::Antialiasing );
00453 painter->setBrush( brush( index ) );
00454 if ( threeDAttrs.isEnabled() )
00455 pen.setColor( QColor( 0, 0, 0 ) );
00456 painter->setPen( pen );
00457
00458 if ( angleLen == 360 ) {
00459
00460 painter->drawEllipse( drawPosition );
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494 } else {
00495
00496
00497 const int arcPoints = static_cast<int>(trunc( angleLen / granularity ));
00498 QPolygonF poly( arcPoints+2 );
00499 qreal degree=0.0;
00500 int iPoint = 0;
00501 bool perfectMatch = false;
00502
00503 while ( degree <= angleLen ){
00504 poly[ iPoint ] = pointOnCircle( drawPosition, startAngle + degree );
00505
00506 perfectMatch = (degree == angleLen);
00507 degree += granularity;
00508 ++iPoint;
00509 }
00510 int last = poly.size();
00511
00512 if( ! perfectMatch ){
00513 poly[ iPoint ] = pointOnCircle( drawPosition, startAngle + angleLen );
00514
00515
00516
00517 poly.append( drawPosition.center() );
00518
00519 }else{
00520 poly[ iPoint ] = drawPosition.center();
00521
00522 }
00523
00524
00525
00526 const qreal sum = valueTotals();
00527 painter->drawPolygon( poly );
00528
00529 QLineF centerLine( drawPosition.center(),
00530 QPointF( (poly[ last - 2].x() + poly.first().x())/2,
00531 ( poly.first().y() + poly[last-2].y() )/2 ) );
00532 QPointF valuePos( ( centerLine.x1() + centerLine.x2() )/2,
00533 ( centerLine.y1() + centerLine.y2() )/2 ) ;
00534
00535 paintDataValueText( painter, index, valuePos, angleLen*sum / 360 );
00536
00537
00538
00539
00540
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592 }
00593
00594
00595 }
00596 }
00597
00598
00608 void PieDiagram::draw3DEffect( QPainter* painter,
00609 const QRectF& drawPosition,
00610 uint dataset, uint pie,
00611 qreal granularity,
00612 const ThreeDPieAttributes& threeDAttrs,
00613 bool )
00614 {
00615 if( ! threeDAttrs.isEnabled() )
00616 return;
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626 if( threeDAttrs.useShadowColors() ){
00627 const QPen pen = this->pen( model()->index( 0, pie, rootIndex() ) );
00628 painter->setBrush( QBrush( pen.color() ) );
00629 }
00630
00631
00632
00633 qreal startAngle = d->startAngles[ pie ];
00634 qreal endAngle = startAngle + d->angleLens[ pie ];
00635
00636 while ( startAngle >= 360 )
00637 startAngle -= 360;
00638 while ( endAngle >= 360 )
00639 endAngle -= 360;
00640 Q_ASSERT( startAngle >= 0 && startAngle <= 360 );
00641 Q_ASSERT( endAngle >= 0 && endAngle <= 360 );
00642
00643
00644
00645 if ( startAngle == endAngle ||
00646 startAngle == endAngle - 360 ) {
00647 drawArcEffectSegment( painter, drawPosition,
00648 threeDAttrs.depth(),
00649 180, 360, granularity );
00650 } else if ( startAngle <= 90 ) {
00651 if ( endAngle <= 90 ) {
00652 if ( startAngle <= endAngle ) {
00654 drawStraightEffectSegment( painter, drawPosition,
00655 threeDAttrs.depth(), startAngle );
00656 drawUpperBrinkEffect( painter, drawPosition, endAngle );
00657 } else {
00659 drawStraightEffectSegment( painter, drawPosition,
00660 threeDAttrs.depth(), startAngle );
00661 drawUpperBrinkEffect( painter, drawPosition, endAngle );
00662 drawArcEffectSegment( painter, drawPosition,
00663 threeDAttrs.depth(),
00664 180, 360, granularity );
00665 }
00666 } else if ( endAngle <= 180 ) {
00669 drawStraightEffectSegment( painter, drawPosition,
00670 threeDAttrs.depth(), startAngle );
00671 drawStraightEffectSegment( painter, drawPosition,
00672 threeDAttrs.depth(), endAngle );
00673 } else if ( endAngle <= 270 ) {
00675 drawStraightEffectSegment( painter, drawPosition,
00676 threeDAttrs.depth(), startAngle );
00677 drawStraightEffectSegment( painter, drawPosition,
00678 threeDAttrs.depth(), endAngle );
00679 drawArcEffectSegment( painter, drawPosition,
00680 threeDAttrs.depth(),
00681 180, endAngle, granularity );
00682 } else {
00685 drawStraightEffectSegment( painter, drawPosition,
00686 threeDAttrs.depth(), startAngle );
00687 drawUpperBrinkEffect( painter, drawPosition, endAngle );
00688 drawArcEffectSegment( painter, drawPosition,
00689 threeDAttrs.depth(),
00690 180, endAngle, granularity );
00691 }
00692 } else if ( startAngle <= 180 ) {
00693 if ( endAngle <= 90 ) {
00694 drawArcEffectSegment( painter, drawPosition,
00695 threeDAttrs.depth(),
00696 180, 360, granularity );
00697 drawUpperBrinkEffect( painter, drawPosition, startAngle );
00698 drawUpperBrinkEffect( painter, drawPosition, endAngle );
00699 } else if ( endAngle <= 180 ) {
00700 if ( startAngle <= endAngle ) {
00703 drawStraightEffectSegment( painter, drawPosition,
00704 threeDAttrs.depth(), endAngle );
00705 drawUpperBrinkEffect( painter, drawPosition, startAngle );
00706 } else {
00709 drawStraightEffectSegment( painter, drawPosition,
00710 threeDAttrs.depth(), endAngle );
00711 drawUpperBrinkEffect( painter, drawPosition, startAngle );
00712 drawArcEffectSegment( painter, drawPosition,
00713 threeDAttrs.depth(),
00714 180, 360, granularity );
00715 }
00716 } else if ( endAngle <= 270 ) {
00717 drawStraightEffectSegment( painter, drawPosition,
00718 threeDAttrs.depth(), endAngle );
00719 drawUpperBrinkEffect( painter, drawPosition, startAngle );
00720 drawArcEffectSegment( painter, drawPosition,
00721 threeDAttrs.depth(),
00722 180, endAngle, granularity );
00723 } else {
00724 drawArcEffectSegment( painter, drawPosition,
00725 threeDAttrs.depth(),
00726 180, endAngle, granularity );
00727 drawUpperBrinkEffect( painter, drawPosition, startAngle );
00728 drawUpperBrinkEffect( painter, drawPosition, endAngle );
00729 }
00730 } else if ( startAngle <= 270 ) {
00731 if ( endAngle <= 90 ) {
00732 drawArcEffectSegment( painter, drawPosition,
00733 threeDAttrs.depth(),
00734 startAngle, 360, granularity );
00735 drawUpperBrinkEffect( painter, drawPosition, startAngle );
00736 drawUpperBrinkEffect( painter, drawPosition, endAngle );
00737 } else if ( endAngle <= 180 ) {
00738 drawStraightEffectSegment( painter, drawPosition,
00739 threeDAttrs.depth(), endAngle );
00740 drawUpperBrinkEffect( painter, drawPosition, startAngle );
00741 drawArcEffectSegment( painter, drawPosition,
00742 threeDAttrs.depth(),
00743 startAngle, 360, granularity );
00744 } else if ( endAngle <= 270 ) {
00745 if ( startAngle <= endAngle ) {
00748 drawStraightEffectSegment( painter, drawPosition,
00749 threeDAttrs.depth(), endAngle );
00750 drawUpperBrinkEffect( painter, drawPosition, startAngle );
00751 drawArcEffectSegment( painter, drawPosition,
00752 threeDAttrs.depth(),
00753 startAngle, endAngle, granularity );
00754 } else {
00757 drawStraightEffectSegment( painter, drawPosition,
00758 threeDAttrs.depth(), endAngle );
00759 drawUpperBrinkEffect( painter, drawPosition, startAngle );
00760 drawArcEffectSegment( painter, drawPosition,
00761 threeDAttrs.depth(),
00762 180, endAngle, granularity );
00763 drawArcEffectSegment( painter, drawPosition,
00764 threeDAttrs.depth(),
00765 startAngle, 360, granularity );
00766 }
00767 } else {
00768 drawArcEffectSegment( painter, drawPosition,
00769 threeDAttrs.depth(),
00770 startAngle, endAngle, granularity );
00771 drawUpperBrinkEffect( painter, drawPosition, startAngle );
00772 drawUpperBrinkEffect( painter, drawPosition, endAngle );
00773 }
00774 } else {
00775 if ( endAngle <= 90 ) {
00776 drawStraightEffectSegment( painter, drawPosition,
00777 threeDAttrs.depth(), startAngle );
00778 drawUpperBrinkEffect( painter, drawPosition, endAngle );
00779 drawArcEffectSegment( painter, drawPosition,
00780 threeDAttrs.depth(),
00781 startAngle, 360, granularity );
00782 } else if ( endAngle <= 180 ) {
00783 drawStraightEffectSegment( painter, drawPosition,
00784 threeDAttrs.depth(), startAngle );
00785 drawStraightEffectSegment( painter, drawPosition,
00786 threeDAttrs.depth(), endAngle );
00787 drawArcEffectSegment( painter, drawPosition,
00788 threeDAttrs.depth(),
00789 startAngle, 360, granularity );
00790 } else if ( endAngle <= 270 ) {
00791 drawStraightEffectSegment( painter, drawPosition,
00792 threeDAttrs.depth(), startAngle );
00793 drawStraightEffectSegment( painter, drawPosition,
00794 threeDAttrs.depth(), endAngle );
00795 drawArcEffectSegment( painter, drawPosition,
00796 threeDAttrs.depth(),
00797 180, endAngle, granularity );
00798 drawArcEffectSegment( painter, drawPosition,
00799 threeDAttrs.depth(),
00800 startAngle, 360, granularity );
00801 } else {
00802 if ( startAngle <= endAngle ) {
00805 drawStraightEffectSegment( painter, drawPosition,
00806 threeDAttrs.depth(), startAngle );
00807 drawUpperBrinkEffect( painter, drawPosition, endAngle );
00808 drawArcEffectSegment( painter, drawPosition,
00809 threeDAttrs.depth(),
00810 startAngle, endAngle, granularity );
00811 } else {
00814 drawStraightEffectSegment( painter, drawPosition,
00815 threeDAttrs.depth(), startAngle );
00816 drawUpperBrinkEffect( painter, drawPosition, endAngle );
00817 drawArcEffectSegment( painter, drawPosition,
00818 threeDAttrs.depth(),
00819 startAngle, 360, granularity );
00820 drawArcEffectSegment( painter, drawPosition,
00821 threeDAttrs.depth(),
00822 180, endAngle, granularity );
00823 }
00824 }
00825 }
00826 drawArcUpperBrinkEffectSegment( painter, drawPosition, startAngle, endAngle, granularity );
00827 }
00828
00829
00838 void PieDiagram::drawStraightEffectSegment( QPainter* painter,
00839 const QRectF& rect,
00840 qreal threeDHeight,
00841 qreal angle )
00842 {
00843 QPolygonF poly( 4 );
00844 const QPointF center = rect.center();
00845 const QPointF circlePoint = pointOnCircle( rect, angle );
00846 poly[0] = center;
00847 poly[1] = circlePoint;
00848 poly[2] = QPointF( circlePoint.x(), circlePoint.y() + threeDHeight );
00849 poly[3] = QPointF( center.x(), center.y() + threeDHeight );
00850 painter->drawPolygon( poly );
00851
00852
00853 }
00854
00862 void PieDiagram::drawUpperBrinkEffect( QPainter* painter,
00863 const QRectF& rect,
00864 qreal angle )
00865 {
00866 const QPointF center = rect.center();
00867 const QPointF circlePoint = pointOnCircle( rect, angle );
00868 painter->drawLine( center, circlePoint );
00869 }
00870
00880 void PieDiagram::drawArcEffectSegment( QPainter* painter,
00881 const QRectF& rect,
00882 qreal threeDHeight,
00883 qreal startAngle,
00884 qreal endAngle,
00885 qreal granularity )
00886 {
00887
00888 qreal startA = qMin( startAngle, endAngle );
00889 qreal endA = qMax( startAngle, endAngle );
00890
00891
00892 if( endA > 540 )
00893 drawArcEffectSegment( painter, rect, threeDHeight, 180, endA - 360, granularity );
00894 if( endA > 360 )
00895 endA = qMin( endA, 360.0 );
00896
00897 int numHalfPoints = static_cast<int>( trunc( ( endA - startA ) / granularity ) ) + 1;
00898
00899 QPolygonF poly( numHalfPoints );
00900
00901 qreal degree = endA;
00902 int iPoint = 0;
00903 bool perfectMatch = false;
00904 while ( degree >= startA ){
00905 poly[ numHalfPoints - iPoint - 1 ] = pointOnCircle( rect, degree );
00906
00907 perfectMatch = (degree == startA);
00908 degree -= granularity;
00909 ++iPoint;
00910 }
00911
00912 if( ! perfectMatch ){
00913 poly.prepend( pointOnCircle( rect, startA ) );
00914 ++numHalfPoints;
00915 }
00916
00917 poly.resize( numHalfPoints * 2 );
00918
00919
00920
00921 for ( int i = numHalfPoints - 1; i >= 0; --i ) {
00922 QPointF pointOnFirstArc( poly[ i ] );
00923 pointOnFirstArc.setY( pointOnFirstArc.y() + threeDHeight );
00924 poly[ numHalfPoints * 2 - i - 1 ] = pointOnFirstArc;
00925 }
00926
00927 painter->drawPolygon( poly );
00928
00929
00930 }
00931
00940 void PieDiagram::drawArcUpperBrinkEffectSegment( QPainter* painter,
00941 const QRectF& rect,
00942 qreal startAngle,
00943 qreal endAngle,
00944 qreal granularity )
00945 {
00946 if ( endAngle < startAngle )
00947 endAngle += 360;
00948
00949 const qreal startA = qMin( startAngle, endAngle );
00950 const qreal endA = qMax( startAngle, endAngle );
00951
00952 int numHalfPoints = static_cast<int>( trunc( ( endA - startA ) / granularity ) ) + 1;
00953
00954 QPolygonF poly( numHalfPoints );
00955
00956 qreal degree = endA;
00957 int iPoint = 0;
00958 bool perfectMatch = false;
00959 while ( degree >= startA ){
00960 poly[ numHalfPoints - iPoint - 1 ] = pointOnCircle( rect, degree );
00961
00962 perfectMatch = (degree == startA);
00963 degree -= granularity;
00964 ++iPoint;
00965 }
00966
00967 if( ! perfectMatch ){
00968 poly.prepend( pointOnCircle( rect, startA ) );
00969 ++numHalfPoints;
00970 }
00971
00972 painter->drawPolyline( poly );
00973
00974
00975 }
00976
00984 uint PieDiagram::findPieAt( qreal angle, int colCount )
00985 {
00986 for ( int i = 0; i < colCount; ++i ) {
00987 qreal endseg = d->startAngles[ i ] + d->angleLens[ i ];
00988 if ( ( d->startAngles[ i ] <= angle ) &&
00989 ( endseg >= angle ) )
00990
00991 return i;
00992 }
00993
00994
00995
00996 if ( angle < 360 )
00997 return findPieAt( angle + 360, colCount );
00998
00999 return 0;
01000 }
01001
01002
01010 uint PieDiagram::findLeftPie( uint pie, int colCount )
01011 {
01012 if ( pie == 0 )
01013 if ( colCount > 1 )
01014 return colCount - 1;
01015 else
01016 return 0;
01017 else {
01018 return pie - 1;
01019 }
01020 }
01021
01022
01030 uint PieDiagram::findRightPie( uint pie, int colCount )
01031 {
01032 int rightpie = pie + 1;
01033 if ( rightpie == colCount )
01034 rightpie = 0;
01035 return rightpie;
01036 }
01037
01038
01039
01040
01041
01042
01043
01044
01045
01046
01047
01048
01049
01050
01051
01052
01053
01054
01055
01056
01057
01058
01059
01060
01061
01062
01063
01064
01065
01066
01067
01068
01069
01070
01071
01076 QPointF PieDiagram::pointOnCircle( const QRectF& rect, qreal angle )
01077 {
01078 qreal angleRad = DEGTORAD( angle );
01079 qreal cosAngle = cos( angleRad );
01080 qreal sinAngle = -sin( angleRad );
01081 qreal posX = cosAngle * rect.width() / 2.0;
01082 qreal posY = sinAngle * rect.height() / 2.0;
01083 return QPointF( posX + rect.center().x(),
01084 posY + rect.center().y() );
01085
01086 }
01087
01088
01089 double PieDiagram::valueTotals() const
01090 {
01091 const int colCount = columnCount();
01092 double total = 0.0;
01093 for ( int j = 0; j < colCount; ++j ) {
01094 total += qAbs(model()->data( model()->index( 0, j, rootIndex() ) ).toDouble());
01095
01096 }
01097 return total;
01098 }
01099
01100
01101 double PieDiagram::numberOfValuesPerDataset() const
01102 {
01103 return model() ? model()->columnCount( rootIndex() ) : 0.0;
01104 }
01105
01106
01107 double PieDiagram::numberOfGridRings() const
01108 {
01109 return 1;
01110 }