1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
4#include <private/splineanimation_p.h>
5#include <private/splinechartitem_p.h>
6#include <QtCore/QDebug>
7
8
9QT_BEGIN_NAMESPACE
10
11SplineAnimation::SplineAnimation(SplineChartItem *item, int duration, QEasingCurve &curve)
12 : XYAnimation(item, duration, curve),
13 m_item(item),
14 m_valid(false)
15{
16}
17
18SplineAnimation::~SplineAnimation()
19{
20}
21
22void SplineAnimation::setup(const QList<QPointF> &oldPoints, const QList<QPointF> &newPoints,
23 const QList<QPointF> &oldControlPoints,
24 const QList<QPointF> &newControlPoints, int index)
25{
26 if (newPoints.size() * 2 - 2 != newControlPoints.size() || newControlPoints.size() < 2) {
27 m_valid = false;
28 m_dirty = false;
29 m_item->setGeometryPoints(newPoints);
30 m_item->setControlGeometryPoints(newControlPoints);
31 m_item->setDirty(false);
32 m_item->updateGeometry();
33 return;
34 }
35
36 m_type = NewAnimation;
37
38 if (state() != QAbstractAnimation::Stopped) {
39 stop();
40 m_dirty = false;
41 }
42
43 if (!m_dirty) {
44 m_dirty = true;
45 m_oldSpline.first = oldPoints;
46 m_oldSpline.second = oldControlPoints;
47 }
48
49 m_newSpline.first = newPoints;
50 m_newSpline.second = newControlPoints;
51
52
53 int x = m_oldSpline.first.size();
54 int y = m_newSpline.first.size();
55
56 if (x - y == 1 && index >= 0 && y > 0) {
57 //remove point
58 if (index > 0) {
59 m_newSpline.first.insert(i: index, t: newPoints[index - 1]);
60 m_newSpline.second.insert(i: (index - 1) * 2, t: newPoints[index - 1]);
61 m_newSpline.second.insert(i: (index - 1) * 2 + 1, t: newPoints[index - 1]);
62 } else {
63 m_newSpline.first.insert(i: 0, t: newPoints[index]);
64 m_newSpline.second.insert(i: 0, t: newPoints[index]);
65 m_newSpline.second.insert(i: 1, t: newPoints[index]);
66 }
67 m_index = index;
68 m_type = RemovePointAnimation;
69 }
70
71 if (x - y == -1 && index >= 0) {
72 //add point
73 if (index > 0) {
74 m_oldSpline.first.insert(i: index, t: newPoints[index - 1]);
75 m_oldSpline.second.insert(i: (index - 1) * 2, t: newPoints[index - 1]);
76 m_oldSpline.second.insert(i: (index - 1) * 2 + 1, t: newPoints[index - 1]);
77 } else {
78 m_oldSpline.first.insert(i: 0, t: newPoints[index]);
79 m_oldSpline.second.insert(i: 0, t: newPoints[index]);
80 m_oldSpline.second.insert(i: 1, t: newPoints[index]);
81 }
82 m_index = index;
83 m_type = AddPointAnimation;
84 }
85
86 x = m_oldSpline.first.size();
87 y = m_newSpline.first.size();
88
89 if (x != y) {
90 m_type = NewAnimation;
91 } else if (m_type == NewAnimation) {
92 m_type = ReplacePointAnimation;
93 }
94
95
96 setKeyValueAt(step: 0.0, value: QVariant::fromValue(value: m_oldSpline));
97 setKeyValueAt(step: 1.0, value: QVariant::fromValue(value: m_newSpline));
98
99 m_valid = true;
100
101}
102
103QVariant SplineAnimation::interpolated(const QVariant &start, const QVariant &end, qreal progress) const
104{
105
106 SplineVector startPair = qvariant_cast< SplineVector >(v: start);
107 SplineVector endPair = qvariant_cast< SplineVector >(v: end);
108 SplineVector result;
109
110 switch (animationType()) {
111 case RemovePointAnimation:
112 case AddPointAnimation:
113 case ReplacePointAnimation: {
114 if (startPair.first.size() != endPair.first.size())
115 break;
116 Q_ASSERT(startPair.first.size() * 2 - 2 == startPair.second.size());
117 Q_ASSERT(endPair.first.size() * 2 - 2 == endPair.second.size());
118 for (int i = 0; i < endPair.first.size(); i++) {
119 qreal x = startPair.first[i].x() + ((endPair.first[i].x() - startPair.first[i].x()) * progress);
120 qreal y = startPair.first[i].y() + ((endPair.first[i].y() - startPair.first[i].y()) * progress);
121 result.first << QPointF(x, y);
122 if (i + 1 >= endPair.first.size())
123 continue;
124 x = startPair.second[i * 2].x() + ((endPair.second[i * 2].x() - startPair.second[i * 2].x()) * progress);
125 y = startPair.second[i * 2].y() + ((endPair.second[i * 2].y() - startPair.second[i * 2].y()) * progress);
126 result.second << QPointF(x, y);
127 x = startPair.second[i * 2 + 1].x() + ((endPair.second[i * 2 + 1].x() - startPair.second[i * 2 + 1].x()) * progress);
128 y = startPair.second[i * 2 + 1].y() + ((endPair.second[i * 2 + 1].y() - startPair.second[i * 2 + 1].y()) * progress);
129 result.second << QPointF(x, y);
130 }
131 }
132 break;
133 case NewAnimation: {
134 Q_ASSERT(endPair.first.size() * 2 - 2 == endPair.second.size());
135 int count = endPair.first.size() * qBound(min: qreal(0), val: progress, max: qreal(1));
136 for (int i = 0; i < count; i++) {
137 result.first << endPair.first[i];
138 if (i + 1 == count)
139 break;
140 result.second << endPair.second[2 * i];
141 result.second << endPair.second[2 * i + 1];
142 }
143 }
144 break;
145 default:
146 qWarning() << "Unknown type of animation";
147 break;
148 }
149
150 return QVariant::fromValue(value: result);
151}
152
153void SplineAnimation::updateCurrentValue(const QVariant &value)
154{
155 if (state() != QAbstractAnimation::Stopped && m_valid) { //workaround
156 const auto pair = qvariant_cast<QPair<QList<QPointF>, QList<QPointF>>>(v: value);
157 m_item->setGeometryPoints(pair.first);
158 m_item->setControlGeometryPoints(pair.second);
159 m_item->updateGeometry();
160 m_item->setDirty(true);
161 m_dirty = false;
162 }
163}
164
165void SplineAnimation::updateState(QAbstractAnimation::State newState, QAbstractAnimation::State oldState)
166{
167 XYAnimation::updateState(newState, oldState);
168
169 if (oldState == QAbstractAnimation::Running && newState == QAbstractAnimation::Stopped) {
170 if (m_item->isDirty() && m_type == RemovePointAnimation) {
171 if (!m_newSpline.first.isEmpty()) {
172 if (m_index) {
173 m_newSpline.first.remove(i: m_index);
174 m_newSpline.second.remove(i: (m_index - 1) * 2);
175 m_newSpline.second.remove(i: (m_index - 1) * 2);
176 } else {
177 m_newSpline.first.remove(i: 0);
178 m_newSpline.second.remove(i: 0);
179 m_newSpline.second.remove(i: 0);
180 }
181 }
182 m_item->setGeometryPoints(m_newSpline.first);
183 m_item->setControlGeometryPoints(m_newSpline.second);
184 }
185 }
186
187 if (oldState == QAbstractAnimation::Stopped && newState == QAbstractAnimation::Running) {
188 if (!m_valid)
189 stop();
190 }
191}
192
193QT_END_NAMESPACE
194

source code of qtcharts/src/charts/animations/splineanimation.cpp