12 #include "KDChartRingDiagram_p.h" 
   17 #include "KDChartPainterSaver_p.h" 
   19 #include "KDChartPolarCoordinatePlane_p.h" 
   24 #include <KDABLibFakes> 
   28 RingDiagram::Private::Private()
 
   32 RingDiagram::Private::~Private()
 
   48 void RingDiagram::init()
 
   80     return d->relativeThickness;
 
   85     d->expandWhenExploded = expand;
 
   90     return d->expandWhenExploded;
 
   96         return QPair<QPointF, QPointF>(QPointF(0, 0), QPointF(0, 0));
 
  100     QPointF bottomLeft(0, 0);
 
  106         qreal maxExplode = 0.0;
 
  107         for (
int i = 0; i < rCount; ++i) {
 
  108             qreal maxExplodeInThisRow = 0.0;
 
  109             for (
int j = 0; j < colCount; ++j) {
 
  111                 maxExplodeInThisRow = qMax(maxExplodeInThisRow, columnAttrs.
explodeFactor());
 
  113             maxExplode += maxExplodeInThisRow;
 
  116             if (!
d->expandWhenExploded) {
 
  121         maxExplode /= (rCount + 1);
 
  122         topRight = QPointF(1.0 + maxExplode, 1.0 + maxExplode);
 
  124         topRight = QPointF(1.0, 1.0);
 
  126     return QPair<QPointF, QPointF>(bottomLeft, topRight);
 
  131     QPainter painter(viewport());
 
  149     d->reverseMapper.clear();
 
  158     if (contentsRect.isEmpty())
 
  161     d->startAngles = QVector<QVector<qreal>>(rCount, QVector<qreal>(colCount));
 
  162     d->angleLens = QVector<QVector<qreal>>(rCount, QVector<qreal>(colCount));
 
  165     d->size = qMin(contentsRect.width(), contentsRect.height()); 
 
  169     qreal totalOffset = 0.0;
 
  170     for (
int i = 0; i < rCount; ++i) {
 
  171         qreal maxOffsetInThisRow = 0.0;
 
  172         for (
int j = 0; j < colCount; ++j) {
 
  176             maxOffsetInThisRow = qMax(maxOffsetInThisRow, cellAttrs.
gapFactor(
false) + explode);
 
  178         if (!
d->expandWhenExploded) {
 
  179             maxOffsetInThisRow -= qreal(i);
 
  181         totalOffset += qMax(maxOffsetInThisRow, ( qreal )0.0);
 
  189         totalOffset /= (rCount + 1);
 
  190     d->size /= (1.0 + totalOffset);
 
  192     qreal x = (contentsRect.width() == 
d->size) ? 0.0 : ((contentsRect.width() - 
d->size) / 2.0);
 
  193     qreal y = (contentsRect.height() == 
d->size) ? 0.0 : ((contentsRect.height() - 
d->size) / 2.0);
 
  194     d->position = QRectF(x, y, 
d->size, 
d->size);
 
  195     d->position.translate(contentsRect.left(), contentsRect.top());
 
  201     d->forgetAlreadyPaintedDataValues();
 
  202     for (
int iRow = 0; iRow < rCount; ++iRow) {
 
  207         const qreal sectorsPerValue = 360.0 / sum;
 
  209         for (
int iColumn = 0; iColumn < colCount; ++iColumn) {
 
  212             const qreal cellValue = qAbs(model()->data(model()->index(iRow, iColumn, rootIndex())) 
 
  216                 d->startAngles[iRow][iColumn] = currentValue;
 
  217                 d->angleLens[iRow][iColumn] = cellValue * sectorsPerValue;
 
  219                 d->angleLens[iRow][iColumn] = 0.0;
 
  221                     d->startAngles[iRow][iColumn] = 
d->startAngles[iRow][iColumn - 1];
 
  223                     d->startAngles[iRow][iColumn] = currentValue;
 
  227             currentValue = 
d->startAngles[iRow][iColumn] + 
d->angleLens[iRow][iColumn];
 
  234 #if defined(Q_WS_WIN) 
  235 #define trunc(x) (( int )(x)) 
  243 void RingDiagram::drawOneSlice(QPainter *painter, uint dataset, uint slice, qreal granularity)
 
  246     const qreal angleLen = 
d->angleLens[dataset][slice];
 
  248         drawPieSurface(painter, dataset, slice, 
granularity);
 
  263 void RingDiagram::drawPieSurface(QPainter *painter, uint dataset, uint slice, qreal granularity)
 
  266     qreal angleLen = 
d->angleLens[dataset][slice];
 
  268         qreal startAngle = 
d->startAngles[dataset][slice];
 
  270         QModelIndex index(model()->index(dataset, slice, rootIndex())); 
 
  279         QRectF drawPosition = 
d->position;
 
  281         painter->setRenderHint(QPainter::Antialiasing);
 
  283         QBrush br = 
brush(index);
 
  284         if (threeDAttrs.isEnabled()) {
 
  285             br = threeDAttrs.threeDBrush(br, drawPosition);
 
  287         painter->setBrush(br);
 
  289         painter->setPen(
pen(index));
 
  291         if (angleLen == 360) {
 
  296             bool perfectMatch = 
false;
 
  298             qreal circularGap = 0.0;
 
  300             if (attrs.gapFactor(
true) > 0.0) {
 
  302                 circularGap = attrs.gapFactor(
true);
 
  309             qreal actualStartAngle = startAngle + circularGap;
 
  310             qreal actualAngleLen = angleLen - 2 * circularGap;
 
  312             qreal totalRadialExplode = 0.0;
 
  313             qreal maxRadialExplode = 0.0;
 
  315             qreal totalRadialGap = 0.0;
 
  316             qreal maxRadialGap = 0.0;
 
  317             for (uint i = rCount - 1; i > dataset; --i) {
 
  318                 qreal maxRadialExplodeInThisRow = 0.0;
 
  319                 qreal maxRadialGapInThisRow = 0.0;
 
  320                 for (
int j = 0; j < colCount; ++j) {
 
  322                     if (
d->expandWhenExploded) {
 
  323                         maxRadialGapInThisRow = qMax(maxRadialGapInThisRow, cellAttrs.gapFactor(
false));
 
  327                     if (cellAttrs.explode() && 
d->expandWhenExploded) {
 
  328                         maxRadialExplodeInThisRow = qMax(maxRadialExplodeInThisRow, cellAttrs.explodeFactor());
 
  331                 maxRadialExplode += maxRadialExplodeInThisRow;
 
  332                 maxRadialGap += maxRadialGapInThisRow;
 
  338             totalRadialGap = maxRadialGap + attrs.gapFactor(
false);
 
  339             totalRadialExplode = attrs.explode() ? maxRadialExplode + attrs.explodeFactor() : maxRadialExplode;
 
  341             while (degree <= actualAngleLen) {
 
  342                 const QPointF p = pointOnEllipse(drawPosition, dataset, slice, 
false, actualStartAngle + degree,
 
  343                                                  totalRadialGap, totalRadialExplode);
 
  349                 poly.append(pointOnEllipse(drawPosition, dataset, slice, 
false, actualStartAngle + actualAngleLen,
 
  350                                            totalRadialGap, totalRadialExplode));
 
  355             const QPointF innerCenterPoint(poly[
int(iPoint / 2)]);
 
  357             actualStartAngle = startAngle + circularGap;
 
  358             actualAngleLen = angleLen - 2 * circularGap;
 
  360             degree = actualAngleLen;
 
  362             const int lastInnerBrinkPoint = iPoint;
 
  363             while (degree >= 0) {
 
  364                 poly.append(pointOnEllipse(drawPosition, dataset, slice, 
true, actualStartAngle + degree,
 
  365                                            totalRadialGap, totalRadialExplode));
 
  366                 perfectMatch = (degree == 0);
 
  372                 poly.append(pointOnEllipse(drawPosition, dataset, slice, 
true, actualStartAngle,
 
  373                                            totalRadialGap, totalRadialExplode));
 
  378             const QPointF outerCenterPoint(poly[lastInnerBrinkPoint + 
int((iPoint - lastInnerBrinkPoint) / 2)]);
 
  383             painter->drawPolygon(poly);
 
  385             d->reverseMapper.addPolygon(index.row(), index.column(), poly);
 
  387             const QPointF centerPoint = (innerCenterPoint + outerCenterPoint) / 2.0;
 
  389             const PainterSaver ps(painter);
 
  392                 const QPointF &p1 = poly.last();
 
  393                 const QPointF &p2 = poly[lastInnerBrinkPoint];
 
  394                 const QLineF line(p1, p2);
 
  396                 const qreal angle = line.dx() == 0 ? 0.0 : atan(line.dy() / line.dx());
 
  397                 painter->translate(centerPoint);
 
  398                 painter->rotate(angle / 2.0 / 3.141592653589793 * 360.0);
 
  399                 painter->translate(-centerPoint);
 
  411 QPointF RingDiagram::pointOnEllipse(
const QRectF &rect, 
int dataset, 
int slice, 
bool outer, qreal angle,
 
  412                                     qreal totalGapFactor, qreal totalExplodeFactor)
 
  414     qreal angleLen = 
d->angleLens[dataset][slice];
 
  415     qreal startAngle = 
d->startAngles[dataset][slice];
 
  419     qreal level = outer ? (rCount - dataset - 1) + 2 : (rCount - dataset - 1) + 1;
 
  421     const qreal offsetX = rCount > 0 ? level * rect.width() / ((rCount + 1) * 2) : 0.0;
 
  422     const qreal offsetY = rCount > 0 ? level * rect.height() / ((rCount + 1) * 2) : 0.0;
 
  423     const qreal centerOffsetX = rCount > 0 ? totalExplodeFactor * rect.width() / ((rCount + 1) * 2) : 0.0;
 
  424     const qreal centerOffsetY = rCount > 0 ? totalExplodeFactor * rect.height() / ((rCount + 1) * 2) : 0.0;
 
  425     const qreal gapOffsetX = rCount > 0 ? totalGapFactor * rect.width() / ((rCount + 1) * 2) : 0.0;
 
  426     const qreal gapOffsetY = rCount > 0 ? totalGapFactor * rect.height() / ((rCount + 1) * 2) : 0.0;
 
  428     qreal explodeAngleRad = DEGTORAD(angle);
 
  429     qreal cosAngle = cos(explodeAngleRad);
 
  430     qreal sinAngle = -sin(explodeAngleRad);
 
  431     qreal explodeAngleCenterRad = DEGTORAD(startAngle + angleLen / 2.0);
 
  432     qreal cosAngleCenter = cos(explodeAngleCenterRad);
 
  433     qreal sinAngleCenter = -sin(explodeAngleCenterRad);
 
  434     return QPointF((offsetX + gapOffsetX) * cosAngle + centerOffsetX * cosAngleCenter + rect.center().x(),
 
  435                    (offsetY + gapOffsetY) * sinAngle + centerOffsetY * sinAngleCenter + rect.center().y());
 
  444     for (
int i = 0; i < rCount; ++i) {
 
  445         for (
int j = 0; j < colCount; ++j) {
 
  446             total += qAbs(model()->data(model()->index(i, j, rootIndex())).toReal()); 
 
  454     Q_ASSERT(dataset < model()->
rowCount());
 
  457     for (
int j = 0; j < colCount; ++j) {
 
  458         total += qAbs(model()->data(model()->index(dataset, j, rootIndex())).toReal()); 
 
  466     return model() ? model()->columnCount(rootIndex()) : 0.0;
 
  471     return model() ? model()->rowCount(rootIndex()) : 0.0;
 
Declaring the class KDChart::DataValueAttributes.
virtual bool checkInvariants(bool justReturnTheStatus=false) const
DataValueAttributes dataValueAttributes() const
void paintDataValueText(QPainter *painter, const QModelIndex &index, const QPointF &pos, qreal value)
Base class for any diagram type.
PieAttributes pieAttributes() const
qreal granularity() const
bool autoRotateLabels() const
ThreeDPieAttributes threeDPieAttributes() const
const PolarCoordinatePlane * polarCoordinatePlane() const
TextAttributes textAttributes() const
Stores information about painting diagrams.
void setPainter(QPainter *painter)
void setRectangle(const QRectF &rect)
const QRectF rectangle() const
QPainter * painter() const
A set of attributes controlling the appearance of pie charts.
qreal gapFactor(bool circular) const
qreal explodeFactor() const
qreal startPosition() const
RingDiagram defines a common ring diagram.
bool relativeThickness() const
void setRelativeThickness(bool relativeThickness)
void paint(PaintContext *paintContext) override
void resize(const QSizeF &area) override
qreal numberOfGridRings() const override
qreal valueTotals() const override
void paintEvent(QPaintEvent *) override
qreal numberOfDatasets() const override
bool compare(const RingDiagram *other) const
qreal numberOfValuesPerDataset() const override
const QPair< QPointF, QPointF > calculateDataBoundaries() const override
virtual void setExpandWhenExploded(bool expand)
virtual bool expandWhenExploded() const
virtual RingDiagram * clone() const
RingDiagram(QWidget *parent=nullptr, PolarCoordinatePlane *plane=nullptr)
void resizeEvent(QResizeEvent *) override
A set of text attributes.
A set of 3D pie attributes.