babalcore 0.5.1

Babal core logic library, low-level things which are game-engine agnostic.
Documentation
/// Fade in func, 0 if x<0, linear between 0 and 1, 1 if x>0.
///
/// # Examples
///
/// ```
/// use babalcore::*;
///
/// assert_eq!(0.0, fade_in(-0.5));
/// assert_eq!(0.0, fade_in(0.0));
/// assert_eq!(0.5, fade_in(0.5));
/// assert_eq!(1.0, fade_in(1.0));
/// assert_eq!(1.0, fade_in(1.5));
/// ```
pub fn fade_in(x: f64) -> f64 {
    if x < 0.0 {
        0.0
    } else if x >= 0.0 && x <= 1.0 {
        x
    } else if x > 1.0 {
        1.0
    } else {
        f64::NAN
    }
}

/// Fade out func, 1 if x<0, linear between 0 and 1, 0 if x>0.
///
/// # Examples
///
/// ```
/// use babalcore::*;
///
/// assert_eq!(1.0, fade_out(-0.5));
/// assert_eq!(1.0, fade_out(0.0));
/// assert_eq!(0.5, fade_out(0.5));
/// assert_eq!(0.0, fade_out(1.0));
/// assert_eq!(0.0, fade_out(1.5));
/// ```
pub fn fade_out(x: f64) -> f64 {
    if x < 0.0 {
        1.0
    } else if x >= 0.0 && x <= 1.0 {
        1.0 - x
    } else if x > 1.0 {
        0.0
    } else {
        f64::NAN
    }
}

/// Square wave func as defined here:
/// https://en.wikipedia.org/wiki/Square_wave
/// It alternates between values of -1 and 1, with a global period of 1.
/// It switches between them at x == 0.5.
///
/// ```
/// use babalcore::*;
///
/// assert_eq!(-1.0, square_wave(-0.25));
/// assert_eq!(1.0, square_wave(0.25));
/// assert_eq!(-1.0, square_wave(0.75));
/// assert_eq!(1.0, square_wave(1.25));
/// ```
pub fn square_wave(x: f64) -> f64 {
    let f = x - x.floor();
    if f < 0.5 {
        1.0
    } else if f > 0.5 {
        -1.0
    } else if f == 0.0 || f == 0.5 {
        0.5
    } else {
        f64::NAN
    }
}

/// Triangle wave func as defined here:
/// https://en.wikipedia.org/wiki/Triangle_wave
/// It alternates between values of -1 and 1, with a global period of 1.
/// It switches between them at x == 0.5.
///
/// ```
/// use babalcore::*;
///
/// assert_eq!(-1.0, triangle_wave(-0.25));
/// assert_eq!(1.0, triangle_wave(0.25));
/// assert_eq!(-1.0, triangle_wave(0.75));
/// assert_eq!(1.0, triangle_wave(1.25));
/// ```
pub fn triangle_wave(x: f64) -> f64 {
    let f = x - x.floor();
    if f < 0.25 {
        f * 4.0
    } else if f >= 0.25 && f < 0.75 {
        1.0 - (f - 0.25) * 4.0
    } else if f >= 0.75 && f <= 1.0 {
        -1.0 + (f - 0.75) * 4.0
    } else {
        f64::NAN
    }
}

/// Sawtooth wave func as defined here:
/// https://en.wikipedia.org/wiki/Sawtooth_wave
/// It alternates between values of -1 and 1, with a global period of 1.
/// It switches between them at x == 0.5.
///
/// ```
/// use babalcore::*;
///
/// assert_eq!(-0.5, sawtooth_wave(-0.25));
/// assert_eq!(0.5, sawtooth_wave(0.25));
/// assert_eq!(-0.5, sawtooth_wave(0.75));
/// assert_eq!(0.5, sawtooth_wave(1.25));
/// ```
pub fn sawtooth_wave(x: f64) -> f64 {
    let f = x - x.floor();
    if f < 0.5 {
        f * 2.0
    } else if f > 0.5 && f <= 1.0 {
        -1.0 + (f - 0.5) * 2.0
    } else if f == 0.5 {
        0.0
    } else {
        f64::NAN
    }
}

/// Sine wave func as defined here:
/// https://en.wikipedia.org/wiki/Sine_wave
/// It's a simple sinusoid, only this one has a period of 1 instead of 2PI.
/// The idea is to be able to use it as a drop in for triangle_wave for
/// instance, without introducing a 2*PI factor. If you want a real sin,
/// just use the builtin func.
///
/// ```
/// use babalcore::*;
///
/// assert_eq!(-1.0, sine_wave(-0.25));
/// assert_eq!(0.0, sine_wave(0.0));
/// assert_eq!(1.0, sine_wave(0.25));
/// ```
pub fn sine_wave(x: f64) -> f64 {
    (2.0 * std::f64::consts::PI * x).sin()
}

/// Pulse func as defined here:
/// https://en.wikipedia.org/wiki/Pulse_wave
/// The global period is 1, the alpha value can be used
/// to control the ratio between 1s and 0s.
///
/// ```
/// use babalcore::*;
///
/// assert_eq!(0.0, pulse(-0.125, 0.25));
/// assert_eq!(1.0, pulse(0.125, 0.25));
/// assert_eq!(0.0, pulse(0.375, 0.25));
/// assert_eq!(1.0, pulse(1.125, 0.25));
/// ```
pub fn pulse(x: f64, alpha: f64) -> f64 {
    let f = x - x.floor();
    if f < alpha {
        1.0
    } else if f > alpha {
        0.0
    } else if f == 0.0 || f == alpha {
        if alpha <= 0.0 {
            0.0
        } else if alpha >= 1.0 {
            1.0
        } else {
            0.5
        }
    } else {
        f64::NAN
    }
}

/// Boxcar function as defined here:
/// https://en.wikipedia.org/wiki/Boxcar_function
/// With A=1, a=0, b=1, so it is 0 if x<0, 1 if x>0 and x<1
/// an 1 if x>1.
///
/// # Examples
///
/// ```
/// use babalcore::*;
///
/// assert_eq!(0.0, boxcar(-0.5));
/// assert_eq!(0.5, boxcar(0.0));
/// assert_eq!(1.0, boxcar(0.5));
/// assert_eq!(0.5, boxcar(1.0));
/// assert_eq!(0.0, boxcar(1.5));
/// ```
pub fn boxcar(x: f64) -> f64 {
    heaviside_step(x) - heaviside_step(x - 1.0)
}

/// Heavyside step function as defined here:
/// https://en.wikipedia.org/wiki/Heaviside_step_function
/// It is 1 is x > 0, and 0 if x < 0.
///
/// # Examples
///
/// ```
/// use babalcore::*;
///
/// assert_eq!(0.0, heaviside_step(-0.5));
/// assert_eq!(0.5, heaviside_step(0.0));
/// assert_eq!(1.0, heaviside_step(0.5));
/// ```
pub fn heaviside_step(x: f64) -> f64 {
    if x < 0.0 {
        0.0
    } else if x > 0.0 {
        1.0
    } else if x == 0.0 {
        0.5
    } else {
        f64::NAN
    }
}

#[cfg(test)]
mod tests {
    use crate::*;

    #[test]
    fn test_fade_in() {
        assert_eq!(0.0, fade_in(-100.0));
        assert_eq!(0.0, fade_in(-0.9));
        assert_eq!(0.0, fade_in(-0.1));
        assert_eq!(0.0, fade_in(0.0));
        assert_eq!(0.25, fade_in(0.25));
        assert_eq!(0.5, fade_in(0.5));
        assert_eq!(0.75, fade_in(0.75));
        assert_eq!(1.0, fade_in(1.0));
        assert_eq!(1.0, fade_in(1.1));
        assert_eq!(1.0, fade_in(1.9));
        assert_eq!(1.0, fade_in(100.0));
        assert!(0.0 != fade_in(f64::NAN));
        assert!(0.5 != fade_in(f64::NAN));
        assert!(1.0 != fade_in(f64::NAN));
    }

    #[test]
    fn test_fade_out() {
        assert_eq!(1.0, fade_out(-100.0));
        assert_eq!(1.0, fade_out(-0.9));
        assert_eq!(1.0, fade_out(-0.1));
        assert_eq!(1.0, fade_out(0.0));
        assert_eq!(0.75, fade_out(0.25));
        assert_eq!(0.5, fade_out(0.5));
        assert_eq!(0.25, fade_out(0.75));
        assert_eq!(0.0, fade_out(1.0));
        assert_eq!(0.0, fade_out(1.1));
        assert_eq!(0.0, fade_out(1.9));
        assert_eq!(0.0, fade_out(100.0));
        assert!(0.0 != fade_out(f64::NAN));
        assert!(0.5 != fade_out(f64::NAN));
        assert!(1.0 != fade_out(f64::NAN));
    }

    #[test]
    fn test_heaviside_step() {
        assert_eq!(0.0, heaviside_step(-100.0));
        assert_eq!(0.0, heaviside_step(-0.9));
        assert_eq!(0.0, heaviside_step(-0.1));
        assert_eq!(0.5, heaviside_step(0.0));
        assert_eq!(1.0, heaviside_step(0.1));
        assert_eq!(1.0, heaviside_step(0.5));
        assert_eq!(1.0, heaviside_step(0.9));
        assert_eq!(1.0, heaviside_step(1.1));
        assert_eq!(1.0, heaviside_step(1.9));
        assert_eq!(1.0, heaviside_step(100.0));
        assert!(0.0 != heaviside_step(f64::NAN));
        assert!(0.5 != heaviside_step(f64::NAN));
        assert!(1.0 != heaviside_step(f64::NAN));
    }
}