honeycomb_core/geometry/dim2/
vector.rs1use crate::geometry::{CoordsError, CoordsFloat};
6
7#[derive(Debug, Clone, Copy, Default, PartialEq)]
35pub struct Vector2<T: CoordsFloat>(pub T, pub T);
36
37unsafe impl<T: CoordsFloat> Send for Vector2<T> {}
38unsafe impl<T: CoordsFloat> Sync for Vector2<T> {}
39
40impl<T: CoordsFloat> Vector2<T> {
41 #[must_use = "unused return value"]
43 pub fn unit_x() -> Self {
44 Self(T::one(), T::zero())
45 }
46
47 #[must_use = "unused return value"]
49 pub fn unit_y() -> Self {
50 Self(T::zero(), T::one())
51 }
52
53 pub fn into_inner(self) -> (T, T) {
55 (self.0, self.1)
56 }
57
58 pub fn to_f32(self) -> Option<Vector2<f32>> {
60 match (self.0.to_f32(), self.1.to_f32()) {
61 (Some(x), Some(y)) => Some(Vector2(x, y)),
62 _ => None,
63 }
64 }
65
66 pub fn to_f64(self) -> Option<Vector2<f64>> {
68 match (self.0.to_f64(), self.1.to_f64()) {
69 (Some(x), Some(y)) => Some(Vector2(x, y)),
70 _ => None,
71 }
72 }
73
74 pub fn x(&self) -> T {
76 self.0
77 }
78
79 pub fn y(&self) -> T {
81 self.1
82 }
83
84 pub fn norm(&self) -> T {
86 self.0.hypot(self.1)
87 }
88
89 pub fn unit_dir(&self) -> Result<Self, CoordsError> {
95 let norm = self.norm();
96 if norm.is_zero() {
97 Err(CoordsError::InvalidUnitDir)
98 } else {
99 Ok(*self / norm)
100 }
101 }
102
103 pub fn normal_dir(&self) -> Result<Vector2<T>, CoordsError> {
109 Self(-self.1, self.0)
110 .unit_dir() .map_err(|_| CoordsError::InvalidNormDir)
112 }
113
114 pub fn dot(&self, other: &Vector2<T>) -> T {
116 self.0 * other.0 + self.1 * other.1
117 }
118}
119
120impl<T: CoordsFloat> From<(T, T)> for Vector2<T> {
123 fn from((x, y): (T, T)) -> Self {
124 Self(x, y)
125 }
126}
127
128impl<T: CoordsFloat> std::ops::Add<Vector2<T>> for Vector2<T> {
131 type Output = Self;
132
133 fn add(self, rhs: Vector2<T>) -> Self::Output {
134 Self(self.0 + rhs.0, self.1 + rhs.1)
135 }
136}
137
138impl<T: CoordsFloat> std::ops::AddAssign<Vector2<T>> for Vector2<T> {
139 fn add_assign(&mut self, rhs: Vector2<T>) {
140 self.0 += rhs.0;
141 self.1 += rhs.1;
142 }
143}
144
145impl<T: CoordsFloat> std::ops::Sub<Vector2<T>> for Vector2<T> {
146 type Output = Self;
147
148 fn sub(self, rhs: Vector2<T>) -> Self::Output {
149 Self(self.0 - rhs.0, self.1 - rhs.1)
150 }
151}
152
153impl<T: CoordsFloat> std::ops::SubAssign<Vector2<T>> for Vector2<T> {
154 fn sub_assign(&mut self, rhs: Vector2<T>) {
155 self.0 -= rhs.0;
156 self.0 -= rhs.0;
157 }
158}
159
160impl<T: CoordsFloat> std::ops::Mul<T> for Vector2<T> {
161 type Output = Self;
162
163 fn mul(self, rhs: T) -> Self::Output {
164 Self(self.0 * rhs, self.1 * rhs)
165 }
166}
167
168impl<T: CoordsFloat> std::ops::MulAssign<T> for Vector2<T> {
169 fn mul_assign(&mut self, rhs: T) {
170 self.0 *= rhs;
171 self.1 *= rhs;
172 }
173}
174
175impl<T: CoordsFloat> std::ops::Div<T> for Vector2<T> {
176 type Output = Self;
177
178 fn div(self, rhs: T) -> Self::Output {
179 assert!(!rhs.is_zero());
180 Self(self.0 / rhs, self.1 / rhs)
181 }
182}
183
184impl<T: CoordsFloat> std::ops::DivAssign<T> for Vector2<T> {
185 fn div_assign(&mut self, rhs: T) {
186 assert!(!rhs.is_zero());
187 self.0 /= rhs;
188 self.1 /= rhs;
189 }
190}
191
192impl<T: CoordsFloat> std::ops::Neg for Vector2<T> {
193 type Output = Self;
194
195 fn neg(self) -> Self::Output {
196 Self(-self.0, -self.1)
197 }
198}