From 3d3ffbf79aecca630f742a9a488404c6294e3d67 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Fri, 23 Aug 2024 15:57:12 -0700 Subject: [PATCH] steal --- src/macros/mod.rs | 1 + src/macros/wide.rs | 315 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 316 insertions(+) create mode 100644 src/macros/wide.rs diff --git a/src/macros/mod.rs b/src/macros/mod.rs index c7be6b0..4e65a86 100644 --- a/src/macros/mod.rs +++ b/src/macros/mod.rs @@ -1,4 +1,5 @@ // Stolen from https://github.com/c1m50c/fixed-vectors (MIT license) +mod wide; #[doc(hidden)] #[macro_export(local_inner_macros)] diff --git a/src/macros/wide.rs b/src/macros/wide.rs new file mode 100644 index 0000000..23b4527 --- /dev/null +++ b/src/macros/wide.rs @@ -0,0 +1,315 @@ +#[doc(hidden)] +#[macro_export(local_inner_macros)] +macro_rules! impl_floating_point_operations { + ( $struct: ident { $($field: ident), + }, $size: expr ) => { + impl $struct { + /// Returns the dot product of two vectors. + /// + /// # Example + /// + /// ``` + /// use fixed_vectors::Vector2; + /// + /// let a = Vector2::new(1.0, 2.0); + /// let b = Vector2::new(2.0, 4.0); + /// let dot = a.dot(&b); + /// + /// assert_eq!(dot, 10.0); + /// ``` + #[inline] + pub fn dot(&self, other: &Self) -> T { + $crate::sum_repeating!( + $( + (self.$field * other.$field) ) + + ) + } + + /// Returns the squared magnitude of vector. + /// + /// # Example + /// + /// ``` + /// use fixed_vectors::Vector3; + /// + /// let vec3 = Vector3::new(3.33, 2.04, 1.337); + /// let lsq = vec3.length_squared(); + /// + /// assert!(lsq >= 17.0); + /// ``` + pub fn length_squared(&self) -> T { + let squared = Self { + $( $field: self.$field * self.$field ), + + }; + + $crate::sum_repeating!( + $( + squared.$field ) + + ) + } + + /// Applies [`floor`](num_traits::float::FloatCore::floor) on all fields within the vector, + /// converting each field to the largest integer less than or equal to its value. + /// + /// # Example + /// + /// ``` + /// use fixed_vectors::Vector2; + /// + /// let vec2 = Vector2::new(1.6, 2.3).floor(); + /// + /// assert_eq!(vec2, Vector2::new(1.0, 2.0)); + /// ``` + #[inline] + pub fn floor(self) -> Self { + self.map(T::floor) + } + + /// Applies [`ceil`](num_traits::float::FloatCore::ceil) on all fields within the vector, + /// converting each field to the largest integer greater than or equal to its value. + /// + /// # Example + /// + /// ``` + /// use fixed_vectors::Vector2; + /// + /// let vec2 = Vector2::new(1.6, 2.3).ceil(); + /// + /// assert_eq!(vec2, Vector2::new(2.0, 3.0)); + /// ``` + #[inline] + pub fn ceil(self) -> Self { + self.map(T::ceil) + } + + /// Applies [`round`](num_traits::float::FloatCore::round) on all fields within the vector, + /// converting each field's value to its nearest integer. + /// + /// # Example + /// + /// ``` + /// use fixed_vectors::Vector2; + /// + /// let vec2 = Vector2::new(1.6, 2.3).round(); + /// + /// assert_eq!(vec2, Vector2::new(2.0, 2.0)); + /// ``` + #[inline] + pub fn round(self) -> Self { + self.map(T::round) + } + + /// Applies [`abs`](num_traits::float::FloatCore::abs) on all fields within the vector, + /// converting each field to their absolute value. + /// + /// # Example + /// + /// ``` + /// use fixed_vectors::Vector2; + /// + /// let vec2 = Vector2::new(-2.6, 2.3).abs(); + /// + /// assert_eq!(vec2, Vector2::new(2.6, 2.3)); + /// ``` + #[inline] + pub fn abs(self) -> Self { + self.map(T::abs) + } + + /// Applies [`trunc`](num_traits::float::FloatCore::trunc) on all fields within the vector, + /// converting each field's value to their integer parts. + /// + /// # Example + /// + /// ``` + /// use fixed_vectors::Vector2; + /// + /// let vec2 = Vector2::new(-2.6, 2.3).trunc(); + /// + /// assert_eq!(vec2, Vector2::new(-2.0, 2.0)); + /// ``` + #[inline] + pub fn trunc(self) -> Self { + self.map(T::trunc) + } + + /// Applies [`fract`](num_traits::float::FloatCore::fract) on all fields within the vector, + /// converting each field's value to their fractional parts. + /// + /// # Example + /// + /// ``` + /// use fixed_vectors::Vector2; + /// + /// let vec2 = Vector2::new(-2.5, 2.25).fract(); + /// + /// assert_eq!(vec2, Vector2::new(-0.5, 0.25)); + /// ``` + #[inline] + pub fn fract(self) -> Self { + self.map(T::fract) + } + + /// Applies [`powi`](num_traits::float::FloatCore::powi) on all fields within the vector, + /// raising each field's value to an integer power. + /// + /// # Example + /// + /// ``` + /// use fixed_vectors::Vector2; + /// + /// let vec2 = Vector2::new(2.0, 4.0).powi(2); + /// + /// assert_eq!(vec2, Vector2::new(4.0, 16.0)); + /// ``` + #[inline] + pub fn powi(self, n: i32) -> Self { + self.map(|f| f.powi(n)) + } + + /// Linearly interpolates between two Vectors by a normalized `weight`. + /// + /// # Example + /// + /// ``` + /// use fixed_vectors::Vector2; + /// + /// let vec2 = Vector2::new(1.0, 2.0).lerp( + /// Vector2::new(2.0, 3.0), 1.0 + /// ); + /// + /// assert_eq!(vec2, Vector2::new(2.0, 3.0)); + /// ``` + #[inline(always)] + pub fn lerp(self, to: Self, weight: T) -> Self { + Self { + $( $field: self.$field + (weight * (to.$field - self.$field)) ), + + } + } + } + + impl $struct + where + T: $crate::macros::floating::_FloatingPoint + + num_traits::float::FloatCore + { + /// Consumes the vector and returns it with all of its fields converted to their square-root. + /// + /// # Example + /// + /// ``` + /// use fixed_vectors::Vector2; + /// + /// let vec2 = Vector2::new(64.0, 25.0).sqrt(); + /// + /// assert_eq!(vec2, Vector2::new(8.0, 5.0)); + /// ``` + #[inline] + pub fn sqrt(self) -> Self { + self.map(T::sqrt) + } + + /// Returns the magnitude of the vector. + /// + /// # Example + /// + /// ``` + /// use fixed_vectors::Vector3; + /// + /// let vec3 = Vector3::new(1.5, 2.0, 3.33); + /// let length = vec3.length(); + /// + /// assert!(length < 4.2); + /// ``` + #[inline] + pub fn length(&self) -> T { + self.length_squared().sqrt() + } + + /// Consumes the vector and returns it as normalized vector. + /// + /// # Example + /// + /// ``` + /// use fixed_vectors::Vector2; + /// + /// let vec2 = Vector2::new(14.3, 7.9).normalized(); + /// + /// assert!(vec2.x < 1.0); + /// assert!(vec2.y < 1.0); + /// ``` + pub fn normalized(self) -> Self { + let length_squared = self.length_squared(); + + if length_squared == T::zero() { + return Self { $( $field: T::zero() ), + }; + } + + let length = length_squared.sqrt(); + + Self { + $( $field: self.$field / length ), + + } + } + + /// Normalizes the vector through mutation. + /// + /// # Example + /// + /// ``` + /// use fixed_vectors::Vector2; + /// + /// let mut vec2 = Vector2::new(14.3, 7.9); + /// vec2.normalize(); + /// + /// assert!(vec2.x < 1.0); + /// assert!(vec2.y < 1.0); + /// ``` + pub fn normalize(&mut self) { + let length_squared = self.length_squared(); + + if length_squared == T::zero() { + *self = Self { $( $field: T::zero() ), + }; + return; + } + + let length = length_squared.sqrt(); + + *self = Self { + $( $field: self.$field / length ), + + } + } + } + }; +} + + +// HACK: Allows us to sum repeating tokens in macros. +// See: https://stackoverflow.com/a/60187870/17452730 +#[doc(hidden)] +#[macro_export(local_inner_macros)] +macro_rules! sum_repeating { + ( + $($item: tt) * ) => { + $($item) * + }; +} + + +// Required trait for `sqrt` impls +#[doc(hidden)] +pub trait _FloatingPoint { + fn sqrt(self) -> Self; +} + + +impl _FloatingPoint for f32 { + #[inline(always)] + fn sqrt(self) -> Self { + libm::sqrtf(self) + } +} + + +impl _FloatingPoint for f64 { + #[inline(always)] + fn sqrt(self) -> Self { + libm::sqrt(self) + } +}