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, Div, DivAssign, 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> Div<T> for $s<T> {
145            type Output = Self;
146
147            #[inline]
148            fn div(self, rhs: T) -> Self {
149                Self{
150                    $($f: self.$f / rhs,)+
151                }
152            }
153        }
154
155        impl<T: Number> DivAssign<T> for $s<T> {
156            #[inline]
157            fn div_assign(&mut self, rhs: T) {
158                $(self.$f /= rhs;)+
159            }
160        }
161
162        impl<T: Number> Mul<T> for $s<T> {
163            type Output = Self;
164
165            #[inline]
166            fn mul(self, rhs: T) -> Self {
167                Self{
168                    $($f: self.$f * rhs,)+
169                }
170            }
171        }
172
173        impl<T: Number> MulAssign<T> for $s<T> {
174            #[inline]
175            fn mul_assign(&mut self, rhs: T) {
176                $(self.$f *= rhs;)+
177            }
178        }
179
180        impl<T: Number> Sub for $s<T> {
181            type Output = Self;
182
183            #[inline]
184            fn sub(self, rhs: Self) -> Self {
185                Self{
186                    $($f: self.$f - rhs.$f,)+
187                }
188            }
189        }
190
191        impl<T: Number> SubAssign for $s<T> {
192            #[inline]
193            fn sub_assign(&mut self, rhs: Self) {
194                $(self.$f -= rhs.$f;)+
195            }
196        }
197
198        impl<T: Number> From<[T; $n]> for $s<T> {
199            #[inline]
200            fn from(arr: [T; $n]) -> Self {
201                Self{$(
202                    $f: arr[$i],
203                )+}
204            }
205        }
206
207        impl<T: Number> From<$tuple> for $s<T> {
208            #[inline]
209            fn from(arr: $tuple) -> Self {
210                Self{$(
211                    $f: arr.$i,
212                )+}
213            }
214        }
215
216        impl<T: Number> From<$s<T>> for [T; $n] {
217            #[inline]
218            fn from(value: $s<T>) -> Self {
219                [$(value.$f),+]
220            }
221        }
222
223        impl<T: Number> From<$s<T>> for $tuple {
224            #[inline]
225            fn from(value: $s<T>) -> Self {
226                ($(value.$f),+)
227            }
228        }
229
230        vec_impl!(@widen $s{$($f),+},
231            u8 => [u16, u32, u64, u128, i16, i32, i64, i128, f32, f64],
232            u16 => [u32, u64, u128, i32, i64, i128, f32, f64],
233            u32 => [u64, u128, i64, i128, f64],
234            u64 => [u128, i128],
235            i8 => [i16, i32, i64, i128, f32, f64],
236            i16 => [i32, i64, i128, f32, f64],
237            i32 => [i64, i128, f64],
238            i64 => [i128],
239        );
240    };
241    (@widen $s:ident{$($f:ident),+}, $($from:ident => [$($to:ident),+],)+) => {$($(
242        impl From<$s<$from>> for $s<$to> {
243            #[inline(always)]
244            fn from(value: $s<$from>) -> Self {
245                value.cast()
246            }
247        }
248    )+)+};
249}
250
251vec_impl! {2, (T, T) =>
252    /// Struct representing a 2D vector or point.
253    #[doc(alias("Vector", "Vector2", "Point", "Point2", "Point2D"))]
254    pub struct Vec2{0 => x, 1 => y}
255}
256
257impl<T: Signed> Vec2<T> {
258    pub const UP: Self = Self {
259        x: T::ZERO,
260        y: T::ONE,
261    };
262    pub const RIGHT: Self = Self {
263        x: T::ONE,
264        y: T::ZERO,
265    };
266    pub const DOWN: Self = Self {
267        x: T::ZERO,
268        y: T::MINUS_ONE,
269    };
270    pub const LEFT: Self = Self {
271        x: T::MINUS_ONE,
272        y: T::ZERO,
273    };
274    pub const DIRECTIONS: [Self; 4] = [Self::UP, Self::RIGHT, Self::DOWN, Self::LEFT];
275
276    /// Rotate this vector 90 degrees clockwise.
277    #[inline]
278    #[must_use]
279    pub fn turn_right(self) -> Self {
280        Self {
281            x: self.y,
282            y: -self.x,
283        }
284    }
285
286    /// Rotate this vector 90 degrees counterclockwise.
287    #[inline]
288    #[must_use]
289    pub fn turn_left(self) -> Self {
290        Self {
291            x: -self.y,
292            y: self.x,
293        }
294    }
295}
296
297vec_impl! {3, (T, T, T) =>
298    /// Struct representing a 3D vector or point.
299    #[doc(alias("Vector3", "Point3", "Point3D"))]
300    pub struct Vec3{0 => x, 1 => y, 2 => z}
301}
302
303vec_impl! {4, (T, T, T, T) =>
304    /// Struct representing a 4D vector or point.
305    #[doc(alias("Vector4", "Point4", "Point4D"))]
306    pub struct Vec4{0 => x, 1 => y, 2 => z, 3 => w}
307}
308
309/// Enum representing the four cardinal directions.
310#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
311#[repr(u8)]
312pub enum Direction {
313    #[default]
314    Up = 0,
315    Right,
316    Down,
317    Left,
318}
319
320impl Direction {
321    /// Rotate this direction by the provided turn.
322    #[inline]
323    #[must_use]
324    pub fn turn(self, turn: Turn) -> Self {
325        Self::from((self as u8).wrapping_add_signed(turn as i8))
326    }
327
328    /// Rotate this direction 90 degrees anticlockwise.
329    #[inline]
330    #[must_use]
331    pub fn turn_left(self) -> Self {
332        self.turn(Turn::Left)
333    }
334
335    /// Rotate this direction 90 degrees clockwise.
336    #[inline]
337    #[must_use]
338    pub fn turn_right(self) -> Self {
339        self.turn(Turn::Right)
340    }
341}
342
343impl From<u8> for Direction {
344    #[inline]
345    fn from(value: u8) -> Self {
346        match value % 4 {
347            0 => Direction::Up,
348            1 => Direction::Right,
349            2 => Direction::Down,
350            3 => Direction::Left,
351            _ => unreachable!(),
352        }
353    }
354}
355
356impl Not for Direction {
357    type Output = Self;
358
359    #[inline]
360    fn not(self) -> Self::Output {
361        Self::from((self as u8).wrapping_add(2))
362    }
363}
364
365impl<T: Signed> From<Direction> for Vec2<T> {
366    #[inline]
367    fn from(value: Direction) -> Self {
368        Vec2::DIRECTIONS[value as usize]
369    }
370}
371
372impl<T: Signed> Add<Direction> for Vec2<T> {
373    type Output = Self;
374
375    #[inline]
376    fn add(self, rhs: Direction) -> Self::Output {
377        self + Vec2::from(rhs)
378    }
379}
380
381impl<T: Signed> Sub<Direction> for Vec2<T> {
382    type Output = Self;
383
384    #[inline]
385    fn sub(self, rhs: Direction) -> Self::Output {
386        self - Vec2::from(rhs)
387    }
388}
389
390/// Enum representing possible turns.
391#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
392#[repr(i8)]
393pub enum Turn {
394    #[doc(alias("Anticlockwise"))]
395    Left = -1,
396    #[doc(alias("Straight"))]
397    #[default]
398    None = 0,
399    #[doc(alias("Clockwise"))]
400    Right = 1,
401}