1use core::ops::{
2 Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Sub, SubAssign,
3};
4
5use crate::{EPSILON, acos, clamp, sqrt};
6
7#[derive(Clone, Copy, Debug, Default, PartialEq)]
9#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
10pub struct Vec2 {
11 pub x: f32,
13 pub y: f32,
15}
16
17#[derive(Clone, Copy, Debug, Default, PartialEq)]
19#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
20pub struct Vec3 {
21 pub x: f32,
23 pub y: f32,
25 pub z: f32,
27}
28
29#[derive(Clone, Copy, Debug, Default, PartialEq)]
31#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
32pub struct Vec4 {
33 pub x: f32,
35 pub y: f32,
37 pub z: f32,
39 pub w: f32,
41}
42
43impl Vec2 {
44 pub const ZERO: Self = Self::new(0.0, 0.0);
46 pub const ONE: Self = Self::new(1.0, 1.0);
48 pub const X: Self = Self::new(1.0, 0.0);
50 pub const Y: Self = Self::new(0.0, 1.0);
52
53 #[inline]
55 pub const fn new(x: f32, y: f32) -> Self {
56 Self { x, y }
57 }
58
59 #[inline]
61 pub fn dot(self, rhs: Self) -> f32 {
62 self.x * rhs.x + self.y * rhs.y
63 }
64
65 #[inline]
67 pub fn length_squared(self) -> f32 {
68 self.dot(self)
69 }
70
71 #[inline]
73 pub fn length(self) -> f32 {
74 sqrt(self.length_squared())
75 }
76
77 #[inline]
79 pub fn normalize(self) -> Self {
80 let length = self.length();
81 if length <= EPSILON {
82 Self::ZERO
83 } else {
84 self / length
85 }
86 }
87
88 #[inline]
90 pub fn lerp(self, rhs: Self, t: f32) -> Self {
91 self + (rhs - self) * t
92 }
93
94 #[inline]
96 pub fn distance(self, rhs: Self) -> f32 {
97 (rhs - self).length()
98 }
99
100 #[inline]
102 pub fn angle_between(self, rhs: Self) -> f32 {
103 let denom = self.length() * rhs.length();
104 if denom <= EPSILON {
105 0.0
106 } else {
107 acos(clamp(self.dot(rhs) / denom, -1.0, 1.0))
108 }
109 }
110
111 #[inline]
113 pub const fn to_array(self) -> [f32; 2] {
114 [self.x, self.y]
115 }
116}
117
118impl Vec3 {
119 pub const ZERO: Self = Self::new(0.0, 0.0, 0.0);
121 pub const ONE: Self = Self::new(1.0, 1.0, 1.0);
123 pub const X: Self = Self::new(1.0, 0.0, 0.0);
125 pub const Y: Self = Self::new(0.0, 1.0, 0.0);
127 pub const Z: Self = Self::new(0.0, 0.0, 1.0);
129 pub const NEG_Z: Self = Self::new(0.0, 0.0, -1.0);
131 pub const UP: Self = Self::Y;
133
134 #[inline]
136 pub const fn new(x: f32, y: f32, z: f32) -> Self {
137 Self { x, y, z }
138 }
139
140 #[inline]
142 pub fn dot(self, rhs: Self) -> f32 {
143 self.x * rhs.x + self.y * rhs.y + self.z * rhs.z
144 }
145
146 #[inline]
148 pub fn cross(self, rhs: Self) -> Self {
149 Self::new(
150 self.y * rhs.z - self.z * rhs.y,
151 self.z * rhs.x - self.x * rhs.z,
152 self.x * rhs.y - self.y * rhs.x,
153 )
154 }
155
156 #[inline]
158 pub fn length_squared(self) -> f32 {
159 self.dot(self)
160 }
161
162 #[inline]
164 pub fn length(self) -> f32 {
165 sqrt(self.length_squared())
166 }
167
168 #[inline]
170 pub fn normalize(self) -> Self {
171 let length = self.length();
172 if length <= EPSILON {
173 Self::ZERO
174 } else {
175 self / length
176 }
177 }
178
179 #[inline]
181 pub fn lerp(self, rhs: Self, t: f32) -> Self {
182 self + (rhs - self) * t
183 }
184
185 #[inline]
187 pub fn distance(self, rhs: Self) -> f32 {
188 (rhs - self).length()
189 }
190
191 #[inline]
193 pub fn reflect(self, normal: Self) -> Self {
194 self - normal * (2.0 * self.dot(normal))
195 }
196
197 #[inline]
199 pub fn angle_between(self, rhs: Self) -> f32 {
200 let denom = self.length() * rhs.length();
201 if denom <= EPSILON {
202 0.0
203 } else {
204 acos(clamp(self.dot(rhs) / denom, -1.0, 1.0))
205 }
206 }
207
208 #[inline]
210 pub fn mul_elements(self, rhs: Self) -> Self {
211 Self::new(self.x * rhs.x, self.y * rhs.y, self.z * rhs.z)
212 }
213
214 #[inline]
216 pub fn div_elements(self, rhs: Self) -> Self {
217 Self::new(
218 if rhs.x.abs() <= EPSILON {
219 0.0
220 } else {
221 self.x / rhs.x
222 },
223 if rhs.y.abs() <= EPSILON {
224 0.0
225 } else {
226 self.y / rhs.y
227 },
228 if rhs.z.abs() <= EPSILON {
229 0.0
230 } else {
231 self.z / rhs.z
232 },
233 )
234 }
235
236 #[inline]
238 pub const fn to_array(self) -> [f32; 3] {
239 [self.x, self.y, self.z]
240 }
241}
242
243impl Vec4 {
244 pub const ZERO: Self = Self::new(0.0, 0.0, 0.0, 0.0);
246 pub const ONE: Self = Self::new(1.0, 1.0, 1.0, 1.0);
248 pub const X: Self = Self::new(1.0, 0.0, 0.0, 0.0);
250 pub const Y: Self = Self::new(0.0, 1.0, 0.0, 0.0);
252 pub const Z: Self = Self::new(0.0, 0.0, 1.0, 0.0);
254 pub const W: Self = Self::new(0.0, 0.0, 0.0, 1.0);
256
257 #[inline]
259 pub const fn new(x: f32, y: f32, z: f32, w: f32) -> Self {
260 Self { x, y, z, w }
261 }
262
263 #[inline]
265 pub fn dot(self, rhs: Self) -> f32 {
266 self.x * rhs.x + self.y * rhs.y + self.z * rhs.z + self.w * rhs.w
267 }
268
269 #[inline]
271 pub fn length_squared(self) -> f32 {
272 self.dot(self)
273 }
274
275 #[inline]
277 pub fn length(self) -> f32 {
278 sqrt(self.length_squared())
279 }
280
281 #[inline]
283 pub fn normalize(self) -> Self {
284 let length = self.length();
285 if length <= EPSILON {
286 Self::ZERO
287 } else {
288 self / length
289 }
290 }
291
292 #[inline]
294 pub fn lerp(self, rhs: Self, t: f32) -> Self {
295 self + (rhs - self) * t
296 }
297
298 #[inline]
300 pub const fn truncate(self) -> Vec3 {
301 Vec3::new(self.x, self.y, self.z)
302 }
303
304 #[inline]
306 pub const fn to_array(self) -> [f32; 4] {
307 [self.x, self.y, self.z, self.w]
308 }
309}
310
311macro_rules! impl_vec_ops {
312 ($type:ident { $($field:ident),+ }) => {
313 impl Add for $type {
314 type Output = Self;
315 #[inline]
316 fn add(self, rhs: Self) -> Self::Output {
317 Self::new($(self.$field + rhs.$field),+)
318 }
319 }
320
321 impl AddAssign for $type {
322 #[inline]
323 fn add_assign(&mut self, rhs: Self) {
324 $(self.$field += rhs.$field;)+
325 }
326 }
327
328 impl Sub for $type {
329 type Output = Self;
330 #[inline]
331 fn sub(self, rhs: Self) -> Self::Output {
332 Self::new($(self.$field - rhs.$field),+)
333 }
334 }
335
336 impl SubAssign for $type {
337 #[inline]
338 fn sub_assign(&mut self, rhs: Self) {
339 $(self.$field -= rhs.$field;)+
340 }
341 }
342
343 impl Mul<f32> for $type {
344 type Output = Self;
345 #[inline]
346 fn mul(self, rhs: f32) -> Self::Output {
347 Self::new($(self.$field * rhs),+)
348 }
349 }
350
351 impl Mul<$type> for f32 {
352 type Output = $type;
353 #[inline]
354 fn mul(self, rhs: $type) -> Self::Output {
355 rhs * self
356 }
357 }
358
359 impl MulAssign<f32> for $type {
360 #[inline]
361 fn mul_assign(&mut self, rhs: f32) {
362 $(self.$field *= rhs;)+
363 }
364 }
365
366 impl Div<f32> for $type {
367 type Output = Self;
368 #[inline]
369 fn div(self, rhs: f32) -> Self::Output {
370 if rhs.abs() <= EPSILON {
371 Self::ZERO
372 } else {
373 Self::new($(self.$field / rhs),+)
374 }
375 }
376 }
377
378 impl DivAssign<f32> for $type {
379 #[inline]
380 fn div_assign(&mut self, rhs: f32) {
381 *self = *self / rhs;
382 }
383 }
384
385 impl Neg for $type {
386 type Output = Self;
387 #[inline]
388 fn neg(self) -> Self::Output {
389 Self::new($(-self.$field),+)
390 }
391 }
392
393 };
394}
395
396impl_vec_ops!(Vec2 { x, y });
397impl_vec_ops!(Vec3 { x, y, z });
398impl_vec_ops!(Vec4 { x, y, z, w });
399
400impl Index<usize> for Vec2 {
401 type Output = f32;
402
403 #[inline]
404 fn index(&self, index: usize) -> &Self::Output {
405 match index {
406 0 => &self.x,
407 1 => &self.y,
408 _ => panic!("vector index out of bounds: {index} >= 2"),
409 }
410 }
411}
412
413impl IndexMut<usize> for Vec2 {
414 #[inline]
415 fn index_mut(&mut self, index: usize) -> &mut Self::Output {
416 match index {
417 0 => &mut self.x,
418 1 => &mut self.y,
419 _ => panic!("vector index out of bounds: {index} >= 2"),
420 }
421 }
422}
423
424impl Index<usize> for Vec3 {
425 type Output = f32;
426
427 #[inline]
428 fn index(&self, index: usize) -> &Self::Output {
429 match index {
430 0 => &self.x,
431 1 => &self.y,
432 2 => &self.z,
433 _ => panic!("vector index out of bounds: {index} >= 3"),
434 }
435 }
436}
437
438impl IndexMut<usize> for Vec3 {
439 #[inline]
440 fn index_mut(&mut self, index: usize) -> &mut Self::Output {
441 match index {
442 0 => &mut self.x,
443 1 => &mut self.y,
444 2 => &mut self.z,
445 _ => panic!("vector index out of bounds: {index} >= 3"),
446 }
447 }
448}
449
450impl Index<usize> for Vec4 {
451 type Output = f32;
452
453 #[inline]
454 fn index(&self, index: usize) -> &Self::Output {
455 match index {
456 0 => &self.x,
457 1 => &self.y,
458 2 => &self.z,
459 3 => &self.w,
460 _ => panic!("vector index out of bounds: {index} >= 4"),
461 }
462 }
463}
464
465impl IndexMut<usize> for Vec4 {
466 #[inline]
467 fn index_mut(&mut self, index: usize) -> &mut Self::Output {
468 match index {
469 0 => &mut self.x,
470 1 => &mut self.y,
471 2 => &mut self.z,
472 3 => &mut self.w,
473 _ => panic!("vector index out of bounds: {index} >= 4"),
474 }
475 }
476}
477
478#[cfg(feature = "approx")]
479macro_rules! impl_approx {
480 ($type:ident { $($field:ident),+ }) => {
481 impl approx::AbsDiffEq for $type {
482 type Epsilon = f32;
483
484 #[inline]
485 fn default_epsilon() -> Self::Epsilon {
486 f32::default_epsilon()
487 }
488
489 #[inline]
490 fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
491 $(f32::abs_diff_eq(&self.$field, &other.$field, epsilon))&&+
492 }
493 }
494
495 impl approx::RelativeEq for $type {
496 #[inline]
497 fn default_max_relative() -> Self::Epsilon {
498 f32::default_max_relative()
499 }
500
501 #[inline]
502 fn relative_eq(
503 &self,
504 other: &Self,
505 epsilon: Self::Epsilon,
506 max_relative: Self::Epsilon,
507 ) -> bool {
508 $(f32::relative_eq(&self.$field, &other.$field, epsilon, max_relative))&&+
509 }
510 }
511
512 impl approx::UlpsEq for $type {
513 #[inline]
514 fn default_max_ulps() -> u32 {
515 f32::default_max_ulps()
516 }
517
518 #[inline]
519 fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
520 $(f32::ulps_eq(&self.$field, &other.$field, epsilon, max_ulps))&&+
521 }
522 }
523 };
524}
525
526#[cfg(feature = "approx")]
527impl_approx!(Vec2 { x, y });
528#[cfg(feature = "approx")]
529impl_approx!(Vec3 { x, y, z });
530#[cfg(feature = "approx")]
531impl_approx!(Vec4 { x, y, z, w });
532
533#[cfg(test)]
534mod tests {
535 use super::*;
536 use crate::assert_close;
537
538 #[test]
539 fn vec3_cross_dot_normalize_and_lerp_work() {
540 let x = Vec3::X;
541 let y = Vec3::Y;
542 assert_eq!(x.cross(y), Vec3::Z);
543 assert_close(x.dot(y), 0.0);
544 assert_close(Vec3::new(3.0, 4.0, 0.0).normalize().length(), 1.0);
545 assert_eq!(Vec3::ZERO.normalize(), Vec3::ZERO);
546 assert_eq!(x.lerp(y, 0.5), Vec3::new(0.5, 0.5, 0.0));
547 }
548
549 #[test]
550 fn angle_between_handles_normal_and_zero_vectors() {
551 assert_close(Vec3::X.angle_between(Vec3::Y), core::f32::consts::FRAC_PI_2);
552 assert_close(Vec3::ZERO.angle_between(Vec3::Y), 0.0);
553 }
554
555 #[test]
556 fn reflect_mirrors_about_normal() {
557 let reflected = Vec3::new(1.0, -1.0, 0.0).reflect(Vec3::Y);
558 assert_eq!(reflected, Vec3::new(1.0, 1.0, 0.0));
559 }
560}