evian_math/
vec2.rs

1use core::{
2    fmt,
3    ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign},
4};
5use vexide::{devices::math::Point2, float::Float};
6
7/// A vector in 2D cartesian space.
8///
9/// The `Vec2` struct represents a two-dimensional vector with x and y components.
10#[derive(Default, Debug, Clone, Copy, Eq, PartialEq)]
11pub struct Vec2<T> {
12    /// The cartesian x coordinate.
13    pub x: T,
14
15    /// The cartesian y coordinate.
16    pub y: T,
17}
18
19// MARK: Basics
20
21impl<T> Vec2<T> {
22    /// Construct a `Vec2` from cartesian coordinates.
23    pub const fn new(x: T, y: T) -> Self {
24        Self { x, y }
25    }
26
27    /// Sets the vector's x component.
28    pub fn set_x(&mut self, x: T) {
29        self.x = x;
30    }
31
32    /// Sets the vector's y component.
33    pub fn set_y(&mut self, y: T) {
34        self.y = y;
35    }
36}
37
38impl<T: Copy> Vec2<T> {
39    /// Returns the x component of the vector.
40    pub const fn x(&self) -> T {
41        self.x
42    }
43
44    /// Returns the y component of the vector.
45    pub const fn y(&self) -> T {
46        self.y
47    }
48}
49
50impl<T: Float + Copy + Mul<Output = T>> Vec2<T> {
51    /// Construct a `Vec2` from polar coordinates.
52    pub fn from_polar(r: T, theta: T) -> Self {
53        let (sin, cos) = theta.sin_cos();
54
55        Vec2 {
56            x: r * cos,
57            y: r * sin,
58        }
59    }
60}
61
62// MARK: Math
63
64impl<T: Float + Copy> Vec2<T> {
65    /// Returns this vector's angle in radians relative to the origin (0, 0).
66    pub fn angle(&self) -> T {
67        self.y.atan2(self.x)
68    }
69
70    /// Returns this vector's distance (magnitude) from the origin (0, 0).
71    pub fn length(&self) -> T {
72        self.x.hypot(self.y)
73    }
74}
75
76impl<T: Float + Copy + Sub<Output = T>> Vec2<T> {
77    /// Returns the cartesian distance between one vector and another.
78    ///
79    /// This operation is equivalent to `(self - other).length()`.
80    pub fn distance(&self, other: Vec2<T>) -> T {
81        (*self - other).length()
82    }
83}
84
85impl<T: Float + Copy + Div<Output = T>> Vec2<T> {
86    /// Returns the unit (normalized) vector.
87    ///
88    /// This function creates a `Vec2` with a length of 1.0 while retaining the
89    /// angle of its original input.
90    #[must_use]
91    pub fn unit(&self) -> Self {
92        *self / self.length()
93    }
94}
95
96impl<T: Float + Copy + Add<Output = T> + Sub<Output = T> + Mul<Output = T>> Vec2<T> {
97    /// Linearly interpolates between two vectors.
98    #[must_use]
99    pub fn lerp(self, other: Vec2<T>, t: T) -> Vec2<T> {
100        self + ((other - self) * t)
101    }
102
103    /// Creates a new vector with its coordinates rotated by a given angle
104    /// in radians.
105    #[must_use]
106    pub fn rotated(&self, angle: T) -> Self {
107        let (sin, cos) = angle.sin_cos();
108
109        Self {
110            x: self.x * cos - self.y * sin,
111            y: self.x * sin + self.y * cos,
112        }
113    }
114}
115
116impl<T: Float + Copy + Mul<Output = T> + Sub<Output = T>> Vec2<T> {
117    /// Computes the cross product between this vector and another `Vec2`.
118    pub fn cross(&self, other: Vec2<T>) -> T {
119        self.x * other.y - self.y * other.x
120    }
121}
122
123impl<T: Float + Copy + Mul<Output = T> + Add<Output = T>> Vec2<T> {
124    /// Computes the dot product between this vector and another `Vec2`.
125    ///
126    /// The dot product is the sum of the products of each vector's components,
127    /// and represents a measurement of how closely two vectors align with respect
128    /// to angle.
129    pub fn dot(&self, other: Vec2<T>) -> T {
130        self.x * other.x + self.y * other.y
131    }
132}
133
134impl<T: Float + Copy + Mul<Output = T> + Add<Output = T> + Div<Output = T>> Vec2<T> {
135    /// Projects one `Vec2` onto onto another.
136    #[must_use]
137    pub fn projected(&self, onto: Vec2<T>) -> Self {
138        onto * (self.dot(onto) / onto.length().powi(2))
139    }
140}
141
142// MARK: Conversion
143
144impl<T> From<(T, T)> for Vec2<T> {
145    fn from(tuple: (T, T)) -> Self {
146        Self {
147            x: tuple.0,
148            y: tuple.1,
149        }
150    }
151}
152
153impl<T> From<Point2<T>> for Vec2<T> {
154    fn from(value: Point2<T>) -> Self {
155        Self {
156            x: value.x,
157            y: value.y,
158        }
159    }
160}
161
162// MARK: Formatting
163
164impl<T: fmt::Display> fmt::Display for Vec2<T> {
165    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
166        write!(f, "({}, {})", self.x, self.y)
167    }
168}
169
170// MARK: Operators
171
172impl<T: Add<Output = T>> Add for Vec2<T> {
173    type Output = Self;
174
175    /// Performs vector addition.
176    fn add(self, other: Vec2<T>) -> Self {
177        Self {
178            x: self.x + other.x,
179            y: self.y + other.y,
180        }
181    }
182}
183
184impl<T: Sub<Output = T>> Sub for Vec2<T> {
185    type Output = Self;
186
187    /// Performs vector subtraction.
188    fn sub(self, other: Vec2<T>) -> Self {
189        Self {
190            x: self.x - other.x,
191            y: self.y - other.y,
192        }
193    }
194}
195
196impl<T: Mul<Output = T> + Copy> Mul<T> for Vec2<T> {
197    type Output = Self;
198
199    /// Performs scalar multiplication.
200    fn mul(self, scalar: T) -> Self {
201        Self {
202            x: self.x * scalar,
203            y: self.y * scalar,
204        }
205    }
206}
207
208impl<T: Div<Output = T> + Copy> Div<T> for Vec2<T> {
209    type Output = Self;
210
211    /// Performs scalar division.
212    fn div(self, scalar: T) -> Self {
213        Self {
214            x: self.x / scalar,
215            y: self.y / scalar,
216        }
217    }
218}
219
220impl<T: Neg<Output = T>> Neg for Vec2<T> {
221    type Output = Self;
222
223    /// Negates each component of the vector.
224    fn neg(self) -> Self {
225        Self {
226            x: -self.x,
227            y: -self.y,
228        }
229    }
230}
231
232impl<T: AddAssign> AddAssign for Vec2<T> {
233    /// Performs vector add-assignment.
234    fn add_assign(&mut self, other: Vec2<T>) {
235        self.x += other.x;
236        self.y += other.y;
237    }
238}
239
240impl<T: SubAssign> SubAssign for Vec2<T> {
241    /// Performs vector sub-assignment.
242    fn sub_assign(&mut self, other: Vec2<T>) {
243        self.x -= other.x;
244        self.y -= other.y;
245    }
246}
247
248impl<T: MulAssign + Copy> MulAssign<T> for Vec2<T> {
249    /// Performs scalar mul-assignment.
250    fn mul_assign(&mut self, scalar: T) {
251        self.x *= scalar;
252        self.y *= scalar;
253    }
254}
255
256impl<T: DivAssign + Copy> DivAssign<T> for Vec2<T> {
257    /// Performs scalar div-assignment.
258    fn div_assign(&mut self, scalar: T) {
259        self.x /= scalar;
260        self.y /= scalar;
261    }
262}