diff --git a/.travis.yml b/.travis.yml index be361a3..4cbf1e3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,7 @@ language: rust addons: apt: packages: - - libcurl14-openssl-dev + - libcurl4-openssl-dev - libelf-dev - libdw-dev - binutils-dev diff --git a/Cargo.toml b/Cargo.toml index 482cd10..a2da52f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "easer" -version = "0.1.1" +version = "0.2.0" authors = ["Orhan Balci "] description="Tiny library imlementing Robert Penner's easing functions" documentation="http://orhanbalci.github.io/rust-easing" @@ -10,11 +10,13 @@ keywords=["easing","animation","tween"] license="MIT" exclude=[".travis.yml"] +[dependencies] +num-traits="0.1" + [dev-dependencies] -approx="0.1.0" -gnuplot="0.0.20" +approx="0.1" +gnuplot="0.0" [[example]] name="easer_plotter" path="examples/easer_plotter.rs" - diff --git a/examples/easer_plotter.rs b/examples/easer_plotter.rs index fdbf651..2e6db86 100644 --- a/examples/easer_plotter.rs +++ b/examples/easer_plotter.rs @@ -3,71 +3,28 @@ extern crate easer; use gnuplot::{Figure, Caption, Color, AxesCommon}; use easer::functions::*; +use std::fmt::Debug; fn main() { let mut fg = Figure::new(); - plot_easing_function(&mut fg, Back::ease_in, Back::ease_out, Back::ease_in_out, 0); - plot_easing_function(&mut fg, - Bounce::ease_in, - Bounce::ease_out, - Bounce::ease_in_out, - 3); - plot_easing_function(&mut fg, Circ::ease_in, Circ::ease_out, Circ::ease_in_out, 6); - // plot_easing_function(&mut fg, - // Cubic::ease_in, - // Cubic::ease_out, - // Cubic::ease_in_out, - // 9); - // plot_easing_function(&mut fg, - // Elastic::ease_in, - // Elastic::ease_out, - // Elastic::ease_in_out, - // 12); - // plot_easing_function(&mut fg, - // Expo::ease_in, - // Expo::ease_out, - // Expo::ease_in_out, - // 15); - // plot_easing_function(&mut fg, - // Linear::ease_in, - // Linear::ease_out, - // Linear::ease_in_out, - // 18); - // plot_easing_function(&mut fg, - // Quad::ease_in, - // Quad::ease_out, - // Quad::ease_in_out, - // 21); - // plot_easing_function(&mut fg, - // Quart::ease_in, - // Quart::ease_out, - // Quart::ease_in_out, - // 24); - // plot_easing_function(&mut fg, - // Quint::ease_in, - // Quint::ease_out, - // Quint::ease_in_out, - // 27); - // plot_easing_function(&mut fg, - // Sine::ease_in, - // Sine::ease_out, - // Sine::ease_in_out, - // 30); + const ROWS: u32 = 3; + + plot_easing(Back, &mut fg, 0, ROWS); + plot_easing(Bounce, &mut fg, 1, ROWS); + plot_easing(Circ, &mut fg, 2, ROWS); + // plot_easing(Cubic, &mut fg, 3, ROWS); + // plot_easing(Elastic, &mut fg, 4, ROWS); + // plot_easing(Expo, &mut fg, 5, ROWS); + // plot_easing(Linear, &mut fg, 6, ROWS); + // plot_easing(Quad, &mut fg, 7, ROWS); + // plot_easing(Quart, &mut fg, 8, ROWS); + // plot_easing(Quint, &mut fg, 9, ROWS); + // plot_easing(Sine, &mut fg, 10, ROWS); fg.show(); - // rintln!("Hello, world!"); } -fn plot_easing_function(fg: &mut Figure, - fun_ease_in: F1, - fun_ease_out: F2, - fun_ease_in_out: F3, - cell: u32) - where F1: Fn(f32, f32, f32, f32) -> f32, - F2: Fn(f32, f32, f32, f32) -> f32, - F3: Fn(f32, f32, f32, f32) -> f32 -{ - +fn plot_easing + Debug>(easing: E, fg: &mut Figure, row_idx: u32, nrows: u32) { let mut x: [f32; 100] = [0.0; 100]; let mut y: [f32; 100] = [0.0; 100]; for i in 0..100 { @@ -76,33 +33,33 @@ fn plot_easing_function(fg: &mut Figure, } let back = y.iter() - .map(|a| fun_ease_in(*a, 0f32, 100f32, 100f32)) + .map(|a| E::ease_in(*a, 0f32, 100f32, 100f32)) .collect::>(); fg.axes2d() .lines(&x[..], &back, &[Caption("In Line"), Color("blue")]) - .set_title("Back Ease In", &[]) - .set_pos_grid(3, 3, cell); + .set_title(&format!("{:?} Ease In", easing), &[]) + .set_pos_grid(nrows, 3, row_idx * 3); let back_ease_out = y.iter() - .map(|a| fun_ease_out(*a, 0f32, 100f32, 100f32)) + .map(|a| E::ease_out(*a, 0f32, 100f32, 100f32)) .collect::>(); fg.axes2d() .lines(&x[..], &back_ease_out, &[Caption("Out Line"), Color("blue")]) - .set_title("Back Ease Out", &[]) - .set_pos_grid(3, 3, cell + 1); + .set_title(&format!("{:?} Ease Out", easing), &[]) + .set_pos_grid(nrows, 3, row_idx * 3 + 1); let back_ease_in_out = y.iter() - .map(|a| fun_ease_in_out(*a, 0f32, 100f32, 100f32)) + .map(|a| E::ease_in_out(*a, 0f32, 100f32, 100f32)) .collect::>(); fg.axes2d() .lines(&x[..], &back_ease_in_out, &[Caption("In Out Line"), Color("blue")]) - .set_title("Back Ease In Out", &[]) - .set_pos_grid(3, 3, cell + 2); + .set_title(&format!("{:?} Ease In Out", easing), &[]) + .set_pos_grid(nrows, 3, row_idx * 3 + 2); } diff --git a/src/functions/back.rs b/src/functions/back.rs index da7d02b..b685b25 100644 --- a/src/functions/back.rs +++ b/src/functions/back.rs @@ -1,53 +1,70 @@ use super::ease::Easing; +use functions::util::*; /// This struct captures Back easing functions +#[derive(Debug)] pub struct Back; -impl Easing for Back { - fn ease_in(t: f32, b: f32, c: f32, d: f32) -> f32 { - let s = 1.70158_f32; +impl Easing for Back { + fn ease_in(t: F, b: F, c: F, d: F) -> F { + let s: F = f(1.70158); let t = t / d; - c * t * t * ((s + 1.0) * t - s) + b + c * t * t * ((s + f(1.0)) * t - s) + b } - fn ease_out(t: f32, b: f32, c: f32, d: f32) -> f32 { - let s = 1.70158_f32; - let t = (t / d) - 1.0; - c * (t * t * ((s + 1.0) * t + s) + 1.0) + b + fn ease_out(t: F, b: F, c: F, d: F) -> F { + let s: F = f(1.70158); + let t = (t / d) - f(1.0); + c * (t * t * ((s + f(1.0)) * t + s) + f(1.0)) + b } - fn ease_in_out(t: f32, b: f32, c: f32, d: f32) -> f32 { - let s = 1.70158_f32; - let t = t / (d / 2.0); - if t < 1.0 { - let s = s * 1.525f32; - c / 2.0 * (t * t * ((s + 1.0) * t - s)) + b + fn ease_in_out(t: F, b: F, c: F, d: F) -> F { + let s: F = f(1.70158); + let t = t / (d / f(2.0)); + if t < f(1.0) { + let s = s * f(1.525); + c / f(2.0) * (t * t * ((s + f(1.0)) * t - s)) + b } else { - let t = t - 2.0; - let s = s * 1.525f32; - c / 2.0 * (t * t * ((s + 1.0) * t + s) + 2.0) + b + let t = t - f(2.0); + let s = s * f(1.525); + c / f(2.0) * (t * t * ((s + f(1.0)) * t + s) + f(2.0)) + b } } } #[cfg(test)] mod test { - #[allow(unused_imports)] - use functions::ease::Easing; + use super::*; + #[test] fn ease_in() { - assert_relative_eq!(super::Back::ease_in(1.0, 2.0, 3.0, 4.0), 1.8075902); + assert_relative_eq!(Back::ease_in(1.0_f32, 2.0, 3.0, 4.0), 1.8075902); } #[test] fn ease_out() { - assert_relative_eq!(super::Back::ease_out(1.0, 2.0, 3.0, 4.0), 4.452229); + assert_relative_eq!(Back::ease_out(1.0_f32, 2.0, 3.0, 4.0), 4.452229); } #[test] fn ease_in_out() { - assert_relative_eq!(super::Back::ease_in_out(1.0, 2.0, 3.0, 4.0), 1.7009544); - assert_relative_eq!(super::Back::ease_in_out(51.0, 1.0, 100.0, 100.0), 56.432546); + assert_relative_eq!(Back::ease_in_out(1.0_f32, 2.0, 3.0, 4.0), 1.7009544); + assert_relative_eq!(Back::ease_in_out(51.0_f32, 1.0, 100.0, 100.0), 56.432546); + } + + const PRECISE_RESULT: f64 = 1.7458203824347307; + + #[test] + fn f32_precision() { + let ease32 = Back::ease_in(10_f32.sqrt(), 2.0, 3.0, 10.0); + assert_relative_ne!(ease32 as f64, PRECISE_RESULT); // f32 maths is actually happening + assert_relative_eq!(ease32, PRECISE_RESULT as f32); + } + + #[test] + fn f64_precision() { + let ease64 = Back::ease_in(10_f64.sqrt(), 2.0, 3.0, 10.0); + assert_relative_eq!(ease64, PRECISE_RESULT); } } diff --git a/src/functions/bounce.rs b/src/functions/bounce.rs index 01120b5..2e9f839 100644 --- a/src/functions/bounce.rs +++ b/src/functions/bounce.rs @@ -1,34 +1,39 @@ use super::ease::Easing; +use functions::util::*; /// This struct captures Bounce easing functions +#[derive(Debug)] pub struct Bounce; -impl Easing for Bounce { - fn ease_in(t: f32, b: f32, c: f32, d: f32) -> f32 { - c - Bounce::ease_out(d - t, 0.0, c, d) + b +impl Easing for Bounce { + fn ease_in(t: F, b: F, c: F, d: F) -> F { + c - Bounce::ease_out(d - t, f(0.0), c, d) + b } - fn ease_out(t: f32, b: f32, c: f32, d: f32) -> f32 { + fn ease_out(t: F, b: F, c: F, d: F) -> F { + cast_constants!(F; _1=1, _1_5=1.5, _2=2, _2_25=2.25, _2_5=2.5, + _2_625=2.625, _7_5625=7.5625); + let t = t / d; - if t < 1.0 / 2.75 { - c * (7.5625 * t * t) + b - } else if t < 2.0 / 2.75 { - let t = t - 1.5 / 2.75; - c * (7.5625 * t * t + 0.75) + b - } else if t < 2.5 / 2.75 { - let t = t - 2.25 / 2.75; - c * (7.5625 * t * t + 0.9375) + b + if t < _1 / f(2.75) { + c * (_7_5625 * t * t) + b + } else if t < _2 / f(2.75) { + let t = t - _1_5 / f(2.75); + c * (_7_5625 * t * t + f(0.75)) + b + } else if t < _2_5 / f(2.75) { + let t = t - _2_25 / f(2.75); + c * (_7_5625 * t * t + f(0.9375)) + b } else { - let t = t - 2.625 / 2.75; - c * (7.5625 * t * t + 0.984375) + b + let t = t - _2_625 / f(2.75); + c * (_7_5625 * t * t + f(0.984375)) + b } } - fn ease_in_out(t: f32, b: f32, c: f32, d: f32) -> f32 { - if t < (d / 2.0) { - Bounce::ease_in(t * 2.0, 0.0, c, d) * 0.5 + b + fn ease_in_out(t: F, b: F, c: F, d: F) -> F { + if t < (d / f(2.0)) { + Bounce::ease_in(t * f(2.0), f(0.0), c, d) * f(0.5) + b } else { - Bounce::ease_out(t * 2.0 - d, 0.0, c, d) * 0.5 + c * 0.5 + b + Bounce::ease_out(t * f(2.0) - d, f(0.0), c, d) * f(0.5) + c * f(0.5) + b } } @@ -36,25 +41,38 @@ impl Easing for Bounce { #[cfg(test)] mod test { - #[allow(unused_imports)] - use functions::ease::Easing; + use super::*; + #[test] fn ease_out() { - assert_relative_eq!(super::Bounce::ease_out(1.0, 2.0, 3.0, 4.0), 3.4179688); - assert_relative_eq!(super::Bounce::ease_out(1.0, 2.0, 3.0, 2.0), 4.296875); - assert_relative_eq!(super::Bounce::ease_out(100.0, 1.0, 100.0, 100.0), - 101.000000); + assert_relative_eq!(Bounce::ease_out(1.0_f32, 2.0, 3.0, 4.0), 3.4179688); + assert_relative_eq!(Bounce::ease_out(1.0_f32, 2.0, 3.0, 2.0), 4.296875); + assert_relative_eq!(Bounce::ease_out(100.0_f32, 1.0, 100.0, 100.0), 101.000000); } #[test] fn ease_in() { - assert_relative_eq!(super::Bounce::ease_in(1.0, 2.0, 3.0, 4.0), 2.082031); + assert_relative_eq!(Bounce::ease_in(1.0_f32, 2.0, 3.0, 4.0), 2.082031); } #[test] fn ease_in_out() { - assert_relative_eq!(super::Bounce::ease_in_out(1.0, 2.0, 3.0, 4.0), 2.3515625); - assert_relative_eq!(super::Bounce::ease_in_out(51.0, 1.0, 100.0, 100.0), - 51.151250); + assert_relative_eq!(Bounce::ease_in_out(1.0_f32, 2.0, 3.0, 4.0), 2.3515625); + assert_relative_eq!(Bounce::ease_in_out(51.0_f32, 1.0, 100.0, 100.0), 51.151250); + } + + const PRECISE_RESULT: f64 = 2.3159476740972824; + + #[test] + fn f32_precision() { + let ease32 = Bounce::ease_in(10_f32.sqrt(), 2.0, 3.0, 10.0); + assert_relative_ne!(ease32 as f64, PRECISE_RESULT); // f32 maths is actually happening + assert_relative_eq!(ease32, PRECISE_RESULT as f32); + } + + #[test] + fn f64_precision() { + let ease64 = Bounce::ease_in(10_f64.sqrt(), 2.0, 3.0, 10.0); + assert_relative_eq!(ease64, PRECISE_RESULT); } } diff --git a/src/functions/circ.rs b/src/functions/circ.rs index ad21ee3..ae1397b 100644 --- a/src/functions/circ.rs +++ b/src/functions/circ.rs @@ -1,48 +1,65 @@ use super::ease::Easing; +use functions::util::*; /// This struct captures Circ easing functions +#[derive(Debug)] pub struct Circ; -impl Easing for Circ { - fn ease_in(t: f32, b: f32, c: f32, d: f32) -> f32 { +impl Easing for Circ { + fn ease_in(t: F, b: F, c: F, d: F) -> F { let t = t / d; - -c * ((1.0 - t * t).sqrt() - 1.0) + b + -c * ((F::one() - t * t).sqrt() - f(1.0)) + b } - fn ease_out(t: f32, b: f32, c: f32, d: f32) -> f32 { - let t = t / d - 1.0; - c * (1.0 - t * t).sqrt() + b + fn ease_out(t: F, b: F, c: F, d: F) -> F { + let t = t / d - f(1.0); + c * (F::one() - t * t).sqrt() + b } - fn ease_in_out(t: f32, b: f32, c: f32, d: f32) -> f32 { - let t = t / (d / 2.0); - if t < 1.0 { - -c / 2.0 * ((1.0 - t * t).sqrt() - 1.0) + b + fn ease_in_out(t: F, b: F, c: F, d: F) -> F { + let t = t / (d / f(2.0)); + if t < f(1.0) { + -c / f(2.0) * ((F::one() - t * t).sqrt() - f(1.0)) + b } else { - let t = t - 2.0; - c / 2.0 * ((1.0 - t * t).sqrt() + 1.0) + b + let t = t - f(2.0); + c / f(2.0) * ((F::one() - t * t).sqrt() + f(1.0)) + b } } } #[cfg(test)] mod test { - #[allow(unused_imports)] - use functions::ease::Easing; + use super::*; + #[test] fn ease_in() { - assert_relative_eq!(super::Circ::ease_in(1.0, 2.0, 3.0, 4.0), 2.0952625); + assert_relative_eq!(Circ::ease_in(1.0_f32, 2.0, 3.0, 4.0), 2.0952625); } #[test] fn ease_out() { - assert_relative_eq!(super::Circ::ease_out(1.0, 2.0, 3.0, 4.0), 3.9843135); + assert_relative_eq!(Circ::ease_out(1.0_f32, 2.0, 3.0, 4.0), 3.9843135); } #[test] fn ease_in_out() { - assert_relative_eq!(super::Circ::ease_in_out(1.0, 2.0, 3.0, 4.0), 2.200962); - assert_relative_eq!(super::Circ::ease_in_out(51.0, 1.0, 100.0, 100.0), 60.949871); + assert_relative_eq!(Circ::ease_in_out(1.0_f32, 2.0, 3.0, 4.0), 2.200962); + assert_relative_eq!(Circ::ease_in_out(51.0_f32, 1.0, 100.0, 100.0), 60.949871); + } + + const PRECISE_RESULT: f64 = 2.153950105848459; + + #[test] + fn f32_precision() { + let ease32 = Circ::ease_in(10_f32.sqrt(), 2.0, 3.0, 10.0); + assert_relative_ne!(ease32 as f64, PRECISE_RESULT); // f32 maths is actually happening + assert_relative_eq!(ease32, PRECISE_RESULT as f32); + } + + #[test] + fn f64_precision() { + let ease64 = Circ::ease_in(10_f64.sqrt(), 2.0, 3.0, 10.0); + assert_relative_eq!(ease64, PRECISE_RESULT); } } diff --git a/src/functions/cubic.rs b/src/functions/cubic.rs index 2381ce4..dc7da77 100644 --- a/src/functions/cubic.rs +++ b/src/functions/cubic.rs @@ -1,49 +1,65 @@ use super::ease::Easing; +use functions::util::*; /// This struct captures Cubic easing functions +#[derive(Debug)] pub struct Cubic; -impl Easing for Cubic { - fn ease_in(t: f32, b: f32, c: f32, d: f32) -> f32 { +impl Easing for Cubic { + fn ease_in(t: F, b: F, c: F, d: F) -> F { let t = t / d; c * (t * t * t) + b } - fn ease_out(t: f32, b: f32, c: f32, d: f32) -> f32 { - let t = t / d - 1.0; - c * ((t * t * t) + 1.0) + b + fn ease_out(t: F, b: F, c: F, d: F) -> F { + let t = t / d - f(1.0); + c * ((t * t * t) + f(1.0)) + b } - fn ease_in_out(t: f32, b: f32, c: f32, d: f32) -> f32 { - let t = t / (d / 2.0); - if t < 1.0 { - c / 2.0 * (t * t * t) + b + fn ease_in_out(t: F, b: F, c: F, d: F) -> F { + let t = t / (d / f(2.0)); + if t < f(1.0) { + c / f(2.0) * (t * t * t) + b } else { - let t = t - 2.0; - c / 2.0 * (t * t * t + 2.0) + b + let t = t - f(2.0); + c / f(2.0) * (t * t * t + f(2.0)) + b } } } #[cfg(test)] mod test { - #[allow(unused_imports)] - use functions::ease::Easing; + use super::*; + #[test] fn ease_in() { - assert_relative_eq!(super::Cubic::ease_in(1.0, 2.0, 3.0, 4.0), 2.046875); + assert_relative_eq!(Cubic::ease_in(1.0_f32, 2.0, 3.0, 4.0), 2.046875); } #[test] fn ease_out() { - assert_relative_eq!(super::Cubic::ease_out(1.0, 2.0, 3.0, 4.0), 3.734375); + assert_relative_eq!(Cubic::ease_out(1.0_f32, 2.0, 3.0, 4.0), 3.734375); } #[test] fn ease_in_out() { - assert_relative_eq!(super::Cubic::ease_in_out(1.0, 2.0, 3.0, 4.0), 2.187500); - assert_relative_eq!(super::Cubic::ease_in_out(51.0, 1.0, 100.0, 100.0), - 53.940397); + assert_relative_eq!(Cubic::ease_in_out(1.0_f32, 2.0, 3.0, 4.0), 2.187500); + assert_relative_eq!(Cubic::ease_in_out(51.0_f32, 1.0, 100.0, 100.0), 53.940397); + } + + const PRECISE_RESULT: f64 = 2.094868329805051; + + #[test] + fn f32_precision() { + let ease32 = Cubic::ease_in(10_f32.sqrt(), 2.0, 3.0, 10.0); + assert_relative_ne!(ease32 as f64, PRECISE_RESULT); // f32 maths is actually happening + assert_relative_eq!(ease32, PRECISE_RESULT as f32); + } + + #[test] + fn f64_precision() { + let ease64 = Cubic::ease_in(10_f64.sqrt(), 2.0, 3.0, 10.0); + assert_relative_eq!(ease64, PRECISE_RESULT); } } diff --git a/src/functions/ease.rs b/src/functions/ease.rs index 4925d78..cc45a3e 100644 --- a/src/functions/ease.rs +++ b/src/functions/ease.rs @@ -1,6 +1,15 @@ +use num_traits::Float; + /// Interface encapsulating general easing functions -pub trait Easing { - fn ease_in(t: f32, b: f32, c: f32, d: f32) -> f32; - fn ease_out(t: f32, b: f32, c: f32, d: f32) -> f32; - fn ease_in_out(t: f32, b: f32, c: f32, d: f32) -> f32; +/// +/// - **`t`** is the current time (or position) of the tween. +/// This can be seconds or frames, steps, seconds, ms, whatever +/// as long as the unit is the same as is used for the total time. +/// - **`b`** is the beginning value of the property. +/// - **`c`** is the change between the beginning and destination value of the property. +/// - **`d`** is the total time of the tween. +pub trait Easing { + fn ease_in(t: F, b: F, c: F, d: F) -> F; + fn ease_out(t: F, b: F, c: F, d: F) -> F; + fn ease_in_out(t: F, b: F, c: F, d: F) -> F; } diff --git a/src/functions/elastic.rs b/src/functions/elastic.rs index 2901bc3..0d7d4f5 100644 --- a/src/functions/elastic.rs +++ b/src/functions/elastic.rs @@ -1,101 +1,120 @@ use super::ease::Easing; -use std::f32::consts::PI; +use functions::util::*; +use num_traits::float::FloatConst; -/// This struct captures Elastic easing functions +/// This) struct captures Elastic easing functions +#[derive(Debug)] pub struct Elastic; -impl Easing for Elastic { - fn ease_in(t: f32, b: f32, c: f32, d: f32) -> f32 { - if t == 0.0 { +impl Easing for Elastic { + fn ease_in(t: F, b: F, c: F, d: F) -> F { + cast_constants!(F; _2=2, _10=10); + + if t == f(0.0) { return b; } let t = t / d; - if t == 1.0 { + if t == f(1.0) { return b + c; } - let p = d * 0.3; + let p = d * f(0.3); let a = c; - let s = p / 4.0; - let t = t - 1.0; - let post_fix = a * 2_f32.powf(10.0 * t); - let temp = (t * d - s) * (2.0 * PI) / p; + let s = p / f(4.0); + let t = t - f(1.0); + let post_fix = a * _2.powf(_10 * t); + let temp = (t * d - s) * (_2 * F::PI()) / p; -(post_fix * temp.sin()) + b } - fn ease_out(t: f32, b: f32, c: f32, d: f32) -> f32 { - if t == 0.0 { + fn ease_out(t: F, b: F, c: F, d: F) -> F { + cast_constants!(F; _2=2, _10=10); + + if t == f(0.0) { return b; } let t = t / d; - if t == 1.0 { + if t == f(1.0) { return b + c; } - let p = d * 0.3; + let p = d * f(0.3); let a = c; - let s = p / 4.0; - let temp = (t * d - s) * (2.0 * PI) / p; - a * 2_f32.powf(-10.0 * t) * temp.sin() + c + b + let s = p / f(4.0); + let temp = (t * d - s) * (_2 * F::PI()) / p; + a * _2.powf(-_10 * t) * temp.sin() + c + b } - fn ease_in_out(t: f32, b: f32, c: f32, d: f32) -> f32 { - if t == 0.0 { + fn ease_in_out(t: F, b: F, c: F, d: F) -> F { + cast_constants!(F; _2=2, _10=10, _0_5=0.5); + + if t == f(0.0) { return b; } - let t = t / (d / 2.0); - if t == 2.0 { + let t = t / (d / _2); + if t == _2 { return b + c; } - let p = d * 0.3 * 1.5; + let p = d * f(0.3) * f(1.5); let a = c; - let s = p / 4.0; + let s = p / f(4.0); - if t < 1.0 { - let t = t - 1.0; - let post_fix = a * 2_f32.powf(10.0 * t); - let temp = (t * d - s) * (2.0 * PI) / p; - return -0.5 * (post_fix * temp.sin()) + b; + if t < f(1.0) { + let t = t - f(1.0); + let post_fix = a * _2.powf(_10 * t); + let temp = (t * d - s) * (_2 * F::PI()) / p; + return -_0_5 * (post_fix * temp.sin()) + b; } - let t = t - 1.0; - let post_fix = a * 2_f32.powf(-10.0 * t); - let temp = (t * d - s) * (2.0 * PI) / p; - post_fix * temp.sin() * 0.5 + c + b + let t = t - f(1.0); + let post_fix = a * _2.powf(-_10 * t); + let temp = (t * d - s) * (_2 * F::PI()) / p; + post_fix * temp.sin() * f(0.5) + c + b } } #[cfg(test)] mod test { - #[allow(unused_imports)] - use functions::ease::Easing; + use super::*; #[test] fn ease_in() { - assert_relative_eq!(super::Elastic::ease_in(1.0, 2.0, 3.0, 4.0), 1.983427); - assert_relative_eq!(super::Elastic::ease_in(0.0, 1.0, 100.0, 100.0), 1.0000); - assert_relative_eq!(super::Elastic::ease_in(100.0, 1.0, 100.0, 100.0), 101.000); + assert_relative_eq!(Elastic::ease_in(1.0_f32, 2.0, 3.0, 4.0), 1.983427); + assert_relative_eq!(Elastic::ease_in(0.0_f32, 1.0, 100.0, 100.0), 1.0000); + assert_relative_eq!(Elastic::ease_in(100.0_f32, 1.0, 100.0, 100.0), 101.000); } #[test] fn ease_out() { - assert_relative_eq!(super::Elastic::ease_out(1.0, 2.0, 3.0, 4.0), 4.734835); - assert_relative_eq!(super::Elastic::ease_out(0.0, 1.0, 100.0, 100.0), 1.0000); - assert_relative_eq!(super::Elastic::ease_out(100.0, 1.0, 100.0, 100.0), 101.000); + assert_relative_eq!(Elastic::ease_out(1.0_f32, 2.0, 3.0, 4.0), 4.734835); + assert_relative_eq!(Elastic::ease_out(0.0_f32, 1.0, 100.0, 100.0), 1.0000); + assert_relative_eq!(Elastic::ease_out(100.0_f32, 1.0, 100.0, 100.0), 101.000); } #[test] fn ease_in_out() { - assert_relative_eq!(super::Elastic::ease_in_out(1.0, 2.0, 3.0, 4.0), 2.035908); - assert_relative_eq!(super::Elastic::ease_in_out(0.0, 1.0, 100.0, 100.0), 1.0000); - assert_relative_eq!(super::Elastic::ease_in_out(100.0, 1.0, 100.0, 100.0), - 101.0000); - assert_relative_eq!(super::Elastic::ease_in_out(51.0, 1.0, 100.0, 100.0), - 59.158646); + assert_relative_eq!(Elastic::ease_in_out(1.0_f32, 2.0, 3.0, 4.0), 2.035908); + assert_relative_eq!(Elastic::ease_in_out(0.0_f32, 1.0, 100.0, 100.0), 1.0000); + assert_relative_eq!(Elastic::ease_in_out(100.0_f32, 1.0, 100.0, 100.0), 101.0000); + assert_relative_eq!(Elastic::ease_in_out(51.0_f32, 1.0, 100.0, 100.0), 59.158646); + } + + const PRECISE_RESULT: f64 = 1.9952083561735905; + #[test] + fn f32_precision() { + let ease32 = Elastic::ease_in(10_f32.sqrt(), 2.0, 3.0, 10.0); + assert_relative_ne!(ease32 as f64, PRECISE_RESULT); // f32 maths is actually happening + assert_relative_eq!(ease32, PRECISE_RESULT as f32); + } + + #[test] + fn f64_precision() { + let ease64 = Elastic::ease_in(10_f64.sqrt(), 2.0, 3.0, 10.0); + assert_relative_eq!(ease64, PRECISE_RESULT); } } diff --git a/src/functions/expo.rs b/src/functions/expo.rs index adcfa63..5d0dda9 100644 --- a/src/functions/expo.rs +++ b/src/functions/expo.rs @@ -1,65 +1,87 @@ use super::ease::Easing; +use functions::util::*; /// This struct captures Expo easing functions +#[derive(Debug)] pub struct Expo; -impl Easing for Expo { - fn ease_in(t: f32, b: f32, c: f32, d: f32) -> f32 { - if t == 0.0 { +impl Easing for Expo { + fn ease_in(t: F, b: F, c: F, d: F) -> F { + cast_constants!(F; _2=2, _10=10); + + if t == f(0.0) { b } else { - c * 2_f32.powf(10.0 * (t / d - 1.0)) + b + c * _2.powf(_10 * (t / d - f(1.0))) + b } } - fn ease_out(t: f32, b: f32, c: f32, d: f32) -> f32 { + fn ease_out(t: F, b: F, c: F, d: F) -> F { + cast_constants!(F; _2=2, _10=10); + if t == d { b + c } else { - c * (-2_f32.powf(-10.0 * t / d) + 1.0) + b + c * (-_2.powf(-_10 * t / d) + f(1.0)) + b } } - fn ease_in_out(t: f32, b: f32, c: f32, d: f32) -> f32 { - if t == 0.0 { + fn ease_in_out(t: F, b: F, c: F, d: F) -> F { + cast_constants!(F; _2=2, _10=10); + + if t == f(0.0) { return b; } if t == d { return b + c; } - let t = t / (d / 2.0); - if t < 1.0 { - c / 2.0 * 2_f32.powf(10.0 * (t - 1.0)) + b + let t = t / (d / _2); + if t < f(1.0) { + c / _2 * _2.powf(_10 * (t - f(1.0))) + b } else { - let t = t - 1.0; - c / 2.0 * (-(2_f32.powf(-10.0 * t)) + 2.0) + b + let t = t - f(1.0); + c / _2 * (-(_2.powf(-_10 * t)) + _2) + b } } } #[cfg(test)] mod test { - #[allow(unused_imports)] - use functions::ease::Easing; + use super::*; + #[test] fn ease_in() { - assert_relative_eq!(super::Expo::ease_in(1.0, 2.0, 3.0, 4.0), 2.016573); - assert_relative_eq!(super::Expo::ease_in(0.0, 1.0, 100.0, 100.0), 1.000000); + assert_relative_eq!(Expo::ease_in(1.0_f32, 2.0, 3.0, 4.0), 2.016573); + assert_relative_eq!(Expo::ease_in(0.0_f32, 1.0, 100.0, 100.0), 1.000000); } #[test] fn ease_out() { - assert_relative_eq!(super::Expo::ease_out(1.0, 2.0, 3.0, 4.0), 4.469670); - assert_relative_eq!(super::Expo::ease_out(100.0, 1.0, 100.0, 100.0), 101.0000); + assert_relative_eq!(Expo::ease_out(1.0_f32, 2.0, 3.0, 4.0), 4.469670); + assert_relative_eq!(Expo::ease_out(100.0_f32, 1.0, 100.0, 100.0), 101.0000); } #[test] fn ease_in_out() { - assert_relative_eq!(super::Expo::ease_in_out(1.0, 2.0, 3.0, 4.0), 2.046875); - assert_relative_eq!(super::Expo::ease_in_out(0.0, 1.0, 100.0, 100.0), 1.0000); - assert_relative_eq!(super::Expo::ease_in_out(100.0, 1.0, 100.0, 100.0), 101.000); - assert_relative_eq!(super::Expo::ease_in_out(51.0, 1.0, 100.0, 100.0), 57.472466); + assert_relative_eq!(Expo::ease_in_out(1.0_f32, 2.0, 3.0, 4.0), 2.046875); + assert_relative_eq!(Expo::ease_in_out(0.0_f32, 1.0, 100.0, 100.0), 1.0000); + assert_relative_eq!(Expo::ease_in_out(100.0_f32, 1.0, 100.0, 100.0), 101.000); + assert_relative_eq!(Expo::ease_in_out(51.0_f32, 1.0, 100.0, 100.0), 57.472466); + } + + const PRECISE_RESULT: f64 = 2.0262277918539184; + + #[test] + fn f32_precision() { + let ease32 = Expo::ease_in(10_f32.sqrt(), 2.0, 3.0, 10.0); + assert_relative_ne!(ease32 as f64, PRECISE_RESULT); // f32 maths is actually happening + assert_relative_eq!(ease32, PRECISE_RESULT as f32); } + #[test] + fn f64_precision() { + let ease64 = Expo::ease_in(10_f64.sqrt(), 2.0, 3.0, 10.0); + assert_relative_eq!(ease64, PRECISE_RESULT); + } } diff --git a/src/functions/linear.rs b/src/functions/linear.rs index 8636625..0504af3 100644 --- a/src/functions/linear.rs +++ b/src/functions/linear.rs @@ -1,38 +1,55 @@ use super::ease::Easing; +use functions::util::*; /// This struct captures Linear easing functions +#[derive(Debug)] pub struct Linear; -impl Easing for Linear { - fn ease_in(t: f32, b: f32, c: f32, d: f32) -> f32 { +impl Easing for Linear { + fn ease_in(t: F, b: F, c: F, d: F) -> F { c * t / d + b } - fn ease_out(t: f32, b: f32, c: f32, d: f32) -> f32 { + fn ease_out(t: F, b: F, c: F, d: F) -> F { c * t / d + b } - fn ease_in_out(t: f32, b: f32, c: f32, d: f32) -> f32 { + fn ease_in_out(t: F, b: F, c: F, d: F) -> F { c * t / d + b } } #[cfg(test)] mod test { - #[allow(unused_imports)] - use functions::ease::Easing; + use super::*; + #[test] fn ease_in() { - assert_relative_eq!(super::Linear::ease_in(1.0, 2.0, 3.0, 4.0), 2.7500); + assert_relative_eq!(Linear::ease_in(1.0_f32, 2.0, 3.0, 4.0), 2.7500); } #[test] fn ease_out() { - assert_relative_eq!(super::Linear::ease_out(1.0, 2.0, 3.0, 4.0), 2.7500); + assert_relative_eq!(Linear::ease_out(1.0_f32, 2.0, 3.0, 4.0), 2.7500); } #[test] fn ease_in_out() { - assert_relative_eq!(super::Linear::ease_in_out(1.0, 2.0, 3.0, 4.0), 2.7500); + assert_relative_eq!(Linear::ease_in_out(1.0_f32, 2.0, 3.0, 4.0), 2.7500); + } + + const PRECISE_RESULT: f64 = 2.948683298050514; + + #[test] + fn f32_precision() { + let ease32 = Linear::ease_in(10_f32.sqrt(), 2.0, 3.0, 10.0); + assert_relative_ne!(ease32 as f64, PRECISE_RESULT); // f32 maths is actually happening + assert_relative_eq!(ease32, PRECISE_RESULT as f32); + } + + #[test] + fn f64_precision() { + let ease64 = Linear::ease_in(10_f64.sqrt(), 2.0, 3.0, 10.0); + assert_relative_eq!(ease64, PRECISE_RESULT); } } diff --git a/src/functions/mod.rs b/src/functions/mod.rs index 64c37b3..ecacc34 100644 --- a/src/functions/mod.rs +++ b/src/functions/mod.rs @@ -12,6 +12,8 @@ pub use self::quint::Quint; pub use self::sine::Sine; mod ease; +#[macro_use] +mod util; mod back; mod bounce; mod circ; diff --git a/src/functions/quad.rs b/src/functions/quad.rs index 667f0ff..a8809bc 100644 --- a/src/functions/quad.rs +++ b/src/functions/quad.rs @@ -1,49 +1,65 @@ use super::ease::Easing; +use functions::util::*; /// This struct captures quadratic easing functions +#[derive(Debug)] pub struct Quad; -impl Easing for Quad { - fn ease_in(t: f32, b: f32, c: f32, d: f32) -> f32 { +impl Easing for Quad { + fn ease_in(t: F, b: F, c: F, d: F) -> F { let t = t / d; c * t * t + b } - fn ease_out(t: f32, b: f32, c: f32, d: f32) -> f32 { + fn ease_out(t: F, b: F, c: F, d: F) -> F { let t = t / d; - -c * t * (t - 2.0) + b + -c * t * (t - f(2.0)) + b } - fn ease_in_out(t: f32, b: f32, c: f32, d: f32) -> f32 { - let t = t / (d / 2.0); - if t < 1.0 { - c / 2.0 * t * t + b + fn ease_in_out(t: F, b: F, c: F, d: F) -> F { + let t = t / (d / f(2.0)); + if t < f(1.0) { + c / f(2.0) * t * t + b } else { - let t = t - 1.0; - -c / 2.0 * (t * (t - 2.0) - 1.0) + b + let t = t - f(1.0); + -c / f(2.0) * (t * (t - f(2.0)) - f(1.0)) + b } } } #[cfg(test)] mod test { - #[allow(unused_imports)] - use functions::ease::Easing; + use super::*; + #[test] fn ease_in() { - assert_relative_eq!(super::Quad::ease_in(1.0, 2.0, 3.0, 4.0), 2.187500); + assert_relative_eq!(Quad::ease_in(1.0_f32, 2.0, 3.0, 4.0), 2.187500); } #[test] fn ease_out() { - assert_relative_eq!(super::Quad::ease_out(1.0, 2.0, 3.0, 4.0), 3.312500); + assert_relative_eq!(Quad::ease_out(1.0_f32, 2.0, 3.0, 4.0), 3.312500); } #[test] fn ease_in_out() { - assert_relative_eq!(super::Quad::ease_in_out(1.0, 2.0, 3.0, 4.0), 2.37500); - assert_relative_eq!(super::Quad::ease_in_out(51.0, 1.0, 100.0, 100.0), 52.98); + assert_relative_eq!(Quad::ease_in_out(1.0_f32, 2.0, 3.0, 4.0), 2.37500); + assert_relative_eq!(Quad::ease_in_out(51.0_f32, 1.0, 100.0, 100.0), 52.98); } + const PRECISE_RESULT: f64 = 2.2479338842975207; + + #[test] + fn f32_precision() { + let ease32 = Quad::ease_in(10_f32.sqrt(), 2.0, 3.0, 11.0); + assert_relative_ne!(ease32 as f64, PRECISE_RESULT); // f32 maths is actually happening + assert_relative_eq!(ease32, PRECISE_RESULT as f32); + } + + #[test] + fn f64_precision() { + let ease64 = Quad::ease_in(10_f64.sqrt(), 2.0, 3.0, 11.0); + assert_relative_eq!(ease64, PRECISE_RESULT); + } } diff --git a/src/functions/quart.rs b/src/functions/quart.rs index 0729491..403d0ec 100644 --- a/src/functions/quart.rs +++ b/src/functions/quart.rs @@ -1,27 +1,29 @@ use super::ease::Easing; +use functions::util::*; /// This struct captures Quart easing functions +#[derive(Debug)] pub struct Quart; -impl Easing for Quart { - fn ease_in(t: f32, b: f32, c: f32, d: f32) -> f32 { +impl Easing for Quart { + fn ease_in(t: F, b: F, c: F, d: F) -> F { let t = t / d; c * (t * t * t * t) + b } - fn ease_out(t: f32, b: f32, c: f32, d: f32) -> f32 { - let t = t / d - 1.0; - -c * ((t * t * t * t) - 1.0) + b + fn ease_out(t: F, b: F, c: F, d: F) -> F { + let t = t / d - f(1.0); + -c * ((t * t * t * t) - f(1.0)) + b } - fn ease_in_out(t: f32, b: f32, c: f32, d: f32) -> f32 { - let t = t / (d / 2.0); - if t < 1.0 { - c / 2.0 * (t * t * t * t) + b + fn ease_in_out(t: F, b: F, c: F, d: F) -> F { + let t = t / (d / f(2.0)); + if t < f(1.0) { + c / f(2.0) * (t * t * t * t) + b } else { - let t = t - 2.0; - -c / 2.0 * ((t * t * t * t) - 2.0) + b + let t = t - f(2.0); + -c / f(2.0) * ((t * t * t * t) - f(2.0)) + b } } @@ -29,22 +31,36 @@ impl Easing for Quart { #[cfg(test)] mod test { - #[allow(unused_imports)] - use functions::ease::Easing; + use super::*; + #[test] fn ease_in() { - assert_relative_eq!(super::Quart::ease_in(1.0, 2.0, 3.0, 4.0), 2.011719); + assert_relative_eq!(Quart::ease_in(1.0_f32, 2.0, 3.0, 4.0), 2.011719); } #[test] fn ease_out() { - assert_relative_eq!(super::Quart::ease_out(1.0, 2.0, 3.0, 4.0), 4.050781); + assert_relative_eq!(Quart::ease_out(1.0_f32, 2.0, 3.0, 4.0), 4.050781); } #[test] fn ease_in_out() { - assert_relative_eq!(super::Quart::ease_in_out(1.0, 2.0, 3.0, 4.0), 2.093750); - assert_relative_eq!(super::Quart::ease_in_out(51.0, 1.0, 100.0, 100.0), - 54.881588); + assert_relative_eq!(Quart::ease_in_out(1.0_f32, 2.0, 3.0, 4.0), 2.093750); + assert_relative_eq!(Quart::ease_in_out(51.0_f32, 1.0, 100.0, 100.0), 54.881588); + } + + const PRECISE_RESULT: f64 = 2.0204904036609523; + + #[test] + fn f32_precision() { + let ease32 = Quart::ease_in(10_f32.sqrt(), 2.0, 3.0, 11.0); + assert_relative_ne!(ease32 as f64, PRECISE_RESULT); // f32 maths is actually happening + assert_relative_eq!(ease32, PRECISE_RESULT as f32); + } + + #[test] + fn f64_precision() { + let ease64 = Quart::ease_in(10_f64.sqrt(), 2.0, 3.0, 11.0); + assert_relative_eq!(ease64, PRECISE_RESULT); } } diff --git a/src/functions/quint.rs b/src/functions/quint.rs index f4a1c42..c55004a 100644 --- a/src/functions/quint.rs +++ b/src/functions/quint.rs @@ -1,48 +1,64 @@ use super::ease::Easing; +use functions::util::*; /// This struct captures Quint easing functions +#[derive(Debug)] pub struct Quint; -impl Easing for Quint { - fn ease_in(t: f32, b: f32, c: f32, d: f32) -> f32 { +impl Easing for Quint { + fn ease_in(t: F, b: F, c: F, d: F) -> F { let t = t / d; c * (t * t * t * t * t) + b } - fn ease_out(t: f32, b: f32, c: f32, d: f32) -> f32 { - let t = t / d - 1.0; - c * ((t * t * t * t * t) + 1.0) + b + fn ease_out(t: F, b: F, c: F, d: F) -> F { + let t = t / d - f(1.0); + c * ((t * t * t * t * t) + f(1.0)) + b } - fn ease_in_out(t: f32, b: f32, c: f32, d: f32) -> f32 { - let t = t / (d / 2.0); - if t < 1.0 { - (c / 2.0) * (t * t * t * t * t) + b + fn ease_in_out(t: F, b: F, c: F, d: F) -> F { + let t = t / (d / f(2.0)); + if t < f(1.0) { + (c / f(2.0)) * (t * t * t * t * t) + b } else { - let t = t - 2.0; - c / 2.0 * ((t * t * t * t * t) + 2.0) + b + let t = t - f(2.0); + c / f(2.0) * ((t * t * t * t * t) + f(2.0)) + b } } } #[cfg(test)] mod test { - #[allow(unused_imports)] - use functions::ease::Easing; + use super::*; + #[test] fn ease_in() { - assert_relative_eq!(super::Quint::ease_in(1.0, 2.0, 3.0, 4.0), 2.002930); + assert_relative_eq!(Quint::ease_in(1.0_f32, 2.0, 3.0, 4.0), 2.002930); } #[test] fn ease_out() { - assert_relative_eq!(super::Quint::ease_out(1.0, 2.0, 3.0, 4.0), 4.288086); + assert_relative_eq!(Quint::ease_out(1.0_f32, 2.0, 3.0, 4.0), 4.288086); } #[test] fn ease_in_out() { - assert_relative_eq!(super::Quint::ease_in_out(1.0, 2.0, 3.0, 4.0), 2.046875); - assert_relative_eq!(super::Quint::ease_in_out(51.0, 1.0, 100.0, 100.0), - 55.803956); + assert_relative_eq!(Quint::ease_in_out(1.0_f32, 2.0, 3.0, 4.0), 2.046875); + assert_relative_eq!(Quint::ease_in_out(51.0_f32, 1.0, 100.0, 100.0), 55.803956); + } + + const PRECISE_RESULT: f64 = 2.0094868329805053; + + #[test] + fn f32_precision() { + let ease32 = Quint::ease_in(10_f32.sqrt(), 2.0, 3.0, 10.0); + assert_relative_ne!(ease32 as f64, PRECISE_RESULT); // f32 maths is actually happening + assert_relative_eq!(ease32, PRECISE_RESULT as f32); + } + + #[test] + fn f64_precision() { + let ease64 = Quint::ease_in(10_f64.sqrt(), 2.0, 3.0, 10.0); + assert_relative_eq!(ease64, PRECISE_RESULT); } } diff --git a/src/functions/sine.rs b/src/functions/sine.rs index 77eca1d..64def87 100644 --- a/src/functions/sine.rs +++ b/src/functions/sine.rs @@ -1,39 +1,56 @@ use super::ease::Easing; -use std::f32::consts::PI; +use functions::util::*; +use num_traits::FloatConst; /// This struct captures Sine easing functions +#[derive(Debug)] pub struct Sine; -impl Easing for Sine { - fn ease_in(t: f32, b: f32, c: f32, d: f32) -> f32 { - -c * (t / d * (PI / 2.0)).cos() + c + b +impl Easing for Sine { + fn ease_in(t: F, b: F, c: F, d: F) -> F { + -c * (t / d * (F::PI() / f(2.0))).cos() + c + b } - fn ease_out(t: f32, b: f32, c: f32, d: f32) -> f32 { - c * (t / d * (PI / 2.0)).sin() + b + fn ease_out(t: F, b: F, c: F, d: F) -> F { + c * (t / d * (F::PI() / f(2.0))).sin() + b } - fn ease_in_out(t: f32, b: f32, c: f32, d: f32) -> f32 { - -c / 2.0 * ((PI * t / d).cos() - 1.0) + b + fn ease_in_out(t: F, b: F, c: F, d: F) -> F { + -c / f(2.0) * ((F::PI() * t / d).cos() - f(1.0)) + b } } #[cfg(test)] mod test { - #[allow(unused_imports)] - use functions::ease::Easing; + use super::*; + #[test] fn ease_in() { - assert_relative_eq!(super::Sine::ease_in(1.0, 2.0, 3.0, 4.0), 2.2283616); + assert_relative_eq!(Sine::ease_in(1.0_f32, 2.0, 3.0, 4.0), 2.2283616); } #[test] fn ease_out() { - assert_relative_eq!(super::Sine::ease_out(1.0, 2.0, 3.0, 4.0), 3.148050); + assert_relative_eq!(Sine::ease_out(1.0_f32, 2.0, 3.0, 4.0), 3.148050); } #[test] fn ease_in_out() { - assert_relative_eq!(super::Sine::ease_in_out(1.0, 2.0, 3.0, 4.0), 2.439340); + assert_relative_eq!(Sine::ease_in_out(1.0_f32, 2.0, 3.0, 4.0), 2.439340); + } + + const PRECISE_RESULT: f64 = 2.362562395222677; + + #[test] + fn f32_precision() { + let ease32 = Sine::ease_in(10_f32.sqrt(), 2.0, 3.0, 10.0); + assert_relative_ne!(ease32 as f64, PRECISE_RESULT); // f32 maths is actually happening + assert_relative_eq!(ease32, PRECISE_RESULT as f32); + } + + #[test] + fn f64_precision() { + let ease64 = Sine::ease_in(10_f64.sqrt(), 2.0, 3.0, 10.0); + assert_relative_eq!(ease64, PRECISE_RESULT); } } diff --git a/src/functions/util.rs b/src/functions/util.rs new file mode 100644 index 0000000..db9c5db --- /dev/null +++ b/src/functions/util.rs @@ -0,0 +1,51 @@ +pub use num_traits::Float; + +/// Casts a literal f64 to an appropriate `Float` value +#[inline] +pub fn f(x: f64) -> F { + F::from(x).expect("cast failed, are you using non f32,f64 types?") +} + +/// Macro for defining constants of generic Float type, reduces boiler plate when `f(1.23)` usage +/// isn't enough and the compiler needs explicit type, ie f::(1.23). Such cases we can improve +/// equation readability by using constants like `_1_23` +/// +/// `cast_constants!(F; _1_23=1.23, _10=10);` is equivalent to +/// ``` +/// let _1_23: F = f(1.23); +/// let _10: F = f(10 as f64); +/// ``` +macro_rules! cast_constants { + ($t:ty; $( $name:ident=$val:expr ),+) => { + $( + let $name: $t = f($val as f64); + )+ + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn float_casting() { + type F1 = f64; + type F2 = f32; + + let root2: f64 = 2.0.sqrt(); + let root2_f1: F1 = f(root2); + assert_relative_eq!(root2_f1, root2); + + let root2_f2: F2 = f(root2); + assert_relative_eq!(root2_f2, root2 as F2); + } + + #[test] + fn cast_constants_macro() { + type F = f64; + cast_constants!(F; _1_234=1.234, _234=234); + + assert_relative_eq!(_1_234, 1.234); + assert_relative_eq!(_234, 234.0); + } +} diff --git a/src/lib.rs b/src/lib.rs index 8350148..34dca85 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,15 +16,16 @@ //! //! ``` //! use easer::functions::*; -//! let mut y: [f32; 100] = [0.0; 100]; +//! let mut y: [f64; 100] = [0.0; 100]; //! for i in 0..100 { -//! y[i] = i as f32; +//! y[i] = i as f64; //! } //! println!("Before {:?}", &y[..]); -//! y.iter_mut().map(|a| *a = Back::ease_in(*a, 0f32, 100f32, 100f32)).count(); +//! y.iter_mut().map(|a| *a = Back::ease_in(*a, 0.0, 100.0, 100.0)).count(); //! println!("After {:?}", &y[..]); //! //! ``` +extern crate num_traits; pub mod functions;