utils/
math.rs

1///
2///  jmath.rs
3///
4///  Created by Mitchell Nordine at 04:23AM on May 30, 2014.
5///
6///
7
8use num::{Float, NumCast};
9use num::PrimInt as Int;
10use std::mem;
11
12/// Clamp a value to a range.
13#[inline]
14pub fn clamp<T: PartialOrd>(val: T, min: T, max: T) -> T {
15    if val < min { min } else { if val > max { max } else { val } }
16}
17
18/// Models the CPP fmod function.
19#[inline]
20pub fn fmod<F: Float>(numer: F, denom: F) -> F {
21    let rquot: F = (numer / denom).floor();
22    numer - rquot * denom
23}
24
25/// Check if value is in range.
26#[inline]
27pub fn in_range<T: Ord>(val: T, min: T, max: T) -> bool {
28    val >= min && val <= max
29}
30
31/// Interpolate from start to stop 'amt' amount.
32#[inline]
33pub fn lerp<F: Float>(start: F, stop: F, amt: F) -> F {
34    start + (stop - start) * amt
35}
36
37/// Map a value from a given range to a new given range.
38#[inline]
39pub fn map_range<X, Y>(val: X, in_min: X, in_max: X, out_min: Y, out_max: Y) -> Y where
40    X: NumCast,
41    Y: NumCast + Copy,
42{
43    use epsilon::epsilon;
44
45    let val_f: f64 = NumCast::from(val).unwrap();
46    let in_min_f: f64 = NumCast::from(in_min).unwrap();
47    let in_max_f: f64 = NumCast::from(in_max).unwrap();
48    let out_min_f: f64 = NumCast::from(out_min).unwrap();
49    let out_max_f: f64 = NumCast::from(out_max).unwrap();
50
51    if (in_min_f - in_max_f).abs() < epsilon() {
52        println!("utils::math::map_range warning: avoiding possible divide by zero, \
53                 in_min ({}) and in_max({})", in_min_f, in_max_f);
54        return out_min;
55    }
56    Y::from((val_f - in_min_f) / (in_max_f - in_min_f) * (out_max_f - out_min_f) + out_min_f)
57        .unwrap()
58}
59
60/// Models the CPP remainder function.
61#[inline]
62pub fn remainder<F: Float>(numer: F, denom: F) -> F {
63    let rquot: F = (numer / denom).round();
64    numer - rquot * denom
65}
66
67/// The modulo function.
68#[inline]
69pub fn modulo<I: Int>(a: I, b: I) -> I {
70    match a % b {
71        r if (r > I::zero() && b < I::zero())
72          || (r < I::zero() && b > I::zero()) => (r + b),
73        r                                         => r,
74    }
75}
76
77/// Wrap value to a range.
78#[inline]
79pub fn wrap<F: Float>(val: F, mut from: F, mut to: F) -> F {
80    if from > to { mem::swap(&mut from, &mut to); }
81    let cycle = to - from;
82    if cycle == F::zero() { return to; }
83    val - cycle * ((val - from) / cycle).floor()
84}
85
86/// The logistic aka sigmoid function.
87#[inline]
88pub fn sigmoid<F: Float>(f: F) -> F {
89    use std::f64::consts::E;
90    let e = F::from(E).unwrap();
91    F::one() / (F::one() + e.powf(-f))
92}
93