[math] make lerp, remap and remap_clamp work for both f32 and f64
//! 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::*};
// ----------------------------------------------------------------------------
+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>
+{
+}
+
+impl Real for f32 {}
+impl Real for f64 {}
+
+// ----------------------------------------------------------------------------
+
/// Linear interpolation.
-pub fn lerp<T>(range: RangeInclusive<T>, t: f32) -> T
+pub fn lerp<R, T>(range: RangeInclusive<R>, t: T) -> R
where
- f32: Mul<T, Output = T>,
- T: Add<T, Output = T> + Copy,
+ T: Real + Mul<R, Output = R>,
+ R: Copy + Add<R, Output = R>,
{
- (1.0 - t) * *range.start() + t * *range.end()
+ (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)
