rust_rectangle_dividing/
point.rs1use 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#[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
76impl<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
86impl<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
96impl<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
108impl<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 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 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}