utils/
point.rs

1//! 2D & 3D point implementations.
2
3use crate::number::{Integer, Number, Signed, UnsignedInteger};
4use std::fmt::Debug;
5use std::ops::{Add, AddAssign, Mul, MulAssign, Sub, SubAssign};
6
7macro_rules! point_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 point, 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
148point_impl! {2, (T, T) =>
149    /// Struct representing a 2D point or vector.
150    pub struct Point2D{0 => x, 1 => y}
151}
152
153impl<T: Signed> Point2D<T> {
154    pub const UP: Self = Self {
155        x: T::ZERO,
156        y: T::ONE,
157    };
158    pub const RIGHT: Self = Self {
159        x: T::ONE,
160        y: T::ZERO,
161    };
162    pub const DOWN: Self = Self {
163        x: T::ZERO,
164        y: T::MINUS_ONE,
165    };
166    pub const LEFT: Self = Self {
167        x: T::MINUS_ONE,
168        y: T::ZERO,
169    };
170
171    /// Rotate this vector 90 degrees clockwise.
172    #[inline]
173    #[must_use]
174    pub fn turn_right(self) -> Self {
175        Self {
176            x: self.y,
177            y: -self.x,
178        }
179    }
180
181    /// Rotate this vector 90 degrees counterclockwise.
182    #[inline]
183    #[must_use]
184    pub fn turn_left(self) -> Self {
185        Self {
186            x: -self.y,
187            y: self.x,
188        }
189    }
190}
191
192point_impl! {3, (T, T, T) =>
193    /// Struct representing a 3D point or vector.
194    pub struct Point3D{0 => x, 1 => y, 2 => z}
195}