30#include "KDChartPiePainter.h"
34#include <tqvaluestack.h>
35#include <tqmessagebox.h>
37#define DEGTORAD(d) (d)*M_PI/180
87 uint chart = paint2nd ? 1 : 0;
89 TQRect ourClipRect( _dataRect );
90 ourClipRect.addCoords( -1,-1,1,1 );
92 const TQWMatrix & world = painter->worldMatrix();
93 ourClipRect = world.mapRect( ourClipRect );
94 painter->setClipRect( ourClipRect );
98 if ( !params()->findDataset( KDChartParams::DataEntry
100 dataset, dataset ) ) {
104 if ( dataset == KDCHART_ALL_DATASETS )
113 if ( params()->numValues() != -1 )
118 _startAngles.resize( _numValues );
119 _angleLens.resize( _numValues );
122 _size = TQMIN( _dataRect.width(), _dataRect.height() );
125 if ( params()->explode() ) {
126 double doubleSize = ( double ) _size;
128 _size = ( int ) doubleSize;
131 int sizeFor3DEffect = 0;
134 int x = ( _dataRect.width() == _size ) ? 0 : ( ( _dataRect.width() - _size ) / 2 );
135 int y = ( _dataRect.height() == _size ) ? 0 : ( ( _dataRect.height() - _size ) / 2 );
136 _position = TQRect( x, y, _size, _size );
137 _position.moveBy( _dataRect.left(), _dataRect.top() );
140 int x = ( _dataRect.width() == _size ) ? 0 : ( ( _dataRect.width() - _size ) / 2 );
147 height = _size - sizeFor3DEffect;
150 sizeFor3DEffect = -( int ) ( ( ( double ) params()->threeDPieHeight() / 100.0 ) * ( double ) height );
151 height = _size - sizeFor3DEffect;
153 int y = ( _dataRect.height() == height ) ? 0 : ( ( _dataRect.height() - height - sizeFor3DEffect ) / 2 );
155 _position = TQRect( _dataRect.left() + x, _dataRect.top() + y,
160 double sum = data->rowAbsSum( dataset );
163 double sectorsPerValue = 5760.0 / sum;
165 int currentValue = params()-> pieStart() * 16;
166 bool atLeastOneValue = false;
168 for ( int value = 0; value < _numValues; value++ ) {
172 if( data-> cellCoord( dataset, value, vValY, 1 ) &&
173 TQVariant::Double == vValY.type() ){
174 _startAngles[ value ] = currentValue;
175 const double cellValue = fabs( vValY.toDouble() );
176 _angleLens[ value ] = ( int ) floor( cellValue * sectorsPerValue + 0.5 );
177 atLeastOneValue = true;
179 _angleLens[ value ] = 0;
181 _startAngles[ value ] = _startAngles[ value - 1 ];
183 _startAngles[ value ] = currentValue;
186 currentValue = _startAngles[ value ] + _angleLens[ value ];
191 if( !atLeastOneValue )
199 int frontmostpie = findPieAt( 270 * 16 );
202 TQValueStack < int > todostack;
203 if ( backmostpie != frontmostpie )
204 todostack.push( backmostpie );
208 if ( leftOfCurrent != frontmostpie ) {
209 todostack.push( leftOfCurrent );
212 if ( rightOfCurrent != frontmostpie ) {
213 todostack.push( rightOfCurrent );
222 TQValueList < int > donelist;
226 while ( !todostack.isEmpty() &&
227 !( ( todostack.count() == 1 ) &&
228 ( ( todostack.top() == frontmostpie ) ) ) ) {
236 int currentpie = todostack.pop();
238 if ( donelist.find( currentpie ) != donelist.end() )
246 if ( currentpie == frontmostpie ) {
247 Q_ASSERT( !todostack.isEmpty() );
249 int secondpie = todostack.pop();
250 if ( currentpie == secondpie )
254 if ( todostack.isEmpty() )
257 secondpie = todostack.pop();
258 todostack.push( currentpie );
259 todostack.push( secondpie );
264 drawOnePie( painter, data, dataset, currentpie, chart,
269 donelist.append( currentpie );
275 if ( donelist.find( leftOfCurrent ) == donelist.end() )
276 todostack.push( leftOfCurrent );
278 if ( donelist.find( rightOfCurrent ) == donelist.end() )
279 todostack.push( rightOfCurrent );
283 drawOnePie( painter, data, dataset, frontmostpie, chart,
301 uint dataset, uint pie, uint chart,
302 uint threeDPieHeight,
306 int angleLen = _angleLens[ ( int ) pie ];
308 int startAngle = _startAngles[ ( int ) pie ];
310 KDChartDataRegion* datReg = 0;
311 TQRegion* region = 0;
312 bool mustDeleteRegion = false;
314 region = new TQRegion();
315 mustDeleteRegion = true;
318 TQRect drawPosition = _position;
319 if ( params()->explode() ) {
322 if( explodeList.count() == 0 ||
323 explodeList.find( pie ) != explodeList.end() ) {
324 double explodeAngle = ( startAngle + angleLen / 2 ) / 16;
325 double explodeAngleRad = DEGTORAD( explodeAngle );
326 double cosAngle = cos( explodeAngleRad );
327 double sinAngle = -sin( explodeAngleRad );
330 double explodeFactor = 0.0;
332 if( !explodeFactors.contains( pie ) )
335 explodeFactor = explodeFactors[pie];
337 double explodeX = explodeFactor * _size * cosAngle;
338 double explodeY = explodeFactor * _size * sinAngle;
339 drawPosition.moveBy( static_cast<int>( explodeX ), static_cast<int>( explodeY ) );
341 drawPosition = _position;
343 drawPosition = _position;
347 if ( params()->threeDPies() ) {
348 draw3DEffect( painter, drawPosition, dataset, pie, chart,
350 params()->explode(), region );
353 painter->setBrush( params()->dataColor( pie ) );
354 if ( angleLen == 5760 ) {
356 painter->drawEllipse( drawPosition );
358 TQPointArray hitregion;
359 hitregion.makeEllipse( drawPosition.x(), drawPosition.y(),
360 drawPosition.width(),
361 drawPosition.height() );
362 datReg = new KDChartDataRegion( region->unite( TQRegion( hitregion ) ),
366 datReg->points[ KDChartEnums::PosCenter ]
367 = drawPosition.center();
368 datReg->points[ KDChartEnums::PosCenterRight ]
369 = pointOnCircle( drawPosition, 0 );
370 datReg->points[ KDChartEnums::PosTopRight ]
371 = pointOnCircle( drawPosition, 720 );
372 datReg->points[ KDChartEnums::PosTopCenter ]
373 = pointOnCircle( drawPosition, 1440 );
374 datReg->points[ KDChartEnums::PosTopLeft ]
375 = pointOnCircle( drawPosition, 2160 );
376 datReg->points[ KDChartEnums::PosCenterLeft ]
377 = pointOnCircle( drawPosition, 2880 );
378 datReg->points[ KDChartEnums::PosBottomLeft ]
379 = pointOnCircle( drawPosition, 3600 );
380 datReg->points[ KDChartEnums::PosBottomCenter ]
381 = pointOnCircle( drawPosition, 4320 );
382 datReg->points[ KDChartEnums::PosBottomRight ]
383 = pointOnCircle( drawPosition, 5040 );
384 datReg->startAngle = 2880;
385 datReg->angleLen = 5760;
386 regions->append( datReg );
391 const int arcPoints = angleLen;
392 TQPointArray collect(arcPoints+2);
394 for ( ; i<=angleLen; ++i){
395 collect.setPoint(i, pointOnCircle( drawPosition, startAngle+i ));
398 collect.setPoint(i, drawPosition.center() );
402 painter->drawPolygon( collect );
412 TQPointArray hitregion;
413 hitregion.makeArc( drawPosition.x(), drawPosition.y(),
414 drawPosition.width(),
415 drawPosition.height(),
416 ( int ) startAngle, ( int ) angleLen );
417 hitregion.resize( hitregion.size() + 1 );
418 hitregion.setPoint( hitregion.size() - 1,
419 drawPosition.center() );
420 datReg = new KDChartDataRegion( region->unite( TQRegion( hitregion ) ),
425 datReg->points[ KDChartEnums::PosTopLeft ]
426 = pointOnCircle( drawPosition, startAngle + angleLen );
427 datReg->points[ KDChartEnums::PosTopCenter ]
428 = pointOnCircle( drawPosition, startAngle + angleLen / 2 );
429 datReg->points[ KDChartEnums::PosTopRight ]
430 = pointOnCircle( drawPosition, startAngle );
432 datReg->points[ KDChartEnums::PosBottomLeft ] = drawPosition.center();
433 datReg->points[ KDChartEnums::PosBottomCenter ]
434 = datReg->points[ KDChartEnums::PosBottomLeft ];
435 datReg->points[ KDChartEnums::PosBottomRight ]
436 = datReg->points[ KDChartEnums::PosBottomLeft ];
438 datReg->points[ KDChartEnums::PosCenterLeft ]
439 = TQPoint( ( datReg->points[ KDChartEnums::PosTopLeft ].x()
440 + datReg->points[ KDChartEnums::PosBottomLeft ].x() ) / 2,
441 ( datReg->points[ KDChartEnums::PosTopLeft ].y()
442 + datReg->points[ KDChartEnums::PosBottomLeft ].y() ) / 2 );
443 datReg->points[ KDChartEnums::PosCenter ]
444 = TQPoint( ( datReg->points[ KDChartEnums::PosTopCenter ].x()
445 + datReg->points[ KDChartEnums::PosBottomCenter ].x() ) / 2,
446 ( datReg->points[ KDChartEnums::PosTopCenter ].y()
447 + datReg->points[ KDChartEnums::PosBottomCenter ].y() ) / 2 );
448 datReg->points[ KDChartEnums::PosCenterRight ]
449 = TQPoint( ( datReg->points[ KDChartEnums::PosTopRight ].x()
450 + datReg->points[ KDChartEnums::PosBottomRight ].x() ) / 2,
451 ( datReg->points[ KDChartEnums::PosTopRight ].y()
452 + datReg->points[ KDChartEnums::PosBottomRight ].y() ) / 2 );
454 datReg->startAngle = startAngle;
455 datReg->angleLen = angleLen;
456 regions->append( datReg );
459 if( mustDeleteRegion )
478 const TQRect& drawPosition,
479 uint dataset, uint pie, uint chart,
492 painter->setBrush( TQBrush( params()->dataShadow1Color( pie ),
493 params()->shadowPattern() ) );
495 int startAngle = _startAngles[ ( int ) pie ];
496 int endAngle = startAngle + _angleLens[ ( int ) pie ];
498 while ( startAngle >= 5760 )
500 while ( endAngle >= 5760 )
502 Q_ASSERT( startAngle >= 0 && startAngle <= 360 * 16 );
503 Q_ASSERT( endAngle >= 0 && endAngle <= 360 * 16 );
507 if ( startAngle == endAngle ||
508 startAngle == endAngle - 5760 ) {
510 threeDHeight, 2880, 5760, region );
511 } else if ( startAngle <= 90 * 16 ) {
512 if ( endAngle <= 90 * 16 ) {
513 if ( startAngle <= endAngle ) {
516 pie, chart, threeDHeight, startAngle,
521 pie, chart, threeDHeight, startAngle,
524 threeDHeight, 2880, 5760, region );
526 } else if ( endAngle <= 180 * 16 ) {
530 threeDHeight, startAngle, region );
532 threeDHeight, endAngle, region );
533 } else if ( endAngle <= 270 * 16 ) {
536 threeDHeight, startAngle,
539 threeDHeight, endAngle, region );
541 threeDHeight, 2880, endAngle, region );
546 threeDHeight, startAngle, region );
548 threeDHeight, 2880, endAngle, region );
550 } else if ( startAngle <= 180 * 16 ) {
551 if ( endAngle <= 90 * 16 ) {
553 threeDHeight, 2880, 5760, region );
554 } else if ( endAngle <= 180 * 16 ) {
555 if ( startAngle <= endAngle ) {
559 pie, chart, threeDHeight, endAngle,
565 pie, chart, threeDHeight, endAngle,
568 threeDHeight, 2880, 5760, region );
570 } else if ( endAngle <= 270 * 16 ) {
572 threeDHeight, endAngle, region );
574 threeDHeight, 2880, endAngle, region );
577 threeDHeight, 2880, endAngle, region );
579 } else if ( startAngle <= 270 * 16 ) {
580 if ( endAngle <= 90 * 16 ) {
582 threeDHeight, startAngle, 5760, region );
583 } else if ( endAngle <= 180 * 16 ) {
585 threeDHeight, endAngle, region );
587 threeDHeight, startAngle, 5760, region );
588 } else if ( endAngle <= 270 * 16 ) {
589 if ( startAngle <= endAngle ) {
593 pie, chart, threeDHeight, endAngle,
596 threeDHeight, startAngle, endAngle,
602 pie, chart, threeDHeight, endAngle,
605 threeDHeight, 2880, endAngle,
608 threeDHeight, startAngle, 5760,
613 threeDHeight, startAngle, endAngle,
617 if ( endAngle <= 90 * 16 ) {
619 threeDHeight, startAngle, region );
621 threeDHeight, startAngle, 5760, region );
622 } else if ( endAngle <= 180 * 16 ) {
624 threeDHeight, startAngle, region );
626 threeDHeight, endAngle, region );
628 threeDHeight, startAngle, 5760, region );
629 } else if ( endAngle <= 270 * 16 ) {
631 threeDHeight, startAngle, region );
633 threeDHeight, endAngle, region );
635 threeDHeight, 2880, endAngle, region );
637 threeDHeight, startAngle, 5760, region );
639 if ( startAngle <= endAngle ) {
643 pie, chart, threeDHeight, startAngle,
646 threeDHeight, startAngle, endAngle,
652 pie, chart, threeDHeight, startAngle,
655 threeDHeight, startAngle, 5760,
658 threeDHeight, 2880, endAngle, region );
682 TQPoint center = rect.center();
683 TQPointArray points( 4 );
684 TQPoint circlePoint = pointOnCircle( rect, angle );
685 points.setPoint( 0, center );
686 points.setPoint( 1, circlePoint );
687 points.setPoint( 2, circlePoint.x(), circlePoint.y() + threeDHeight );
688 points.setPoint( 3, center.x(),
689 center.y() + threeDHeight );
690 painter->drawPolygon( points );
692 *region += TQRegion( points );
716 const int startA = TQMIN(startAngle, endAngle);
717 const int endA = TQMAX(startAngle, endAngle);
718 const int arcPoints = endA-startA+1;
719 TQPointArray collect(arcPoints * 2);
720 for ( int angle=endA; angle>=startA; --angle){
721 collect.setPoint(endA-angle, pointOnCircle( rect, angle ));
726 for ( int i = arcPoints - 1; i >= 0; --i ) {
727 TQPoint pointOnFirstArc = collect.point( i );
728 pointOnFirstArc.setY( pointOnFirstArc.y() + threeDHeight );
729 collect.setPoint( arcPoints * 2 - i - 1, pointOnFirstArc );
731 painter->drawPolygon( collect );
733 *region += TQRegion( collect );
746 for ( int i = 0; i < _numValues; i++ ) {
747 int endseg = _startAngles[ i ] + _angleLens[ i ];
748 if ( ( _startAngles[ i ] <= angle ) &&
749 ( endseg >= angle ) )
769 if ( _numValues > 1 )
770 return _numValues - 1;
788 int rightpie = pie + 1;
789 if ( rightpie == _numValues )
809 return TQObject::tr( "Item " ) + TQString::number( dataset + 1 );
Definition of global enums.
Header for all common chart parameters.
The collection class used by KD Chart to store data region information.
An abstract base class that defines an interface for classes that implement chart drawing.
Bundles the display parameters of a chart.
int threeDPieHeight() const Returns the height of the 3D effect for pies in pixels.
ExplodeFactorsMap explodeFactors() const Returns the list of explode factors.
int numValues() const Returns how many of the values should be shown.
bool threeDPies() const Returns whether the engine should draw any pies in 3D.
TQValueList< int > explodeValues() const Returns which values are exploded in a pie or ring chart.
int pieStart() const Returns the starting point of the pie circle.
double explodeFactor() const Returns the default explode factor, i.e., the explode factor used for those segments which should be ...
virtual void drawOnePie(TQPainter *painter, KDChartTableDataBase *data, uint dataset, uint pie, uint chart, uint threeDPieHeight, KDChartDataRegionList *regions=0) Internal method that draws one of the pies in a pie chart.
void drawStraightEffectSegment(TQPainter *painter, const TQRect &rect, uint dataset, uint pie, uint chart, int threeDHeight, int angle, TQRegion *region=0) Internal method that draws a segment with a straight 3D effect.
virtual void draw3DEffect(TQPainter *painter, const TQRect &drawPosition, uint dataset, uint pie, uint chart, uint threeDPieHeight, bool explode, TQRegion *region=0) Internal method that draws the shadow creating the 3D effect of a pie.
virtual TQString fallbackLegendText(uint dataset) const This method is a specialization that returns a fallback legend text appropriate for pies that do not ...
uint findRightPie(uint pie) Internal method that finds the pie that is located to the right of the pie specified by pie.
uint findPieAt(int angle) Internal method that finds the pie that is located at the position specified by angle.
virtual ~KDChartPiePainter() Destructor.
virtual void paintData(TQPainter *painter, KDChartTableDataBase *data, bool paint2nd, KDChartDataRegionList *regions=0) Paints the actual data area.
KDChartPiePainter(KDChartParams *params) Constructor.
uint findLeftPie(uint pie) Internal method that finds the pie that is located to the left of the pie specified by pie.
void drawArcEffectSegment(TQPainter *painter, const TQRect &rect, uint dataset, uint pie, uint chart, int threeDHeight, int startAngle, int endAngle, TQRegion *region=0) Internal method that draws a segment with an arc 3D effect.
virtual uint numLegendFallbackTexts(KDChartTableDataBase *data) const This methods returns the number of elements to be shown in the legend in case fallback texts are used...
KD Chart's build-in table data for an easy way of storing data values.
virtual uint usedCols() const Returns the number of cols in the table that actually contain data.
virtual bool cellCoord(uint _row, uint _col, TQVariant &_value, int coordinate=1) const =0 Returns one of the coordinate data value(s) stored in a cell.
|