Repository: bitshifter/glam-rs
Pull request #492 (2024-03-11 23:20:34)

Add `move_towards` for vectors
Adds a `move_towards` function for vectors based on #477 and #265, with tests.



Patch:
diff --git a/codegen/templates/vec.rs.tera b/codegen/templates/vec.rs.tera
index 489014a..f076351 100644
--- a/codegen/templates/vec.rs.tera
+++ b/codegen/templates/vec.rs.tera
@@ -1609,6 +1609,21 @@ impl {{ self_t }} {
         self + ((rhs - self) * s)
     }
 
+    /// Moves towards `rhs` based on the value `d`.
+    ///
+    /// When `d` is `0.0`, the result will be equal to `self`. When `d` is equal to 
+    /// `self.distance(rhs)`, the result will be equal to `rhs`. Will not go past `rhs`.
+    #[inline]
+    #[must_use]
+    pub fn move_towards(&self, rhs: Self, d: {{ scalar_t }}) -> Self {
+        let a = rhs - *self;
+        let len = a.length();
+        if len <= d || len <= 1e-4 {
+            return rhs;
+        }
+        *self + a / len * d 
+    }
+
     /// Calculates the midpoint between `self` and `rhs`. 
     ///
     /// The midpoint is the average of, or halfway point between, two vectors.
diff --git a/src/f32/coresimd/vec3a.rs b/src/f32/coresimd/vec3a.rs
index 52f58be..abc2dca 100644
--- a/src/f32/coresimd/vec3a.rs
+++ b/src/f32/coresimd/vec3a.rs
@@ -673,6 +673,21 @@ impl Vec3A {
         self + ((rhs - self) * s)
     }
 
+    /// Moves towards `rhs` based on the value `d`.
+    ///
+    /// When `d` is `0.0`, the result will be equal to `self`. When `d` is equal to
+    /// `self.distance(rhs)`, the result will be equal to `rhs`. Will not go past `rhs`.
+    #[inline]
+    #[must_use]
+    pub fn move_towards(&self, rhs: Self, d: f32) -> Self {
+        let a = rhs - *self;
+        let len = a.length();
+        if len <= d || len <= 1e-4 {
+            return rhs;
+        }
+        *self + a / len * d
+    }
+
     /// Calculates the midpoint between `self` and `rhs`.
     ///
     /// The midpoint is the average of, or halfway point between, two vectors.
diff --git a/src/f32/coresimd/vec4.rs b/src/f32/coresimd/vec4.rs
index 59b11eb..8430d15 100644
--- a/src/f32/coresimd/vec4.rs
+++ b/src/f32/coresimd/vec4.rs
@@ -651,6 +651,21 @@ impl Vec4 {
         self + ((rhs - self) * s)
     }
 
+    /// Moves towards `rhs` based on the value `d`.
+    ///
+    /// When `d` is `0.0`, the result will be equal to `self`. When `d` is equal to
+    /// `self.distance(rhs)`, the result will be equal to `rhs`. Will not go past `rhs`.
+    #[inline]
+    #[must_use]
+    pub fn move_towards(&self, rhs: Self, d: f32) -> Self {
+        let a = rhs - *self;
+        let len = a.length();
+        if len <= d || len <= 1e-4 {
+            return rhs;
+        }
+        *self + a / len * d
+    }
+
     /// Calculates the midpoint between `self` and `rhs`.
     ///
     /// The midpoint is the average of, or halfway point between, two vectors.
diff --git a/src/f32/scalar/vec3a.rs b/src/f32/scalar/vec3a.rs
index a5e148e..133afa1 100644
--- a/src/f32/scalar/vec3a.rs
+++ b/src/f32/scalar/vec3a.rs
@@ -714,6 +714,21 @@ impl Vec3A {
         self + ((rhs - self) * s)
     }
 
+    /// Moves towards `rhs` based on the value `d`.
+    ///
+    /// When `d` is `0.0`, the result will be equal to `self`. When `d` is equal to
+    /// `self.distance(rhs)`, the result will be equal to `rhs`. Will not go past `rhs`.
+    #[inline]
+    #[must_use]
+    pub fn move_towards(&self, rhs: Self, d: f32) -> Self {
+        let a = rhs - *self;
+        let len = a.length();
+        if len <= d || len <= 1e-4 {
+            return rhs;
+        }
+        *self + a / len * d
+    }
+
     /// Calculates the midpoint between `self` and `rhs`.
     ///
     /// The midpoint is the average of, or halfway point between, two vectors.
diff --git a/src/f32/scalar/vec4.rs b/src/f32/scalar/vec4.rs
index 538a064..3f05963 100644
--- a/src/f32/scalar/vec4.rs
+++ b/src/f32/scalar/vec4.rs
@@ -760,6 +760,21 @@ impl Vec4 {
         self + ((rhs - self) * s)
     }
 
+    /// Moves towards `rhs` based on the value `d`.
+    ///
+    /// When `d` is `0.0`, the result will be equal to `self`. When `d` is equal to
+    /// `self.distance(rhs)`, the result will be equal to `rhs`. Will not go past `rhs`.
+    #[inline]
+    #[must_use]
+    pub fn move_towards(&self, rhs: Self, d: f32) -> Self {
+        let a = rhs - *self;
+        let len = a.length();
+        if len <= d || len <= 1e-4 {
+            return rhs;
+        }
+        *self + a / len * d
+    }
+
     /// Calculates the midpoint between `self` and `rhs`.
     ///
     /// The midpoint is the average of, or halfway point between, two vectors.
diff --git a/src/f32/sse2/vec3a.rs b/src/f32/sse2/vec3a.rs
index 72d66f5..9d6cd7c 100644
--- a/src/f32/sse2/vec3a.rs
+++ b/src/f32/sse2/vec3a.rs
@@ -721,6 +721,21 @@ impl Vec3A {
         self + ((rhs - self) * s)
     }
 
+    /// Moves towards `rhs` based on the value `d`.
+    ///
+    /// When `d` is `0.0`, the result will be equal to `self`. When `d` is equal to
+    /// `self.distance(rhs)`, the result will be equal to `rhs`. Will not go past `rhs`.
+    #[inline]
+    #[must_use]
+    pub fn move_towards(&self, rhs: Self, d: f32) -> Self {
+        let a = rhs - *self;
+        let len = a.length();
+        if len <= d || len <= 1e-4 {
+            return rhs;
+        }
+        *self + a / len * d
+    }
+
     /// Calculates the midpoint between `self` and `rhs`.
     ///
     /// The midpoint is the average of, or halfway point between, two vectors.
diff --git a/src/f32/sse2/vec4.rs b/src/f32/sse2/vec4.rs
index f97884f..ae37519 100644
--- a/src/f32/sse2/vec4.rs
+++ b/src/f32/sse2/vec4.rs
@@ -700,6 +700,21 @@ impl Vec4 {
         self + ((rhs - self) * s)
     }
 
+    /// Moves towards `rhs` based on the value `d`.
+    ///
+    /// When `d` is `0.0`, the result will be equal to `self`. When `d` is equal to
+    /// `self.distance(rhs)`, the result will be equal to `rhs`. Will not go past `rhs`.
+    #[inline]
+    #[must_use]
+    pub fn move_towards(&self, rhs: Self, d: f32) -> Self {
+        let a = rhs - *self;
+        let len = a.length();
+        if len <= d || len <= 1e-4 {
+            return rhs;
+        }
+        *self + a / len * d
+    }
+
     /// Calculates the midpoint between `self` and `rhs`.
     ///
     /// The midpoint is the average of, or halfway point between, two vectors.
diff --git a/src/f32/vec2.rs b/src/f32/vec2.rs
index 4154a2d..d33eca0 100644
--- a/src/f32/vec2.rs
+++ b/src/f32/vec2.rs
@@ -646,6 +646,21 @@ impl Vec2 {
         self + ((rhs - self) * s)
     }
 
+    /// Moves towards `rhs` based on the value `d`.
+    ///
+    /// When `d` is `0.0`, the result will be equal to `self`. When `d` is equal to
+    /// `self.distance(rhs)`, the result will be equal to `rhs`. Will not go past `rhs`.
+    #[inline]
+    #[must_use]
+    pub fn move_towards(&self, rhs: Self, d: f32) -> Self {
+        let a = rhs - *self;
+        let len = a.length();
+        if len <= d || len <= 1e-4 {
+            return rhs;
+        }
+        *self + a / len * d
+    }
+
     /// Calculates the midpoint between `self` and `rhs`.
     ///
     /// The midpoint is the average of, or halfway point between, two vectors.
diff --git a/src/f32/vec3.rs b/src/f32/vec3.rs
index 1c3314b..467568d 100644
--- a/src/f32/vec3.rs
+++ b/src/f32/vec3.rs
@@ -705,6 +705,21 @@ impl Vec3 {
         self + ((rhs - self) * s)
     }
 
+    /// Moves towards `rhs` based on the value `d`.
+    ///
+    /// When `d` is `0.0`, the result will be equal to `self`. When `d` is equal to
+    /// `self.distance(rhs)`, the result will be equal to `rhs`. Will not go past `rhs`.
+    #[inline]
+    #[must_use]
+    pub fn move_towards(&self, rhs: Self, d: f32) -> Self {
+        let a = rhs - *self;
+        let len = a.length();
+        if len <= d || len <= 1e-4 {
+            return rhs;
+        }
+        *self + a / len * d
+    }
+
     /// Calculates the midpoint between `self` and `rhs`.
     ///
     /// The midpoint is the average of, or halfway point between, two vectors.
diff --git a/src/f32/wasm32/vec3a.rs b/src/f32/wasm32/vec3a.rs
index 8f59ddd..82c791b 100644
--- a/src/f32/wasm32/vec3a.rs
+++ b/src/f32/wasm32/vec3a.rs
@@ -692,6 +692,21 @@ impl Vec3A {
         self + ((rhs - self) * s)
     }
 
+    /// Moves towards `rhs` based on the value `d`.
+    ///
+    /// When `d` is `0.0`, the result will be equal to `self`. When `d` is equal to
+    /// `self.distance(rhs)`, the result will be equal to `rhs`. Will not go past `rhs`.
+    #[inline]
+    #[must_use]
+    pub fn move_towards(&self, rhs: Self, d: f32) -> Self {
+        let a = rhs - *self;
+        let len = a.length();
+        if len <= d || len <= 1e-4 {
+            return rhs;
+        }
+        *self + a / len * d
+    }
+
     /// Calculates the midpoint between `self` and `rhs`.
     ///
     /// The midpoint is the average of, or halfway point between, two vectors.
diff --git a/src/f32/wasm32/vec4.rs b/src/f32/wasm32/vec4.rs
index 0075de8..9707275 100644
--- a/src/f32/wasm32/vec4.rs
+++ b/src/f32/wasm32/vec4.rs
@@ -678,6 +678,21 @@ impl Vec4 {
         self + ((rhs - self) * s)
     }
 
+    /// Moves towards `rhs` based on the value `d`.
+    ///
+    /// When `d` is `0.0`, the result will be equal to `self`. When `d` is equal to
+    /// `self.distance(rhs)`, the result will be equal to `rhs`. Will not go past `rhs`.
+    #[inline]
+    #[must_use]
+    pub fn move_towards(&self, rhs: Self, d: f32) -> Self {
+        let a = rhs - *self;
+        let len = a.length();
+        if len <= d || len <= 1e-4 {
+            return rhs;
+        }
+        *self + a / len * d
+    }
+
     /// Calculates the midpoint between `self` and `rhs`.
     ///
     /// The midpoint is the average of, or halfway point between, two vectors.
diff --git a/src/f64/dvec2.rs b/src/f64/dvec2.rs
index 3661b15..9618b4c 100644
--- a/src/f64/dvec2.rs
+++ b/src/f64/dvec2.rs
@@ -646,6 +646,21 @@ impl DVec2 {
         self + ((rhs - self) * s)
     }
 
+    /// Moves towards `rhs` based on the value `d`.
+    ///
+    /// When `d` is `0.0`, the result will be equal to `self`. When `d` is equal to
+    /// `self.distance(rhs)`, the result will be equal to `rhs`. Will not go past `rhs`.
+    #[inline]
+    #[must_use]
+    pub fn move_towards(&self, rhs: Self, d: f64) -> Self {
+        let a = rhs - *self;
+        let len = a.length();
+        if len <= d || len <= 1e-4 {
+            return rhs;
+        }
+        *self + a / len * d
+    }
+
     /// Calculates the midpoint between `self` and `rhs`.
     ///
     /// The midpoint is the average of, or halfway point between, two vectors.
diff --git a/src/f64/dvec3.rs b/src/f64/dvec3.rs
index c96f89c..ce8be9b 100644
--- a/src/f64/dvec3.rs
+++ b/src/f64/dvec3.rs
@@ -705,6 +705,21 @@ impl DVec3 {
         self + ((rhs - self) * s)
     }
 
+    /// Moves towards `rhs` based on the value `d`.
+    ///
+    /// When `d` is `0.0`, the result will be equal to `self`. When `d` is equal to
+    /// `self.distance(rhs)`, the result will be equal to `rhs`. Will not go past `rhs`.
+    #[inline]
+    #[must_use]
+    pub fn move_towards(&self, rhs: Self, d: f64) -> Self {
+        let a = rhs - *self;
+        let len = a.length();
+        if len <= d || len <= 1e-4 {
+            return rhs;
+        }
+        *self + a / len * d
+    }
+
     /// Calculates the midpoint between `self` and `rhs`.
     ///
     /// The midpoint is the average of, or halfway point between, two vectors.
diff --git a/src/f64/dvec4.rs b/src/f64/dvec4.rs
index d60e4b7..574260a 100644
--- a/src/f64/dvec4.rs
+++ b/src/f64/dvec4.rs
@@ -749,6 +749,21 @@ impl DVec4 {
         self + ((rhs - self) * s)
     }
 
+    /// Moves towards `rhs` based on the value `d`.
+    ///
+    /// When `d` is `0.0`, the result will be equal to `self`. When `d` is equal to
+    /// `self.distance(rhs)`, the result will be equal to `rhs`. Will not go past `rhs`.
+    #[inline]
+    #[must_use]
+    pub fn move_towards(&self, rhs: Self, d: f64) -> Self {
+        let a = rhs - *self;
+        let len = a.length();
+        if len <= d || len <= 1e-4 {
+            return rhs;
+        }
+        *self + a / len * d
+    }
+
     /// Calculates the midpoint between `self` and `rhs`.
     ///
     /// The midpoint is the average of, or halfway point between, two vectors.


Test patch:
diff --git a/tests/vec2.rs b/tests/vec2.rs
index e8044b5..c1a3e9c 100644
--- a/tests/vec2.rs
+++ b/tests/vec2.rs
@@ -820,6 +820,14 @@ macro_rules! impl_vec2_float_tests {
             assert_approx_eq!($vec2::ZERO, v0.lerp(v1, 0.5));
         });
 
+        glam_test!(test_move_towards, {
+            let v0 = $vec2::new(-1.0, -1.0);
+            let v1 = $vec2::new(1.0, 1.0);
+            assert_approx_eq!(v0, v0.move_towards(v1, 0.0));
+            assert_approx_eq!(v1, v0.move_towards(v1, v0.distance(v1)));
+            assert_approx_eq!(v1, v0.move_towards(v1, v0.distance(v1) + 1.0));
+        });
+
         glam_test!(test_midpoint, {
             let v0 = $vec2::new(-1.0, -1.0);
             let v1 = $vec2::new(1.0, 1.0);
diff --git a/tests/vec3.rs b/tests/vec3.rs
index 8673056..bd5459a 100644
--- a/tests/vec3.rs
+++ b/tests/vec3.rs
@@ -955,6 +955,14 @@ macro_rules! impl_vec3_float_tests {
             assert_approx_eq!($vec3::ZERO, v0.lerp(v1, 0.5));
         });
 
+        glam_test!(test_move_towards, {
+            let v0 = $vec3::new(-1.0, -1.0, -1.0);
+            let v1 = $vec3::new(1.0, 1.0, 1.0);
+            assert_approx_eq!(v0, v0.move_towards(v1, 0.0));
+            assert_approx_eq!(v1, v0.move_towards(v1, v0.distance(v1)));
+            assert_approx_eq!(v1, v0.move_towards(v1, v0.distance(v1) + 1.0));
+        });
+
         glam_test!(test_midpoint, {
             let v0 = $vec3::new(-1.0, -1.0, -1.0);
             let v1 = $vec3::new(1.0, 1.0, 1.0);
diff --git a/tests/vec4.rs b/tests/vec4.rs
index bc70a74..d0fedb2 100644
--- a/tests/vec4.rs
+++ b/tests/vec4.rs
@@ -1075,6 +1075,14 @@ macro_rules! impl_vec4_float_tests {
             assert_approx_eq!($vec4::ZERO, v0.lerp(v1, 0.5));
         });
 
+        glam_test!(test_move_towards, {
+            let v0 = $vec4::new(-1.0, -1.0, -1.0, -1.0);
+            let v1 = $vec4::new(1.0, 1.0, 1.0, 1.0);
+            assert_approx_eq!(v0, v0.move_towards(v1, 0.0));
+            assert_approx_eq!(v1, v0.move_towards(v1, v0.distance(v1)));
+            assert_approx_eq!(v1, v0.move_towards(v1, v0.distance(v1) + 1.0));
+        });
+
         glam_test!(test_midpoint, {
             let v0 = $vec4::new(-1.0, -1.0, -1.0, -1.0);
             let v1 = $vec4::new(1.0, 1.0, 1.0, 1.0);