honeycomb_core/geometry/dim3/
vector.rs

1use crate::geometry::{CoordsError, CoordsFloat, Vector2};
2
3/// # 3D vector structure
4///
5/// ## Generics
6///
7/// - `T: CoordsFloat` -- Generic FP type for coordinates.
8///
9/// ## Example
10///
11/// ```
12/// # use honeycomb_core::geometry::CoordsError;
13/// # fn main() -> Result<(), CoordsError> {
14/// use honeycomb_core::geometry::Vector3;
15///
16/// let unit_x = Vector3::unit_x();
17/// let unit_y = Vector3::unit_y();
18/// let unit_z = Vector3::unit_z();
19///
20/// assert_eq!(unit_x.dot(&unit_y), 0.0);
21/// assert_eq!(unit_x.cross(&unit_y), unit_z);
22///
23/// let sum: Vector3<f64> = unit_x + unit_y + unit_z;
24///
25/// assert_eq!(sum.norm(), 3.0_f64.sqrt());
26/// assert_eq!(
27///     sum.unit_dir()?,
28///     Vector3(
29///         1.0 / 3.0_f64.sqrt(),
30///         1.0 / 3.0_f64.sqrt(),
31///         1.0 / 3.0_f64.sqrt(),
32///     ),
33/// );
34/// # Ok(())
35/// # }
36/// ```
37#[derive(Debug, Clone, Copy, Default, PartialEq)]
38pub struct Vector3<T: CoordsFloat>(pub T, pub T, pub T);
39
40unsafe impl<T: CoordsFloat> Send for Vector3<T> {}
41unsafe impl<T: CoordsFloat> Sync for Vector3<T> {}
42
43impl<T: CoordsFloat> Vector3<T> {
44    /// Return a unit vector along the `x` axis.
45    #[must_use = "unused return value"]
46    pub fn unit_x() -> Self {
47        Self(T::one(), T::zero(), T::zero())
48    }
49
50    /// Return a unit vector along the `y` axis.
51    #[must_use = "unused return value"]
52    pub fn unit_y() -> Self {
53        Self(T::zero(), T::one(), T::zero())
54    }
55
56    /// Return a unit vector along the `z` axis.
57    #[must_use = "unused return value"]
58    pub fn unit_z() -> Self {
59        Self(T::zero(), T::zero(), T::one())
60    }
61
62    /// Consume `self` to return inner values.
63    pub fn into_inner(self) -> (T, T, T) {
64        (self.0, self.1, self.2)
65    }
66
67    /// Return the value of the `x` coordinate of the vector.
68    pub fn x(&self) -> T {
69        self.0
70    }
71
72    /// Return the value of the `y` coordinate of the vector.
73    pub fn y(&self) -> T {
74        self.1
75    }
76
77    /// Return the value of the `z` coordinate of the vector.
78    pub fn z(&self) -> T {
79        self.2
80    }
81
82    /// Compute the norm of `self`.
83    pub fn norm(&self) -> T {
84        (self.0 * self.0 + self.1 * self.1 + self.2 * self.2).sqrt()
85    }
86
87    /// Compute the direction of `self` as a unit vector.
88    ///
89    /// # Errors
90    ///
91    /// This method will return an error if called on a null `Vector3`.
92    pub fn unit_dir(&self) -> Result<Self, CoordsError> {
93        let norm = self.norm();
94        if norm.is_zero() {
95            Err(CoordsError::InvalidUnitDir)
96        } else {
97            Ok(*self / norm)
98        }
99    }
100    ///Return the dot product between `self` and `other`.
101    pub fn dot(&self, other: &Vector3<T>) -> T {
102        self.0 * other.0 + self.1 * other.1 + self.2 * other.2
103    }
104
105    /// Return the cross product between `self` and `other`.
106    #[must_use = "unused return value"]
107    pub fn cross(&self, other: &Vector3<T>) -> Self {
108        Self(
109            self.1 * other.2 - self.2 * other.1,
110            self.2 * other.0 - self.0 * other.2,
111            self.0 * other.1 - self.1 * other.0,
112        )
113    }
114}
115
116// Building trait
117
118impl<T: CoordsFloat> From<(T, T, T)> for Vector3<T> {
119    fn from((x, y, z): (T, T, T)) -> Self {
120        Self(x, y, z)
121    }
122}
123
124impl<T: CoordsFloat> From<Vector2<T>> for Vector3<T> {
125    fn from(v: Vector2<T>) -> Self {
126        Self(v.0, v.1, T::zero())
127    }
128}
129
130// Basic operations
131
132impl<T: CoordsFloat> std::ops::Add<Vector3<T>> for Vector3<T> {
133    type Output = Self;
134    fn add(self, rhs: Vector3<T>) -> Self::Output {
135        Self(self.0 + rhs.0, self.1 + rhs.1, self.2 + rhs.2)
136    }
137}
138
139impl<T: CoordsFloat> std::ops::AddAssign<Vector3<T>> for Vector3<T> {
140    fn add_assign(&mut self, rhs: Vector3<T>) {
141        self.0 += rhs.0;
142        self.1 += rhs.1;
143        self.2 += rhs.2;
144    }
145}
146
147impl<T: CoordsFloat> std::ops::Sub<Vector3<T>> for Vector3<T> {
148    type Output = Self;
149    fn sub(self, rhs: Vector3<T>) -> Self::Output {
150        Self(self.0 - rhs.0, self.1 - rhs.1, self.2 - rhs.2)
151    }
152}
153
154impl<T: CoordsFloat> std::ops::SubAssign<Vector3<T>> for Vector3<T> {
155    fn sub_assign(&mut self, rhs: Vector3<T>) {
156        self.0 -= rhs.0;
157        self.1 -= rhs.1;
158        self.2 -= rhs.2;
159    }
160}
161
162impl<T: CoordsFloat> std::ops::Mul<T> for Vector3<T> {
163    type Output = Self;
164    fn mul(self, rhs: T) -> Self::Output {
165        Self(self.0 * rhs, self.1 * rhs, self.2 * rhs)
166    }
167}
168
169impl<T: CoordsFloat> std::ops::MulAssign<T> for Vector3<T> {
170    fn mul_assign(&mut self, rhs: T) {
171        self.0 *= rhs;
172        self.1 *= rhs;
173        self.2 *= rhs;
174    }
175}
176
177impl<T: CoordsFloat> std::ops::Div<T> for Vector3<T> {
178    type Output = Self;
179    fn div(self, rhs: T) -> Self::Output {
180        assert!(!rhs.is_zero());
181        Self(self.0 / rhs, self.1 / rhs, self.2 / rhs)
182    }
183}
184
185impl<T: CoordsFloat> std::ops::DivAssign<T> for Vector3<T> {
186    fn div_assign(&mut self, rhs: T) {
187        assert!(!rhs.is_zero());
188        self.0 /= rhs;
189        self.1 /= rhs;
190        self.2 /= rhs;
191    }
192}
193
194impl<T: CoordsFloat> std::ops::Neg for Vector3<T> {
195    type Output = Self;
196    fn neg(self) -> Self::Output {
197        Self(-self.0, -self.1, -self.2)
198    }
199}