1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the Qt Charts module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 or (at your option) any later version
20** approved by the KDE Free Qt Foundation. The licenses are as published by
21** the Free Software Foundation and appearing in the file LICENSE.GPL3
22** included in the packaging of this file. Please review the following
23** information to ensure the GNU General Public License requirements will
24** be met: https://www.gnu.org/licenses/gpl-3.0.html.
25**
26** $QT_END_LICENSE$
27**
28****************************************************************************/
29
30#include "private/glxyseriesdata_p.h"
31#include "private/abstractdomain_p.h"
32#include <QtCharts/QScatterSeries>
33
34QT_CHARTS_BEGIN_NAMESPACE
35
36GLXYSeriesDataManager::GLXYSeriesDataManager(QObject *parent)
37 : QObject(parent),
38 m_mapDirty(false)
39{
40}
41
42GLXYSeriesDataManager::~GLXYSeriesDataManager()
43{
44 cleanup();
45}
46
47void GLXYSeriesDataManager::setPoints(QXYSeries *series, const AbstractDomain *domain)
48{
49 GLXYSeriesData *data = m_seriesDataMap.value(akey: series);
50 if (!data) {
51 data = new GLXYSeriesData;
52 data->type = series->type();
53 data->visible = series->isVisible();
54 QColor sc;
55 if (data->type == QAbstractSeries::SeriesTypeScatter) {
56 QScatterSeries *scatter = static_cast<QScatterSeries *>(series);
57 data->width = float(scatter->markerSize());
58 sc = scatter->color(); // Scatter overwrites color property
59 connect(sender: scatter, signal: &QScatterSeries::colorChanged, receiver: this,
60 slot: &GLXYSeriesDataManager::handleScatterColorChange);
61 connect(sender: scatter, signal: &QScatterSeries::markerSizeChanged, receiver: this,
62 slot: &GLXYSeriesDataManager::handleScatterMarkerSizeChange);
63 } else {
64 data->width = float(series->pen().widthF());
65 sc = series->color();
66 connect(sender: series, signal: &QXYSeries::penChanged, receiver: this,
67 slot: &GLXYSeriesDataManager::handleSeriesPenChange);
68 }
69 data->color = QVector3D(float(sc.redF()), float(sc.greenF()), float(sc.blueF()));
70 connect(sender: series, signal: &QXYSeries::useOpenGLChanged, receiver: this,
71 slot: &GLXYSeriesDataManager::handleSeriesOpenGLChange);
72 connect(sender: series, signal: &QXYSeries::visibleChanged, receiver: this,
73 slot: &GLXYSeriesDataManager::handleSeriesVisibilityChange);
74 m_seriesDataMap.insert(akey: series, avalue: data);
75 m_mapDirty = true;
76 }
77 QVector<float> &array = data->array;
78
79 bool logAxis = false;
80 bool reverseX = false;
81 bool reverseY = false;
82 foreach (QAbstractAxis* axis, series->attachedAxes()) {
83 if (axis->type() == QAbstractAxis::AxisTypeLogValue) {
84 logAxis = true;
85 break;
86 }
87 if (axis->isReverse()) {
88 if (axis->orientation() == Qt::Horizontal)
89 reverseX = true;
90 else
91 reverseY = true;
92 if (reverseX && reverseY)
93 break;
94 }
95 }
96 int count = series->count();
97 int index = 0;
98 array.resize(asize: count * 2);
99 QMatrix4x4 matrix;
100 if (logAxis) {
101 // Use domain to resolve geometry points. Not as fast as shaders, but simpler that way
102 QVector<QPointF> geometryPoints = domain->calculateGeometryPoints(vector: series->pointsVector());
103 const float height = domain->size().height();
104 if (geometryPoints.size()) {
105 for (int i = 0; i < count; i++) {
106 const QPointF &point = geometryPoints.at(i);
107 array[index++] = float(point.x());
108 array[index++] = float(height - point.y());
109 }
110 } else {
111 // If there are invalid log values, geometry points generation fails
112 for (int i = 0; i < count; i++) {
113 array[index++] = 0.0f;
114 array[index++] = 0.0f;
115 }
116 }
117 data->min = QVector2D(0, 0);
118 data->delta = QVector2D(domain->size().width() / 2.0f, domain->size().height() / 2.0f);
119 } else {
120 // Regular value axes, so we can optimize it a bit.
121 if (reverseX)
122 matrix.scale(x: -1.0, y: 1.0);
123 if (reverseY)
124 matrix.scale(x: 1.0, y: -1.0);
125
126 const qreal mx = domain->minX();
127 const qreal my = domain->minY();
128 const qreal xd = domain->maxX() - mx;
129 const qreal yd = domain->maxY() - my;
130
131 if (!qFuzzyIsNull(d: xd) && !qFuzzyIsNull(d: yd)) {
132 const QVector<QPointF> seriesPoints = series->pointsVector();
133 for (const QPointF &point : seriesPoints) {
134 array[index++] = float((point.x() - mx) / xd);
135 array[index++] = float((point.y() - my) / yd);
136 }
137 }
138 data->min = QVector2D(0.0f, 0.0f);
139 data->delta = QVector2D(0.5f, 0.5f);
140 }
141 data->matrix = matrix;
142 data->dirty = true;
143}
144
145void GLXYSeriesDataManager::removeSeries(const QXYSeries *series)
146{
147 GLXYSeriesData *data = m_seriesDataMap.take(akey: series);
148 if (data) {
149 disconnect(sender: series, signal: 0, receiver: this, member: 0);
150 delete data;
151 emit seriesRemoved(series);
152 m_mapDirty = true;
153 }
154}
155
156void GLXYSeriesDataManager::cleanup()
157{
158 foreach (GLXYSeriesData *data, m_seriesDataMap.values())
159 delete data;
160 m_seriesDataMap.clear();
161 m_mapDirty = true;
162 // Signal all series removal by using zero as parameter
163 emit seriesRemoved(series: 0);
164}
165
166void GLXYSeriesDataManager::handleSeriesPenChange()
167{
168 QXYSeries *series = qobject_cast<QXYSeries *>(object: sender());
169 if (series) {
170 GLXYSeriesData *data = m_seriesDataMap.value(akey: series);
171 if (data) {
172 QColor sc = series->color();
173 data->color = QVector3D(float(sc.redF()), float(sc.greenF()), float(sc.blueF()));
174 data->width = float(series->pen().widthF());
175 data->dirty = true;
176 }
177 }
178}
179
180void GLXYSeriesDataManager::handleSeriesOpenGLChange()
181{
182 QXYSeries *series = qobject_cast<QXYSeries *>(object: sender());
183 if (!series->useOpenGL())
184 removeSeries(series);
185}
186
187void GLXYSeriesDataManager::handleSeriesVisibilityChange()
188{
189 QXYSeries *series = qobject_cast<QXYSeries *>(object: sender());
190 if (series) {
191 GLXYSeriesData *data = m_seriesDataMap.value(akey: series);
192 if (data) {
193 data->visible = series->isVisible();
194 data->dirty = true;
195 }
196 }
197}
198
199void GLXYSeriesDataManager::handleScatterColorChange()
200{
201 QScatterSeries *series = qobject_cast<QScatterSeries *>(object: sender());
202 if (series) {
203 GLXYSeriesData *data = m_seriesDataMap.value(akey: series);
204 if (data) {
205 QColor sc = series->color();
206 data->color = QVector3D(float(sc.redF()), float(sc.greenF()), float(sc.blueF()));
207 data->dirty = true;
208 }
209 }
210}
211
212void GLXYSeriesDataManager::handleScatterMarkerSizeChange()
213{
214 QScatterSeries *series = qobject_cast<QScatterSeries *>(object: sender());
215 if (series) {
216 GLXYSeriesData *data = m_seriesDataMap.value(akey: series);
217 if (data) {
218 data->width =float(series->markerSize());
219 data->dirty = true;
220 }
221 }
222}
223
224void GLXYSeriesDataManager::handleAxisReverseChanged(const QList<QAbstractSeries *> &seriesList)
225{
226 bool reverseX = false;
227 bool reverseY = false;
228 foreach (QAbstractSeries *series, seriesList) {
229 if (QXYSeries *xyseries = qobject_cast<QXYSeries *>(object: series)) {
230 GLXYSeriesData *data = m_seriesDataMap.value(akey: xyseries);
231 if (data) {
232 foreach (QAbstractAxis* axis, xyseries->attachedAxes()) {
233 if (axis->isReverse()) {
234 if (axis->orientation() == Qt::Horizontal)
235 reverseX = true;
236 else
237 reverseY = true;
238 }
239 if (reverseX && reverseY)
240 break;
241 }
242 QMatrix4x4 matrix;
243 if (reverseX)
244 matrix.scale(x: -1.0, y: 1.0);
245 if (reverseY)
246 matrix.scale(x: 1.0, y: -1.0);
247 data->matrix = matrix;
248 data->dirty = true;
249 }
250 }
251 }
252}
253
254QT_CHARTS_END_NAMESPACE
255
256

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