24 #include "KDChartRingDiagram_p.h" 28 #include "KDChartPainterSaver_p.h" 30 #include "KDChartPolarCoordinatePlane_p.h" 36 #include <KDABLibFakes> 40 RingDiagram::Private::Private()
41 : relativeThickness( false )
42 , expandWhenExploded( false )
46 RingDiagram::Private::~Private() {}
60 void RingDiagram::init()
74 if ( other ==
this )
return true;
92 return d->relativeThickness;
97 d->expandWhenExploded = expand;
102 return d->expandWhenExploded;
111 QPointF bottomLeft( 0, 0 );
114 if ( attrs.explode() ) {
117 qreal maxExplode = 0.0;
118 for (
int i = 0; i < rCount; ++i ) {
119 qreal maxExplodeInThisRow = 0.0;
120 for (
int j = 0; j < colCount; ++j ) {
122 maxExplodeInThisRow = qMax( maxExplodeInThisRow, columnAttrs.
explodeFactor() );
124 maxExplode += maxExplodeInThisRow;
127 if ( !
d->expandWhenExploded ) {
132 maxExplode /= ( rCount + 1);
133 topRight = QPointF( 1.0 + maxExplode, 1.0 + maxExplode );
135 topRight = QPointF( 1.0, 1.0 );
142 QPainter painter ( viewport() );
160 d->reverseMapper.clear();
169 if ( contentsRect.isEmpty() )
176 d->size = qMin( contentsRect.width(), contentsRect.height() );
180 qreal totalOffset = 0.0;
181 for (
int i = 0; i < rCount; ++i ) {
182 qreal maxOffsetInThisRow = 0.0;
183 for (
int j = 0; j < colCount; ++j ) {
187 maxOffsetInThisRow = qMax( maxOffsetInThisRow, cellAttrs.
gapFactor(
false ) + explode );
189 if ( !
d->expandWhenExploded ) {
190 maxOffsetInThisRow -= qreal( i );
192 totalOffset += qMax( maxOffsetInThisRow, (qreal)0.0 );
200 totalOffset /= ( rCount + 1 );
201 d->size /= ( 1.0 + totalOffset );
204 qreal x = ( contentsRect.width() ==
d->size ) ? 0.0 : ( ( contentsRect.width() -
d->size ) / 2.0 );
205 qreal y = ( contentsRect.height() ==
d->size ) ? 0.0 : ( ( contentsRect.height() -
d->size ) / 2.0 );
206 d->position = QRectF( x, y,
d->size,
d->size );
207 d->position.translate( contentsRect.left(), contentsRect.top() );
213 d->forgetAlreadyPaintedDataValues();
214 for (
int iRow = 0; iRow < rCount; ++iRow ) {
219 const qreal sectorsPerValue = 360.0 / sum;
221 for (
int iColumn = 0; iColumn < colCount; ++iColumn ) {
224 const qreal cellValue = qAbs( model()->data( model()->index( iRow, iColumn, rootIndex() ) )
228 d->startAngles[ iRow ][ iColumn ] = currentValue;
229 d->angleLens[ iRow ][ iColumn ] = cellValue * sectorsPerValue;
231 d->angleLens[ iRow ][ iColumn ] = 0.0;
232 if ( iColumn > 0.0 ) {
233 d->startAngles[ iRow ][ iColumn ] =
d->startAngles[ iRow ][ iColumn - 1 ];
235 d->startAngles[ iRow ][ iColumn ] = currentValue;
239 currentValue =
d->startAngles[ iRow ][ iColumn ] +
d->angleLens[ iRow ][ iColumn ];
246 #if defined ( Q_WS_WIN) 247 #define trunc(x) ((int)(x)) 255 void RingDiagram::drawOneSlice( QPainter* painter, uint dataset, uint slice, qreal
granularity )
258 const qreal angleLen =
d->angleLens[ dataset ][ slice ];
260 drawPieSurface( painter, dataset, slice, granularity );
275 void RingDiagram::drawPieSurface( QPainter* painter, uint dataset, uint slice, qreal
granularity )
278 qreal angleLen =
d->angleLens[ dataset ][ slice ];
280 qreal startAngle =
d->startAngles[ dataset ][ slice ];
282 QModelIndex index( model()->index( dataset, slice, rootIndex() ) );
291 QRectF drawPosition =
d->position;
293 painter->setRenderHint ( QPainter::Antialiasing );
295 QBrush br =
brush( index );
299 painter->setBrush( br );
301 painter->setPen(
pen( index ) );
303 if ( angleLen == 360 ) {
308 bool perfectMatch =
false;
310 qreal circularGap = 0.0;
321 qreal actualStartAngle = startAngle + circularGap;
322 qreal actualAngleLen = angleLen - 2 * circularGap;
324 qreal totalRadialExplode = 0.0;
325 qreal maxRadialExplode = 0.0;
327 qreal totalRadialGap = 0.0;
328 qreal maxRadialGap = 0.0;
329 for ( uint i = rCount - 1; i > dataset; --i ) {
330 qreal maxRadialExplodeInThisRow = 0.0;
331 qreal maxRadialGapInThisRow = 0.0;
332 for (
int j = 0; j < colCount; ++j ) {
334 if (
d->expandWhenExploded ) {
335 maxRadialGapInThisRow = qMax( maxRadialGapInThisRow, cellAttrs.
gapFactor(
false ) );
339 if ( cellAttrs.
explode() &&
d->expandWhenExploded ) {
340 maxRadialExplodeInThisRow = qMax( maxRadialExplodeInThisRow, cellAttrs.
explodeFactor() );
343 maxRadialExplode += maxRadialExplodeInThisRow;
344 maxRadialGap += maxRadialGapInThisRow;
350 totalRadialGap = maxRadialGap + attrs.
gapFactor(
false );
351 totalRadialExplode = attrs.
explode() ? maxRadialExplode + attrs.
explodeFactor() : maxRadialExplode;
353 while ( degree <= actualAngleLen ) {
354 const QPointF p = pointOnEllipse( drawPosition, dataset, slice,
false, actualStartAngle + degree,
355 totalRadialGap, totalRadialExplode );
360 if ( ! perfectMatch ) {
361 poly.append( pointOnEllipse( drawPosition, dataset, slice,
false, actualStartAngle + actualAngleLen,
362 totalRadialGap, totalRadialExplode ) );
367 const QPointF innerCenterPoint( poly[
int(iPoint / 2) ] );
369 actualStartAngle = startAngle + circularGap;
370 actualAngleLen = angleLen - 2 * circularGap;
372 degree = actualAngleLen;
374 const int lastInnerBrinkPoint = iPoint;
375 while ( degree >= 0 ) {
376 poly.append( pointOnEllipse( drawPosition, dataset, slice,
true, actualStartAngle + degree,
377 totalRadialGap, totalRadialExplode ) );
378 perfectMatch = (degree == 0);
383 if ( ! perfectMatch ) {
384 poly.append( pointOnEllipse( drawPosition, dataset, slice,
true, actualStartAngle,
385 totalRadialGap, totalRadialExplode ) );
390 const QPointF outerCenterPoint( poly[ lastInnerBrinkPoint +
int((iPoint - lastInnerBrinkPoint) / 2) ] );
395 painter->drawPolygon( poly );
397 d->reverseMapper.addPolygon( index.row(), index.column(), poly );
399 const QPointF centerPoint = (innerCenterPoint + outerCenterPoint) / 2.0;
401 const PainterSaver ps( painter );
405 const QPointF& p1 = poly.last();
406 const QPointF& p2 = poly[ lastInnerBrinkPoint ];
407 const QLineF line( p1, p2 );
409 const qreal angle = line.dx() == 0 ? 0.0 : atan( line.dy() / line.dx() );
410 painter->translate( centerPoint );
411 painter->rotate( angle / 2.0 / 3.141592653589793 * 360.0 );
412 painter->translate( -centerPoint );
425 QPointF RingDiagram::pointOnEllipse(
const QRectF& rect,
int dataset,
int slice,
bool outer, qreal angle,
426 qreal totalGapFactor, qreal totalExplodeFactor )
428 qreal angleLen =
d->angleLens[ dataset ][ slice ];
429 qreal startAngle =
d->startAngles[ dataset ][ slice ];
433 qreal level = outer ? ( rCount - dataset - 1 ) + 2 : ( rCount - dataset - 1 ) + 1;
435 const qreal offsetX = rCount > 0 ? level * rect.width() / ( ( rCount + 1 ) * 2 ) : 0.0;
436 const qreal offsetY = rCount > 0 ? level * rect.height() / ( ( rCount + 1 ) * 2 ) : 0.0;
437 const qreal centerOffsetX = rCount > 0 ? totalExplodeFactor * rect.width() / ( ( rCount + 1 ) * 2 ) : 0.0;
438 const qreal centerOffsetY = rCount > 0 ? totalExplodeFactor * rect.height() / ( ( rCount + 1 ) * 2 ) : 0.0;
439 const qreal gapOffsetX = rCount > 0 ? totalGapFactor * rect.width() / ( ( rCount + 1 ) * 2 ) : 0.0;
440 const qreal gapOffsetY = rCount > 0 ? totalGapFactor * rect.height() / ( ( rCount + 1 ) * 2 ) : 0.0;
442 qreal explodeAngleRad = DEGTORAD( angle );
443 qreal cosAngle = cos( explodeAngleRad );
444 qreal sinAngle = -sin( explodeAngleRad );
445 qreal explodeAngleCenterRad = DEGTORAD( startAngle + angleLen / 2.0 );
446 qreal cosAngleCenter = cos( explodeAngleCenterRad );
447 qreal sinAngleCenter = -sin( explodeAngleCenterRad );
448 return QPointF( ( offsetX + gapOffsetX ) * cosAngle + centerOffsetX * cosAngleCenter + rect.center().x(),
449 ( offsetY + gapOffsetY ) * sinAngle + centerOffsetY * sinAngleCenter + rect.center().y() );
458 for (
int i = 0; i < rCount; ++i ) {
459 for (
int j = 0; j < colCount; ++j ) {
460 total += qAbs( model()->data( model()->index( i, j, rootIndex() ) ).toReal() );
468 Q_ASSERT( dataset < model()->
rowCount() );
471 for (
int j = 0; j < colCount; ++j ) {
472 total += qAbs( model()->data( model()->index( dataset, j, rootIndex() ) ).toReal() );
480 return model() ? model()->columnCount( rootIndex() ) : 0.0;
485 return model() ? model()->rowCount( rootIndex() ) : 0.0;
DataValueAttributes dataValueAttributes() const
Retrieve the DataValueAttributes specified globally.
void resize(const QSizeF &area) override
[reimplemented]
virtual bool expandWhenExploded() const
void paint(PaintContext *paintContext) override
[reimplemented]
const QRectF rectangle() const
void setPainter(QPainter *painter)
virtual bool checkInvariants(bool justReturnTheStatus=false) const
qreal valueTotals() const override
[reimplemented]
Declaring the class KDChart::DataValueAttributes.
void resizeEvent(QResizeEvent *) override
QPainter * painter() const
virtual void setExpandWhenExploded(bool expand)
qreal granularity() const
RingDiagram(QWidget *parent=0, PolarCoordinatePlane *plane=0)
PieAttributes pieAttributes() const
virtual RingDiagram * clone() const
Creates an exact copy of this diagram.
QBrush brush() const
Retrieve the brush to be used for painting datapoints globally.
A set of attributes controlling the appearance of pie charts.
qreal numberOfDatasets() const override
const QPair< QPointF, QPointF > calculateDataBoundaries() const override
[reimplemented]
const PolarCoordinatePlane * polarCoordinatePlane() const
qreal explodeFactor() const
TextAttributes textAttributes() const
bool compare(const RingDiagram *other) const
Returns true if both diagrams have the same settings.
void setRelativeThickness(bool relativeThickness)
Stores information about painting diagrams.
A set of 3D pie attributes.
qreal numberOfGridRings() const override
[reimplemented]
Base class for any diagram type.
ThreeDPieAttributes threeDPieAttributes() const
bool autoRotateLabels() const
void paintDataValueText(QPainter *painter, const QModelIndex &index, const QPointF &pos, qreal value)
QPen pen() const
Retrieve the pen to be used for painting datapoints globally.
virtual QBrush threeDBrush(const QBrush &brush, const QRectF &rect) const
qreal startPosition() const
Retrieve the rotation of the coordinate plane.
void paintEvent(QPaintEvent *) override
void setRectangle(const QRectF &rect)
RingDiagram defines a common ring diagram.
qreal numberOfValuesPerDataset() const override
[reimplemented]
A set of text attributes.
bool relativeThickness() const
qreal gapFactor(bool circular) const