utils/
geometry.rs

1//! 2D & 3D vector implementations.
2
3use crate::number::{Integer, Number, Signed, UnsignedInteger};
4use std::fmt::Debug;
5use std::ops::{Add, AddAssign, Mul, MulAssign, Not, Sub, SubAssign};
6
7macro_rules! vec_impl {
8    ($n:literal, $tuple:tt =>
9        $(#[$m:meta])* $v:vis struct $s:ident{$($i:tt => $f:ident),+}
10    ) => {
11        #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)]
12        $(#[$m])* $v struct $s<T: Number> {
13            $(pub $f: T,)+
14        }
15
16        impl<T: Number> $s<T> {
17            pub const ORIGIN: Self = Self{$($f: T::ZERO),+};
18
19            #[inline]
20            #[must_use]
21            pub const fn new($($f: T),+) -> Self {
22                Self{$($f),+}
23            }
24
25            /// Returns the manhattan distance from the origin.
26            #[inline]
27            #[must_use]
28            pub fn manhattan_distance(self) -> T::Unsigned
29            where
30                T: Integer
31            {
32                T::Unsigned::ZERO $(+ self.$f.unsigned_abs())+
33            }
34
35            /// Returns the manhattan distance from the specified point.
36            #[inline]
37            #[must_use]
38            pub fn manhattan_distance_from(self, rhs: Self) -> T::Unsigned
39            where
40                T: Integer
41            {
42                T::Unsigned::ZERO $(+ self.$f.abs_diff(rhs.$f))+
43            }
44
45            /// Add the provided signed vector, wrapping on overflow.
46            ///
47            /// Useful for adding a signed direction onto an unsigned position.
48            #[inline]
49            #[must_use]
50            pub fn wrapping_add_signed(self, rhs: $s<T::Signed>) -> Self
51            where
52                T: UnsignedInteger,
53            {
54                Self{
55                    $($f: self.$f.wrapping_add_signed(rhs.$f),)+
56                }
57            }
58        }
59
60        impl<T: Number> Add for $s<T> {
61            type Output = Self;
62
63            #[inline]
64            fn add(self, rhs: Self) -> Self {
65                Self{
66                    $($f: self.$f + rhs.$f,)+
67                }
68            }
69        }
70
71        impl<T: Number> AddAssign for $s<T> {
72            #[inline]
73            fn add_assign(&mut self, rhs: Self) {
74                $(self.$f += rhs.$f;)+
75            }
76        }
77
78        impl<T: Number> Mul<T> for $s<T> {
79            type Output = Self;
80
81            #[inline]
82            fn mul(self, rhs: T) -> Self {
83                Self{
84                    $($f: self.$f * rhs,)+
85                }
86            }
87        }
88
89        impl<T: Number> MulAssign<T> for $s<T> {
90            #[inline]
91            fn mul_assign(&mut self, rhs: T) {
92                $(self.$f *= rhs;)+
93            }
94        }
95
96        impl<T: Number> Sub for $s<T> {
97            type Output = Self;
98
99            #[inline]
100            fn sub(self, rhs: Self) -> Self {
101                Self{
102                    $($f: self.$f - rhs.$f,)+
103                }
104            }
105        }
106
107        impl<T: Number> SubAssign for $s<T> {
108            #[inline]
109            fn sub_assign(&mut self, rhs: Self) {
110                $(self.$f -= rhs.$f;)+
111            }
112        }
113
114        impl<T: Number> From<[T; $n]> for $s<T> {
115            #[inline]
116            fn from(arr: [T; $n]) -> Self {
117                Self{$(
118                    $f: arr[$i],
119                )+}
120            }
121        }
122
123        impl<T: Number> From<$tuple> for $s<T> {
124            #[inline]
125            fn from(arr: $tuple) -> Self {
126                Self{$(
127                    $f: arr.$i,
128                )+}
129            }
130        }
131
132        impl<T: Number> From<$s<T>> for [T; $n] {
133            #[inline]
134            fn from(value: $s<T>) -> Self {
135                [$(value.$f),+]
136            }
137        }
138
139        impl<T: Number> From<$s<T>> for $tuple {
140            #[inline]
141            fn from(value: $s<T>) -> Self {
142                ($(value.$f),+)
143            }
144        }
145    };
146}
147
148vec_impl! {2, (T, T) =>
149    /// Struct representing a 2D vector or point.
150    #[doc(alias("Vector", "Vector2", "Point", "Point2", "Point2D"))]
151    pub struct Vec2{0 => x, 1 => y}
152}
153
154impl<T: Signed> Vec2<T> {
155    pub const UP: Self = Self {
156        x: T::ZERO,
157        y: T::ONE,
158    };
159    pub const RIGHT: Self = Self {
160        x: T::ONE,
161        y: T::ZERO,
162    };
163    pub const DOWN: Self = Self {
164        x: T::ZERO,
165        y: T::MINUS_ONE,
166    };
167    pub const LEFT: Self = Self {
168        x: T::MINUS_ONE,
169        y: T::ZERO,
170    };
171    pub const DIRECTIONS: [Self; 4] = [Self::UP, Self::RIGHT, Self::DOWN, Self::LEFT];
172
173    /// Rotate this vector 90 degrees clockwise.
174    #[inline]
175    #[must_use]
176    pub fn turn_right(self) -> Self {
177        Self {
178            x: self.y,
179            y: -self.x,
180        }
181    }
182
183    /// Rotate this vector 90 degrees counterclockwise.
184    #[inline]
185    #[must_use]
186    pub fn turn_left(self) -> Self {
187        Self {
188            x: -self.y,
189            y: self.x,
190        }
191    }
192}
193
194vec_impl! {3, (T, T, T) =>
195    /// Struct representing a 3D vector or point.
196    #[doc(alias("Vector3", "Point3", "Point3D"))]
197    pub struct Vec3{0 => x, 1 => y, 2 => z}
198}
199
200/// Enum representing the four cardinal directions.
201#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
202#[repr(u8)]
203pub enum Direction {
204    #[default]
205    Up = 0,
206    Right,
207    Down,
208    Left,
209}
210
211impl Direction {
212    /// Rotate this direction by the provided turn.
213    #[inline]
214    #[must_use]
215    pub fn turn(self, turn: Turn) -> Self {
216        Self::from((self as u8).wrapping_add_signed(turn as i8))
217    }
218
219    /// Rotate this direction 90 degrees anticlockwise.
220    #[inline]
221    #[must_use]
222    pub fn turn_left(self) -> Self {
223        self.turn(Turn::Left)
224    }
225
226    /// Rotate this direction 90 degrees clockwise.
227    #[inline]
228    #[must_use]
229    pub fn turn_right(self) -> Self {
230        self.turn(Turn::Right)
231    }
232}
233
234impl From<u8> for Direction {
235    #[inline]
236    fn from(value: u8) -> Self {
237        match value % 4 {
238            0 => Direction::Up,
239            1 => Direction::Right,
240            2 => Direction::Down,
241            3 => Direction::Left,
242            _ => unreachable!(),
243        }
244    }
245}
246
247impl Not for Direction {
248    type Output = Self;
249
250    #[inline]
251    fn not(self) -> Self::Output {
252        Self::from((self as u8).wrapping_add(2))
253    }
254}
255
256impl<T: Signed> From<Direction> for Vec2<T> {
257    #[inline]
258    fn from(value: Direction) -> Self {
259        Vec2::DIRECTIONS[value as usize]
260    }
261}
262
263impl<T: Signed> Add<Direction> for Vec2<T> {
264    type Output = Self;
265
266    #[inline]
267    fn add(self, rhs: Direction) -> Self::Output {
268        self + Vec2::from(rhs)
269    }
270}
271
272impl<T: Signed> Sub<Direction> for Vec2<T> {
273    type Output = Self;
274
275    #[inline]
276    fn sub(self, rhs: Direction) -> Self::Output {
277        self - Vec2::from(rhs)
278    }
279}
280
281/// Enum representing possible turns.
282#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
283#[repr(i8)]
284pub enum Turn {
285    #[doc(alias("Anticlockwise"))]
286    Left = -1,
287    #[doc(alias("Straight"))]
288    #[default]
289    None = 0,
290    #[doc(alias("Clockwise"))]
291    Right = 1,
292}