pax_runtime_api/math/
vector.rs1use 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> {
13 pub x: f64,
15 pub y: f64,
17 _phantom: PhantomData<W>,
18}
19
20impl<W: Space> Interpolatable for Vector2<W> {}
23
24impl<W: Space> std::fmt::Debug for Vector2<W> {
25 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
26 write!(f, "<{} {}>", self.x, self.y)
27 }
28}
29
30impl<W: Space> Clone for Vector2<W> {
31 fn clone(&self) -> Self {
32 Self {
33 x: self.x,
34 y: self.y,
35 _phantom: PhantomData,
36 }
37 }
38}
39
40impl<W: Space> Copy for Vector2<W> {}
41
42impl<W: Space> PartialEq for Vector2<W> {
43 fn eq(&self, other: &Self) -> bool {
44 self.x == other.x && self.y == other.y
45 }
46}
47
48impl<W: Space> Default for Vector2<W> {
49 fn default() -> Self {
50 Self::new(0.0, 0.0)
51 }
52}
53
54impl<W: Space> Vector2<W> {
55 pub fn new(x: f64, y: f64) -> Self {
57 Self {
58 x,
59 y,
60 _phantom: PhantomData,
61 }
62 }
63
64 pub fn x() -> Self {
66 Self::new(1.0, 0.0)
67 }
68
69 pub fn y() -> Self {
71 Self::new(0.0, 1.0)
72 }
73
74 pub fn normal(&self) -> Self {
76 Self::new(-self.y, self.x)
77 }
78
79 pub fn normalize(self) -> Self {
81 self / self.length()
82 }
83
84 pub fn length_squared(&self) -> f64 {
86 self.x * self.x + self.y * self.y
87 }
88
89 pub fn length(&self) -> f64 {
91 self.length_squared().sqrt()
92 }
93
94 pub fn coord_abs(&self) -> Self {
96 Self::new(self.x.abs(), self.y.abs())
97 }
98
99 pub fn project_onto(self, axis: Self) -> Self {
101 let dot_product = self * axis;
102 axis * dot_product / axis.length_squared()
103 }
104
105 pub fn project_axis_aligned(self, other: Self) -> Self {
107 let v = self.coord_abs();
108 let o = other.coord_abs().normalize();
109 o.to_signums_of(self) * (v.x / o.x).max(v.y / o.y)
110 }
111
112 pub fn angle_to(self, other: Self) -> Rotation {
114 let dot = self.x * other.x + self.y * other.y; let det = self.x * other.y - self.y * other.x; let angle = det.atan2(dot).rem_euclid(2.0 * PI); Rotation::Radians(Numeric::from(angle))
118 }
119
120 pub fn cross(self, other: Self) -> f64 {
122 self.x * other.y - self.y * other.x
123 }
124
125 pub fn to_signums_of(&self, other: Self) -> Self {
127 Self::new(
128 self.x.abs() * other.x.signum(),
129 self.y.abs() * other.y.signum(),
130 )
131 }
132
133 pub fn to_point(&self) -> Point2<W> {
135 Point2::new(self.x, self.y)
136 }
137
138 pub fn cast_space<WNew: Space>(&self) -> Vector2<WNew> {
140 Vector2::new(self.x, self.y)
141 }
142
143 pub fn rotate(&self, angle: Rotation) -> Self {
145 let (s, c) = angle.get_as_radians().sin_cos();
146 let x = self.x * c - self.y * s;
147 let y = self.x * s + self.y * c;
148 Self::new(x, y)
149 }
150
151 pub fn rotate90(self) -> Self {
153 Self::new(self.y, -self.x)
154 }
155
156 pub fn mult(&self, other: Self) -> Vector2<W> {
158 Vector2::new(self.x * other.x, self.y * other.y)
159 }
160}
161
162impl<W: Space> Mul for Vector2<W> {
163 type Output = f64;
164
165 fn mul(self, rhs: Vector2<W>) -> Self::Output {
166 self.x * rhs.x + self.y * rhs.y
167 }
168}
169
170impl<W: Space> Mul<f64> for Vector2<W> {
171 type Output = Self;
172
173 fn mul(self, rhs: f64) -> Self::Output {
174 Vector2::new(self.x * rhs, self.y * rhs)
175 }
176}
177impl<W: Space> Mul<Vector2<W>> for f64 {
178 type Output = Vector2<W>;
179
180 fn mul(self, rhs: Vector2<W>) -> Self::Output {
181 Vector2::new(rhs.x * self, rhs.y * self)
182 }
183}
184
185impl<W: Space> Add for Vector2<W> {
186 type Output = Vector2<W>;
187
188 fn add(self, rhs: Vector2<W>) -> Self::Output {
189 Self::Output::new(self.x + rhs.x, self.y + rhs.y)
190 }
191}
192
193impl<W: Space> Neg for Vector2<W> {
194 type Output = Vector2<W>;
195
196 fn neg(self) -> Self::Output {
197 Self::Output::new(-self.x, -self.y)
198 }
199}
200
201impl<W: Space> Sub for Vector2<W> {
202 type Output = Vector2<W>;
203 fn sub(self, rhs: Vector2<W>) -> Self::Output {
204 Self::Output::new(self.x - rhs.x, self.y - rhs.y)
205 }
206}
207
208impl<W: Space> Sub<f64> for Vector2<W> {
209 type Output = Vector2<W>;
210 fn sub(self, rhs: f64) -> Self::Output {
211 Self::Output::new(self.x - rhs, self.y - rhs)
212 }
213}
214
215impl<W: Space> Add<f64> for Vector2<W> {
216 type Output = Vector2<W>;
217 fn add(self, rhs: f64) -> Self::Output {
218 Self::Output::new(self.x + rhs, self.y + rhs)
219 }
220}
221
222impl<W: Space> Div<f64> for Vector2<W> {
223 type Output = Vector2<W>;
224 fn div(self, rhs: f64) -> Self::Output {
225 Self::Output::new(self.x / rhs, self.y / rhs)
226 }
227}
228
229impl<W: Space> Div for Vector2<W> {
230 type Output = Vector2<W>;
231 fn div(self, rhs: Vector2<W>) -> Self::Output {
232 Self::Output::new(self.x / rhs.x, self.y / rhs.y)
233 }
234}