1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
//! Math functions.

use super::*;

/// Adds two functions.
pub fn add<T: 'static + Copy>(a: Func<T, f64>, b: Func<T, f64>) -> Func<T, f64> {
    Arc::new(move |x| a(x) + b(x))
}

/// Subtracts two functions.
pub fn sub<T: 'static + Copy>(a: Func<T, f64>, b: Func<T, f64>) -> Func<T, f64> {
    Arc::new(move |x| a(x) - b(x))
}

/// Adds a new argument to the right.
pub fn lift_right<T, U: 'static, V: 'static>(f: Func<U, V>) -> Func<(U, T), V> {
    Arc::new(move |(a, _)| f(a))
}

/// Adds a new argument to the left.
pub fn lift_left<T, U: 'static, V: 'static>(f: Func<U, V>) -> Func<(T, U), V> {
    Arc::new(move |(_, a)| f(a))
}

/// Returns identity function.
pub fn id<T>() -> Func<T, T> {
    Arc::new(move |a| a)
}

/// Returns step function.
/// This is zero for negative numbers and one for positive numbers.
pub fn step() -> Func<f64, f64> {
    Arc::new(move |a| if a < 0.0 {0.0} else {1.0})
}

/// Returns floor function.
pub fn floor() -> Func<f64, f64> {
    Arc::new(move |a| a.floor())
}

/// Returns zero function.
pub fn zero<T>() -> Func<T, f64> {
    Arc::new(move |_| 0.0)
}

/// Returns one function.
pub fn one<T>() -> Func<T, f64> {
    Arc::new(move |_| 1.0)
}

/// Returns a constant.
pub fn k<T>(v: f64) -> Func<T, f64> {
    Arc::new(move |_| v)
}

/// Zips two functions, such that it alternates between them.
pub fn zip(a: Func<f64, f64>, b: Func<f64, f64>) -> Func<f64, f64> {
    Arc::new(move |t| if t % 2.0 < 1.0 {
        a(t % 1.0 + (t/2.0).floor())
    } else {
        b(t % 1.0 + ((t-1.0)/2.0).floor())
    })
}

/// Returns the `y` component for `x` on a half circle.
pub fn half_circle() -> Func<f64, f64> {
    Arc::new(move |x| (1.0 - x * x).sqrt())
}

/// Maps input type into another.
pub fn map<F, T, U, V>(a: Func<U, V>, f: F) -> Func<T, V>
where F: 'static + Fn(T) -> U + Send + Sync, U: 'static, V: 'static {
    Arc::new(move |x| a(f(x)))
}

/// Creates a linear combination of two shapes.
pub fn line<T: Clone, U: Clone, V: Clone>(a: &T, b: &U, t: &V) ->
<T as Add<<<U as Sub<T>>::Output as Mul<V>>::Output>>::Output
    where U: Sub<T>,
          <U as Sub<T>>::Output: Mul<V>,
          T: Add<<<U as Sub<T>>::Output as Mul<V>>::Output>
{
    let a1 = a.clone();
    let a2 = a.clone();
    let b = b.clone();
    let t = t.clone();
    a1 + (b - a2) * t
}

/// Constructs a cubic bezier.
#[macro_export]
macro_rules! qbez(
    ($a:expr, $b:expr, $c:expr, $t:expr) => {
        line(&line($a, $b, $t), &line($b, $c, $t), $t)
    }
);

/// Constructs a cubic bezier.
#[macro_export]
macro_rules! cbez(
    ($a:expr, $b:expr, $c:expr, $d:expr, $t:expr) => {
        line(&line($a, $b, $t), &line($c, $d, $t), $t)
    }
);

/// Mathematical constant for 360 degrees in radians.
pub const TAU: f64 = 6.283185307179586;

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

    #[test]
    fn test_zip() {
        let a: Func<f64, f64> = Arc::new(move |t| t);
        let b: Func<f64, f64> = Arc::new(move |t| -t);
        let c = zip(a.clone(), b.clone());
        assert_eq!(c(0.0), a(0.0));
        assert_eq!(c(0.5), a(0.5));
        assert_eq!(c(1.0), b(0.0));
        assert_eq!(c(1.5), b(0.5));
        assert_eq!(c(2.0), a(1.0));
        assert_eq!(c(2.5), a(1.5));
        assert_eq!(c(3.0), b(1.0));
        assert_eq!(c(3.5), b(1.5));
        assert_eq!(c(4.0), a(2.0));
        assert_eq!(c(4.5), a(2.5));
    }
}