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    ($(#[$m:meta])* $v:vis struct $s:ident{$($f:ident),+}) => {
9        #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)]
10        $(#[$m])* $v struct $s<T: Number> {
11            $(pub $f: T,)+
12        }
13
14        impl<T: Number> $s<T> {
15            pub const ORIGIN: Self = Self{$($f: T::ZERO),+};
16
17            #[inline]
18            #[must_use]
19            pub const fn new($($f: T),+) -> Self {
20                Self{$($f),+}
21            }
22
23            /// Returns the manhattan distance from the origin.
24            #[inline]
25            #[must_use]
26            pub fn manhattan_distance(self) -> T::Unsigned
27            where
28                T: Integer
29            {
30                T::Unsigned::ZERO $(+ self.$f.unsigned_abs())+
31            }
32
33            /// Returns the manhattan distance from the specified point.
34            #[inline]
35            #[must_use]
36            pub fn manhattan_distance_from(self, rhs: Self) -> T::Unsigned
37            where
38                T: Integer
39            {
40                T::Unsigned::ZERO $(+ self.$f.abs_diff(rhs.$f))+
41            }
42
43            /// Add the provided signed point, wrapping on overflow.
44            ///
45            /// Useful for adding a signed direction onto an unsigned position.
46            #[inline]
47            #[must_use]
48            pub fn wrapping_add_signed(self, rhs: $s<T::Signed>) -> Self
49            where
50                T: UnsignedInteger,
51            {
52                Self{
53                    $($f: self.$f.wrapping_add_signed(rhs.$f),)+
54                }
55            }
56        }
57
58        impl<T: Number> Add for $s<T> {
59            type Output = Self;
60
61            #[inline]
62            fn add(self, rhs: Self) -> Self {
63                Self{
64                    $($f: self.$f + rhs.$f,)+
65                }
66            }
67        }
68
69        impl<T: Number> AddAssign for $s<T> {
70            #[inline]
71            fn add_assign(&mut self, rhs: Self) {
72                $(self.$f += rhs.$f;)+
73            }
74        }
75
76        impl<T: Number> Mul<T> for $s<T> {
77            type Output = Self;
78
79            #[inline]
80            fn mul(self, rhs: T) -> Self {
81                Self{
82                    $($f: self.$f * rhs,)+
83                }
84            }
85        }
86
87        impl<T: Number> MulAssign<T> for $s<T> {
88            #[inline]
89            fn mul_assign(&mut self, rhs: T) {
90                $(self.$f *= rhs;)+
91            }
92        }
93
94        impl<T: Number> Sub for $s<T> {
95            type Output = Self;
96
97            #[inline]
98            fn sub(self, rhs: Self) -> Self {
99                Self{
100                    $($f: self.$f - rhs.$f,)+
101                }
102            }
103        }
104
105        impl<T: Number> SubAssign for $s<T> {
106            #[inline]
107            fn sub_assign(&mut self, rhs: Self) {
108                $(self.$f -= rhs.$f;)+
109            }
110        }
111    };
112}
113
114point_impl! {
115    /// Struct representing a 2D point or vector.
116    pub struct Point2D{x, y}
117}
118
119impl<T: Signed> Point2D<T> {
120    pub const UP: Self = Self {
121        x: T::ZERO,
122        y: T::ONE,
123    };
124    pub const RIGHT: Self = Self {
125        x: T::ONE,
126        y: T::ZERO,
127    };
128    pub const DOWN: Self = Self {
129        x: T::ZERO,
130        y: T::MINUS_ONE,
131    };
132    pub const LEFT: Self = Self {
133        x: T::MINUS_ONE,
134        y: T::ZERO,
135    };
136
137    /// Rotate this vector 90 degrees clockwise.
138    #[inline]
139    #[must_use]
140    pub fn turn_right(self) -> Self {
141        Self {
142            x: self.y,
143            y: -self.x,
144        }
145    }
146
147    /// Rotate this vector 90 degrees counterclockwise.
148    #[inline]
149    #[must_use]
150    pub fn turn_left(self) -> Self {
151        Self {
152            x: -self.y,
153            y: self.x,
154        }
155    }
156}
157
158point_impl! {
159    /// Struct representing a 3D point or vector.
160    pub struct Point3D{x, y, z}
161}