khora_core/math/
vector.rs

1// Copyright 2025 eraflo
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Provides 2D, 3D, and 4D vector types and their associated operations.
16
17use bincode::{Decode, Encode};
18use serde::{Deserialize, Serialize};
19
20use super::EPSILON;
21use std::ops::{Add, Div, Index, IndexMut, Mul, Neg, Sub};
22
23// --- Vec2 ---
24
25/// A 2-dimensional vector with `f32` components.
26#[derive(
27    Debug,
28    Default,
29    Copy,
30    Clone,
31    PartialEq,
32    bytemuck::Pod,
33    bytemuck::Zeroable,
34    Serialize,
35    Deserialize,
36    Encode,
37    Decode,
38)]
39#[repr(C)]
40pub struct Vec2 {
41    /// The x component of the vector.
42    pub x: f32,
43    /// The y component of the vector.
44    pub y: f32,
45}
46
47impl Vec2 {
48    /// A vector with all components set to `0.0`.
49    pub const ZERO: Self = Self { x: 0.0, y: 0.0 };
50    /// A vector with all components set to `1.0`.
51    pub const ONE: Self = Self { x: 1.0, y: 1.0 };
52    /// The unit vector pointing along the positive X-axis.
53    pub const X: Self = Self { x: 1.0, y: 0.0 };
54    /// The unit vector pointing along the positive Y-axis.
55    pub const Y: Self = Self { x: 0.0, y: 1.0 };
56
57    /// Creates a new `Vec2` with the specified components.
58    #[inline]
59    pub const fn new(x: f32, y: f32) -> Self {
60        Self { x, y }
61    }
62
63    /// Returns a new vector with the absolute value of each component.
64    #[inline]
65    pub const fn abs(self) -> Self {
66        Self {
67            x: if self.x < 0.0 { -self.x } else { self.x },
68            y: if self.y < 0.0 { -self.y } else { self.y },
69        }
70    }
71
72    /// Calculates the squared length (magnitude) of the vector.
73    /// This is faster than `length()` as it avoids a square root.
74    #[inline]
75    pub fn length_squared(&self) -> f32 {
76        self.dot(*self)
77    }
78
79    /// Calculates the length (magnitude) of the vector.
80    #[inline]
81    pub fn length(&self) -> f32 {
82        self.length_squared().sqrt()
83    }
84
85    /// Returns a normalized version of the vector with a length of 1.
86    /// If the vector's length is near zero, it returns `Vec2::ZERO`.
87    #[inline]
88    pub fn normalize(&self) -> Self {
89        let len_sq = self.length_squared();
90        if len_sq > EPSILON * EPSILON {
91            *self * (1.0 / len_sq.sqrt())
92        } else {
93            Self::ZERO
94        }
95    }
96
97    /// Calculates the dot product of this vector and another.
98    #[inline]
99    pub fn dot(&self, rhs: Self) -> f32 {
100        self.x * rhs.x + self.y * rhs.y
101    }
102
103    /// Performs a linear interpolation between two vectors.
104    /// The interpolation factor `t` is clamped to the `[0.0, 1.0]` range.
105    #[inline]
106    pub fn lerp(start: Self, end: Self, t: f32) -> Self {
107        start + (end - start) * t.clamp(0.0, 1.0)
108    }
109}
110
111// --- Operator Overloads ---
112
113impl Add for Vec2 {
114    type Output = Self;
115    /// Adds two vectors component-wise.
116    #[inline]
117    fn add(self, rhs: Self) -> Self::Output {
118        Self {
119            x: self.x + rhs.x,
120            y: self.y + rhs.y,
121        }
122    }
123}
124
125impl Sub for Vec2 {
126    type Output = Self;
127    /// Subtracts two vectors component-wise.
128    #[inline]
129    fn sub(self, rhs: Self) -> Self::Output {
130        Self {
131            x: self.x - rhs.x,
132            y: self.y - rhs.y,
133        }
134    }
135}
136
137impl Mul<f32> for Vec2 {
138    type Output = Self;
139    /// Multiplies the vector by a scalar.
140    #[inline]
141    fn mul(self, rhs: f32) -> Self::Output {
142        Self {
143            x: self.x * rhs,
144            y: self.y * rhs,
145        }
146    }
147}
148
149impl Mul<Vec2> for f32 {
150    type Output = Vec2;
151    /// Multiplies a scalar by a vector.
152    #[inline]
153    fn mul(self, rhs: Vec2) -> Self::Output {
154        rhs * self
155    }
156}
157
158impl Mul<Vec2> for Vec2 {
159    type Output = Self;
160    /// Multiplies two vectors component-wise.
161    #[inline]
162    fn mul(self, rhs: Vec2) -> Self::Output {
163        Self {
164            x: self.x * rhs.x,
165            y: self.y * rhs.y,
166        }
167    }
168}
169
170impl Div<f32> for Vec2 {
171    type Output = Self;
172    /// Divides the vector by a scalar.
173    #[inline]
174    fn div(self, rhs: f32) -> Self::Output {
175        let inv_rhs = 1.0 / rhs;
176        Self {
177            x: self.x * inv_rhs,
178            y: self.y * inv_rhs,
179        }
180    }
181}
182
183impl Neg for Vec2 {
184    type Output = Self;
185    /// Negates the vector.
186    #[inline]
187    fn neg(self) -> Self::Output {
188        Self {
189            x: -self.x,
190            y: -self.y,
191        }
192    }
193}
194
195impl Index<usize> for Vec2 {
196    type Output = f32;
197    /// Allows accessing a vector component by index (`v[0]`, `v[1]`).
198    ///
199    /// # Panics
200    /// Panics if `index` is not 0 or 1.
201    #[inline]
202    fn index(&self, index: usize) -> &Self::Output {
203        match index {
204            0 => &self.x,
205            1 => &self.y,
206            _ => panic!("Index out of bounds for Vec2"),
207        }
208    }
209}
210
211impl IndexMut<usize> for Vec2 {
212    /// Allows mutably accessing a vector component by index (`v[0] = ...`).
213    ///
214    /// # Panics
215    /// Panics if `index` is not 0 or 1.
216    #[inline]
217    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
218        match index {
219            0 => &mut self.x,
220            1 => &mut self.y,
221            _ => panic!("Index out of bounds for Vec2"),
222        }
223    }
224}
225
226// --- Vector3D ---
227
228/// A 3-dimensional vector with `f32` components.
229#[derive(
230    Debug,
231    Clone,
232    Copy,
233    PartialEq,
234    bytemuck::Pod,
235    bytemuck::Zeroable,
236    Serialize,
237    Deserialize,
238    Encode,
239    Decode,
240)]
241#[repr(C)]
242pub struct Vec3 {
243    /// The x component of the vector.
244    pub x: f32,
245    /// The y component of the vector.
246    pub y: f32,
247    /// The z component of the vector.
248    pub z: f32,
249}
250
251impl Vec3 {
252    /// A vector with all components set to `0.0`.
253    pub const ZERO: Self = Self {
254        x: 0.0,
255        y: 0.0,
256        z: 0.0,
257    };
258    /// A vector with all components set to `1.0`.
259    pub const ONE: Self = Self {
260        x: 1.0,
261        y: 1.0,
262        z: 1.0,
263    };
264    /// The unit vector pointing along the positive X-axis.
265    pub const X: Self = Self {
266        x: 1.0,
267        y: 0.0,
268        z: 0.0,
269    };
270    /// The unit vector pointing along the positive Y-axis.
271    pub const Y: Self = Self {
272        x: 0.0,
273        y: 1.0,
274        z: 0.0,
275    };
276    /// The unit vector pointing along the positive Z-axis.
277    pub const Z: Self = Self {
278        x: 0.0,
279        y: 0.0,
280        z: 1.0,
281    };
282
283    /// Creates a new `Vec3` with the specified components.
284    #[inline]
285    pub const fn new(x: f32, y: f32, z: f32) -> Self {
286        Self { x, y, z }
287    }
288
289    /// Returns a new vector with the absolute value of each component.
290    #[inline]
291    pub const fn abs(self) -> Self {
292        Self {
293            x: if self.x < 0.0 { -self.x } else { self.x },
294            y: if self.y < 0.0 { -self.y } else { self.y },
295            z: if self.z < 0.0 { -self.z } else { self.z },
296        }
297    }
298
299    /// Calculates the squared length (magnitude) of the vector.
300    #[inline]
301    pub fn length_squared(&self) -> f32 {
302        self.dot(*self)
303    }
304
305    /// Calculates the length (magnitude) of the vector.
306    #[inline]
307    pub fn length(&self) -> f32 {
308        self.length_squared().sqrt()
309    }
310
311    /// Returns a normalized version of the vector with a length of 1.
312    #[inline]
313    pub fn normalize(&self) -> Self {
314        let len_sq = self.length_squared();
315        if len_sq > EPSILON * EPSILON {
316            // Use squared length to avoid sqrt
317            // Multiply by inverse sqrt for potentially better performance
318            *self * (1.0 / len_sq.sqrt())
319        } else {
320            Self::ZERO
321        }
322    }
323
324    /// Calculates the dot product of this vector and another.
325    #[inline]
326    pub fn dot(&self, other: Self) -> f32 {
327        self.x * other.x + self.y * other.y + self.z * other.z
328    }
329
330    /// Computes the cross product of this vector and another.
331    #[inline]
332    pub fn cross(&self, other: Self) -> Self {
333        Self {
334            x: self.y * other.z - self.z * other.y,
335            y: self.z * other.x - self.x * other.z,
336            z: self.x * other.y - self.y * other.x,
337        }
338    }
339
340    /// Calculates the squared distance between this vector and another.
341    #[inline]
342    pub fn distance_squared(&self, other: Self) -> f32 {
343        let dx = self.x - other.x;
344        let dy = self.y - other.y;
345        let dz = self.z - other.z;
346        dx * dx + dy * dy + dz * dz
347    }
348
349    /// Calculates the distance between this vector and another.
350    #[inline]
351    pub fn distance(&self, other: Self) -> f32 {
352        self.distance_squared(other).sqrt()
353    }
354
355    /// Performs a linear interpolation between two vectors.
356    #[inline]
357    pub fn lerp(start: Self, end: Self, t: f32) -> Self {
358        Self {
359            x: start.x + (end.x - start.x) * t,
360            y: start.y + (end.y - start.y) * t,
361            z: start.z + (end.z - start.z) * t,
362        }
363    }
364
365    /// Retrieves a component of the vector by its index.
366    ///
367    /// # Panics
368    /// Panics if `index` is not 0, 1, or 2.
369    #[inline]
370    pub fn get(&self, index: usize) -> f32 {
371        match index {
372            0 => self.x,
373            1 => self.y,
374            2 => self.z,
375            _ => panic!("Index out of bounds for Vec3"),
376        }
377    }
378}
379
380// --- Operator Overloads ---
381
382impl Default for Vec3 {
383    /// Returns `Vec3::ZERO`.
384    #[inline]
385    fn default() -> Self {
386        Self::ZERO
387    }
388}
389
390impl Add for Vec3 {
391    type Output = Self;
392    /// Adds two vectors component-wise.
393    #[inline]
394    fn add(self, rhs: Self) -> Self::Output {
395        Self {
396            x: self.x + rhs.x,
397            y: self.y + rhs.y,
398            z: self.z + rhs.z,
399        }
400    }
401}
402
403impl Sub for Vec3 {
404    type Output = Self;
405    /// Subtracts two vectors component-wise.
406    #[inline]
407    fn sub(self, rhs: Self) -> Self::Output {
408        Self {
409            x: self.x - rhs.x,
410            y: self.y - rhs.y,
411            z: self.z - rhs.z,
412        }
413    }
414}
415
416impl Mul<f32> for Vec3 {
417    type Output = Self;
418    /// Multiplies the vector by a scalar.
419    #[inline]
420    fn mul(self, rhs: f32) -> Self::Output {
421        Self {
422            x: self.x * rhs,
423            y: self.y * rhs,
424            z: self.z * rhs,
425        }
426    }
427}
428
429impl Mul<Vec3> for f32 {
430    type Output = Vec3;
431    /// Multiplies a scalar by a vector.
432    #[inline]
433    fn mul(self, rhs: Vec3) -> Self::Output {
434        rhs * self
435    }
436}
437
438impl Mul<Vec3> for Vec3 {
439    type Output = Self;
440    /// Multiplies two vectors component-wise.
441    #[inline]
442    fn mul(self, rhs: Self) -> Self::Output {
443        Self {
444            x: self.x * rhs.x,
445            y: self.y * rhs.y,
446            z: self.z * rhs.z,
447        }
448    }
449}
450
451impl Div<f32> for Vec3 {
452    type Output = Self;
453    /// Divides the vector by a scalar.
454    #[inline]
455    fn div(self, rhs: f32) -> Self::Output {
456        let inv_rhs = 1.0 / rhs;
457        Self {
458            x: self.x * inv_rhs,
459            y: self.y * inv_rhs,
460            z: self.z * inv_rhs,
461        }
462    }
463}
464
465impl Neg for Vec3 {
466    type Output = Self;
467    /// Negates the vector.
468    #[inline]
469    fn neg(self) -> Self::Output {
470        Self {
471            x: -self.x,
472            y: -self.y,
473            z: -self.z,
474        }
475    }
476}
477
478impl Index<usize> for Vec3 {
479    type Output = f32;
480    /// Allows accessing a vector component by index.
481    /// # Panics
482    /// Panics if `index` is not 0, 1, or 2.
483    #[inline]
484    fn index(&self, index: usize) -> &Self::Output {
485        match index {
486            0 => &self.x,
487            1 => &self.y,
488            2 => &self.z,
489            _ => panic!("Index out of bounds for Vec3"),
490        }
491    }
492}
493
494impl IndexMut<usize> for Vec3 {
495    /// Allows mutably accessing a vector component by index.
496    /// # Panics
497    /// Panics if `index` is not 0, 1, or 2.
498    #[inline]
499    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
500        match index {
501            0 => &mut self.x,
502            1 => &mut self.y,
503            2 => &mut self.z,
504            _ => panic!("Index out of bounds for Vec3"),
505        }
506    }
507}
508
509// --- Vector4D ---
510
511/// A 4-dimensional vector with `f32` components, often used for homogeneous coordinates.
512///
513/// In 3D graphics, `Vec4` is primarily used to represent points (`w`=1.0) and
514/// vectors (`w`=0.0) in homogeneous space, allowing them to be transformed by a `Mat4`.
515#[derive(
516    Debug,
517    Default,
518    Copy,
519    Clone,
520    PartialEq,
521    bytemuck::Pod,
522    bytemuck::Zeroable,
523    Serialize,
524    Deserialize,
525    Encode,
526    Decode,
527)]
528#[repr(C)]
529pub struct Vec4 {
530    /// The x component of the vector.
531    pub x: f32,
532    /// The y component of the vector.
533    pub y: f32,
534    /// The z component of the vector.
535    pub z: f32,
536    /// The w component, used for homogeneous coordinates.
537    pub w: f32,
538}
539
540impl Vec4 {
541    /// A vector with all components set to `0.0`.
542    pub const ZERO: Self = Self {
543        x: 0.0,
544        y: 0.0,
545        z: 0.0,
546        w: 0.0,
547    };
548    /// A vector with all components set to `1.0`.
549    pub const ONE: Self = Self {
550        x: 1.0,
551        y: 1.0,
552        z: 1.0,
553        w: 1.0,
554    };
555    /// The unit vector pointing along the positive X-axis.
556    pub const X: Self = Self {
557        x: 1.0,
558        y: 0.0,
559        z: 0.0,
560        w: 0.0,
561    };
562    /// The unit vector pointing along the positive Y-axis.
563    pub const Y: Self = Self {
564        x: 0.0,
565        y: 1.0,
566        z: 0.0,
567        w: 0.0,
568    };
569    /// The unit vector pointing along the positive Z-axis.
570    pub const Z: Self = Self {
571        x: 0.0,
572        y: 0.0,
573        z: 1.0,
574        w: 0.0,
575    };
576    /// The unit vector pointing along the positive W-axis.
577    pub const W: Self = Self {
578        x: 0.0,
579        y: 0.0,
580        z: 0.0,
581        w: 1.0,
582    };
583
584    /// Creates a new `Vec4` with the specified components.
585    #[inline]
586    pub const fn new(x: f32, y: f32, z: f32, w: f32) -> Self {
587        Self { x, y, z, w }
588    }
589
590    /// Returns a new vector with the absolute value of each component.
591    #[inline]
592    pub const fn abs(self) -> Self {
593        Self {
594            x: if self.x < 0.0 { -self.x } else { self.x },
595            y: if self.y < 0.0 { -self.y } else { self.y },
596            z: if self.z < 0.0 { -self.z } else { self.z },
597            w: if self.w < 0.0 { -self.w } else { self.w },
598        }
599    }
600
601    /// Creates a `Vec4` from a `Vec3` and a `w` component.
602    #[inline]
603    pub fn from_vec3(v: Vec3, w: f32) -> Self {
604        Self::new(v.x, v.y, v.z, w)
605    }
606
607    /// Returns the `[x, y, z]` components of the vector as a `Vec3`, discarding `w`.
608    #[inline]
609    pub fn truncate(&self) -> Vec3 {
610        Vec3::new(self.x, self.y, self.z)
611    }
612
613    /// Calculates the dot product of this vector and another.
614    #[inline]
615    pub fn dot(&self, other: Self) -> f32 {
616        self.x * other.x + self.y * other.y + self.z * other.z + self.w * other.w
617    }
618
619    /// Retrieves a component of the vector by its index.
620    ///
621    /// # Panics
622    /// Panics if `index` is not between 0 and 3.
623    #[inline]
624    pub fn get(&self, index: usize) -> f32 {
625        match index {
626            0 => self.x,
627            1 => self.y,
628            2 => self.z,
629            3 => self.w,
630            _ => panic!("Index out of bounds for Vec4"),
631        }
632    }
633}
634
635// --- Operator Overloads ---
636
637impl Add for Vec4 {
638    type Output = Self;
639    /// Adds two vectors component-wise.
640    #[inline]
641    fn add(self, rhs: Self) -> Self::Output {
642        Self {
643            x: self.x + rhs.x,
644            y: self.y + rhs.y,
645            z: self.z + rhs.z,
646            w: self.w + rhs.w,
647        }
648    }
649}
650
651impl Sub for Vec4 {
652    type Output = Self;
653    /// Subtracts two vectors component-wise.
654    #[inline]
655    fn sub(self, rhs: Self) -> Self::Output {
656        Self {
657            x: self.x - rhs.x,
658            y: self.y - rhs.y,
659            z: self.z - rhs.z,
660            w: self.w - rhs.w,
661        }
662    }
663}
664
665impl Mul<f32> for Vec4 {
666    type Output = Self;
667    /// Multiplies the vector by a scalar.
668    #[inline]
669    fn mul(self, rhs: f32) -> Self::Output {
670        Self {
671            x: self.x * rhs,
672            y: self.y * rhs,
673            z: self.z * rhs,
674            w: self.w * rhs,
675        }
676    }
677}
678
679impl Mul<Vec4> for f32 {
680    type Output = Vec4;
681    /// Multiplies a scalar by a vector.
682    #[inline]
683    fn mul(self, rhs: Vec4) -> Self::Output {
684        rhs * self
685    }
686}
687
688impl Mul<Vec4> for Vec4 {
689    type Output = Self;
690    /// Multiplies two vectors component-wise.
691    #[inline]
692    fn mul(self, rhs: Self) -> Self::Output {
693        Self {
694            x: self.x * rhs.x,
695            y: self.y * rhs.y,
696            z: self.z * rhs.z,
697            w: self.w * rhs.w,
698        }
699    }
700}
701
702impl Div<f32> for Vec4 {
703    type Output = Self;
704    /// Divides the vector by a scalar.
705    #[inline]
706    fn div(self, rhs: f32) -> Self::Output {
707        let inv_rhs = 1.0 / rhs;
708        Self {
709            x: self.x * inv_rhs,
710            y: self.y * inv_rhs,
711            z: self.z * inv_rhs,
712            w: self.w * inv_rhs,
713        }
714    }
715}
716
717impl Neg for Vec4 {
718    type Output = Self;
719    /// Negates the vector.
720    #[inline]
721    fn neg(self) -> Self::Output {
722        Self {
723            x: -self.x,
724            y: -self.y,
725            z: -self.z,
726            w: -self.w,
727        }
728    }
729}
730
731impl Index<usize> for Vec4 {
732    type Output = f32;
733    /// Allows accessing a vector component by index.
734    /// # Panics
735    /// Panics if `index` is not between 0 and 3.
736    #[inline]
737    fn index(&self, index: usize) -> &Self::Output {
738        match index {
739            0 => &self.x,
740            1 => &self.y,
741            2 => &self.z,
742            3 => &self.w,
743            _ => panic!("Index out of bounds for Vec4"),
744        }
745    }
746}
747
748impl IndexMut<usize> for Vec4 {
749    /// Allows mutably accessing a vector component by index.
750    /// # Panics
751    /// Panics if `index` is not between 0 and 3.
752    #[inline]
753    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
754        match index {
755            0 => &mut self.x,
756            1 => &mut self.y,
757            2 => &mut self.z,
758            3 => &mut self.w,
759            _ => panic!("Index out of bounds for Vec4"),
760        }
761    }
762}
763
764/// --- Tests ---
765#[cfg(test)]
766mod tests {
767    use super::*; // Import Vec3 from the parent module
768    use crate::math::approx_eq;
769
770    fn vec2_approx_eq(a: Vec2, b: Vec2) -> bool {
771        approx_eq(a.x, b.x) && approx_eq(a.y, b.y)
772    }
773
774    fn vec3_approx_eq(a: Vec3, b: Vec3) -> bool {
775        approx_eq(a.x, b.x) && approx_eq(a.y, b.y) && approx_eq(a.z, b.z)
776    }
777
778    // Test Vec2
779
780    #[test]
781    fn test_vec2_new() {
782        let v = Vec2::new(1.0, 2.0);
783        assert_eq!(v.x, 1.0);
784        assert_eq!(v.y, 2.0);
785    }
786
787    #[test]
788    fn test_vec2_abs() {
789        let v = Vec2::new(-1.0, 2.0);
790        assert_eq!(v.abs(), Vec2::new(1.0, 2.0));
791    }
792
793    #[test]
794    fn test_vec2_constants() {
795        assert_eq!(Vec2::ZERO, Vec2::new(0.0, 0.0));
796        assert_eq!(Vec2::ONE, Vec2::new(1.0, 1.0));
797        assert_eq!(Vec2::X, Vec2::new(1.0, 0.0));
798        assert_eq!(Vec2::Y, Vec2::new(0.0, 1.0));
799    }
800
801    #[test]
802    fn test_vec2_ops() {
803        let v1 = Vec2::new(1.0, 2.0);
804        let v2 = Vec2::new(3.0, 4.0);
805        assert_eq!(v1 + v2, Vec2::new(4.0, 6.0));
806        assert_eq!(v2 - v1, Vec2::new(2.0, 2.0));
807        assert_eq!(v1 * 2.0, Vec2::new(2.0, 4.0));
808        assert_eq!(3.0 * v1, Vec2::new(3.0, 6.0));
809        assert_eq!(v1 * v2, Vec2::new(3.0, 8.0)); // Component-wise
810        assert_eq!(-v1, Vec2::new(-1.0, -2.0));
811        assert!(vec2_approx_eq(
812            Vec2::new(4.0, 6.0) / 2.0,
813            Vec2::new(2.0, 3.0)
814        ));
815    }
816
817    #[test]
818    fn test_vec2_dot() {
819        let v1 = Vec2::new(1.0, 2.0);
820        let v2 = Vec2::new(3.0, 4.0);
821        assert!(approx_eq(v1.dot(v2), 1.0 * 3.0 + 2.0 * 4.0)); // 3 + 8 = 11
822    }
823
824    #[test]
825    fn test_vec2_length() {
826        let v = Vec2::new(3.0, 4.0);
827        assert!(approx_eq(v.length_squared(), 25.0));
828        assert!(approx_eq(v.length(), 5.0));
829        assert!(approx_eq(Vec2::ZERO.length(), 0.0));
830    }
831
832    #[test]
833    fn test_vec2_normalize() {
834        let v1 = Vec2::new(3.0, 0.0);
835        let norm_v1 = v1.normalize();
836        assert!(vec2_approx_eq(norm_v1, Vec2::X));
837        assert!(approx_eq(norm_v1.length(), 1.0));
838
839        let v_zero = Vec2::ZERO;
840        assert_eq!(v_zero.normalize(), Vec2::ZERO);
841    }
842
843    #[test]
844    fn test_vec2_lerp() {
845        let start = Vec2::new(0.0, 10.0);
846        let end = Vec2::new(10.0, 0.0);
847        assert!(vec2_approx_eq(Vec2::lerp(start, end, 0.0), start));
848        assert!(vec2_approx_eq(Vec2::lerp(start, end, 1.0), end));
849        assert!(vec2_approx_eq(
850            Vec2::lerp(start, end, 0.5),
851            Vec2::new(5.0, 5.0)
852        ));
853        // Test clamping
854        assert!(vec2_approx_eq(Vec2::lerp(start, end, -0.5), start));
855        assert!(vec2_approx_eq(Vec2::lerp(start, end, 1.5), end));
856    }
857
858    #[test]
859    fn test_vec2_index() {
860        let mut v = Vec2::new(5.0, 6.0);
861        assert_eq!(v[0], 5.0);
862        assert_eq!(v[1], 6.0);
863        v[0] = 10.0;
864        assert_eq!(v.x, 10.0);
865    }
866
867    #[test]
868    #[should_panic]
869    fn test_vec2_index_out_of_bounds() {
870        let v = Vec2::new(1.0, 2.0);
871        let _ = v[2]; // Should panic
872    }
873
874    // Test Vec3
875
876    #[test]
877    fn test_new() {
878        let v = Vec3::new(1.0, 2.0, 3.0);
879        assert_eq!(v.x, 1.0);
880        assert_eq!(v.y, 2.0);
881        assert_eq!(v.z, 3.0);
882    }
883
884    #[test]
885    fn test_vec3_abs() {
886        let v = Vec3::new(-1.0, 2.0, -3.0);
887        assert_eq!(v.abs(), Vec3::new(1.0, 2.0, 3.0));
888        assert_eq!(Vec3::ZERO.abs(), Vec3::ZERO);
889    }
890
891    #[test]
892    fn test_constants() {
893        assert_eq!(Vec3::ZERO, Vec3::new(0.0, 0.0, 0.0));
894        assert_eq!(Vec3::ONE, Vec3::new(1.0, 1.0, 1.0));
895        assert_eq!(Vec3::X, Vec3::new(1.0, 0.0, 0.0));
896        assert_eq!(Vec3::Y, Vec3::new(0.0, 1.0, 0.0));
897        assert_eq!(Vec3::Z, Vec3::new(0.0, 0.0, 1.0));
898    }
899
900    #[test]
901    fn test_add() {
902        let v1 = Vec3::new(1.0, 2.0, 3.0);
903        let v2 = Vec3::new(4.0, 5.0, 6.0);
904        assert_eq!(v1 + v2, Vec3::new(5.0, 7.0, 9.0));
905    }
906
907    #[test]
908    fn test_sub() {
909        let v1 = Vec3::new(5.0, 7.0, 9.0);
910        let v2 = Vec3::new(1.0, 2.0, 3.0);
911        assert_eq!(v1 - v2, Vec3::new(4.0, 5.0, 6.0));
912    }
913
914    #[test]
915    fn test_scalar_mul() {
916        let v = Vec3::new(1.0, 2.0, 3.0);
917        assert_eq!(v * 2.0, Vec3::new(2.0, 4.0, 6.0));
918        assert_eq!(3.0 * v, Vec3::new(3.0, 6.0, 9.0)); // Test f32 * Vec3
919    }
920
921    #[test]
922    fn test_component_mul() {
923        let v1 = Vec3::new(1.0, 2.0, 3.0);
924        let v2 = Vec3::new(4.0, 5.0, 6.0);
925        assert_eq!(v1 * v2, Vec3::new(4.0, 10.0, 18.0));
926    }
927
928    #[test]
929    fn test_scalar_div() {
930        let v = Vec3::new(2.0, 4.0, 6.0);
931        assert_eq!(v / 2.0, Vec3::new(1.0, 2.0, 3.0));
932    }
933
934    #[test]
935    fn test_neg() {
936        let v = Vec3::new(1.0, -2.0, 3.0);
937        assert_eq!(-v, Vec3::new(-1.0, 2.0, -3.0));
938    }
939
940    #[test]
941    fn test_length() {
942        let v1 = Vec3::new(3.0, 4.0, 0.0);
943        assert!(approx_eq(v1.length_squared(), 25.0));
944        assert!(approx_eq(v1.length(), 5.0));
945
946        let v2 = Vec3::ZERO;
947        assert!(approx_eq(v2.length_squared(), 0.0));
948        assert!(approx_eq(v2.length(), 0.0));
949    }
950
951    #[test]
952    fn test_dot() {
953        let v1 = Vec3::new(1.0, 2.0, 3.0);
954        let v2 = Vec3::new(4.0, -5.0, 6.0);
955        // 1*4 + 2*(-5) + 3*6 = 4 - 10 + 18 = 12
956        assert!(approx_eq(v1.dot(v2), 12.0));
957
958        // Orthogonal vectors
959        assert!(approx_eq(Vec3::X.dot(Vec3::Y), 0.0));
960    }
961
962    #[test]
963    fn test_distance() {
964        let v1 = Vec3::new(1.0, 2.0, 3.0);
965        let v2 = Vec3::new(4.0, 5.0, 6.0);
966        // Distance = sqrt((4-1)^2 + (5-2)^2 + (6-3)^2) = sqrt(9 + 9 + 9) = sqrt(27) = 3*sqrt(3)
967        assert!(approx_eq(v1.distance(v2), 3.0 * (3.0_f32).sqrt()));
968    }
969
970    #[test]
971    fn test_cross() {
972        // Standard basis vectors
973        assert_eq!(Vec3::X.cross(Vec3::Y), Vec3::Z);
974        assert_eq!(Vec3::Y.cross(Vec3::Z), Vec3::X);
975        assert_eq!(Vec3::Z.cross(Vec3::X), Vec3::Y);
976
977        // Anti-commutative property
978        assert_eq!(Vec3::Y.cross(Vec3::X), -Vec3::Z);
979
980        // Parallel vectors
981        assert_eq!(Vec3::X.cross(Vec3::X), Vec3::ZERO);
982    }
983
984    #[test]
985    fn test_normalize() {
986        let v1 = Vec3::new(3.0, 0.0, 0.0);
987        let norm_v1 = v1.normalize();
988        assert!(vec3_approx_eq(norm_v1, Vec3::X));
989        assert!(approx_eq(norm_v1.length(), 1.0));
990
991        let v2 = Vec3::new(1.0, 1.0, 1.0);
992        let norm_v2 = v2.normalize();
993        assert!(approx_eq(norm_v2.length(), 1.0)); // Check length is 1
994
995        // Test normalizing zero vector
996        let v_zero = Vec3::ZERO;
997        assert_eq!(v_zero.normalize(), Vec3::ZERO);
998    }
999
1000    #[test]
1001    fn test_lerp() {
1002        let start = Vec3::new(0.0, 0.0, 0.0);
1003        let end = Vec3::new(10.0, 10.0, 10.0);
1004
1005        assert!(vec3_approx_eq(Vec3::lerp(start, end, 0.0), start));
1006        assert!(vec3_approx_eq(Vec3::lerp(start, end, 1.0), end));
1007        assert!(vec3_approx_eq(
1008            Vec3::lerp(start, end, 0.5),
1009            Vec3::new(5.0, 5.0, 5.0)
1010        ));
1011    }
1012
1013    // Test Vec4
1014
1015    #[test]
1016    fn test_vec4_new() {
1017        let v = Vec4::new(1.0, 2.0, 3.0, 4.0);
1018        assert_eq!(v.x, 1.0);
1019        assert_eq!(v.y, 2.0);
1020        assert_eq!(v.z, 3.0);
1021        assert_eq!(v.w, 4.0);
1022    }
1023
1024    #[test]
1025    fn test_vec4_abs() {
1026        let v = Vec4::new(-1.0, 2.0, -3.0, -0.5);
1027        assert_eq!(v.abs(), Vec4::new(1.0, 2.0, 3.0, 0.5));
1028    }
1029
1030    #[test]
1031    fn test_vec4_from_vec3() {
1032        let v3 = Vec3::new(1.0, 2.0, 3.0);
1033        let v4 = Vec4::from_vec3(v3, 4.0);
1034        assert_eq!(v4, Vec4::new(1.0, 2.0, 3.0, 4.0));
1035    }
1036
1037    #[test]
1038    fn test_vec4_truncate() {
1039        let v4 = Vec4::new(1.0, 2.0, 3.0, 4.0);
1040        let v3 = v4.truncate();
1041        assert_eq!(v3, Vec3::new(1.0, 2.0, 3.0));
1042    }
1043}