From: Joshua Simmons Date: Thu, 8 Sep 2022 06:51:34 +0000 (+0200) Subject: Add `min`, `max` and `clamp` functions X-Git-Url: https://git.nega.tv//gitweb.cgi?a=commitdiff_plain;h=a7ecf6c1f8d296fcb8d1501341a84f1aaac1b371;p=josh%2Fnarcissus Add `min`, `max` and `clamp` functions --- diff --git a/narcissus-maths/src/lib.rs b/narcissus-maths/src/lib.rs index 174f69f..0159592 100644 --- a/narcissus-maths/src/lib.rs +++ b/narcissus-maths/src/lib.rs @@ -64,6 +64,30 @@ impl From for Rad { } } +#[inline(always)] +pub fn min(x: f32, y: f32) -> f32 { + if x < y { + x + } else { + y + } +} + +#[inline(always)] +pub fn max(x: f32, y: f32) -> f32 { + if x > y { + x + } else { + y + } +} + +#[inline(always)] +pub fn clamp(x: f32, lo: f32, hi: f32) -> f32 { + debug_assert!(lo <= hi); + max(min(x, hi), lo) +} + #[macro_export] macro_rules! impl_shared { ($name:ty, $t:ty, $n:expr) => { @@ -78,6 +102,21 @@ macro_rules! impl_shared { unsafe { std::mem::transmute([value; $n]) } } + #[inline] + pub fn min(a: Self, b: Self) -> Self { + a.map2(b, |a, b| crate::min(a, b)) + } + + #[inline] + pub fn max(a: Self, b: Self) -> Self { + a.map2(b, |a, b| crate::max(a, b)) + } + + #[inline] + pub fn clamp(x: Self, lo: Self, hi: Self) -> Self { + Self::max(Self::min(x, hi), lo) + } + #[inline(always)] pub fn ceil(self) -> Self { self.map(|x| x.ceil()) @@ -116,12 +155,12 @@ macro_rules! impl_affine { impl $name { #[inline] pub fn distance(a: Self, b: Self) -> $t { - (a - b).length() + (b - a).length() } #[inline] pub fn distance_sq(a: Self, b: Self) -> $t { - (a - b).length_sq() + (b - a).length_sq() } } }; diff --git a/narcissus-maths/src/point2.rs b/narcissus-maths/src/point2.rs index 109d197..4e1a60a 100644 --- a/narcissus-maths/src/point2.rs +++ b/narcissus-maths/src/point2.rs @@ -32,6 +32,18 @@ impl Point2 { y: f(self.y), } } + + /// Returns a new point in 2d space with the function `f` applied to each pair of components from `self` and `rhs` in order. + #[inline(always)] + pub fn map2(self, rhs: Self, mut f: F) -> Self + where + F: FnMut(f32, f32) -> f32, + { + Self { + x: f(self.x, rhs.x), + y: f(self.y, rhs.y), + } + } } impl std::ops::Sub for Point2 { diff --git a/narcissus-maths/src/point3.rs b/narcissus-maths/src/point3.rs index 721e6c0..c3aa2e4 100644 --- a/narcissus-maths/src/point3.rs +++ b/narcissus-maths/src/point3.rs @@ -35,6 +35,19 @@ impl Point3 { z: f(self.z), } } + + /// Returns a new point in 3d space with the function `f` applied to each pair of components from `self` and `rhs` in order. + #[inline(always)] + pub fn map2(self, rhs: Self, mut f: F) -> Self + where + F: FnMut(f32, f32) -> f32, + { + Self { + x: f(self.x, rhs.x), + y: f(self.y, rhs.y), + z: f(self.z, rhs.z), + } + } } impl std::ops::Sub for Point3 { diff --git a/narcissus-maths/src/vec2.rs b/narcissus-maths/src/vec2.rs index 8056dbe..156d104 100644 --- a/narcissus-maths/src/vec2.rs +++ b/narcissus-maths/src/vec2.rs @@ -32,6 +32,18 @@ impl Vec2 { } } + /// Returns a new 2d vector with the function `f` applied to each pair of components from `self` and `rhs` in order. + #[inline(always)] + pub fn map2(self, rhs: Self, mut f: F) -> Self + where + F: FnMut(f32, f32) -> f32, + { + Self { + x: f(self.x, rhs.x), + y: f(self.y, rhs.y), + } + } + #[inline] pub fn dot(a: Self, b: Self) -> f32 { a.x * b.x + a.y * b.y diff --git a/narcissus-maths/src/vec3.rs b/narcissus-maths/src/vec3.rs index b609f88..507d9af 100644 --- a/narcissus-maths/src/vec3.rs +++ b/narcissus-maths/src/vec3.rs @@ -35,6 +35,19 @@ impl Vec3 { } } + /// Returns a new 3d vector with the function `f` applied to each pair of components from `self` and `rhs` in order. + #[inline(always)] + pub fn map2(self, rhs: Self, mut f: F) -> Self + where + F: FnMut(f32, f32) -> f32, + { + Self { + x: f(self.x, rhs.x), + y: f(self.y, rhs.y), + z: f(self.z, rhs.z), + } + } + #[inline] pub fn dot(a: Self, b: Self) -> f32 { a.x * b.x + a.y * b.y + a.z * b.z diff --git a/narcissus-maths/src/vec4.rs b/narcissus-maths/src/vec4.rs index f0f2392..a73b976 100644 --- a/narcissus-maths/src/vec4.rs +++ b/narcissus-maths/src/vec4.rs @@ -38,6 +38,20 @@ impl Vec4 { } } + /// Returns a new 3d vector with the function `f` applied to each pair of components from `self` and `rhs` in order. + #[inline(always)] + pub fn map2(self, rhs: Self, mut f: F) -> Self + where + F: FnMut(f32, f32) -> f32, + { + Self { + x: f(self.x, rhs.x), + y: f(self.y, rhs.y), + z: f(self.z, rhs.z), + w: f(self.w, rhs.w), + } + } + #[inline] pub fn dot(a: Self, b: Self) -> f32 { a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w @@ -218,5 +232,10 @@ mod tests { assert_eq!(Vec4::new(2.0, 2.0, 2.0, 2.0).length_sq(), 16.0); assert_eq!(Vec4::new(2.0, 2.0, 2.0, 2.0).length(), 4.0); + + assert_eq!( + Vec4::clamp(Vec4::ONE * 5.0, Vec4::ZERO, Vec4::ONE), + Vec4::ONE + ); } }