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