Qt 6.x
The Qt SDK
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
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
280{
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) &&
303 }
304};
306
308{
309 stream << point._point
310 << point._t
311 << point._c
312 << point._b;
313 return stream;
314}
315
317{
318 stream >> point._point
319 >> point._t
320 >> point._c
321 >> point._b;
322 return stream;
323}
324
326
328{
329public:
331 qreal overshoot = 1.70158)
332 : _t(type), _p(period), _a(amplitude), _o(overshoot)
333 { }
335 virtual qreal value(qreal t);
336 virtual QEasingCurveFunction *copy() const;
337 bool operator==(const QEasingCurveFunction &other) const;
338
345
346};
347
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
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
377
379{
381 return func(t);
382}
383
385{
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
403#include "../../3rdparty/easing/easing.cpp"
405
407{
408public:
412 func(&easeNone)
413 { }
415 : type(other.type),
418 { }
421
425};
426
428{
434 };
435
439 bool _init;
440 bool _valid;
441
444 { }
445
446 void init()
447 {
448 if (_bezierCurves.constLast() == QPointF(1.0, 1.0)) {
449 _init = true;
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;
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
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
858
859 //one new iteration to increase numeric stability
860 //return newtonIteration(singleCubicBezier, t, x);
861 }
862};
863
864struct TCBEase : public BezierEase
865{
867 : BezierEase(QEasingCurve::TCBSpline)
868 { }
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{
891 : QEasingCurveFunction(type, qreal(0.3), qreal(1.0))
892 { }
893
894 QEasingCurveFunction *copy() const override
895 {
896 ElasticEase *rv = new ElasticEase(_t);
897 rv->_p = _p;
898 rv->_a = _a;
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) {
910 return easeInElastic(t, a, p);
912 return easeOutElastic(t, a, p);
914 return easeInOutElastic(t, a, p);
916 return easeOutInElastic(t, a, p);
917 default:
918 return t;
919 }
920 }
921};
922
924{
926 : QEasingCurveFunction(type, qreal(0.3), qreal(1.0))
927 { }
928
929 QEasingCurveFunction *copy() const override
930 {
931 BounceEase *rv = new BounceEase(_t);
932 rv->_a = _a;
935 return rv;
936 }
937
938 qreal value(qreal t) override
939 {
940 qreal a = (_a < 0) ? qreal(1.0) : _a;
941 switch (_t) {
943 return easeInBounce(t, a);
945 return easeOutBounce(t, a);
947 return easeInOutBounce(t, a);
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;
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) {
981 return easeInBack(t, o);
983 return easeOutBack(t, o);
985 return easeInOutBack(t, o);
987 return easeOutInBack(t, o);
988 default:
989 return t;
990 }
991 }
992};
993
995{
996 switch (curve) {
998 return &easeNone;
1000 return &easeInQuad;
1002 return &easeOutQuad;
1004 return &easeInOutQuad;
1006 return &easeOutInQuad;
1008 return &easeInCubic;
1010 return &easeOutCubic;
1012 return &easeInOutCubic;
1014 return &easeOutInCubic;
1016 return &easeInQuart;
1018 return &easeOutQuart;
1020 return &easeInOutQuart;
1022 return &easeOutInQuart;
1024 return &easeInQuint;
1026 return &easeOutQuint;
1028 return &easeInOutQuint;
1030 return &easeOutInQuint;
1032 return &easeInSine;
1034 return &easeOutSine;
1036 return &easeInOutSine;
1038 return &easeOutInSine;
1040 return &easeInExpo;
1042 return &easeOutExpo;
1044 return &easeInOutExpo;
1046 return &easeOutInExpo;
1048 return &easeInCirc;
1050 return &easeOutCirc;
1052 return &easeInOutCirc;
1054 return &easeOutInCirc;
1055 // Internal - needed for QTimeLine backward-compatibility:
1057 return &easeInCurve;
1059 return &easeOutCurve;
1061 return &easeSineCurve;
1063 return &easeCosineCurve;
1064 default:
1065 return nullptr;
1066 };
1067}
1068
1070{
1071 switch (type) {
1076 return new ElasticEase(type);
1081 return new BounceEase(type);
1086 return new BackEase(type);
1088 return new BezierEase;
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
1111 : d_ptr(new QEasingCurvePrivate)
1112{
1113 setType(type);
1114}
1115
1120 : d_ptr(new QEasingCurvePrivate(*other.d_ptr))
1121{
1122 // ### non-atomic, requires malloc on shallow copy
1123}
1124
1130{
1131 delete d_ptr;
1132}
1133
1160{
1161 bool res = d_ptr->func == other.d_ptr->func
1162 && d_ptr->type == other.d_ptr->type;
1163 if (res) {
1164 if (d_ptr->config && other.d_ptr->config) {
1165 // catch the config content
1166 res = d_ptr->config->operator==(*(other.d_ptr->config));
1167
1168 } else if (d_ptr->config || other.d_ptr->config) {
1169 // one one has a config object, which could contain default values
1170 res = qFuzzyCompare(amplitude(), other.amplitude())
1171 && qFuzzyCompare(period(), other.period())
1172 && qFuzzyCompare(overshoot(), other.overshoot());
1173 }
1174 }
1175 return res;
1176}
1177
1194{
1195 return d_ptr->config ? d_ptr->config->_a : qreal(1.0);
1196}
1197
1206{
1207 if (!d_ptr->config)
1208 d_ptr->config = curveToFunctionObject(d_ptr->type);
1209 d_ptr->config->_a = amplitude;
1210}
1211
1218{
1219 return d_ptr->config ? d_ptr->config->_p : qreal(0.3);
1220}
1221
1230{
1231 if (!d_ptr->config)
1232 d_ptr->config = curveToFunctionObject(d_ptr->type);
1233 d_ptr->config->_p = period;
1234}
1235
1242{
1243 return d_ptr->config ? d_ptr->config->_o : qreal(1.70158);
1244}
1245
1254{
1255 if (!d_ptr->config)
1256 d_ptr->config = curveToFunctionObject(d_ptr->type);
1257 d_ptr->config->_o = overshoot;
1258}
1259
1268void QEasingCurve::addCubicBezierSegment(const QPointF & c1, const QPointF & c2, const QPointF & endPoint)
1269{
1270 if (!d_ptr->config)
1271 d_ptr->config = curveToFunctionObject(d_ptr->type);
1272 d_ptr->config->_bezierCurves << c1 << c2 << endPoint;
1273}
1274
1275QList<QPointF> static inline tcbToBezier(const TCBPoints &tcbPoints)
1276{
1277 const int count = tcbPoints.size();
1278 QList<QPointF> bezierPoints;
1279 bezierPoints.reserve(3 * (count - 1));
1280
1281 for (int i = 1; i < count; i++) {
1282 const qreal t_0 = tcbPoints.at(i - 1)._t;
1283 const qreal c_0 = tcbPoints.at(i - 1)._c;
1284 qreal b_0 = -1;
1285
1286 qreal const t_1 = tcbPoints.at(i)._t;
1287 qreal const c_1 = tcbPoints.at(i)._c;
1288 qreal b_1 = 1;
1289
1290 QPointF c_minusOne; //P1 last segment - not available for the first point
1291 const QPointF c0(tcbPoints.at(i - 1)._point); //P0 Hermite/TBC
1292 const QPointF c3(tcbPoints.at(i)._point); //P1 Hermite/TBC
1293 QPointF c4; //P0 next segment - not available for the last point
1294
1295 if (i > 1) { //first point no left tangent
1296 c_minusOne = tcbPoints.at(i - 2)._point;
1297 b_0 = tcbPoints.at(i - 1)._b;
1298 }
1299
1300 if (i < (count - 1)) { //last point no right tangent
1301 c4 = tcbPoints.at(i + 1)._point;
1302 b_1 = tcbPoints.at(i)._b;
1303 }
1304
1305 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()));
1306 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()));
1307
1308 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()));
1309 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()));
1310
1311 const QPointF d_0 = QPointF(dx_0, dy_0);
1312 const QPointF d_1 = QPointF(dx_1, dy_1);
1313
1314 QPointF c1 = (3 * c0 + d_0) / 3;
1315 QPointF c2 = (3 * c3 - d_1) / 3;
1316 bezierPoints << c1 << c2 << c3;
1317 }
1318 return bezierPoints;
1319}
1320
1336{
1337 if (!d_ptr->config)
1338 d_ptr->config = curveToFunctionObject(d_ptr->type);
1339
1340 d_ptr->config->_tcbPoints.append(TCBPoint(nextPoint, t, c, b));
1341
1342 if (nextPoint == QPointF(1.0, 1.0)) {
1344 d_ptr->config->_tcbPoints.clear();
1345 }
1346
1347}
1348
1357{
1358 return d_ptr->config ? d_ptr->config->_bezierCurves : QList<QPointF>();
1359}
1360
1365{
1366 return d_ptr->type;
1367}
1368
1370{
1371 qreal amp = -1.0;
1372 qreal period = -1.0;
1373 qreal overshoot = -1.0;
1374 QList<QPointF> bezierCurves;
1375 QList<TCBPoint> tcbPoints;
1376
1377 if (config) {
1378 amp = config->_a;
1379 period = config->_p;
1380 overshoot = config->_o;
1381 bezierCurves = std::move(config->_bezierCurves);
1382 tcbPoints = std::move(config->_tcbPoints);
1383
1384 delete config;
1385 config = nullptr;
1386 }
1387
1388 if (isConfigFunction(newType) || (amp != -1.0) || (period != -1.0) || (overshoot != -1.0) ||
1389 !bezierCurves.isEmpty()) {
1390 config = curveToFunctionObject(newType);
1391 if (amp != -1.0)
1392 config->_a = amp;
1393 if (period != -1.0)
1394 config->_p = period;
1395 if (overshoot != -1.0)
1396 config->_o = overshoot;
1397 config->_bezierCurves = std::move(bezierCurves);
1398 config->_tcbPoints = std::move(tcbPoints);
1399 func = nullptr;
1400 } else if (newType != QEasingCurve::Custom) {
1401 func = curveToFunc(newType);
1402 }
1403 Q_ASSERT((func == nullptr) == (config != nullptr));
1404 type = newType;
1405}
1406
1411{
1412 if (d_ptr->type == type)
1413 return;
1414 if (type < Linear || type >= NCurveTypes - 1) {
1415 qWarning("QEasingCurve: Invalid curve type %d", type);
1416 return;
1417 }
1418
1419 d_ptr->setType_helper(type);
1420}
1421
1434{
1435 if (!func) {
1436 qWarning("Function pointer must not be null");
1437 return;
1438 }
1439 d_ptr->func = func;
1440 d_ptr->setType_helper(Custom);
1441}
1442
1449{
1450 return d_ptr->type == Custom ? d_ptr->func : nullptr;
1451}
1452
1460{
1461 progress = qBound<qreal>(0, progress, 1);
1462 if (d_ptr->func)
1463 return d_ptr->func(progress);
1464 else if (d_ptr->config)
1465 return d_ptr->config->value(progress);
1466 else
1467 return progress;
1468}
1469
1470#ifndef QT_NO_DEBUG_STREAM
1472{
1473 QDebugStateSaver saver(debug);
1474 debug << "type:" << item.d_ptr->type
1475 << "func:" << reinterpret_cast<const void *>(item.d_ptr->func);
1476 if (item.d_ptr->config) {
1477 debug << QString::fromLatin1("period:%1").arg(item.d_ptr->config->_p, 0, 'f', 20)
1478 << QString::fromLatin1("amp:%1").arg(item.d_ptr->config->_a, 0, 'f', 20)
1479 << QString::fromLatin1("overshoot:%1").arg(item.d_ptr->config->_o, 0, 'f', 20);
1480 }
1481 return debug;
1482}
1483#endif // QT_NO_DEBUG_STREAM
1484
1485#ifndef QT_NO_DATASTREAM
1497{
1498 stream << quint8(easing.d_ptr->type);
1499 stream << quint64(quintptr(easing.d_ptr->func));
1500
1501 bool hasConfig = easing.d_ptr->config;
1502 stream << hasConfig;
1503 if (hasConfig) {
1504 stream << easing.d_ptr->config;
1505 }
1506 return stream;
1507}
1508
1520{
1522 quint8 int_type;
1523 stream >> int_type;
1524 type = static_cast<QEasingCurve::Type>(int_type);
1526
1527 quint64 ptr_func;
1528 stream >> ptr_func;
1530
1531 bool hasConfig;
1532 stream >> hasConfig;
1533 delete easing.d_ptr->config;
1534 easing.d_ptr->config = nullptr;
1535 if (hasConfig) {
1537 stream >> config;
1538 easing.d_ptr->config = config;
1539 }
1540 return stream;
1541}
1542#endif // QT_NO_DATASTREAM
1543
1545
1546#include "moc_qeasingcurve.cpp"
\inmodule QtCore\reentrant
Definition qdatastream.h:30
\inmodule QtCore
\inmodule QtCore
QList< QPointF > _bezierCurves
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
QEasingCurve::Type _t
QEasingCurveFunction * config
QEasingCurve::EasingFunction func
QEasingCurvePrivate(const QEasingCurvePrivate &other)
QEasingCurve::Type type
void setType_helper(QEasingCurve::Type)
\inmodule QtCore
EasingFunction customType() const
Returns the function pointer to the custom easing curve.
~QEasingCurve()
Destructor.
void setAmplitude(qreal amplitude)
Sets the amplitude to amplitude.
bool operator==(const QEasingCurve &other) const
Compare this easing curve with other and returns true if they are equal.
void setPeriod(qreal period)
Sets the period to period.
qreal period() const
Returns the period.
Type type() const
Returns the type of the easing curve.
qreal overshoot() const
Returns the overshoot.
qreal(* EasingFunction)(qreal progress)
This is a typedef for a pointer to a function with the following signature:
void addCubicBezierSegment(const QPointF &c1, const QPointF &c2, const QPointF &endPoint)
Adds a segment of a cubic bezier spline to define a custom easing curve.
QEasingCurve(Type type=Linear)
Constructs an easing curve of the given type.
void setOvershoot(qreal overshoot)
Sets the overshoot to overshoot.
void addTCBSegment(const QPointF &nextPoint, qreal t, qreal c, qreal b)
Adds a segment of a TCB bezier spline to define a custom easing curve.
void setCustomType(EasingFunction func)
Sets a custom easing curve that is defined by the user in the function func.
Type
The type of easing curve.
qreal valueForProgress(qreal progress) const
Return the effective progress for the easing curve at progress.
qreal amplitude() const
Returns the amplitude.
void setType(Type type)
Sets the type of the easing curve to type.
QList< QPointF > toCubicSpline() const
QScopedPointer< QGraphicsItemPrivate > d_ptr
Definition qlist.h:74
qsizetype size() const noexcept
Definition qlist.h:386
bool isEmpty() const noexcept
Definition qlist.h:390
const T & constLast() const noexcept
Definition qlist.h:633
const_reference at(qsizetype i) const noexcept
Definition qlist.h:429
void reserve(qsizetype size)
Definition qlist.h:746
pointer data()
Definition qlist.h:414
void append(parameter_type t)
Definition qlist.h:441
void clear()
Definition qlist.h:417
\inmodule QtCore\reentrant
Definition qpoint.h:214
constexpr qreal x() const noexcept
Returns the x coordinate of this point.
Definition qpoint.h:333
constexpr qreal y() const noexcept
Returns the y coordinate of this point.
Definition qpoint.h:338
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5710
QString arg(qlonglong a, int fieldwidth=0, int base=10, QChar fillChar=u' ') const
Definition qstring.cpp:8606
QPixmap p2
QPixmap p1
[0]
double e
Combined button and popup list for selecting options.
static jboolean copy(JNIEnv *, jobject)
static QList< QPointF > tcbToBezier(const TCBPoints &tcbPoints)
static QEasingCurve::EasingFunction curveToFunc(QEasingCurve::Type curve)
static QT_BEGIN_NAMESPACE bool isConfigFunction(QEasingCurve::Type type)
QDataStream & operator>>(QDataStream &stream, TCBPoint &point)
QList< TCBPoint > TCBPoints
static QEasingCurveFunction * curveToFunctionObject(QEasingCurve::Type type)
QDataStream & operator<<(QDataStream &stream, const TCBPoint &point)
EGLStreamKHR stream
EGLConfig config
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
bool qFuzzyCompare(qfloat16 p1, qfloat16 p2) noexcept
Definition qfloat16.h:287
qfloat16 qSqrt(qfloat16 f)
Definition qfloat16.h:243
#define qWarning
Definition qlogging.h:162
#define M_PI
Definition qmath.h:209
GLboolean GLboolean GLboolean b
GLsizei const GLfloat * v
[13]
GLint GLint GLint GLint GLint x
[0]
GLboolean GLboolean GLboolean GLboolean a
[7]
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat s1
GLenum GLenum GLsizei count
GLfloat GLfloat f
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat t1
[4]
GLenum type
GLboolean GLboolean g
GLenum func
Definition qopenglext.h:663
GLuint res
const GLubyte * c
GLdouble GLdouble t
Definition qopenglext.h:243
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLdouble s
[6]
Definition qopenglext.h:235
GLfloat GLfloat p
[1]
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define s3
#define s2
#define s1
#define t3
#define t2
#define t1
#define QT_BEGIN_INCLUDE_NAMESPACE
#define QT_END_INCLUDE_NAMESPACE
@ Q_PRIMITIVE_TYPE
Definition qtypeinfo.h:144
#define Q_DECLARE_TYPEINFO(TYPE, FLAGS)
Definition qtypeinfo.h:163
unsigned int quint32
Definition qtypes.h:45
size_t quintptr
Definition qtypes.h:72
unsigned long long quint64
Definition qtypes.h:56
double qreal
Definition qtypes.h:92
unsigned char quint8
Definition qtypes.h:41
static int sign(int x)
QObject::connect nullptr
MyCustomStruct c2
QEasingCurve easing(QEasingCurve::InOutQuad)
[typedef]
QSharedPointer< T > other(t)
[5]
QGraphicsItem * item
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)
static qreal singleRealSolutionForCubic(qreal a, qreal b, qreal c)
qreal value(qreal x) override
QList< SingleCubicBezier > _curves
QEasingCurveFunction * copy() const override
void getBezierSegment(SingleCubicBezier *&singleCubicBezier, qreal x)
static qreal findTForX(const SingleCubicBezier &singleCubicBezier, qreal x)
QList< qreal > _intervals
BezierEase(QEasingCurve::Type type=QEasingCurve::BezierSpline)
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
Definition moc.h:24