1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
4#include "private/glxyseriesdata_p.h"
5#include "private/abstractdomain_p.h"
6#if QT_CONFIG(charts_scatter_chart)
7#include <QtCharts/QScatterSeries>
8#endif
9
10QT_BEGIN_NAMESPACE
11
12GLXYSeriesDataManager::GLXYSeriesDataManager(QObject *parent)
13 : QObject(parent),
14 m_mapDirty(false)
15{
16}
17
18GLXYSeriesDataManager::~GLXYSeriesDataManager()
19{
20 cleanup();
21}
22
23void GLXYSeriesDataManager::setPoints(QXYSeries *series, const AbstractDomain *domain)
24{
25 GLXYSeriesData *data = m_seriesDataMap.value(key: series);
26 if (!data) {
27 data = new GLXYSeriesData;
28 data->type = series->type();
29 data->visible = series->isVisible();
30 QColor sc;
31#if QT_CONFIG(charts_scatter_chart)
32 if (data->type == QAbstractSeries::SeriesTypeScatter) {
33 QScatterSeries *scatter = static_cast<QScatterSeries *>(series);
34 data->width = float(scatter->markerSize());
35 sc = scatter->color(); // Scatter overwrites color property
36 connect(sender: scatter, signal: &QScatterSeries::colorChanged, context: this,
37 slot: &GLXYSeriesDataManager::handleScatterColorChange);
38 connect(sender: scatter, signal: &QScatterSeries::markerSizeChanged, context: this,
39 slot: &GLXYSeriesDataManager::handleScatterMarkerSizeChange);
40 } else
41#endif
42 {
43 data->width = float(series->pen().widthF());
44 sc = series->color();
45 connect(sender: series, signal: &QXYSeries::penChanged, context: this,
46 slot: &GLXYSeriesDataManager::handleSeriesPenChange);
47 }
48 data->color = QVector3D(float(sc.redF()), float(sc.greenF()), float(sc.blueF()));
49 connect(sender: series, signal: &QXYSeries::useOpenGLChanged, context: this,
50 slot: &GLXYSeriesDataManager::handleSeriesOpenGLChange);
51 connect(sender: series, signal: &QXYSeries::visibleChanged, context: this,
52 slot: &GLXYSeriesDataManager::handleSeriesVisibilityChange);
53 m_seriesDataMap.insert(key: series, value: data);
54 m_mapDirty = true;
55 }
56 QList<float> &array = data->array;
57
58 bool logAxis = false;
59 bool reverseX = false;
60 bool reverseY = false;
61 foreach (QAbstractAxis* axis, series->attachedAxes()) {
62 if (axis->type() == QAbstractAxis::AxisTypeLogValue) {
63 logAxis = true;
64 break;
65 }
66 if (axis->isReverse()) {
67 if (axis->orientation() == Qt::Horizontal)
68 reverseX = true;
69 else
70 reverseY = true;
71 if (reverseX && reverseY)
72 break;
73 }
74 }
75 int count = series->count();
76 int index = 0;
77 array.resize(size: count * 2);
78 QMatrix4x4 matrix;
79 if (logAxis) {
80 // Use domain to resolve geometry points. Not as fast as shaders, but simpler that way
81 QList<QPointF> geometryPoints = domain->calculateGeometryPoints(list: series->points());
82 const float height = domain->size().height();
83 if (geometryPoints.size()) {
84 for (int i = 0; i < count; i++) {
85 const QPointF &point = geometryPoints.at(i);
86 array[index++] = float(point.x());
87 array[index++] = float(height - point.y());
88 }
89 } else {
90 // If there are invalid log values, geometry points generation fails
91 for (int i = 0; i < count; i++) {
92 array[index++] = 0.0f;
93 array[index++] = 0.0f;
94 }
95 }
96 data->min = QVector2D(0, 0);
97 data->delta = QVector2D(domain->size().width() / 2.0f, domain->size().height() / 2.0f);
98 } else {
99 // Regular value axes, so we can optimize it a bit.
100 if (reverseX)
101 matrix.scale(x: -1.0, y: 1.0);
102 if (reverseY)
103 matrix.scale(x: 1.0, y: -1.0);
104
105 const qreal mx = domain->minX();
106 const qreal my = domain->minY();
107 const qreal xd = domain->maxX() - mx;
108 const qreal yd = domain->maxY() - my;
109
110 if (!qFuzzyIsNull(d: xd) && !qFuzzyIsNull(d: yd)) {
111 const QList<QPointF> seriesPoints = series->points();
112 for (const QPointF &point : seriesPoints) {
113 array[index++] = float((point.x() - mx) / xd);
114 array[index++] = float((point.y() - my) / yd);
115 }
116 }
117 data->min = QVector2D(0.0f, 0.0f);
118 data->delta = QVector2D(0.5f, 0.5f);
119 }
120 data->matrix = matrix;
121 data->dirty = true;
122}
123
124void GLXYSeriesDataManager::removeSeries(const QXYSeries *series)
125{
126 GLXYSeriesData *data = m_seriesDataMap.take(key: series);
127 if (data) {
128 disconnect(sender: series, signal: 0, receiver: this, member: 0);
129 delete data;
130 emit seriesRemoved(series);
131 m_mapDirty = true;
132 }
133}
134
135void GLXYSeriesDataManager::cleanup()
136{
137 foreach (GLXYSeriesData *data, m_seriesDataMap.values())
138 delete data;
139 m_seriesDataMap.clear();
140 m_mapDirty = true;
141 // Signal all series removal by using zero as parameter
142 emit seriesRemoved(series: 0);
143}
144
145void GLXYSeriesDataManager::handleSeriesPenChange()
146{
147 QXYSeries *series = qobject_cast<QXYSeries *>(object: sender());
148 if (series) {
149 GLXYSeriesData *data = m_seriesDataMap.value(key: series);
150 if (data) {
151 QColor sc = series->color();
152 data->color = QVector3D(float(sc.redF()), float(sc.greenF()), float(sc.blueF()));
153 data->width = float(series->pen().widthF());
154 data->dirty = true;
155 }
156 }
157}
158
159void GLXYSeriesDataManager::handleSeriesOpenGLChange()
160{
161 QXYSeries *series = qobject_cast<QXYSeries *>(object: sender());
162 if (!series->useOpenGL())
163 removeSeries(series);
164}
165
166void GLXYSeriesDataManager::handleSeriesVisibilityChange()
167{
168 QXYSeries *series = qobject_cast<QXYSeries *>(object: sender());
169 if (series) {
170 GLXYSeriesData *data = m_seriesDataMap.value(key: series);
171 if (data) {
172 data->visible = series->isVisible();
173 data->dirty = true;
174 }
175 }
176}
177
178#if QT_CONFIG(charts_scatter_chart)
179void GLXYSeriesDataManager::handleScatterColorChange()
180{
181 QScatterSeries *series = qobject_cast<QScatterSeries *>(object: sender());
182 if (series) {
183 GLXYSeriesData *data = m_seriesDataMap.value(key: series);
184 if (data) {
185 QColor sc = series->color();
186 data->color = QVector3D(float(sc.redF()), float(sc.greenF()), float(sc.blueF()));
187 data->dirty = true;
188 }
189 }
190}
191
192void GLXYSeriesDataManager::handleScatterMarkerSizeChange()
193{
194 QScatterSeries *series = qobject_cast<QScatterSeries *>(object: sender());
195 if (series) {
196 GLXYSeriesData *data = m_seriesDataMap.value(key: series);
197 if (data) {
198 data->width =float(series->markerSize());
199 data->dirty = true;
200 }
201 }
202}
203#endif
204
205void GLXYSeriesDataManager::handleAxisReverseChanged(const QList<QAbstractSeries *> &seriesList)
206{
207 bool reverseX = false;
208 bool reverseY = false;
209 foreach (QAbstractSeries *series, seriesList) {
210 if (QXYSeries *xyseries = qobject_cast<QXYSeries *>(object: series)) {
211 GLXYSeriesData *data = m_seriesDataMap.value(key: xyseries);
212 if (data) {
213 foreach (QAbstractAxis* axis, xyseries->attachedAxes()) {
214 if (axis->isReverse()) {
215 if (axis->orientation() == Qt::Horizontal)
216 reverseX = true;
217 else
218 reverseY = true;
219 }
220 if (reverseX && reverseY)
221 break;
222 }
223 QMatrix4x4 matrix;
224 if (reverseX)
225 matrix.scale(x: -1.0, y: 1.0);
226 if (reverseY)
227 matrix.scale(x: 1.0, y: -1.0);
228 data->matrix = matrix;
229 data->dirty = true;
230 }
231 }
232 }
233}
234
235QT_END_NAMESPACE
236
237

source code of qtcharts/src/charts/xychart/glxyseriesdata.cpp