lighthouse_protocol/utils/
vec2.rs

1use std::{fmt, ops::{Add, AddAssign, Neg, Sub, SubAssign}};
2
3use rand::{thread_rng, Rng};
4use serde::{Deserialize, Serialize};
5
6use super::{Unity, Zero};
7
8/// A 2D vector.
9#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
10pub struct Vec2<T> {
11    pub x: T,
12    pub y: T,
13}
14
15impl<T> Vec2<T> {
16    /// Creates a mew position.
17    pub const fn new(x: T, y: T) -> Self {
18        Self { x, y }
19    }
20
21    /// Maps a function over the vector.
22    pub fn map<U>(self, mut f: impl FnMut(T) -> U) -> Vec2<U> {
23        Vec2 {
24            x: f(self.x),
25            y: f(self.y),
26        }
27    }
28}
29
30impl<T> Zero for Vec2<T> where T: Zero {
31    /// The origin.
32    const ZERO: Self = Self::new(T::ZERO, T::ZERO);
33}
34
35impl<T> Vec2<T> where T: Zero + Unity {
36    /// The vector pointing one pixel to the left.
37    pub const LEFT:  Self = Self::new(T::NEG_ONE, T::ZERO);
38    /// The vector pointing one pixel up.
39    pub const UP:    Self = Self::new(T::ZERO, T::NEG_ONE);
40    /// The vector pointing one pixel to the right.
41    pub const RIGHT: Self = Self::new(T::ONE, T::ZERO);
42    /// The vector pointing one pixel down.
43    pub const DOWN:  Self = Self::new(T::ZERO, T::ONE);
44
45    /// Randomly one of the four cardinal rotations with the given rng.
46    pub fn random_cardinal_with(rng: &mut impl Rng) -> Self {
47        match rng.gen_range(0..4) {
48            0 => Self::LEFT,
49            1 => Self::UP,
50            2 => Self::RIGHT,
51            3 => Self::DOWN,
52            _ => unreachable!(),
53        }
54    }
55
56    /// Randomly one of the four cardinal rotations with the thread-local rng.
57    pub fn random_cardinal() -> Self {
58        Self::random_cardinal_with(&mut thread_rng())
59    }
60}
61
62impl<T> fmt::Display for Vec2<T> where T: fmt::Display {
63    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
64        write!(f, "({}, {})", self.x, self.y)
65    }
66}
67
68impl<T> Add for Vec2<T> where T: Add<Output = T> {
69    type Output = Self;
70
71    fn add(self, rhs: Vec2<T>) -> Self {
72        Self::new(self.x + rhs.x, self.y + rhs.y)
73    }
74}
75
76impl<T> Neg for Vec2<T> where T: Neg<Output = T> {
77    type Output = Self;
78
79    fn neg(self) -> Self {
80        Self::new(-self.x, -self.y)
81    }
82}
83
84impl<T> Sub for Vec2<T> where T: Sub<Output = T> {
85    type Output = Self;
86
87    fn sub(self, rhs: Vec2<T>) -> Self {
88        Self::new(self.x - rhs.x, self.y - rhs.y)
89    }
90}
91
92impl<T> AddAssign<Self> for Vec2<T> where T: AddAssign<T> {
93    fn add_assign(&mut self, rhs: Vec2<T>) {
94        self.x += rhs.x;
95        self.y += rhs.y;
96    }
97}
98
99impl<T> SubAssign<Self> for Vec2<T> where T: SubAssign<T> {
100    fn sub_assign(&mut self, rhs: Vec2<T>) {
101        self.x -= rhs.x;
102        self.y -= rhs.y;
103    }
104}
105
106/// A type alias that semantically expresses a position.
107pub type Pos<T> = Vec2<T>;
108
109/// A type alias that semantically expresses an offset/delta.
110pub type Delta<T> = Vec2<T>;