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}