1use serde::{Deserialize, Serialize};
2
3use crate::{Affine, Point, Vector};
4
5#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
7pub struct Aabb {
8 pub min: Point,
10 pub max: Point,
12}
13
14impl Default for Aabb {
15 fn default() -> Self {
16 Self::EMPTY
17 }
18}
19
20impl Aabb {
21 pub const EMPTY: Self =
23 Self { min: Point::new(f64::INFINITY, f64::INFINITY), max: Point::new(f64::NEG_INFINITY, f64::NEG_INFINITY) };
24
25 #[must_use]
27 pub fn from_corners(a: Point, b: Point) -> Self {
28 Self { min: Point::new(a.x.min(b.x), a.y.min(b.y)), max: Point::new(a.x.max(b.x), a.y.max(b.y)) }
29 }
30
31 #[must_use]
33 pub fn from_points<I: IntoIterator<Item = Point>>(points: I) -> Self {
34 points.into_iter().fold(Self::EMPTY, Self::include)
35 }
36
37 #[must_use]
39 pub fn is_empty(self) -> bool {
40 !(self.min.x <= self.max.x && self.min.y <= self.max.y)
41 }
42
43 #[must_use]
45 pub fn include(self, p: Point) -> Self {
46 if !p.is_finite() {
47 return self;
48 }
49 Self {
50 min: Point::new(self.min.x.min(p.x), self.min.y.min(p.y)),
51 max: Point::new(self.max.x.max(p.x), self.max.y.max(p.y)),
52 }
53 }
54
55 #[must_use]
57 pub fn union(self, o: Self) -> Self {
58 if o.is_empty() {
59 return self;
60 }
61 if self.is_empty() {
62 return o;
63 }
64 Self {
65 min: Point::new(self.min.x.min(o.min.x), self.min.y.min(o.min.y)),
66 max: Point::new(self.max.x.max(o.max.x), self.max.y.max(o.max.y)),
67 }
68 }
69
70 #[must_use]
72 pub fn inflate(self, d: f64) -> Self {
73 if self.is_empty() {
74 return self;
75 }
76 Self { min: Point::new(self.min.x - d, self.min.y - d), max: Point::new(self.max.x + d, self.max.y + d) }
77 }
78
79 #[must_use]
81 pub fn width(self) -> f64 {
82 if self.is_empty() { 0.0 } else { self.max.x - self.min.x }
83 }
84
85 #[must_use]
87 pub fn height(self) -> f64 {
88 if self.is_empty() { 0.0 } else { self.max.y - self.min.y }
89 }
90
91 #[must_use]
93 pub fn center(self) -> Point {
94 self.min.midpoint(self.max)
95 }
96
97 #[must_use]
99 pub fn size(self) -> Vector {
100 Vector::new(self.width(), self.height())
101 }
102
103 #[must_use]
105 pub fn contains_point(self, p: Point) -> bool {
106 p.x >= self.min.x && p.x <= self.max.x && p.y >= self.min.y && p.y <= self.max.y
107 }
108
109 #[must_use]
111 pub fn contains(self, o: Self) -> bool {
112 !o.is_empty()
113 && !self.is_empty()
114 && o.min.x >= self.min.x
115 && o.max.x <= self.max.x
116 && o.min.y >= self.min.y
117 && o.max.y <= self.max.y
118 }
119
120 #[must_use]
122 pub fn intersects(self, o: Self) -> bool {
123 !self.is_empty()
124 && !o.is_empty()
125 && self.min.x <= o.max.x
126 && o.min.x <= self.max.x
127 && self.min.y <= o.max.y
128 && o.min.y <= self.max.y
129 }
130
131 #[must_use]
133 pub fn distance_to_point(self, p: Point) -> f64 {
134 if self.is_empty() {
135 return f64::INFINITY;
136 }
137 let dx = (self.min.x - p.x).max(0.0).max(p.x - self.max.x);
138 let dy = (self.min.y - p.y).max(0.0).max(p.y - self.max.y);
139 crate::math::hypot(dx, dy)
140 }
141
142 #[must_use]
144 pub fn corners(self) -> [Point; 4] {
145 [self.min, Point::new(self.max.x, self.min.y), self.max, Point::new(self.min.x, self.max.y)]
146 }
147
148 #[must_use]
150 pub fn transform(self, t: Affine) -> Self {
151 if self.is_empty() {
152 return self;
153 }
154 Self::from_points(self.corners().map(|c| t.apply(c)))
155 }
156}
157
158#[cfg(test)]
159mod tests {
160 use super::*;
161
162 #[test]
163 fn empty_behaviour() {
164 assert!(Aabb::EMPTY.is_empty());
165 let b = Aabb::from_corners(Point::new(1.0, 2.0), Point::new(-1.0, 0.0));
166 assert_eq!(Aabb::EMPTY.union(b), b);
167 assert_eq!(b.union(Aabb::EMPTY), b);
168 assert!(!Aabb::EMPTY.intersects(b));
169 assert_eq!(Aabb::from_points([]), Aabb::EMPTY);
170 }
171
172 #[test]
173 fn distance() {
174 let b = Aabb::from_corners(Point::ORIGIN, Point::new(2.0, 2.0));
175 assert_eq!(b.distance_to_point(Point::new(1.0, 1.0)), 0.0);
176 assert!((b.distance_to_point(Point::new(5.0, 6.0)) - 5.0).abs() < 1e-12);
177 }
178}