KPlotting

kplotobject.cpp
1/* -*- C++ -*-
2 This file is part of the KDE libraries
3 SPDX-FileCopyrightText: 2003 Jason Harris <kstars@30doradus.org>
4
5 SPDX-License-Identifier: LGPL-2.0-or-later
6*/
7
8#include "kplotobject.h"
9
10#include <QDebug>
11#include <QPainter>
12#include <QtAlgorithms>
13
14#include "kplotpoint.h"
15#include "kplotwidget.h"
16
17class KPlotObject::Private
18{
19public:
20 Private(KPlotObject *qq)
21 : q(qq)
22 {
23 }
24
25 ~Private()
26 {
27 qDeleteAll(pList);
28 }
29
30 KPlotObject *q;
31
33 PlotTypes type;
34 PointStyle pointStyle;
35 double size;
36 QPen pen, linePen, barPen, labelPen;
37 QBrush brush, barBrush;
38};
39
41 : d(new Private(this))
42{
43 // By default, all pens and brushes are set to the given color
44 setBrush(c);
45 setBarBrush(c);
46 setPen(QPen(brush(), 1));
47 setLinePen(pen());
48 setBarPen(pen());
50
51 d->type |= t;
53 setPointStyle(ps);
54}
55
57
59{
60 return d->type;
61}
62
64{
65 if (b) {
66 d->type |= KPlotObject::Points;
67 } else {
68 d->type &= ~KPlotObject::Points;
69 }
70}
71
73{
74 if (b) {
75 d->type |= KPlotObject::Lines;
76 } else {
77 d->type &= ~KPlotObject::Lines;
78 }
79}
80
82{
83 if (b) {
84 d->type |= KPlotObject::Bars;
85 } else {
86 d->type &= ~KPlotObject::Bars;
87 }
88}
89
90double KPlotObject::size() const
91{
92 return d->size;
93}
94
96{
97 d->size = s;
98}
99
101{
102 return d->pointStyle;
103}
104
106{
107 d->pointStyle = p;
108}
109
110const QPen &KPlotObject::pen() const
111{
112 return d->pen;
113}
114
116{
117 d->pen = p;
118}
119
121{
122 return d->linePen;
123}
124
126{
127 d->linePen = p;
128}
129
131{
132 return d->barPen;
133}
134
136{
137 d->barPen = p;
138}
139
141{
142 return d->labelPen;
143}
144
146{
147 d->labelPen = p;
148}
149
151{
152 return d->brush;
153}
154
156{
157 d->brush = b;
158}
159
161{
162 return d->barBrush;
163}
164
166{
167 d->barBrush = b;
168}
169
171{
172 return d->pList;
173}
174
175void KPlotObject::addPoint(const QPointF &p, const QString &label, double barWidth)
176{
177 addPoint(new KPlotPoint(p.x(), p.y(), label, barWidth));
178}
179
181{
182 if (!p) {
183 return;
184 }
185 d->pList.append(p);
186}
187
188void KPlotObject::addPoint(double x, double y, const QString &label, double barWidth)
189{
190 addPoint(new KPlotPoint(x, y, label, barWidth));
191}
192
194{
195 if ((index < 0) || (index >= d->pList.count())) {
196 // qWarning() << "KPlotObject::removePoint(): index " << index << " out of range!";
197 return;
198 }
199
200 d->pList.removeAt(index);
201}
202
204{
205 qDeleteAll(d->pList);
206 d->pList.clear();
207}
208
210{
211 // Order of drawing determines z-distance: Bars in the back, then lines,
212 // then points, then labels.
213
214 if (d->type & Bars) {
215 painter->setPen(barPen());
216 painter->setBrush(barBrush());
217
218 double w = 0;
219 for (int i = 0; i < d->pList.size(); ++i) {
220 if (d->pList[i]->barWidth() == 0.0) {
221 if (i < d->pList.size() - 1) {
222 w = d->pList[i + 1]->x() - d->pList[i]->x();
223 }
224 // For the last bin, we'll just keep the previous width
225
226 } else {
227 w = d->pList[i]->barWidth();
228 }
229
230 QPointF pp = d->pList[i]->position();
231 QPointF p1(pp.x() - 0.5 * w, 0.0);
232 QPointF p2(pp.x() + 0.5 * w, pp.y());
233 QPointF sp1 = pw->mapToWidget(p1);
234 QPointF sp2 = pw->mapToWidget(p2);
235
236 QRectF barRect = QRectF(sp1.x(), sp1.y(), sp2.x() - sp1.x(), sp2.y() - sp1.y()).normalized();
237 painter->drawRect(barRect);
238 pw->maskRect(barRect, 0.25);
239 }
240 }
241
242 // Draw lines:
243 if (d->type & Lines) {
244 painter->setPen(linePen());
245
246 QPointF Previous = QPointF(); // Initialize to null
247
248 for (const KPlotPoint *pp : std::as_const(d->pList)) {
249 // q is the position of the point in screen pixel coordinates
250 QPointF q = pw->mapToWidget(pp->position());
251
252 if (!Previous.isNull()) {
253 painter->drawLine(Previous, q);
254 pw->maskAlongLine(Previous, q);
255 }
256
257 Previous = q;
258 }
259 }
260
261 // Draw points:
262 if (d->type & Points) {
263 for (const KPlotPoint *pp : std::as_const(d->pList)) {
264 // q is the position of the point in screen pixel coordinates
265 QPointF q = pw->mapToWidget(pp->position());
266 if (pw->pixRect().contains(q.toPoint(), false)) {
267 double x1 = q.x() - size();
268 double y1 = q.y() - size();
269 QRectF qr = QRectF(x1, y1, 2 * size(), 2 * size());
270
271 // Mask out this rect in the plot for label avoidance
272 pw->maskRect(qr, 2.0);
273
274 painter->setPen(pen());
275 painter->setBrush(brush());
276
277 switch (pointStyle()) {
278 case Circle:
279 painter->drawEllipse(qr);
280 break;
281
282 case Letter:
283 painter->drawText(qr, Qt::AlignCenter, pp->label().left(1));
284 break;
285
286 case Triangle: {
287 QPolygonF tri;
288 /* clang-format off */
289 tri << QPointF(q.x() - size(), q.y() + size())
290 << QPointF(q.x(), q.y() - size())
291 << QPointF(q.x() + size(), q.y() + size());
292 /* clang-format on */
293 painter->drawPolygon(tri);
294 break;
295 }
296
297 case Square:
298 painter->drawRect(qr);
299 break;
300
301 case Pentagon: {
302 QPolygonF pent;
303 /* clang-format off */
304 pent << QPointF(q.x(), q.y() - size())
305 << QPointF(q.x() + size(), q.y() - 0.309 * size())
306 << QPointF(q.x() + 0.588 * size(), q.y() + size())
307 << QPointF(q.x() - 0.588 * size(), q.y() + size())
308 << QPointF(q.x() - size(), q.y() - 0.309 * size());
309 /* clang-format on */
310 painter->drawPolygon(pent);
311 break;
312 }
313
314 case Hexagon: {
315 QPolygonF hex;
316 /* clang-format off */
317 hex << QPointF(q.x(), q.y() + size())
318 << QPointF(q.x() + size(), q.y() + 0.5 * size())
319 << QPointF(q.x() + size(), q.y() - 0.5 * size())
320 << QPointF(q.x(), q.y() - size())
321 << QPointF(q.x() - size(), q.y() + 0.5 * size())
322 << QPointF(q.x() - size(), q.y() - 0.5 * size());
323 /* clang-format on */
324 painter->drawPolygon(hex);
325 break;
326 }
327
328 case Asterisk:
329 painter->drawLine(q, QPointF(q.x(), q.y() + size()));
330 painter->drawLine(q, QPointF(q.x() + size(), q.y() + 0.5 * size()));
331 painter->drawLine(q, QPointF(q.x() + size(), q.y() - 0.5 * size()));
332 painter->drawLine(q, QPointF(q.x(), q.y() - size()));
333 painter->drawLine(q, QPointF(q.x() - size(), q.y() + 0.5 * size()));
334 painter->drawLine(q, QPointF(q.x() - size(), q.y() - 0.5 * size()));
335 break;
336
337 case Star: {
338 QPolygonF star;
339 /* clang-format off */
340 star << QPointF(q.x(), q.y() - size())
341 << QPointF(q.x() + 0.2245 * size(), q.y() - 0.309 * size())
342 << QPointF(q.x() + size(), q.y() - 0.309 * size()) << QPointF(q.x() + 0.363 * size(), q.y() + 0.118 * size())
343 << QPointF(q.x() + 0.588 * size(), q.y() + size()) << QPointF(q.x(), q.y() + 0.382 * size())
344 << QPointF(q.x() - 0.588 * size(), q.y() + size()) << QPointF(q.x() - 0.363 * size(), q.y() + 0.118 * size())
345 << QPointF(q.x() - size(), q.y() - 0.309 * size()) << QPointF(q.x() - 0.2245 * size(), q.y() - 0.309 * size());
346 /* clang-format on */
347 painter->drawPolygon(star);
348 break;
349 }
350
351 default:
352 break;
353 }
354 }
355 }
356 }
357
358 // Draw labels
359 painter->setPen(labelPen());
360
361 for (KPlotPoint *pp : std::as_const(d->pList)) {
362 QPoint q = pw->mapToWidget(pp->position()).toPoint();
363 if (pw->pixRect().contains(q, false) && !pp->label().isEmpty()) {
364 pw->placeLabel(painter, pp);
365 }
366 }
367}
Encapsulates a data set to be plotted in a KPlotWidget.
Definition kplotobject.h:43
void draw(QPainter *p, KPlotWidget *pw)
Draw this KPlotObject on the given QPainter.
const QPen & barPen() const
~KPlotObject()
Destructor.
void setSize(double s)
Set the size for plotted points in this object, in pixels.
void addPoint(const QPointF &p, const QString &label=QString(), double barWidth=0.0)
Add a point to the object's list of points, using input data to construct a KPlotPoint.
PointStyle
The available shape styles for plotted points.
Definition kplotobject.h:65
void setBarPen(const QPen &p)
Set the pen to use for drawing bars for this object The pen to use.
void removePoint(int index)
Remove the QPointF at position index from the list of points.
const QPen & linePen() const
PlotTypes plotTypes() const
void setLinePen(const QPen &p)
Set the pen to use for drawing lines for this object The pen to use.
void setPointStyle(PointStyle p)
Set a new style for drawing the points in this object.
double size() const
void setPen(const QPen &p)
Set the default pen for this object The pen to use.
void setShowBars(bool b)
Set whether bars will be drawn for this object.
const QPen & labelPen() const
void setBrush(const QBrush &b)
Set the default brush to use for this object The brush to use.
QList< KPlotPoint * > points() const
void clearPoints()
Remove and destroy the points of this object.
const QPen & pen() const
const QBrush barBrush() const
void setBarBrush(const QBrush &b)
Set the brush to use for drawing bars for this object The brush to use.
void setLabelPen(const QPen &p)
Set the pen to use for labels for this object The pen to use.
PlotType
The type classification of the KPlotObject.
Definition kplotobject.h:54
@ Lines
each KPlotPoint is connected with a line
Definition kplotobject.h:57
@ Points
each KPlotPoint is represented with a drawn point
Definition kplotobject.h:56
@ Bars
each KPlotPoint is shown as a vertical bar
Definition kplotobject.h:58
const QBrush brush() const
PointStyle pointStyle() const
void setShowLines(bool b)
Set whether lines will be drawn for this object.
void setShowPoints(bool b)
Set whether points will be drawn for this object.
KPlotObject(const QColor &color=Qt::white, PlotType otype=Points, double size=2.0, PointStyle ps=Circle)
Constructor.
Encapsulates a point in the plot.
Definition kplotpoint.h:30
Generic data plotting widget.
Definition kplotwidget.h:70
void maskRect(const QRectF &r, float value=1.0f)
Indicate that object labels should try to avoid the given rectangle in the plot.
void maskAlongLine(const QPointF &p1, const QPointF &p2, float value=1.0f)
Indicate that object labels should try to avoid the line joining the two given points (in pixel coord...
QPointF mapToWidget(const QPointF &p) const
Map a coordinate.
void placeLabel(QPainter *painter, KPlotPoint *pp)
Place an object label optimally in the plot.
QRect pixRect() const
void drawEllipse(const QPoint &center, int rx, int ry)
void drawLine(const QLine &line)
void drawPolygon(const QPoint *points, int pointCount, Qt::FillRule fillRule)
void drawRect(const QRect &rectangle)
void drawText(const QPoint &position, const QString &text)
void setBrush(Qt::BrushStyle style)
void setPen(Qt::PenStyle style)
bool isNull() const const
QPoint toPoint() const const
qreal x() const const
qreal y() const const
bool contains(const QPoint &point, bool proper) const const
qreal left() const const
QRectF normalized() const const
AlignCenter
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:14:18 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.