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