utils/
geometry.rs

1//! 2D, 3D and 4D 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 a vector with all components set to the provided value.
26            #[inline]
27            #[must_use]
28            pub const fn splat(v: T) -> Self {
29                Self{$($f: v),+}
30            }
31
32            /// Map each component of this vector using the provided function.
33            #[inline]
34            #[must_use]
35            pub fn map<O: Number>(self, mut f: impl FnMut(T) -> O) -> $s<O> {
36                $s{$($f: f(self.$f)),+}
37            }
38
39            /// Convert each component of this vector.
40            #[inline]
41            #[must_use]
42            pub fn cast<O: Number + From<T>>(self) -> $s<O> {
43                self.map(O::from)
44            }
45
46            /// Returns the manhattan distance from the origin.
47            #[inline]
48            #[must_use]
49            pub fn manhattan_distance(self) -> T::Unsigned
50            where
51                T: Integer
52            {
53                T::Unsigned::ZERO $(+ self.$f.unsigned_abs())+
54            }
55
56            /// Returns the manhattan distance to the specified point.
57            #[inline]
58            #[must_use]
59            pub fn manhattan_distance_to(self, rhs: Self) -> T::Unsigned
60            where
61                T: Integer
62            {
63                T::Unsigned::ZERO $(+ self.$f.abs_diff(rhs.$f))+
64            }
65
66            /// Returns the manhattan distance to the specified axis-aligned bounding box.
67            #[inline]
68            #[must_use]
69            pub fn manhattan_distance_to_aabb(self, min: Self, max: Self) -> T::Unsigned
70            where
71                T: Integer
72            {
73                T::Unsigned::ZERO $(
74                    + min.$f.saturating_sub_0(self.$f)
75                    + self.$f.saturating_sub_0(max.$f)
76                )+
77            }
78
79            /// Returns the squared euclidean distance to the specified point.
80            #[inline]
81            #[must_use]
82            pub fn squared_euclidean_distance_to(self, rhs: Self) -> T {
83                T::ZERO $(+ self.$f.squared_diff(rhs.$f))+
84            }
85
86            /// Add the provided signed vector, wrapping on overflow.
87            ///
88            /// Useful for adding a signed direction onto an unsigned position.
89            #[inline]
90            #[must_use]
91            pub fn wrapping_add_signed(self, rhs: $s<T::Signed>) -> Self
92            where
93                T: UnsignedInteger,
94            {
95                Self{
96                    $($f: self.$f.wrapping_add_signed(rhs.$f),)+
97                }
98            }
99
100            /// Returns the per-component minimum.
101            #[inline]
102            #[must_use]
103            pub fn component_min(self, rhs: Self) -> Self
104            where
105                T: Ord,
106            {
107                Self{
108                    $($f: self.$f.min(rhs.$f),)+
109                }
110            }
111
112
113            /// Returns the per-component maximum.
114            #[inline]
115            #[must_use]
116            pub fn component_max(self, rhs: Self) -> Self
117            where
118                T: Ord,
119            {
120                Self{
121                    $($f: self.$f.max(rhs.$f),)+
122                }
123            }
124        }
125
126        impl<T: Number> Add for $s<T> {
127            type Output = Self;
128
129            #[inline]
130            fn add(self, rhs: Self) -> Self {
131                Self{
132                    $($f: self.$f + rhs.$f,)+
133                }
134            }
135        }
136
137        impl<T: Number> AddAssign for $s<T> {
138            #[inline]
139            fn add_assign(&mut self, rhs: Self) {
140                $(self.$f += rhs.$f;)+
141            }
142        }
143
144        impl<T: Number> Mul<T> for $s<T> {
145            type Output = Self;
146
147            #[inline]
148            fn mul(self, rhs: T) -> Self {
149                Self{
150                    $($f: self.$f * rhs,)+
151                }
152            }
153        }
154
155        impl<T: Number> MulAssign<T> for $s<T> {
156            #[inline]
157            fn mul_assign(&mut self, rhs: T) {
158                $(self.$f *= rhs;)+
159            }
160        }
161
162        impl<T: Number> Sub for $s<T> {
163            type Output = Self;
164
165            #[inline]
166            fn sub(self, rhs: Self) -> Self {
167                Self{
168                    $($f: self.$f - rhs.$f,)+
169                }
170            }
171        }
172
173        impl<T: Number> SubAssign for $s<T> {
174            #[inline]
175            fn sub_assign(&mut self, rhs: Self) {
176                $(self.$f -= rhs.$f;)+
177            }
178        }
179
180        impl<T: Number> From<[T; $n]> for $s<T> {
181            #[inline]
182            fn from(arr: [T; $n]) -> Self {
183                Self{$(
184                    $f: arr[$i],
185                )+}
186            }
187        }
188
189        impl<T: Number> From<$tuple> for $s<T> {
190            #[inline]
191            fn from(arr: $tuple) -> Self {
192                Self{$(
193                    $f: arr.$i,
194                )+}
195            }
196        }
197
198        impl<T: Number> From<$s<T>> for [T; $n] {
199            #[inline]
200            fn from(value: $s<T>) -> Self {
201                [$(value.$f),+]
202            }
203        }
204
205        impl<T: Number> From<$s<T>> for $tuple {
206            #[inline]
207            fn from(value: $s<T>) -> Self {
208                ($(value.$f),+)
209            }
210        }
211
212        vec_impl!(@widen $s{$($f),+},
213            u8 => [u16, u32, u64, u128, i16, i32, i64, i128, f32, f64],
214            u16 => [u32, u64, u128, i32, i64, i128, f32, f64],
215            u32 => [u64, u128, i64, i128, f64],
216            u64 => [u128, i128],
217            i8 => [i16, i32, i64, i128, f32, f64],
218            i16 => [i32, i64, i128, f32, f64],
219            i32 => [i64, i128, f64],
220            i64 => [i128],
221        );
222    };
223    (@widen $s:ident{$($f:ident),+}, $($from:ident => [$($to:ident),+],)+) => {$($(
224        impl From<$s<$from>> for $s<$to> {
225            #[inline(always)]
226            fn from(value: $s<$from>) -> Self {
227                value.cast()
228            }
229        }
230    )+)+};
231}
232
233vec_impl! {2, (T, T) =>
234    /// Struct representing a 2D vector or point.
235    #[doc(alias("Vector", "Vector2", "Point", "Point2", "Point2D"))]
236    pub struct Vec2{0 => x, 1 => y}
237}
238
239impl<T: Signed> Vec2<T> {
240    pub const UP: Self = Self {
241        x: T::ZERO,
242        y: T::ONE,
243    };
244    pub const RIGHT: Self = Self {
245        x: T::ONE,
246        y: T::ZERO,
247    };
248    pub const DOWN: Self = Self {
249        x: T::ZERO,
250        y: T::MINUS_ONE,
251    };
252    pub const LEFT: Self = Self {
253        x: T::MINUS_ONE,
254        y: T::ZERO,
255    };
256    pub const DIRECTIONS: [Self; 4] = [Self::UP, Self::RIGHT, Self::DOWN, Self::LEFT];
257
258    /// Rotate this vector 90 degrees clockwise.
259    #[inline]
260    #[must_use]
261    pub fn turn_right(self) -> Self {
262        Self {
263            x: self.y,
264            y: -self.x,
265        }
266    }
267
268    /// Rotate this vector 90 degrees counterclockwise.
269    #[inline]
270    #[must_use]
271    pub fn turn_left(self) -> Self {
272        Self {
273            x: -self.y,
274            y: self.x,
275        }
276    }
277}
278
279vec_impl! {3, (T, T, T) =>
280    /// Struct representing a 3D vector or point.
281    #[doc(alias("Vector3", "Point3", "Point3D"))]
282    pub struct Vec3{0 => x, 1 => y, 2 => z}
283}
284
285vec_impl! {4, (T, T, T, T) =>
286    /// Struct representing a 4D vector or point.
287    #[doc(alias("Vector4", "Point4", "Point4D"))]
288    pub struct Vec4{0 => x, 1 => y, 2 => z, 3 => w}
289}
290
291/// Enum representing the four cardinal directions.
292#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
293#[repr(u8)]
294pub enum Direction {
295    #[default]
296    Up = 0,
297    Right,
298    Down,
299    Left,
300}
301
302impl Direction {
303    /// Rotate this direction by the provided turn.
304    #[inline]
305    #[must_use]
306    pub fn turn(self, turn: Turn) -> Self {
307        Self::from((self as u8).wrapping_add_signed(turn as i8))
308    }
309
310    /// Rotate this direction 90 degrees anticlockwise.
311    #[inline]
312    #[must_use]
313    pub fn turn_left(self) -> Self {
314        self.turn(Turn::Left)
315    }
316
317    /// Rotate this direction 90 degrees clockwise.
318    #[inline]
319    #[must_use]
320    pub fn turn_right(self) -> Self {
321        self.turn(Turn::Right)
322    }
323}
324
325impl From<u8> for Direction {
326    #[inline]
327    fn from(value: u8) -> Self {
328        match value % 4 {
329            0 => Direction::Up,
330            1 => Direction::Right,
331            2 => Direction::Down,
332            3 => Direction::Left,
333            _ => unreachable!(),
334        }
335    }
336}
337
338impl Not for Direction {
339    type Output = Self;
340
341    #[inline]
342    fn not(self) -> Self::Output {
343        Self::from((self as u8).wrapping_add(2))
344    }
345}
346
347impl<T: Signed> From<Direction> for Vec2<T> {
348    #[inline]
349    fn from(value: Direction) -> Self {
350        Vec2::DIRECTIONS[value as usize]
351    }
352}
353
354impl<T: Signed> Add<Direction> for Vec2<T> {
355    type Output = Self;
356
357    #[inline]
358    fn add(self, rhs: Direction) -> Self::Output {
359        self + Vec2::from(rhs)
360    }
361}
362
363impl<T: Signed> Sub<Direction> for Vec2<T> {
364    type Output = Self;
365
366    #[inline]
367    fn sub(self, rhs: Direction) -> Self::Output {
368        self - Vec2::from(rhs)
369    }
370}
371
372/// Enum representing possible turns.
373#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
374#[repr(i8)]
375pub enum Turn {
376    #[doc(alias("Anticlockwise"))]
377    Left = -1,
378    #[doc(alias("Straight"))]
379    #[default]
380    None = 0,
381    #[doc(alias("Clockwise"))]
382    Right = 1,
383}