[math] make lerp, remap and remap_clamp work for both f32 and f64

This commit is contained in:
Emil Ernerfeldt 2020-10-06 20:51:59 +02:00
parent 7a71ac1a95
commit a49cba54ac

View file

@ -1,6 +1,6 @@
//! Vectors, positions, rectangles etc.
use std::ops::{Add, Mul, RangeInclusive};
use std::ops::{Add, Div, Mul, RangeInclusive, Sub};
// ----------------------------------------------------------------------------
@ -13,27 +13,64 @@ pub use {pos2::*, rect::*, vec2::*};
// ----------------------------------------------------------------------------
/// Linear interpolation.
pub fn lerp<T>(range: RangeInclusive<T>, t: f32) -> T
where
f32: Mul<T, Output = T>,
T: Add<T, Output = T> + Copy,
pub trait One {
fn one() -> Self;
}
impl One for f32 {
fn one() -> Self {
1.0
}
}
impl One for f64 {
fn one() -> Self {
1.0
}
}
pub trait Real:
Copy
+ PartialEq
+ PartialOrd
+ One
+ Add<Self, Output = Self>
+ Sub<Self, Output = Self>
+ Mul<Self, Output = Self>
+ Div<Self, Output = Self>
{
(1.0 - t) * *range.start() + t * *range.end()
}
impl Real for f32 {}
impl Real for f64 {}
// ----------------------------------------------------------------------------
/// Linear interpolation.
pub fn lerp<R, T>(range: RangeInclusive<R>, t: T) -> R
where
T: Real + Mul<R, Output = R>,
R: Copy + Add<R, Output = R>,
{
(T::one() - t) * *range.start() + t * *range.end()
}
/// 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()`.
pub fn remap(x: f32, from: RangeInclusive<f32>, to: RangeInclusive<f32>) -> f32 {
pub fn remap<T>(x: T, from: RangeInclusive<T>, to: RangeInclusive<T>) -> T
where
T: Real,
{
#![allow(clippy::float_cmp)]
debug_assert!(from.start() != from.end());
let t = (x - from.start()) / (from.end() - from.start());
let t = (x - *from.start()) / (*from.end() - *from.start());
lerp(to, t)
}
/// Like `remap`, but also clamps the value so that the returned value is always in the `to` range.
pub fn remap_clamp(x: f32, from: RangeInclusive<f32>, to: RangeInclusive<f32>) -> f32 {
pub fn remap_clamp<T>(x: T, from: RangeInclusive<T>, to: RangeInclusive<T>) -> T
where
T: Real,
{
#![allow(clippy::float_cmp)]
if from.end() < from.start() {
return remap_clamp(x, *from.end()..=*from.start(), *to.end()..=*to.start());
@ -44,9 +81,9 @@ pub fn remap_clamp(x: f32, from: RangeInclusive<f32>, to: RangeInclusive<f32>) -
*to.end()
} else {
debug_assert!(from.start() != from.end());
let t = (x - from.start()) / (from.end() - from.start());
let t = (x - *from.start()) / (*from.end() - *from.start());
// Ensure no numerical inaccuracies sneak in:
if 1.0 <= t {
if T::one() <= t {
*to.end()
} else {
lerp(to, t)