cosmic_time/
lib.rs

1//! An animation toolkit for [Iced](https://github.com/iced-rs/iced)
2//!
3//! > This Project was build for [Cosmic DE](https://github.com/pop-os/cosmic-epoch). Though this will work for any project that depends on [Iced](https://github.com/iced-rs/iced).
4//!
5//!
6//!  The goal of this project is to provide a simple API to build and show
7//!  complex animations efficiently in applications built with Iced-rs/Iced.
8//!
9//! # Project Goals:
10//! * Full compatibility with Iced and The Elm Architecture.
11//! * Ease of use.
12//! * No math required for any animation.
13//! * No heap allocations in render loop.
14//! * Provide additional animatable widgets.
15//! * Custom widget support (create your own!).
16//!
17//! # Overview
18//! To wire cosmic-time into Iced there are five steps to do.
19//!
20//! 1. Create a [`Timeline`] This is the type that controls the animations.
21//! ```ignore
22//! struct Counter {
23//!       timeline: Timeline
24//! }
25//!
26//! // ~ SNIP
27//!
28//! impl Application for Counter {
29//!     // ~ SNIP
30//!      fn new(_flags: ()) -> (Self, Command<Message>) {
31//!         (Self { timeline: Timeline::new()}, Command::none())
32//!      }
33//! }
34//! ```
35//! 2. Add at least one animation to your timeline. This can be done in your
36//!    Application's `new()` or `update()`, or both!
37//! ```ignore
38//! static CONTAINER: Lazy<id::Container> = Lazy::new(id::Container::unique);
39//!
40//! let animation = chain![
41//!   CONTAINER,
42//!   container(Duration::ZERO).width(10),
43//!   container(Duration::from_secs(10)).width(100)
44//! ];
45//! self.timeline.set_chain(animation).start();
46//!
47//! ```
48//! There are some different things here!
49//!   > static CONTAINER: Lazy<id::Container> = Lazy::new(id::Container::unique);
50//!
51//!   Cosmic Time refers to each animation with an Id. We export our own, but they are
52//!   Identical to the widget Id's Iced uses for widget operations.
53//!   Each animatable widget needs an Id. And each Id can only refer to one animation.
54//!
55//!   > let animation = chain![
56//!
57//!   Cosmic Time refers to animations as [`Chain`]s because of how we build then.
58//!   Each Keyframe is linked together like a chain. The Cosmic Time API doesn't
59//!   say "change your width from 10 to 100". We define each state we want the
60//!   widget to have `.width(10)` at `Duration::ZERO` then `.width(100)` at
61//!   `Duration::from_secs(10)`. Where the `Duration` is the time after the previous
62//!   keyframe. This is why we call the animations chains. We cannot get to the
63//!   next state without animating though all previous Keyframes.
64//!
65//!   > self.timeline.set_chain(animation).start();
66//!
67//!   Then we need to add the animation to the [`Timeline`]. We call this `.set_chain`,
68//!   because there can only be one chain per Id.
69//!   If we `set_chain` with a different animation with the same Id, the first one is
70//!   replaced. This a actually a feature not a bug!
71//!   As well you can set multiple animations at once:
72//!   `self.timeline.set_chain(animation1).set_chain(animation2).start()`
73//!
74//!   > .start()
75//!
76//!   This one function call is important enough that we should look at it specifically.
77//!   Cosmic Time is atomic, given the animation state held in the [`Timeline`] at any
78//!   given time the global animations will be the exact same. The value used to
79//!   calculate any animation's interpolation is global. And we use `.start()` to
80//!   sync them together.
81//!   Say you have two 5 seconds animations running at the same time. They should end
82//!   at the same time right? That all depends on when the widget thinks it's animation
83//!   should start. `.start()` tells all pending animations to start at the moment that
84//!   `.start()` is called. This guarantees they stay in sync.
85//!   IMPORTANT! Be sure to only call `.start()` once per call to `update()`.
86//!   The below is incorrect!
87//!   ```ignore
88//!   self.timeline.set_chain(animation1).start();
89//!   self.timeline.set_chain(animation2).start();
90//!   ```
91//!   That code will compile, but will result in the animations not being in sync.
92//!
93//! 3. Add the Cosmic time Subscription
94//! ```ignore
95//!   fn subscription(&self) -> Subscription<Message> {
96//!        self.timeline.as_subscription::<Event>().map(Message::Tick)
97//!    }
98//! ```
99//!
100//! 4. Map the subscription to update the timeline's state:
101//! ```ignore
102//! fn update(&mut self, message: Message) -> Command<Message> {
103//!        match message {
104//!            Message::Tick(now) => self.timeline.now(now),
105//!        }
106//!    }
107//! ```
108//!   If you skip this step your animations will not progress!
109//!
110//! 5. Show the widget in your `view()`!
111//! ```ignore
112//! anim!(CONTIANER, &self.timeline, contents)
113//! ```
114//!
115//! All done!
116//! There is a bit of wiring to get Cosmic Time working, but after that it's only
117//! a few lines to create rather complex animations!
118//! See the Pong example to see how a full game of pong can be implemented in
119//! only a few lines!
120#![deny(
121    missing_debug_implementations,
122    missing_docs,
123    unused_results,
124    clippy::extra_unused_lifetimes,
125    clippy::from_over_into,
126    clippy::needless_borrow,
127    clippy::new_without_default,
128    clippy::useless_conversion
129)]
130#![forbid(unsafe_code, rust_2018_idioms)]
131#![allow(clippy::inherent_to_string, clippy::type_complexity)]
132#![cfg_attr(docsrs, feature(doc_cfg))]
133/// The main timeline for your animations!
134pub mod timeline;
135/// Additional Widgets that Cosmic Time uses for more advanced animations.
136pub mod widget;
137
138mod keyframes;
139
140pub use crate::keyframes::{
141    button, column, container, id, lazy, row, space, style_button, style_container,
142};
143pub use crate::timeline::{Chain, Timeline};
144
145pub use iced::time::{Duration, Instant};
146
147const PI: f32 = std::f32::consts::PI;
148
149/// A simple linear interpolation calculation function.
150/// p = percent_complete in decimal form
151pub fn lerp(start: f32, end: f32, p: f32) -> f32 {
152    (1.0 - p) * start + p * end
153}
154
155/// A simple animation percentage flip calculation function.
156pub fn flip(num: f32) -> f32 {
157    1.0 - num
158}
159
160/// A trait that all ease's need to implement to be used.
161pub trait Tween: std::fmt::Debug + Copy {
162    /// Takes a linear percentage, and returns tweened value.
163    /// p = percent complete as decimal
164    fn tween(&self, p: f32) -> f32;
165}
166
167/// Speed Controlled Animation use this type.
168/// Rather than specifying the time (`Duration`)
169/// between links in the animation chain, this
170/// type auto-calculates the time for you.
171/// Very useful with lazy keyframes.
172/// Designed to have an API very similar to std::time::Duration
173#[derive(Debug, Copy, Clone)]
174pub enum Speed {
175    /// Whole number of seconds to move per second.
176    PerSecond(f32),
177    /// Whole number of millisseconds to move per millisecond.
178    PerMillis(f32),
179    /// Whole number of microseconds to move per microseconds.
180    PerMicros(f32),
181    /// Whole number of nanoseconds to move per nanosecond.
182    PerNanoSe(f32),
183}
184
185impl Speed {
186    /// Creates a new `Speed` from the specified number of whole seconds.
187    pub fn per_secs(speed: f32) -> Self {
188        Speed::PerSecond(speed)
189    }
190
191    /// Creates a new `Speed` from the specified number of whole milliseconds.
192    pub fn per_millis(speed: f32) -> Self {
193        Speed::PerMillis(speed)
194    }
195
196    /// Creates a new `Speed` from the specified number of whole microseconds.
197    pub fn per_micros(speed: f32) -> Self {
198        Speed::PerMicros(speed)
199    }
200
201    /// Creates a new `Speed` from the specified number of whole nanoseconds.
202    pub fn per_nanos(speed: f32) -> Self {
203        Speed::PerNanoSe(speed)
204    }
205
206    fn calc_duration(self, first: f32, second: f32) -> Duration {
207        match self {
208            Speed::PerSecond(speed) => {
209                ((first - second).abs() / speed).round() as u32 * Duration::from_nanos(1e9 as u64)
210            }
211            Speed::PerMillis(speed) => {
212                ((first - second).abs() / speed).round() as u32 * Duration::from_nanos(1e6 as u64)
213            }
214            Speed::PerMicros(speed) => {
215                ((first - second).abs() / speed).round() as u32 * Duration::from_nanos(1000)
216            }
217            Speed::PerNanoSe(speed) => {
218                ((first - second).abs() / speed).round() as u32 * Duration::from_nanos(1)
219            }
220        }
221    }
222}
223
224/// A container type so that the API user can specify Either
225/// Time controlled animations, or speed controlled animations.
226#[derive(Debug, Copy, Clone)]
227pub enum MovementType {
228    /// Keyframe is time controlled.
229    Duration(Duration),
230    /// keyframe is speed controlled.
231    Speed(Speed),
232}
233
234impl From<Duration> for MovementType {
235    fn from(duration: Duration) -> Self {
236        MovementType::Duration(duration)
237    }
238}
239
240impl From<Speed> for MovementType {
241    fn from(speed: Speed) -> Self {
242        MovementType::Speed(speed)
243    }
244}
245
246macro_rules! tween {
247    ($($x:ident),*) => {
248        #[derive(Debug, Copy, Clone)]
249        /// A container type for all types of animations easings.
250        pub enum Ease {
251            $(
252                /// A container for $x
253                $x($x),
254            )*
255        }
256
257        impl Tween for Ease {
258            fn tween(&self, p: f32) -> f32 {
259                match self {
260                    $(
261                        Ease::$x(ease) => ease.tween(p),
262                    )*
263                }
264            }
265        }
266    };
267}
268
269tween!(
270    Linear,
271    Quadratic,
272    Cubic,
273    Quartic,
274    Quintic,
275    Sinusoidal,
276    Exponential,
277    Circular,
278    Elastic,
279    Back,
280    Bounce
281);
282
283/// Used to set a linear animation easing.
284/// The default for most animations.
285#[derive(Debug, Copy, Clone)]
286pub enum Linear {
287    /// Modeled after the line y = x
288    InOut,
289}
290
291impl Tween for Linear {
292    fn tween(&self, p: f32) -> f32 {
293        p
294    }
295}
296
297impl From<Linear> for Ease {
298    fn from(linear: Linear) -> Self {
299        Ease::Linear(linear)
300    }
301}
302
303/// Used to set a quadratic animation easing.
304#[derive(Debug, Copy, Clone)]
305pub enum Quadratic {
306    /// Modeled after the parabola y = x^2
307    In,
308    /// Modeled after the parabola y = -x^2 + 2x
309    Out,
310    /// Modeled after the piecewise quadratic
311    /// y = (1/2)((2x)^2)             ; [0, 0.5)
312    /// y = -(1/2)((2x-1)*(2x-3) - 1) ; [0.5, 1]
313    InOut,
314    /// A Bezier Curve TODO
315    Bezier(i32),
316}
317
318impl Tween for Quadratic {
319    fn tween(&self, p: f32) -> f32 {
320        match self {
321            Quadratic::In => p.powi(2),
322            Quadratic::Out => -(p * (p - 2.)),
323            Quadratic::InOut => {
324                if p < 0.5 {
325                    2. * p.powi(2)
326                } else {
327                    (-2. * p.powi(2)) + p.mul_add(4., -1.)
328                }
329            }
330            Quadratic::Bezier(_n) => p,
331        }
332    }
333}
334
335impl From<Quadratic> for Ease {
336    fn from(quadratic: Quadratic) -> Self {
337        Ease::Quadratic(quadratic)
338    }
339}
340
341/// Used to set a cubic animation easing.
342#[derive(Debug, Copy, Clone)]
343pub enum Cubic {
344    /// Modeled after the cubic y = x^3
345    In,
346    /// Modeled after the cubic y = (x-1)^3 + 1
347    Out,
348    /// Modeled after the piecewise cubic
349    /// y = (1/2)((2x)^3)       ; [0, 0.5]
350    /// y = (1/2)((2x-2)^3 + 2) ; [0.5, 1]
351    InOut,
352}
353
354impl Tween for Cubic {
355    fn tween(&self, p: f32) -> f32 {
356        match self {
357            Cubic::In => p.powi(3),
358            Cubic::Out => {
359                let q = p - 1.;
360                q.powi(3) + 1.
361            }
362            Cubic::InOut => {
363                if p < 0.5 {
364                    4. * p.powi(3)
365                } else {
366                    let q = p.mul_add(2., -2.);
367                    (q.powi(3)).mul_add(0.5, 1.)
368                }
369            }
370        }
371    }
372}
373
374impl From<Cubic> for Ease {
375    fn from(cubic: Cubic) -> Self {
376        Ease::Cubic(cubic)
377    }
378}
379
380/// Used to set a quartic animation easing.
381#[derive(Debug, Copy, Clone)]
382pub enum Quartic {
383    /// Modeled after the quartic y = x^4
384    In,
385    /// Modeled after the quartic y = 1 - (x - 1)^4
386    Out,
387    /// Modeled after the piecewise quartic
388    /// y = (1/2)((2x)^4)       ; [0, 0.5]
389    /// y = -(1/2)((2x-2)^4 -2) ; [0.5, 1]
390    InOut,
391}
392
393impl Tween for Quartic {
394    fn tween(&self, p: f32) -> f32 {
395        match self {
396            Quartic::In => p.powi(4),
397            Quartic::Out => {
398                let q = p - 1.;
399                (q.powi(3)).mul_add(1. - p, 1.)
400            }
401            Quartic::InOut => {
402                if p < 0.5 {
403                    8. * p.powi(4)
404                } else {
405                    let q = p - 1.;
406                    (q.powi(4)).mul_add(-8., 1.)
407                }
408            }
409        }
410    }
411}
412
413impl From<Quartic> for Ease {
414    fn from(quartic: Quartic) -> Self {
415        Ease::Quartic(quartic)
416    }
417}
418
419/// Used to set a quintic animation easing.
420#[derive(Debug, Copy, Clone)]
421pub enum Quintic {
422    /// Modeled after the quintic y = x^5
423    In,
424    /// Modeled after the quintic y = (x - 1)^5 + 1
425    Out,
426    /// Modeled after the piecewise quintic
427    /// y = (1/2)((2x)^5)       ; [0, 0.5]
428    /// y = (1/2)((2x-2)^5 + 2) ; [0.5, 1]
429    InOut,
430}
431
432impl Tween for Quintic {
433    fn tween(&self, p: f32) -> f32 {
434        match self {
435            Quintic::In => p.powi(5),
436            Quintic::Out => {
437                let q = p - 1.;
438                q.powi(5) + 1.
439            }
440            Quintic::InOut => {
441                if p < 0.5 {
442                    16. * p.powi(5)
443                } else {
444                    let q = (2. * p) - 2.;
445                    q.powi(5).mul_add(0.5, 1.)
446                }
447            }
448        }
449    }
450}
451
452impl From<Quintic> for Ease {
453    fn from(quintic: Quintic) -> Self {
454        Ease::Quintic(quintic)
455    }
456}
457
458/// Used to set a sinusoildal animation easing.
459#[derive(Debug, Copy, Clone)]
460pub enum Sinusoidal {
461    /// Modeled after eighth sinusoidal wave y = 1 - cos((x * PI) / 2)
462    In,
463    /// Modeled after eigth sinusoidal wave y = sin((x * PI) / 2)
464    Out,
465    /// Modeled after quarter sinusoidal wave y = -0.5 * (cos(x * PI) - 1);
466    InOut,
467}
468
469impl Tween for Sinusoidal {
470    fn tween(&self, p: f32) -> f32 {
471        match self {
472            Sinusoidal::In => 1. - ((p * PI) / 2.).cos(),
473            Sinusoidal::Out => ((p * PI) / 2.).sin(),
474            Sinusoidal::InOut => -0.5 * ((p * PI).cos() - 1.),
475        }
476    }
477}
478
479impl From<Sinusoidal> for Ease {
480    fn from(sinusoidal: Sinusoidal) -> Self {
481        Ease::Sinusoidal(sinusoidal)
482    }
483}
484
485/// Used to set an exponential animation easing.
486#[derive(Debug, Copy, Clone)]
487pub enum Exponential {
488    /// Modeled after the piecewise exponential
489    /// y = 0            ; [0, 0]
490    /// y = 2^(10x-10)   ; [0, 1]
491    In,
492    /// Modeled after the piecewise exponential
493    /// y = 1 - 2^(-10x)  ; [0, 1]
494    /// y = 1             ; [1, 1]
495    Out,
496    /// Modeled after the piecewise exponential
497    /// y = 0                        ; [0, 0  ]
498    /// y = 2^(20x - 10) / 2         ; [0, 0.5]
499    /// y = 1 - 0.5*2^(-10(2x - 1))  ; [0.5, 1]
500    /// y = 1                        ; [1, 1  ]
501    InOut,
502}
503
504impl Tween for Exponential {
505    fn tween(&self, p: f32) -> f32 {
506        match self {
507            Exponential::In => {
508                if p == 0. {
509                    0.
510                } else {
511                    2_f32.powf(10. * p - 10.)
512                }
513            }
514            Exponential::Out => {
515                if p == 1. {
516                    1.
517                } else {
518                    1. - 2_f32.powf(-10. * p)
519                }
520            }
521            Exponential::InOut => {
522                if p == 0. {
523                    0.
524                } else if p == 1. {
525                    1.
526                } else if p < 0.5 {
527                    2_f32.powf(p.mul_add(20., -10.)) * 0.5
528                } else {
529                    2_f32.powf(p.mul_add(-20., 10.)).mul_add(-0.5, 1.)
530                }
531            }
532        }
533    }
534}
535
536impl From<Exponential> for Ease {
537    fn from(exponential: Exponential) -> Self {
538        Ease::Exponential(exponential)
539    }
540}
541
542/// Used to set an circular animation easing.
543#[derive(Debug, Copy, Clone)]
544pub enum Circular {
545    /// Modeled after shifted quadrant IV of unit circle. y = 1 - sqrt(1 - x^2)
546    In,
547    /// Modeled after shifted quadrant II of unit circle. y = sqrt(1 - (x - 1)^ 2)
548    Out,
549    /// Modeled after the piecewise circular function
550    /// y = (1/2)(1 - sqrt(1 - 2x^2))           ; [0, 0.5)
551    /// y = (1/2)(sqrt(1 - ((-2x + 2)^2)) + 1) ; [0.5, 1]
552    InOut,
553}
554
555impl Tween for Circular {
556    fn tween(&self, p: f32) -> f32 {
557        match self {
558            Circular::In => 1.0 - (1. - (p.powi(2))).sqrt(),
559            Circular::Out => ((2. - p) * p).sqrt(),
560            Circular::InOut => {
561                if p < 0.5 {
562                    0.5 * (1. - (1. - (2. * p).powi(2)).sqrt())
563                } else {
564                    0.5 * ((1. - (-2. * p + 2.).powi(2)).sqrt() + 1.)
565                }
566            }
567        }
568    }
569}
570
571impl From<Circular> for Ease {
572    fn from(circular: Circular) -> Self {
573        Ease::Circular(circular)
574    }
575}
576
577/// Used to set an elastic animation easing.
578#[derive(Debug, Copy, Clone)]
579pub enum Elastic {
580    /// Modeled after damped sin wave: y = sin(13×π/2 x)×2^(10 (x - 1))
581    In,
582    /// Modeled after damped piecewise sin wave:
583    /// y = 2^(-10 x) sin((x×10 - 0.75) (2×π/3)) + 1 [0, 1]
584    /// y = 1 [1, 1]
585    Out,
586    /// Modeled after the piecewise exponentially-damped sine wave:
587    /// y = 2^(10 (2 x - 1) - 1) sin(13 π x) [0, 0.5]
588    /// y = 1/2 (2 - 2^(-10 (2 x - 1)) sin(13 π x)) [0.5, 1]
589    InOut,
590}
591
592impl Tween for Elastic {
593    fn tween(&self, p: f32) -> f32 {
594        match self {
595            Elastic::In => (13. * (PI / 2.) * p).sin() * 2_f32.powf(10. * (p - 1.)),
596            Elastic::Out => {
597                if p == 1. {
598                    1.
599                } else {
600                    2_f32.powf(-10. * p) * ((10. * p - 0.75) * ((2. * PI) / 3.)).sin() + 1.
601                }
602            }
603            Elastic::InOut => {
604                if p < 0.5 {
605                    2_f32.powf(10. * (2. * p - 1.) - 1.) * (13. * PI * p).sin()
606                } else {
607                    0.5 * (2. - 2_f32.powf(-20. * p + 10.) * (13. * PI * p).sin())
608                }
609            }
610        }
611    }
612}
613
614impl From<Elastic> for Ease {
615    fn from(elastic: Elastic) -> Self {
616        Ease::Elastic(elastic)
617    }
618}
619
620/// Used to set a back animation easing.
621#[derive(Debug, Copy, Clone)]
622pub enum Back {
623    /// Modeled after the function: y = 2.70158 * x^3 + x^2 * (-1.70158)
624    In,
625    /// Modeled after the function: y = 1 + 2.70158 (x - 1)^3 + 1.70158 (x - 1)^2
626    Out,
627    /// Modeled after the piecewise function:
628    /// y = (2x)^2 * (1/2 * ((2.5949095 + 1) * 2x - 2.5949095)) [0, 0.5]
629    /// y = 1/2 * ((2 x - 2)^2 * ((2.5949095 + 1) * (2x - 2) + 2.5949095) + 2) [0.5, 1]
630    InOut,
631}
632
633impl Tween for Back {
634    fn tween(&self, p: f32) -> f32 {
635        match self {
636            Back::In => 2.70158 * p.powi(3) - 1.70158 * p.powi(2),
637            Back::Out => {
638                let q: f32 = p - 1.;
639                1. + 2.70158 * q.powi(3) + 1.70158 * q.powi(2)
640            }
641            Back::InOut => {
642                let c = 2.5949095;
643                if p < 0.5 {
644                    let q = 2. * p;
645                    q.powi(2) * (0.5 * ((c + 1.) * q - c))
646                } else {
647                    let q = 2. * p - 2.;
648                    0.5 * (q.powi(2) * ((c + 1.) * q + c) + 2.)
649                }
650            }
651        }
652    }
653}
654
655impl From<Back> for Ease {
656    fn from(back: Back) -> Self {
657        Ease::Back(back)
658    }
659}
660
661/// Used to set a bounce animation easing.
662#[derive(Debug, Copy, Clone)]
663pub enum Bounce {
664    /// Bounce before animating in.
665    In,
666    /// Bounce against end point.
667    Out,
668    /// Bounce before animating in, then against the end point.
669    InOut,
670}
671
672impl Bounce {
673    fn bounce_ease_in(p: f32) -> f32 {
674        1. - Bounce::bounce_ease_out(1. - p)
675    }
676
677    fn bounce_ease_out(p: f32) -> f32 {
678        if p < 4. / 11. {
679            (121. * p.powi(2)) / 16.
680        } else if p < 8. / 11. {
681            (363. / 40. * p.powi(2)) - 99. / 10. * p + 17. / 5.
682        } else if p < 9. / 10. {
683            4356. / 361. * p.powi(2) - 35442. / 1805. * p + 16061. / 1805.
684        } else {
685            54. / 5. * p.powi(2) - 513. / 25. * p + 268. / 25.
686        }
687    }
688}
689
690impl Tween for Bounce {
691    fn tween(&self, p: f32) -> f32 {
692        match self {
693            Bounce::In => Bounce::bounce_ease_in(p),
694            Bounce::Out => Bounce::bounce_ease_out(p),
695            Bounce::InOut => {
696                if p < 0.5 {
697                    0.5 * Bounce::bounce_ease_in(p * 2.)
698                } else {
699                    0.5 + 0.5 * Bounce::bounce_ease_out(p * 2. - 1.)
700                }
701            }
702        }
703    }
704}
705
706impl From<Bounce> for Ease {
707    fn from(bounce: Bounce) -> Self {
708        Ease::Bounce(bounce)
709    }
710}
711
712#[cfg(test)]
713mod test {
714    #![allow(clippy::excessive_precision)]
715    use super::*;
716
717    fn r(val: f32) -> f32 {
718        (val * 10E+5).round() / 10E+5
719    }
720
721    #[test]
722    fn linear() {
723        assert_eq!(0.0, Linear::InOut.tween(0.0));
724        assert_eq!(0.1, Linear::InOut.tween(0.1));
725        assert_eq!(0.2, Linear::InOut.tween(0.2));
726        assert_eq!(0.3, Linear::InOut.tween(0.3));
727        assert_eq!(0.4, Linear::InOut.tween(0.4));
728        assert_eq!(0.5, Linear::InOut.tween(0.5));
729        assert_eq!(0.6, Linear::InOut.tween(0.6));
730        assert_eq!(0.7, Linear::InOut.tween(0.7));
731        assert_eq!(0.8, Linear::InOut.tween(0.8));
732        assert_eq!(0.9, Linear::InOut.tween(0.9));
733        assert_eq!(1.0, Linear::InOut.tween(1.0));
734    }
735
736    #[test]
737    // Modeled after the parabola y = x^2
738    fn quadratic_in() {
739        assert_eq!(0.00, r(Quadratic::In.tween(0.0)));
740        assert_eq!(0.01, r(Quadratic::In.tween(0.1)));
741        assert_eq!(0.04, r(Quadratic::In.tween(0.2)));
742        assert_eq!(0.09, r(Quadratic::In.tween(0.3)));
743        assert_eq!(0.16, r(Quadratic::In.tween(0.4)));
744        assert_eq!(0.25, r(Quadratic::In.tween(0.5)));
745        assert_eq!(0.36, r(Quadratic::In.tween(0.6)));
746        assert_eq!(0.49, r(Quadratic::In.tween(0.7)));
747        assert_eq!(0.64, r(Quadratic::In.tween(0.8)));
748        assert_eq!(0.81, r(Quadratic::In.tween(0.9)));
749        assert_eq!(1.00, r(Quadratic::In.tween(1.0)));
750    }
751
752    #[test]
753    // Modeled after the parabola y = -x^2 + 2x
754    fn quadratic_out() {
755        assert_eq!(0.00, r(Quadratic::Out.tween(0.0)));
756        assert_eq!(0.19, r(Quadratic::Out.tween(0.1)));
757        assert_eq!(0.36, r(Quadratic::Out.tween(0.2)));
758        assert_eq!(0.51, r(Quadratic::Out.tween(0.3)));
759        assert_eq!(0.64, r(Quadratic::Out.tween(0.4)));
760        assert_eq!(0.75, r(Quadratic::Out.tween(0.5)));
761        assert_eq!(0.84, r(Quadratic::Out.tween(0.6)));
762        assert_eq!(0.91, r(Quadratic::Out.tween(0.7)));
763        assert_eq!(0.96, r(Quadratic::Out.tween(0.8)));
764        assert_eq!(0.99, r(Quadratic::Out.tween(0.9)));
765        assert_eq!(1.00, r(Quadratic::Out.tween(1.0)));
766    }
767
768    #[test]
769    // Modeled after the piecewise quadratic
770    // y = (1/2)((2x)^2)             ; [0, 0.5)
771    // y = -(1/2)((2x-1)*(2x-3) - 1) ; [0.5, 1]
772    fn quadratic_inout() {
773        assert_eq!(0.00, r(Quadratic::InOut.tween(0.0)));
774        assert_eq!(0.02, r(Quadratic::InOut.tween(0.1)));
775        assert_eq!(0.08, r(Quadratic::InOut.tween(0.2)));
776        assert_eq!(0.18, r(Quadratic::InOut.tween(0.3)));
777        assert_eq!(0.32, r(Quadratic::InOut.tween(0.4)));
778        assert_eq!(0.50, r(Quadratic::InOut.tween(0.5)));
779        assert_eq!(0.68, r(Quadratic::InOut.tween(0.6)));
780        assert_eq!(0.82, r(Quadratic::InOut.tween(0.7)));
781        assert_eq!(0.92, r(Quadratic::InOut.tween(0.8)));
782        assert_eq!(0.98, r(Quadratic::InOut.tween(0.9)));
783        assert_eq!(1.00, r(Quadratic::InOut.tween(1.0)));
784    }
785
786    // TODO Bezier
787
788    #[test]
789    // Modeled after the cubic y = x^3
790    fn cubic_in() {
791        assert_eq!(0.000, r(Cubic::In.tween(0.0)));
792        assert_eq!(0.001, r(Cubic::In.tween(0.1)));
793        assert_eq!(0.008, r(Cubic::In.tween(0.2)));
794        assert_eq!(0.027, r(Cubic::In.tween(0.3)));
795        assert_eq!(0.064, r(Cubic::In.tween(0.4)));
796        assert_eq!(0.125, r(Cubic::In.tween(0.5)));
797        assert_eq!(0.216, r(Cubic::In.tween(0.6)));
798        assert_eq!(0.343, r(Cubic::In.tween(0.7)));
799        assert_eq!(0.512, r(Cubic::In.tween(0.8)));
800        assert_eq!(0.729, r(Cubic::In.tween(0.9)));
801        assert_eq!(1.000, r(Cubic::In.tween(1.0)));
802    }
803
804    #[test]
805    // Modeled after the cubic y = (x-1)^3 + 1
806    fn cubic_out() {
807        assert_eq!(0.000, r(Cubic::Out.tween(0.0)));
808        assert_eq!(0.271, r(Cubic::Out.tween(0.1)));
809        assert_eq!(0.488, r(Cubic::Out.tween(0.2)));
810        assert_eq!(0.657, r(Cubic::Out.tween(0.3)));
811        assert_eq!(0.784, r(Cubic::Out.tween(0.4)));
812        assert_eq!(0.875, r(Cubic::Out.tween(0.5)));
813        assert_eq!(0.936, r(Cubic::Out.tween(0.6)));
814        assert_eq!(0.973, r(Cubic::Out.tween(0.7)));
815        assert_eq!(0.992, r(Cubic::Out.tween(0.8)));
816        assert_eq!(0.999, r(Cubic::Out.tween(0.9)));
817        assert_eq!(1.000, r(Cubic::Out.tween(1.0)));
818    }
819
820    #[test]
821    // Modeled after the piecewise cubic
822    // y = (1/2)((2x)^3)       ; [0, 0.5]
823    // y = (1/2)((2x-2)^3 + 2) ; [0.5, 1]
824    fn cubic_inout() {
825        assert_eq!(0.000, r(Cubic::InOut.tween(0.0)));
826        assert_eq!(0.004, r(Cubic::InOut.tween(0.1)));
827        assert_eq!(0.032, r(Cubic::InOut.tween(0.2)));
828        assert_eq!(0.108, r(Cubic::InOut.tween(0.3)));
829        assert_eq!(0.256, r(Cubic::InOut.tween(0.4)));
830        assert_eq!(0.500, r(Cubic::InOut.tween(0.5)));
831        assert_eq!(0.744, r(Cubic::InOut.tween(0.6)));
832        assert_eq!(0.892, r(Cubic::InOut.tween(0.7)));
833        assert_eq!(0.968, r(Cubic::InOut.tween(0.8)));
834        assert_eq!(0.996, r(Cubic::InOut.tween(0.9)));
835        assert_eq!(1.000, r(Cubic::InOut.tween(1.0)));
836    }
837
838    #[test]
839    // Modeled after the quartic y = x^4
840    fn quartic_in() {
841        assert_eq!(0.0000, r(Quartic::In.tween(0.0)));
842        assert_eq!(0.0001, r(Quartic::In.tween(0.1)));
843        assert_eq!(0.0016, r(Quartic::In.tween(0.2)));
844        assert_eq!(0.0081, r(Quartic::In.tween(0.3)));
845        assert_eq!(0.0256, r(Quartic::In.tween(0.4)));
846        assert_eq!(0.0625, r(Quartic::In.tween(0.5)));
847        assert_eq!(0.1296, r(Quartic::In.tween(0.6)));
848        assert_eq!(0.2401, r(Quartic::In.tween(0.7)));
849        assert_eq!(0.4096, r(Quartic::In.tween(0.8)));
850        assert_eq!(0.6561, r(Quartic::In.tween(0.9)));
851        assert_eq!(1.0000, r(Quartic::In.tween(1.0)));
852    }
853
854    #[test]
855    // Modeled after the quartic y = 1 - (x - 1)^4
856    fn quartic_out() {
857        assert_eq!(0.0000, r(Quartic::Out.tween(0.0)));
858        assert_eq!(0.3439, r(Quartic::Out.tween(0.1)));
859        assert_eq!(0.5904, r(Quartic::Out.tween(0.2)));
860        assert_eq!(0.7599, r(Quartic::Out.tween(0.3)));
861        assert_eq!(0.8704, r(Quartic::Out.tween(0.4)));
862        assert_eq!(0.9375, r(Quartic::Out.tween(0.5)));
863        assert_eq!(0.9744, r(Quartic::Out.tween(0.6)));
864        assert_eq!(0.9919, r(Quartic::Out.tween(0.7)));
865        assert_eq!(0.9984, r(Quartic::Out.tween(0.8)));
866        assert_eq!(0.9999, r(Quartic::Out.tween(0.9)));
867        assert_eq!(1.0000, r(Quartic::Out.tween(1.0)));
868    }
869
870    #[test]
871    // Modeled after the piecewise quartic
872    // y = (1/2)((2x)^4)       ; [0, 0.5]
873    // y = -(1/2)((2x-2)^4 -2) ; [0.5, 1]
874    fn quartic_inout() {
875        assert_eq!(0.0000, r(Quartic::InOut.tween(0.0)));
876        assert_eq!(0.0008, r(Quartic::InOut.tween(0.1)));
877        assert_eq!(0.0128, r(Quartic::InOut.tween(0.2)));
878        assert_eq!(0.0648, r(Quartic::InOut.tween(0.3)));
879        assert_eq!(0.2048, r(Quartic::InOut.tween(0.4)));
880        assert_eq!(0.5000, r(Quartic::InOut.tween(0.5)));
881        assert_eq!(0.7952, r(Quartic::InOut.tween(0.6)));
882        assert_eq!(0.9352, r(Quartic::InOut.tween(0.7)));
883        assert_eq!(0.9872, r(Quartic::InOut.tween(0.8)));
884        assert_eq!(0.9992, r(Quartic::InOut.tween(0.9)));
885        assert_eq!(1.0000, r(Quartic::InOut.tween(1.0)));
886    }
887
888    #[test]
889    // Modeled after the quartic y = x^5
890    fn quintic_in() {
891        assert_eq!(0.00000, r(Quintic::In.tween(0.0)));
892        assert_eq!(0.00001, r(Quintic::In.tween(0.1)));
893        assert_eq!(0.00032, r(Quintic::In.tween(0.2)));
894        assert_eq!(0.00243, r(Quintic::In.tween(0.3)));
895        assert_eq!(0.01024, r(Quintic::In.tween(0.4)));
896        assert_eq!(0.03125, r(Quintic::In.tween(0.5)));
897        assert_eq!(0.07776, r(Quintic::In.tween(0.6)));
898        assert_eq!(0.16807, r(Quintic::In.tween(0.7)));
899        assert_eq!(0.32768, r(Quintic::In.tween(0.8)));
900        assert_eq!(0.59049, r(Quintic::In.tween(0.9)));
901        assert_eq!(1.00000, r(Quintic::In.tween(1.0)));
902    }
903
904    #[test]
905    // Modeled after the quintic y = (x - 1)^5 + 1
906    fn quintic_out() {
907        assert_eq!(0.00000, r(Quintic::Out.tween(0.0)));
908        assert_eq!(0.40951, r(Quintic::Out.tween(0.1)));
909        assert_eq!(0.67232, r(Quintic::Out.tween(0.2)));
910        assert_eq!(0.83193, r(Quintic::Out.tween(0.3)));
911        assert_eq!(0.92224, r(Quintic::Out.tween(0.4)));
912        assert_eq!(0.96875, r(Quintic::Out.tween(0.5)));
913        assert_eq!(0.98976, r(Quintic::Out.tween(0.6)));
914        assert_eq!(0.99757, r(Quintic::Out.tween(0.7)));
915        assert_eq!(0.99968, r(Quintic::Out.tween(0.8)));
916        assert_eq!(0.99999, r(Quintic::Out.tween(0.9)));
917        assert_eq!(1.00000, r(Quintic::Out.tween(1.0)));
918    }
919
920    #[test]
921    // Modeled after the piecewise quintic
922    // y = (1/2)((2x)^5)       ; [0, 0.5]
923    // y = (1/2)((2x-2)^5 + 2) ; [0.5, 1]
924    fn quintic_inout() {
925        assert_eq!(0.00000, r(Quintic::InOut.tween(0.0)));
926        assert_eq!(0.00016, r(Quintic::InOut.tween(0.1)));
927        assert_eq!(0.00512, r(Quintic::InOut.tween(0.2)));
928        assert_eq!(0.03888, r(Quintic::InOut.tween(0.3)));
929        assert_eq!(0.16384, r(Quintic::InOut.tween(0.4)));
930        assert_eq!(0.50000, r(Quintic::InOut.tween(0.5)));
931        assert_eq!(0.83616, r(Quintic::InOut.tween(0.6)));
932        assert_eq!(0.96112, r(Quintic::InOut.tween(0.7)));
933        assert_eq!(0.99488, r(Quintic::InOut.tween(0.8)));
934        assert_eq!(0.99984, r(Quintic::InOut.tween(0.9)));
935        assert_eq!(1.00000, r(Quintic::InOut.tween(1.0)));
936    }
937
938    #[test]
939    // Modeled after eighth sinusoidal wave y = 1 - cos((x * PI) / 2)
940    fn sinusoidal_in() {
941        assert_eq!(0.000000, r(Sinusoidal::In.tween(0.0)));
942        assert_eq!(0.012312, r(Sinusoidal::In.tween(0.1)));
943        assert_eq!(0.048943, r(Sinusoidal::In.tween(0.2)));
944        assert_eq!(0.108993, r(Sinusoidal::In.tween(0.3)));
945        assert_eq!(0.190983, r(Sinusoidal::In.tween(0.4)));
946        assert_eq!(0.292893, r(Sinusoidal::In.tween(0.5)));
947        assert_eq!(0.412215, r(Sinusoidal::In.tween(0.6)));
948        assert_eq!(0.546010, r(Sinusoidal::In.tween(0.7)));
949        assert_eq!(0.690983, r(Sinusoidal::In.tween(0.8)));
950        assert_eq!(0.843566, r(Sinusoidal::In.tween(0.9)));
951        assert_eq!(1.000000, r(Sinusoidal::In.tween(1.0)));
952    }
953
954    #[test]
955    #[allow(clippy::approx_constant)]
956    // Modeled after eigth sinusoidal wave y = sin((x * PI) / 2)
957    fn sinusoidal_out() {
958        assert_eq!(0.000000, r(Sinusoidal::Out.tween(0.0)));
959        assert_eq!(0.156434, r(Sinusoidal::Out.tween(0.1)));
960        assert_eq!(0.309017, r(Sinusoidal::Out.tween(0.2)));
961        assert_eq!(0.453991, r(Sinusoidal::Out.tween(0.3)));
962        assert_eq!(0.587785, r(Sinusoidal::Out.tween(0.4)));
963        assert_eq!(0.707107, r(Sinusoidal::Out.tween(0.5)));
964        assert_eq!(0.809017, r(Sinusoidal::Out.tween(0.6)));
965        assert_eq!(0.891007, r(Sinusoidal::Out.tween(0.7)));
966        assert_eq!(0.951057, r(Sinusoidal::Out.tween(0.8)));
967        assert_eq!(0.987688, r(Sinusoidal::Out.tween(0.9)));
968        assert_eq!(1.000000, r(Sinusoidal::Out.tween(1.0)));
969    }
970
971    #[test]
972    // Modeled after quarter sinusoidal wave y = -0.5 * (cos(x * PI) - 1);
973    fn sinusoidal_inout() {
974        assert_eq!(0.000000, r(Sinusoidal::InOut.tween(0.0)));
975        assert_eq!(0.024472, r(Sinusoidal::InOut.tween(0.1)));
976        assert_eq!(0.095492, r(Sinusoidal::InOut.tween(0.2)));
977        assert_eq!(0.206107, r(Sinusoidal::InOut.tween(0.3)));
978        assert_eq!(0.345492, r(Sinusoidal::InOut.tween(0.4)));
979        assert_eq!(0.500000, r(Sinusoidal::InOut.tween(0.5)));
980        assert_eq!(0.654509, r(Sinusoidal::InOut.tween(0.6)));
981        assert_eq!(0.793893, r(Sinusoidal::InOut.tween(0.7)));
982        assert_eq!(0.904509, r(Sinusoidal::InOut.tween(0.8)));
983        assert_eq!(0.975528, r(Sinusoidal::InOut.tween(0.9)));
984        assert_eq!(1.000000, r(Sinusoidal::InOut.tween(1.0)));
985    }
986
987    #[test]
988    // Modeled after the piecewise exponential
989    // y = 0            ; [0, 0]
990    // y = 2^(10x-10)   ; [0, 1]
991    fn exponential_in() {
992        assert_eq!(0.000000, r(Exponential::In.tween(0.0)));
993        assert_eq!(0.001953, r(Exponential::In.tween(0.1)));
994        assert_eq!(0.003906, r(Exponential::In.tween(0.2)));
995        assert_eq!(0.007813, r(Exponential::In.tween(0.3)));
996        assert_eq!(0.015625, r(Exponential::In.tween(0.4)));
997        assert_eq!(0.031250, r(Exponential::In.tween(0.5)));
998        assert_eq!(0.062500, r(Exponential::In.tween(0.6)));
999        assert_eq!(0.125000, r(Exponential::In.tween(0.7)));
1000        assert_eq!(0.250000, r(Exponential::In.tween(0.8)));
1001        assert_eq!(0.500000, r(Exponential::In.tween(0.9)));
1002        assert_eq!(1.000000, r(Exponential::In.tween(1.0)));
1003    }
1004
1005    #[test]
1006    // Modeled after the piecewise exponential
1007    // y = 1 - 2^(-10x)  ; [0, 1]
1008    // y = 1             ; [1, 1]
1009    fn exponential_out() {
1010        assert_eq!(0.000000, r(Exponential::Out.tween(0.0)));
1011        assert_eq!(0.500000, r(Exponential::Out.tween(0.1)));
1012        assert_eq!(0.750000, r(Exponential::Out.tween(0.2)));
1013        assert_eq!(0.875000, r(Exponential::Out.tween(0.3)));
1014        assert_eq!(0.937500, r(Exponential::Out.tween(0.4)));
1015        assert_eq!(0.968750, r(Exponential::Out.tween(0.5)));
1016        assert_eq!(0.984375, r(Exponential::Out.tween(0.6)));
1017        assert_eq!(0.992188, r(Exponential::Out.tween(0.7)));
1018        assert_eq!(0.996094, r(Exponential::Out.tween(0.8)));
1019        assert_eq!(0.998047, r(Exponential::Out.tween(0.9)));
1020        assert_eq!(1.000000, r(Exponential::Out.tween(1.0)));
1021    }
1022
1023    #[test]
1024    // Modeled after the piecewise exponential
1025    // y = 0                        ; [0, 0  ]
1026    // y = 2^(20x - 10) / 2         ; [0, 0.5]
1027    // y = 1 - 0.5*2^(-20x + 10))   ; [0.5, 1]
1028    // y = 1                        ; [1, 1  ]
1029    fn exponential_inout() {
1030        assert_eq!(0.000000, r(Exponential::InOut.tween(0.0)));
1031        assert_eq!(0.001953, r(Exponential::InOut.tween(0.1)));
1032        assert_eq!(0.007813, r(Exponential::InOut.tween(0.2)));
1033        assert_eq!(0.031250, r(Exponential::InOut.tween(0.3)));
1034        assert_eq!(0.125000, r(Exponential::InOut.tween(0.4)));
1035        assert_eq!(0.500000, r(Exponential::InOut.tween(0.5)));
1036        assert_eq!(0.875000, r(Exponential::InOut.tween(0.6)));
1037        assert_eq!(0.968750, r(Exponential::InOut.tween(0.7)));
1038        assert_eq!(0.992188, r(Exponential::InOut.tween(0.8)));
1039        assert_eq!(0.998047, r(Exponential::InOut.tween(0.9)));
1040        assert_eq!(1.000000, r(Exponential::InOut.tween(1.0)));
1041    }
1042
1043    #[test]
1044    // Modeled after shifted quadrant IV of unit circle. y = 1 - sqrt(1 - x^2)
1045    fn circular_in() {
1046        assert_eq!(0.000000, r(Circular::In.tween(0.0)));
1047        assert_eq!(0.005013, r(Circular::In.tween(0.1)));
1048        assert_eq!(0.020204, r(Circular::In.tween(0.2)));
1049        assert_eq!(0.046061, r(Circular::In.tween(0.3)));
1050        assert_eq!(0.083485, r(Circular::In.tween(0.4)));
1051        assert_eq!(0.133975, r(Circular::In.tween(0.5)));
1052        assert_eq!(0.200000, r(Circular::In.tween(0.6)));
1053        assert_eq!(0.285857, r(Circular::In.tween(0.7)));
1054        assert_eq!(0.400000, r(Circular::In.tween(0.8)));
1055        assert_eq!(0.564110, r(Circular::In.tween(0.9)));
1056        assert_eq!(1.000000, r(Circular::In.tween(1.0)));
1057    }
1058
1059    #[test]
1060    // Modeled after shifted quadrant II of unit circle. y = sqrt(1 - (x - 1)^ 2)
1061    fn circular_out() {
1062        assert_eq!(0.000000, r(Circular::Out.tween(0.0)));
1063        assert_eq!(0.435890, r(Circular::Out.tween(0.1)));
1064        assert_eq!(0.600000, r(Circular::Out.tween(0.2)));
1065        assert_eq!(0.714143, r(Circular::Out.tween(0.3)));
1066        assert_eq!(0.800000, r(Circular::Out.tween(0.4)));
1067        assert_eq!(0.866025, r(Circular::Out.tween(0.5)));
1068        assert_eq!(0.916515, r(Circular::Out.tween(0.6)));
1069        assert_eq!(0.953939, r(Circular::Out.tween(0.7)));
1070        assert_eq!(0.979796, r(Circular::Out.tween(0.8)));
1071        assert_eq!(0.994987, r(Circular::Out.tween(0.9)));
1072        assert_eq!(1.000000, r(Circular::Out.tween(1.0)));
1073    }
1074
1075    #[test]
1076    // Modeled after the piecewise circular function
1077    // y = (1/2)(1 - sqrt(1 - (2x)^2))          ; [0, 0.5)
1078    // y = (1/2)(sqrt(1 - ((-2x + 2)^2)) + 1) ; [0.5, 1]
1079    fn circular_inout() {
1080        assert_eq!(0.000000, r(Circular::InOut.tween(0.0)));
1081        assert_eq!(0.010102, r(Circular::InOut.tween(0.1)));
1082        assert_eq!(0.041742, r(Circular::InOut.tween(0.2)));
1083        assert_eq!(0.100000, r(Circular::InOut.tween(0.3)));
1084        assert_eq!(0.200000, r(Circular::InOut.tween(0.4)));
1085        assert_eq!(0.500000, r(Circular::InOut.tween(0.5)));
1086        assert_eq!(0.800000, r(Circular::InOut.tween(0.6)));
1087        assert_eq!(0.900000, r(Circular::InOut.tween(0.7)));
1088        assert_eq!(0.958258, r(Circular::InOut.tween(0.8)));
1089        assert_eq!(0.989898, r(Circular::InOut.tween(0.9)));
1090        assert_eq!(1.000000, r(Circular::InOut.tween(1.0)));
1091    }
1092
1093    #[test]
1094    #[rustfmt::skip]
1095    // Modeled after damped sin wave: y = sin(13 * π/2 * x) * 2^(10 (x - 1))
1096    fn elastic_in() {
1097        assert_eq!( 0.000000, r(Elastic::In.tween(0.0)));
1098        assert_eq!( 0.001740, r(Elastic::In.tween(0.1)));
1099        assert_eq!(-0.003160, r(Elastic::In.tween(0.2)));
1100        assert_eq!(-0.001222, r(Elastic::In.tween(0.3)));
1101        assert_eq!( 0.014860, r(Elastic::In.tween(0.4)));
1102        assert_eq!(-0.022097, r(Elastic::In.tween(0.5)));
1103        assert_eq!(-0.019313, r(Elastic::In.tween(0.6)));
1104        assert_eq!( 0.123461, r(Elastic::In.tween(0.7)));
1105        assert_eq!(-0.146947, r(Elastic::In.tween(0.8)));
1106        assert_eq!(-0.226995, r(Elastic::In.tween(0.9)));
1107        assert_eq!( 1.000000, r(Elastic::In.tween(1.0)));
1108    }
1109
1110    #[test]
1111    // Modeled after damped piecewise sin wave:
1112    // y = 1 - 2^(-10 x) sin((13 π)/(2 (x + 1))) ; [0, 1]
1113    // y = 1 [1, 1]
1114    fn elastic_out() {
1115        assert_eq!(0.000000, r(Elastic::Out.tween(0.0)));
1116        assert_eq!(1.250000, r(Elastic::Out.tween(0.1)));
1117        assert_eq!(1.125000, r(Elastic::Out.tween(0.2)));
1118        assert_eq!(0.875000, r(Elastic::Out.tween(0.3)));
1119        assert_eq!(1.031250, r(Elastic::Out.tween(0.4)));
1120        assert_eq!(1.015625, r(Elastic::Out.tween(0.5)));
1121        assert_eq!(0.984375, r(Elastic::Out.tween(0.6)));
1122        assert_eq!(1.003906, r(Elastic::Out.tween(0.7)));
1123        assert_eq!(1.001953, r(Elastic::Out.tween(0.8)));
1124        assert_eq!(0.998047, r(Elastic::Out.tween(0.9)));
1125        assert_eq!(1.000000, r(Elastic::Out.tween(1.0)));
1126    }
1127
1128    #[test]
1129    #[rustfmt::skip]
1130    // Modeled after the piecewise exponentially-damped sine wave:
1131    // y = 2^(10 (2 x - 1) - 1) sin(13 π x) [0, 0.5]
1132    // y = 1/2 (2 - 2^(-10 (2 x - 1)) sin(13 π x)) [0.5, 1]
1133    fn elastic_inout() {
1134        assert_eq!( 0.000000, r(Elastic::InOut.tween(0.0)));
1135        assert_eq!(-0.001580, r(Elastic::InOut.tween(0.1)));
1136        assert_eq!( 0.007430, r(Elastic::InOut.tween(0.2)));
1137        assert_eq!(-0.009657, r(Elastic::InOut.tween(0.3)));
1138        assert_eq!(-0.073473, r(Elastic::InOut.tween(0.4)));
1139        assert_eq!( 0.500000, r(Elastic::InOut.tween(0.5)));
1140        assert_eq!( 1.073473, r(Elastic::InOut.tween(0.6)));
1141        assert_eq!( 1.009657, r(Elastic::InOut.tween(0.7)));
1142        assert_eq!( 0.992570, r(Elastic::InOut.tween(0.8)));
1143        assert_eq!( 1.001580, r(Elastic::InOut.tween(0.9)));
1144        assert_eq!( 1.000000, r(Elastic::InOut.tween(1.0)));
1145    }
1146
1147    #[test]
1148    #[rustfmt::skip]
1149    fn back_in() {
1150        // Modeled after the function: y = 2.70158 * x^3 + x^2 * (-1.70158)
1151        assert_eq!( 0.000000, r(Back::In.tween(0.0)));
1152        assert_eq!(-0.014314, r(Back::In.tween(0.1)));
1153        assert_eq!(-0.046451, r(Back::In.tween(0.2)));
1154        assert_eq!(-0.080200, r(Back::In.tween(0.3)));
1155        assert_eq!(-0.099352, r(Back::In.tween(0.4)));
1156        assert_eq!(-0.087698, r(Back::In.tween(0.5)));
1157        assert_eq!(-0.029028, r(Back::In.tween(0.6)));
1158        assert_eq!( 0.092868, r(Back::In.tween(0.7)));
1159        assert_eq!( 0.294198, r(Back::In.tween(0.8)));
1160        assert_eq!( 0.591172, r(Back::In.tween(0.9)));
1161        assert_eq!( 1.000000, r(Back::In.tween(1.0)));
1162    }
1163
1164    #[test]
1165    fn back_out() {
1166        // Modeled after the function: y = 1 + 2.70158 (x - 1)^3 + 1.70158 (x - 1)^2
1167        assert_eq!(0.000000, r(Back::Out.tween(0.0)));
1168        assert_eq!(0.408828, r(Back::Out.tween(0.1)));
1169        assert_eq!(0.705802, r(Back::Out.tween(0.2)));
1170        assert_eq!(0.907132, r(Back::Out.tween(0.3)));
1171        assert_eq!(1.029027, r(Back::Out.tween(0.4)));
1172        assert_eq!(1.087698, r(Back::Out.tween(0.5)));
1173        assert_eq!(1.099352, r(Back::Out.tween(0.6)));
1174        assert_eq!(1.0802, r(Back::Out.tween(0.7)));
1175        assert_eq!(1.046451, r(Back::Out.tween(0.8)));
1176        assert_eq!(1.014314, r(Back::Out.tween(0.9)));
1177        assert_eq!(1.000000, r(Back::Out.tween(1.0)));
1178    }
1179
1180    #[test]
1181    #[rustfmt::skip]
1182    fn back_inout() {
1183        // Modeled after the piecewise function:
1184        // y = (2x)^2 * (1/2 * ((2.5949095 + 1) * 2x - 2.5949095)) [0, 0.5]
1185        // y = 1/2 * ((2 x - 2)^2 * ((2.5949095 + 1) * (2x - 2) + 2.5949095) + 2) [0.5, 1]
1186        assert_eq!( 0.000000, r(Back::InOut.tween(0.0)));
1187        assert_eq!(-0.037519, r(Back::InOut.tween(0.1)));
1188        assert_eq!(-0.092556, r(Back::InOut.tween(0.2)));
1189        assert_eq!(-0.078833, r(Back::InOut.tween(0.3)));
1190        assert_eq!( 0.089926, r(Back::InOut.tween(0.4)));
1191        assert_eq!( 0.500000, r(Back::InOut.tween(0.5)));
1192        assert_eq!( 0.910074, r(Back::InOut.tween(0.6)));
1193        assert_eq!( 1.078834, r(Back::InOut.tween(0.7)));
1194        assert_eq!( 1.092556, r(Back::InOut.tween(0.8)));
1195        assert_eq!( 1.037519, r(Back::InOut.tween(0.9)));
1196        assert_eq!( 1.000000, r(Back::InOut.tween(1.0)));
1197    }
1198
1199    #[test]
1200    #[rustfmt::skip]
1201    fn bounce_in() {
1202        assert_eq!(0.000000, r(Bounce::In.tween(0.0)));
1203        assert_eq!(    1e-6, r(Bounce::In.tween(0.1)));
1204        assert_eq!(0.087757, r(Bounce::In.tween(0.2)));
1205        assert_eq!(0.083250, r(Bounce::In.tween(0.3)));
1206        assert_eq!(0.273000, r(Bounce::In.tween(0.4)));
1207        assert_eq!(0.281250, r(Bounce::In.tween(0.5)));
1208        assert_eq!(0.108000, r(Bounce::In.tween(0.6)));
1209        assert_eq!(0.319375, r(Bounce::In.tween(0.7)));
1210        assert_eq!(0.697500, r(Bounce::In.tween(0.8)));
1211        assert_eq!(0.924375, r(Bounce::In.tween(0.9)));
1212        assert_eq!(1.000000, r(Bounce::In.tween(1.0)));
1213    }
1214
1215    #[test]
1216    fn bounce_out() {
1217        assert_eq!(0.000000, r(Bounce::Out.tween(0.0)));
1218        assert_eq!(0.075625, r(Bounce::Out.tween(0.1)));
1219        assert_eq!(0.302500, r(Bounce::Out.tween(0.2)));
1220        assert_eq!(0.680625, r(Bounce::Out.tween(0.3)));
1221        assert_eq!(0.892000, r(Bounce::Out.tween(0.4)));
1222        assert_eq!(0.718750, r(Bounce::Out.tween(0.5)));
1223        assert_eq!(0.727000, r(Bounce::Out.tween(0.6)));
1224        assert_eq!(0.916750, r(Bounce::Out.tween(0.7)));
1225        assert_eq!(0.912243, r(Bounce::Out.tween(0.8)));
1226        assert_eq!(0.999999, r(Bounce::Out.tween(0.9)));
1227        assert_eq!(1.000000, r(Bounce::Out.tween(1.0)));
1228    }
1229
1230    #[test]
1231    fn bounce_inout() {
1232        assert_eq!(0.000000, r(Bounce::InOut.tween(0.0)));
1233        assert_eq!(0.043878, r(Bounce::InOut.tween(0.1)));
1234        assert_eq!(0.136500, r(Bounce::InOut.tween(0.2)));
1235        assert_eq!(0.054000, r(Bounce::InOut.tween(0.3)));
1236        assert_eq!(0.348750, r(Bounce::InOut.tween(0.4)));
1237        assert_eq!(0.500000, r(Bounce::InOut.tween(0.5)));
1238        assert_eq!(0.651250, r(Bounce::InOut.tween(0.6)));
1239        assert_eq!(0.946000, r(Bounce::InOut.tween(0.7)));
1240        assert_eq!(0.863500, r(Bounce::InOut.tween(0.8)));
1241        assert_eq!(0.956121, r(Bounce::InOut.tween(0.9)));
1242        assert_eq!(1.000000, r(Bounce::InOut.tween(1.0)));
1243    }
1244}