rustbatch/math/
vect.rs

1use std::ops;
2
3/// Vect is 2D vector and is used all over the place. I choose to use f32 because
4/// opengl also accepts only f32
5#[derive(Copy, Clone, Debug, PartialEq)]
6pub struct Vect{
7    pub x: f32,
8    pub y: f32,
9}
10
11impl Vect {
12    pub const ZERO: Self = Self { x: 0f32, y: 0f32 };
13    pub const LEFT: Self = Self { x: -1f32, y: 0f32 };
14    pub const RIGHT: Self = Self { x: 1f32, y: 0f32 };
15    pub const UP: Self = Self { x: 0f32, y: 1f32 };
16    pub const DOWN: Self = Self { x: 0f32, y: -1f32 };
17    pub const MAX: Self = Self { x: f32::MAX, y: f32::MAX };
18    pub const MIN: Self = Self { x: f32::MIN, y: f32::MIN };
19
20    /// average returns average of slice of vectors
21    #[inline]
22    pub fn average(arr: &[Vect]) -> Self {
23        let len = arr.len();
24        if len == 0 {
25            return Self::ZERO;
26        }
27
28        let mut total = Self::ZERO;
29        for vec in arr {
30            total += *vec
31        }
32
33        total / len as f32
34    }
35
36    /// new is vector constructor
37    #[inline]
38    pub fn new(x: f32, y: f32) -> Self {
39        Self { x, y }
40    }
41
42    /// mirror returns homogenous vector
43    #[inline]
44    pub fn mirror(m: f32) -> Self {
45        Self { x: m, y: m }
46    }
47
48    /// unit returns vector of length 1.0 with given angle
49    #[inline]
50    pub fn unit(a: f32) -> Self {
51        Self { x: a.cos(), y: a.sin() }
52    }
53
54    /// rad is same as unit but you can also specify length
55    #[inline]
56    pub fn rad(a: f32, l: f32) -> Self {
57        Self::unit(a) * l
58    }
59
60    /// clamped clamps a vectors length
61    #[inline]
62    pub fn clamped(&self, min: f32, max: f32) -> Self {
63        Self::rad(self.ang(), clamp!(self.len(), min, max))
64    }
65
66    pub fn lerp(self, o: Vect, t: f32) -> Vect {
67        o * t + self * (1.0 - t)
68    }
69
70    /// ang returns vectors angle
71    #[inline]
72    pub fn ang(&self) -> f32 {
73        self.y.atan2(self.x)
74    }
75
76    /// len returns vectors length
77    #[inline]
78    pub fn len(&self) -> f32 {
79        self.x.hypot(self.y)
80    }
81
82    /// norm returns normalized vector with length 1.0
83    #[inline]
84    pub fn norm(self) -> Self {
85        let len = self.len();
86        if len == 0f32 {
87            return Self::ZERO
88        }
89        self / len
90    }
91
92    /// normal on the other hand returns normal vector to vector of same length
93    #[inline]
94    pub fn normal(&self) -> Self {
95        Self {
96            x: self.y,
97            y: -self.x,
98        }
99    }
100
101    /// swp swaps x and y of vector
102    #[inline]
103    pub fn swp(self) -> Self {
104        Self { x: self.y, y: self.x }
105    }
106
107    /// rot rotates vector by a
108    #[inline]
109    pub fn rot(self, a: f32) -> Self {
110        Self::rad(self.ang() + a, self.len())
111    }
112
113    /// dist returns distance to other vector
114    #[inline]
115    pub fn dist(self, b: Self) -> f32 {
116        (self - b).len()
117    }
118
119    /// to returns vector from self to b
120    #[inline]
121    pub fn to(self, b: Self) -> Self {
122        b - self
123    }
124
125    /// dot returns vectors dot
126    #[inline]
127    pub fn dot(self, b: Self) -> f32 {
128        self.x * b.x + self.y * b.y
129    }
130
131    /// ang_to returns smallest angle between two vectors
132    #[inline]
133    pub fn ang_to(self, b: Self) -> f32 {
134        let r = self.norm().dot(b.norm()).acos();
135        if r.is_nan() { 0.0 } else { r }
136    }
137
138    /// trn applies closure to both x and y of a vector
139    #[inline]
140    pub fn trn<T: Fn(f32) -> f32>(&self, tr: T) -> Self {
141        Self { x: tr(self.x), y: tr(self.y) }
142    }
143
144    /// inverted inverts vector
145    #[inline]
146    pub fn inverted(&self) -> Self {
147        Self { x: -self.x, y: -self.y }
148    }
149
150    /// round rounds a vector
151    #[inline]
152    pub fn round(&self) -> Self {
153        Self { x: self.x.round(), y: self.y.round() }
154    }
155}
156
157impl ops::Add<Vect> for Vect {
158    type Output = Vect;
159    #[inline]
160    fn add(self, rhs: Vect) -> Self::Output {
161        Self::new(self.x + rhs.x, self.y + rhs.y)
162    }
163}
164
165impl ops::AddAssign<Vect> for Vect {
166    #[inline]
167    fn add_assign(&mut self, rhs: Vect) {
168        self.x += rhs.x;
169        self.y += rhs.y;
170    }
171}
172
173impl ops::Sub<Vect> for Vect {
174    type Output = Vect;
175    #[inline]
176    fn sub(self, rhs: Vect) -> Self::Output {
177        Self::new(self.x - rhs.x, self.y - rhs.y)
178    }
179}
180
181impl ops::SubAssign<Vect> for Vect {
182    #[inline]
183    fn sub_assign(&mut self, rhs: Vect) {
184        self.x -= rhs.x;
185        self.y -= rhs.y;
186    }
187}
188
189impl ops::Mul<Vect> for Vect {
190    type Output = Vect;
191    #[inline]
192    fn mul(self, rhs: Vect) -> Self::Output {
193        Self::new(self.x * rhs.x, self.y * rhs.y)
194    }
195}
196
197impl ops::MulAssign<Vect> for Vect {
198    #[inline]
199    fn mul_assign(&mut self, rhs: Vect) {
200        self.x *= rhs.x;
201        self.y *= rhs.y;
202    }
203}
204
205impl ops::Mul<f32> for Vect {
206    type Output = Vect;
207    #[inline]
208    fn mul(self, rhs: f32) -> Self::Output {
209        Self::new(self.x * rhs, self.y * rhs)
210    }
211}
212
213impl ops::MulAssign<f32> for Vect {
214    #[inline]
215    fn mul_assign(&mut self, rhs: f32) {
216        self.x *= rhs;
217        self.y *= rhs;
218    }
219}
220
221impl ops::Div<Vect> for Vect {
222    type Output = Vect;
223    #[inline]
224    fn div(self, rhs: Vect) -> Self::Output {
225        Self::new(self.x / rhs.x, self.y / rhs.y)
226    }
227}
228
229impl ops::DivAssign<Vect> for Vect {
230    #[inline]
231    fn div_assign(&mut self, rhs: Vect) {
232        self.x /= rhs.x;
233        self.y /= rhs.y;
234    }
235}
236
237impl ops::Div<f32> for Vect {
238    type Output = Vect;
239    #[inline]
240    fn div(self, rhs: f32) -> Self::Output {
241        Self::new(self.x / rhs, self.y / rhs)
242    }
243}
244
245impl ops::DivAssign<f32> for Vect {
246    #[inline]
247    fn div_assign(&mut self, rhs: f32) {
248        self.x /= rhs;
249        self.y /= rhs;
250    }
251}
252
253impl Default for Vect {
254    fn default() -> Self {
255        Vect::ZERO
256    }
257}
258
259#[cfg(test)]
260mod tests {
261    use std::f32::consts::PI;
262    use crate::math::vect::Vect;
263
264    fn round(a: f32, decimals: i32) -> f32 {
265        let mul = 10f32.powi(decimals);
266        (a * mul).round() / mul
267    }
268
269    #[test]
270    fn angle_test() {
271        assert_eq!(PI, Vect::LEFT.ang())
272    }
273    #[test]
274    fn ang_to_test() {
275        assert_eq!(PI, Vect::LEFT.ang_to(Vect::RIGHT))
276    }
277    #[test]
278    fn rot_test() {
279        assert_eq!(Vect::LEFT.x,round(Vect::RIGHT.rot(PI).x, 6));
280        assert_eq!(Vect::LEFT.y,round(Vect::RIGHT.rot(PI).y, 6));
281    }
282    #[test]
283    fn average_test() {
284        let vec = vec![Vect::LEFT, Vect::RIGHT];
285        assert_eq!(Vect::average(&vec), Vect::ZERO);
286    }
287}