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> {
12 pub x: f64,
13 pub y: f64,
14 _panthom: PhantomData<W>,
15}
16
17impl<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 pub fn angle_to(self, other: Self) -> Rotation {
101 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))
105 }
106
107 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}