commonlibsse_ng\re\n/
NiPoint3.rs

1use core::ops::{
2    Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Sub, SubAssign,
3};
4
5/// 3D vector representation.
6#[repr(C)]
7#[derive(Debug, Default, Clone, Copy, PartialEq, PartialOrd)]
8pub struct NiPoint3 {
9    pub x: f32,
10    pub y: f32,
11    pub z: f32,
12}
13const _: () = assert!(core::mem::size_of::<NiPoint3>() == 0xc);
14
15impl NiPoint3 {
16    /// Creates a new `NiPoint3` from x, y, and z coordinates.
17    ///
18    /// # Example
19    /// ```
20    /// # use commonlibsse_ng::re::NiPoint3::NiPoint3;
21    /// let point = NiPoint3::new(1.0, 2.0, 3.0);
22    /// assert_eq!(point.x, 1.0);
23    /// ```
24    #[inline]
25    pub const fn new(x: f32, y: f32, z: f32) -> Self {
26        Self { x, y, z }
27    }
28
29    /// Computes the dot product with another `NiPoint3`.
30    ///
31    /// # Example
32    /// ```
33    /// # use commonlibsse_ng::re::NiPoint3::NiPoint3;
34    /// let a = NiPoint3::new(1.0, 2.0, 3.0);
35    /// let b = NiPoint3::new(4.0, 5.0, 6.0);
36    /// assert_eq!(a.dot(&b), 32.0);
37    /// ```
38    #[inline]
39    pub fn dot(&self, other: &Self) -> f32 {
40        self.z.mul_add(other.z, self.x.mul_add(other.x, self.y * other.y))
41    }
42
43    /// Computes the cross product with another `NiPoint3`.
44    ///
45    /// # Example
46    /// ```
47    /// # use commonlibsse_ng::re::NiPoint3::NiPoint3;
48    /// let a = NiPoint3::new(1.0, 0.0, 0.0);
49    /// let b = NiPoint3::new(0.0, 1.0, 0.0);
50    /// let cross = a.cross(&b);
51    /// assert_eq!(cross, NiPoint3::new(0.0, 0.0, 1.0));
52    /// ```
53    #[inline]
54    pub fn cross(&self, other: &Self) -> Self {
55        Self {
56            x: self.y.mul_add(other.z, -(self.z * other.y)),
57            y: self.z.mul_add(other.x, -(self.x * other.z)),
58            z: self.x.mul_add(other.y, -(self.y * other.x)),
59        }
60    }
61
62    /// Computes the length (magnitude) of the vector.
63    ///
64    /// # Example
65    /// ```
66    /// # use commonlibsse_ng::re::NiPoint3::NiPoint3;
67    /// let v = NiPoint3::new(3.0, 4.0, 0.0);
68    /// assert_eq!(v.length(), 5.0);
69    /// ```
70    #[inline]
71    pub fn length(&self) -> f32 {
72        self.sqr_length().sqrt()
73    }
74
75    /// Returns the squared length of the vector.
76    #[inline]
77    pub fn sqr_length(&self) -> f32 {
78        self.dot(self)
79    }
80
81    /// Computes the distance to another `NiPoint3`.
82    ///
83    /// # Example
84    /// ```
85    /// # use commonlibsse_ng::re::NiPoint3::NiPoint3;
86    /// let a = NiPoint3::new(1.0, 2.0, 3.0);
87    /// let b = NiPoint3::new(4.0, 6.0, 3.0);
88    /// assert_eq!(a.distance(&b), 5.0);
89    /// ```
90    #[inline]
91    pub fn distance(&self, other: &Self) -> f32 {
92        (*self - *other).length()
93    }
94
95    /// Computes the squared distance to another `NiPoint3`.
96    #[inline]
97    pub fn squared_distance(&self, other: &Self) -> f32 {
98        (*self - *other).sqr_length()
99    }
100
101    /// Normalizes the vector in place and returns its original length.
102    ///
103    /// # Example
104    /// ```
105    /// # use commonlibsse_ng::re::NiPoint3::NiPoint3;
106    /// let mut v = NiPoint3::new(3.0, 4.0, 0.0);
107    /// let len = v.unitize();
108    /// assert_eq!(len, 5.0);
109    /// assert_eq!(v, NiPoint3::new(0.6, 0.8, 0.0));
110    /// ```
111    #[inline]
112    pub fn unitize(&mut self) -> f32 {
113        let len = self.length();
114        if len > 0.0 {
115            *self /= len;
116        }
117        len
118    }
119
120    /// Computes the unit cross product with another `NiPoint3`.
121    ///
122    /// # Example
123    /// ```
124    /// # use commonlibsse_ng::re::NiPoint3::NiPoint3;
125    /// let a = NiPoint3::new(1.0, 0.0, 0.0);
126    /// let b = NiPoint3::new(0.0, 1.0, 0.0);
127    /// let unit_cross = a.unit_cross(&b);
128    /// assert_eq!(unit_cross, NiPoint3::new(0.0, 0.0, 1.0));
129    /// ```
130    #[inline]
131    pub fn unit_cross(&self, other: &Self) -> Self {
132        let mut cross = self.cross(other);
133        cross.unitize();
134        cross
135    }
136
137    /// Returns the zero vector.
138    ///
139    /// # Example
140    /// ```
141    /// # use commonlibsse_ng::re::NiPoint3::NiPoint3;
142    /// let zero = NiPoint3::zero();
143    /// assert_eq!(zero, NiPoint3::new(0.0, 0.0, 0.0));
144    /// ```
145    #[inline]
146    pub const fn zero() -> Self {
147        Self { x: 0.0, y: 0.0, z: 0.0 }
148    }
149}
150
151impl Index<usize> for NiPoint3 {
152    type Output = f32;
153
154    #[inline]
155    fn index(&self, index: usize) -> &Self::Output {
156        match index {
157            0 => &self.x,
158            1 => &self.y,
159            2 => &self.z,
160            invalid_index => {
161                panic!("NiPoint3 expects an index in the range 0..=2, but got {invalid_index}.")
162            }
163        }
164    }
165}
166
167impl IndexMut<usize> for NiPoint3 {
168    #[inline]
169    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
170        match index {
171            0 => &mut self.x,
172            1 => &mut self.y,
173            2 => &mut self.z,
174            invalid_index => {
175                panic!("NiPoint3 expects an index in the range 0..=2, but got {invalid_index}.")
176            }
177        }
178    }
179}
180
181impl Add for NiPoint3 {
182    type Output = Self;
183
184    #[inline]
185    fn add(self, rhs: Self) -> Self::Output {
186        Self::new(self.x + rhs.x, self.y + rhs.y, self.z + rhs.z)
187    }
188}
189
190impl Sub for NiPoint3 {
191    type Output = Self;
192
193    #[inline]
194    fn sub(self, rhs: Self) -> Self::Output {
195        Self::new(self.x - rhs.x, self.y - rhs.y, self.z - rhs.z)
196    }
197}
198
199impl Mul<f32> for NiPoint3 {
200    type Output = Self;
201
202    #[inline]
203    fn mul(self, scalar: f32) -> Self::Output {
204        Self::new(self.x * scalar, self.y * scalar, self.z * scalar)
205    }
206}
207
208impl Div<f32> for NiPoint3 {
209    type Output = Self;
210
211    #[inline]
212    fn div(self, scalar: f32) -> Self::Output {
213        Self::new(self.x / scalar, self.y / scalar, self.z / scalar)
214    }
215}
216
217impl Neg for NiPoint3 {
218    type Output = Self;
219
220    #[inline]
221    fn neg(self) -> Self::Output {
222        Self::new(-self.x, -self.y, -self.z)
223    }
224}
225
226impl AddAssign for NiPoint3 {
227    #[inline]
228    fn add_assign(&mut self, rhs: Self) {
229        self.x += rhs.x;
230        self.y += rhs.y;
231        self.z += rhs.z;
232    }
233}
234
235impl SubAssign for NiPoint3 {
236    #[inline]
237    fn sub_assign(&mut self, rhs: Self) {
238        self.x -= rhs.x;
239        self.y -= rhs.y;
240        self.z -= rhs.z;
241    }
242}
243
244impl MulAssign<f32> for NiPoint3 {
245    #[inline]
246    fn mul_assign(&mut self, scalar: f32) {
247        self.x *= scalar;
248        self.y *= scalar;
249        self.z *= scalar;
250    }
251}
252
253impl DivAssign<f32> for NiPoint3 {
254    #[inline]
255    fn div_assign(&mut self, scalar: f32) {
256        self.x /= scalar;
257        self.y /= scalar;
258        self.z /= scalar;
259    }
260}
261
262impl core::fmt::Display for NiPoint3 {
263    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
264        write!(f, "({:.1}, {:.1}, {:.1})", self.x, self.y, self.z)
265    }
266}