From 30948c4c8e9a251d7041de95572e97718612d0a9 Mon Sep 17 00:00:00 2001 From: Antony Date: Tue, 12 Mar 2024 21:38:28 -0400 Subject: [PATCH] Add `move_towards` for vectors (#492) --- codegen/templates/vec.rs.tera | 15 +++++++++++++++ src/f32/coresimd/vec3a.rs | 15 +++++++++++++++ src/f32/coresimd/vec4.rs | 15 +++++++++++++++ src/f32/scalar/vec3a.rs | 15 +++++++++++++++ src/f32/scalar/vec4.rs | 15 +++++++++++++++ src/f32/sse2/vec3a.rs | 15 +++++++++++++++ src/f32/sse2/vec4.rs | 15 +++++++++++++++ src/f32/vec2.rs | 15 +++++++++++++++ src/f32/vec3.rs | 15 +++++++++++++++ src/f32/wasm32/vec3a.rs | 15 +++++++++++++++ src/f32/wasm32/vec4.rs | 15 +++++++++++++++ src/f64/dvec2.rs | 15 +++++++++++++++ src/f64/dvec3.rs | 15 +++++++++++++++ src/f64/dvec4.rs | 15 +++++++++++++++ tests/vec2.rs | 8 ++++++++ tests/vec3.rs | 8 ++++++++ tests/vec4.rs | 8 ++++++++ 17 files changed, 234 insertions(+) diff --git a/codegen/templates/vec.rs.tera b/codegen/templates/vec.rs.tera index 489014ab..f0763519 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 52f58be9..abc2dca3 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 59b11eba..8430d156 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 a5e148eb..133afa13 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 538a064b..3f05963d 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 72d66f5a..9d6cd7c2 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 f97884f4..ae375196 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 4154a2d3..d33eca08 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 1c3314ba..467568d6 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 8f59ddd6..82c791be 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 0075de8f..9707275a 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 3661b153..9618b4c2 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 c96f89cb..ce8be9b4 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 d60e4b78..574260a8 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. diff --git a/tests/vec2.rs b/tests/vec2.rs index e8044b57..c1a3e9c8 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 86730561..bd5459a0 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 bc70a74b..d0fedb2c 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);