1/*
2 * This file is part of KQuickCharts
3 * SPDX-FileCopyrightText: 2019 Arjen Hiemstra <ahiemstra@heimr.nl>
4 *
5 * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
6 */
7
8#include "LineChartNode.h"
9
10#include <QtMath>
11
12#include "LineChartMaterial.h"
13#include "LineSegmentNode.h"
14
15static const int MaxPointsInSegment = 6;
16
17qreal calculateNormalizedLineWidth(qreal pixelWidth, const QRectF &rect)
18{
19 if (qFuzzyIsNull(d: pixelWidth)) {
20 return 0.0;
21 }
22
23 qreal min = 0.6 / std::max(a: rect.width(), b: rect.height());
24 return std::max(a: min, b: (pixelWidth - 1.0) / (std::min(a: rect.width(), b: rect.height()) * 4.0));
25}
26
27LineChartNode::LineChartNode()
28{
29}
30
31LineChartNode::~LineChartNode()
32{
33}
34
35void LineChartNode::setRect(const QRectF &rect, qreal devicePixelRatio)
36{
37 if (rect == m_rect) {
38 return;
39 }
40
41 m_rect = rect;
42 m_aspect = m_rect.height() / m_rect.width();
43
44 auto nativeSize = QSizeF(m_rect.width() * devicePixelRatio, m_rect.height() * devicePixelRatio);
45 auto diagonal = std::sqrt(x: nativeSize.width() * nativeSize.width() + nativeSize.height() * nativeSize.height());
46 m_smoothing = 1.0 / diagonal;
47}
48
49void LineChartNode::setLineWidth(float width)
50{
51 if (qFuzzyCompare(p1: width, p2: m_lineWidth)) {
52 return;
53 }
54
55 m_lineWidth = width;
56}
57
58void LineChartNode::setLineColor(const QColor &color)
59{
60 if (m_lineColor == color) {
61 return;
62 }
63
64 m_lineColor = color;
65}
66
67void LineChartNode::setFillColor(const QColor &color)
68{
69 if (m_fillColor == color) {
70 return;
71 }
72
73 m_fillColor = color;
74}
75
76void LineChartNode::setValues(const QList<QVector2D> &values)
77{
78 m_values = values;
79}
80
81void LineChartNode::updatePoints()
82{
83 if (m_values.isEmpty()) {
84 return;
85 }
86
87 auto segmentCount = qCeil(v: qreal(m_values.count()) / MaxPointsInSegment);
88
89 auto currentX = m_rect.left();
90 auto pointStart = 0;
91 auto pointsPerSegment = MaxPointsInSegment;
92
93 for (int i = 0; i < segmentCount; ++i) {
94 if (i >= childCount()) {
95 appendChildNode(node: new LineSegmentNode{});
96 }
97
98 auto segment = static_cast<LineSegmentNode *>(childAtIndex(i));
99
100 auto segmentPoints = m_values.mid(pos: pointStart, len: pointsPerSegment);
101 pointStart += pointsPerSegment;
102
103 auto segmentWidth = segmentPoints.last().x() - currentX;
104 auto rect = QRectF(currentX, m_rect.top(), segmentWidth, m_rect.height());
105
106 segment->setRect(rect);
107 segment->setAspect(xAspect: segmentWidth / m_rect.width(), yAspect: m_aspect);
108 segment->setSmoothing(m_smoothing);
109 segment->setLineWidth(calculateNormalizedLineWidth(pixelWidth: m_lineWidth, rect: m_rect));
110 segment->setLineColor(m_lineColor);
111 segment->setFillColor(m_fillColor);
112 segment->setValues(segmentPoints);
113 segment->setFarLeft(m_values.at(i: std::max(a: 0, b: pointStart - pointsPerSegment - 1)));
114 segment->setFarRight(m_values.at(i: std::min<int>(a: m_values.count() - 1, b: pointStart + 1)));
115 segment->update();
116
117 currentX += segmentWidth;
118 }
119
120 while (childCount() > segmentCount) {
121 auto child = childAtIndex(i: childCount() - 1);
122 removeChildNode(node: child);
123 delete child;
124 }
125}
126

source code of kquickcharts/src/scenegraph/LineChartNode.cpp