1use std::fmt;
4use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
5
6use crate::EPS;
7
8#[derive(Clone, Copy, PartialEq)]
14#[repr(C)]
15pub struct Vec3 {
16 pub x: f64,
18 pub y: f64,
20 pub z: f64,
22}
23
24impl Vec3 {
25 pub const ZERO: Self = Self {
27 x: 0.0,
28 y: 0.0,
29 z: 0.0,
30 };
31 pub const X: Self = Self {
33 x: 1.0,
34 y: 0.0,
35 z: 0.0,
36 };
37 pub const Y: Self = Self {
39 x: 0.0,
40 y: 1.0,
41 z: 0.0,
42 };
43 pub const Z: Self = Self {
45 x: 0.0,
46 y: 0.0,
47 z: 1.0,
48 };
49
50 #[inline]
52 pub const fn new(x: f64, y: f64, z: f64) -> Self {
53 Self { x, y, z }
54 }
55
56 #[inline]
58 pub fn length_sq(self) -> f64 {
59 self.dot(self)
60 }
61
62 #[inline]
64 pub fn length(self) -> f64 {
65 self.length_sq().sqrt()
66 }
67
68 #[inline]
70 pub fn dot(self, rhs: Self) -> f64 {
71 self.x * rhs.x + self.y * rhs.y + self.z * rhs.z
72 }
73
74 #[inline]
76 pub fn cross(self, rhs: Self) -> Self {
77 Self {
78 x: self.y * rhs.z - self.z * rhs.y,
79 y: self.z * rhs.x - self.x * rhs.z,
80 z: self.x * rhs.y - self.y * rhs.x,
81 }
82 }
83
84 #[inline]
86 pub fn try_normalize(self) -> Option<Self> {
87 let len = self.length();
88 if len < EPS {
89 None
90 } else {
91 Some(self / len)
92 }
93 }
94
95 #[inline]
97 pub fn normalize(self) -> Self {
98 self.try_normalize()
99 .expect("Vec3::normalize called on zero vector")
100 }
101
102 #[inline]
104 pub fn abs(self) -> Self {
105 Self::new(self.x.abs(), self.y.abs(), self.z.abs())
106 }
107
108 #[inline]
110 pub fn reflect(self, n: Self) -> Self {
111 self - n * (2.0 * self.dot(n))
112 }
113
114 pub fn any_perp(self) -> Self {
116 if self.x.abs() <= self.y.abs() && self.x.abs() <= self.z.abs() {
119 self.cross(Self::X)
120 } else if self.y.abs() <= self.z.abs() {
121 self.cross(Self::Y)
122 } else {
123 self.cross(Self::Z)
124 }
125 }
126
127 #[inline]
129 pub fn lerp(self, rhs: Self, t: f64) -> Self {
130 self + (rhs - self) * t
131 }
132}
133
134impl Add for Vec3 {
137 type Output = Self;
138 #[inline]
139 fn add(self, r: Self) -> Self {
140 Self::new(self.x + r.x, self.y + r.y, self.z + r.z)
141 }
142}
143impl Sub for Vec3 {
144 type Output = Self;
145 #[inline]
146 fn sub(self, r: Self) -> Self {
147 Self::new(self.x - r.x, self.y - r.y, self.z - r.z)
148 }
149}
150impl Neg for Vec3 {
151 type Output = Self;
152 #[inline]
153 fn neg(self) -> Self {
154 Self::new(-self.x, -self.y, -self.z)
155 }
156}
157impl Mul<f64> for Vec3 {
158 type Output = Self;
159 #[inline]
160 fn mul(self, s: f64) -> Self {
161 Self::new(self.x * s, self.y * s, self.z * s)
162 }
163}
164impl Mul<Vec3> for f64 {
165 type Output = Vec3;
166 #[inline]
167 fn mul(self, v: Vec3) -> Vec3 {
168 v * self
169 }
170}
171impl Div<f64> for Vec3 {
172 type Output = Self;
173 #[inline]
174 fn div(self, s: f64) -> Self {
175 self * (1.0 / s)
176 }
177}
178
179impl AddAssign for Vec3 {
180 #[inline]
181 fn add_assign(&mut self, r: Self) {
182 *self = *self + r;
183 }
184}
185impl SubAssign for Vec3 {
186 #[inline]
187 fn sub_assign(&mut self, r: Self) {
188 *self = *self - r;
189 }
190}
191impl MulAssign<f64> for Vec3 {
192 #[inline]
193 fn mul_assign(&mut self, s: f64) {
194 *self = *self * s;
195 }
196}
197impl DivAssign<f64> for Vec3 {
198 #[inline]
199 fn div_assign(&mut self, s: f64) {
200 *self = *self / s;
201 }
202}
203
204impl fmt::Debug for Vec3 {
205 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
206 write!(f, "Vec3({:.6}, {:.6}, {:.6})", self.x, self.y, self.z)
207 }
208}
209impl fmt::Display for Vec3 {
210 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
211 write!(f, "({:.4}, {:.4}, {:.4})", self.x, self.y, self.z)
212 }
213}
214
215#[cfg(test)]
216mod tests {
217 use super::*;
218
219 #[test]
220 fn cross_product() {
221 let x = Vec3::X;
222 let y = Vec3::Y;
223 let z = x.cross(y);
224 assert!((z - Vec3::Z).length() < 1e-12);
225 }
226
227 #[test]
228 fn normalize_unit_length() {
229 let v = Vec3::new(3.0, 4.0, 0.0).normalize();
230 assert!((v.length() - 1.0).abs() < 1e-12);
231 }
232
233 #[test]
234 fn reflect() {
235 let v = Vec3::new(1.0, -1.0, 0.0);
236 let n = Vec3::Y;
237 let r = v.reflect(n);
238 assert!((r - Vec3::new(1.0, 1.0, 0.0)).length() < 1e-12);
239 }
240}