Skip to main content

arcane_engine/physics/
broadphase.rs

1use std::collections::{HashMap, HashSet};
2
3use super::types::BodyId;
4
5pub struct SpatialHash {
6    #[allow(dead_code)]
7    cell_size: f32,
8    inv_cell_size: f32,
9    cells: HashMap<(i32, i32), Vec<BodyId>>,
10}
11
12impl SpatialHash {
13    pub fn new(cell_size: f32) -> Self {
14        let cell_size = if cell_size > 0.0 { cell_size } else { 64.0 };
15        Self {
16            cell_size,
17            inv_cell_size: 1.0 / cell_size,
18            cells: HashMap::new(),
19        }
20    }
21
22    pub fn clear(&mut self) {
23        self.cells.clear();
24    }
25
26    /// Insert a body's AABB into all overlapping cells.
27    pub fn insert(&mut self, id: BodyId, min_x: f32, min_y: f32, max_x: f32, max_y: f32) {
28        let x0 = (min_x * self.inv_cell_size).floor() as i32;
29        let y0 = (min_y * self.inv_cell_size).floor() as i32;
30        let x1 = (max_x * self.inv_cell_size).floor() as i32;
31        let y1 = (max_y * self.inv_cell_size).floor() as i32;
32
33        for cx in x0..=x1 {
34            for cy in y0..=y1 {
35                self.cells.entry((cx, cy)).or_default().push(id);
36            }
37        }
38    }
39
40    /// Collect unique pairs of bodies that share at least one cell.
41    pub fn get_pairs(&self) -> Vec<(BodyId, BodyId)> {
42        let mut seen = HashSet::new();
43        let mut pairs = Vec::new();
44
45        for cell_bodies in self.cells.values() {
46            let n = cell_bodies.len();
47            for i in 0..n {
48                for j in (i + 1)..n {
49                    let a = cell_bodies[i];
50                    let b = cell_bodies[j];
51                    let pair = if a < b { (a, b) } else { (b, a) };
52                    if seen.insert(pair) {
53                        pairs.push(pair);
54                    }
55                }
56            }
57        }
58        pairs
59    }
60}