bb_geometry/linear_algebra/vector3/
mod.rs

1use super::matrix3x3::*;
2use crate::linear_algebra::EPSILON;
3use std::ops::{Add, Index, IndexMut, Mul, Neg, Sub};
4
5/// Represents a 3-dimensional vector with f32 components.
6#[derive(Debug, Clone, Copy, PartialEq)]
7pub struct Vector3 {
8    /// The vector data stored as an array.
9    data: [f32; 3],
10}
11
12impl Vector3 {
13    /// Creates a new 3-vector from the provided array data.
14    ///
15    /// # Example
16    /// ```
17    /// use bb_geometry::linear_algebra::vector3::*;
18    /// let v = Vector3::new([1.0, 2.0, 3.0]);
19    /// assert_eq!(v.get(0), 1.0);
20    /// ```
21    pub fn new(data: [f32; 3]) -> Self {
22        Self { data }
23    }
24
25    /// Creates a zero vector (all components are 0.0).
26    ///
27    /// # Example
28    /// ```
29    /// use bb_geometry::linear_algebra::vector3::*;
30    /// let zero = Vector3::zero();
31    /// assert_eq!(zero.get(1), 0.0);
32    /// ```
33    pub fn zero() -> Self {
34        Self { data: [0.0; 3] }
35    }
36
37    /// Creates a unit vector along the X axis ([1.0, 0.0, 0.0]).
38    pub fn unit_x() -> Self {
39        Self {
40            data: [1.0, 0.0, 0.0],
41        }
42    }
43
44    /// Creates a unit vector along the Y axis ([0.0, 1.0, 0.0]).
45    pub fn unit_y() -> Self {
46        Self {
47            data: [0.0, 1.0, 0.0],
48        }
49    }
50
51    /// Creates a unit vector along the Z axis ([0.0, 0.0, 1.0]).
52    pub fn unit_z() -> Self {
53        Self {
54            data: [0.0, 0.0, 1.0],
55        }
56    }
57
58    /// Gets the value at the specified index using a method call.
59    ///
60    /// Prefer using the index operator `vector[index]` for more idiomatic access.
61    ///
62    /// # Panics
63    /// Panics if `index` is out of bounds (>= 3).
64    ///
65    /// # Example
66    /// ```
67    /// use bb_geometry::linear_algebra::vector3::*;
68    /// let v = Vector3::new([1.0, 2.0, 3.0]);
69    /// assert_eq!(v.get(1), 2.0);
70    /// ```
71    #[inline]
72    pub fn get(&self, index: usize) -> f32 {
73        assert!(index < 3, "Index out of bounds: {}", index);
74        self.data[index]
75    }
76
77    /// Sets the value at the specified index using a method call.
78    ///
79    /// Prefer using the mutable index operator `vector[index] = value`
80    /// for more idiomatic modification.
81    ///
82    /// # Panics
83    /// Panics if `index` is out of bounds (>= 3).
84    ///
85    /// # Example
86    /// ```
87    /// use bb_geometry::linear_algebra::vector3::*;
88    /// let mut v = Vector3::zero();
89    /// v.set(2, 5.0);
90    /// assert_eq!(v.get(2), 5.0);
91    /// ```
92    #[inline]
93    pub fn set(&mut self, index: usize, value: f32) {
94        assert!(index < 3, "Index out of bounds: {}", index);
95        self.data[index] = value;
96    }
97
98    /// Calculates the dot (inner) product of this vector with another vector.
99    ///
100    /// result = self[0]*other[0] + self[1]*other[1] + self[2]*other[2]
101    ///
102    /// # Example
103    /// ```
104    /// use bb_geometry::linear_algebra::vector3::*;
105    /// let v1 = Vector3::new([1.0, 2.0, 3.0]);
106    /// let v2 = Vector3::new([4.0, 5.0, 6.0]);
107    /// // 1*4 + 2*5 + 3*6 = 4 + 10 + 18 = 32
108    /// assert_eq!(v1.dot(&v2), 32.0);
109    /// ```
110    pub fn dot(&self, other: &Self) -> f32 {
111        let mut sum = 0.0;
112        for i in 0..3 {
113            sum += self.data[i] * other.data[i];
114        }
115        sum
116    }
117
118    pub fn l2_norm(&self) -> f32 {
119        let mut sum = 0.0;
120        for i in 0..3 {
121            sum += self.data[i] * self.data[i];
122        }
123        sum.sqrt()
124    }
125
126    pub fn l1_norm(&self) -> f32 {
127        let mut sum = 0.0;
128        for i in 0..3 {
129            let inc = self.data[i].abs();
130            if inc > sum {
131                sum = inc;
132            }
133        }
134        sum
135    }
136
137    /// Is true if none component of the vector exceeds EPSILON
138    ///
139    /// # Example
140    /// ```
141    /// use crate::bb_geometry::linear_algebra::vector3::*;
142    /// use crate::bb_geometry::linear_algebra::EPSILON;
143    ///
144    /// let zero_vector = Vector3::zero();
145    /// let vector_with_epsilon_entries = Vector3::new([EPSILON, EPSILON, 0.0]);
146    /// let vector_with_entries_exceeding_epsilon = Vector3::new([EPSILON, 1.1 * EPSILON, 0.0]);
147    ///
148    /// let zero_vector_is_almost_zero = zero_vector.is_almost_zero();
149    /// let vector_with_epsilon_entries_is_almost_zero = vector_with_epsilon_entries.is_almost_zero();
150    /// let vector_with_entries_exceeding_epsilon_is_not_almost_zero = !vector_with_entries_exceeding_epsilon.is_almost_zero();
151    ///
152    /// assert!(zero_vector_is_almost_zero);
153    /// assert!(vector_with_epsilon_entries_is_almost_zero);
154    /// assert!(vector_with_entries_exceeding_epsilon_is_not_almost_zero);
155    /// ```
156    pub fn is_almost_zero(&self) -> bool {
157        self.data.iter().all(|c| c.abs() <= EPSILON)
158    }
159
160    /// Calculates the cross product of this vector with another vector (`self x other`).
161    ///
162    /// Returns a new vector that is perpendicular to both input vectors,
163    /// following the right-hand rule.
164    ///
165    /// # Example
166    /// ```
167    /// use bb_geometry::linear_algebra::vector3::*;
168    /// let x_axis = Vector3::new([1.0, 0.0, 0.0]);
169    /// let y_axis = Vector3::new([0.0, 1.0, 0.0]);
170    /// let z_axis = Vector3::new([0.0, 0.0, 1.0]);
171    ///
172    /// let xy_cross = x_axis.cross(&y_axis);
173    /// // x x y = z
174    /// assert_eq!(xy_cross, z_axis);
175    ///
176    /// let yx_cross = y_axis.cross(&x_axis);
177    /// // y x x = -z
178    /// assert_eq!(yx_cross, -z_axis);
179    ///
180    /// let v1 = Vector3::new([1.0, 2.0, 3.0]);
181    /// let v2 = Vector3::new([4.0, 5.0, 6.0]);
182    /// let cross_v1_v2 = v1.cross(&v2);
183    /// // x = 2*6 - 3*5 = 12 - 15 = -3
184    /// // y = 3*4 - 1*6 = 12 - 6 = 6
185    /// // z = 1*5 - 2*4 = 5 - 8 = -3
186    /// assert_eq!(cross_v1_v2, Vector3::new([-3.0, 6.0, -3.0]));
187    /// let t1 = cross_v1_v2.dot(&v1);
188    /// let t2 = cross_v1_v2.dot(&v2);
189    /// assert_eq!(t1, 0.0);
190    /// assert_eq!(t2, 0.0);
191    /// ```
192    pub fn cross(&self, other: &Self) -> Self {
193        Vector3::new([
194            self.data[1] * other.data[2] - self.data[2] * other.data[1],
195            self.data[2] * other.data[0] - self.data[0] * other.data[2],
196            self.data[0] * other.data[1] - self.data[1] * other.data[0],
197        ])
198    }
199
200    /// Calculates the squared magnitude (length squared) of the vector.
201    /// Often useful as it avoids a square root calculation.
202    /// result = x*x + y*y + z*z
203    pub fn magnitude_squared(&self) -> f32 {
204        self.dot(self)
205    }
206
207    /// Calculates the magnitude (length) of the vector.
208    /// result = sqrt(x*x + y*y + z*z)
209    pub fn magnitude(&self) -> f32 {
210        self.magnitude_squared().sqrt()
211    }
212
213    /// Returns a new vector with the same direction but a magnitude of 1.
214    /// Returns a zero vector if the original vector's magnitude is zero.
215    pub fn normalize(&self) -> Self {
216        let mag = self.magnitude();
217        if mag == 0.0 {
218            Self::zero()
219        } else {
220            self * (1.0 / mag)
221        }
222    }
223}
224
225// --- Trait Implementations ---
226
227/// Allows accessing vector components using index `vector[index]`.
228///
229/// # Panics
230/// Panics if `index` is out of bounds (>= 3).
231impl Index<usize> for Vector3 {
232    type Output = f32;
233
234    #[inline]
235    fn index(&self, index: usize) -> &Self::Output {
236        assert!(index < 3, "Index out of bounds: {}", index);
237        &self.data[index]
238    }
239}
240
241/// Allows mutating vector components using index `vector[index] = value`.
242///
243/// # Panics
244/// Panics if `index` is out of bounds (>= 3).
245impl IndexMut<usize> for Vector3 {
246    #[inline]
247    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
248        assert!(index < 3, "Index out of bounds: {}", index);
249        &mut self.data[index]
250    }
251}
252
253/// Implements vector addition using the `+` operator (`&Vector3 + &Vector3`).
254impl Add<&Vector3> for &Vector3 {
255    type Output = Vector3;
256
257    fn add(self, rhs: &Vector3) -> Self::Output {
258        let mut result_data = [0.0f32; 3];
259        for i in 0..3 {
260            result_data[i] = self.data[i] + rhs.data[i];
261        }
262        Vector3 { data: result_data }
263    }
264}
265// Delegate owned + owned, owned + ref, ref + owned to ref + ref
266impl Add<Vector3> for Vector3 {
267    type Output = Vector3;
268    #[inline]
269    fn add(self, rhs: Vector3) -> Self::Output {
270        &self + &rhs
271    }
272}
273impl Add<&Vector3> for Vector3 {
274    type Output = Vector3;
275    #[inline]
276    fn add(self, rhs: &Vector3) -> Self::Output {
277        &self + rhs
278    }
279}
280impl Add<Vector3> for &Vector3 {
281    type Output = Vector3;
282    #[inline]
283    fn add(self, rhs: Vector3) -> Self::Output {
284        self + &rhs
285    }
286}
287
288/// Implements vector subtraction using the `-` operator (`&Vector3 - &Vector3`).
289impl Sub<&Vector3> for &Vector3 {
290    type Output = Vector3;
291
292    fn sub(self, rhs: &Vector3) -> Self::Output {
293        let mut result_data = [0.0f32; 3];
294        for i in 0..3 {
295            result_data[i] = self.data[i] - rhs.data[i];
296        }
297        Vector3 { data: result_data }
298    }
299}
300// Delegate owned - owned, owned - ref, ref - owned to ref - ref
301impl Sub<Vector3> for Vector3 {
302    type Output = Vector3;
303    #[inline]
304    fn sub(self, rhs: Vector3) -> Self::Output {
305        &self - &rhs
306    }
307}
308impl Sub<&Vector3> for Vector3 {
309    type Output = Vector3;
310    #[inline]
311    fn sub(self, rhs: &Vector3) -> Self::Output {
312        &self - rhs
313    }
314}
315impl Sub<Vector3> for &Vector3 {
316    type Output = Vector3;
317    #[inline]
318    fn sub(self, rhs: Vector3) -> Self::Output {
319        self - &rhs
320    }
321}
322
323/// Implements vector negation using the unary `-` operator (`-vector`).
324impl Neg for Vector3 {
325    type Output = Self;
326
327    fn neg(self) -> Self::Output {
328        -&self
329    }
330}
331
332impl Neg for &Vector3 {
333    type Output = Vector3;
334
335    fn neg(self) -> Self::Output {
336        let mut result_data = [0.0f32; 3];
337        for i in 0..3 {
338            result_data[i] = -self.data[i];
339        }
340        Vector3 { data: result_data }
341    }
342}
343
344/// Implements scalar multiplication (`&Vector3 * f32`).
345impl Mul<f32> for &Vector3 {
346    type Output = Vector3;
347
348    fn mul(self, rhs: f32) -> Self::Output {
349        let mut result_data = [0.0f32; 3];
350        for i in 0..3 {
351            result_data[i] = self.data[i] * rhs;
352        }
353        Vector3 { data: result_data }
354    }
355}
356// Delegate owned * scalar to ref * scalar
357impl Mul<f32> for Vector3 {
358    type Output = Vector3;
359    #[inline]
360    fn mul(self, rhs: f32) -> Self::Output {
361        &self * rhs
362    }
363}
364
365/// Implements scalar multiplication (`f32 * &Vector3`).
366impl Mul<&Vector3> for f32 {
367    type Output = Vector3;
368
369    fn mul(self, rhs: &Vector3) -> Self::Output {
370        // Reuse the Vector * scalar implementation
371        rhs * self
372    }
373}
374// Delegate scalar * owned to scalar * ref
375impl Mul<Vector3> for f32 {
376    type Output = Vector3;
377    #[inline]
378    fn mul(self, rhs: Vector3) -> Self::Output {
379        self * &rhs
380    }
381}
382
383/// Implements Matrix * Vector multiplication (`&Matrix3x3 * &Vector3`).
384/// Treats the vector as a column vector.
385impl Mul<&Vector3> for &Matrix3x3 {
386    type Output = Vector3;
387
388    fn mul(self, rhs: &Vector3) -> Self::Output {
389        let mut result_data = [0.0f32; 3];
390        for i in 0..3 {
391            // Row of linear_algebra / element of result vector
392            let mut sum = 0.0;
393            for k in 0..3 {
394                // Column of linear_algebra / element of input vector
395                sum += self[(i, k)] * rhs.data[k];
396            }
397            result_data[i] = sum;
398        }
399        Vector3 { data: result_data }
400    }
401}
402
403// Delegate other Matrix * Vector combinations if needed
404impl Mul<Vector3> for Matrix3x3 {
405    type Output = Vector3;
406    #[inline]
407    fn mul(self, rhs: Vector3) -> Self::Output {
408        &self * &rhs
409    }
410}
411impl Mul<&Vector3> for Matrix3x3 {
412    type Output = Vector3;
413    #[inline]
414    fn mul(self, rhs: &Vector3) -> Self::Output {
415        &self * rhs
416    }
417}
418impl Mul<Vector3> for &Matrix3x3 {
419    type Output = Vector3;
420    #[inline]
421    fn mul(self, rhs: Vector3) -> Self::Output {
422        self * &rhs
423    }
424}
425
426pub const E_X: Vector3 = Vector3 {
427    data: [1.0, 0.0, 0.0],
428};
429pub const E_Y: Vector3 = Vector3 {
430    data: [0.0, 1.0, 0.0],
431};
432pub const E_Z: Vector3 = Vector3 {
433    data: [0.0, 0.0, 1.0],
434};