rust_rectangle_dividing/
point.rs

1use num_traits::{Float, Num, NumAssignOps, NumOps};
2
3use crate::axis::{Axis, ValueForAxis};
4use crate::component::Component;
5use crate::rotate::QuarterRotation;
6use crate::vector::Vector;
7/// A point in 2D space
8#[derive(Debug, PartialEq, Clone, Copy)]
9pub struct Point<T>
10where
11    T: Copy + Num + NumAssignOps + NumOps,
12{
13    x: T,
14    y: T,
15}
16
17#[derive(Debug, PartialEq, Clone, Copy)]
18pub enum Edge {
19    LeftTop,
20    RightTop,
21    LeftBottom,
22    RightBottom,
23}
24
25impl<T> Point<T>
26where
27    T: Copy + Num + NumAssignOps + NumOps + Float,
28{
29    pub fn round(&self, edge: Edge) -> Self {
30        match edge {
31            Edge::LeftTop => Self {
32                x: self.x.floor(),
33                y: self.y.floor(),
34            },
35            Edge::RightTop => Self {
36                x: self.x.ceil(),
37                y: self.y.floor(),
38            },
39            Edge::LeftBottom => Self {
40                x: self.x.floor(),
41                y: self.y.ceil(),
42            },
43            Edge::RightBottom => Self {
44                x: self.x.ceil(),
45                y: self.y.ceil(),
46            },
47        }
48    }
49}
50
51impl<T> ValueForAxis<T> for Point<T>
52where
53    T: Copy + Num + NumAssignOps + NumOps,
54{
55    fn value_for_axis(&self, axis: Axis) -> T {
56        match axis {
57            Axis::Vertical => self.x,
58            Axis::Horizontal => self.y,
59        }
60    }
61}
62
63impl<T> Component<T> for Point<T>
64where
65    T: Copy + Num + NumAssignOps + NumOps,
66{
67    fn x(&self) -> T {
68        self.x
69    }
70
71    fn y(&self) -> T {
72        self.y
73    }
74}
75
76/// A point in 2D space constructor
77impl<T> Point<T>
78where
79    T: Copy + Num + NumAssignOps + NumOps,
80{
81    pub fn new(x: T, y: T) -> Self {
82        Point { x, y }
83    }
84}
85
86/// A point in 2D space with default values. in many cases, this is (0, 0)
87impl<T> std::default::Default for Point<T>
88where
89    T: Default + Copy + Num + NumAssignOps + NumOps,
90{
91    fn default() -> Self {
92        Self::new(T::default(), T::default())
93    }
94}
95
96/// Vector from point A to point B
97impl<T> std::ops::Sub<Point<T>> for Point<T>
98where
99    T: Copy + Num + NumAssignOps + NumOps,
100{
101    type Output = Vector<T>;
102
103    fn sub(self, rhs: Point<T>) -> Self::Output {
104        Vector::new(self.x - rhs.x, self.y - rhs.y)
105    }
106}
107
108/// Rotate a point by 90 degrees
109impl<T> QuarterRotation for Point<T>
110where
111    T: Copy + Num + NumAssignOps + NumOps,
112{
113    fn rotate_clockwise(&self) -> Self {
114        Point {
115            x: self.y,
116            y: self.x,
117        }
118    }
119}
120
121#[cfg(test)]
122mod tests {
123    use super::*;
124
125    #[test]
126    fn test_new() {
127        let result = Point::new(2, 2);
128        assert_eq!(result.x, 2);
129        assert_eq!(result.y, 2);
130    }
131
132    #[test]
133    fn test_default() {
134        let result = Point::<i32>::default();
135        assert_point_eq(&result, &Point::new(0, 0));
136    }
137
138    #[test]
139    fn test_value_for_axis() {
140        let result = Point::new(2, 3);
141        assert_eq!(result.value_for_axis(Axis::Vertical), 2);
142        assert_eq!(result.value_for_axis(Axis::Horizontal), 3);
143    }
144
145    #[test]
146    fn test_sub() {
147        let a = Point::new(2, 2);
148        let b = Point::new(1, 1);
149        assert_ne!(a, b);
150        let result = a - b;
151        assert_eq!(result, Vector::new(1, 1));
152    }
153
154    #[test]
155    fn test_rotate() {
156        let result = Point::new(2, 3).rotate_clockwise();
157        assert_point_eq(&result, &Point::new(3, 2));
158    }
159
160    /// Helper function to assert that two points are equal
161    fn assert_point_eq<T>(p1: &Point<T>, p2: &Point<T>)
162    where
163        T: Copy + PartialEq + std::fmt::Debug + Num + NumAssignOps + NumOps,
164    {
165        assert_point_has_same_component_is_equal(p1, p2);
166    }
167
168    /// Assert that two points have the same component values
169    fn assert_point_has_same_component_is_equal<T>(p1: &Point<T>, p2: &Point<T>)
170    where
171        T: Copy + PartialEq + std::fmt::Debug + Num + NumAssignOps + NumOps,
172    {
173        assert_eq!(p1.x, p2.x);
174        assert_eq!(p1.y, p2.y);
175        assert_eq!(p1, p2);
176    }
177}