1use core::ops::{Add, Div, Mul, Neg, Sub};
7
8#[derive(Debug, Clone, Copy, PartialEq)]
13#[non_exhaustive]
14pub struct Vec2 {
15 pub x: f64,
16 pub y: f64,
17}
18
19impl Vec2 {
20 pub const ZERO: Self = Self { x: 0.0, y: 0.0 };
21 pub const ONE: Self = Self { x: 1.0, y: 1.0 };
22
23 pub const fn new(x: f64, y: f64) -> Self {
24 Self { x, y }
25 }
26
27 pub fn dot(self, rhs: Self) -> f64 {
28 self.x * rhs.x + self.y * rhs.y
29 }
30
31 pub fn cross(self, rhs: Self) -> f64 {
33 self.x * rhs.y - self.y * rhs.x
34 }
35
36 pub fn length_sq(self) -> f64 {
37 self.dot(self)
38 }
39
40 pub fn length(self) -> f64 {
41 self.length_sq().sqrt()
42 }
43
44 pub fn normalize(self) -> Self {
45 let len = self.length();
46 if len < f64::EPSILON {
47 Self::ZERO
48 } else {
49 self * (1.0 / len)
50 }
51 }
52
53 pub fn perp(self) -> Self {
55 Self::new(-self.y, self.x)
56 }
57
58 pub fn lerp(self, other: Self, t: f64) -> Self {
59 Self::new(
60 self.x + (other.x - self.x) * t,
61 self.y + (other.y - self.y) * t,
62 )
63 }
64}
65
66impl Add for Vec2 {
67 type Output = Self;
68 fn add(self, rhs: Self) -> Self {
69 Self::new(self.x + rhs.x, self.y + rhs.y)
70 }
71}
72
73impl Sub for Vec2 {
74 type Output = Self;
75 fn sub(self, rhs: Self) -> Self {
76 Self::new(self.x - rhs.x, self.y - rhs.y)
77 }
78}
79
80impl Mul<f64> for Vec2 {
81 type Output = Self;
82 fn mul(self, s: f64) -> Self {
83 Self::new(self.x * s, self.y * s)
84 }
85}
86
87impl Mul<Vec2> for f64 {
88 type Output = Vec2;
89 fn mul(self, v: Vec2) -> Vec2 {
90 Vec2::new(self * v.x, self * v.y)
91 }
92}
93
94impl Neg for Vec2 {
95 type Output = Self;
96 fn neg(self) -> Self {
97 Self::new(-self.x, -self.y)
98 }
99}
100
101#[derive(Debug, Clone, Copy, PartialEq)]
106#[non_exhaustive]
107pub struct Vec3 {
108 pub x: f64,
109 pub y: f64,
110 pub z: f64,
111}
112
113impl Vec3 {
114 pub const ZERO: Self = Self {
115 x: 0.0,
116 y: 0.0,
117 z: 0.0,
118 };
119 pub const ONE: Self = Self {
120 x: 1.0,
121 y: 1.0,
122 z: 1.0,
123 };
124 pub const X: Self = Self {
125 x: 1.0,
126 y: 0.0,
127 z: 0.0,
128 };
129 pub const Y: Self = Self {
130 x: 0.0,
131 y: 1.0,
132 z: 0.0,
133 };
134 pub const Z: Self = Self {
135 x: 0.0,
136 y: 0.0,
137 z: 1.0,
138 };
139
140 pub const fn new(x: f64, y: f64, z: f64) -> Self {
141 Self { x, y, z }
142 }
143
144 pub fn from_vec2(v: Vec2, z: f64) -> Self {
145 Self::new(v.x, v.y, z)
146 }
147
148 pub fn xy(self) -> Vec2 {
149 Vec2::new(self.x, self.y)
150 }
151
152 pub fn dot(self, rhs: Self) -> f64 {
153 self.x * rhs.x + self.y * rhs.y + self.z * rhs.z
154 }
155
156 pub fn cross(self, rhs: Self) -> Self {
157 Self::new(
158 self.y * rhs.z - self.z * rhs.y,
159 self.z * rhs.x - self.x * rhs.z,
160 self.x * rhs.y - self.y * rhs.x,
161 )
162 }
163
164 pub fn length_sq(self) -> f64 {
165 self.dot(self)
166 }
167
168 pub fn length(self) -> f64 {
169 self.length_sq().sqrt()
170 }
171
172 pub fn normalize(self) -> Self {
173 let len = self.length();
174 if len < f64::EPSILON {
175 Self::ZERO
176 } else {
177 self * (1.0 / len)
178 }
179 }
180
181 pub fn lerp(self, other: Self, t: f64) -> Self {
182 Self::new(
183 self.x + (other.x - self.x) * t,
184 self.y + (other.y - self.y) * t,
185 self.z + (other.z - self.z) * t,
186 )
187 }
188}
189
190impl Add for Vec3 {
191 type Output = Self;
192 fn add(self, rhs: Self) -> Self {
193 Self::new(self.x + rhs.x, self.y + rhs.y, self.z + rhs.z)
194 }
195}
196
197impl Sub for Vec3 {
198 type Output = Self;
199 fn sub(self, rhs: Self) -> Self {
200 Self::new(self.x - rhs.x, self.y - rhs.y, self.z - rhs.z)
201 }
202}
203
204impl Mul<f64> for Vec3 {
205 type Output = Self;
206 fn mul(self, s: f64) -> Self {
207 Self::new(self.x * s, self.y * s, self.z * s)
208 }
209}
210
211impl Mul<Vec3> for f64 {
212 type Output = Vec3;
213 fn mul(self, v: Vec3) -> Vec3 {
214 Vec3::new(self * v.x, self * v.y, self * v.z)
215 }
216}
217
218impl Neg for Vec3 {
219 type Output = Self;
220 fn neg(self) -> Self {
221 Self::new(-self.x, -self.y, -self.z)
222 }
223}
224
225#[derive(Debug, Clone, Copy, PartialEq)]
230#[non_exhaustive]
231pub struct Vec4 {
232 pub x: f64,
233 pub y: f64,
234 pub z: f64,
235 pub w: f64,
236}
237
238impl Vec4 {
239 pub const ZERO: Self = Self {
240 x: 0.0,
241 y: 0.0,
242 z: 0.0,
243 w: 0.0,
244 };
245
246 pub const fn new(x: f64, y: f64, z: f64, w: f64) -> Self {
247 Self { x, y, z, w }
248 }
249
250 pub fn point(x: f64, y: f64, z: f64) -> Self {
252 Self::new(x, y, z, 1.0)
253 }
254
255 pub fn direction(x: f64, y: f64, z: f64) -> Self {
257 Self::new(x, y, z, 0.0)
258 }
259
260 pub fn from_vec3(v: Vec3, w: f64) -> Self {
261 Self::new(v.x, v.y, v.z, w)
262 }
263
264 pub fn to_vec3(self) -> Vec3 {
266 if self.w.abs() < f64::EPSILON {
267 Vec3::new(self.x, self.y, self.z)
268 } else {
269 Vec3::new(self.x / self.w, self.y / self.w, self.z / self.w)
270 }
271 }
272
273 pub fn xyz(self) -> Vec3 {
274 Vec3::new(self.x, self.y, self.z)
275 }
276
277 pub fn dot(self, rhs: Self) -> f64 {
278 self.x * rhs.x + self.y * rhs.y + self.z * rhs.z + self.w * rhs.w
279 }
280}
281
282impl Add for Vec4 {
283 type Output = Self;
284 fn add(self, rhs: Self) -> Self {
285 Self::new(
286 self.x + rhs.x,
287 self.y + rhs.y,
288 self.z + rhs.z,
289 self.w + rhs.w,
290 )
291 }
292}
293
294impl Sub for Vec4 {
295 type Output = Self;
296 fn sub(self, rhs: Self) -> Self {
297 Self::new(
298 self.x - rhs.x,
299 self.y - rhs.y,
300 self.z - rhs.z,
301 self.w - rhs.w,
302 )
303 }
304}
305
306impl Mul<f64> for Vec4 {
307 type Output = Self;
308 fn mul(self, s: f64) -> Self {
309 Self::new(self.x * s, self.y * s, self.z * s, self.w * s)
310 }
311}
312
313impl Div<f64> for Vec4 {
314 type Output = Self;
315 fn div(self, s: f64) -> Self {
316 Self::new(self.x / s, self.y / s, self.z / s, self.w / s)
317 }
318}
319
320#[cfg(test)]
325mod tests {
326 use super::*;
327
328 #[test]
329 fn vec2_basic_ops() {
330 let a = Vec2::new(3.0, 4.0);
331 let b = Vec2::new(1.0, 2.0);
332 let sum = a + b;
333 assert!((sum.x - 4.0).abs() < f64::EPSILON);
334 assert!((sum.y - 6.0).abs() < f64::EPSILON);
335 }
336
337 #[test]
338 fn vec2_length() {
339 let v = Vec2::new(3.0, 4.0);
340 assert!((v.length() - 5.0).abs() < 1e-10);
341 }
342
343 #[test]
344 fn vec2_normalize() {
345 let v = Vec2::new(3.0, 4.0).normalize();
346 assert!((v.length() - 1.0).abs() < 1e-10);
347 }
348
349 #[test]
350 fn vec2_cross() {
351 let a = Vec2::new(1.0, 0.0);
352 let b = Vec2::new(0.0, 1.0);
353 assert!((a.cross(b) - 1.0).abs() < f64::EPSILON);
354 }
355
356 #[test]
357 fn vec2_perp() {
358 let v = Vec2::new(1.0, 0.0);
359 let p = v.perp();
360 assert!((p.x - 0.0).abs() < f64::EPSILON);
361 assert!((p.y - 1.0).abs() < f64::EPSILON);
362 }
363
364 #[test]
365 fn vec3_cross_product() {
366 let x = Vec3::X;
367 let y = Vec3::Y;
368 let z = x.cross(y);
369 assert!((z.x - 0.0).abs() < f64::EPSILON);
370 assert!((z.y - 0.0).abs() < f64::EPSILON);
371 assert!((z.z - 1.0).abs() < f64::EPSILON);
372 }
373
374 #[test]
375 fn vec3_dot() {
376 let a = Vec3::new(1.0, 2.0, 3.0);
377 let b = Vec3::new(4.0, 5.0, 6.0);
378 assert!((a.dot(b) - 32.0).abs() < f64::EPSILON);
379 }
380
381 #[test]
382 fn vec4_perspective_divide() {
383 let v = Vec4::new(4.0, 6.0, 8.0, 2.0);
384 let p = v.to_vec3();
385 assert!((p.x - 2.0).abs() < f64::EPSILON);
386 assert!((p.y - 3.0).abs() < f64::EPSILON);
387 assert!((p.z - 4.0).abs() < f64::EPSILON);
388 }
389
390 #[test]
391 fn vec2_lerp() {
392 let a = Vec2::new(0.0, 0.0);
393 let b = Vec2::new(10.0, 10.0);
394 let mid = a.lerp(b, 0.5);
395 assert!((mid.x - 5.0).abs() < f64::EPSILON);
396 assert!((mid.y - 5.0).abs() < f64::EPSILON);
397 }
398
399 #[test]
400 fn vec3_normalize_zero() {
401 let v = Vec3::ZERO.normalize();
402 assert!((v.length()).abs() < f64::EPSILON);
403 }
404}