1use crate::{Intersects, Point};
2
3#[derive(Debug, PartialEq, Copy, Clone)]
16pub struct Aabb {
17 pub upper_left: Point,
19 pub lower_right: Point,
21}
22
23impl Aabb {
24 pub fn try_new<P1, P2>(upper_left: P1, lower_right: P2) -> Result<Self, ()>
49 where
50 P1: Into<Point>,
51 P2: Into<Point>,
52 {
53 let upper_left = upper_left.into();
54 let lower_right = lower_right.into();
55
56 if upper_left.x >= lower_right.x || upper_left.y >= lower_right.y {
57 Err(())
58 } else {
59 Ok(Self {
60 upper_left,
61 lower_right,
62 })
63 }
64 }
65}
66
67impl Intersects for Aabb {
68 fn intersects(&self, other: &Aabb) -> bool {
81 let x_overlaps =
82 self.upper_left.x <= other.lower_right.x && self.lower_right.x >= other.upper_left.x;
83 let y_overlaps =
84 self.upper_left.y <= other.lower_right.y && self.lower_right.y >= other.upper_left.y;
85
86 x_overlaps && y_overlaps
87 }
88}
89
90#[cfg(test)]
91mod tests {
92 use super::*;
93
94 #[test]
95 fn try_new_errors_for_equal_points() {
96 assert!(Aabb::try_new((10.0, 10.0), (10.0, 10.0)).is_err());
97 }
98
99 #[test]
100 fn try_new_errors_when_upper_left_is_larger_than_lower_right() {
101 assert!(Aabb::try_new((10.0, 10.0), (0.0, 0.0)).is_err());
102 }
103
104 #[test]
105 fn try_new_errors_when_upper_left_x_is_larger_than_lower_right_x() {
106 assert!(Aabb::try_new((10.0, 0.0), (0.0, 5.5)).is_err());
107 }
108
109 #[test]
110 fn try_new_errors_when_upper_left_y_is_larger_than_lower_right_y() {
111 assert!(Aabb::try_new((0.0, 10.0), (5.0, 0.0)).is_err());
112 }
113
114 #[test]
115 fn intersects_self() {
116 let aabb = Aabb::try_new((0.0, 0.0), (10.0, 10.0)).unwrap();
117 assert!(aabb.intersects(&aabb));
118 }
119
120 #[test]
121 fn intersects_contained() {
122 let bigger_aabb = Aabb::try_new((0.0, 0.0), (10.0, 10.0)).unwrap();
123 let smaller_aabb = Aabb::try_new((2.0, 2.0), (8.0, 8.0)).unwrap();
124 assert!(bigger_aabb.intersects(&smaller_aabb));
125 assert!(smaller_aabb.intersects(&bigger_aabb));
126 }
127
128 #[test]
129 fn intersects_touching() {
130 let left_aabb = Aabb::try_new((0.0, 0.0), (10.0, 10.0)).unwrap();
131 let right_aabb = Aabb::try_new((10.0, 0.0), (20.0, 10.0)).unwrap();
132 assert!(left_aabb.intersects(&right_aabb));
133 assert!(right_aabb.intersects(&left_aabb));
134 }
135
136 #[test]
137 fn intersects_diagonally_touching() {
138 let left_aabb = Aabb::try_new((0.0, 0.0), (10.0, 10.0)).unwrap();
139 let right_aabb = Aabb::try_new((10.0, 10.0), (20.0, 11.0)).unwrap();
140 assert!(left_aabb.intersects(&right_aabb));
141 assert!(right_aabb.intersects(&left_aabb));
142 }
143
144 #[test]
145 fn intersects_intersecting() {
146 let first_aabb = Aabb::try_new((0.0, 0.0), (10.0, 10.0)).unwrap();
147 let second_aabb = Aabb::try_new((8.0, 8.0), (20.0, 20.0)).unwrap();
148 assert!(first_aabb.intersects(&second_aabb));
149 assert!(second_aabb.intersects(&first_aabb));
150 }
151
152 #[test]
153 fn intersects_intersecting_when_negative() {
154 let first_aabb = Aabb::try_new((-10.0, -10.0), (-5.0, -5.0)).unwrap();
155 let second_aabb = Aabb::try_new((-6.0, -20.0), (-3.0, -3.0)).unwrap();
156 assert!(first_aabb.intersects(&second_aabb));
157 assert!(second_aabb.intersects(&first_aabb));
158 }
159
160 #[test]
161 fn intersects_intersecting_when_negative_and_positive() {
162 let first_aabb = Aabb::try_new((-5.0, -5.0), (5.0, 5.0)).unwrap();
163 let second_aabb = Aabb::try_new((-6.0, -20.0), (0.0, 2.0)).unwrap();
164 assert!(first_aabb.intersects(&second_aabb));
165 assert!(second_aabb.intersects(&first_aabb));
166 }
167
168 #[test]
169 fn does_not_intersect_when_appart() {
170 let first_aabb = Aabb::try_new((0.0, 0.0), (10.0, 10.0)).unwrap();
171 let second_aabb = Aabb::try_new((20.0, 0.0), (21.0, 20.0)).unwrap();
172 assert!(!first_aabb.intersects(&second_aabb));
173 assert!(!second_aabb.intersects(&first_aabb));
174 }
175}