KD Chart API Documentation 3.1
Loading...
Searching...
No Matches
KDChartRadarDiagram.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 "KDChartRadarDiagram.h"
12#include "KDChartRadarDiagram_p.h"
13
14#include "KDChartPaintContext.h"
15#include "KDChartPainterSaver_p.h"
16#include <QPainter>
17
18#include <KDABLibFakes>
19
20using namespace KDChart;
21
22RadarDiagram::Private::Private()
23{
24}
25
26RadarDiagram::Private::~Private()
27{
28}
29
30#define d d_func()
31
33 : AbstractPolarDiagram(new Private(), parent, plane)
34{
35 // init();
36}
37
41
42void RadarDiagram::init()
43{
44}
45
50{
51 auto *newDiagram = new RadarDiagram(new Private(*d));
52 // This needs to be copied after the fact
53 newDiagram->d->closeDatasets = d->closeDatasets;
54 return newDiagram;
55}
56
58{
59 if (!checkInvariants(true))
60 return QPair<QPointF, QPointF>(QPointF(0, 0), QPointF(0, 0));
61 const int rowCount = model()->rowCount(rootIndex());
62 const int colCount = model()->columnCount(rootIndex());
63 qreal xMin = 0.0;
65 qreal yMin = 0, yMax = 0;
66 for (int iCol = 0; iCol < colCount; ++iCol) {
67 for (int iRow = 0; iRow < rowCount; ++iRow) {
68 qreal value = model()->data(model()->index(iRow, iCol, rootIndex())).toReal(); // checked
69 yMax = qMax(yMax, value);
70 yMin = qMin(yMin, value);
71 }
72 }
73 QPointF bottomLeft(QPointF(xMin, yMin));
74 QPointF topRight(QPointF(xMax, yMax));
75 return QPair<QPointF, QPointF>(bottomLeft, topRight);
76}
77
79{
80 QPainter painter(viewport());
82 ctx.setPainter(&painter);
83 ctx.setRectangle(QRectF(0, 0, width(), height()));
84 paint(&ctx);
85}
86
88{
90 paint(ctx, true, dummy1, dummy2);
91 paint(ctx, false, dummy1, dummy2);
92}
93
94static qreal fitFontSizeToGeometry(const QString &text, const QFont &font, const QRectF &geometry, const TextAttributes &ta)
95{
96 QFont f = font;
97 const qreal origResult = f.pointSizeF();
98 qreal result = origResult;
99 const QSizeF mySize = geometry.size();
100 if (mySize.isNull())
101 return result;
102
103 const QString t = text;
104 QFontMetrics fm(f);
105 while (true) {
106 const QSizeF textSize = rotatedRect(fm.boundingRect(t), ta.rotation()).normalized().size();
107
108 if (textSize.height() <= mySize.height() && textSize.width() <= mySize.width())
109 return result;
110
111 result -= 0.5;
112 if (result <= 0.0)
113 return origResult;
114 f.setPointSizeF(result);
115 fm = QFontMetrics(f);
116 }
117}
118
119static QPointF scaleToRealPosition(const QPointF &origin, const QRectF &sourceRect, const QRectF &destRect, const AbstractCoordinatePlane &plane)
120{
121 QPointF result = plane.translate(origin);
122 result -= sourceRect.topLeft();
123 result.setX(result.x() / sourceRect.width() * destRect.width());
124 result.setY(result.y() / sourceRect.height() * destRect.height());
125 result += destRect.topLeft();
126 return result;
127}
128
130{
131 d->reverseData = val;
132}
134{
135 return d->reverseData;
136}
137
138// local structure to remember the settings of a polygon inclusive the used color and pen.
139struct Polygon
140{
141 QPolygonF polygon;
142 QBrush brush;
143 QPen pen;
144 Polygon(const QPolygonF &polygon, const QBrush &brush, const QPen &pen)
145 : polygon(polygon)
146 , brush(brush)
147 , pen(pen)
148 {
149 }
150};
151
153 bool calculateListAndReturnScale,
154 qreal &newZoomX, qreal &newZoomY)
155{
156 // note: Not having any data model assigned is no bug
157 // but we can not draw a diagram then either.
158 if (!checkInvariants(true))
159 return;
160 d->reverseMapper.clear();
161
162 const int rowCount = model()->rowCount(rootIndex());
163 const int colCount = model()->columnCount(rootIndex());
164
165 int iRow, iCol;
166
167 const qreal min = dataBoundaries().first.y();
168 const qreal r = qAbs(min) + dataBoundaries().second.y();
169 const qreal step = (r - qAbs(min)) / (numberOfGridRings());
170
171 auto *plane = dynamic_cast<RadarCoordinatePlane *>(ctx->coordinatePlane());
172 TextAttributes ta = plane->textAttributes();
173 QRectF fontRect = ctx->rectangle();
174 fontRect.setSize(QSizeF(fontRect.width(), step / 2.0));
176 QFont labelFont = ta.font();
177 ctx->painter()->setPen(ta.pen());
180 const qreal labelHeight = metric.height();
181 QRectF destRect = ctx->rectangle();
182 if (ta.isVisible()) {
184 destRect.setHeight(destRect.height() - 4 * labelHeight);
185 }
186
188 ctx->painter()->save();
189 // Check if all of the data value texts / data comments will fit
190 // into the available space:
191 d->labelPaintCache.clear();
192 ctx->painter()->save();
193 for (iCol = 0; iCol < colCount; ++iCol) {
194 for (iRow = 0; iRow < rowCount; ++iRow) {
195 QModelIndex index = model()->index(iRow, iCol, rootIndex()); // checked
196 const qreal value = model()->data(index).toReal();
197 QPointF point = scaleToRealPosition(QPointF(value, iRow), ctx->rectangle(), destRect, *ctx->coordinatePlane());
198 d->addLabel(&d->labelPaintCache, index, nullptr, PositionPoints(point),
200 }
201 }
202 ctx->painter()->restore();
207 if (d->labelPaintCache.paintReplay.count()) {
209 d->paintDataValueTextsAndMarkers(ctx, d->labelPaintCache, true, true, &txtRectF);
210 const QRect txtRect = txtRectF.toRect();
212 const qreal gapX = qMin(txtRect.left() - curRect.left(), curRect.right() - txtRect.right());
213 const qreal gapY = qMin(txtRect.top() - curRect.top(), curRect.bottom() - txtRect.bottom());
216 if (gapX < 0.0)
217 newZoomX *= 1.0 + (gapX - 1.0) / curRect.width();
218 if (gapY < 0.0)
219 newZoomY *= 1.0 + (gapY - 1.0) / curRect.height();
220 }
221 ctx->painter()->restore();
222
223 } else {
224 // Iterate through data sets and create a list of polygons out of them.
226 for (iCol = 0; iCol < colCount; ++iCol) {
227 // TODO(khz): As of yet RadarDiagram can not show per-segment line attributes
228 // but it draws every polyline in one go - using one color.
229 // This needs to be enhanced to allow for cell-specific settings
230 // in the same way as LineDiagram does it.
231 QPolygonF polygon;
233 for (iRow = 0; iRow < rowCount; ++iRow) {
234 QModelIndex index = model()->index(iRow, iCol, rootIndex()); // checked
235 const qreal value = model()->data(index).toReal();
236 QPointF point = scaleToRealPosition(QPointF(value, d->reverseData ? (rowCount - iRow) : iRow), ctx->rectangle(), destRect, *ctx->coordinatePlane());
237 polygon.append(point);
238 if (!iRow)
239 point0 = point;
240 }
241 if (closeDatasets() && rowCount)
242 polygon.append(point0);
243
244 QBrush brush = d->datasetAttrs(iCol, KDChart::DatasetBrushRole).value<QBrush>();
245 QPen p = d->datasetAttrs(iCol, KDChart::DatasetPenRole).value<QPen>();
246 if (p.style() != Qt::NoPen) {
247 polygons.append(Polygon(polygon, brush, PrintingParameters::scalePen(p)));
248 }
249 }
250
251 // first fill the areas with the brush-color and the defined alpha-value.
252 if (d->fillAlpha > 0.0) {
253 for (const Polygon &p : polygons) {
254 PainterSaver painterSaver(ctx->painter());
255 ctx->painter()->setRenderHint(QPainter::Antialiasing);
256 QBrush br = p.brush;
257 QColor c = br.color();
258 c.setAlphaF(d->fillAlpha);
259 br.setColor(c);
260 ctx->painter()->setBrush(br);
261 ctx->painter()->setPen(p.pen);
262 ctx->painter()->drawPolygon(p.polygon);
263 }
264 }
265
266 // then draw the poly-lines.
267 for (const Polygon &p : polygons) {
268 PainterSaver painterSaver(ctx->painter());
269 ctx->painter()->setRenderHint(QPainter::Antialiasing);
270 ctx->painter()->setBrush(p.brush);
271 ctx->painter()->setPen(p.pen);
272 ctx->painter()->drawPolyline(p.polygon);
273 }
274
275 d->paintDataValueTextsAndMarkers(ctx, d->labelPaintCache, true);
276 }
277}
278
280{
281}
282
283/*virtual*/
285{
286 return model()->rowCount(rootIndex());
287}
288
289/*virtual*/
291{
292 return model() ? model()->rowCount(rootIndex()) : 0.0;
293}
294
295/*virtual*/
297{
298 return 5; // FIXME
299}
300
301void RadarDiagram::setCloseDatasets(bool closeDatasets)
302{
303 d->closeDatasets = closeDatasets;
304}
305
307{
308 return d->closeDatasets;
309}
310
312{
313 return d->fillAlpha;
314}
315
317{
318 d->fillAlpha = alphaF;
319}
320
QRectF rotatedRect(const QRectF &rect, qreal rotation)
static QPointF scaleToRealPosition(const QPointF &origin, const QRectF &sourceRect, const QRectF &destRect, const AbstractCoordinatePlane &plane)
static qreal fitFontSizeToGeometry(const QString &text, const QFont &font, const QRectF &geometry, const TextAttributes &ta)
Base class common for all coordinate planes, CartesianCoordinatePlane, PolarCoordinatePlane,...
virtual const QPointF translate(const QPointF &diagramPoint) const =0
virtual bool checkInvariants(bool justReturnTheStatus=false) const
const QPair< QPointF, QPointF > dataBoundaries() const
Return the bottom left and top right data point, that the diagram will display (unless the grid adjus...
AbstractCoordinatePlane * coordinatePlane() const
Base class for diagrams based on a polar coordinate system.
Stores information about painting diagrams.
void setPainter(QPainter *painter)
Stores the absolute target points of a Position.
static const Position & Center
static QPen scalePen(const QPen &pen)
RadarDiagram defines a common radar diagram.
virtual RadarDiagram * clone() const
qreal numberOfGridRings() const override
void resizeEvent(QResizeEvent *) override
const QPair< QPointF, QPointF > calculateDataBoundaries() const override
void resize(const QSizeF &area) override
qreal numberOfValuesPerDataset() const override
void paintEvent(QPaintEvent *) override
void setFillAlpha(qreal alphaF)
virtual void paint(PaintContext *paintContext, bool calculateListAndReturnScale, qreal &newZoomX, qreal &newZoomY)
qreal valueTotals() const override
RadarDiagram(QWidget *parent=nullptr, RadarCoordinatePlane *plane=nullptr)
void setCloseDatasets(bool closeDatasets)
A set of text attributes.
virtual int columnCount(const QModelIndex &parent) const const=0
virtual QVariant data(const QModelIndex &index, int role) const const=0
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const const=0
virtual int rowCount(const QModelIndex &parent) const const=0
QAbstractItemModel * model() const const
QModelIndex rootIndex() const const
QWidget * viewport() const const
void setAlphaF(qreal alpha)
qreal pointSizeF() const const
void setPointSizeF(qreal pointSize)
QRect boundingRect(QChar ch) const const
T qobject_cast(QObject *object)
void setX(qreal x)
void setY(qreal y)
qreal x() const const
qreal y() const const
qreal height() const const
QRectF normalized() const const
void setSize(const QSizeF &size)
void setY(qreal y)
QSizeF size() const const
QPointF topLeft() const const
qreal width() const const
qreal height() const const
bool isNull() const const
qreal width() const const
QString fromLatin1(const char *str, int size)
qreal toReal(bool *ok) const const
void append(const T &value)
virtual int metric(QPaintDevice::PaintDeviceMetric m) const const override

© 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 on Fri Apr 26 2024 00:04:57 for KD Chart API Documentation by doxygen 1.9.8