summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWonki Kim <wonki_.kim@samsung.com>2020-05-19 13:05:11 +0900
committerHermet Park <chuneon.park@samsung.com>2020-05-19 13:05:11 +0900
commit633202a0f93661d35a340dae692208dfcc792a41 (patch)
tree40c3df884b854104749a31bd517e4ab6ed093a64
parent9c0484c9cb5bc9d9569a31d8e49f4fff31b0b472 (diff)
ecore_anim: rework bezier curve function
Summary: current cubic bezier function isn't accurate at sometime. to make it more accurate, this patch rework bezier curve by using a cardano's algorithm. (refer to https://pomax.github.io/bezierinfo/) Reviewers: Hermet, bu5hm4n Reviewed By: Hermet Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D11819
-rw-r--r--src/lib/ecore/ecore_anim.c137
1 files changed, 86 insertions, 51 deletions
diff --git a/src/lib/ecore/ecore_anim.c b/src/lib/ecore/ecore_anim.c
index f2ec2d61c8..a5bde81ff6 100644
--- a/src/lib/ecore/ecore_anim.c
+++ b/src/lib/ecore/ecore_anim.c
@@ -626,68 +626,103 @@ _pos_map_spring(double pos,
626 return _pos_map_sin((M_PI / 2.0) + (p2 * len)) * decay; 626 return _pos_map_sin((M_PI / 2.0) + (p2 * len)) * decay;
627} 627}
628 628
629static double 629static inline double
630_cubic_bezier_a (double a1, double a2) 630cuberoot(double v)
631{ 631{
632 return 1.0 - 3.0 * a2 + 3.0 * a1; 632 if (v < 0.0)
633 return -pow(-v, 1. / 3.);
634 else
635 return pow(v, 1. / 3.);
633} 636}
634 637
635static double 638static double
636_cubic_bezier_b (double a1, double a2) 639_bezier_t_get(double _x, double _x1, double _x2)
637{ 640{
638 return 3.0 * a2 - 6.0 * a1; 641 if (_x < 0.0 || _x > 1.0) return _x;
639} 642
643 // Cardano's algorithm
644 double\
645 pa = _x - 0.0,
646 pb = _x - _x1,
647 pc = _x - _x2,
648 pd = _x - 1.0;
649
650 double\
651 a = 3*pa-6*pb+3*pc,
652 b = -3*pa+3*pb,
653 c = pa,
654 d = -pa+3*pb-3*pc+pd;
655
656 a /= d;
657 b /= d;
658 c /= d;
659
660 double\
661 p = (3*b-a*a)/3.0,
662 p3 = p/3.0,
663 q = (2*a*a*a-9*a*b+27*c)/27.0,
664 q2 = q/2.0,
665 discriminant = q2*q2 + p3*p3*p3;
666
667 double u1, v1, root1, root2, root3;
668
669 if (discriminant < 0)
670 {
671 double\
672 mp3 = -p/3.0,
673 mp33 = mp3*mp3*mp3,
674 r = sqrt(mp33),
675 t = -q / (2*r),
676 cosphi = t<-1.0 ? -1.0 : t>1.0 ? 1.0 : t,
677 phi = acos(cosphi),
678 crtr = cuberoot(r),
679 t1 = 2*crtr;
680 root1 = t1 * cos(phi/3.0) - a/3.0;
681 root2 = t1 * cos((phi+2*M_PI)/3.0) - a/3.0;
682 root3 = t1 * cos((phi+4*M_PI)/3.0) - a/3.0;
683
684 if (root1 >= 0.0 && root1 <= 1.0) return root1;
685 if (root2 >= 0.0 && root2 <= 1.0) return root2;
686 if (root3 >= 0.0 && root3 <= 1.0) return root3;
687 }
688 else if (discriminant == 0)
689 {
690 u1 = q2 < 0 ? cuberoot(-q2) : -cuberoot(q2);
691 root1 = 2*u1 - a/3.0;
692 root2 = -u1 - a/3.0;
640 693
641static double 694 if (root1 >= 0.0 && root1 <= 1.0) return root1;
642_cubic_bezier_c(double a1) 695 if (root2 >= 0.0 && root2 <= 1.0) return root2;
643{ 696 }
644 return 3.0 * a1; 697 else
645} 698 {
699 double sd = sqrt(discriminant);
700 u1 = cuberoot(sd - q2);
701 v1 = cuberoot(sd + q2);
702 root1 = u1 - v1 - a/3.0;
646 703
647static double 704 if (root1 >= 0.0 && root1 <= 1.0) return root1;
648_cubic_bezier_calc(double t, 705 }
649 double a1,
650 double a2)
651{
652 return ((_cubic_bezier_a(a1, a2) * t +
653 _cubic_bezier_b(a1, a2)) * t +
654 _cubic_bezier_c(a1)) * t;
655}
656 706
657static double 707 return _x;
658_cubic_bezier_slope_get(double t,
659 double a1,
660 double a2)
661{
662 return 3.0 * _cubic_bezier_a(a1, a2) * t * t +
663 2.0 * _cubic_bezier_b(a1, a2) * t +
664 _cubic_bezier_c(a1);
665} 708}
666 709
667static double 710static double
668_cubic_bezier_t_get(double a, 711_bezier_calc(double t, double y1, double y2)
669 double x1,
670 double x2)
671{ 712{
672#define APPROXIMATE_RANGE(val) \ 713 double y0 = 0.0;
673 ((((val) < 0.01) && ((val) > -0.01)) ? EINA_TRUE : EINA_FALSE) 714 double y3 = 1.0;
674 715
675 const int LIMIT = 100; 716 double u = 1.0 - t;
676 double current_slope; 717 double t2 = t*t;
677 double change; 718 double t3 = t*t*t;
678 double current_x; 719 double u2 = u*u;
679 double guess_t = a; 720 double u3 = u*u*u;
680 721
681 for (int i = 0; i < LIMIT; i++) 722 return u3 * y0 +
682 { 723 3.0 * u2 * t * y1 +
683 current_slope = _cubic_bezier_slope_get(guess_t, x1, x2); 724 3.0 * u * t2 * y2 +
684 if (EINA_DBL_EQ(current_slope, 0.0)) return guess_t; 725 t3 * y3;
685 current_x = _cubic_bezier_calc(guess_t, x1, x2) - a;
686 change = current_x / current_slope;
687 guess_t -= change;
688 if (APPROXIMATE_RANGE(change)) break;
689 }
690 return guess_t;
691} 726}
692 727
693static double 728static double
@@ -700,7 +735,7 @@ _pos_map_cubic_bezier(double pos,
700 if (EINA_DBL_EQ(x1, y1) && 735 if (EINA_DBL_EQ(x1, y1) &&
701 EINA_DBL_EQ(x2, y2)) 736 EINA_DBL_EQ(x2, y2))
702 return pos; 737 return pos;
703 return _cubic_bezier_calc(_cubic_bezier_t_get(pos, x1, x2), y1, y2); 738 return _bezier_calc(_bezier_t_get(pos, x1, x2), y1, y2);
704} 739}
705 740
706#define DBL_TO(Fp) eina_f32p32_double_to(Fp) 741#define DBL_TO(Fp) eina_f32p32_double_to(Fp)