pax_runtime_api/math/
vector.rs

1use std::{
2    f64::consts::PI,
3    marker::PhantomData,
4    ops::{Add, Div, Mul, Neg, Sub},
5};
6
7use crate::{Interpolatable, Numeric, Rotation};
8
9use super::{Generic, Point2, Space};
10
11pub struct Vector2<W = Generic> {
12    pub x: f64,
13    pub y: f64,
14    _panthom: PhantomData<W>,
15}
16
17// Implement Clone, Copy, PartialEq, etc manually, as
18// to not require the Space to implement these.
19impl<W: Space> Interpolatable for Vector2<W> {}
20
21impl<W: Space> std::fmt::Debug for Vector2<W> {
22    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
23        write!(f, "<{} {}>", self.x, self.y)
24    }
25}
26
27impl<W: Space> Clone for Vector2<W> {
28    fn clone(&self) -> Self {
29        Self {
30            x: self.x,
31            y: self.y,
32            _panthom: PhantomData,
33        }
34    }
35}
36
37impl<W: Space> Copy for Vector2<W> {}
38
39impl<W: Space> PartialEq for Vector2<W> {
40    fn eq(&self, other: &Self) -> bool {
41        self.x == other.x && self.y == other.y
42    }
43}
44
45impl<W: Space> Default for Vector2<W> {
46    fn default() -> Self {
47        Self::new(0.0, 0.0)
48    }
49}
50
51impl<W: Space> Vector2<W> {
52    pub fn new(x: f64, y: f64) -> Self {
53        Self {
54            x,
55            y,
56            _panthom: PhantomData,
57        }
58    }
59
60    pub fn x() -> Self {
61        Self::new(1.0, 0.0)
62    }
63
64    pub fn y() -> Self {
65        Self::new(0.0, 1.0)
66    }
67
68    pub fn normal(&self) -> Self {
69        Self::new(-self.y, self.x)
70    }
71
72    pub fn normalize(self) -> Self {
73        self / self.length()
74    }
75
76    pub fn length_squared(&self) -> f64 {
77        self.x * self.x + self.y * self.y
78    }
79
80    pub fn length(&self) -> f64 {
81        self.length_squared().sqrt()
82    }
83
84    pub fn coord_abs(&self) -> Self {
85        Self::new(self.x.abs(), self.y.abs())
86    }
87
88    pub fn project_onto(self, axis: Self) -> Self {
89        let dot_product = self * axis;
90        axis * dot_product / axis.length_squared()
91    }
92
93    pub fn project_axis_aligned(self, other: Self) -> Self {
94        let v = self.coord_abs();
95        let o = other.coord_abs().normalize();
96        o.to_signums_of(self) * (v.x / o.x).max(v.y / o.y)
97    }
98
99    /// Returns the angle walking from self to other counter clockwise
100    pub fn angle_to(self, other: Self) -> Rotation {
101        let dot = self.x * other.x + self.y * other.y; //Dot product between [x1, y1] and [x2, y2]
102        let det = self.x * other.y - self.y * other.x; //Determinant
103        let angle = det.atan2(dot).rem_euclid(2.0 * PI); //atan2(y, x) or atan2(sin, cos)
104        Rotation::Radians(Numeric::from(angle))
105    }
106
107    /// Returns the magnitude of the cross product as if both vectors had z value 0.0
108    pub fn cross(self, other: Self) -> f64 {
109        self.x * other.y - self.y * other.x
110    }
111
112    pub fn to_signums_of(&self, other: Self) -> Self {
113        Self::new(
114            self.x.abs() * other.x.signum(),
115            self.y.abs() * other.y.signum(),
116        )
117    }
118
119    pub fn to_point(&self) -> Point2<W> {
120        Point2::new(self.x, self.y)
121    }
122
123    pub fn cast_space<WNew: Space>(&self) -> Vector2<WNew> {
124        Vector2::new(self.x, self.y)
125    }
126
127    pub fn rotate(&self, angle: Rotation) -> Self {
128        let (s, c) = angle.get_as_radians().sin_cos();
129        let x = self.x * c - self.y * s;
130        let y = self.x * s + self.y * c;
131        Self::new(x, y)
132    }
133
134    pub fn rotate90(self) -> Self {
135        Self::new(self.y, -self.x)
136    }
137
138    pub fn mult(&self, other: Self) -> Vector2<W> {
139        Vector2::new(self.x * other.x, self.y * other.y)
140    }
141}
142
143impl<W: Space> Mul for Vector2<W> {
144    type Output = f64;
145
146    fn mul(self, rhs: Vector2<W>) -> Self::Output {
147        self.x * rhs.x + self.y * rhs.y
148    }
149}
150
151impl<W: Space> Mul<f64> for Vector2<W> {
152    type Output = Self;
153
154    fn mul(self, rhs: f64) -> Self::Output {
155        Vector2::new(self.x * rhs, self.y * rhs)
156    }
157}
158impl<W: Space> Mul<Vector2<W>> for f64 {
159    type Output = Vector2<W>;
160
161    fn mul(self, rhs: Vector2<W>) -> Self::Output {
162        Vector2::new(rhs.x * self, rhs.y * self)
163    }
164}
165
166impl<W: Space> Add for Vector2<W> {
167    type Output = Vector2<W>;
168
169    fn add(self, rhs: Vector2<W>) -> Self::Output {
170        Self::Output::new(self.x + rhs.x, self.y + rhs.y)
171    }
172}
173
174impl<W: Space> Neg for Vector2<W> {
175    type Output = Vector2<W>;
176
177    fn neg(self) -> Self::Output {
178        Self::Output::new(-self.x, -self.y)
179    }
180}
181
182impl<W: Space> Sub for Vector2<W> {
183    type Output = Vector2<W>;
184    fn sub(self, rhs: Vector2<W>) -> Self::Output {
185        Self::Output::new(self.x - rhs.x, self.y - rhs.y)
186    }
187}
188
189impl<W: Space> Sub<f64> for Vector2<W> {
190    type Output = Vector2<W>;
191    fn sub(self, rhs: f64) -> Self::Output {
192        Self::Output::new(self.x - rhs, self.y - rhs)
193    }
194}
195
196impl<W: Space> Add<f64> for Vector2<W> {
197    type Output = Vector2<W>;
198    fn add(self, rhs: f64) -> Self::Output {
199        Self::Output::new(self.x + rhs, self.y + rhs)
200    }
201}
202
203impl<W: Space> Div<f64> for Vector2<W> {
204    type Output = Vector2<W>;
205    fn div(self, rhs: f64) -> Self::Output {
206        Self::Output::new(self.x / rhs, self.y / rhs)
207    }
208}
209
210impl<W: Space> Div for Vector2<W> {
211    type Output = Vector2<W>;
212    fn div(self, rhs: Vector2<W>) -> Self::Output {
213        Self::Output::new(self.x / rhs.x, self.y / rhs.y)
214    }
215}