Tizen 2.1 base
[framework/osp/uifw.git] / src / ui / animations / FUiAnimBezierTimingFunction.cpp
1 //
2 // Open Service Platform
3 // Copyright (c) 2012-2013 Samsung Electronics Co., Ltd.
4 //
5 // Licensed under the Flora License, Version 1.0 (the License);
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 //     http://floralicense.org/license/
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an AS IS BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17
18 /**
19  * @file        FUiAnimBezierTimingFunction.cpp
20  * @brief       This file contains implementation of BezierTimingFunction class
21  *
22  * This file contains implementation BezierTimingFunction class.
23  */
24
25 #include <math.h>
26
27 #include <FBaseErrors.h>
28 #include <FBaseSysLog.h>
29
30 #include <FUiAnimBezierTimingFunction.h>
31
32 #include "FUi_Math.h"
33
34
35 namespace Tizen { namespace Ui { namespace Animations
36 {
37
38 #define THIRD                   0.33333333333333f
39 #define ROOTTHREE               1.73205080756888f
40
41 float
42 CubeRoot(float x)
43 {
44         if (x < 0.0f)
45         {
46                 return -powf(-x, THIRD);
47         }
48
49         return powf(x, THIRD);
50 }
51
52
53 BezierTimingFunction::BezierTimingFunction(void)
54         : __timeProgress1(0.0f)
55         , __progress1(0.0f)
56         , __timeProgress2(0.0f)
57         , __progress2(0.0f)
58         , __coefficientA(0.0f)
59         , __coefficientB(0.0f)
60         , __coefficientC(0.0f)
61 {
62         SetControlPoints(0.33f, 0.8f, 0.66f, 0.2f);
63 }
64
65 BezierTimingFunction::~BezierTimingFunction(void)
66 {
67
68 }
69
70 result
71 BezierTimingFunction::SetControlPoints(float timeProgress1, float progress1, float timeProgress2, float progress2)
72 {
73         SysTryReturnResult(NID_UI_ANIM, (timeProgress1 >= 0.f && timeProgress1 <= 1.0f), E_INVALID_ARG, "Invalid argument(s) is used. timeProgress1 is invalid.");
74         SysTryReturnResult(NID_UI_ANIM, (progress1 >= 0.f && progress1 <= 1.0f), E_INVALID_ARG, "Invalid argument(s) is used. progress1 is invalid.");
75         SysTryReturnResult(NID_UI_ANIM, (timeProgress2 >= 0.f && timeProgress2 <= 1.0f), E_INVALID_ARG, "Invalid argument(s) is used. timeProgress2 is invalid.");
76         SysTryReturnResult(NID_UI_ANIM, (progress2 >= 0.f && progress2 <= 1.0f), E_INVALID_ARG, "Invalid argument(s) is used. progress2 is invalid.");
77
78         __timeProgress1 = timeProgress1;
79         __progress1 = progress1;
80
81         __timeProgress2 = timeProgress2;
82         __progress2 = progress2;
83
84         // Bezier curve
85         //
86         // B(t) = (1-t)^3 * P0 + 3t(1-t)^2*P1 + 3t^2(1-t)*P2 + t^3*P3
87         //       = (P3 - P0 + 3P1 - 3P2) * t^3 + (3P0 - 6P1 + 3P2) * t^2 + (3P1 - 3P0) * t + P0
88         //
89         // Now, P0 = (0, 0), P3 = (1, 1)
90         //
91         // (1 + 3P1 - 3P2) * t^3  + (3P2 - 6P1) * t^2 + 3P1 * t - timeProgress = 0
92
93         // ax^3 + bx^2 + cx + d = 0
94
95         __coefficientA = 1.0f + 3.0f * __timeProgress1 - 3.0f * __timeProgress2;
96         __coefficientB = 3.0f * __timeProgress2 - 6.0f * __timeProgress1;
97         __coefficientC = 3.0f * __timeProgress1;
98
99         return E_SUCCESS;
100 }
101
102 result
103 BezierTimingFunction::GetControlPoints(float& timeProgress1, float& progress1, float& timeProgress2, float& progress2) const
104 {
105         timeProgress1 = __timeProgress1;
106         progress1 = __progress1;
107
108         timeProgress2 = __timeProgress2;
109         progress2 = __progress2;
110
111         return E_SUCCESS;
112 }
113
114 float
115 BezierTimingFunction::CalculateProgress(float timeProgress) const
116 {
117         float t = 0.0f;
118         float d = -timeProgress;
119
120         // 1. Cardano's method
121         // http://www.wolframalpha.com
122         // http://www.dreamincode.net/code/snippet2915.htm
123
124         SysTryReturn(NID_UI_ANIM, (__coefficientA <-ALMOST_ZERO_FLOAT || __coefficientA> ALMOST_ZERO_FLOAT), 0.0f, E_INVALID_OPERATION,
125                                 "[E_INVALID_OPERATION] Invalid control points.");
126
127         // find the discriminant
128         float f = (3.0f * __coefficientC / __coefficientA - __coefficientB * __coefficientB / (__coefficientA * __coefficientA)) / 3.0f;
129         float g = (2.0f * powf(__coefficientB, 3) / powf(__coefficientA, 3) - 9.0f * __coefficientB * __coefficientC / (__coefficientA * __coefficientA) + 27.0f * d / __coefficientA) / 27.0f;
130         float h = g * g / 4.0f + powf(f, 3) / 27.0f;
131
132         // evaluate discriminat
133         if (f >= -ALMOST_ZERO_FLOAT && f <= ALMOST_ZERO_FLOAT && g >= -ALMOST_ZERO_FLOAT && g <= ALMOST_ZERO_FLOAT && h >=
134                 -ALMOST_ZERO_FLOAT && h <= ALMOST_ZERO_FLOAT)
135         {
136                 // 3 equal roots
137                 // when f, g and h all equal 0 the roots can be found by the following line
138                 t = -CubeRoot(d / __coefficientA);
139         }
140         else if (h <= 0.0f)
141         {
142                 // 3 real roots
143                 // complicated maths making use of the method
144                 float i = powf(g * g / 4.0f - h, 0.5f);
145                 float j = CubeRoot(i);
146                 float k = acosf(-(g / (2.0f * i)));
147                 float m = cosf(k / 3.0f);
148                 float n = ROOTTHREE * sinf(k / 3.0f);
149                 float p = -(__coefficientB / (3.0f * __coefficientA));
150
151                 float t1 = 2.0f * j * m + p;
152                 float t2 = -j * (m + n) + p;
153                 float t3 = -j * (m - n) + p;
154
155                 // find the proper t
156                 if (t1 >= 0.0f && t1 <= 1.0f)
157                 {
158                         t = t1;
159                 }
160                 else if (t2 >= 0.0f && t2 <= 1.0f)
161                 {
162                         t = t2;
163                 }
164                 else if (t3 >= 0.0f && t3 <= 1.0f)
165                 {
166                         t = t3;
167                 }
168                 else
169                 {
170                         SysLogException(NID_UI_ANIM, E_INVALID_OPERATION, "[E_INVALID_OPERATION] control points are invalid.");
171                         return 0.0f;
172                 }
173         }
174         else    // if (h > 0.0f)
175         {
176                 // 1 real root and 2 complex roots
177                 // complicated maths making use of the method
178                 float r = -(g / 2.0f) + powf(h, 0.5f);
179                 float s = CubeRoot(r);
180                 float u = -(g / 2.0f) - powf(h, 0.5f);
181                 float v = CubeRoot(u);
182                 float p = -(__coefficientB / (3.0f * __coefficientA));
183
184                 t = s + v + p;
185         }
186
187         // calculate progress from t
188         // progress = (1 + 3P1 - 3P2) * t^3  + (3P2 - 6P1) * t^2 + 3P1 * t
189         return (1.0f + 3.0f * __progress1 - 3.0f * __progress2) * t * t * t + (3.0f * __progress2 - 6.0f * __progress1) * t * t + 3.0f * __progress1 * t;
190
191 #if 0
192         // 2. Newton-Raphson's method
193         //
194         // f(x) = ax^3 + bx^2 + cx + d
195         // f'(x) = 3ax^2 + 2bx + c
196         //
197         // x_n+1 = x_n - f(x_n) / f'(x_n)
198
199         float t = 0.5f;
200         float t1 = 0.5f;
201         int iteration = 0;
202
203         do
204         {
205                 t = t1;
206                 t1 = t - (a * t * t * t + b * t * t + c * t + d) / (3.0f * a * t * t + 2.0f * b * t + c);
207                 iteration++;
208         }
209         while ((t - t1 > ALMOST_ZERO_FLOAT || t - t1 < -ALMOST_ZERO_FLOAT) && iteration < 10);
210
211         // calculate progress from t
212         // progress = (1 + 3P1 - 3P2) * t^3  + (3P2 - 6P1) * t^2 + 3P1 * t
213         return (1.0f + 3.0f * __y1 - 3.0f * __y2) * t1 * t1 * t1 + (3.0f * __y2 - 6.0f * __y1) * t1 * t1 + 3.0f * __y1 * t1;
214 #endif
215 }
216
217
218 }}}   // Tizen::Ui::Animations
219