1use std::fmt;
4
5#[derive(Debug, Clone, Copy, PartialEq)]
6pub struct AABB {
7 pub min: [f64; 2],
8 pub max: [f64; 2],
9}
10
11impl AABB {
12 pub fn new(min: [f64; 2], max: [f64; 2]) -> Self {
13 Self { min, max }
14 }
15
16 pub fn from_center(center: [f64; 2], half_extents: [f64; 2]) -> Self {
17 Self {
18 min: [center[0] - half_extents[0], center[1] - half_extents[1]],
19 max: [center[0] + half_extents[0], center[1] + half_extents[1]],
20 }
21 }
22
23 pub fn center(&self) -> [f64; 2] {
24 [(self.min[0] + self.max[0]) / 2.0, (self.min[1] + self.max[1]) / 2.0]
25 }
26
27 pub fn half_extents(&self) -> [f64; 2] {
28 [(self.max[0] - self.min[0]) / 2.0, (self.max[1] - self.min[1]) / 2.0]
29 }
30
31 pub fn intersects(&self, other: &AABB) -> bool {
32 self.min[0] <= other.max[0]
33 && self.max[0] >= other.min[0]
34 && self.min[1] <= other.max[1]
35 && self.max[1] >= other.min[1]
36 }
37
38 pub fn contains_point(&self, p: [f64; 2]) -> bool {
39 p[0] >= self.min[0] && p[0] <= self.max[0] && p[1] >= self.min[1] && p[1] <= self.max[1]
40 }
41
42 pub fn contains(&self, other: &AABB) -> bool {
43 self.min[0] <= other.min[0]
44 && self.max[0] >= other.max[0]
45 && self.min[1] <= other.min[1]
46 && self.max[1] >= other.max[1]
47 }
48
49 pub fn overlap(&self, other: &AABB) -> Option<AABB> {
51 if !self.intersects(other) {
52 return None;
53 }
54 Some(AABB {
55 min: [self.min[0].max(other.min[0]), self.min[1].max(other.min[1])],
56 max: [self.max[0].min(other.max[0]), self.max[1].min(other.max[1])],
57 })
58 }
59
60 pub fn merged(&self, other: &AABB) -> AABB {
61 AABB {
62 min: [self.min[0].min(other.min[0]), self.min[1].min(other.min[1])],
63 max: [self.max[0].max(other.max[0]), self.max[1].max(other.max[1])],
64 }
65 }
66
67 pub fn area(&self) -> f64 {
68 (self.max[0] - self.min[0]) * (self.max[1] - self.min[1])
69 }
70}
71
72#[derive(Debug, Clone)]
74pub struct CollisionDetector {
75 boxes: Vec<(usize, AABB)>,
76}
77
78impl CollisionDetector {
79 pub fn new() -> Self {
80 Self { boxes: Vec::new() }
81 }
82
83 pub fn insert(&mut self, id: usize, aabb: AABB) {
84 self.boxes.push((id, aabb));
85 }
86
87 pub fn clear(&mut self) {
88 self.boxes.clear();
89 }
90
91 pub fn find_collisions(&self) -> Vec<(usize, usize)> {
93 let mut pairs = Vec::new();
94 for i in 0..self.boxes.len() {
95 for j in (i + 1)..self.boxes.len() {
96 if self.boxes[i].1.intersects(&self.boxes[j].1) {
97 let (a, b) = if self.boxes[i].0 < self.boxes[j].0 {
98 (self.boxes[i].0, self.boxes[j].0)
99 } else {
100 (self.boxes[j].0, self.boxes[i].0)
101 };
102 pairs.push((a, b));
103 }
104 }
105 }
106 pairs.sort();
107 pairs.dedup();
108 pairs
109 }
110}
111
112impl Default for CollisionDetector {
113 fn default() -> Self {
114 Self::new()
115 }
116}
117
118#[derive(Debug, Clone, Copy, PartialEq)]
120pub struct AABB3 {
121 pub min: [f64; 3],
122 pub max: [f64; 3],
123}
124
125impl AABB3 {
126 pub fn new(min: [f64; 3], max: [f64; 3]) -> Self {
127 Self { min, max }
128 }
129
130 pub fn intersects(&self, other: &AABB3) -> bool {
131 self.min[0] <= other.max[0]
132 && self.max[0] >= other.min[0]
133 && self.min[1] <= other.max[1]
134 && self.max[1] >= other.min[1]
135 && self.min[2] <= other.max[2]
136 && self.max[2] >= other.min[2]
137 }
138
139 pub fn volume(&self) -> f64 {
140 (self.max[0] - self.min[0]) * (self.max[1] - self.min[1]) * (self.max[2] - self.min[2])
141 }
142}
143
144#[cfg(test)]
145mod tests {
146 use super::*;
147
148 #[test]
149 fn test_overlap() {
150 let a = AABB::new([0.0, 0.0], [2.0, 2.0]);
151 let b = AABB::new([1.0, 1.0], [3.0, 3.0]);
152 assert!(a.intersects(&b));
153 let overlap = a.overlap(&b).unwrap();
154 assert_eq!(overlap.min, [1.0, 1.0]);
155 assert_eq!(overlap.max, [2.0, 2.0]);
156 }
157
158 #[test]
159 fn test_no_overlap() {
160 let a = AABB::new([0.0, 0.0], [1.0, 1.0]);
161 let b = AABB::new([2.0, 2.0], [3.0, 3.0]);
162 assert!(!a.intersects(&b));
163 }
164
165 #[test]
166 fn test_collision_detector() {
167 let mut det = CollisionDetector::new();
168 det.insert(0, AABB::new([0.0, 0.0], [2.0, 2.0]));
169 det.insert(1, AABB::new([1.0, 1.0], [3.0, 3.0]));
170 det.insert(2, AABB::new([10.0, 10.0], [11.0, 11.0]));
171 let pairs = det.find_collisions();
172 assert_eq!(pairs, vec![(0, 1)]);
173 }
174}