coordinates/
traits.rs

1use num_traits::{Float, Num};
2
3pub trait Positional<T: Float>
4where
5    Self: Magnitude<T> + Dot<T> + Copy,
6{
7    /// Angle between two points in space.
8    ///
9    /// # Returns
10    ///
11    /// The result is a positive value (in radians) aside from if
12    /// `self.magnitude() == 0` or `other.magnitude() == 0` where it will return
13    /// NaN (acos(infinity) is undefined)
14    ///
15    /// # Examples
16    ///
17    /// ## In 2D
18    /// ```
19    /// # use coordinates::prelude::*;
20    /// let right =  Vector2::<f64>::RIGHT;
21    /// let up = Vector2::<f64>::UP;
22    ///
23    /// assert!((right.angle_to(&up) - std::f64::consts::FRAC_PI_2).abs() < std::f64::EPSILON);
24    /// ```
25    ///
26    /// ## In 3D
27    /// ```
28    /// # use coordinates::prelude::*;
29    /// let right= Vector3::<f64>::RIGHT;
30    /// let up = Vector3::<f64>::UP;
31    ///
32    /// assert!((right.angle_to(&up) - std::f64::consts::FRAC_PI_2).abs() < std::f64::EPSILON);
33    /// ```
34    #[must_use]
35    fn angle_to(&self, other: &Self) -> T {
36        (self.dot(other) / (self.magnitude() * other.magnitude())).acos()
37    }
38}
39
40pub trait Magnitude<T: Float>
41where
42    Self: Sized + std::ops::Div<T, Output = Self> + Copy,
43{
44    /// Returns the exact magnitude of the vector
45    ///
46    /// This is the same as getting the euclidean distance from the origin to the
47    /// tip of the vector, i.e. `sqrt(x^2 + y^2 + z^2)` for a cartesian coordinate
48    #[must_use]
49    fn magnitude(&self) -> T;
50
51    /// Returns the magnitude of a vector in as few operations as possible
52    ///
53    /// # Note:
54    ///
55    /// This operation is not appropriate for comparing vectors of different type.
56    ///  e.g. the spherical coordinates `(10,0,0)` will have a smaller
57    ///  `quick_magnitude()` than the cartesian coordinate `(0,5,0)` despite
58    ///  having a larger real magnitude
59    #[must_use]
60    fn quick_magnitude(&self) -> T;
61
62    #[must_use]
63    fn normalize(self) -> Self {
64        self / self.magnitude()
65    }
66}
67
68pub trait Dot<T: Num> {
69    #[must_use]
70    fn dot(&self, rhs: &Self) -> T;
71}
72
73pub trait Cross3D {
74    #[must_use]
75    fn cross(&self, rhs: &Self) -> Self;
76}
77
78pub trait TrigConsts
79where
80    Self: Sized,
81{
82    const ZERO: Self;
83    const ONE: Self;
84    const NEG_ONE: Self;
85    const TAU: Self;
86    const FRAC_3PI_2: Self;
87    const PI: Self;
88    const FRAC_PI_2: Self;
89    const FRAC_PI_3: Self;
90    const FRAC_PI_4: Self;
91    const FRAC_PI_6: Self;
92    const FRAC_PI_8: Self;
93    const FRAC_1_PI: Self;
94    const FRAC_2_PI: Self;
95    const FRAC_2_SQRT_PI: Self;
96}
97
98macro_rules! impl_trig_consts {
99    ($($t : ident) +) => {
100        // Find constants of rust primitives.
101        $(impl_trig_consts!{$t, std::$t::consts})+
102    };
103    ($t : ident, $path : path) => {
104        // Find constants as children of the path
105        //  e.g. `std::f32::consts{TAU,PI,...}`
106        impl_trig_consts!{$t, $path, TAU, PI, FRAC_PI_2, FRAC_PI_3,FRAC_PI_4,FRAC_PI_6,FRAC_PI_8, FRAC_1_PI, FRAC_2_PI, FRAC_2_SQRT_PI}
107    };
108    ($t : ident, $path : path, $($constant : ident),+)=> {
109        impl TrigConsts for $t{
110        // For each provided constant expand to a usable function
111        // e.g. `impl_constants!(f32, std::f32, TAU)`
112        //      expands to `const TAU: f32 = std::f32::consts::TAU`
113        $(
114            const $constant : Self = { use $path as consts; consts::$constant };
115        )+
116        const NEG_ONE : Self = -1.0;
117        const ZERO: Self = 0.0;
118        const ONE: Self = 1.0;
119        const FRAC_3PI_2: Self = { use $path as consts; consts::PI + consts::FRAC_PI_2 };
120    }
121
122    };
123}
124
125impl_trig_consts!(f32 f64);