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/splineanimation_p.h>
31#include <private/splinechartitem_p.h>
32#include <QtCore/QDebug>
33
34Q_DECLARE_METATYPE(QVector<QPointF>)
35Q_DECLARE_METATYPE(SplineVector)
36
37QT_CHARTS_BEGIN_NAMESPACE
38
39SplineAnimation::SplineAnimation(SplineChartItem *item, int duration, QEasingCurve &curve)
40 : XYAnimation(item, duration, curve),
41 m_item(item),
42 m_valid(false)
43{
44}
45
46SplineAnimation::~SplineAnimation()
47{
48}
49
50void SplineAnimation::setup(QVector<QPointF> &oldPoints, QVector<QPointF> &newPoints, QVector<QPointF> &oldControlPoints, QVector<QPointF> &newControlPoints, int index)
51{
52 if (newPoints.count() * 2 - 2 != newControlPoints.count() || newControlPoints.count() < 2) {
53 m_valid = false;
54 m_dirty = false;
55 m_item->setGeometryPoints(newPoints);
56 m_item->setControlGeometryPoints(newControlPoints);
57 m_item->setDirty(false);
58 m_item->updateGeometry();
59 return;
60 }
61
62 m_type = NewAnimation;
63
64 if (state() != QAbstractAnimation::Stopped) {
65 stop();
66 m_dirty = false;
67 }
68
69 if (!m_dirty) {
70 m_dirty = true;
71 m_oldSpline.first = oldPoints;
72 m_oldSpline.second = oldControlPoints;
73 }
74
75 m_newSpline.first = newPoints;
76 m_newSpline.second = newControlPoints;
77
78
79 int x = m_oldSpline.first.count();
80 int y = m_newSpline.first.count();
81
82 if (x - y == 1 && index >= 0 && y > 0) {
83 //remove point
84 if (index > 0) {
85 m_newSpline.first.insert(i: index, t: newPoints[index - 1]);
86 m_newSpline.second.insert(i: (index - 1) * 2, t: newPoints[index - 1]);
87 m_newSpline.second.insert(i: (index - 1) * 2 + 1, t: newPoints[index - 1]);
88 } else {
89 m_newSpline.first.insert(i: 0, t: newPoints[index]);
90 m_newSpline.second.insert(i: 0, t: newPoints[index]);
91 m_newSpline.second.insert(i: 1, t: newPoints[index]);
92 }
93 m_index = index;
94 m_type = RemovePointAnimation;
95 }
96
97 if (x - y == -1 && index >= 0) {
98 //add point
99 if (index > 0) {
100 m_oldSpline.first.insert(i: index, t: newPoints[index - 1]);
101 m_oldSpline.second.insert(i: (index - 1) * 2, t: newPoints[index - 1]);
102 m_oldSpline.second.insert(i: (index - 1) * 2 + 1, t: newPoints[index - 1]);
103 } else {
104 m_oldSpline.first.insert(i: 0, t: newPoints[index]);
105 m_oldSpline.second.insert(i: 0, t: newPoints[index]);
106 m_oldSpline.second.insert(i: 1, t: newPoints[index]);
107 }
108 m_index = index;
109 m_type = AddPointAnimation;
110 }
111
112 x = m_oldSpline.first.count();
113 y = m_newSpline.first.count();
114
115 if (x != y) {
116 m_type = NewAnimation;
117 } else if (m_type == NewAnimation) {
118 m_type = ReplacePointAnimation;
119 }
120
121
122 setKeyValueAt(step: 0.0, value: QVariant::fromValue(value: m_oldSpline));
123 setKeyValueAt(step: 1.0, value: QVariant::fromValue(value: m_newSpline));
124
125 m_valid = true;
126
127}
128
129QVariant SplineAnimation::interpolated(const QVariant &start, const QVariant &end, qreal progress) const
130{
131
132 SplineVector startPair = qvariant_cast< SplineVector >(v: start);
133 SplineVector endPair = qvariant_cast< SplineVector >(v: end);
134 SplineVector result;
135
136 switch (animationType()) {
137 case RemovePointAnimation:
138 case AddPointAnimation:
139 case ReplacePointAnimation: {
140 if (startPair.first.count() != endPair.first.count())
141 break;
142 Q_ASSERT(startPair.first.count() * 2 - 2 == startPair.second.count());
143 Q_ASSERT(endPair.first.count() * 2 - 2 == endPair.second.count());
144 for (int i = 0; i < endPair.first.count(); i++) {
145 qreal x = startPair.first[i].x() + ((endPair.first[i].x() - startPair.first[i].x()) * progress);
146 qreal y = startPair.first[i].y() + ((endPair.first[i].y() - startPair.first[i].y()) * progress);
147 result.first << QPointF(x, y);
148 if (i + 1 >= endPair.first.count())
149 continue;
150 x = startPair.second[i * 2].x() + ((endPair.second[i * 2].x() - startPair.second[i * 2].x()) * progress);
151 y = startPair.second[i * 2].y() + ((endPair.second[i * 2].y() - startPair.second[i * 2].y()) * progress);
152 result.second << QPointF(x, y);
153 x = startPair.second[i * 2 + 1].x() + ((endPair.second[i * 2 + 1].x() - startPair.second[i * 2 + 1].x()) * progress);
154 y = startPair.second[i * 2 + 1].y() + ((endPair.second[i * 2 + 1].y() - startPair.second[i * 2 + 1].y()) * progress);
155 result.second << QPointF(x, y);
156 }
157 }
158 break;
159 case NewAnimation: {
160 Q_ASSERT(endPair.first.count() * 2 - 2 == endPair.second.count());
161 int count = endPair.first.count() * qBound(min: qreal(0), val: progress, max: qreal(1));
162 for (int i = 0; i < count; i++) {
163 result.first << endPair.first[i];
164 if (i + 1 == count)
165 break;
166 result.second << endPair.second[2 * i];
167 result.second << endPair.second[2 * i + 1];
168 }
169 }
170 break;
171 default:
172 qWarning() << "Unknown type of animation";
173 break;
174 }
175
176 return QVariant::fromValue(value: result);
177}
178
179void SplineAnimation::updateCurrentValue(const QVariant &value)
180{
181 if (state() != QAbstractAnimation::Stopped && m_valid) { //workaround
182 QPair<QVector<QPointF >, QVector<QPointF > > pair = qvariant_cast< QPair< QVector<QPointF>, QVector<QPointF> > >(v: value);
183 m_item->setGeometryPoints(pair.first);
184 m_item->setControlGeometryPoints(pair.second);
185 m_item->updateGeometry();
186 m_item->setDirty(true);
187 m_dirty = false;
188 }
189}
190
191void SplineAnimation::updateState(QAbstractAnimation::State newState, QAbstractAnimation::State oldState)
192{
193 XYAnimation::updateState(newState, oldState);
194
195 if (oldState == QAbstractAnimation::Running && newState == QAbstractAnimation::Stopped) {
196 if (m_item->isDirty() && m_type == RemovePointAnimation) {
197 if (!m_newSpline.first.isEmpty()) {
198 if (m_index) {
199 m_newSpline.first.remove(i: m_index);
200 m_newSpline.second.remove(i: (m_index - 1) * 2);
201 m_newSpline.second.remove(i: (m_index - 1) * 2);
202 } else {
203 m_newSpline.first.remove(i: 0);
204 m_newSpline.second.remove(i: 0);
205 m_newSpline.second.remove(i: 0);
206 }
207 }
208 m_item->setGeometryPoints(m_newSpline.first);
209 m_item->setControlGeometryPoints(m_newSpline.second);
210 }
211 }
212
213 if (oldState == QAbstractAnimation::Stopped && newState == QAbstractAnimation::Running) {
214 if (!m_valid)
215 stop();
216 }
217}
218
219QT_CHARTS_END_NAMESPACE
220

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