1use crate::{Point, Point2D};
6use core::ops::DivAssign;
7use core::ops::{Add, AddAssign, Mul, MulAssign, Sub, SubAssign};
8use irox_tools::math::Matrix;
9use irox_tools::FloatIsh;
10use irox_units::units::angle::Angle;
11
12pub trait Vector2D<T: FloatIsh>: Default + Copy + Clone + PartialEq + PartialOrd {
13 fn vx(&self) -> T;
14 fn vy(&self) -> T;
15 fn magnitude(&self) -> T;
16 #[must_use]
17 fn normalize(&self) -> Self;
18 fn dot(&self, other: &Self) -> T;
19
20 fn angle(&self, other: &Self) -> Angle;
21 #[must_use]
22 fn perpendicular(&self) -> Self;
23 #[must_use]
24 fn rotate(&self, angle: Angle) -> Self;
25 #[must_use]
26 fn abs(&self) -> Self;
27 fn to_point(&self) -> Point<T>;
28}
29
30#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Default)]
31pub struct Vector<T: FloatIsh> {
32 pub vx: T,
33 pub vy: T,
34}
35impl<T: FloatIsh> Vector<T> {
36 pub fn new(vx: T, vy: T) -> Self {
37 Self { vx, vy }
38 }
39 pub fn splat(v: T) -> Self {
40 Self::new(v, v)
41 }
42 pub fn to_matrix(&self) -> Matrix<2, 1, f64> {
43 Matrix::new([[self.vy.to_f64()], [self.vy.to_f64()]])
44 }
45}
46
47impl<T: FloatIsh> Vector2D<T> for Vector<T> {
48 fn vx(&self) -> T {
49 self.vx
50 }
51
52 fn vy(&self) -> T {
53 self.vy
54 }
55
56 fn magnitude(&self) -> T {
57 (self.vx * self.vx + self.vy * self.vy).sqrt()
58 }
59
60 fn normalize(&self) -> Self {
61 let mag = self.magnitude();
62 Self {
63 vx: self.vx / mag,
64 vy: self.vy / mag,
65 }
66 }
67
68 fn dot(&self, other: &Self) -> T {
69 self.vx * other.vx + self.vy * other.vy
70 }
71
72 fn angle(&self, other: &Self) -> Angle {
73 let rad = self.vy.atan2(self.vx) - other.vy.atan2(other.vx);
74 Angle::new_radians(rad.to_f64())
75 }
76
77 fn perpendicular(&self) -> Self {
78 self.rotate(Angle::new_degrees(90.))
79 }
80
81 fn rotate(&self, angle: Angle) -> Self {
82 let Matrix {
83 values: [[vx], [vy]],
84 } = Matrix::<2, 2, _>::rotation_counterclockwise(angle.as_radians().value())
85 .mul(self.to_matrix());
86 Self {
87 vx: T::from_f64(vx),
88 vy: T::from_f64(vy),
89 }
90 }
91
92 fn abs(&self) -> Self {
93 Self {
94 vx: self.vx.abs(),
95 vy: self.vy.abs(),
96 }
97 }
98 fn to_point(&self) -> Point<T> {
99 Point::new_point(self.vx, self.vy)
100 }
101}
102
103impl<T: FloatIsh> Add for Vector<T> {
104 type Output = Self;
105
106 fn add(self, rhs: Self) -> Self::Output {
107 Self {
108 vx: self.vx + rhs.vx,
109 vy: self.vy + rhs.vy,
110 }
111 }
112}
113impl<T: FloatIsh> AddAssign for Vector<T> {
114 fn add_assign(&mut self, rhs: Self) {
115 self.vx += rhs.vx;
116 self.vy += rhs.vy;
117 }
118}
119impl<T: FloatIsh> Mul<T> for Vector<T> {
120 type Output = Self;
121
122 fn mul(self, rhs: T) -> Self::Output {
123 Self {
124 vx: self.vx * rhs,
125 vy: self.vy * rhs,
126 }
127 }
128}
129impl<T: FloatIsh> MulAssign<T> for Vector<T> {
130 fn mul_assign(&mut self, rhs: T) {
131 self.vx *= rhs;
132 self.vy *= rhs;
133 }
134}
135impl<T: FloatIsh> Sub for Vector<T> {
136 type Output = Self;
137
138 fn sub(self, rhs: Self) -> Self::Output {
139 Self {
140 vx: self.vx - rhs.vx,
141 vy: self.vy - rhs.vy,
142 }
143 }
144}
145impl<T: FloatIsh> SubAssign for Vector<T> {
146 fn sub_assign(&mut self, rhs: Self) {
147 self.vx -= rhs.vx;
148 self.vy -= rhs.vy;
149 }
150}
151impl<T: FloatIsh> DivAssign<T> for Vector<T> {
152 fn div_assign(&mut self, rhs: T) {
153 self.vx /= rhs;
154 self.vy /= rhs;
155 }
156}