use super::geometry::AABB;
pub type CollisionPair = (usize, usize);
#[derive(Clone, Copy)]
struct Endpoint {
value: f64,
body_idx: usize,
is_min: bool,
}
pub fn sweep_and_prune(aabbs: &[AABB]) -> Vec<CollisionPair> {
if aabbs.len() < 2 {
return Vec::new();
}
let mut pairs = Vec::new();
let mut endpoints: Vec<Endpoint> = Vec::new();
for (i, aabb) in aabbs.iter().enumerate() {
endpoints.push(Endpoint {
value: aabb.min.x,
body_idx: i,
is_min: true,
});
endpoints.push(Endpoint {
value: aabb.max.x,
body_idx: i,
is_min: false,
});
}
endpoints.sort_by(|a, b| a.value.partial_cmp(&b.value).unwrap());
let mut active = Vec::new();
for ep in endpoints {
if ep.is_min {
for &other in &active {
if aabbs[ep.body_idx].overlaps(&aabbs[other]) {
let pair = if ep.body_idx < other {
(ep.body_idx, other)
} else {
(other, ep.body_idx)
};
pairs.push(pair);
}
}
active.push(ep.body_idx);
} else {
active.retain(|&x| x != ep.body_idx);
}
}
pairs
}
#[cfg(test)]
mod tests {
use super::*;
use crate::math::Vec3;
#[test]
fn test_sweep_and_prune_no_overlap() {
let aabbs = vec![
AABB::new(Vec3::new(0.0, 0.0, 0.0), Vec3::new(1.0, 1.0, 1.0)),
AABB::new(Vec3::new(2.0, 0.0, 0.0), Vec3::new(3.0, 1.0, 1.0)),
];
let pairs = sweep_and_prune(&aabbs);
assert_eq!(pairs.len(), 0);
}
#[test]
fn test_sweep_and_prune_overlap() {
let aabbs = vec![
AABB::new(Vec3::new(0.0, 0.0, 0.0), Vec3::new(1.5, 1.0, 1.0)),
AABB::new(Vec3::new(1.0, 0.0, 0.0), Vec3::new(2.0, 1.0, 1.0)),
];
let pairs = sweep_and_prune(&aabbs);
assert_eq!(pairs.len(), 1);
assert_eq!(pairs[0], (0, 1));
}
}