#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Linear {
domain: (f64, f64),
range: (f64, f64),
}
impl Linear {
pub fn new(domain: (f64, f64), range: (f64, f64)) -> Linear {
Linear { domain, range }
}
pub(crate) fn finite_affine(&self) -> Option<(f64, f64, f64, f64)> {
let (d0, d1) = self.domain;
let (r0, r1) = self.range;
let domain_span = d1 - d0;
let range_span = r1 - r0;
(domain_span.is_finite() && domain_span != 0.0 && range_span.is_finite()).then_some((
d0,
domain_span,
r0,
range_span,
))
}
pub fn map(&self, value: f64) -> f64 {
let (d0, d1) = self.domain;
let (r0, r1) = self.range;
if d0 == d1 {
return if value.is_nan() {
value
} else {
crate::numeric::midpoint(r0, r1)
};
}
crate::numeric::lerp(r0, r1, crate::numeric::inverse_lerp(d0, d1, value))
}
pub fn unmap(&self, value: f64) -> f64 {
let (d0, d1) = self.domain;
let (r0, r1) = self.range;
if r0 == r1 {
return if value.is_nan() {
value
} else {
crate::numeric::midpoint(d0, d1)
};
}
crate::numeric::lerp(d0, d1, crate::numeric::inverse_lerp(r0, r1, value))
}
}
#[cfg(test)]
#[path = "tests/linear_tests.rs"]
mod tests;