KD Chart API Documentation  3.1
KDChartRadarGrid.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** This file is part of the KD Chart library.
4 **
5 ** SPDX-FileCopyrightText: 2001 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
6 **
7 ** SPDX-License-Identifier: MIT
8 **
9 ****************************************************************************/
10 
11 #include "KDChartRadarGrid.h"
12 #include "KDChartPaintContext.h"
13 #include "KDChartPieDiagram.h"
15 #include "KDChartRadarDiagram.h"
16 
17 #include <QPainter>
18 
19 #include <KDABLibFakes>
20 
21 using namespace KDChart;
22 
23 DataDimensionsList RadarGrid::calculateGrid(
24  const DataDimensionsList &rawDataDimensions) const
25 {
26  qDebug("Calling PolarGrid::calculateGrid()");
28 
29  // FIXME(khz): do the real calculation
30 
31  l = rawDataDimensions;
32 
33  return l;
34 }
35 
36 static qreal fitFontSizeToGeometry(const QString &text, const QFont &font, const QRectF &geometry, const TextAttributes &ta)
37 {
38  QFont f = font;
39  const qreal origResult = f.pointSizeF();
40  qreal result = origResult;
41  const QSizeF mySize = geometry.size();
42  if (mySize.isNull())
43  return result;
44 
45  const QString t = text;
46  QFontMetrics fm(f);
47  while (true) {
48  const QSizeF textSize = rotatedRect(fm.boundingRect(t), ta.rotation()).normalized().size();
49 
50  if (textSize.height() <= mySize.height() && textSize.width() <= mySize.width())
51  return result;
52 
53  result -= 0.5;
54  if (result <= 0.0)
55  return origResult;
56  f.setPointSizeF(result);
57  fm = QFontMetrics(f);
58  }
59 }
60 
61 QPointF scaleToRealPosition(const QPointF &origin, const QRectF &sourceRect, const QRectF &destRect, const AbstractCoordinatePlane &plane)
62 {
63  QPointF result = plane.translate(origin);
64  result -= sourceRect.topLeft();
65  result.setX(result.x() / sourceRect.width() * destRect.width());
66  result.setY(result.y() / sourceRect.height() * destRect.height());
67  result += destRect.topLeft();
68  return result;
69 }
70 
71 QPointF scaleToRect(const QPointF &origin, const QRectF &sourceRect, const QRectF &destRect)
72 {
73  QPointF result(origin);
74  result -= sourceRect.topLeft();
75  result.setX(result.x() / sourceRect.width() * destRect.width());
76  result.setY(result.y() / sourceRect.height() * destRect.height());
77  result += destRect.topLeft();
78  return result;
79 }
80 
82 {
83  const QBrush backupBrush(context->painter()->brush());
84  context->painter()->setBrush(QBrush());
85  auto *plane = dynamic_cast<RadarCoordinatePlane *>(context->coordinatePlane());
86  Q_ASSERT(plane);
87  Q_ASSERT(plane->diagram());
88  QPair<QPointF, QPointF> boundaries = plane->diagram()->dataBoundaries();
89  Q_ASSERT_X(plane, "PolarGrid::drawGrid",
90  "Bad function call: PaintContext::coodinatePlane() NOT a polar plane.");
91 
92  const GridAttributes gridAttrsCircular(plane->gridAttributes(true));
93  const GridAttributes gridAttrsSagittal(plane->gridAttributes(false));
94 
95  // qDebug() << "OK:";
96  if (!gridAttrsCircular.isGridVisible() && !gridAttrsSagittal.isGridVisible())
97  return;
98  // qDebug() << "A";
99 
100  // FIXME: we paint the rulers to the settings of the first diagram for now:
101  AbstractPolarDiagram *dgr = dynamic_cast<AbstractPolarDiagram *>(plane->diagrams().first());
102  Q_ASSERT(dgr); // only polar diagrams are allowed here
103 
104  // Do not draw a grid for pie diagrams
105  if (dynamic_cast<PieDiagram *>(plane->diagrams().first()))
106  return;
107 
108  context->painter()->setPen(PrintingParameters::scalePen(QColor(Qt::lightGray)));
109  const qreal min = dgr->dataBoundaries().first.y();
110  QPointF origin = plane->translate(QPointF(min, 0)) + context->rectangle().topLeft();
111  // qDebug() << "origin" << origin;
112 
113  const qreal r = qAbs(min) + dgr->dataBoundaries().second.y(); // use the full extents
114 
115  // distance between two axis lines
116  const qreal step = (r - qAbs(min)) / (dgr->numberOfGridRings());
117 
118  // calculate the height needed for text to be displayed at the bottom and top of the chart
119  QPointF topLeft = context->rectangle().topLeft();
120  Q_ASSERT(plane->diagram()->model());
121  TextAttributes ta = plane->textAttributes();
122  const int numberOfSpokes = ( int )(360 / plane->angleUnit());
123  const qreal stepWidth = boundaries.second.y() / (dgr->numberOfGridRings());
124  QRectF destRect = context->rectangle();
125  if (ta.isVisible()) {
126  QAbstractItemModel *model = plane->diagram()->model();
127  QRectF fontRect = context->rectangle();
128  fontRect.setSize(QSizeF(fontRect.width(), step / 2.0));
129  const qreal labelFontSize = fitFontSizeToGeometry(QString::fromLatin1("TestXYWQgqy"), ta.font(), fontRect, ta);
130  QFont labelFont = ta.font();
131  context->painter()->setPen(ta.pen());
132  labelFont.setPointSizeF(labelFontSize);
133  const QFontMetricsF metric(labelFont);
134  const qreal labelHeight = metric.height();
135  QPointF offset;
136  destRect.setY(destRect.y() + 2 * labelHeight);
137  destRect.setHeight(destRect.height() - 4 * labelHeight);
138  offset.setY(labelHeight);
139  offset.setX(0);
140  topLeft += offset;
141  origin += offset;
142  origin = scaleToRealPosition(QPointF(min, 0), context->rectangle(), destRect, *plane);
143 
144  const qreal aWidth = metric.horizontalAdvance(QString::fromLatin1("A"));
145  const QLineF startLine(origin, scaleToRealPosition(QPointF(r - qAbs(min), 0), context->rectangle(), destRect, *plane));
146  for (int i = 0; i < model->rowCount(); ++i) {
147  const QLineF currentLine(origin, scaleToRealPosition(QPointF(r - qAbs(min), i), context->rectangle(), destRect, *plane));
148  const int angle = ( int )startLine.angleTo(currentLine) % 360;
149  const qreal angleTest = qAbs(angle - 180);
150  const QString data = model->headerData(i, Qt::Vertical).toString();
151  const qreal xOffset = metric.horizontalAdvance(data) / 2.0;
152  if (angleTest < 5.0)
153  context->painter()->drawText(currentLine.pointAt(1) + QPointF(-xOffset, labelHeight + qAbs(min)), data);
154  else if (qAbs(angleTest - 180) < 5.0)
155  context->painter()->drawText(currentLine.pointAt(1) - QPointF(xOffset, labelHeight + qAbs(min)), data);
156  else if (angle < 175 && angle > 5)
157  context->painter()->drawText(currentLine.pointAt(1) - QPointF(xOffset * 2 + qAbs(min) + aWidth, -labelHeight / 2.0 + qAbs(min)), data);
158  else if (angle < 355 && angle > 185)
159  context->painter()->drawText(currentLine.pointAt(1) + QPointF(qAbs(min) + aWidth, labelHeight / 2.0 + qAbs(min)), data);
160  }
161  }
162  context->painter()->setPen(PrintingParameters::scalePen(QColor(Qt::lightGray)));
163  if (plane->globalGridAttributes().isGridVisible()) {
164  for (int j = 1; j < dgr->numberOfGridRings() + 1; ++j) {
165  QPointF oldPoint(scaleToRealPosition(QPointF(j * step - qAbs(min), numberOfSpokes - 1), context->rectangle(), destRect, *plane));
166  for (int i = 0; i < numberOfSpokes; ++i) {
167  const QPointF newPoint = scaleToRealPosition(QPointF(j * step - qAbs(min), i), context->rectangle(), destRect, *plane);
168  context->painter()->drawLine(oldPoint, newPoint);
169  oldPoint = newPoint;
170 
171  context->painter()->drawLine(origin, newPoint);
172  }
173  }
174  context->painter()->setPen(ta.pen());
175  qreal fontSize = 0;
176  for (int i = 0; i < dgr->numberOfGridRings() + 1; ++i) {
177  const QString text = QString::number(i * stepWidth);
178  const QPointF translatedPoint = scaleToRealPosition(QPointF(i * step - qAbs(min), 0), context->rectangle(), destRect, *plane);
179  const QFontMetrics metric(ta.font() /*QFont( "Arial", 10 )*/);
180  const qreal textLength = metric.horizontalAdvance(text);
181  const qreal textHeight = metric.height() / 2.0;
182  QPointF textOffset(textLength, -textHeight);
183  textOffset = scaleToRect(textOffset, context->rectangle(), destRect);
184  QPointF _topLeft = topLeft;
185  _topLeft.setY(translatedPoint.y());
186  QRectF boundary(_topLeft, (translatedPoint + QPointF(0, step / 2.0)));
187  const qreal calcFontSize = fitFontSizeToGeometry(text, ta.font(), boundary, ta);
188  if (fontSize != calcFontSize) {
189  QFont paintFont(ta.font());
190  paintFont.setPointSizeF(calcFontSize);
191  ta.setFont(paintFont);
192  ta.setFontSize(calcFontSize);
193  const qreal textHeight2 = QFontMetricsF(paintFont).height() / 2.0;
194  textOffset.setY(-textHeight2);
195  textOffset = scaleToRect(textOffset, context->rectangle(), destRect);
196  context->painter()->setFont(paintFont);
197  fontSize = calcFontSize;
198  }
199  context->painter()->drawText(translatedPoint + destRect.topLeft() - textOffset, text);
200  }
201  }
202  plane->setTextAttributes(ta);
203  context->painter()->setPen(PrintingParameters::scalePen(QColor(Qt::lightGray)));
204  context->painter()->setBrush(backupBrush);
205 }
QRectF rotatedRect(const QRectF &rect, qreal rotation)
QPointF scaleToRect(const QPointF &origin, const QRectF &sourceRect, const QRectF &destRect)
static qreal fitFontSizeToGeometry(const QString &text, const QFont &font, const QRectF &geometry, const TextAttributes &ta)
QPointF scaleToRealPosition(const QPointF &origin, const QRectF &sourceRect, const QRectF &destRect, const AbstractCoordinatePlane &plane)
Base class common for all coordinate planes, CartesianCoordinatePlane, PolarCoordinatePlane,...
virtual const QPointF translate(const QPointF &diagramPoint) const =0
const QPair< QPointF, QPointF > dataBoundaries() const
Return the bottom left and top right data point, that the diagram will display (unless the grid adjus...
Base class for diagrams based on a polar coordinate system.
virtual qreal numberOfGridRings() const =0
A set of attributes controlling the appearance of grids.
Stores information about painting diagrams.
const QRectF rectangle() const
AbstractCoordinatePlane * coordinatePlane() const
QPainter * painter() const
PieDiagram defines a common pie diagram.
static QPen scalePen(const QPen &pen)
void drawGrid(PaintContext *context) override
A set of text attributes.
void setFontSize(const Measure &measure)
void setFont(const QFont &font)
QList< DataDimension > DataDimensionsList

© 2001 Klarälvdalens Datakonsult AB (KDAB)
"The Qt, C++ and OpenGL Experts"
https://www.kdab.com/
https://www.kdab.com/development-resources/qt-tools/kd-chart/
Generated by doxygen 1.9.1