Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qeasingcurve.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4/*
5
6| *property* | *Used for type* |
7| period | QEasingCurve::{In,Out,InOut,OutIn}Elastic |
8| amplitude | QEasingCurve::{In,Out,InOut,OutIn}Bounce, QEasingCurve::{In,Out,InOut,OutIn}Elastic |
9| overshoot | QEasingCurve::{In,Out,InOut,OutIn}Back |
10
11*/
12
13
14
15
16/*!
17 \class QEasingCurve
18 \inmodule QtCore
19 \since 4.6
20 \ingroup animation
21 \brief The QEasingCurve class provides easing curves for controlling animation.
22
23 Easing curves describe a function that controls how the speed of the interpolation
24 between 0 and 1 should be. Easing curves allow transitions from
25 one value to another to appear more natural than a simple constant speed would allow.
26 The QEasingCurve class is usually used in conjunction with the QVariantAnimation and
27 QPropertyAnimation classes but can be used on its own. It is usually used to accelerate
28 the interpolation from zero velocity (ease in) or decelerate to zero velocity (ease out).
29 Ease in and ease out can also be combined in the same easing curve.
30
31 To calculate the speed of the interpolation, the easing curve provides the function
32 valueForProgress(), where the \a progress argument specifies the progress of the
33 interpolation: 0 is the start value of the interpolation, 1 is the end value of the
34 interpolation. The returned value is the effective progress of the interpolation.
35 If the returned value is the same as the input value for all input values the easing
36 curve is a linear curve. This is the default behaviour.
37
38 For example,
39
40 \snippet code/src_corelib_tools_qeasingcurve.cpp 0
41
42 will print the effective progress of the interpolation between 0 and 1.
43
44 When using a QPropertyAnimation, the associated easing curve will be used to control the
45 progress of the interpolation between startValue and endValue:
46
47 \snippet code/src_corelib_tools_qeasingcurve.cpp 1
48
49 The ability to set an amplitude, overshoot, or period depends on
50 the QEasingCurve type. Amplitude access is available to curves
51 that behave as springs such as elastic and bounce curves. Changing
52 the amplitude changes the height of the curve. Period access is
53 only available to elastic curves and setting a higher period slows
54 the rate of bounce. Only curves that have "boomerang" behaviors
55 such as the InBack, OutBack, InOutBack, and OutInBack have
56 overshoot settings. These curves will interpolate beyond the end
57 points and return to the end point, acting similar to a boomerang.
58
59 The \l{Easing Curves Example} contains samples of QEasingCurve
60 types and lets you change the curve settings.
61
62 */
63
64/*!
65 \enum QEasingCurve::Type
66
67 The type of easing curve.
68
69 \value Linear \image qeasingcurve-linear.png {Graph of a
70 linear function.}
71 \caption Easing curve for a linear (t) function:
72 velocity is constant.
73 \value InQuad \image qeasingcurve-inquad.png {Graph of a
74 InQuadratic function.}
75 \caption Easing curve for a quadratic (t^2) function:
76 accelerating from zero velocity.
77 \value OutQuad \image qeasingcurve-outquad.png {Graph of a
78 OutQuadratic function}
79 \caption Easing curve for a quadratic (t^2) function:
80 decelerating to zero velocity.
81 \value InOutQuad \image qeasingcurve-inoutquad.png {Graph of a
82 InOutquad quadratic function}
83 \caption Easing curve for a quadratic (t^2) function:
84 acceleration until halfway, then deceleration.
85 \value OutInQuad \image qeasingcurve-outinquad.png {Graph of a
86 OutInquad quadratic function}
87 \caption Easing curve for a quadratic (t^2) function:
88 deceleration until halfway, then acceleration.
89 \value InCubic \image qeasingcurve-incubic.png {Graph of a
90 InCubic function}
91 \caption Easing curve for a cubic (t^3) function:
92 accelerating from zero velocity.
93 \value OutCubic \image qeasingcurve-outcubic.png {Graph of a
94 OutCubic function}
95 \caption Easing curve for a cubic (t^3) function:
96 decelerating to zero velocity.
97 \value InOutCubic \image qeasingcurve-inoutcubic.png {Graph of a
98 InOutCubic function.}
99 \caption Easing curve for a cubic (t^3) function:
100 acceleration until halfway, then deceleration.
101 \value OutInCubic \image qeasingcurve-outincubic.png {Graph of a
102 OutInCubic function.}
103 \caption Easing curve for a cubic (t^3) function:
104 deceleration until halfway, then acceleration.
105 \value InQuart \image qeasingcurve-inquart.png {Graph of a
106 InQuartic function.}
107 \caption Easing curve for a quartic (t^4) function:
108 accelerating from zero velocity.
109 \value OutQuart \image qeasingcurve-outquart.png {Graph of a
110 OutQuartic function.}
111 \caption
112 Easing curve for a quartic (t^4) function:
113 decelerating to zero velocity.
114 \value InOutQuart \image qeasingcurve-inoutquart.png {Graph of a
115 InOutQuartic function.}
116 \caption
117 Easing curve for a quartic (t^4) function:
118 acceleration until halfway, then deceleration.
119 \value OutInQuart \image qeasingcurve-outinquart.png {Graph of a
120 OutInQuartic function.}
121 \caption
122 Easing curve for a quartic (t^4) function:
123 deceleration until halfway, then acceleration.
124 \value InQuint \image qeasingcurve-inquint.png {Graph of a
125 InQuintic function}
126 \caption
127 Easing curve for a quintic (t^5) easing
128 in: accelerating from zero velocity.
129 \value OutQuint \image qeasingcurve-outquint.png {Graph of a
130 OutQuintic function}
131 \caption
132 Easing curve for a quintic (t^5) function:
133 decelerating to zero velocity.
134 \value InOutQuint \image qeasingcurve-inoutquint.png {Graph of a
135 InOutQuintic function}
136 \caption
137 Easing curve for a quintic (t^5) function:
138 acceleration until halfway, then deceleration.
139 \value OutInQuint \image qeasingcurve-outinquint.png {Graph of a
140 OutInQuintic function}
141 \caption
142 Easing curve for a quintic (t^5) function:
143 deceleration until halfway, then acceleration.
144 \value InSine \image qeasingcurve-insine.png {Graph of a
145 InSinusoidal function}
146 \caption
147 Easing curve for a sinusoidal (sin(t)) function:
148 accelerating from zero velocity.
149 \value OutSine \image qeasingcurve-outsine.png {Graph of a
150 OutSinusoidal function}
151 \caption
152 Easing curve for a sinusoidal (sin(t)) function:
153 decelerating to zero velocity.
154 \value InOutSine \image qeasingcurve-inoutsine.png {Graph of a
155 InOutSinusoidal function}
156 \caption
157 Easing curve for a sinusoidal (sin(t)) function:
158 acceleration until halfway, then deceleration.
159 \value OutInSine \image qeasingcurve-outinsine.png {Graph of a
160 OutInSinusoidal function}
161 \caption
162 Easing curve for a sinusoidal (sin(t)) function:
163 deceleration until halfway, then acceleration.
164 \value InExpo \image qeasingcurve-inexpo.png {Graph of a
165 InExponential function}
166 \caption
167 Easing curve for an exponential (2^t) function:
168 accelerating from zero velocity.
169 \value OutExpo \image qeasingcurve-outexpo.png {Graph of a
170 OutExponential function}
171 \caption
172 Easing curve for an exponential (2^t) function:
173 decelerating to zero velocity.
174 \value InOutExpo \image qeasingcurve-inoutexpo.png {Graph of a
175 InOutExponential function}
176 \caption
177 Easing curve for an exponential (2^t) function:
178 acceleration until halfway, then deceleration.
179 \value OutInExpo \image qeasingcurve-outinexpo.png {Graph of a
180 OutInExponential function}
181 \caption
182 Easing curve for an exponential (2^t) function:
183 deceleration until halfway, then acceleration.
184 \value InCirc \image qeasingcurve-incirc.png {Graph of a
185 InCircular function}
186 \caption
187 Easing curve for a circular (sqrt(1-t^2)) function:
188 accelerating from zero velocity.
189 \value OutCirc \image qeasingcurve-outcirc.png {Graph of a
190 OutCircular function}
191 \caption
192 Easing curve for a circular (sqrt(1-t^2)) function:
193 decelerating to zero velocity.
194 \value InOutCirc \image qeasingcurve-inoutcirc.png {Graph of a
195 InOutCircular function}
196 \caption
197 Easing curve for a circular (sqrt(1-t^2)) function:
198 acceleration until halfway, then deceleration.
199 \value OutInCirc \image qeasingcurve-outincirc.png {Graph of a
200 OutInCircular function}
201 \caption
202 Easing curve for a circular (sqrt(1-t^2)) function:
203 deceleration until halfway, then acceleration.
204 \value InElastic \image qeasingcurve-inelastic.png {Graph of a
205 InElastic function}
206 \caption
207 Easing curve for an elastic
208 (exponentially decaying sine wave) function:
209 accelerating from zero velocity. The peak amplitude
210 can be set with the \e amplitude parameter, and the
211 period of decay by the \e period parameter.
212 \value OutElastic \image qeasingcurve-outelastic.png {Graph of a
213 OutElastic function}
214 \caption
215 Easing curve for an elastic
216 (exponentially decaying sine wave) function:
217 decelerating to zero velocity. The peak amplitude
218 can be set with the \e amplitude parameter, and the
219 period of decay by the \e period parameter.
220 \value InOutElastic \image qeasingcurve-inoutelastic.png {Graph of a
221 InOutElastic function}
222 \caption
223 Easing curve for an elastic
224 (exponentially decaying sine wave) function:
225 acceleration until halfway, then deceleration.
226 \value OutInElastic \image qeasingcurve-outinelastic.png {Graph of a
227 OutInElastic function}
228 \caption
229 Easing curve for an elastic
230 (exponentially decaying sine wave) function:
231 deceleration until halfway, then acceleration.
232 \value InBack \image qeasingcurve-inback.png {Graph of a
233 InBack function}
234 \caption
235 Easing curve for a back (overshooting
236 cubic function: (s+1)*t^3 - s*t^2) easing in:
237 accelerating from zero velocity.
238 \value OutBack \image qeasingcurve-outback.png {Graph of a
239 OutBack function}
240 \caption
241 Easing curve for a back (overshooting
242 cubic function: (s+1)*t^3 - s*t^2) easing out:
243 decelerating to zero velocity.
244 \value InOutBack \image qeasingcurve-inoutback.png Graph of a
245 InOutBack function}
246 \caption
247 Easing curve for a back (overshooting
248 cubic function: (s+1)*t^3 - s*t^2) easing in/out:
249 acceleration until halfway, then deceleration.
250 \value OutInBack \image qeasingcurve-outinback.png {Graph of a
251 OutInBack function}
252 \caption
253 Easing curve for a back (overshooting
254 cubic easing: (s+1)*t^3 - s*t^2) easing out/in:
255 deceleration until halfway, then acceleration.
256 \value InBounce \image qeasingcurve-inbounce.png {Graph of a
257 InBounce function}
258 \caption
259 Easing curve for a bounce (exponentially
260 decaying parabolic bounce) function: accelerating
261 from zero velocity.
262 \value OutBounce \image qeasingcurve-outbounce.png {Graph of a
263 OutBounce function}
264 \caption
265 Easing curve for a bounce (exponentially
266 decaying parabolic bounce) function: decelerating
267 from zero velocity.
268 \value InOutBounce \image qeasingcurve-inoutbounce.png {Graph of a
269 InOutBounce function}
270 \caption
271 Easing curve for a bounce (exponentially
272 decaying parabolic bounce) function easing in/out:
273 acceleration until halfway, then deceleration.
274 \value OutInBounce \image qeasingcurve-outinbounce.png {Graph of a
275 OutInBounce function}
276 \caption
277 Easing curve for a bounce (exponentially
278 decaying parabolic bounce) function easing out/in:
279 deceleration until halfway, then acceleration.
280 \omitvalue InCurve
281 \omitvalue OutCurve
282 \omitvalue SineCurve
283 \omitvalue CosineCurve
284 \value BezierSpline Allows defining a custom easing curve using a cubic bezier spline
285 \sa addCubicBezierSegment()
286 \value TCBSpline Allows defining a custom easing curve using a TCB spline
287 \sa addTCBSegment()
288 \value Custom This is returned if the user specified a custom curve type with
289 setCustomType(). Note that you cannot call setType() with this value,
290 but type() can return it.
291 \omitvalue NCurveTypes
292*/
293
294/*!
295 \typedef QEasingCurve::EasingFunction
296
297 This is a typedef for a pointer to a function with the following
298 signature:
299
300 \snippet code/src_corelib_tools_qeasingcurve.cpp typedef
301*/
302
303#include "qeasingcurve.h"
304#include <cmath>
305
306#ifndef QT_NO_DEBUG_STREAM
307#include <QtCore/qdebug.h>
308#include <QtCore/qstring.h>
309#endif
310
311#ifndef QT_NO_DATASTREAM
312#include <QtCore/qdatastream.h>
313#endif
314
315#include <QtCore/qpoint.h>
316#include <QtCore/qlist.h>
317
319
320static constexpr bool isConfigFunction(QEasingCurve::Type type)
321{
322 return (type >= QEasingCurve::InElastic
323 && type <= QEasingCurve::OutInBounce) ||
324 type == QEasingCurve::BezierSpline ||
325 type == QEasingCurve::TCBSpline;
326}
327
329{
334
336 TCBPoint(QPointF point, qreal t, qreal c, qreal b) : _point(point), _t(t), _c(c), _b(b) {}
337
338 bool operator==(const TCBPoint &other) const
339 {
340 return _point == other._point &&
341 qFuzzyCompare(_t, other._t) &&
342 qFuzzyCompare(_c, other._c) &&
343 qFuzzyCompare(_b, other._b);
344 }
345};
347
348QDataStream &operator<<(QDataStream &stream, const TCBPoint &point)
349{
350 stream << point._point
351 << point._t
352 << point._c
353 << point._b;
354 return stream;
355}
356
357QDataStream &operator>>(QDataStream &stream, TCBPoint &point)
358{
359 stream >> point._point
360 >> point._t
361 >> point._c
362 >> point._b;
363 return stream;
364}
365
367
388
389QDataStream &operator<<(QDataStream &stream, QEasingCurveFunction *func)
390{
391 if (func) {
392 stream << func->_p;
393 stream << func->_a;
394 stream << func->_o;
395 if (stream.version() > QDataStream::Qt_5_12) {
396 stream << func->_bezierCurves;
397 stream << func->_tcbPoints;
398 }
399 }
400 return stream;
401}
402
403QDataStream &operator>>(QDataStream &stream, QEasingCurveFunction *func)
404{
405 if (func) {
406 stream >> func->_p;
407 stream >> func->_a;
408 stream >> func->_o;
409 if (stream.version() > QDataStream::Qt_5_12) {
410 stream >> func->_bezierCurves;
411 stream >> func->_tcbPoints;
412 }
413 }
414 return stream;
415}
416
417static QEasingCurve::EasingFunction curveToFunc(QEasingCurve::Type curve);
418
420{
421 QEasingCurve::EasingFunction func = curveToFunc(_t);
422 return func(t);
423}
424
426{
427 QEasingCurveFunction *rv = new QEasingCurveFunction(_t, _p, _a, _o);
428 rv->_bezierCurves = _bezierCurves;
430 return rv;
431}
432
434{
435 return _t == other._t &&
436 qFuzzyCompare(_p, other._p) &&
437 qFuzzyCompare(_a, other._a) &&
438 qFuzzyCompare(_o, other._o) &&
439 _bezierCurves == other._bezierCurves &&
440 _tcbPoints == other._tcbPoints;
441}
442
443QT_BEGIN_INCLUDE_NAMESPACE
444#include "../../3rdparty/easing/easing.cpp"
445QT_END_INCLUDE_NAMESPACE
446
447class QEasingCurvePrivate
448{
449public:
450 QEasingCurvePrivate()
451 : type(QEasingCurve::Linear),
452 config(nullptr),
453 func(&easeNone)
454 { }
455 QEasingCurvePrivate(const QEasingCurvePrivate &other)
456 : type(other.type),
457 config(other.config ? other.config->copy() : nullptr),
458 func(other.func)
459 { }
460 ~QEasingCurvePrivate() { delete config; }
461 void setType_helper(QEasingCurve::Type);
462
463 QEasingCurve::Type type;
464 QEasingCurveFunction *config;
465 QEasingCurve::EasingFunction func;
466};
467
469{
476
480 bool _init;
481 bool _valid;
482
486
487 void init()
488 {
489 if (_bezierCurves.constLast() == QPointF(1.0, 1.0)) {
490 _init = true;
491 _curveCount = _bezierCurves.size() / 3;
492
493 for (int i=0; i < _curveCount; i++) {
494 _intervals[i] = _bezierCurves.at(i * 3 + 2).x();
495
496 if (i == 0) {
497 _curves[0].p0x = 0.0;
498 _curves[0].p0y = 0.0;
499
500 _curves[0].p1x = _bezierCurves.at(0).x();
501 _curves[0].p1y = _bezierCurves.at(0).y();
502
503 _curves[0].p2x = _bezierCurves.at(1).x();
504 _curves[0].p2y = _bezierCurves.at(1).y();
505
506 _curves[0].p3x = _bezierCurves.at(2).x();
507 _curves[0].p3y = _bezierCurves.at(2).y();
508
509 } else if (i == (_curveCount - 1)) {
510 _curves[i].p0x = _bezierCurves.at(_bezierCurves.size() - 4).x();
511 _curves[i].p0y = _bezierCurves.at(_bezierCurves.size() - 4).y();
512
513 _curves[i].p1x = _bezierCurves.at(_bezierCurves.size() - 3).x();
514 _curves[i].p1y = _bezierCurves.at(_bezierCurves.size() - 3).y();
515
516 _curves[i].p2x = _bezierCurves.at(_bezierCurves.size() - 2).x();
517 _curves[i].p2y = _bezierCurves.at(_bezierCurves.size() - 2).y();
518
519 _curves[i].p3x = _bezierCurves.at(_bezierCurves.size() - 1).x();
520 _curves[i].p3y = _bezierCurves.at(_bezierCurves.size() - 1).y();
521 } else {
522 _curves[i].p0x = _bezierCurves.at(i * 3 - 1).x();
523 _curves[i].p0y = _bezierCurves.at(i * 3 - 1).y();
524
525 _curves[i].p1x = _bezierCurves.at(i * 3).x();
526 _curves[i].p1y = _bezierCurves.at(i * 3).y();
527
528 _curves[i].p2x = _bezierCurves.at(i * 3 + 1).x();
529 _curves[i].p2y = _bezierCurves.at(i * 3 + 1).y();
530
531 _curves[i].p3x = _bezierCurves.at(i * 3 + 2).x();
532 _curves[i].p3y = _bezierCurves.at(i * 3 + 2).y();
533 }
534 }
535 _valid = true;
536 } else {
537 _valid = false;
538 }
539 }
540
541 QEasingCurveFunction *copy() const override
542 {
543 BezierEase *rv = new BezierEase();
544 rv->_t = _t;
545 rv->_p = _p;
546 rv->_a = _a;
547 rv->_o = _o;
548 rv->_bezierCurves = _bezierCurves;
550 return rv;
551 }
552
553 void getBezierSegment(SingleCubicBezier * &singleCubicBezier, qreal x)
554 {
555
556 int currentSegment = 0;
557
558 while (currentSegment < _curveCount) {
559 if (x <= _intervals.data()[currentSegment])
560 break;
561 currentSegment++;
562 }
563
564 singleCubicBezier = &_curves.data()[currentSegment];
565 }
566
567
568 qreal static inline newtonIteration(const SingleCubicBezier &singleCubicBezier, qreal t, qreal x)
569 {
570 qreal currentXValue = evaluateForX(singleCubicBezier, t);
571
572 const qreal newT = t - (currentXValue - x) / evaluateDerivateForX(singleCubicBezier, t);
573
574 return newT;
575 }
576
577 qreal value(qreal x) override
578 {
579 Q_ASSERT(_bezierCurves.size() % 3 == 0);
580
581 if (_bezierCurves.isEmpty()) {
582 return x;
583 }
584
585 if (!_init)
586 init();
587
588 if (!_valid) {
589 qWarning("QEasingCurve: Invalid bezier curve");
590 return x;
591 }
592
593 // The bezier computation is not always precise on the endpoints, so handle explicitly
594 if (!(x > 0))
595 return 0;
596 if (!(x < 1))
597 return 1;
598
599 SingleCubicBezier *singleCubicBezier = nullptr;
600 getBezierSegment(singleCubicBezier, x);
601
602 return evaluateSegmentForY(*singleCubicBezier, findTForX(*singleCubicBezier, x));
603 }
604
605 qreal static inline evaluateSegmentForY(const SingleCubicBezier &singleCubicBezier, qreal t)
606 {
607 const qreal p0 = singleCubicBezier.p0y;
608 const qreal p1 = singleCubicBezier.p1y;
609 const qreal p2 = singleCubicBezier.p2y;
610 const qreal p3 = singleCubicBezier.p3y;
611
612 const qreal s = 1 - t;
613
614 const qreal s_squared = s * s;
615 const qreal t_squared = t * t;
616
617 const qreal s_cubic = s_squared * s;
618 const qreal t_cubic = t_squared * t;
619
620 return s_cubic * p0 + 3 * s_squared * t * p1 + 3 * s * t_squared * p2 + t_cubic * p3;
621 }
622
623 qreal static inline evaluateForX(const SingleCubicBezier &singleCubicBezier, qreal t)
624 {
625 const qreal p0 = singleCubicBezier.p0x;
626 const qreal p1 = singleCubicBezier.p1x;
627 const qreal p2 = singleCubicBezier.p2x;
628 const qreal p3 = singleCubicBezier.p3x;
629
630 const qreal s = 1 - t;
631
632 const qreal s_squared = s * s;
633 const qreal t_squared = t * t;
634
635 const qreal s_cubic = s_squared * s;
636 const qreal t_cubic = t_squared * t;
637
638 return s_cubic * p0 + 3 * s_squared * t * p1 + 3 * s * t_squared * p2 + t_cubic * p3;
639 }
640
641 qreal static inline evaluateDerivateForX(const SingleCubicBezier &singleCubicBezier, qreal t)
642 {
643 const qreal p0 = singleCubicBezier.p0x;
644 const qreal p1 = singleCubicBezier.p1x;
645 const qreal p2 = singleCubicBezier.p2x;
646 const qreal p3 = singleCubicBezier.p3x;
647
648 const qreal t_squared = t * t;
649
650 return -3*p0 + 3*p1 + 6*p0*t - 12*p1*t + 6*p2*t + 3*p3*t_squared - 3*p0*t_squared + 9*p1*t_squared - 9*p2*t_squared;
651 }
652
653 qreal static inline _cbrt(qreal d)
654 {
655 qreal sign = 1;
656 if (d < 0)
657 sign = -1;
658 d = d * sign;
659
660 qreal t = _fast_cbrt(d);
661
662 //one step of Halley's Method to get a better approximation
663 const qreal t_cubic = t * t * t;
664 const qreal f = t_cubic + t_cubic + d;
665 if (f != qreal(0.0))
666 t = t * (t_cubic + d + d) / f;
667
668 //another step
669 /*qreal t_i = t;
670 t_i_cubic = pow(t_i, 3);
671 t = t_i * (t_i_cubic + d + d) / (t_i_cubic + t_i_cubic + d);*/
672
673 return t * sign;
674 }
675
676 float static inline _fast_cbrt(float x)
677 {
678 union {
679 float f;
680 quint32 i;
681 } ux;
682
683 const unsigned int B1 = 709921077;
684
685 ux.f = x;
686 ux.i = (ux.i / 3 + B1);
687
688 return ux.f;
689 }
690
691 double static inline _fast_cbrt(double d)
692 {
693 union {
694 double d;
695 quint32 pt[2];
696 } ut, ux;
697
698 const unsigned int B1 = 715094163;
699
700#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
701 const int h0 = 1;
702#else
703 const int h0 = 0;
704#endif
705 ut.d = 0.0;
706 ux.d = d;
707
708 quint32 hx = ux.pt[h0]; //high word of d
709 ut.pt[h0] = hx / 3 + B1;
710
711 return ut.d;
712 }
713
714 qreal static inline _acos(qreal x)
715 {
716 return std::sqrt(1-x)*(1.5707963267948966192313216916398f + x*(-0.213300989f + x*(0.077980478f + x*-0.02164095f)));
717 }
718
719 qreal static inline _cos(qreal x) //super fast _cos
720 {
721 const qreal pi_times2 = 2 * M_PI;
722 const qreal pi_neg = -1 * M_PI;
723 const qreal pi_by2 = M_PI / 2.0;
724
725 x += pi_by2; //the polynom is for sin
726
727 if (x < pi_neg)
728 x += pi_times2;
729 else if (x > M_PI)
730 x -= pi_times2;
731
732 const qreal a = 0.405284735;
733 const qreal b = 1.27323954;
734
735 const qreal x_squared = x * x;
736
737 if (x < 0) {
738 qreal cos = b * x + a * x_squared;
739
740 if (cos < 0)
741 return 0.225 * (cos * -1 * cos - cos) + cos;
742 return 0.225 * (cos * cos - cos) + cos;
743 } //else
744
745 qreal cos = b * x - a * x_squared;
746
747 if (cos < 0)
748 return 0.225 * (cos * 1 * -cos - cos) + cos;
749 return 0.225 * (cos * cos - cos) + cos;
750 }
751
752 bool static inline inRange(qreal f)
753 {
754 return (f >= -0.01 && f <= 1.01);
755 }
756
757 void static inline cosacos(qreal x, qreal &s1, qreal &s2, qreal &s3 )
758 {
759 //This function has no proper algebraic representation in real numbers.
760 //We use approximations instead
761
762 const qreal x_squared = x * x;
763 const qreal x_plus_one_sqrt = qSqrt(1.0 + x);
764 const qreal one_minus_x_sqrt = qSqrt(1.0 - x);
765
766 //cos(acos(x) / 3)
767 //s1 = _cos(_acos(x) / 3);
768 s1 = 0.463614 - 0.0347815 * x + 0.00218245 * x_squared + 0.402421 * x_plus_one_sqrt;
769
770 //cos(acos((x) - M_PI) / 3)
771 //s3 = _cos((_acos(x) - M_PI) / 3);
772 s3 = 0.463614 + 0.402421 * one_minus_x_sqrt + 0.0347815 * x + 0.00218245 * x_squared;
773
774 //cos((acos(x) + M_PI) / 3)
775 //s2 = _cos((_acos(x) + M_PI) / 3);
776 s2 = -0.401644 * one_minus_x_sqrt - 0.0686804 * x + 0.401644 * x_plus_one_sqrt;
777 }
778
779 qreal static inline singleRealSolutionForCubic(qreal a, qreal b, qreal c)
780 {
781 //returns the real solutiuon in [0..1]
782 //We use the Cardano formula
783
784 //substituiton: x = z - a/3
785 // z^3+pz+q=0
786
787 if (c < 0.000001 && c > -0.000001)
788 return 0;
789
790 const qreal a_by3 = a / 3.0;
791
792 const qreal a_cubic = a * a * a;
793
794 const qreal p = b - a * a_by3;
795 const qreal q = 2.0 * a_cubic / 27.0 - a * b / 3.0 + c;
796
797 const qreal q_squared = q * q;
798 const qreal p_cubic = p * p * p;
799 const qreal D = 0.25 * q_squared + p_cubic / 27.0;
800
801 if (D >= 0) {
802 const qreal D_sqrt = qSqrt(D);
803 qreal u = _cbrt(-q * 0.5 + D_sqrt);
804 qreal v = _cbrt(-q * 0.5 - D_sqrt);
805 qreal z1 = u + v;
806
807 qreal t1 = z1 - a_by3;
808
809 if (inRange(t1))
810 return t1;
811 qreal z2 = -1 * u;
812 qreal t2 = z2 - a_by3;
813 return t2;
814 }
815
816 //casus irreducibilis
817 const qreal p_minus_sqrt = qSqrt(-p);
818
819 //const qreal f = sqrt(4.0 / 3.0 * -p);
820 const qreal f = qSqrt(4.0 / 3.0) * p_minus_sqrt;
821
822 //const qreal sqrtP = sqrt(27.0 / -p_cubic);
823 const qreal sqrtP = -3.0*qSqrt(3.0) / (p_minus_sqrt * p);
824
825
826 const qreal g = -q * 0.5 * sqrtP;
827
828 qreal s1;
829 qreal s2;
830 qreal s3;
831
832 cosacos(g, s1, s2, s3);
833
834 qreal z1 = -1 * f * s2;
835 qreal t1 = z1 - a_by3;
836 if (inRange(t1))
837 return t1;
838
839 qreal z2 = f * s1;
840 qreal t2 = z2 - a_by3;
841 if (inRange(t2))
842 return t2;
843
844 qreal z3 = -1 * f * s3;
845 qreal t3 = z3 - a_by3;
846 return t3;
847 }
848
849 bool static inline almostZero(qreal value)
850 {
851 // 1e-3 might seem excessively fuzzy, but any smaller value will make the
852 // factors a, b, and c large enough to knock out the cubic solver.
853 return value > -1e-3 && value < 1e-3;
854 }
855
856 qreal static inline findTForX(const SingleCubicBezier &singleCubicBezier, qreal x)
857 {
858 const qreal p0 = singleCubicBezier.p0x;
859 const qreal p1 = singleCubicBezier.p1x;
860 const qreal p2 = singleCubicBezier.p2x;
861 const qreal p3 = singleCubicBezier.p3x;
862
863 const qreal factorT3 = p3 - p0 + 3 * p1 - 3 * p2;
864 const qreal factorT2 = 3 * p0 - 6 * p1 + 3 * p2;
865 const qreal factorT1 = -3 * p0 + 3 * p1;
866 const qreal factorT0 = p0 - x;
867
868 // Cases for quadratic, linear and invalid equations
869 if (almostZero(factorT3)) {
870 if (almostZero(factorT2)) {
871 if (almostZero(factorT1))
872 return 0.0;
873
874 return -factorT0 / factorT1;
875 }
876 const qreal discriminant = factorT1 * factorT1 - 4.0 * factorT2 * factorT0;
877 if (discriminant < 0.0)
878 return 0.0;
879
880 if (discriminant == 0.0)
881 return -factorT1 / (2.0 * factorT2);
882
883 const qreal solution1 = (-factorT1 + std::sqrt(discriminant)) / (2.0 * factorT2);
884 if (solution1 >= 0.0 && solution1 <= 1.0)
885 return solution1;
886
887 const qreal solution2 = (-factorT1 - std::sqrt(discriminant)) / (2.0 * factorT2);
888 if (solution2 >= 0.0 && solution2 <= 1.0)
889 return solution2;
890
891 return 0.0;
892 }
893
894 const qreal a = factorT2 / factorT3;
895 const qreal b = factorT1 / factorT3;
896 const qreal c = factorT0 / factorT3;
897
898 return singleRealSolutionForCubic(a, b, c);
899
900 //one new iteration to increase numeric stability
901 //return newtonIteration(singleCubicBezier, t, x);
902 }
903};
904
905struct TCBEase : public BezierEase
906{
910
911 qreal value(qreal x) override
912 {
913 Q_ASSERT(_bezierCurves.size() % 3 == 0);
914
915 if (_bezierCurves.isEmpty()) {
916 qWarning("QEasingCurve: Invalid tcb curve");
917 return x;
918 }
919
920 return BezierEase::value(x);
921 }
922
923 QEasingCurveFunction *copy() const override
924 {
925 return new TCBEase{*this};
926 }
927};
928
930{
932 : QEasingCurveFunction(type, qreal(0.3), qreal(1.0))
933 { }
934
935 QEasingCurveFunction *copy() const override
936 {
937 ElasticEase *rv = new ElasticEase(_t);
938 rv->_p = _p;
939 rv->_a = _a;
940 rv->_bezierCurves = _bezierCurves;
942 return rv;
943 }
944
945 qreal value(qreal t) override
946 {
947 qreal p = (_p < 0) ? qreal(0.3) : _p;
948 qreal a = (_a < 0) ? qreal(1.0) : _a;
949 switch (_t) {
950 case QEasingCurve::InElastic:
951 return easeInElastic(t, a, p);
952 case QEasingCurve::OutElastic:
953 return easeOutElastic(t, a, p);
954 case QEasingCurve::InOutElastic:
955 return easeInOutElastic(t, a, p);
956 case QEasingCurve::OutInElastic:
957 return easeOutInElastic(t, a, p);
958 default:
959 return t;
960 }
961 }
962};
963
965{
967 : QEasingCurveFunction(type, qreal(0.3), qreal(1.0))
968 { }
969
970 QEasingCurveFunction *copy() const override
971 {
972 BounceEase *rv = new BounceEase(_t);
973 rv->_a = _a;
974 rv->_bezierCurves = _bezierCurves;
976 return rv;
977 }
978
979 qreal value(qreal t) override
980 {
981 qreal a = (_a < 0) ? qreal(1.0) : _a;
982 switch (_t) {
983 case QEasingCurve::InBounce:
984 return easeInBounce(t, a);
985 case QEasingCurve::OutBounce:
986 return easeOutBounce(t, a);
987 case QEasingCurve::InOutBounce:
988 return easeInOutBounce(t, a);
989 case QEasingCurve::OutInBounce:
990 return easeOutInBounce(t, a);
991 default:
992 return t;
993 }
994 }
995};
996
998{
1000 : QEasingCurveFunction(type, qreal(0.3), qreal(1.0), qreal(1.70158))
1001 { }
1002
1003 QEasingCurveFunction *copy() const override
1004 {
1005 BackEase *rv = new BackEase(_t);
1006 rv->_o = _o;
1007 rv->_bezierCurves = _bezierCurves;
1009 return rv;
1010 }
1011
1012 qreal value(qreal t) override
1013 {
1014 // The *Back() functions are not always precise on the endpoints, so handle explicitly
1015 if (!(t > 0))
1016 return 0;
1017 if (!(t < 1))
1018 return 1;
1019 qreal o = (_o < 0) ? qreal(1.70158) : _o;
1020 switch (_t) {
1021 case QEasingCurve::InBack:
1022 return easeInBack(t, o);
1023 case QEasingCurve::OutBack:
1024 return easeOutBack(t, o);
1025 case QEasingCurve::InOutBack:
1026 return easeInOutBack(t, o);
1027 case QEasingCurve::OutInBack:
1028 return easeOutInBack(t, o);
1029 default:
1030 return t;
1031 }
1032 }
1033};
1034
1035static QEasingCurve::EasingFunction curveToFunc(QEasingCurve::Type curve)
1036{
1037 switch (curve) {
1038 case QEasingCurve::Linear:
1039 return &easeNone;
1040 case QEasingCurve::InQuad:
1041 return &easeInQuad;
1042 case QEasingCurve::OutQuad:
1043 return &easeOutQuad;
1044 case QEasingCurve::InOutQuad:
1045 return &easeInOutQuad;
1046 case QEasingCurve::OutInQuad:
1047 return &easeOutInQuad;
1048 case QEasingCurve::InCubic:
1049 return &easeInCubic;
1050 case QEasingCurve::OutCubic:
1051 return &easeOutCubic;
1052 case QEasingCurve::InOutCubic:
1053 return &easeInOutCubic;
1054 case QEasingCurve::OutInCubic:
1055 return &easeOutInCubic;
1056 case QEasingCurve::InQuart:
1057 return &easeInQuart;
1058 case QEasingCurve::OutQuart:
1059 return &easeOutQuart;
1060 case QEasingCurve::InOutQuart:
1061 return &easeInOutQuart;
1062 case QEasingCurve::OutInQuart:
1063 return &easeOutInQuart;
1064 case QEasingCurve::InQuint:
1065 return &easeInQuint;
1066 case QEasingCurve::OutQuint:
1067 return &easeOutQuint;
1068 case QEasingCurve::InOutQuint:
1069 return &easeInOutQuint;
1070 case QEasingCurve::OutInQuint:
1071 return &easeOutInQuint;
1072 case QEasingCurve::InSine:
1073 return &easeInSine;
1074 case QEasingCurve::OutSine:
1075 return &easeOutSine;
1076 case QEasingCurve::InOutSine:
1077 return &easeInOutSine;
1078 case QEasingCurve::OutInSine:
1079 return &easeOutInSine;
1080 case QEasingCurve::InExpo:
1081 return &easeInExpo;
1082 case QEasingCurve::OutExpo:
1083 return &easeOutExpo;
1084 case QEasingCurve::InOutExpo:
1085 return &easeInOutExpo;
1086 case QEasingCurve::OutInExpo:
1087 return &easeOutInExpo;
1088 case QEasingCurve::InCirc:
1089 return &easeInCirc;
1090 case QEasingCurve::OutCirc:
1091 return &easeOutCirc;
1092 case QEasingCurve::InOutCirc:
1093 return &easeInOutCirc;
1094 case QEasingCurve::OutInCirc:
1095 return &easeOutInCirc;
1096 // Internal - needed for QTimeLine backward-compatibility:
1097 case QEasingCurve::InCurve:
1098 return &easeInCurve;
1099 case QEasingCurve::OutCurve:
1100 return &easeOutCurve;
1101 case QEasingCurve::SineCurve:
1102 return &easeSineCurve;
1103 case QEasingCurve::CosineCurve:
1104 return &easeCosineCurve;
1105 default:
1106 return nullptr;
1107 };
1108}
1109
1110static QEasingCurveFunction *curveToFunctionObject(QEasingCurve::Type type)
1111{
1112 switch (type) {
1113 case QEasingCurve::InElastic:
1114 case QEasingCurve::OutElastic:
1115 case QEasingCurve::InOutElastic:
1116 case QEasingCurve::OutInElastic:
1117 return new ElasticEase(type);
1118 case QEasingCurve::OutBounce:
1119 case QEasingCurve::InBounce:
1120 case QEasingCurve::OutInBounce:
1121 case QEasingCurve::InOutBounce:
1122 return new BounceEase(type);
1123 case QEasingCurve::InBack:
1124 case QEasingCurve::OutBack:
1125 case QEasingCurve::InOutBack:
1126 case QEasingCurve::OutInBack:
1127 return new BackEase(type);
1128 case QEasingCurve::BezierSpline:
1129 return new BezierEase;
1130 case QEasingCurve::TCBSpline:
1131 return new TCBEase;
1132 default:
1133 return new QEasingCurveFunction(type, qreal(0.3), qreal(1.0), qreal(1.70158));
1134 }
1135
1136 return nullptr;
1137}
1138
1139/*!
1140 \fn QEasingCurve::QEasingCurve(QEasingCurve &&other)
1141
1142 Move-constructs a QEasingCurve instance, making it point at the same
1143 object that \a other was pointing to.
1144
1145 \since 5.2
1146*/
1147
1148/*!
1149 Constructs an easing curve of the given \a type.
1150 */
1151QEasingCurve::QEasingCurve(Type type)
1152 : d_ptr(new QEasingCurvePrivate)
1153{
1154 setType(type);
1155}
1156
1157/*!
1158 Construct a copy of \a other.
1159 */
1160QEasingCurve::QEasingCurve(const QEasingCurve &other)
1161 : d_ptr(new QEasingCurvePrivate(*other.d_ptr))
1162{
1163 // ### non-atomic, requires malloc on shallow copy
1164}
1165
1166/*!
1167 Destructor.
1168 */
1169
1170QEasingCurve::~QEasingCurve()
1171{
1172 delete d_ptr;
1173}
1174
1175/*!
1176 \fn QEasingCurve &QEasingCurve::operator=(const QEasingCurve &other)
1177 Copy \a other.
1178 */
1179
1180/*!
1181 \fn QEasingCurve &QEasingCurve::operator=(QEasingCurve &&other)
1182
1183 Move-assigns \a other to this QEasingCurve instance.
1184
1185 \since 5.2
1186*/
1187
1188/*!
1189 \fn void QEasingCurve::swap(QEasingCurve &other)
1190 \since 5.0
1191 \memberswap{curve}
1192*/
1193
1194/*!
1195 \fn bool QEasingCurve::operator==(const QEasingCurve &lhs, const QEasingCurve &rhs)
1196
1197 Compares easing curve \a lhs with \a rhs and returns \c true if they are
1198 equal; otherwise returns \c false.
1199 It will also compare the properties of the curves.
1200 */
1201bool comparesEqual(const QEasingCurve &lhs, const QEasingCurve &rhs)
1202{
1203 bool res = lhs.d_ptr->func == rhs.d_ptr->func
1204 && lhs.d_ptr->type == rhs.d_ptr->type;
1205 if (res) {
1206 if (lhs.d_ptr->config && rhs.d_ptr->config) {
1207 // catch the config content
1208 res = lhs.d_ptr->config->operator==(*(rhs.d_ptr->config));
1209
1210 } else if (lhs.d_ptr->config || rhs.d_ptr->config) {
1211 // one one has a config object, which could contain default values
1212 res = qFuzzyCompare(lhs.amplitude(), rhs.amplitude())
1213 && qFuzzyCompare(lhs.period(), rhs.period())
1214 && qFuzzyCompare(lhs.overshoot(), rhs.overshoot());
1215 }
1216 }
1217 return res;
1218}
1219
1220/*!
1221 \fn bool QEasingCurve::operator!=(const QEasingCurve &lhs, const QEasingCurve &rhs)
1222
1223 Compares easing curve \a lhs with \a rhs and returns \c true if they are
1224 not equal; otherwise returns \c false.
1225 It will also compare the properties of the curves.
1226
1227 \sa operator==()
1228*/
1229
1230/*!
1231 Returns the amplitude. This is not applicable for all curve types.
1232 It is only applicable for bounce and elastic curves (curves of type()
1233 QEasingCurve::InBounce, QEasingCurve::OutBounce, QEasingCurve::InOutBounce,
1234 QEasingCurve::OutInBounce, QEasingCurve::InElastic, QEasingCurve::OutElastic,
1235 QEasingCurve::InOutElastic or QEasingCurve::OutInElastic).
1236 */
1237qreal QEasingCurve::amplitude() const
1238{
1239 return d_ptr->config ? d_ptr->config->_a : qreal(1.0);
1240}
1241
1242/*!
1243 Sets the amplitude to \a amplitude.
1244
1245 This will set the amplitude of the bounce or the amplitude of the
1246 elastic "spring" effect. The higher the number, the higher the amplitude.
1247 \sa amplitude()
1248*/
1249void QEasingCurve::setAmplitude(qreal amplitude)
1250{
1251 if (!d_ptr->config)
1252 d_ptr->config = curveToFunctionObject(d_ptr->type);
1253 d_ptr->config->_a = amplitude;
1254}
1255
1256/*!
1257 Returns the period. This is not applicable for all curve types.
1258 It is only applicable if type() is QEasingCurve::InElastic, QEasingCurve::OutElastic,
1259 QEasingCurve::InOutElastic or QEasingCurve::OutInElastic.
1260 */
1261qreal QEasingCurve::period() const
1262{
1263 return d_ptr->config ? d_ptr->config->_p : qreal(0.3);
1264}
1265
1266/*!
1267 Sets the period to \a period.
1268 Setting a small period value will give a high frequency of the curve. A
1269 large period will give it a small frequency.
1270
1271 \sa period()
1272*/
1273void QEasingCurve::setPeriod(qreal period)
1274{
1275 if (!d_ptr->config)
1276 d_ptr->config = curveToFunctionObject(d_ptr->type);
1277 d_ptr->config->_p = period;
1278}
1279
1280/*!
1281 Returns the overshoot. This is not applicable for all curve types.
1282 It is only applicable if type() is QEasingCurve::InBack, QEasingCurve::OutBack,
1283 QEasingCurve::InOutBack or QEasingCurve::OutInBack.
1284 */
1285qreal QEasingCurve::overshoot() const
1286{
1287 return d_ptr->config ? d_ptr->config->_o : qreal(1.70158);
1288}
1289
1290/*!
1291 Sets the overshoot to \a overshoot.
1292
1293 0 produces no overshoot, and the default value of 1.70158 produces an overshoot of 10 percent.
1294
1295 \sa overshoot()
1296*/
1297void QEasingCurve::setOvershoot(qreal overshoot)
1298{
1299 if (!d_ptr->config)
1300 d_ptr->config = curveToFunctionObject(d_ptr->type);
1301 d_ptr->config->_o = overshoot;
1302}
1303
1304/*!
1305 Adds a segment of a cubic bezier spline to define a custom easing curve.
1306 It is only applicable if type() is QEasingCurve::BezierSpline.
1307 Note that the spline implicitly starts at (0.0, 0.0) and has to end at (1.0, 1.0) to
1308 be a valid easing curve.
1309 \a c1 and \a c2 are the control points used for drawing the curve.
1310 \a endPoint is the endpoint of the curve.
1311 */
1312void QEasingCurve::addCubicBezierSegment(const QPointF & c1, const QPointF & c2, const QPointF & endPoint)
1313{
1314 if (!d_ptr->config)
1315 d_ptr->config = curveToFunctionObject(d_ptr->type);
1316 d_ptr->config->_bezierCurves << c1 << c2 << endPoint;
1317}
1318
1319QList<QPointF> static inline tcbToBezier(const TCBPoints &tcbPoints)
1320{
1321 const int count = tcbPoints.size();
1322 QList<QPointF> bezierPoints;
1323 bezierPoints.reserve(3 * (count - 1));
1324
1325 for (int i = 1; i < count; i++) {
1326 const qreal t_0 = tcbPoints.at(i - 1)._t;
1327 const qreal c_0 = tcbPoints.at(i - 1)._c;
1328 qreal b_0 = -1;
1329
1330 qreal const t_1 = tcbPoints.at(i)._t;
1331 qreal const c_1 = tcbPoints.at(i)._c;
1332 qreal b_1 = 1;
1333
1334 QPointF c_minusOne; //P1 last segment - not available for the first point
1335 const QPointF c0(tcbPoints.at(i - 1)._point); //P0 Hermite/TBC
1336 const QPointF c3(tcbPoints.at(i)._point); //P1 Hermite/TBC
1337 QPointF c4; //P0 next segment - not available for the last point
1338
1339 if (i > 1) { //first point no left tangent
1340 c_minusOne = tcbPoints.at(i - 2)._point;
1341 b_0 = tcbPoints.at(i - 1)._b;
1342 }
1343
1344 if (i < (count - 1)) { //last point no right tangent
1345 c4 = tcbPoints.at(i + 1)._point;
1346 b_1 = tcbPoints.at(i)._b;
1347 }
1348
1349 const qreal dx_0 = 0.5 * (1-t_0) * ((1 + b_0) * (1 + c_0) * (c0.x() - c_minusOne.x()) + (1- b_0) * (1 - c_0) * (c3.x() - c0.x()));
1350 const qreal dy_0 = 0.5 * (1-t_0) * ((1 + b_0) * (1 + c_0) * (c0.y() - c_minusOne.y()) + (1- b_0) * (1 - c_0) * (c3.y() - c0.y()));
1351
1352 const qreal dx_1 = 0.5 * (1-t_1) * ((1 + b_1) * (1 - c_1) * (c3.x() - c0.x()) + (1 - b_1) * (1 + c_1) * (c4.x() - c3.x()));
1353 const qreal dy_1 = 0.5 * (1-t_1) * ((1 + b_1) * (1 - c_1) * (c3.y() - c0.y()) + (1 - b_1) * (1 + c_1) * (c4.y() - c3.y()));
1354
1355 const QPointF d_0 = QPointF(dx_0, dy_0);
1356 const QPointF d_1 = QPointF(dx_1, dy_1);
1357
1358 QPointF c1 = (3 * c0 + d_0) / 3;
1359 QPointF c2 = (3 * c3 - d_1) / 3;
1360 bezierPoints << c1 << c2 << c3;
1361 }
1362 return bezierPoints;
1363}
1364
1365/*!
1366 Adds a segment of a TCB bezier spline to define a custom easing curve.
1367 It is only applicable if type() is QEasingCurve::TCBSpline.
1368 The spline has to start explicitly at (0.0, 0.0) and has to end at (1.0, 1.0) to
1369 be a valid easing curve.
1370 The tension \a t changes the length of the tangent vector.
1371 The continuity \a c changes the sharpness in change between the tangents.
1372 The bias \a b changes the direction of the tangent vector.
1373 \a nextPoint is the sample position.
1374 All three parameters are valid between -1 and 1 and define the
1375 tangent of the control point.
1376 If all three parameters are 0 the resulting spline is a Catmull-Rom spline.
1377 The begin and endpoint always have a bias of -1 and 1, since the outer tangent is not defined.
1378 */
1379void QEasingCurve::addTCBSegment(const QPointF &nextPoint, qreal t, qreal c, qreal b)
1380{
1381 if (!d_ptr->config)
1382 d_ptr->config = curveToFunctionObject(d_ptr->type);
1383
1384 d_ptr->config->_tcbPoints.append(TCBPoint(nextPoint, t, c, b));
1385
1386 if (nextPoint == QPointF(1.0, 1.0)) {
1387 d_ptr->config->_bezierCurves = tcbToBezier(d_ptr->config->_tcbPoints);
1388 d_ptr->config->_tcbPoints.clear();
1389 }
1390
1391}
1392
1393/*!
1394 \since 5.0
1395
1396 Returns the cubicBezierSpline that defines a custom easing curve.
1397 If the easing curve does not have a custom bezier easing curve the list
1398 is empty.
1399*/
1400QList<QPointF> QEasingCurve::toCubicSpline() const
1401{
1402 return d_ptr->config ? d_ptr->config->_bezierCurves : QList<QPointF>();
1403}
1404
1405/*!
1406 Returns the type of the easing curve.
1407*/
1408QEasingCurve::Type QEasingCurve::type() const
1409{
1410 return d_ptr->type;
1411}
1412
1413void QEasingCurvePrivate::setType_helper(QEasingCurve::Type newType)
1414{
1415 qreal amp = -1.0;
1416 qreal period = -1.0;
1417 qreal overshoot = -1.0;
1418 QList<QPointF> bezierCurves;
1419 QList<TCBPoint> tcbPoints;
1420
1421 if (config) {
1422 amp = config->_a;
1423 period = config->_p;
1424 overshoot = config->_o;
1425 bezierCurves = std::move(config->_bezierCurves);
1426 tcbPoints = std::move(config->_tcbPoints);
1427
1428 delete config;
1429 config = nullptr;
1430 }
1431
1432 if (isConfigFunction(newType) || (amp != -1.0) || (period != -1.0) || (overshoot != -1.0) ||
1433 !bezierCurves.isEmpty()) {
1434 config = curveToFunctionObject(newType);
1435 if (amp != -1.0)
1436 config->_a = amp;
1437 if (period != -1.0)
1438 config->_p = period;
1439 if (overshoot != -1.0)
1440 config->_o = overshoot;
1441 config->_bezierCurves = std::move(bezierCurves);
1442 config->_tcbPoints = std::move(tcbPoints);
1443 func = nullptr;
1444 } else if (newType != QEasingCurve::Custom) {
1445 func = curveToFunc(newType);
1446 }
1447 Q_ASSERT((func == nullptr) == (config != nullptr));
1448 type = newType;
1449}
1450
1451/*!
1452 Sets the type of the easing curve to \a type.
1453*/
1454void QEasingCurve::setType(Type type)
1455{
1456 if (d_ptr->type == type)
1457 return;
1458 if (type < Linear || type >= NCurveTypes - 1) {
1459 qWarning("QEasingCurve: Invalid curve type %d", type);
1460 return;
1461 }
1462
1463 d_ptr->setType_helper(type);
1464}
1465
1466/*!
1467 Sets a custom easing curve that is defined by the user in the function \a func.
1468 The signature of the function is qreal myEasingFunction(qreal progress),
1469 where \e progress and the return value are considered to be normalized between 0 and 1.
1470 (In some cases the return value can be outside that range)
1471 After calling this function type() will return QEasingCurve::Custom.
1472 \a func cannot be \nullptr.
1473
1474 \sa customType()
1475 \sa valueForProgress()
1476*/
1477void QEasingCurve::setCustomType(EasingFunction func)
1478{
1479 if (!func) {
1480 qWarning("Function pointer must not be null");
1481 return;
1482 }
1483 d_ptr->func = func;
1484 d_ptr->setType_helper(Custom);
1485}
1486
1487/*!
1488 Returns the function pointer to the custom easing curve.
1489 If type() does not return QEasingCurve::Custom, this function
1490 will return 0.
1491*/
1492QEasingCurve::EasingFunction QEasingCurve::customType() const
1493{
1494 return d_ptr->type == Custom ? d_ptr->func : nullptr;
1495}
1496
1497/*!
1498 Return the effective progress for the easing curve at \a progress.
1499 Whereas \a progress must be between 0 and 1, the returned effective progress
1500 can be outside those bounds. For example, QEasingCurve::InBack will
1501 return negative values in the beginning of the function.
1502 */
1503qreal QEasingCurve::valueForProgress(qreal progress) const
1504{
1505 progress = qBound<qreal>(0, progress, 1);
1506 if (d_ptr->func)
1507 return d_ptr->func(progress);
1508 else if (d_ptr->config)
1509 return d_ptr->config->value(progress);
1510 else
1511 return progress;
1512}
1513
1514#ifndef QT_NO_DEBUG_STREAM
1515QDebug operator<<(QDebug debug, const QEasingCurve &item)
1516{
1517 QDebugStateSaver saver(debug);
1518 debug << "type:" << item.d_ptr->type
1519 << "func:" << reinterpret_cast<const void *>(item.d_ptr->func);
1520 if (item.d_ptr->config) {
1521 debug << QString::fromLatin1("period:%1").arg(item.d_ptr->config->_p, 0, 'f', 20)
1522 << QString::fromLatin1("amp:%1").arg(item.d_ptr->config->_a, 0, 'f', 20)
1523 << QString::fromLatin1("overshoot:%1").arg(item.d_ptr->config->_o, 0, 'f', 20);
1524 }
1525 return debug;
1526}
1527#endif // QT_NO_DEBUG_STREAM
1528
1529#ifndef QT_NO_DATASTREAM
1530/*!
1531 \fn QDataStream &operator<<(QDataStream &stream, const QEasingCurve &easing)
1532 \relates QEasingCurve
1533
1534 Writes the given \a easing curve to the given \a stream and returns a
1535 reference to the stream.
1536
1537 \warning Writing easing curves of QEasingCurve::Custom type
1538 (that is, curves with a custom easing function) is not supported.
1539
1540 \sa {Serializing Qt Data Types}
1541*/
1542
1543QDataStream &operator<<(QDataStream &stream, const QEasingCurve &easing)
1544{
1545 if (easing.d_ptr->type == QEasingCurve::Custom) {
1546 qWarning("QEasingCurve: Cannot serialize an easing curve with a custom easing function");
1547
1548 // Backwards compatibility: stream _something_ out.
1549 // Deliberately choose a curve that uses a config and not a
1550 // easing function. If this curve is deserialized from old
1551 // code, it will ignore the function pointer (cf.
1552 // QTBUG-132575).
1553 static_assert(isConfigFunction(QEasingCurve::InElastic));
1554 stream << QEasingCurve(QEasingCurve::InElastic);
1555 return stream;
1556 }
1557
1558 stream << quint8(easing.d_ptr->type);
1559 // Unused; for backwards compatibility
1560 stream << quint64(0);
1561
1562 bool hasConfig = easing.d_ptr->config;
1563 stream << hasConfig;
1564 if (hasConfig) {
1565 stream << easing.d_ptr->config;
1566 }
1567 return stream;
1568}
1569
1570/*!
1571 \fn QDataStream &operator>>(QDataStream &stream, QEasingCurve &easing)
1572 \relates QEasingCurve
1573
1574 Reads an easing curve from the given \a stream into the given \a
1575 easing curve and returns a reference to the stream.
1576
1577 \sa {Serializing Qt Data Types}
1578*/
1579
1580QDataStream &operator>>(QDataStream &stream, QEasingCurve &easing)
1581{
1582 QEasingCurve::Type type;
1583 quint8 int_type;
1584 stream >> int_type;
1585 type = static_cast<QEasingCurve::Type>(int_type);
1586 if (type == QEasingCurve::Custom) {
1587 qWarning("QEasingCurve: Cannot deserialize an easing curve with a custom easing function");
1588 stream.setStatus(QDataStream::ReadCorruptData);
1589 type = QEasingCurve::Linear;
1590 }
1591 easing.setType(type);
1592
1593 // Unused; for backwards compatibility
1594 [[maybe_unused]] quint64 ptr_func;
1595 stream >> ptr_func;
1596
1597 bool hasConfig;
1598 stream >> hasConfig;
1599 delete easing.d_ptr->config;
1600 easing.d_ptr->config = nullptr;
1601 if (hasConfig) {
1603 stream >> config;
1604 easing.d_ptr->config = config;
1605 }
1606 return stream;
1607}
1608#endif // QT_NO_DATASTREAM
1609
1610QT_END_NAMESPACE
1611
1612#include "moc_qeasingcurve.cpp"
virtual ~QEasingCurveFunction()
bool operator==(const QEasingCurveFunction &other) const
QEasingCurveFunction(QEasingCurve::Type type, qreal period=0.3, qreal amplitude=1.0, qreal overshoot=1.70158)
virtual qreal value(qreal t)
virtual QEasingCurveFunction * copy() const
QList< QPointF > _bezierCurves
\inmodule QtCore\reentrant
Definition qpoint.h:231
static QList< QPointF > tcbToBezier(const TCBPoints &tcbPoints)
static QEasingCurve::EasingFunction curveToFunc(QEasingCurve::Type curve)
Q_DECLARE_TYPEINFO(TCBPoint, Q_PRIMITIVE_TYPE)
static QT_BEGIN_NAMESPACE constexpr bool isConfigFunction(QEasingCurve::Type type)
QDataStream & operator<<(QDataStream &stream, QEasingCurveFunction *func)
QList< TCBPoint > TCBPoints
QDataStream & operator>>(QDataStream &stream, QEasingCurveFunction *func)
QDataStream & operator>>(QDataStream &stream, TCBPoint &point)
static QEasingCurveFunction * curveToFunctionObject(QEasingCurve::Type type)
QDataStream & operator<<(QDataStream &stream, const TCBPoint &point)
QDebug operator<<(QDebug dbg, const QFileInfo &fi)
bool comparesEqual(const QFileInfo &lhs, const QFileInfo &rhs)
#define M_PI
Definition qmath.h:200
QDataStream & operator<<(QDataStream &stream, const QImage &image)
[0]
Definition qimage.cpp:4006
QDataStream & operator>>(QDataStream &stream, QImage &image)
Definition qimage.cpp:4032
QEasingCurveFunction * copy() const override
qreal value(qreal t) override
BackEase(QEasingCurve::Type type)
static float _fast_cbrt(float x)
static qreal evaluateDerivateForX(const SingleCubicBezier &singleCubicBezier, qreal t)
static qreal evaluateForX(const SingleCubicBezier &singleCubicBezier, qreal t)
static qreal _acos(qreal x)
static void cosacos(qreal x, qreal &s1, qreal &s2, qreal &s3)
static qreal _cos(qreal x)
static qreal _cbrt(qreal d)
static qreal newtonIteration(const SingleCubicBezier &singleCubicBezier, qreal t, qreal x)
static qreal evaluateSegmentForY(const SingleCubicBezier &singleCubicBezier, qreal t)
QList< SingleCubicBezier > _curves
static qreal singleRealSolutionForCubic(qreal a, qreal b, qreal c)
qreal value(qreal x) override
QEasingCurveFunction * copy() const override
void getBezierSegment(SingleCubicBezier *&singleCubicBezier, qreal x)
static qreal findTForX(const SingleCubicBezier &singleCubicBezier, qreal x)
BezierEase(QEasingCurve::Type type=QEasingCurve::BezierSpline)
QList< qreal > _intervals
static double _fast_cbrt(double d)
static bool inRange(qreal f)
static bool almostZero(qreal value)
BounceEase(QEasingCurve::Type type)
QEasingCurveFunction * copy() const override
qreal value(qreal t) override
qreal value(qreal t) override
ElasticEase(QEasingCurve::Type type)
QEasingCurveFunction * copy() const override
QEasingCurveFunction * copy() const override
qreal value(qreal x) override
bool operator==(const TCBPoint &other) const
TCBPoint(QPointF point, qreal t, qreal c, qreal b)
QPointF _point