fixed_vectors/macros/
floating.rs

1#[doc(hidden)]
2#[macro_export(local_inner_macros)]
3macro_rules! impl_floating_point_operations {
4    ( $struct: ident { $($field: ident), + }, $size: expr ) => {
5        impl<T: num_traits::float::FloatCore> $struct<T> {
6            /// Returns the dot product of two vectors.
7            /// 
8            /// # Example
9            /// 
10            /// ```
11            /// use fixed_vectors::Vector2;
12            /// 
13            /// let a = Vector2::new(1.0, 2.0);
14            /// let b = Vector2::new(2.0, 4.0);
15            /// let dot = a.dot(&b);
16            /// 
17            /// assert_eq!(dot, 10.0);
18            /// ```
19            #[inline]
20            pub fn dot(&self, other: &Self) -> T {
21                $crate::sum_repeating!(
22                    $( + (self.$field * other.$field) ) +
23                )
24            }
25
26            /// Returns the squared magnitude of vector.
27            /// 
28            /// # Example
29            /// 
30            /// ```
31            /// use fixed_vectors::Vector3;
32            /// 
33            /// let vec3 = Vector3::new(3.33, 2.04, 1.337);
34            /// let lsq = vec3.length_squared();
35            /// 
36            /// assert!(lsq >= 17.0);
37            /// ```
38            pub fn length_squared(&self) -> T {
39                let squared = Self {
40                    $( $field: self.$field * self.$field ), +
41                };
42
43                $crate::sum_repeating!(
44                    $( + squared.$field ) +
45                )
46            }
47
48            /// Applies [`floor`](num_traits::float::FloatCore::floor) on all fields within the vector,
49            /// converting each field to the largest integer less than or equal to its value.
50            /// 
51            /// # Example
52            /// 
53            /// ```
54            /// use fixed_vectors::Vector2;
55            /// 
56            /// let vec2 = Vector2::new(1.6, 2.3).floor();
57            /// 
58            /// assert_eq!(vec2, Vector2::new(1.0, 2.0));
59            /// ```
60            #[inline]
61            pub fn floor(self) -> Self {
62                self.map(T::floor)
63            }
64
65            /// Applies [`ceil`](num_traits::float::FloatCore::ceil) on all fields within the vector,
66            /// converting each field to the largest integer greater than or equal to its value.
67            /// 
68            /// # Example
69            /// 
70            /// ```
71            /// use fixed_vectors::Vector2;
72            /// 
73            /// let vec2 = Vector2::new(1.6, 2.3).ceil();
74            /// 
75            /// assert_eq!(vec2, Vector2::new(2.0, 3.0));
76            /// ```
77            #[inline]
78            pub fn ceil(self) -> Self {
79                self.map(T::ceil)
80            }
81
82            /// Applies [`round`](num_traits::float::FloatCore::round) on all fields within the vector,
83            /// converting each field's value to its nearest integer.
84            /// 
85            /// # Example
86            /// 
87            /// ```
88            /// use fixed_vectors::Vector2;
89            /// 
90            /// let vec2 = Vector2::new(1.6, 2.3).round();
91            /// 
92            /// assert_eq!(vec2, Vector2::new(2.0, 2.0));
93            /// ```
94            #[inline]
95            pub fn round(self) -> Self {
96                self.map(T::round)
97            }
98
99            /// Applies [`abs`](num_traits::float::FloatCore::abs) on all fields within the vector,
100            /// converting each field to their absolute value.
101            /// 
102            /// # Example
103            /// 
104            /// ```
105            /// use fixed_vectors::Vector2;
106            /// 
107            /// let vec2 = Vector2::new(-2.6, 2.3).abs();
108            /// 
109            /// assert_eq!(vec2, Vector2::new(2.6, 2.3));
110            /// ```
111            #[inline]
112            pub fn abs(self) -> Self {
113                self.map(T::abs)
114            }
115
116            /// Applies [`trunc`](num_traits::float::FloatCore::trunc) on all fields within the vector,
117            /// converting each field's value to their integer parts.
118            /// 
119            /// # Example
120            /// 
121            /// ```
122            /// use fixed_vectors::Vector2;
123            /// 
124            /// let vec2 = Vector2::new(-2.6, 2.3).trunc();
125            /// 
126            /// assert_eq!(vec2, Vector2::new(-2.0, 2.0));
127            /// ```
128            #[inline]
129            pub fn trunc(self) -> Self {
130                self.map(T::trunc)
131            }
132
133            /// Applies [`fract`](num_traits::float::FloatCore::fract) on all fields within the vector,
134            /// converting each field's value to their fractional parts.
135            /// 
136            /// # Example
137            /// 
138            /// ```
139            /// use fixed_vectors::Vector2;
140            /// 
141            /// let vec2 = Vector2::new(-2.5, 2.25).fract();
142            /// 
143            /// assert_eq!(vec2, Vector2::new(-0.5, 0.25));
144            /// ```
145            #[inline]
146            pub fn fract(self) -> Self {
147                self.map(T::fract)
148            }
149
150            /// Applies [`powi`](num_traits::float::FloatCore::powi) on all fields within the vector,
151            /// raising each field's value to an integer power.
152            /// 
153            /// # Example
154            /// 
155            /// ```
156            /// use fixed_vectors::Vector2;
157            /// 
158            /// let vec2 = Vector2::new(2.0, 4.0).powi(2);
159            /// 
160            /// assert_eq!(vec2, Vector2::new(4.0, 16.0));
161            /// ```
162            #[inline]
163            pub fn powi(self, n: i32) -> Self {
164                self.map(|f| f.powi(n))
165            }
166
167            /// Linearly interpolates between two Vectors by a normalized `weight`.
168            /// 
169            /// # Example
170            /// 
171            /// ```
172            /// use fixed_vectors::Vector2;
173            /// 
174            /// let vec2 = Vector2::new(1.0, 2.0).lerp(
175            ///     Vector2::new(2.0, 3.0), 1.0
176            /// );
177            /// 
178            /// assert_eq!(vec2, Vector2::new(2.0, 3.0));
179            /// ```
180            #[inline(always)]
181            pub fn lerp(self, to: Self, weight: T) -> Self {
182                Self {
183                    $( $field: self.$field + (weight * (to.$field - self.$field)) ), +
184                }
185            }
186        }
187
188        impl<T> $struct<T>
189        where
190            T: $crate::macros::floating::_FloatingPoint
191            + num_traits::float::FloatCore
192        {
193            /// Consumes the vector and returns it with all of its fields converted to their square-root.
194            /// 
195            /// # Example
196            /// 
197            /// ```
198            /// use fixed_vectors::Vector2;
199            /// 
200            /// let vec2 = Vector2::new(64.0, 25.0).sqrt();
201            /// 
202            /// assert_eq!(vec2, Vector2::new(8.0, 5.0));
203            /// ```
204            #[inline]
205            pub fn sqrt(self) -> Self {
206                self.map(T::sqrt)
207            }
208
209            /// Returns the magnitude of the vector.
210            /// 
211            /// # Example
212            /// 
213            /// ```
214            /// use fixed_vectors::Vector3;
215            /// 
216            /// let vec3 = Vector3::new(1.5, 2.0, 3.33);
217            /// let length = vec3.length();
218            /// 
219            /// assert!(length < 4.2);
220            /// ```
221            #[inline]
222            pub fn length(&self) -> T {
223                self.length_squared().sqrt()
224            }
225
226            /// Consumes the vector and returns it as normalized vector.
227            /// 
228            /// # Example
229            /// 
230            /// ```
231            /// use fixed_vectors::Vector2;
232            /// 
233            /// let vec2 = Vector2::new(14.3, 7.9).normalized();
234            /// 
235            /// assert!(vec2.x < 1.0);
236            /// assert!(vec2.y < 1.0);
237            /// ```
238            pub fn normalized(self) -> Self {
239                let length_squared = self.length_squared();
240
241                if length_squared == T::zero() {
242                    return Self { $( $field: T::zero() ), + };
243                }
244
245                let length = length_squared.sqrt();
246
247                Self {
248                    $( $field: self.$field / length ), +
249                }
250            }
251
252            /// Normalizes the vector through mutation.
253            /// 
254            /// # Example
255            /// 
256            /// ```
257            /// use fixed_vectors::Vector2;
258            /// 
259            /// let mut vec2 = Vector2::new(14.3, 7.9);
260            /// vec2.normalize();
261            /// 
262            /// assert!(vec2.x < 1.0);
263            /// assert!(vec2.y < 1.0);
264            /// ```
265            pub fn normalize(&mut self) {
266                let length_squared = self.length_squared();
267
268                if length_squared == T::zero() {
269                    *self = Self { $( $field: T::zero() ), + };
270                    return;
271                }
272
273                let length = length_squared.sqrt();
274
275                *self = Self {
276                    $( $field: self.$field / length ), +
277                }
278            }
279        }
280    };
281}
282
283
284// HACK: Allows us to sum repeating tokens in macros.
285// See: https://stackoverflow.com/a/60187870/17452730
286#[doc(hidden)]
287#[macro_export(local_inner_macros)]
288macro_rules! sum_repeating {
289    ( + $($item: tt) * ) => {
290        $($item) *
291    };
292}
293
294
295// Required trait for `sqrt` impls
296#[doc(hidden)]
297pub trait _FloatingPoint {
298    fn sqrt(self) -> Self;
299}
300
301
302impl _FloatingPoint for f32 {
303    #[inline(always)]
304    fn sqrt(self) -> Self {
305        libm::sqrtf(self)
306    }
307}
308
309
310impl _FloatingPoint for f64 {
311    #[inline(always)]
312    fn sqrt(self) -> Self {
313        libm::sqrt(self)
314    }
315}