animate/
easing.rs

1#![allow(dead_code)]
2#![allow(clippy::float_cmp)]
3
4/// The easing function type.
5///
6/// An easing function takes an input number [t] in range 0..1, inclusive, and
7/// returns a non-negative amount. In addition, the function must return 1 for
8/// [t] = 1.
9use std::f64::consts::PI;
10
11pub type EasingFunction = fn(t: f64) -> f64;
12
13fn linear(amount: f64) -> f64 {
14    amount
15}
16
17fn quad_in(amount: f64) -> f64 {
18    amount * amount
19}
20
21fn quad_out(amount: f64) -> f64 {
22    amount * (2.0 - amount)
23}
24
25fn quad_in_out(amount: f64) -> f64 {
26    let mut amount = amount * 2.0;
27    if amount < 1.0 {
28        return 0.5 * amount * amount;
29    }
30    amount -= 1.0;
31    0.5 * (1.0 - amount * (amount - 2.0))
32}
33
34fn cubic_in(amount: f64) -> f64 {
35    amount * amount * amount
36}
37
38fn cubic_out(amount: f64) -> f64 {
39    let amount = amount - 1.0;
40    amount * amount * amount + 1.0
41}
42
43fn cubic_in_out(amount: f64) -> f64 {
44    let mut amount = amount * 2.0;
45    if amount < 1.0 {
46        return 0.5 * amount * amount * amount;
47    }
48    amount -= 2.0;
49    0.5 * (amount * amount * amount + 2.0)
50}
51
52fn quart_in(amount: f64) -> f64 {
53    amount * amount * amount * amount
54}
55
56fn quart_out(amount: f64) -> f64 {
57    let amount = amount - 1.0;
58    1.0 - amount * amount * amount * amount
59}
60
61fn quart_in_out(amount: f64) -> f64 {
62    let mut amount = amount * 2.0;
63    if amount < 1.0 {
64        return 0.5 * amount * amount * amount * amount;
65    }
66    amount -= 2.0;
67    0.5 * (2.0 - amount * amount * amount * amount)
68}
69
70fn quint_in(amount: f64) -> f64 {
71    amount * amount * amount * amount * amount
72}
73
74fn quint_out(amount: f64) -> f64 {
75    let amount = amount - 1.0;
76    amount * amount * amount * amount * amount + 1.0
77}
78
79fn quint_in_out(amount: f64) -> f64 {
80    let mut amount = amount * 2.0;
81    if amount < 1.0 {
82        return 0.5 * amount * amount * amount * amount * amount;
83    }
84
85    amount -= 2.0;
86    0.5 * (amount * amount * amount * amount * amount + 2.0)
87}
88
89fn sine_in(amount: f64) -> f64 {
90    1.0 - (amount * PI / 2.0).cos()
91}
92
93fn sine_out(amount: f64) -> f64 {
94    (amount * PI / 2.0).sin()
95}
96
97fn sine_in_out(t: f64) -> f64 {
98    0.5 * (1.0 - (PI * t).cos())
99}
100
101fn expo_in(amount: f64) -> f64 {
102    if amount == 0.0 {
103        return 1.0;
104    }
105
106    f64::powf(2.0, 10.0 * (amount - 1.0))
107}
108
109fn expo_out(amount: f64) -> f64 {
110    if amount == 1.0 {
111        return 1.0;
112    }
113
114    1.0 - f64::powf(2.0, -10.0 * amount)
115}
116
117fn expo_in_out(amount: f64) -> f64 {
118    if amount == 0.0 {
119        return 0.0;
120    }
121    if amount == 1.0 {
122        return 1.0;
123    }
124    let amount = amount * 2.0;
125    if amount < 1.0 {
126        return 1.0 / 2.0 * f64::powf(2.0, 10.0 * (amount - 1.0));
127    }
128
129    let amount = amount - 1.0;
130    0.5 * (-f64::powf(2.0, -10.0 * amount) + 2.0)
131}
132
133fn circ_in(amount: f64) -> f64 {
134    if amount >= 1.0 {
135        return amount;
136    }
137
138    1.0 - (1.0 - amount * amount).sqrt()
139}
140
141fn circ_out(amount: f64) -> f64 {
142    let amount = amount - 1.0;
143    (1.0 - amount * amount).sqrt()
144}
145
146fn circ_in_out(amount: f64) -> f64 {
147    let mut amount = amount * 2.0;
148    if amount < 1.0 {
149        return -0.5 * ((1.0 - amount * amount).sqrt() - 1.0);
150    }
151    amount -= 2.0;
152    0.5 * ((1.0 - amount * amount).sqrt() + 1.0)
153}
154
155fn elastic_in(amount: f64) -> f64 {
156    let mut p = 0.0;
157    let mut a = 1.0;
158    if amount == 0.0 {
159        return 0.0;
160    }
161    if amount == 1.0 {
162        return 1.0;
163    }
164    if p == 0.0 {
165        p = 0.3;
166    }
167
168    #[allow(unused_assignments)]
169    let mut s = 1.70158;
170    if a < 1.0 {
171        a = 1.0;
172        s = p / 4.0;
173    } else {
174        s = p / (2.0 * PI) * f64::asin(1.0 / a);
175    }
176
177    let amount = amount - 1.0;
178    -(a * f64::powf(2.0, 10.0 * amount) * ((amount - s) * (2.0 * PI) / p).sin())
179}
180
181fn elastic_out(amount: f64) -> f64 {
182    let mut p = 0.0;
183    let mut a = 1.0;
184
185    if amount == 0.0 {
186        return 0.0;
187    }
188
189    if amount == 1.0 {
190        return 1.0;
191    }
192
193    if p == 0.0 {
194        p = 0.3;
195    }
196
197    #[allow(unused_assignments)]
198    let mut s = 1.70158;
199    if a < 1.0 {
200        a = 1.0;
201        s = p / 4.0;
202    } else {
203        s = p / (2.0 * PI) * f64::asin(1.0 / a);
204    }
205
206    a * f64::powf(2.0, -10.0 * amount) * ((amount - s) * (2.0 * PI) / p).sin() + 1.0
207}
208
209fn elastic_in_out(amount: f64) -> f64 {
210    let mut p = 0.0;
211    let mut a = 1.0;
212
213    if amount == 0.0 {
214        return 0.0;
215    }
216
217    if amount == 1.0 {
218        return 1.0;
219    }
220
221    if p == 0.0 {
222        p = 1.0 * (0.3 * 1.5);
223    }
224
225    #[allow(unused_assignments)]
226    let mut s = 1.70158;
227    if a < 1.0 {
228        a = 1.0;
229        s = p / 4.0;
230    } else {
231        s = p / (2.0 * PI) * f64::asin(1.0 / a);
232    }
233
234    let amount = 2.0 * amount - 1.0;
235    if amount < 0.0 {
236        return -0.5 * (a * f64::powf(2.0, 10.0 * amount) * ((amount - s) * (2.0 * PI) / p).sin());
237    }
238
239    a * f64::powf(2.0, -10.0 * amount) * ((amount - s) * (2.0 * PI) / p).sin() * 0.5 + 1.0
240}
241
242fn back_in(amount: f64) -> f64 {
243    let s = 1.70158;
244    amount * amount * ((s + 1.0) * amount - s)
245}
246
247fn back_out(amount: f64) -> f64 {
248    let s = 1.70158;
249    let amount = amount - 1.0;
250    amount * amount * ((s + 1.0) * amount + s) + 1.0
251}
252
253fn back_in_out(amount: f64) -> f64 {
254    let s = 1.70158 * 1.525;
255    let mut amount = amount * 2.0;
256    if amount < 1.0 {
257        return 0.5 * (amount * amount * ((s + 1.0) * amount - s));
258    }
259    amount -= 2.0;
260    0.5 * (amount * amount * ((s + 1.0) * amount + s) + 2.0)
261}
262
263fn bounce_in(amount: f64) -> f64 {
264    1.0 - bounce_out(1.0 - amount)
265}
266
267fn bounce_out(t: f64) -> f64 {
268    let mut amount = t;
269    if amount < 1.0 / 2.75 {
270        7.5625 * amount * amount
271    } else if amount < 2.0 / 2.75 {
272        amount -= 1.5 / 2.75;
273        7.5625 * amount * amount + 0.75
274    } else if amount < 2.5 / 2.75 {
275        amount -= 2.25 / 2.75;
276        7.5625 * amount * amount + 0.9375
277    } else {
278        amount -= 2.625 / 2.75;
279        7.5625 * amount * amount + 0.984375
280    }
281}
282
283fn bounce_in_out(amount: f64) -> f64 {
284    if amount < 0.5 {
285        return bounce_in(amount * 2.0) * 0.5;
286    }
287
288    bounce_out(amount * 2.0 - 1.0) * 0.5 + 1.0 * 0.5
289}
290
291pub enum Easing {
292    Linear,
293    QuadIn,
294    QuadOut,
295    QuadInOut,
296    CubicIn,
297    CubicOut,
298    CubicInOut,
299    QuartIn,
300    QuartOut,
301    QuartInOut,
302    QuintIn,
303    QuintOut,
304    QuintInOut,
305    SineIn,
306    SineOut,
307    SineInOut,
308    ExpoIn,
309    ExpoOut,
310    ExpoInOut,
311    CircIn,
312    CircOut,
313    CircInOut,
314    ElasticIn,
315    ElasticOut,
316    ElasticInOut,
317    BackIn,
318    BackOut,
319    BackInOut,
320    BounceIn,
321    BounceOut,
322    BounceInOut,
323}
324
325/// Returns the easing function with the given [name].
326///
327/// [name] can be an [EasingFunction] or a [String] specifying the name of one
328/// of the easing functions defined above.
329pub fn get_easing(etype: Easing) -> EasingFunction {
330    match etype {
331        Easing::Linear => linear,
332        Easing::QuadIn => quad_in,
333        Easing::QuadOut => quad_out,
334        Easing::QuadInOut => quad_in_out,
335        Easing::CubicIn => cubic_in,
336        Easing::CubicOut => cubic_out,
337        Easing::CubicInOut => cubic_in_out,
338        Easing::QuartIn => quart_in,
339        Easing::QuartOut => quart_out,
340        Easing::QuartInOut => quad_in_out,
341        Easing::QuintIn => quint_in,
342        Easing::QuintOut => quint_out,
343        Easing::QuintInOut => quint_in_out,
344        Easing::SineIn => sine_in,
345        Easing::SineOut => sine_out,
346        Easing::SineInOut => sine_in_out,
347        Easing::ExpoIn => expo_in,
348        Easing::ExpoOut => expo_out,
349        Easing::ExpoInOut => expo_in_out,
350        Easing::CircIn => circ_in,
351        Easing::CircOut => circ_out,
352        Easing::CircInOut => circ_in_out,
353        Easing::ElasticIn => elastic_in,
354        Easing::ElasticOut => elastic_out,
355        Easing::ElasticInOut => elastic_in_out,
356        Easing::BackIn => back_in,
357        Easing::BackOut => back_out,
358        Easing::BackInOut => back_out,
359        Easing::BounceIn => bounce_in,
360        Easing::BounceOut => bounce_out,
361        Easing::BounceInOut => bounce_in_out,
362    }
363}