[math] make lerp, remap and remap_clamp work for both f32 and f64
This commit is contained in:
parent
7a71ac1a95
commit
a49cba54ac
1 changed files with 49 additions and 12 deletions
|
@ -1,6 +1,6 @@
|
||||||
//! Vectors, positions, rectangles etc.
|
//! 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 trait One {
|
||||||
pub fn lerp<T>(range: RangeInclusive<T>, t: f32) -> T
|
fn one() -> Self;
|
||||||
where
|
}
|
||||||
f32: Mul<T, Output = T>,
|
impl One for f32 {
|
||||||
T: Add<T, Output = T> + Copy,
|
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,
|
/// Linearly remap a value from one range to another,
|
||||||
/// so that when `x == from.start()` returns `to.start()`
|
/// so that when `x == from.start()` returns `to.start()`
|
||||||
/// and when `x == from.end()` returns `to.end()`.
|
/// 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)]
|
#![allow(clippy::float_cmp)]
|
||||||
debug_assert!(from.start() != from.end());
|
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)
|
lerp(to, t)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Like `remap`, but also clamps the value so that the returned value is always in the `to` range.
|
/// 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)]
|
#![allow(clippy::float_cmp)]
|
||||||
if from.end() < from.start() {
|
if from.end() < from.start() {
|
||||||
return remap_clamp(x, *from.end()..=*from.start(), *to.end()..=*to.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()
|
*to.end()
|
||||||
} else {
|
} else {
|
||||||
debug_assert!(from.start() != from.end());
|
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:
|
// Ensure no numerical inaccuracies sneak in:
|
||||||
if 1.0 <= t {
|
if T::one() <= t {
|
||||||
*to.end()
|
*to.end()
|
||||||
} else {
|
} else {
|
||||||
lerp(to, t)
|
lerp(to, t)
|
||||||
|
|
Loading…
Reference in a new issue