Skip to content

Commit

Permalink
Merge pull request #8 from alexheretic/master
Browse files Browse the repository at this point in the history
Add generic f64 support
  • Loading branch information
orhanbalci authored May 22, 2017
2 parents 6b668e4 + 3d258dc commit 06910a5
Show file tree
Hide file tree
Showing 18 changed files with 523 additions and 310 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ language: rust
addons:
apt:
packages:
- libcurl14-openssl-dev
- libcurl4-openssl-dev
- libelf-dev
- libdw-dev
- binutils-dev
Expand Down
10 changes: 6 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "easer"
version = "0.1.1"
version = "0.2.0"
authors = ["Orhan Balci <[email protected]>"]
description="Tiny library imlementing Robert Penner's easing functions"
documentation="http://orhanbalci.github.io/rust-easing"
Expand All @@ -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"

91 changes: 24 additions & 67 deletions examples/easer_plotter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<F1, F2, F3>(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<E: Easing<f32> + 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 {
Expand All @@ -76,33 +33,33 @@ fn plot_easing_function<F1, F2, F3>(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::<Vec<f32>>();

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::<Vec<f32>>();

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::<Vec<f32>>();

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);

}
63 changes: 40 additions & 23 deletions src/functions/back.rs
Original file line number Diff line number Diff line change
@@ -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<F: Float> Easing<F> 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);
}
}
74 changes: 46 additions & 28 deletions src/functions/bounce.rs
Original file line number Diff line number Diff line change
@@ -1,60 +1,78 @@
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<F: Float> Easing<F> 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
}

}
}

#[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);
}
}
Loading

0 comments on commit 06910a5

Please sign in to comment.