KPlotting

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

KDE's Doxygen guidelines are available online.