1use crate::{
2 primitives::{Primitive2d, Primitive3d},
3 Quat, Rot2, Vec2, Vec3, Vec3A, Vec4,
4};
5
6use core::f32::consts::FRAC_1_SQRT_2;
7use core::fmt;
8use derive_more::derive::Into;
9
10#[cfg(feature = "bevy_reflect")]
11use bevy_reflect::Reflect;
12
13#[cfg(all(feature = "serialize", feature = "bevy_reflect"))]
14use bevy_reflect::{ReflectDeserialize, ReflectSerialize};
15
16#[cfg(all(debug_assertions, feature = "std"))]
17use std::eprintln;
18
19use thiserror::Error;
20
21#[derive(Debug, PartialEq, Error)]
23pub enum InvalidDirectionError {
24 #[error("The length of the direction vector is zero or very close to zero")]
26 Zero,
27 #[error("The length of the direction vector is `std::f32::INFINITY`")]
29 Infinite,
30 #[error("The length of the direction vector is `NaN`")]
32 NaN,
33}
34
35impl InvalidDirectionError {
36 pub fn from_length(length: f32) -> Self {
38 if length.is_nan() {
39 InvalidDirectionError::NaN
40 } else if !length.is_finite() {
41 InvalidDirectionError::Infinite
43 } else {
44 InvalidDirectionError::Zero
46 }
47 }
48}
49
50#[cfg(debug_assertions)]
58fn assert_is_normalized(message: &str, length_squared: f32) {
59 use crate::ops;
60
61 let length_error_squared = ops::abs(length_squared - 1.0);
62
63 if length_error_squared > 2e-2 || length_error_squared.is_nan() {
65 panic!(
67 "Error: {message} The length is {}.",
68 ops::sqrt(length_squared)
69 );
70 } else if length_error_squared > 2e-4 {
71 #[cfg(feature = "std")]
73 #[expect(clippy::print_stderr, reason = "Allowed behind `std` feature gate.")]
74 {
75 eprintln!(
76 "Warning: {message} The length is {}.",
77 ops::sqrt(length_squared)
78 );
79 }
80 }
81}
82
83#[derive(Clone, Copy, Debug, PartialEq)]
85#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
86#[cfg_attr(
87 feature = "bevy_reflect",
88 derive(Reflect),
89 reflect(Debug, PartialEq, Clone)
90)]
91#[cfg_attr(
92 all(feature = "serialize", feature = "bevy_reflect"),
93 reflect(Serialize, Deserialize)
94)]
95#[doc(alias = "Direction2d")]
96pub struct Dir2(Vec2);
97impl Primitive2d for Dir2 {}
98
99impl Dir2 {
100 pub const X: Self = Self(Vec2::X);
102 pub const Y: Self = Self(Vec2::Y);
104 pub const NEG_X: Self = Self(Vec2::NEG_X);
106 pub const NEG_Y: Self = Self(Vec2::NEG_Y);
108 pub const AXES: [Self; 2] = [Self::X, Self::Y];
110 pub const CARDINALS: [Self; 4] = [Self::X, Self::NEG_X, Self::Y, Self::NEG_Y];
112
113 pub const NORTH: Self = Self(Vec2::Y);
115 pub const SOUTH: Self = Self(Vec2::NEG_Y);
117 pub const EAST: Self = Self(Vec2::X);
119 pub const WEST: Self = Self(Vec2::NEG_X);
121 pub const NORTH_EAST: Self = Self(Vec2::new(FRAC_1_SQRT_2, FRAC_1_SQRT_2));
123 pub const NORTH_WEST: Self = Self(Vec2::new(-FRAC_1_SQRT_2, FRAC_1_SQRT_2));
125 pub const SOUTH_EAST: Self = Self(Vec2::new(FRAC_1_SQRT_2, -FRAC_1_SQRT_2));
127 pub const SOUTH_WEST: Self = Self(Vec2::new(-FRAC_1_SQRT_2, -FRAC_1_SQRT_2));
129
130 pub const DIAGONALS: [Self; 4] = [
132 Self::NORTH_EAST,
133 Self::NORTH_WEST,
134 Self::SOUTH_EAST,
135 Self::SOUTH_WEST,
136 ];
137 pub const ALL_NEIGHBORS: [Self; 8] = [
139 Self::X,
140 Self::NEG_X,
141 Self::Y,
142 Self::NEG_Y,
143 Self::NORTH_EAST,
144 Self::NORTH_WEST,
145 Self::SOUTH_EAST,
146 Self::SOUTH_WEST,
147 ];
148
149 pub fn new(value: Vec2) -> Result<Self, InvalidDirectionError> {
154 Self::new_and_length(value).map(|(dir, _)| dir)
155 }
156
157 pub fn new_unchecked(value: Vec2) -> Self {
163 #[cfg(debug_assertions)]
164 assert_is_normalized(
165 "The vector given to `Dir2::new_unchecked` is not normalized.",
166 value.length_squared(),
167 );
168
169 Self(value)
170 }
171
172 pub fn new_and_length(value: Vec2) -> Result<(Self, f32), InvalidDirectionError> {
178 let length = value.length();
179 let direction = (length.is_finite() && length > 0.0).then_some(value / length);
180
181 direction
182 .map(|dir| (Self(dir), length))
183 .ok_or(InvalidDirectionError::from_length(length))
184 }
185
186 pub fn from_xy(x: f32, y: f32) -> Result<Self, InvalidDirectionError> {
191 Self::new(Vec2::new(x, y))
192 }
193
194 pub fn from_xy_unchecked(x: f32, y: f32) -> Self {
200 Self::new_unchecked(Vec2::new(x, y))
201 }
202
203 #[inline]
205 pub fn from_angle(angle: f32) -> Self {
206 Self(Vec2::from_angle(angle))
207 }
208
209 pub const fn as_vec2(&self) -> Vec2 {
211 self.0
212 }
213
214 #[inline]
240 pub fn slerp(self, rhs: Self, s: f32) -> Self {
241 let angle = self.angle_to(rhs.0);
242 Rot2::radians(angle * s) * self
243 }
244
245 #[inline]
247 pub fn rotation_to(self, other: Self) -> Rot2 {
248 other.rotation_from_x() * self.rotation_to_x()
250 }
251
252 #[inline]
254 pub fn rotation_from(self, other: Self) -> Rot2 {
255 other.rotation_to(self)
256 }
257
258 #[inline]
260 pub fn rotation_from_x(self) -> Rot2 {
261 Rot2::from_sin_cos(self.0.y, self.0.x)
262 }
263
264 #[inline]
266 pub fn rotation_to_x(self) -> Rot2 {
267 self.rotation_from_x().inverse()
269 }
270
271 #[inline]
273 pub fn rotation_from_y(self) -> Rot2 {
274 Rot2::from_sin_cos(-self.0.x, self.0.y)
278 }
279
280 #[inline]
282 pub fn rotation_to_y(self) -> Rot2 {
283 self.rotation_from_y().inverse()
284 }
285
286 #[inline]
290 pub fn fast_renormalize(self) -> Self {
291 let length_squared = self.0.length_squared();
292 Self(self * (0.5 * (3.0 - length_squared)))
294 }
295}
296
297impl TryFrom<Vec2> for Dir2 {
298 type Error = InvalidDirectionError;
299
300 fn try_from(value: Vec2) -> Result<Self, Self::Error> {
301 Self::new(value)
302 }
303}
304
305impl From<Dir2> for Vec2 {
306 fn from(value: Dir2) -> Self {
307 value.as_vec2()
308 }
309}
310
311impl core::ops::Deref for Dir2 {
312 type Target = Vec2;
313 fn deref(&self) -> &Self::Target {
314 &self.0
315 }
316}
317
318impl core::ops::Neg for Dir2 {
319 type Output = Self;
320 fn neg(self) -> Self::Output {
321 Self(-self.0)
322 }
323}
324
325impl core::ops::Mul<f32> for Dir2 {
326 type Output = Vec2;
327 fn mul(self, rhs: f32) -> Self::Output {
328 self.0 * rhs
329 }
330}
331
332impl core::ops::Mul<Dir2> for f32 {
333 type Output = Vec2;
334 fn mul(self, rhs: Dir2) -> Self::Output {
335 self * rhs.0
336 }
337}
338
339impl core::ops::Mul<Dir2> for Rot2 {
340 type Output = Dir2;
341
342 fn mul(self, direction: Dir2) -> Self::Output {
344 let rotated = self * *direction;
345
346 #[cfg(debug_assertions)]
347 assert_is_normalized(
348 "`Dir2` is denormalized after rotation.",
349 rotated.length_squared(),
350 );
351
352 Dir2(rotated)
353 }
354}
355
356impl fmt::Display for Dir2 {
357 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
358 write!(f, "{}", self.0)
359 }
360}
361
362#[cfg(any(feature = "approx", test))]
363impl approx::AbsDiffEq for Dir2 {
364 type Epsilon = f32;
365 fn default_epsilon() -> f32 {
366 f32::EPSILON
367 }
368 fn abs_diff_eq(&self, other: &Self, epsilon: f32) -> bool {
369 self.as_ref().abs_diff_eq(other.as_ref(), epsilon)
370 }
371}
372
373#[cfg(any(feature = "approx", test))]
374impl approx::RelativeEq for Dir2 {
375 fn default_max_relative() -> f32 {
376 f32::EPSILON
377 }
378 fn relative_eq(&self, other: &Self, epsilon: f32, max_relative: f32) -> bool {
379 self.as_ref()
380 .relative_eq(other.as_ref(), epsilon, max_relative)
381 }
382}
383
384#[cfg(any(feature = "approx", test))]
385impl approx::UlpsEq for Dir2 {
386 fn default_max_ulps() -> u32 {
387 4
388 }
389 fn ulps_eq(&self, other: &Self, epsilon: f32, max_ulps: u32) -> bool {
390 self.as_ref().ulps_eq(other.as_ref(), epsilon, max_ulps)
391 }
392}
393
394#[derive(Clone, Copy, Debug, PartialEq, Into)]
396#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
397#[cfg_attr(
398 feature = "bevy_reflect",
399 derive(Reflect),
400 reflect(Debug, PartialEq, Clone)
401)]
402#[cfg_attr(
403 all(feature = "serialize", feature = "bevy_reflect"),
404 reflect(Serialize, Deserialize)
405)]
406#[doc(alias = "Direction3d")]
407pub struct Dir3(Vec3);
408impl Primitive3d for Dir3 {}
409
410impl Dir3 {
411 pub const X: Self = Self(Vec3::X);
413 pub const Y: Self = Self(Vec3::Y);
415 pub const Z: Self = Self(Vec3::Z);
417 pub const NEG_X: Self = Self(Vec3::NEG_X);
419 pub const NEG_Y: Self = Self(Vec3::NEG_Y);
421 pub const NEG_Z: Self = Self(Vec3::NEG_Z);
423 pub const AXES: [Self; 3] = [Self::X, Self::Y, Self::Z];
425 pub const CARDINALS: [Self; 6] = [
427 Self::X,
428 Self::NEG_X,
429 Self::Y,
430 Self::NEG_Y,
431 Self::Z,
432 Self::NEG_Z,
433 ];
434
435 const FRAC_1_SQRT_3: f32 = 0.577350269189625764509148780501957456_f32;
439 pub const ALL_VERTICES: [Self; 8] = [
441 Self(Vec3::new(
442 Self::FRAC_1_SQRT_3,
443 Self::FRAC_1_SQRT_3,
444 Self::FRAC_1_SQRT_3,
445 )),
446 Self(Vec3::new(
447 -Self::FRAC_1_SQRT_3,
448 Self::FRAC_1_SQRT_3,
449 Self::FRAC_1_SQRT_3,
450 )),
451 Self(Vec3::new(
452 Self::FRAC_1_SQRT_3,
453 -Self::FRAC_1_SQRT_3,
454 Self::FRAC_1_SQRT_3,
455 )),
456 Self(Vec3::new(
457 -Self::FRAC_1_SQRT_3,
458 -Self::FRAC_1_SQRT_3,
459 Self::FRAC_1_SQRT_3,
460 )),
461 Self(Vec3::new(
462 Self::FRAC_1_SQRT_3,
463 Self::FRAC_1_SQRT_3,
464 -Self::FRAC_1_SQRT_3,
465 )),
466 Self(Vec3::new(
467 -Self::FRAC_1_SQRT_3,
468 Self::FRAC_1_SQRT_3,
469 -Self::FRAC_1_SQRT_3,
470 )),
471 Self(Vec3::new(
472 Self::FRAC_1_SQRT_3,
473 -Self::FRAC_1_SQRT_3,
474 -Self::FRAC_1_SQRT_3,
475 )),
476 Self(Vec3::new(
477 -Self::FRAC_1_SQRT_3,
478 -Self::FRAC_1_SQRT_3,
479 -Self::FRAC_1_SQRT_3,
480 )),
481 ];
482 pub const ALL_EDGES: [Self; 12] = [
484 Self(Vec3::new(FRAC_1_SQRT_2, FRAC_1_SQRT_2, 0.)),
485 Self(Vec3::new(-FRAC_1_SQRT_2, FRAC_1_SQRT_2, 0.)),
486 Self(Vec3::new(FRAC_1_SQRT_2, -FRAC_1_SQRT_2, 0.)),
487 Self(Vec3::new(-FRAC_1_SQRT_2, -FRAC_1_SQRT_2, 0.)),
488 Self(Vec3::new(FRAC_1_SQRT_2, 0., FRAC_1_SQRT_2)),
489 Self(Vec3::new(-FRAC_1_SQRT_2, 0., FRAC_1_SQRT_2)),
490 Self(Vec3::new(FRAC_1_SQRT_2, 0., -FRAC_1_SQRT_2)),
491 Self(Vec3::new(-FRAC_1_SQRT_2, 0., -FRAC_1_SQRT_2)),
492 Self(Vec3::new(0., FRAC_1_SQRT_2, FRAC_1_SQRT_2)),
493 Self(Vec3::new(0., -FRAC_1_SQRT_2, FRAC_1_SQRT_2)),
494 Self(Vec3::new(0., FRAC_1_SQRT_2, -FRAC_1_SQRT_2)),
495 Self(Vec3::new(0., -FRAC_1_SQRT_2, -FRAC_1_SQRT_2)),
496 ];
497 pub const ALL_NEIGHBORS: [Self; 26] = [
499 Self::X,
500 Self::NEG_X,
501 Self::Y,
502 Self::NEG_Y,
503 Self::Z,
504 Self::NEG_Z,
505 Self(Vec3::new(FRAC_1_SQRT_2, FRAC_1_SQRT_2, 0.)),
506 Self(Vec3::new(-FRAC_1_SQRT_2, FRAC_1_SQRT_2, 0.)),
507 Self(Vec3::new(FRAC_1_SQRT_2, -FRAC_1_SQRT_2, 0.)),
508 Self(Vec3::new(-FRAC_1_SQRT_2, -FRAC_1_SQRT_2, 0.)),
509 Self(Vec3::new(FRAC_1_SQRT_2, 0., FRAC_1_SQRT_2)),
510 Self(Vec3::new(-FRAC_1_SQRT_2, 0., FRAC_1_SQRT_2)),
511 Self(Vec3::new(FRAC_1_SQRT_2, 0., -FRAC_1_SQRT_2)),
512 Self(Vec3::new(-FRAC_1_SQRT_2, 0., -FRAC_1_SQRT_2)),
513 Self(Vec3::new(0., FRAC_1_SQRT_2, FRAC_1_SQRT_2)),
514 Self(Vec3::new(0., -FRAC_1_SQRT_2, FRAC_1_SQRT_2)),
515 Self(Vec3::new(0., FRAC_1_SQRT_2, -FRAC_1_SQRT_2)),
516 Self(Vec3::new(0., -FRAC_1_SQRT_2, -FRAC_1_SQRT_2)),
517 Self(Vec3::new(
518 Self::FRAC_1_SQRT_3,
519 Self::FRAC_1_SQRT_3,
520 Self::FRAC_1_SQRT_3,
521 )),
522 Self(Vec3::new(
523 -Self::FRAC_1_SQRT_3,
524 Self::FRAC_1_SQRT_3,
525 Self::FRAC_1_SQRT_3,
526 )),
527 Self(Vec3::new(
528 Self::FRAC_1_SQRT_3,
529 -Self::FRAC_1_SQRT_3,
530 Self::FRAC_1_SQRT_3,
531 )),
532 Self(Vec3::new(
533 -Self::FRAC_1_SQRT_3,
534 -Self::FRAC_1_SQRT_3,
535 Self::FRAC_1_SQRT_3,
536 )),
537 Self(Vec3::new(
538 Self::FRAC_1_SQRT_3,
539 Self::FRAC_1_SQRT_3,
540 -Self::FRAC_1_SQRT_3,
541 )),
542 Self(Vec3::new(
543 -Self::FRAC_1_SQRT_3,
544 Self::FRAC_1_SQRT_3,
545 -Self::FRAC_1_SQRT_3,
546 )),
547 Self(Vec3::new(
548 Self::FRAC_1_SQRT_3,
549 -Self::FRAC_1_SQRT_3,
550 -Self::FRAC_1_SQRT_3,
551 )),
552 Self(Vec3::new(
553 -Self::FRAC_1_SQRT_3,
554 -Self::FRAC_1_SQRT_3,
555 -Self::FRAC_1_SQRT_3,
556 )),
557 ];
558
559 pub fn new(value: Vec3) -> Result<Self, InvalidDirectionError> {
564 Self::new_and_length(value).map(|(dir, _)| dir)
565 }
566
567 pub fn new_unchecked(value: Vec3) -> Self {
573 #[cfg(debug_assertions)]
574 assert_is_normalized(
575 "The vector given to `Dir3::new_unchecked` is not normalized.",
576 value.length_squared(),
577 );
578
579 Self(value)
580 }
581
582 pub fn new_and_length(value: Vec3) -> Result<(Self, f32), InvalidDirectionError> {
588 let length = value.length();
589 let direction = (length.is_finite() && length > 0.0).then_some(value / length);
590
591 direction
592 .map(|dir| (Self(dir), length))
593 .ok_or(InvalidDirectionError::from_length(length))
594 }
595
596 pub fn from_xyz(x: f32, y: f32, z: f32) -> Result<Self, InvalidDirectionError> {
601 Self::new(Vec3::new(x, y, z))
602 }
603
604 pub fn from_xyz_unchecked(x: f32, y: f32, z: f32) -> Self {
610 Self::new_unchecked(Vec3::new(x, y, z))
611 }
612
613 pub const fn as_vec3(&self) -> Vec3 {
615 self.0
616 }
617
618 #[inline]
648 pub fn slerp(self, rhs: Self, s: f32) -> Self {
649 let quat = Quat::IDENTITY.slerp(Quat::from_rotation_arc(self.0, rhs.0), s);
650 Dir3(quat.mul_vec3(self.0))
651 }
652
653 #[inline]
680 pub fn fast_renormalize(self) -> Self {
681 let length_squared = self.0.length_squared();
700 Self(self * (0.5 * (3.0 - length_squared)))
701 }
702}
703
704impl TryFrom<Vec3> for Dir3 {
705 type Error = InvalidDirectionError;
706
707 fn try_from(value: Vec3) -> Result<Self, Self::Error> {
708 Self::new(value)
709 }
710}
711
712impl core::ops::Deref for Dir3 {
713 type Target = Vec3;
714 fn deref(&self) -> &Self::Target {
715 &self.0
716 }
717}
718
719impl core::ops::Neg for Dir3 {
720 type Output = Self;
721 fn neg(self) -> Self::Output {
722 Self(-self.0)
723 }
724}
725
726impl core::ops::Mul<f32> for Dir3 {
727 type Output = Vec3;
728 fn mul(self, rhs: f32) -> Self::Output {
729 self.0 * rhs
730 }
731}
732
733impl core::ops::Mul<Dir3> for f32 {
734 type Output = Vec3;
735 fn mul(self, rhs: Dir3) -> Self::Output {
736 self * rhs.0
737 }
738}
739
740impl core::ops::Mul<Dir3> for Quat {
741 type Output = Dir3;
742
743 fn mul(self, direction: Dir3) -> Self::Output {
745 let rotated = self * *direction;
746
747 #[cfg(debug_assertions)]
748 assert_is_normalized(
749 "`Dir3` is denormalized after rotation.",
750 rotated.length_squared(),
751 );
752
753 Dir3(rotated)
754 }
755}
756
757impl fmt::Display for Dir3 {
758 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
759 write!(f, "{}", self.0)
760 }
761}
762
763#[cfg(feature = "approx")]
764impl approx::AbsDiffEq for Dir3 {
765 type Epsilon = f32;
766 fn default_epsilon() -> f32 {
767 f32::EPSILON
768 }
769 fn abs_diff_eq(&self, other: &Self, epsilon: f32) -> bool {
770 self.as_ref().abs_diff_eq(other.as_ref(), epsilon)
771 }
772}
773
774#[cfg(feature = "approx")]
775impl approx::RelativeEq for Dir3 {
776 fn default_max_relative() -> f32 {
777 f32::EPSILON
778 }
779 fn relative_eq(&self, other: &Self, epsilon: f32, max_relative: f32) -> bool {
780 self.as_ref()
781 .relative_eq(other.as_ref(), epsilon, max_relative)
782 }
783}
784
785#[cfg(feature = "approx")]
786impl approx::UlpsEq for Dir3 {
787 fn default_max_ulps() -> u32 {
788 4
789 }
790 fn ulps_eq(&self, other: &Self, epsilon: f32, max_ulps: u32) -> bool {
791 self.as_ref().ulps_eq(other.as_ref(), epsilon, max_ulps)
792 }
793}
794
795#[derive(Clone, Copy, Debug, PartialEq)]
800#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
801#[cfg_attr(
802 feature = "bevy_reflect",
803 derive(Reflect),
804 reflect(Debug, PartialEq, Clone)
805)]
806#[cfg_attr(
807 all(feature = "serialize", feature = "bevy_reflect"),
808 reflect(Serialize, Deserialize)
809)]
810#[doc(alias = "Direction3dA")]
811pub struct Dir3A(Vec3A);
812impl Primitive3d for Dir3A {}
813
814impl Dir3A {
815 pub const X: Self = Self(Vec3A::X);
817 pub const Y: Self = Self(Vec3A::Y);
819 pub const Z: Self = Self(Vec3A::Z);
821 pub const NEG_X: Self = Self(Vec3A::NEG_X);
823 pub const NEG_Y: Self = Self(Vec3A::NEG_Y);
825 pub const NEG_Z: Self = Self(Vec3A::NEG_Z);
827 pub const AXES: [Self; 3] = [Self::X, Self::Y, Self::Z];
829
830 pub fn new(value: Vec3A) -> Result<Self, InvalidDirectionError> {
835 Self::new_and_length(value).map(|(dir, _)| dir)
836 }
837
838 pub fn new_unchecked(value: Vec3A) -> Self {
844 #[cfg(debug_assertions)]
845 assert_is_normalized(
846 "The vector given to `Dir3A::new_unchecked` is not normalized.",
847 value.length_squared(),
848 );
849
850 Self(value)
851 }
852
853 pub fn new_and_length(value: Vec3A) -> Result<(Self, f32), InvalidDirectionError> {
859 let length = value.length();
860 let direction = (length.is_finite() && length > 0.0).then_some(value / length);
861
862 direction
863 .map(|dir| (Self(dir), length))
864 .ok_or(InvalidDirectionError::from_length(length))
865 }
866
867 pub fn from_xyz(x: f32, y: f32, z: f32) -> Result<Self, InvalidDirectionError> {
872 Self::new(Vec3A::new(x, y, z))
873 }
874
875 pub fn from_xyz_unchecked(x: f32, y: f32, z: f32) -> Self {
881 Self::new_unchecked(Vec3A::new(x, y, z))
882 }
883
884 pub const fn as_vec3a(&self) -> Vec3A {
886 self.0
887 }
888
889 #[inline]
919 pub fn slerp(self, rhs: Self, s: f32) -> Self {
920 let quat = Quat::IDENTITY.slerp(
921 Quat::from_rotation_arc(Vec3::from(self.0), Vec3::from(rhs.0)),
922 s,
923 );
924 Dir3A(quat.mul_vec3a(self.0))
925 }
926
927 #[inline]
932 pub fn fast_renormalize(self) -> Self {
933 let length_squared = self.0.length_squared();
934 Self(self * (0.5 * (3.0 - length_squared)))
936 }
937}
938
939impl From<Dir3> for Dir3A {
940 fn from(value: Dir3) -> Self {
941 Self(value.0.into())
942 }
943}
944
945impl From<Dir3A> for Dir3 {
946 fn from(value: Dir3A) -> Self {
947 Self(value.0.into())
948 }
949}
950
951impl TryFrom<Vec3A> for Dir3A {
952 type Error = InvalidDirectionError;
953
954 fn try_from(value: Vec3A) -> Result<Self, Self::Error> {
955 Self::new(value)
956 }
957}
958
959impl From<Dir3A> for Vec3A {
960 fn from(value: Dir3A) -> Self {
961 value.0
962 }
963}
964
965impl core::ops::Deref for Dir3A {
966 type Target = Vec3A;
967 fn deref(&self) -> &Self::Target {
968 &self.0
969 }
970}
971
972impl core::ops::Neg for Dir3A {
973 type Output = Self;
974 fn neg(self) -> Self::Output {
975 Self(-self.0)
976 }
977}
978
979impl core::ops::Mul<f32> for Dir3A {
980 type Output = Vec3A;
981 fn mul(self, rhs: f32) -> Self::Output {
982 self.0 * rhs
983 }
984}
985
986impl core::ops::Mul<Dir3A> for f32 {
987 type Output = Vec3A;
988 fn mul(self, rhs: Dir3A) -> Self::Output {
989 self * rhs.0
990 }
991}
992
993impl core::ops::Mul<Dir3A> for Quat {
994 type Output = Dir3A;
995
996 fn mul(self, direction: Dir3A) -> Self::Output {
998 let rotated = self * *direction;
999
1000 #[cfg(debug_assertions)]
1001 assert_is_normalized(
1002 "`Dir3A` is denormalized after rotation.",
1003 rotated.length_squared(),
1004 );
1005
1006 Dir3A(rotated)
1007 }
1008}
1009
1010impl fmt::Display for Dir3A {
1011 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1012 write!(f, "{}", self.0)
1013 }
1014}
1015
1016#[cfg(feature = "approx")]
1017impl approx::AbsDiffEq for Dir3A {
1018 type Epsilon = f32;
1019 fn default_epsilon() -> f32 {
1020 f32::EPSILON
1021 }
1022 fn abs_diff_eq(&self, other: &Self, epsilon: f32) -> bool {
1023 self.as_ref().abs_diff_eq(other.as_ref(), epsilon)
1024 }
1025}
1026
1027#[cfg(feature = "approx")]
1028impl approx::RelativeEq for Dir3A {
1029 fn default_max_relative() -> f32 {
1030 f32::EPSILON
1031 }
1032 fn relative_eq(&self, other: &Self, epsilon: f32, max_relative: f32) -> bool {
1033 self.as_ref()
1034 .relative_eq(other.as_ref(), epsilon, max_relative)
1035 }
1036}
1037
1038#[cfg(feature = "approx")]
1039impl approx::UlpsEq for Dir3A {
1040 fn default_max_ulps() -> u32 {
1041 4
1042 }
1043 fn ulps_eq(&self, other: &Self, epsilon: f32, max_ulps: u32) -> bool {
1044 self.as_ref().ulps_eq(other.as_ref(), epsilon, max_ulps)
1045 }
1046}
1047
1048#[derive(Clone, Copy, Debug, PartialEq, Into)]
1050#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
1051#[cfg_attr(
1052 feature = "bevy_reflect",
1053 derive(Reflect),
1054 reflect(Debug, PartialEq, Clone)
1055)]
1056#[cfg_attr(
1057 all(feature = "serialize", feature = "bevy_reflect"),
1058 reflect(Serialize, Deserialize)
1059)]
1060#[doc(alias = "Direction4d")]
1061pub struct Dir4(Vec4);
1062
1063impl Dir4 {
1064 pub const X: Self = Self(Vec4::X);
1066 pub const Y: Self = Self(Vec4::Y);
1068 pub const Z: Self = Self(Vec4::Z);
1070 pub const W: Self = Self(Vec4::W);
1072 pub const NEG_X: Self = Self(Vec4::NEG_X);
1074 pub const NEG_Y: Self = Self(Vec4::NEG_Y);
1076 pub const NEG_Z: Self = Self(Vec4::NEG_Z);
1078 pub const NEG_W: Self = Self(Vec4::NEG_W);
1080 pub const AXES: [Self; 4] = [Self::X, Self::Y, Self::Z, Self::W];
1082
1083 pub fn new(value: Vec4) -> Result<Self, InvalidDirectionError> {
1088 Self::new_and_length(value).map(|(dir, _)| dir)
1089 }
1090
1091 pub fn new_unchecked(value: Vec4) -> Self {
1097 #[cfg(debug_assertions)]
1098 assert_is_normalized(
1099 "The vector given to `Dir4::new_unchecked` is not normalized.",
1100 value.length_squared(),
1101 );
1102 Self(value)
1103 }
1104
1105 pub fn new_and_length(value: Vec4) -> Result<(Self, f32), InvalidDirectionError> {
1111 let length = value.length();
1112 let direction = (length.is_finite() && length > 0.0).then_some(value / length);
1113
1114 direction
1115 .map(|dir| (Self(dir), length))
1116 .ok_or(InvalidDirectionError::from_length(length))
1117 }
1118
1119 pub fn from_xyzw(x: f32, y: f32, z: f32, w: f32) -> Result<Self, InvalidDirectionError> {
1124 Self::new(Vec4::new(x, y, z, w))
1125 }
1126
1127 pub fn from_xyzw_unchecked(x: f32, y: f32, z: f32, w: f32) -> Self {
1133 Self::new_unchecked(Vec4::new(x, y, z, w))
1134 }
1135
1136 pub const fn as_vec4(&self) -> Vec4 {
1138 self.0
1139 }
1140
1141 #[inline]
1144 pub fn fast_renormalize(self) -> Self {
1145 let length_squared = self.0.length_squared();
1164 Self(self * (0.5 * (3.0 - length_squared)))
1165 }
1166}
1167
1168impl TryFrom<Vec4> for Dir4 {
1169 type Error = InvalidDirectionError;
1170
1171 fn try_from(value: Vec4) -> Result<Self, Self::Error> {
1172 Self::new(value)
1173 }
1174}
1175
1176impl core::ops::Deref for Dir4 {
1177 type Target = Vec4;
1178 fn deref(&self) -> &Self::Target {
1179 &self.0
1180 }
1181}
1182
1183impl core::ops::Neg for Dir4 {
1184 type Output = Self;
1185 fn neg(self) -> Self::Output {
1186 Self(-self.0)
1187 }
1188}
1189
1190impl core::ops::Mul<f32> for Dir4 {
1191 type Output = Vec4;
1192 fn mul(self, rhs: f32) -> Self::Output {
1193 self.0 * rhs
1194 }
1195}
1196
1197impl core::ops::Mul<Dir4> for f32 {
1198 type Output = Vec4;
1199 fn mul(self, rhs: Dir4) -> Self::Output {
1200 self * rhs.0
1201 }
1202}
1203
1204impl fmt::Display for Dir4 {
1205 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1206 write!(f, "{}", self.0)
1207 }
1208}
1209
1210#[cfg(feature = "approx")]
1211impl approx::AbsDiffEq for Dir4 {
1212 type Epsilon = f32;
1213 fn default_epsilon() -> f32 {
1214 f32::EPSILON
1215 }
1216 fn abs_diff_eq(&self, other: &Self, epsilon: f32) -> bool {
1217 self.as_ref().abs_diff_eq(other.as_ref(), epsilon)
1218 }
1219}
1220
1221#[cfg(feature = "approx")]
1222impl approx::RelativeEq for Dir4 {
1223 fn default_max_relative() -> f32 {
1224 f32::EPSILON
1225 }
1226 fn relative_eq(&self, other: &Self, epsilon: f32, max_relative: f32) -> bool {
1227 self.as_ref()
1228 .relative_eq(other.as_ref(), epsilon, max_relative)
1229 }
1230}
1231
1232#[cfg(feature = "approx")]
1233impl approx::UlpsEq for Dir4 {
1234 fn default_max_ulps() -> u32 {
1235 4
1236 }
1237
1238 fn ulps_eq(&self, other: &Self, epsilon: f32, max_ulps: u32) -> bool {
1239 self.as_ref().ulps_eq(other.as_ref(), epsilon, max_ulps)
1240 }
1241}
1242
1243#[cfg(test)]
1244#[cfg(feature = "approx")]
1245mod tests {
1246 use crate::ops;
1247
1248 use super::*;
1249 use approx::assert_relative_eq;
1250
1251 #[test]
1252 fn dir2_creation() {
1253 assert_eq!(Dir2::new(Vec2::X * 12.5), Ok(Dir2::X));
1254 assert_eq!(
1255 Dir2::new(Vec2::new(0.0, 0.0)),
1256 Err(InvalidDirectionError::Zero)
1257 );
1258 assert_eq!(
1259 Dir2::new(Vec2::new(f32::INFINITY, 0.0)),
1260 Err(InvalidDirectionError::Infinite)
1261 );
1262 assert_eq!(
1263 Dir2::new(Vec2::new(f32::NEG_INFINITY, 0.0)),
1264 Err(InvalidDirectionError::Infinite)
1265 );
1266 assert_eq!(
1267 Dir2::new(Vec2::new(f32::NAN, 0.0)),
1268 Err(InvalidDirectionError::NaN)
1269 );
1270 assert_eq!(Dir2::new_and_length(Vec2::X * 6.5), Ok((Dir2::X, 6.5)));
1271 }
1272
1273 #[test]
1274 fn dir2_slerp() {
1275 assert_relative_eq!(
1276 Dir2::X.slerp(Dir2::Y, 0.5),
1277 Dir2::from_xy(ops::sqrt(0.5_f32), ops::sqrt(0.5_f32)).unwrap()
1278 );
1279 assert_eq!(Dir2::Y.slerp(Dir2::X, 0.0), Dir2::Y);
1280 assert_relative_eq!(Dir2::X.slerp(Dir2::Y, 1.0), Dir2::Y);
1281 assert_relative_eq!(
1282 Dir2::Y.slerp(Dir2::X, 1.0 / 3.0),
1283 Dir2::from_xy(0.5, ops::sqrt(0.75_f32)).unwrap()
1284 );
1285 assert_relative_eq!(
1286 Dir2::X.slerp(Dir2::Y, 2.0 / 3.0),
1287 Dir2::from_xy(0.5, ops::sqrt(0.75_f32)).unwrap()
1288 );
1289 }
1290
1291 #[test]
1292 fn dir2_to_rotation2d() {
1293 assert_relative_eq!(Dir2::EAST.rotation_to(Dir2::NORTH_EAST), Rot2::FRAC_PI_4);
1294 assert_relative_eq!(Dir2::NORTH.rotation_from(Dir2::NORTH_EAST), Rot2::FRAC_PI_4);
1295 assert_relative_eq!(Dir2::SOUTH.rotation_to_x(), Rot2::FRAC_PI_2);
1296 assert_relative_eq!(Dir2::SOUTH.rotation_to_y(), Rot2::PI);
1297 assert_relative_eq!(Dir2::NORTH_WEST.rotation_from_x(), Rot2::degrees(135.0));
1298 assert_relative_eq!(Dir2::NORTH_WEST.rotation_from_y(), Rot2::FRAC_PI_4);
1299 }
1300
1301 #[test]
1302 fn dir2_renorm() {
1303 let (sin, cos) = ops::sin_cos(1.0_f32);
1305 let rot2 = Rot2::from_sin_cos(sin * (1.0 + 1e-5), cos * (1.0 + 1e-5));
1306 let mut dir_a = Dir2::X;
1307 let mut dir_b = Dir2::X;
1308
1309 assert_relative_eq!(dir_b, dir_b.fast_renormalize(), epsilon = 0.000001);
1311
1312 for _ in 0..50 {
1313 dir_a = rot2 * dir_a;
1314 dir_b = rot2 * dir_b;
1315 dir_b = dir_b.fast_renormalize();
1316 }
1317
1318 assert!(
1320 !dir_a.is_normalized(),
1321 "Denormalization doesn't work, test is faulty"
1322 );
1323 assert!(dir_b.is_normalized(), "Renormalisation did not work.");
1324 }
1325
1326 #[test]
1327 fn dir3_creation() {
1328 assert_eq!(Dir3::new(Vec3::X * 12.5), Ok(Dir3::X));
1329 assert_eq!(
1330 Dir3::new(Vec3::new(0.0, 0.0, 0.0)),
1331 Err(InvalidDirectionError::Zero)
1332 );
1333 assert_eq!(
1334 Dir3::new(Vec3::new(f32::INFINITY, 0.0, 0.0)),
1335 Err(InvalidDirectionError::Infinite)
1336 );
1337 assert_eq!(
1338 Dir3::new(Vec3::new(f32::NEG_INFINITY, 0.0, 0.0)),
1339 Err(InvalidDirectionError::Infinite)
1340 );
1341 assert_eq!(
1342 Dir3::new(Vec3::new(f32::NAN, 0.0, 0.0)),
1343 Err(InvalidDirectionError::NaN)
1344 );
1345 assert_eq!(Dir3::new_and_length(Vec3::X * 6.5), Ok((Dir3::X, 6.5)));
1346
1347 assert!(
1349 (Quat::from_rotation_z(core::f32::consts::FRAC_PI_2) * Dir3::X)
1350 .abs_diff_eq(Vec3::Y, 10e-6)
1351 );
1352 }
1353
1354 #[test]
1355 fn dir3_slerp() {
1356 assert_relative_eq!(
1357 Dir3::X.slerp(Dir3::Y, 0.5),
1358 Dir3::from_xyz(ops::sqrt(0.5f32), ops::sqrt(0.5f32), 0.0).unwrap()
1359 );
1360 assert_relative_eq!(Dir3::Y.slerp(Dir3::Z, 0.0), Dir3::Y);
1361 assert_relative_eq!(Dir3::Z.slerp(Dir3::X, 1.0), Dir3::X, epsilon = 0.000001);
1362 assert_relative_eq!(
1363 Dir3::X.slerp(Dir3::Z, 1.0 / 3.0),
1364 Dir3::from_xyz(ops::sqrt(0.75f32), 0.0, 0.5).unwrap(),
1365 epsilon = 0.000001
1366 );
1367 assert_relative_eq!(
1368 Dir3::Z.slerp(Dir3::Y, 2.0 / 3.0),
1369 Dir3::from_xyz(0.0, ops::sqrt(0.75f32), 0.5).unwrap()
1370 );
1371 }
1372
1373 #[test]
1374 fn dir3_renorm() {
1375 let rot3 = Quat::from_euler(glam::EulerRot::XYZ, 1.0, 2.0, 3.0) * (1.0 + 1e-5);
1377 let mut dir_a = Dir3::X;
1378 let mut dir_b = Dir3::X;
1379
1380 assert_relative_eq!(dir_b, dir_b.fast_renormalize(), epsilon = 0.000001);
1382
1383 for _ in 0..50 {
1384 dir_a = rot3 * dir_a;
1385 dir_b = rot3 * dir_b;
1386 dir_b = dir_b.fast_renormalize();
1387 }
1388
1389 assert!(
1391 !dir_a.is_normalized(),
1392 "Denormalization doesn't work, test is faulty"
1393 );
1394 assert!(dir_b.is_normalized(), "Renormalisation did not work.");
1395 }
1396
1397 #[test]
1398 fn dir3a_creation() {
1399 assert_eq!(Dir3A::new(Vec3A::X * 12.5), Ok(Dir3A::X));
1400 assert_eq!(
1401 Dir3A::new(Vec3A::new(0.0, 0.0, 0.0)),
1402 Err(InvalidDirectionError::Zero)
1403 );
1404 assert_eq!(
1405 Dir3A::new(Vec3A::new(f32::INFINITY, 0.0, 0.0)),
1406 Err(InvalidDirectionError::Infinite)
1407 );
1408 assert_eq!(
1409 Dir3A::new(Vec3A::new(f32::NEG_INFINITY, 0.0, 0.0)),
1410 Err(InvalidDirectionError::Infinite)
1411 );
1412 assert_eq!(
1413 Dir3A::new(Vec3A::new(f32::NAN, 0.0, 0.0)),
1414 Err(InvalidDirectionError::NaN)
1415 );
1416 assert_eq!(Dir3A::new_and_length(Vec3A::X * 6.5), Ok((Dir3A::X, 6.5)));
1417
1418 assert!(
1420 (Quat::from_rotation_z(core::f32::consts::FRAC_PI_2) * Dir3A::X)
1421 .abs_diff_eq(Vec3A::Y, 10e-6)
1422 );
1423 }
1424
1425 #[test]
1426 fn dir3a_slerp() {
1427 assert_relative_eq!(
1428 Dir3A::X.slerp(Dir3A::Y, 0.5),
1429 Dir3A::from_xyz(ops::sqrt(0.5f32), ops::sqrt(0.5f32), 0.0).unwrap()
1430 );
1431 assert_relative_eq!(Dir3A::Y.slerp(Dir3A::Z, 0.0), Dir3A::Y);
1432 assert_relative_eq!(Dir3A::Z.slerp(Dir3A::X, 1.0), Dir3A::X, epsilon = 0.000001);
1433 assert_relative_eq!(
1434 Dir3A::X.slerp(Dir3A::Z, 1.0 / 3.0),
1435 Dir3A::from_xyz(ops::sqrt(0.75f32), 0.0, 0.5).unwrap(),
1436 epsilon = 0.000001
1437 );
1438 assert_relative_eq!(
1439 Dir3A::Z.slerp(Dir3A::Y, 2.0 / 3.0),
1440 Dir3A::from_xyz(0.0, ops::sqrt(0.75f32), 0.5).unwrap()
1441 );
1442 }
1443
1444 #[test]
1445 fn dir3a_renorm() {
1446 let rot3 = Quat::from_euler(glam::EulerRot::XYZ, 1.0, 2.0, 3.0) * (1.0 + 1e-5);
1448 let mut dir_a = Dir3A::X;
1449 let mut dir_b = Dir3A::X;
1450
1451 assert_relative_eq!(dir_b, dir_b.fast_renormalize(), epsilon = 0.000001);
1453
1454 for _ in 0..50 {
1455 dir_a = rot3 * dir_a;
1456 dir_b = rot3 * dir_b;
1457 dir_b = dir_b.fast_renormalize();
1458 }
1459
1460 assert!(
1462 !dir_a.is_normalized(),
1463 "Denormalization doesn't work, test is faulty"
1464 );
1465 assert!(dir_b.is_normalized(), "Renormalisation did not work.");
1466 }
1467
1468 #[test]
1469 fn dir4_creation() {
1470 assert_eq!(Dir4::new(Vec4::X * 12.5), Ok(Dir4::X));
1471 assert_eq!(
1472 Dir4::new(Vec4::new(0.0, 0.0, 0.0, 0.0)),
1473 Err(InvalidDirectionError::Zero)
1474 );
1475 assert_eq!(
1476 Dir4::new(Vec4::new(f32::INFINITY, 0.0, 0.0, 0.0)),
1477 Err(InvalidDirectionError::Infinite)
1478 );
1479 assert_eq!(
1480 Dir4::new(Vec4::new(f32::NEG_INFINITY, 0.0, 0.0, 0.0)),
1481 Err(InvalidDirectionError::Infinite)
1482 );
1483 assert_eq!(
1484 Dir4::new(Vec4::new(f32::NAN, 0.0, 0.0, 0.0)),
1485 Err(InvalidDirectionError::NaN)
1486 );
1487 assert_eq!(Dir4::new_and_length(Vec4::X * 6.5), Ok((Dir4::X, 6.5)));
1488 }
1489
1490 #[test]
1491 fn dir4_renorm() {
1492 let mat4 = bevy_math::Mat4::from_quat(Quat::from_euler(glam::EulerRot::XYZ, 1.0, 2.0, 3.0))
1494 * (1.0 + 1e-5);
1495 let mut dir_a = Dir4::from_xyzw(1., 1., 0., 0.).unwrap();
1496 let mut dir_b = Dir4::from_xyzw(1., 1., 0., 0.).unwrap();
1497 assert_relative_eq!(dir_b, dir_b.fast_renormalize(), epsilon = 0.000001);
1499 for _ in 0..50 {
1500 dir_a = Dir4(mat4 * *dir_a);
1501 dir_b = Dir4(mat4 * *dir_b);
1502 dir_b = dir_b.fast_renormalize();
1503 }
1504 assert!(
1506 !dir_a.is_normalized(),
1507 "Denormalization doesn't work, test is faulty"
1508 );
1509 assert!(dir_b.is_normalized(), "Renormalisation did not work.");
1510 }
1511}