diff --git a/crates/emath/src/lib.rs b/crates/emath/src/lib.rs index 7652252f..5a88c9a3 100644 --- a/crates/emath/src/lib.rs +++ b/crates/emath/src/lib.rs @@ -87,6 +87,14 @@ impl Real for f64 {} // ---------------------------------------------------------------------------- /// Linear interpolation. +/// +/// ``` +/// # use emath::lerp; +/// assert_eq!(lerp(1.0..=5.0, 0.0), 1.0); +/// assert_eq!(lerp(1.0..=5.0, 0.5), 3.0); +/// assert_eq!(lerp(1.0..=5.0, 1.0), 5.0); +/// assert_eq!(lerp(1.0..=5.0, 2.0), 9.0); +/// ``` #[inline(always)] pub fn lerp(range: RangeInclusive, t: T) -> R where @@ -96,6 +104,34 @@ where (T::one() - t) * *range.start() + t * *range.end() } +/// Where in the range is this value? Returns 0-1 if within the range. +/// +/// Returns <0 if before and >1 if after. +/// +/// Returns `None` if the input range is zero-width. +/// +/// ``` +/// # use emath::inverse_lerp; +/// assert_eq!(inverse_lerp(1.0..=5.0, 1.0), Some(0.0)); +/// assert_eq!(inverse_lerp(1.0..=5.0, 3.0), Some(0.5)); +/// assert_eq!(inverse_lerp(1.0..=5.0, 5.0), Some(1.0)); +/// assert_eq!(inverse_lerp(1.0..=5.0, 9.0), Some(2.0)); +/// assert_eq!(inverse_lerp(1.0..=1.0, 3.0), None); +/// ``` +#[inline] +pub fn inverse_lerp(range: RangeInclusive, value: R) -> Option +where + R: Copy + PartialEq + Sub + Div, +{ + let min = *range.start(); + let max = *range.end(); + if min == max { + None + } else { + Some((value - min) / (max - min)) + } +} + /// Linearly remap a value from one range to another, /// so that when `x == from.start()` returns `to.start()` /// and when `x == from.end()` returns `to.end()`.