]> git.nega.tv - josh/narcissus/commitdiff
Add `min`, `max` and `clamp` functions
authorJoshua Simmons <josh@nega.tv>
Thu, 8 Sep 2022 06:51:34 +0000 (08:51 +0200)
committerJoshua Simmons <josh@nega.tv>
Thu, 8 Sep 2022 06:51:34 +0000 (08:51 +0200)
narcissus-maths/src/lib.rs
narcissus-maths/src/point2.rs
narcissus-maths/src/point3.rs
narcissus-maths/src/vec2.rs
narcissus-maths/src/vec3.rs
narcissus-maths/src/vec4.rs

index 174f69f3a8638c303e54e3a8604347b6adcab0ea..015959238bf6f5871dd226120fee2cb87423860c 100644 (file)
@@ -64,6 +64,30 @@ impl From<Deg> 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()
             }
         }
     };
index 109d197539ddcf5aa9fc46ace44e3eee52f0f488..4e1a60a894d8a3c97286bbbd0469c3eb4a398e13 100644 (file)
@@ -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<F>(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 {
index 721e6c0aad8df7b3f3a91f97918aa2c8b4a12d23..c3aa2e408540418a1636a784c159c88bdced7f24 100644 (file)
@@ -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<F>(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 {
index 8056dbebc4f245347f77db831af56554058c29e9..156d104c1096d26969030edebbb6be2025628ec4 100644 (file)
@@ -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<F>(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
index b609f88a02d765b9ed8f32d98336b82c4218f1c5..507d9afabec8840603d3ddc6a5797c7962fa4fa1 100644 (file)
@@ -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<F>(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
index f0f23921ee1b94f2c68e1763c147d2fcc5a5a13b..a73b97673a77c4ae6ad5cb1d72e69bdeace8866b 100644 (file)
@@ -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<F>(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
+        );
     }
 }