Skip to main content

spatialrust_math/
vec.rs

1use crate::{Real, Scalar};
2
3/// 2D vector.
4#[derive(Clone, Copy, Debug, Default, PartialEq)]
5#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
6pub struct Vec2<T: Scalar> {
7    /// X component.
8    pub x: T,
9    /// Y component.
10    pub y: T,
11}
12
13/// 3D vector.
14#[derive(Clone, Copy, Debug, Default, PartialEq)]
15#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
16pub struct Vec3<T: Scalar> {
17    /// X component.
18    pub x: T,
19    /// Y component.
20    pub y: T,
21    /// Z component.
22    pub z: T,
23}
24
25/// 4D vector.
26#[derive(Clone, Copy, Debug, Default, PartialEq)]
27#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
28pub struct Vec4<T: Scalar> {
29    /// X component.
30    pub x: T,
31    /// Y component.
32    pub y: T,
33    /// Z component.
34    pub z: T,
35    /// W component.
36    pub w: T,
37}
38
39impl<T: Scalar> Vec3<T> {
40    /// Creates a new 3D vector.
41    #[must_use]
42    pub const fn new(x: T, y: T, z: T) -> Self {
43        Self { x, y, z }
44    }
45}
46
47impl<T: Scalar> core::ops::Add for Vec3<T> {
48    type Output = Self;
49
50    fn add(self, rhs: Self) -> Self::Output {
51        Self::new(self.x + rhs.x, self.y + rhs.y, self.z + rhs.z)
52    }
53}
54
55impl<T: Scalar> core::ops::Sub for Vec3<T> {
56    type Output = Self;
57
58    fn sub(self, rhs: Self) -> Self::Output {
59        Self::new(self.x - rhs.x, self.y - rhs.y, self.z - rhs.z)
60    }
61}
62
63impl<T: Real> Vec3<T> {
64    /// Dot product.
65    #[must_use]
66    pub fn dot(self, other: Self) -> T {
67        self.x * other.x + self.y * other.y + self.z * other.z
68    }
69
70    /// Cross product.
71    #[must_use]
72    pub fn cross(self, other: Self) -> Self {
73        Self {
74            x: self.y * other.z - self.z * other.y,
75            y: self.z * other.x - self.x * other.z,
76            z: self.x * other.y - self.y * other.x,
77        }
78    }
79
80    /// Squared Euclidean length.
81    #[must_use]
82    pub fn length_squared(self) -> T {
83        self.dot(self)
84    }
85
86    /// Euclidean length.
87    #[must_use]
88    pub fn length(self) -> T {
89        self.length_squared().sqrt()
90    }
91
92    /// Returns a unit vector when length is non-zero.
93    #[must_use]
94    pub fn normalize(self) -> Self {
95        let len = self.length();
96        if len == T::default() {
97            return self;
98        }
99        Self { x: self.x / len, y: self.y / len, z: self.z / len }
100    }
101}
102
103#[cfg(test)]
104mod tests {
105    use super::Vec3;
106
107    #[test]
108    fn vec3_dot_and_cross() {
109        let a = Vec3::new(1.0_f32, 0.0, 0.0);
110        let b = Vec3::new(0.0, 1.0, 0.0);
111        assert_eq!(a.dot(b), 0.0);
112        assert_eq!(a.cross(b), Vec3::new(0.0, 0.0, 1.0));
113    }
114
115    #[test]
116    fn vec3_normalize() {
117        let v = Vec3::new(3.0_f32, 0.0, 4.0);
118        let n = v.normalize();
119        assert!((n.length() - 1.0).abs() < 1e-6);
120    }
121}