impacted/v3/
point.rs

1use core::{
2    iter,
3    ops::{Add, AddAssign, Sub, SubAssign},
4};
5
6use sealed::sealed;
7
8use super::{vector::Vec2, Range, Shape, __seal_shape};
9
10#[derive(Debug, Copy, Clone, PartialEq)]
11pub struct Point(Vec2);
12
13impl Point {
14    pub const ORIGIN: Self = Self(Vec2::ZERO);
15
16    #[must_use]
17    pub fn new(x: f32, y: f32) -> Self {
18        Self(Vec2::new(x, y))
19    }
20
21    #[must_use]
22    pub fn x(self) -> f32 {
23        self.0.x
24    }
25
26    #[must_use]
27    pub fn y(self) -> f32 {
28        self.0.y
29    }
30}
31
32impl From<[f32; 2]> for Point {
33    fn from([x, y]: [f32; 2]) -> Self {
34        Self::new(x, y)
35    }
36}
37
38impl From<Point> for [f32; 2] {
39    fn from(Point(v): Point) -> Self {
40        v.into()
41    }
42}
43
44impl From<(f32, f32)> for Point {
45    fn from((x, y): (f32, f32)) -> Self {
46        Point::new(x, y)
47    }
48}
49
50impl From<Point> for (f32, f32) {
51    fn from(Point(v): Point) -> Self {
52        v.into()
53    }
54}
55
56impl From<Vec2> for Point {
57    fn from(value: Vec2) -> Self {
58        Self(value)
59    }
60}
61
62impl From<Point> for Vec2 {
63    fn from(Point(v): Point) -> Self {
64        v
65    }
66}
67
68#[sealed]
69impl Shape for Point {
70    fn axes(&self) -> impl Iterator<Item = Vec2> {
71        iter::empty()
72    }
73
74    fn focals(&self) -> impl Iterator<Item = Point> {
75        iter::empty()
76    }
77
78    fn vertices(&self) -> impl Iterator<Item = Point> {
79        iter::once(*self)
80    }
81
82    fn project_on(&self, axis: Vec2) -> Range {
83        let p = self.0.dot(axis);
84        Range::from_min_max(p, p)
85    }
86}
87
88impl AddAssign<Vec2> for Point {
89    fn add_assign(&mut self, rhs: Vec2) {
90        self.0 += rhs;
91    }
92}
93
94impl Add<Vec2> for Point {
95    type Output = Self;
96    fn add(mut self, rhs: Vec2) -> Self::Output {
97        self += rhs;
98        self
99    }
100}
101
102impl SubAssign<Vec2> for Point {
103    fn sub_assign(&mut self, rhs: Vec2) {
104        self.0 -= rhs;
105    }
106}
107
108impl Sub<Vec2> for Point {
109    type Output = Self;
110    fn sub(mut self, rhs: Vec2) -> Self::Output {
111        self -= rhs;
112        self
113    }
114}
115
116#[cfg(test)]
117impl approx::AbsDiffEq for Point {
118    type Epsilon = f32;
119    fn default_epsilon() -> Self::Epsilon {
120        f32::default_epsilon()
121    }
122    fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
123        self.0.abs_diff_eq(&other.0, epsilon)
124    }
125}
126
127#[cfg(test)]
128mod tests {
129    use approx::assert_abs_diff_eq;
130    use rstest::rstest;
131
132    use super::*;
133
134    #[rstest]
135    #[case(Vec2::ZERO, Vec2::ZERO, 0.0)]
136    #[case(Vec2::ZERO, Vec2::X, 0.0)]
137    #[case(Vec2::X, Vec2::X, 1.0)]
138    #[case(Vec2::X, Vec2::Y, 0.0)]
139    #[case(Vec2::Y, Vec2::Y, 1.0)]
140    #[case(Vec2::Y, Vec2::X, 0.0)]
141    #[case(Vec2::new(3.0, 4.0), Vec2::X, 3.0)]
142    #[case(Vec2::new(3.0, 4.0), Vec2::Y, 4.0)]
143    #[case(Vec2::new(3.0, 4.0),Vec2::new(3.0/5.0, 4.0/5.0),5.0)]
144    #[case(Vec2::new(3.0, 3.0),Vec2::new(2f32.sqrt(), -(2f32.sqrt())),0.0)]
145    fn test_axis_projection(
146        #[case] point: impl Into<Point>,
147        #[case] axis: Vec2,
148        #[case] expected: f32,
149    ) {
150        let expected = Range::from_min_max(expected, expected);
151        assert_abs_diff_eq!(point.into().project_on(axis), expected);
152    }
153
154    #[test]
155    fn test_sat_axes() {
156        assert_eq!(Point::from(Vec2::ZERO).axes().next(), None);
157    }
158}