2 // Open Service Platform
3 // Copyright (c) 2012-2013 Samsung Electronics Co., Ltd.
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
9 // http://floralicense.org/license/
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.
19 * @file FUiAnimBezierTimingFunction.cpp
20 * @brief This file contains implementation of BezierTimingFunction class
22 * This file contains implementation BezierTimingFunction class.
27 #include <FBaseErrors.h>
28 #include <FBaseSysLog.h>
30 #include <FUiAnimBezierTimingFunction.h>
35 namespace Tizen { namespace Ui { namespace Animations
38 #define THIRD 0.33333333333333f
39 #define ROOTTHREE 1.73205080756888f
46 return -powf(-x, THIRD);
49 return powf(x, THIRD);
53 BezierTimingFunction::BezierTimingFunction(void)
54 : __timeProgress1(0.0f)
56 , __timeProgress2(0.0f)
58 , __coefficientA(0.0f)
59 , __coefficientB(0.0f)
60 , __coefficientC(0.0f)
62 SetControlPoints(0.33f, 0.8f, 0.66f, 0.2f);
65 BezierTimingFunction::~BezierTimingFunction(void)
71 BezierTimingFunction::SetControlPoints(float timeProgress1, float progress1, float timeProgress2, float progress2)
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.");
78 __timeProgress1 = timeProgress1;
79 __progress1 = progress1;
81 __timeProgress2 = timeProgress2;
82 __progress2 = progress2;
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
89 // Now, P0 = (0, 0), P3 = (1, 1)
91 // (1 + 3P1 - 3P2) * t^3 + (3P2 - 6P1) * t^2 + 3P1 * t - timeProgress = 0
93 // ax^3 + bx^2 + cx + d = 0
95 __coefficientA = 1.0f + 3.0f * __timeProgress1 - 3.0f * __timeProgress2;
96 __coefficientB = 3.0f * __timeProgress2 - 6.0f * __timeProgress1;
97 __coefficientC = 3.0f * __timeProgress1;
103 BezierTimingFunction::GetControlPoints(float& timeProgress1, float& progress1, float& timeProgress2, float& progress2) const
105 timeProgress1 = __timeProgress1;
106 progress1 = __progress1;
108 timeProgress2 = __timeProgress2;
109 progress2 = __progress2;
115 BezierTimingFunction::CalculateProgress(float timeProgress) const
118 float d = -timeProgress;
120 // 1. Cardano's method
121 // http://www.wolframalpha.com
122 // http://www.dreamincode.net/code/snippet2915.htm
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.");
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;
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)
137 // when f, g and h all equal 0 the roots can be found by the following line
138 t = -CubeRoot(d / __coefficientA);
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));
151 float t1 = 2.0f * j * m + p;
152 float t2 = -j * (m + n) + p;
153 float t3 = -j * (m - n) + p;
156 if (t1 >= 0.0f && t1 <= 1.0f)
160 else if (t2 >= 0.0f && t2 <= 1.0f)
164 else if (t3 >= 0.0f && t3 <= 1.0f)
170 SysLogException(NID_UI_ANIM, E_INVALID_OPERATION, "[E_INVALID_OPERATION] control points are invalid.");
174 else // if (h > 0.0f)
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));
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;
192 // 2. Newton-Raphson's method
194 // f(x) = ax^3 + bx^2 + cx + d
195 // f'(x) = 3ax^2 + 2bx + c
197 // x_n+1 = x_n - f(x_n) / f'(x_n)
206 t1 = t - (a * t * t * t + b * t * t + c * t + d) / (3.0f * a * t * t + 2.0f * b * t + c);
209 while ((t - t1 > ALMOST_ZERO_FLOAT || t - t1 < -ALMOST_ZERO_FLOAT) && iteration < 10);
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;
218 }}} // Tizen::Ui::Animations