1use std::fmt;
2use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
3
4use crate::Vec2b;
5
6#[repr(C)]
13#[derive(Clone, Copy, Default, PartialEq)]
14#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
15#[cfg_attr(feature = "bytemuck", derive(bytemuck::Pod, bytemuck::Zeroable))]
16pub struct Vec2 {
17 pub x: f32,
19
20 pub y: f32,
22}
23
24#[inline(always)]
26pub const fn vec2(x: f32, y: f32) -> Vec2 {
27 Vec2 { x, y }
28}
29
30impl From<[f32; 2]> for Vec2 {
34 #[inline(always)]
35 fn from(v: [f32; 2]) -> Self {
36 Self { x: v[0], y: v[1] }
37 }
38}
39
40impl From<&[f32; 2]> for Vec2 {
41 #[inline(always)]
42 fn from(v: &[f32; 2]) -> Self {
43 Self { x: v[0], y: v[1] }
44 }
45}
46
47impl From<Vec2> for [f32; 2] {
48 #[inline(always)]
49 fn from(v: Vec2) -> Self {
50 [v.x, v.y]
51 }
52}
53
54impl From<&Vec2> for [f32; 2] {
55 #[inline(always)]
56 fn from(v: &Vec2) -> Self {
57 [v.x, v.y]
58 }
59}
60
61impl From<(f32, f32)> for Vec2 {
65 #[inline(always)]
66 fn from(v: (f32, f32)) -> Self {
67 Self { x: v.0, y: v.1 }
68 }
69}
70
71impl From<&(f32, f32)> for Vec2 {
72 #[inline(always)]
73 fn from(v: &(f32, f32)) -> Self {
74 Self { x: v.0, y: v.1 }
75 }
76}
77
78impl From<Vec2> for (f32, f32) {
79 #[inline(always)]
80 fn from(v: Vec2) -> Self {
81 (v.x, v.y)
82 }
83}
84
85impl From<&Vec2> for (f32, f32) {
86 #[inline(always)]
87 fn from(v: &Vec2) -> Self {
88 (v.x, v.y)
89 }
90}
91
92impl From<Vec2b> for Vec2 {
93 #[inline(always)]
94 fn from(v: Vec2b) -> Self {
95 Self {
96 x: v.x as i32 as f32,
97 y: v.y as i32 as f32,
98 }
99 }
100}
101
102#[cfg(feature = "mint")]
106impl From<mint::Vector2<f32>> for Vec2 {
107 #[inline]
108 fn from(v: mint::Vector2<f32>) -> Self {
109 Self::new(v.x, v.y)
110 }
111}
112
113#[cfg(feature = "mint")]
114impl From<Vec2> for mint::Vector2<f32> {
115 #[inline]
116 fn from(v: Vec2) -> Self {
117 Self { x: v.x, y: v.y }
118 }
119}
120
121impl Vec2 {
124 pub const X: Self = Self { x: 1.0, y: 0.0 };
126
127 pub const Y: Self = Self { x: 0.0, y: 1.0 };
129
130 pub const RIGHT: Self = Self { x: 1.0, y: 0.0 };
132
133 pub const LEFT: Self = Self { x: -1.0, y: 0.0 };
135
136 pub const UP: Self = Self { x: 0.0, y: -1.0 };
138
139 pub const DOWN: Self = Self { x: 0.0, y: 1.0 };
141
142 pub const ZERO: Self = Self { x: 0.0, y: 0.0 };
143 pub const ONE: Self = Self { x: 1.0, y: 1.0 };
144 pub const INFINITY: Self = Self::splat(f32::INFINITY);
145 pub const NAN: Self = Self::splat(f32::NAN);
146
147 #[inline(always)]
148 pub const fn new(x: f32, y: f32) -> Self {
149 Self { x, y }
150 }
151
152 #[inline(always)]
154 pub const fn splat(v: f32) -> Self {
155 Self { x: v, y: v }
156 }
157
158 #[inline(always)]
161 pub fn to_pos2(self) -> crate::Pos2 {
162 crate::Pos2 {
163 x: self.x,
164 y: self.y,
165 }
166 }
167
168 #[must_use]
170 #[inline(always)]
171 pub fn normalized(self) -> Self {
172 let len = self.length();
173 if len <= 0.0 { self } else { self / len }
174 }
175
176 #[inline(always)]
178 pub fn is_normalized(self) -> bool {
179 (self.length_sq() - 1.0).abs() < 2e-6
180 }
181
182 #[inline(always)]
185 pub fn rot90(self) -> Self {
186 vec2(self.y, -self.x)
187 }
188
189 #[inline(always)]
190 pub fn length(self) -> f32 {
191 self.x.hypot(self.y)
192 }
193
194 #[inline(always)]
195 pub fn length_sq(self) -> f32 {
196 self.x * self.x + self.y * self.y
197 }
198
199 #[inline(always)]
216 pub fn angle(self) -> f32 {
217 self.y.atan2(self.x)
218 }
219
220 #[inline(always)]
232 pub fn angled(angle: f32) -> Self {
233 let (sin, cos) = angle.sin_cos();
234 vec2(cos, sin)
235 }
236
237 #[must_use]
238 #[inline(always)]
239 pub fn floor(self) -> Self {
240 vec2(self.x.floor(), self.y.floor())
241 }
242
243 #[must_use]
244 #[inline(always)]
245 pub fn round(self) -> Self {
246 vec2(self.x.round(), self.y.round())
247 }
248
249 #[must_use]
250 #[inline(always)]
251 pub fn ceil(self) -> Self {
252 vec2(self.x.ceil(), self.y.ceil())
253 }
254
255 #[must_use]
256 #[inline]
257 pub fn abs(self) -> Self {
258 vec2(self.x.abs(), self.y.abs())
259 }
260
261 #[inline(always)]
263 pub fn is_finite(self) -> bool {
264 self.x.is_finite() && self.y.is_finite()
265 }
266
267 #[inline(always)]
269 pub fn any_nan(self) -> bool {
270 self.x.is_nan() || self.y.is_nan()
271 }
272
273 #[must_use]
274 #[inline]
275 pub fn min(self, other: Self) -> Self {
276 vec2(self.x.min(other.x), self.y.min(other.y))
277 }
278
279 #[must_use]
280 #[inline]
281 pub fn max(self, other: Self) -> Self {
282 vec2(self.x.max(other.x), self.y.max(other.y))
283 }
284
285 #[inline]
287 pub fn dot(self, other: Self) -> f32 {
288 self.x * other.x + self.y * other.y
289 }
290
291 #[must_use]
293 #[inline(always)]
294 pub fn min_elem(self) -> f32 {
295 self.x.min(self.y)
296 }
297
298 #[inline(always)]
300 #[must_use]
301 pub fn max_elem(self) -> f32 {
302 self.x.max(self.y)
303 }
304
305 #[inline]
307 #[must_use]
308 pub fn yx(self) -> Self {
309 Self {
310 x: self.y,
311 y: self.x,
312 }
313 }
314
315 #[must_use]
316 #[inline]
317 pub fn clamp(self, min: Self, max: Self) -> Self {
318 Self {
319 x: self.x.clamp(min.x, max.x),
320 y: self.y.clamp(min.y, max.y),
321 }
322 }
323}
324
325impl std::ops::Index<usize> for Vec2 {
326 type Output = f32;
327
328 #[inline(always)]
329 fn index(&self, index: usize) -> &f32 {
330 match index {
331 0 => &self.x,
332 1 => &self.y,
333 _ => panic!("Vec2 index out of bounds: {index}"),
334 }
335 }
336}
337
338impl std::ops::IndexMut<usize> for Vec2 {
339 #[inline(always)]
340 fn index_mut(&mut self, index: usize) -> &mut f32 {
341 match index {
342 0 => &mut self.x,
343 1 => &mut self.y,
344 _ => panic!("Vec2 index out of bounds: {index}"),
345 }
346 }
347}
348
349impl Eq for Vec2 {}
350
351impl Neg for Vec2 {
352 type Output = Self;
353
354 #[inline(always)]
355 fn neg(self) -> Self {
356 vec2(-self.x, -self.y)
357 }
358}
359
360impl AddAssign for Vec2 {
361 #[inline(always)]
362 fn add_assign(&mut self, rhs: Self) {
363 *self = Self {
364 x: self.x + rhs.x,
365 y: self.y + rhs.y,
366 };
367 }
368}
369
370impl SubAssign for Vec2 {
371 #[inline(always)]
372 fn sub_assign(&mut self, rhs: Self) {
373 *self = Self {
374 x: self.x - rhs.x,
375 y: self.y - rhs.y,
376 };
377 }
378}
379
380impl Add for Vec2 {
381 type Output = Self;
382
383 #[inline(always)]
384 fn add(self, rhs: Self) -> Self {
385 Self {
386 x: self.x + rhs.x,
387 y: self.y + rhs.y,
388 }
389 }
390}
391
392impl Sub for Vec2 {
393 type Output = Self;
394
395 #[inline(always)]
396 fn sub(self, rhs: Self) -> Self {
397 Self {
398 x: self.x - rhs.x,
399 y: self.y - rhs.y,
400 }
401 }
402}
403
404impl Mul<Self> for Vec2 {
406 type Output = Self;
407
408 #[inline(always)]
409 fn mul(self, vec: Self) -> Self {
410 Self {
411 x: self.x * vec.x,
412 y: self.y * vec.y,
413 }
414 }
415}
416
417impl Div<Self> for Vec2 {
419 type Output = Self;
420
421 #[inline(always)]
422 fn div(self, rhs: Self) -> Self {
423 Self {
424 x: self.x / rhs.x,
425 y: self.y / rhs.y,
426 }
427 }
428}
429
430impl MulAssign<f32> for Vec2 {
431 #[inline(always)]
432 fn mul_assign(&mut self, rhs: f32) {
433 self.x *= rhs;
434 self.y *= rhs;
435 }
436}
437
438impl DivAssign<f32> for Vec2 {
439 #[inline(always)]
440 fn div_assign(&mut self, rhs: f32) {
441 self.x /= rhs;
442 self.y /= rhs;
443 }
444}
445
446impl Mul<f32> for Vec2 {
447 type Output = Self;
448
449 #[inline(always)]
450 fn mul(self, factor: f32) -> Self {
451 Self {
452 x: self.x * factor,
453 y: self.y * factor,
454 }
455 }
456}
457
458impl Mul<Vec2> for f32 {
459 type Output = Vec2;
460
461 #[inline(always)]
462 fn mul(self, vec: Vec2) -> Vec2 {
463 Vec2 {
464 x: self * vec.x,
465 y: self * vec.y,
466 }
467 }
468}
469
470impl Div<f32> for Vec2 {
471 type Output = Self;
472
473 #[inline(always)]
474 fn div(self, factor: f32) -> Self {
475 Self {
476 x: self.x / factor,
477 y: self.y / factor,
478 }
479 }
480}
481
482impl fmt::Debug for Vec2 {
483 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
484 if let Some(precision) = f.precision() {
485 write!(f, "[{1:.0$} {2:.0$}]", precision, self.x, self.y)
486 } else {
487 write!(f, "[{:.1} {:.1}]", self.x, self.y)
488 }
489 }
490}
491
492impl fmt::Display for Vec2 {
493 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
494 f.write_str("[")?;
495 self.x.fmt(f)?;
496 f.write_str(" ")?;
497 self.y.fmt(f)?;
498 f.write_str("]")?;
499 Ok(())
500 }
501}
502
503#[cfg(test)]
504mod test {
505 use super::*;
506
507 macro_rules! almost_eq {
508 ($left: expr, $right: expr) => {
509 let left = $left;
510 let right = $right;
511 assert!((left - right).abs() < 1e-6, "{} != {}", left, right);
512 };
513 }
514
515 #[test]
516 fn test_vec2() {
517 use std::f32::consts::TAU;
518
519 assert_eq!(Vec2::ZERO.angle(), 0.0);
520 assert_eq!(Vec2::angled(0.0).angle(), 0.0);
521 assert_eq!(Vec2::angled(1.0).angle(), 1.0);
522 assert_eq!(Vec2::X.angle(), 0.0);
523 assert_eq!(Vec2::Y.angle(), 0.25 * TAU);
524
525 assert_eq!(Vec2::RIGHT.angle(), 0.0);
526 assert_eq!(Vec2::DOWN.angle(), 0.25 * TAU);
527 almost_eq!(Vec2::LEFT.angle(), 0.50 * TAU);
528 assert_eq!(Vec2::UP.angle(), -0.25 * TAU);
529
530 let mut assignment = vec2(1.0, 2.0);
531 assignment += vec2(3.0, 4.0);
532 assert_eq!(assignment, vec2(4.0, 6.0));
533
534 let mut assignment = vec2(4.0, 6.0);
535 assignment -= vec2(1.0, 2.0);
536 assert_eq!(assignment, vec2(3.0, 4.0));
537
538 let mut assignment = vec2(1.0, 2.0);
539 assignment *= 2.0;
540 assert_eq!(assignment, vec2(2.0, 4.0));
541
542 let mut assignment = vec2(2.0, 4.0);
543 assignment /= 2.0;
544 assert_eq!(assignment, vec2(1.0, 2.0));
545 }
546
547 #[test]
548 fn test_vec2_normalized() {
549 fn generate_spiral(n: usize, start: Vec2, end: Vec2) -> impl Iterator<Item = Vec2> {
550 let angle_step = 2.0 * std::f32::consts::PI / n as f32;
551 let radius_step = (end.length() - start.length()) / n as f32;
552
553 (0..n).map(move |i| {
554 let angle = i as f32 * angle_step;
555 let radius = start.length() + i as f32 * radius_step;
556 let x = radius * angle.cos();
557 let y = radius * angle.sin();
558 vec2(x, y)
559 })
560 }
561
562 for v in generate_spiral(40, Vec2::splat(0.1), Vec2::splat(2.0)) {
563 let vn = v.normalized();
564 almost_eq!(vn.length(), 1.0);
565 assert!(vn.is_normalized());
566 }
567 }
568}