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};