File indexing completed on 2024-05-19 03:59:18
0001 /* 0002 * This file is part of KQuickCharts 0003 * SPDX-FileCopyrightText: 2019 Arjen Hiemstra <ahiemstra@heimr.nl> 0004 * 0005 * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0006 */ 0007 0008 #include "LineChartNode.h" 0009 0010 #include <QtMath> 0011 0012 #include "LineChartMaterial.h" 0013 #include "LineSegmentNode.h" 0014 0015 static const int MaxPointsInSegment = 6; 0016 0017 qreal calculateNormalizedLineWidth(qreal pixelWidth, const QRectF &rect) 0018 { 0019 if (qFuzzyIsNull(pixelWidth)) { 0020 return 0.0; 0021 } 0022 0023 qreal min = 0.6 / std::max(rect.width(), rect.height()); 0024 return std::max(min, (pixelWidth - 1.0) / (std::min(rect.width(), rect.height()) * 4.0)); 0025 } 0026 0027 LineChartNode::LineChartNode() 0028 { 0029 } 0030 0031 LineChartNode::~LineChartNode() 0032 { 0033 } 0034 0035 void LineChartNode::setRect(const QRectF &rect, qreal devicePixelRatio) 0036 { 0037 if (rect == m_rect) { 0038 return; 0039 } 0040 0041 m_rect = rect; 0042 m_aspect = m_rect.height() / m_rect.width(); 0043 0044 auto nativeSize = QSizeF(m_rect.width() * devicePixelRatio, m_rect.height() * devicePixelRatio); 0045 auto diagonal = std::sqrt(nativeSize.width() * nativeSize.width() + nativeSize.height() * nativeSize.height()); 0046 m_smoothing = 1.0 / diagonal; 0047 } 0048 0049 void LineChartNode::setLineWidth(float width) 0050 { 0051 if (qFuzzyCompare(width, m_lineWidth)) { 0052 return; 0053 } 0054 0055 m_lineWidth = width; 0056 } 0057 0058 void LineChartNode::setLineColor(const QColor &color) 0059 { 0060 if (m_lineColor == color) { 0061 return; 0062 } 0063 0064 m_lineColor = color; 0065 } 0066 0067 void LineChartNode::setFillColor(const QColor &color) 0068 { 0069 if (m_fillColor == color) { 0070 return; 0071 } 0072 0073 m_fillColor = color; 0074 } 0075 0076 void LineChartNode::setValues(const QList<QVector2D> &values) 0077 { 0078 m_values = values; 0079 } 0080 0081 void LineChartNode::updatePoints() 0082 { 0083 if (m_values.isEmpty()) { 0084 return; 0085 } 0086 0087 auto segmentCount = qCeil(qreal(m_values.count()) / MaxPointsInSegment); 0088 0089 auto currentX = m_rect.left(); 0090 auto pointStart = 0; 0091 auto pointsPerSegment = MaxPointsInSegment; 0092 0093 for (int i = 0; i < segmentCount; ++i) { 0094 if (i >= childCount()) { 0095 appendChildNode(new LineSegmentNode{}); 0096 } 0097 0098 auto segment = static_cast<LineSegmentNode *>(childAtIndex(i)); 0099 0100 auto segmentPoints = m_values.mid(pointStart, pointsPerSegment); 0101 pointStart += pointsPerSegment; 0102 0103 auto segmentWidth = segmentPoints.last().x() - currentX; 0104 auto rect = QRectF(currentX, m_rect.top(), segmentWidth, m_rect.height()); 0105 0106 segment->setRect(rect); 0107 segment->setAspect(segmentWidth / m_rect.width(), m_aspect); 0108 segment->setSmoothing(m_smoothing); 0109 segment->setLineWidth(calculateNormalizedLineWidth(m_lineWidth, m_rect)); 0110 segment->setLineColor(m_lineColor); 0111 segment->setFillColor(m_fillColor); 0112 segment->setValues(segmentPoints); 0113 segment->setFarLeft(m_values.at(std::max(0, pointStart - pointsPerSegment - 1))); 0114 segment->setFarRight(m_values.at(std::min<int>(m_values.count() - 1, pointStart + 1))); 0115 segment->update(); 0116 0117 currentX += segmentWidth; 0118 } 0119 0120 while (childCount() > segmentCount) { 0121 auto child = childAtIndex(childCount() - 1); 0122 removeChildNode(child); 0123 delete child; 0124 } 0125 }