00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include <QDebug>
00024 #include <QPainter>
00025 #include <QStack>
00026
00027 #include "KDChartPieDiagram.h"
00028 #include "KDChartPieDiagram_p.h"
00029
00030 #include "KDChartAttributesModel.h"
00031 #include "KDChartPaintContext.h"
00032 #include "KDChartPieAttributes.h"
00033 #include "KDChartThreeDPieAttributes.h"
00034 #include "KDChartPainterSaver_p.h"
00035 #include "KDChartDataValueAttributes.h"
00036 #include "KDChartNullPaintDevice.h"
00037
00038 #include <KDABLibFakes>
00039
00040
00041 using namespace KDChart;
00042
00043 PieDiagram::Private::Private()
00044 {
00045 }
00046
00047 PieDiagram::Private::~Private() {}
00048
00049 #define d d_func()
00050
00051 PieDiagram::PieDiagram( QWidget* parent, PolarCoordinatePlane* plane ) :
00052 AbstractPieDiagram( new Private(), parent, plane )
00053 {
00054 init();
00055 }
00056
00057 PieDiagram::~PieDiagram()
00058 {
00059 }
00060
00061 void PieDiagram::init()
00062 {
00063 }
00064
00068 PieDiagram * PieDiagram::clone() const
00069 {
00070 return new PieDiagram( new Private( *d ) );
00071 }
00072
00073 const QPair<QPointF, QPointF> PieDiagram::calculateDataBoundaries () const
00074 {
00075 if ( !checkInvariants( true ) ) return QPair<QPointF, QPointF>( QPointF( 0, 0 ), QPointF( 0, 0 ) );
00076
00077 const PieAttributes attrs( pieAttributes( model()->index( 0, 0, rootIndex() ) ) );
00078
00079 QPointF bottomLeft ( QPointF( 0, 0 ) );
00080 QPointF topRight;
00081
00082
00083 if ( attrs.explode() ) {
00084 const int colCount = columnCount();
00085 qreal maxExplode = 0.0;
00086 for( int j = 0; j < colCount; ++j ){
00087 const PieAttributes columnAttrs( pieAttributes( model()->index( 0, j, rootIndex() ) ) );
00088 maxExplode = qMax( maxExplode, columnAttrs.explodeFactor() );
00089 }
00090 topRight = QPointF( 1.0+maxExplode, 1.0+maxExplode );
00091 }else{
00092 topRight = QPointF( 1.0, 1.0 );
00093 }
00094 return QPair<QPointF, QPointF> ( bottomLeft, topRight );
00095 }
00096
00097
00098 void PieDiagram::paintEvent( QPaintEvent* )
00099 {
00100 QPainter painter ( viewport() );
00101 PaintContext ctx;
00102 ctx.setPainter ( &painter );
00103 ctx.setRectangle( QRectF ( 0, 0, width(), height() ) );
00104 paint ( &ctx );
00105 }
00106
00107 void PieDiagram::resizeEvent ( QResizeEvent*)
00108 {
00109 }
00110
00111 void PieDiagram::resize ( const QSizeF& )
00112 {
00113 }
00114
00115 static QRectF buildReferenceRect( const PolarCoordinatePlane* plane )
00116 {
00117 QRectF contentsRect;
00118
00119 QPointF referencePointAtTop = plane->translate( QPointF( 1, 0 ) );
00120 QPointF temp = plane->translate( QPointF( 0, 0 ) ) - referencePointAtTop;
00121 const double offset = temp.y();
00122 referencePointAtTop.setX( referencePointAtTop.x() - offset );
00123 contentsRect.setTopLeft( referencePointAtTop );
00124 contentsRect.setBottomRight( referencePointAtTop + QPointF( 2*offset, 2*offset) );
00125
00126 return contentsRect;
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
00170
00171 void PieDiagram::paint(PaintContext* ctx)
00172 {
00173
00174
00175
00176
00177
00178 QPainter* actualPainter = ctx->painter();
00179 QRectF textBoundingRect;
00180
00181
00182 KDChart::NullPaintDevice nullPd(ctx->rectangle().size().toSize());
00183 QPainter nullPainter(&nullPd);
00184 ctx->setPainter(&nullPainter);
00185 paintInternal(ctx, textBoundingRect);
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201 ctx->setPainter(actualPainter);
00202 paintInternal(ctx, textBoundingRect);
00203 }
00204
00205 void PieDiagram::paintInternal(PaintContext* ctx, QRectF& textBoundingRect)
00206 {
00207
00208
00209 if ( !checkInvariants(true) )
00210 return;
00211
00212 d->reverseMapper.clear();
00213
00214 const PieAttributes attrs( pieAttributes() );
00215 const ThreeDPieAttributes threeDAttrs( threeDPieAttributes( model()->index( 0, 0, rootIndex() ) ) );
00216
00217 const int colCount = columnCount();
00218
00219 QRectF contentsRect( buildReferenceRect( polarCoordinatePlane() ) );
00220 contentsRect = ctx->rectangle();
00221
00222
00223 if( contentsRect.isEmpty() )
00224 return;
00225
00226 DataValueTextInfoList list;
00227 const qreal sum = valueTotals();
00228
00229 if( sum == 0.0 )
00230 return;
00231
00232 d->startAngles.resize( colCount );
00233 d->angleLens.resize( colCount );
00234
00235
00236 d->size = qMin( contentsRect.width(), contentsRect.height() );
00237
00238
00239
00240 qreal maxExplode = 0.0;
00241 for( int j = 0; j < colCount; ++j ){
00242 const PieAttributes columnAttrs( pieAttributes( model()->index( 0, j, rootIndex() ) ) );
00243 maxExplode = qMax( maxExplode, columnAttrs.explodeFactor() );
00244 }
00245 d->size /= ( 1.0 + 1.0 * maxExplode );
00246
00247 if(!textBoundingRect.isEmpty())
00248 {
00249
00250
00251 double maxDistance = 0, dist = 0;
00252
00253 QPointF center = ctx->rectangle().center();
00254
00255 dist = qAbs(textBoundingRect.right() - center.x());
00256 if(dist > maxDistance)
00257 maxDistance = dist;
00258
00259 dist = qAbs(textBoundingRect.left() - center.x());
00260 if(dist > maxDistance)
00261 maxDistance = dist;
00262
00263 dist = qAbs(textBoundingRect.top() - center.y());
00264 if(dist > maxDistance)
00265 maxDistance = dist;
00266
00267 dist = qAbs(textBoundingRect.bottom() - center.y());
00268 if(dist > maxDistance)
00269 maxDistance = dist;
00270
00271 double size = d->size;
00272 double diff = (2*maxDistance - d->size);
00273 if(diff > 0)
00274 d->size *= 1.0-(diff/size);
00275 }
00276
00277 if(d->size < 0)
00278 d->size = 0;
00279
00280 qreal sizeFor3DEffect = 0.0;
00281 if ( ! threeDAttrs.isEnabled() ) {
00282
00283 qreal x = ( contentsRect.width() == d->size ) ? 0.0 : ( ( contentsRect.width() - d->size ) / 2.0 );
00284 qreal y = ( contentsRect.height() == d->size ) ? 0.0 : ( ( contentsRect.height() - d->size ) / 2.0 );
00285 d->position = QRectF( x, y, d->size, d->size );
00286 d->position.translate( contentsRect.left(), contentsRect.top() );
00287 } else {
00288
00289 qreal x = ( contentsRect.width() == d->size ) ? 0.0 : ( ( contentsRect.width() - d->size ) / 2.0 );
00290 qreal height = d->size;
00291
00292
00293 if ( threeDAttrs.depth() >= 0.0 ) {
00294
00295 sizeFor3DEffect = threeDAttrs.depth();
00296 height = d->size - sizeFor3DEffect;
00297 } else {
00298
00299 sizeFor3DEffect = - threeDAttrs.depth() / 100.0 * height;
00300 height = d->size - sizeFor3DEffect;
00301 }
00302 qreal y = ( contentsRect.height() == height ) ? 0.0 : ( ( contentsRect.height() - height - sizeFor3DEffect ) / 2.0 );
00303
00304 d->position = QRectF( contentsRect.left() + x, contentsRect.top() + y,
00305 d->size, height );
00306
00307 }
00308
00309 const PolarCoordinatePlane * plane = polarCoordinatePlane();
00310 const qreal sectorsPerValue = 360.0 / sum;
00311 qreal currentValue = plane ? plane->startPosition() : 0.0;
00312
00313 bool atLeastOneValue = false;
00314 QVariant vValY;
00315 for ( int iColumn = 0; iColumn < colCount; ++iColumn ) {
00316
00317 bool bOK;
00318 const double cellValue = qAbs( model()->data( model()->index( 0, iColumn, rootIndex() ) )
00319 .toDouble( &bOK ) );
00320
00321 if( bOK ){
00322 d->startAngles[ iColumn ] = currentValue;
00323 d->angleLens[ iColumn ] = cellValue * sectorsPerValue;
00324 atLeastOneValue = true;
00325 } else {
00326 d->angleLens[ iColumn ] = 0.0;
00327 if ( iColumn > 0.0 )
00328 d->startAngles[ iColumn ] = d->startAngles[ iColumn - 1 ];
00329 else
00330 d->startAngles[ iColumn ] = currentValue;
00331 }
00332
00333
00334
00335
00336 currentValue = d->startAngles[ iColumn ] + d->angleLens[ iColumn ];
00337 }
00338
00339
00340
00341 if( ! atLeastOneValue )
00342 return;
00343
00344
00345
00346
00347 int backmostpie = findPieAt( 90, colCount );
00348
00349 int frontmostpie = findPieAt( 270, colCount );
00350
00351 int rightmostpie = findPieAt( 0, colCount );
00352 int leftmostpie = findPieAt( 180, colCount );
00353
00354
00355 int currentLeftPie = backmostpie;
00356 int currentRightPie = backmostpie;
00357
00358 d->clearListOfAlreadyDrawnDataValueTexts();
00359
00360 drawOnePie( ctx->painter(), &list, 0, backmostpie, granularity(), sizeFor3DEffect );
00361
00362 if( backmostpie == frontmostpie )
00363 {
00364 if( backmostpie == leftmostpie )
00365 currentLeftPie = findLeftPie( currentLeftPie, colCount );
00366 if( backmostpie == rightmostpie )
00367 currentRightPie = findRightPie( currentRightPie, colCount );
00368 }
00369 while( currentLeftPie != frontmostpie )
00370 {
00371 if( currentLeftPie != backmostpie )
00372 drawOnePie( ctx->painter(), &list, 0, currentLeftPie, granularity(), sizeFor3DEffect );
00373 currentLeftPie = findLeftPie( currentLeftPie, colCount );
00374 }
00375 while( currentRightPie != frontmostpie )
00376 {
00377 if( currentRightPie != backmostpie )
00378 drawOnePie( ctx->painter(), &list, 0, currentRightPie, granularity(), sizeFor3DEffect );
00379 currentRightPie = findRightPie( currentRightPie, colCount );
00380 }
00381
00382
00383 if( backmostpie != frontmostpie || ! threeDPieAttributes().isEnabled() )
00384 {
00385 drawOnePie( ctx->painter(), &list, 0, frontmostpie, granularity(), sizeFor3DEffect );
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405 }
00406
00407 d->paintDataValueTextsAndMarkers( this, ctx, list, false, false, &textBoundingRect );
00408 }
00409
00410 #if defined ( Q_WS_WIN)
00411 #define trunc(x) ((int)(x))
00412 #endif
00413
00414 QRectF PieDiagram::piePosition( uint dataset, uint pie ) const
00415 {
00416 Q_UNUSED( dataset );
00417 qreal angleLen = d->angleLens[ pie ];
00418 qreal startAngle = d->startAngles[ pie ];
00419 QModelIndex index( model()->index( 0, pie, rootIndex() ) );
00420 const PieAttributes attrs( pieAttributes( index ) );
00421 const ThreeDPieAttributes threeDAttrs( threeDPieAttributes( index ) );
00422
00423 QRectF drawPosition( d->position );
00424
00425 if ( attrs.explode() ) {
00426 qreal explodeAngle = ( startAngle + angleLen / 2.0 );
00427 qreal explodeAngleRad = DEGTORAD( explodeAngle );
00428 qreal cosAngle = cos( explodeAngleRad );
00429 qreal sinAngle = -sin( explodeAngleRad );
00430 qreal explodeX = attrs.explodeFactor() * d->size / 2.0 * cosAngle;
00431 qreal explodeY = attrs.explodeFactor() * d->size / 2.0 * sinAngle;
00432 drawPosition.translate( explodeX, explodeY );
00433 }
00434 return drawPosition;
00435 }
00436
00445 void PieDiagram::drawOnePie( QPainter* painter,
00446 DataValueTextInfoList* list,
00447 uint dataset, uint pie,
00448 qreal granularity,
00449 qreal threeDPieHeight )
00450 {
00451 Q_UNUSED( threeDPieHeight );
00452
00453 const qreal angleLen = d->angleLens[ pie ];
00454 if ( angleLen ) {
00455 const QModelIndex index( model()->index( 0, pie, rootIndex() ) );
00456 const PieAttributes attrs( pieAttributes( index ) );
00457 const ThreeDPieAttributes threeDAttrs( threeDPieAttributes( index ) );
00458
00459 const QRectF drawPosition = piePosition( dataset, pie );
00460
00461 draw3DEffect( painter,
00462 drawPosition, dataset, pie,
00463 granularity,
00464 threeDAttrs,
00465 attrs.explode() );
00466
00467 drawPieSurface( painter, list, dataset, pie, granularity );
00468 }
00469 }
00470
00478 void PieDiagram::drawPieSurface( QPainter* painter,
00479 DataValueTextInfoList* list,
00480 uint dataset, uint pie,
00481 qreal granularity )
00482 {
00483
00484 qreal angleLen = d->angleLens[ pie ];
00485 if ( angleLen ) {
00486 qreal startAngle = d->startAngles[ pie ];
00487
00488 QModelIndex index( model()->index( 0, pie, rootIndex() ) );
00489 const PieAttributes attrs( pieAttributes( index ) );
00490 const ThreeDPieAttributes threeDAttrs( threeDPieAttributes( index ) );
00491
00492 QRectF drawPosition = piePosition( dataset, pie );
00493
00494 painter->setRenderHint ( QPainter::Antialiasing );
00495 painter->setBrush( brush( index ) );
00496 painter->setPen( pen( index ) );
00497
00498
00499
00500
00501 if ( angleLen == 360 ) {
00502
00503 painter->drawEllipse( drawPosition );
00504
00505
00506 QPolygonF poly( drawPosition );
00507 d->reverseMapper.addPolygon( index.row(), index.column(), poly );
00508 } else {
00509
00510
00511 const int arcPoints = static_cast<int>(trunc( angleLen / granularity ));
00512 QPolygonF poly( arcPoints+2 );
00513 qreal degree=0.0;
00514 int iPoint = 0;
00515 bool perfectMatch = false;
00516
00517 while ( degree <= angleLen ){
00518 poly[ iPoint ] = pointOnCircle( drawPosition, startAngle + degree );
00519
00520 perfectMatch = (degree == angleLen);
00521 degree += granularity;
00522 ++iPoint;
00523 }
00524
00525 if( ! perfectMatch ){
00526 poly[ iPoint ] = pointOnCircle( drawPosition, startAngle + angleLen );
00527
00528
00529 poly.append( drawPosition.center() );
00530 }else{
00531 poly[ iPoint ] = drawPosition.center();
00532 }
00533
00534
00535 d->reverseMapper.addPolygon( index.row(), index.column(), poly );
00536
00537 painter->drawPolygon( poly );
00538 }
00539
00540
00541
00542
00543 const qreal sum = valueTotals();
00544 const QPointF south = drawPosition.center();
00545 const QPointF southEast = south;
00546 const QPointF southWest = south;
00547 const QPointF north = pointOnCircle( drawPosition, startAngle + angleLen/2.0 );
00548
00549 const QPointF northEast = pointOnCircle( drawPosition, startAngle );
00550 const QPointF northWest = pointOnCircle( drawPosition, startAngle + angleLen );
00551 QPointF center = (south + north) / 2.0;
00552 const QPointF east = (south + northEast) / 2.0;
00553 const QPointF west = (south + northWest) / 2.0;
00554
00555 CartesianDiagramDataCompressor::DataValueAttributesList allAttrs( d->aggregatedAttrs( this, index, 0 ) );
00556 const QFontMetrics * fm = (d->cachedFontMetrics( allAttrs.value(index).textAttributes().calculatedFont(d->plane,KDChartEnums::MeasureOrientationMinimum ), this ));
00557 if(!list->isEmpty())
00558 {
00559 QRect textRect = fm->boundingRect(QString::number(list->last().value));
00560 textRect.translated(center.toPoint());
00561 QPoint textRectCenter = textRect.center();
00562 qreal newX = center.x() - textRectCenter.x();
00563 qreal newY = center.y() - textRectCenter.y();
00564 center.setX(newX);
00565 center.setY(newY);
00566 }
00567
00568 PositionPoints points( center, northWest, north, northEast, east, southEast, south, southWest, west);
00569 qreal topAngle = startAngle - 90;
00570 if( topAngle < 0.0 )
00571 topAngle += 360;
00572 points.setDegrees(KDChartEnums::PositionEast, topAngle);
00573 points.setDegrees(KDChartEnums::PositionNorthEast, topAngle);
00574 points.setDegrees(KDChartEnums::PositionWest, topAngle + angleLen);
00575 points.setDegrees(KDChartEnums::PositionNorthWest, topAngle + angleLen);
00576 points.setDegrees(KDChartEnums::PositionCenter, topAngle + angleLen/2.0);
00577 points.setDegrees(KDChartEnums::PositionNorth, topAngle + angleLen/2.0);
00578
00579
00580
00581 d->appendDataValueTextInfoToList(
00582 this, *list, index, 0,
00583 points, Position::Center, Position::Center,
00584 angleLen*sum / 360 );
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597 }
00598 }
00599
00600
00610 void PieDiagram::draw3DEffect( QPainter* painter,
00611 const QRectF& drawPosition,
00612 uint dataset, uint pie,
00613 qreal granularity,
00614 const ThreeDPieAttributes& threeDAttrs,
00615 bool )
00616 {
00617 Q_UNUSED( dataset );
00618
00619 if( ! threeDAttrs.isEnabled() )
00620 return;
00621
00622
00623
00624
00625
00626
00627
00628
00629
00630 if( threeDAttrs.useShadowColors() ){
00631 const QPen pen = this->pen( model()->index( 0, pie, rootIndex() ) );
00632 painter->setBrush( QBrush( pen.color() ) );
00633 }
00634
00635
00636
00637 qreal startAngle = d->startAngles[ pie ];
00638 qreal endAngle = startAngle + d->angleLens[ pie ];
00639
00640 while ( startAngle >= 360 )
00641 startAngle -= 360;
00642 while ( endAngle >= 360 )
00643 endAngle -= 360;
00644 Q_ASSERT( startAngle >= 0 && startAngle <= 360 );
00645 Q_ASSERT( endAngle >= 0 && endAngle <= 360 );
00646
00647
00648
00649 if ( startAngle == endAngle ||
00650 startAngle == endAngle - 360 ) {
00651 drawArcEffectSegment( painter, drawPosition,
00652 threeDAttrs.depth(),
00653 180, 360, granularity );
00654 } else if ( startAngle <= 90 ) {
00655 if ( endAngle <= 90 ) {
00656 if ( startAngle <= endAngle ) {
00658 drawStraightEffectSegment( painter, drawPosition,
00659 threeDAttrs.depth(), startAngle );
00660 drawUpperBrinkEffect( painter, drawPosition, endAngle );
00661 } else {
00663 drawStraightEffectSegment( painter, drawPosition,
00664 threeDAttrs.depth(), startAngle );
00665 drawUpperBrinkEffect( painter, drawPosition, endAngle );
00666 drawArcEffectSegment( painter, drawPosition,
00667 threeDAttrs.depth(),
00668 180, 360, granularity );
00669 }
00670 } else if ( endAngle <= 180 ) {
00673 drawStraightEffectSegment( painter, drawPosition,
00674 threeDAttrs.depth(), startAngle );
00675 drawStraightEffectSegment( painter, drawPosition,
00676 threeDAttrs.depth(), endAngle );
00677 } else if ( endAngle <= 270 ) {
00679 drawStraightEffectSegment( painter, drawPosition,
00680 threeDAttrs.depth(), startAngle );
00681 drawStraightEffectSegment( painter, drawPosition,
00682 threeDAttrs.depth(), endAngle );
00683 drawArcEffectSegment( painter, drawPosition,
00684 threeDAttrs.depth(),
00685 180, endAngle, granularity );
00686 } else {
00689 drawStraightEffectSegment( painter, drawPosition,
00690 threeDAttrs.depth(), startAngle );
00691 drawUpperBrinkEffect( painter, drawPosition, endAngle );
00692 drawArcEffectSegment( painter, drawPosition,
00693 threeDAttrs.depth(),
00694 180, endAngle, granularity );
00695 }
00696 } else if ( startAngle <= 180 ) {
00697 if ( endAngle <= 90 ) {
00698 drawArcEffectSegment( painter, drawPosition,
00699 threeDAttrs.depth(),
00700 180, 360, granularity );
00701 drawUpperBrinkEffect( painter, drawPosition, startAngle );
00702 drawUpperBrinkEffect( painter, drawPosition, endAngle );
00703 } else if ( endAngle <= 180 ) {
00704 if ( startAngle <= endAngle ) {
00707 drawStraightEffectSegment( painter, drawPosition,
00708 threeDAttrs.depth(), endAngle );
00709 drawUpperBrinkEffect( painter, drawPosition, startAngle );
00710 } else {
00713 drawStraightEffectSegment( painter, drawPosition,
00714 threeDAttrs.depth(), endAngle );
00715 drawUpperBrinkEffect( painter, drawPosition, startAngle );
00716 drawArcEffectSegment( painter, drawPosition,
00717 threeDAttrs.depth(),
00718 180, 360, granularity );
00719 }
00720 } else if ( endAngle <= 270 ) {
00721 drawStraightEffectSegment( painter, drawPosition,
00722 threeDAttrs.depth(), endAngle );
00723 drawUpperBrinkEffect( painter, drawPosition, startAngle );
00724 drawArcEffectSegment( painter, drawPosition,
00725 threeDAttrs.depth(),
00726 180, endAngle, granularity );
00727 } else {
00728 drawArcEffectSegment( painter, drawPosition,
00729 threeDAttrs.depth(),
00730 180, endAngle, granularity );
00731 drawUpperBrinkEffect( painter, drawPosition, startAngle );
00732 drawUpperBrinkEffect( painter, drawPosition, endAngle );
00733 }
00734 } else if ( startAngle <= 270 ) {
00735 if ( endAngle <= 90 ) {
00736 drawArcEffectSegment( painter, drawPosition,
00737 threeDAttrs.depth(),
00738 startAngle, 360, granularity );
00739 drawUpperBrinkEffect( painter, drawPosition, startAngle );
00740 drawUpperBrinkEffect( painter, drawPosition, endAngle );
00741 } else if ( endAngle <= 180 ) {
00742 drawStraightEffectSegment( painter, drawPosition,
00743 threeDAttrs.depth(), endAngle );
00744 drawUpperBrinkEffect( painter, drawPosition, startAngle );
00745 drawArcEffectSegment( painter, drawPosition,
00746 threeDAttrs.depth(),
00747 startAngle, 360, granularity );
00748 } else if ( endAngle <= 270 ) {
00749 if ( startAngle <= endAngle ) {
00752 drawStraightEffectSegment( painter, drawPosition,
00753 threeDAttrs.depth(), endAngle );
00754 drawUpperBrinkEffect( painter, drawPosition, startAngle );
00755 drawArcEffectSegment( painter, drawPosition,
00756 threeDAttrs.depth(),
00757 startAngle, endAngle, granularity );
00758 } else {
00761 drawStraightEffectSegment( painter, drawPosition,
00762 threeDAttrs.depth(), endAngle );
00763 drawUpperBrinkEffect( painter, drawPosition, startAngle );
00764 drawArcEffectSegment( painter, drawPosition,
00765 threeDAttrs.depth(),
00766 180, endAngle, granularity );
00767 drawArcEffectSegment( painter, drawPosition,
00768 threeDAttrs.depth(),
00769 startAngle, 360, granularity );
00770 }
00771 } else {
00772 drawArcEffectSegment( painter, drawPosition,
00773 threeDAttrs.depth(),
00774 startAngle, endAngle, granularity );
00775 drawUpperBrinkEffect( painter, drawPosition, startAngle );
00776 drawUpperBrinkEffect( painter, drawPosition, endAngle );
00777 }
00778 } else {
00779 if ( endAngle <= 90 ) {
00780 drawStraightEffectSegment( painter, drawPosition,
00781 threeDAttrs.depth(), startAngle );
00782 drawUpperBrinkEffect( painter, drawPosition, endAngle );
00783 drawArcEffectSegment( painter, drawPosition,
00784 threeDAttrs.depth(),
00785 startAngle, 360, granularity );
00786 } else if ( endAngle <= 180 ) {
00787 drawStraightEffectSegment( painter, drawPosition,
00788 threeDAttrs.depth(), startAngle );
00789 drawStraightEffectSegment( painter, drawPosition,
00790 threeDAttrs.depth(), endAngle );
00791 drawArcEffectSegment( painter, drawPosition,
00792 threeDAttrs.depth(),
00793 startAngle, 360, granularity );
00794 } else if ( endAngle <= 270 ) {
00795 drawStraightEffectSegment( painter, drawPosition,
00796 threeDAttrs.depth(), startAngle );
00797 drawStraightEffectSegment( painter, drawPosition,
00798 threeDAttrs.depth(), endAngle );
00799 drawArcEffectSegment( painter, drawPosition,
00800 threeDAttrs.depth(),
00801 180, endAngle, granularity );
00802 drawArcEffectSegment( painter, drawPosition,
00803 threeDAttrs.depth(),
00804 startAngle, 360, granularity );
00805 } else {
00806 if ( startAngle <= endAngle ) {
00809 drawStraightEffectSegment( painter, drawPosition,
00810 threeDAttrs.depth(), startAngle );
00811 drawUpperBrinkEffect( painter, drawPosition, endAngle );
00812 drawArcEffectSegment( painter, drawPosition,
00813 threeDAttrs.depth(),
00814 startAngle, endAngle, granularity );
00815 } else {
00818 drawStraightEffectSegment( painter, drawPosition,
00819 threeDAttrs.depth(), startAngle );
00820 drawUpperBrinkEffect( painter, drawPosition, endAngle );
00821 drawArcEffectSegment( painter, drawPosition,
00822 threeDAttrs.depth(),
00823 startAngle, 360, granularity );
00824 drawArcEffectSegment( painter, drawPosition,
00825 threeDAttrs.depth(),
00826 180, endAngle, granularity );
00827 }
00828 }
00829 }
00830 drawArcUpperBrinkEffectSegment( painter, drawPosition, startAngle, endAngle, granularity );
00831 }
00832
00833
00842 void PieDiagram::drawStraightEffectSegment( QPainter* painter,
00843 const QRectF& rect,
00844 qreal threeDHeight,
00845 qreal angle )
00846 {
00847 QPolygonF poly( 4 );
00848 const QPointF center = rect.center();
00849 const QPointF circlePoint = pointOnCircle( rect, angle );
00850 poly[0] = center;
00851 poly[1] = circlePoint;
00852 poly[2] = QPointF( circlePoint.x(), circlePoint.y() + threeDHeight );
00853 poly[3] = QPointF( center.x(), center.y() + threeDHeight );
00854
00855 painter->drawPolygon( poly );
00856
00857
00858 }
00859
00867 void PieDiagram::drawUpperBrinkEffect( QPainter* painter,
00868 const QRectF& rect,
00869 qreal angle )
00870 {
00871 const QPointF center = rect.center();
00872 const QPointF circlePoint = pointOnCircle( rect, angle );
00873 painter->drawLine( center, circlePoint );
00874 }
00875
00885 void PieDiagram::drawArcEffectSegment( QPainter* painter,
00886 const QRectF& rect,
00887 qreal threeDHeight,
00888 qreal startAngle,
00889 qreal endAngle,
00890 qreal granularity )
00891 {
00892
00893 qreal startA = qMin( startAngle, endAngle );
00894 qreal endA = qMax( startAngle, endAngle );
00895
00896
00897 if( endA > 540 )
00898 drawArcEffectSegment( painter, rect, threeDHeight, 180, endA - 360, granularity );
00899 if( endA > 360 )
00900 endA = qMin( endA, qreal( 360.0 ) );
00901
00902 int numHalfPoints = static_cast<int>( trunc( ( endA - startA ) / granularity ) ) + 1;
00903
00904 QPolygonF poly( numHalfPoints );
00905
00906 qreal degree = endA;
00907 int iPoint = 0;
00908 bool perfectMatch = false;
00909 while ( degree >= startA ){
00910 poly[ numHalfPoints - iPoint - 1 ] = pointOnCircle( rect, degree );
00911
00912 perfectMatch = (degree == startA);
00913 degree -= granularity;
00914 ++iPoint;
00915 }
00916
00917 if( ! perfectMatch ){
00918 poly.prepend( pointOnCircle( rect, startA ) );
00919 ++numHalfPoints;
00920 }
00921
00922 poly.resize( numHalfPoints * 2 );
00923
00924
00925
00926 for ( int i = numHalfPoints - 1; i >= 0; --i ) {
00927 QPointF pointOnFirstArc( poly[ i ] );
00928 pointOnFirstArc.setY( pointOnFirstArc.y() + threeDHeight );
00929 poly[ numHalfPoints * 2 - i - 1 ] = pointOnFirstArc;
00930 }
00931
00932
00933 painter->drawPolygon( poly );
00934
00935
00936 }
00937
00946 void PieDiagram::drawArcUpperBrinkEffectSegment( QPainter* painter,
00947 const QRectF& rect,
00948 qreal startAngle,
00949 qreal endAngle,
00950 qreal granularity )
00951 {
00952 if ( endAngle < startAngle )
00953 endAngle += 360;
00954
00955 const qreal startA = qMin( startAngle, endAngle );
00956 const qreal endA = qMax( startAngle, endAngle );
00957
00958 int numHalfPoints = static_cast<int>( trunc( ( endA - startA ) / granularity ) ) + 1;
00959
00960 QPolygonF poly( numHalfPoints );
00961
00962 qreal degree = endA;
00963 int iPoint = 0;
00964 bool perfectMatch = false;
00965 while ( degree >= startA ){
00966 poly[ numHalfPoints - iPoint - 1 ] = pointOnCircle( rect, degree );
00967
00968 perfectMatch = (degree == startA);
00969 degree -= granularity;
00970 ++iPoint;
00971 }
00972
00973 if( ! perfectMatch ){
00974 poly.prepend( pointOnCircle( rect, startA ) );
00975 ++numHalfPoints;
00976 }
00977
00978 painter->drawPolyline( poly );
00979
00980
00981 }
00982
00990 uint PieDiagram::findPieAt( qreal angle, int colCount )
00991 {
00992 for ( int i = 0; i < colCount; ++i ) {
00993 qreal endseg = d->startAngles[ i ] + d->angleLens[ i ];
00994 if ( ( d->startAngles[ i ] <= angle ) &&
00995 ( endseg >= angle ) )
00996
00997 return i;
00998 }
00999
01000
01001
01002 if ( angle < 360 )
01003 return findPieAt( angle + 360, colCount );
01004
01005 return 0;
01006 }
01007
01008
01016 uint PieDiagram::findLeftPie( uint pie, int colCount )
01017 {
01018 if ( pie == 0 )
01019 if ( colCount > 1 )
01020 return colCount - 1;
01021 else
01022 return 0;
01023 else {
01024 return pie - 1;
01025 }
01026 }
01027
01028
01036 uint PieDiagram::findRightPie( uint pie, int colCount )
01037 {
01038 int rightpie = pie + 1;
01039 if ( rightpie == colCount )
01040 rightpie = 0;
01041 return rightpie;
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
01072
01073
01074
01075
01076
01077
01082 QPointF PieDiagram::pointOnCircle( const QRectF& rect, qreal angle )
01083 {
01084 qreal angleRad = DEGTORAD( angle );
01085 qreal cosAngle = cos( angleRad );
01086 qreal sinAngle = -sin( angleRad );
01087 qreal posX = cosAngle * rect.width() / 2.0;
01088 qreal posY = sinAngle * rect.height() / 2.0;
01089 return QPointF( posX + rect.center().x(),
01090 posY + rect.center().y() );
01091
01092 }
01093
01094
01095 double PieDiagram::valueTotals() const
01096 {
01097 const int colCount = columnCount();
01098 double total = 0.0;
01099 for ( int j = 0; j < colCount; ++j ) {
01100 total += qAbs(model()->data( model()->index( 0, j, rootIndex() ) ).toDouble());
01101
01102 }
01103 return total;
01104 }
01105
01106
01107 double PieDiagram::numberOfValuesPerDataset() const
01108 {
01109 return model() ? model()->columnCount( rootIndex() ) : 0.0;
01110 }
01111
01112
01113 double PieDiagram::numberOfGridRings() const
01114 {
01115 return 1;
01116 }