1#![cfg_attr(test, feature(concat_idents))]
6
7extern crate num_traits;
8use num_traits::Float;
9
10use std::f64::consts::{PI,FRAC_PI_2};
11
12fn lit<F: Float>(f: f64) -> F {
13 F::from(f).unwrap()
14}
15
16#[inline]
19pub fn linear<F: Float>(t: F) -> F {
20 t
21}
22
23#[inline]
26pub fn quad_in<F: Float>(t: F) -> F {
27 t * t
28}
29
30#[inline]
31pub fn quad_out<F: Float>(t: F) -> F {
32 -t * (t - lit::<F>(2.0))
33}
34
35#[inline]
36pub fn quad_inout<F: Float>(t: F) -> F {
37 if t < lit::<F>(0.5) {
38 lit::<F>(2.0) * t * t
39 } else {
40 (lit::<F>(-2.0) * t * t) + (lit::<F>(4.0) * t) - lit::<F>(1.0)
41 }
42}
43
44#[inline]
47pub fn cubic_in<F: Float>(t: F) -> F {
48 t * t * t
49}
50
51#[inline]
52pub fn cubic_out<F: Float>(t: F) -> F {
53 let f = t - lit::<F>(1.0);
54 f * f * f + lit::<F>(1.0)
55}
56
57#[inline]
58pub fn cubic_inout<F: Float>(t: F) -> F {
59 if t < lit::<F>(0.5) {
60 lit::<F>(4.0) * t * t * t
61 } else {
62 let f = (lit::<F>(2.0) * t) - lit::<F>(2.0);
63 lit::<F>(0.5) * f * f * f + lit::<F>(1.0)
64 }
65}
66
67#[inline]
70pub fn quart_in<F: Float>(t: F) -> F {
71 t * t * t * t
72}
73
74#[inline]
75pub fn quart_out<F: Float>(t: F) -> F {
76 let f = t - lit::<F>(1.0);
77 f * f * f * (lit::<F>(1.0) - t) + lit::<F>(1.0)
78}
79
80#[inline]
81pub fn quart_inout<F: Float>(t: F) -> F {
82 if t < lit::<F>(0.5) {
83 lit::<F>(8.0) * t * t * t * t
84 } else {
85 let f = t - lit::<F>(1.0);
86 lit::<F>(-8.0) * f * f * f * f + lit::<F>(1.0)
87 }
88}
89
90#[inline]
93pub fn quint_in<F: Float>(t: F) -> F {
94 t * t * t * t * t
95}
96
97#[inline]
98pub fn quint_out<F: Float>(t: F) -> F {
99 let f = t - lit::<F>(1.0);
100 f * f * f * f * f + lit::<F>(1.0)
101}
102
103#[inline]
104pub fn quint_inout<F: Float>(t: F) -> F {
105 if t < lit::<F>(0.5) {
106 lit::<F>(16.0) * t * t * t * t * t
107 } else {
108 let f = (lit::<F>(2.0) * t) - lit::<F>(2.0);
109 lit::<F>(0.5) * f * f * f * f * f + lit::<F>(1.0)
110 }
111}
112
113#[inline]
116pub fn sine_in<F: Float>(t: F) -> F {
117 ((t - lit::<F>(1.0)) * lit::<F>(FRAC_PI_2)).sin() + lit::<F>(1.0)
118}
119
120#[inline]
121pub fn sine_out<F: Float>(t: F) -> F {
122 (t * lit::<F>(FRAC_PI_2)).sin()
123}
124
125#[inline]
126pub fn sine_inout<F: Float>(t: F) -> F {
127 lit::<F>(0.5) * (lit::<F>(1.0) - (t * lit::<F>(PI)).cos())
128}
129
130#[inline]
133pub fn circ_in<F: Float>(t: F) -> F {
134 lit::<F>(1.0) - (lit::<F>(1.0) - t * t).sqrt()
135}
136
137#[inline]
138pub fn circ_out<F: Float>(t: F) -> F {
139 ((lit::<F>(2.0) - t) * t).sqrt()
140}
141
142#[inline]
143pub fn circ_inout<F: Float>(t: F) -> F {
144 if t < lit::<F>(0.5) {
145 lit::<F>(0.5) * (lit::<F>(1.0) - (lit::<F>(1.0) - lit::<F>(4.0) * t * t).sqrt())
146 } else {
147 lit::<F>(0.5) * ((-(lit::<F>(2.0) * t - lit::<F>(3.0)) * (lit::<F>(2.0) * t - lit::<F>(1.0))).sqrt() + lit::<F>(1.0))
148 }
149}
150
151#[inline]
154pub fn expo_in<F: Float>(t: F) -> F {
155 if t == lit::<F>(0.0) {
156 lit::<F>(0.0)
157 } else {
158 lit::<F>(2.0).powf(lit::<F>(10.0) * (t - lit::<F>(1.0)))
159 }
160}
161
162
163#[cfg_attr(feature = "cargo-clippy", allow(float_cmp))]
164#[inline]
165pub fn expo_out<F: Float>(t: F) -> F {
166 if t == lit::<F>(1.0) {
167 lit::<F>(1.0)
168 } else {
169 lit::<F>(1.0) - lit::<F>(2.0).powf(lit::<F>(-10.0) * t)
170 }
171}
172
173#[cfg_attr(feature = "cargo-clippy", allow(float_cmp))]
174#[inline]
175pub fn expo_inout<F: Float>(t: F) -> F {
176 if t == lit::<F>(0.0) {
177 lit::<F>(0.0)
178 } else if t == lit::<F>(1.0) {
179 lit::<F>(1.0)
180 } else if t < lit::<F>(0.5) {
181 lit::<F>(0.5) * lit::<F>(2.0).powf(lit::<F>(20.0) * t - lit::<F>(10.0))
182 } else {
183 lit::<F>(-0.5) * lit::<F>(2.0).powf(lit::<F>(-20.0) * t + lit::<F>(10.0)) + lit::<F>(1.0)
184 }
185}
186
187#[inline]
190pub fn elastic_in<F: Float>(t: F) -> F {
191 (lit::<F>(13.0) * lit::<F>(FRAC_PI_2) * t).sin() * lit::<F>(2.0).powf(lit::<F>(10.0) * (t - lit::<F>(1.0)))
192}
193
194#[inline]
195pub fn elastic_out<F: Float>(t: F) -> F {
196 (lit::<F>(-13.0) * lit::<F>(FRAC_PI_2) * (t + lit::<F>(1.0))).sin() * lit::<F>(2.0).powf(lit::<F>(-10.0) * t) + lit::<F>(1.0)
197}
198
199#[inline]
200pub fn elastic_inout<F: Float>(t: F) -> F {
201 if t < lit::<F>(0.5) {
202 lit::<F>(0.5) * (lit::<F>(13.0) * lit::<F>(FRAC_PI_2) * lit::<F>(2.0) * t).sin() * lit::<F>(2.0).powf(lit::<F>(10.0) * (lit::<F>(2.0) * t - lit::<F>(1.0)))
203 } else {
204 lit::<F>(0.5) * ((lit::<F>(-13.0) * lit::<F>(FRAC_PI_2) * lit::<F>(2.0) * t).sin() * (lit::<F>(2.0)).powf(lit::<F>(-10.0) * (lit::<F>(2.0) * t - lit::<F>(1.0))) + lit::<F>(2.0))
205 }
206}
207
208#[inline]
211pub fn back_in<F: Float>(t: F) -> F {
212 t * t * t - t * (t * lit::<F>(PI)).sin()
213}
214
215#[inline]
216pub fn back_out<F: Float>(t: F) -> F {
217 let f = lit::<F>(1.0) - t;
218 lit::<F>(1.0) - f * f * f + f * (f * lit::<F>(PI)).sin()
219}
220
221#[inline]
222pub fn back_inout<F: Float>(t: F) -> F {
223 if t < lit::<F>(0.5) {
224 let f = lit::<F>(2.0) * t;
225 lit::<F>(0.5) * (f * f * f - f * (f * lit::<F>(PI)).sin())
226 } else {
227 let f = lit::<F>(2.0) - lit::<F>(2.0) * t;
228 lit::<F>(0.5) * (lit::<F>(1.0) - (f * f * f - f * (f * lit::<F>(PI)).sin())) + lit::<F>(0.5)
229 }
230}
231
232#[inline]
235pub fn bounce_in<F: Float>(t: F) -> F {
236 lit::<F>(1.0) - bounce_out(lit::<F>(1.0) - t)
237}
238
239#[inline]
240pub fn bounce_out<F: Float>(t: F) -> F {
241 if t < lit::<F>(4.0 / 11.0) {
242 lit::<F>(121.0 / 16.0) * t * t
243 } else if t < lit::<F>(8.0 / 11.0) {
244 lit::<F>(363.0 / 40.0) * t * t - lit::<F>(99.0 / 10.0) * t + lit::<F>(17.0 / 5.0)
245 } else if t < lit::<F>(9.0 / 10.0) {
246 lit::<F>(4356.0 / 361.0) * t * t - lit::<F>(35442.0 / 1805.0) * t + lit::<F>(16061.0 / 1805.0)
247 } else {
248 lit::<F>(54.0 / 5.0) * t * t - lit::<F>(513.0 / 25.0) * t + lit::<F>(268.0 / 25.0)
249 }
250}
251
252#[inline]
253pub fn bounce_inout<F: Float>(t: F) -> F {
254 if t < lit::<F>(0.5) {
255 lit::<F>(0.5) * bounce_in(t * lit::<F>(2.0))
256 } else {
257 lit::<F>(0.5) * bounce_out(t * lit::<F>(2.0) - lit::<F>(1.0)) + lit::<F>(0.5)
258 }
259}
260
261
262#[cfg(test)]
263mod tests {
264 use num_traits::Float;
265 use super::lit;
266
267 fn assert_float_eq<A: Float, B: Float>(a: A, b: B) {
268 let a = a.to_f64().unwrap();
269 let b = b.to_f64().unwrap();
270
271 assert!(a - b < 0.00001, "a = {}, b = {}", a, b);
272 }
273
274 macro_rules! tests {
275 ($name:ident) => {
276 mod $name{
277 use super::*;
278 use super::super::*;
279
280 #[test] fn in32() { test::<f32, _>(concat_idents!($name, _in)); }
281 #[test] fn in64() { test::<f64, _>(concat_idents!($name, _in)); }
282 #[test] fn out32() { test::<f32, _>(concat_idents!($name, _out)); }
283 #[test] fn out64() { test::<f64, _>(concat_idents!($name, _out)); }
284 #[test] fn inout32() { test::<f32, _>(concat_idents!($name, _inout)); }
285 #[test] fn inout64() { test::<f64, _>(concat_idents!($name, _inout)); }
286 #[test] fn trio32() { test_trio::<f32, _, _, _>(concat_idents!($name, _in),
287 concat_idents!($name, _out),
288 concat_idents!($name, _inout)); }
289 #[test] fn trio64() { test_trio::<f64, _, _, _>(concat_idents!($name, _in),
290 concat_idents!($name, _out),
291 concat_idents!($name, _inout)); }
292 }
293 }
294 }
295
296 fn test<T: Float, F>(f: F)
297 where F: Fn(T) -> T {
298 assert_float_eq(f(lit::<T>(0.0)), 0.0);
299 assert_float_eq(f(lit::<T>(1.0)), 1.0);
300 }
301
302 fn test_trio<T: Float, FIN, FOUT, FINOUT>(fin: FIN, fout: FOUT, finout: FINOUT)
303 where FIN: Fn(T) -> T,
304 FOUT: Fn(T) -> T,
305 FINOUT: Fn(T) -> T {
306
307 let n = 99;
308
309 for i in 0..n+1 {
310 let t = T::from(i).unwrap() / T::from(n).unwrap();
311 println!("{}", t.to_f32().unwrap());
312
313 assert_float_eq::<T, T>(fin(t), lit::<T>(1.0) - (fout(lit::<T>(1.0) - t)));
314
315 if t < lit(0.5) {
316 assert_float_eq(finout(t), fin(t*lit::<T>(2.0)) / lit::<T>(2.0));
317 } else {
318 assert_float_eq(finout(t), fout((t-lit::<T>(0.5))*lit::<T>(2.0)) / lit::<T>(2.0) + lit::<T>(0.5));
319 }
320 }
321 }
322
323 tests!(quad);
324 tests!(cubic);
325 tests!(quart);
326 tests!(quint);
327 tests!(sine);
328 tests!(circ);
329 tests!(expo);
330 tests!(elastic);
331 tests!(back);
332 tests!(bounce);
333 #[test]
334 fn test_linear() {
335 test::<f32, _>(super::linear);
336 test::<f64, _>(super::linear);
337 }
338}