veloren_common/util/
spatial_grid.rs1use super::GridHasher;
2use vek::*;
3
4#[derive(Debug)]
5pub struct SpatialGrid {
6 grid: hashbrown::HashMap<Vec2<i32>, Vec<specs::Entity>, GridHasher>,
9 large_grid: hashbrown::HashMap<Vec2<i32>, Vec<specs::Entity>, GridHasher>,
10 lg2_cell_size: usize,
12 lg2_large_cell_size: usize,
14 radius_cutoff: u32,
18 largest_large_radius: u32,
26}
27
28impl SpatialGrid {
29 pub fn new(lg2_cell_size: usize, lg2_large_cell_size: usize, radius_cutoff: u32) -> Self {
30 Self {
31 grid: Default::default(),
32 large_grid: Default::default(),
33 lg2_cell_size,
34 lg2_large_cell_size,
35 radius_cutoff,
36 largest_large_radius: radius_cutoff,
37 }
38 }
39
40 pub fn insert(&mut self, pos: Vec2<i32>, radius: u32, entity: specs::Entity) {
42 if radius <= self.radius_cutoff {
43 let cell = pos.map(|e| e >> self.lg2_cell_size);
44 self.grid.entry(cell).or_default().push(entity);
45 } else {
46 let cell = pos.map(|e| e >> self.lg2_large_cell_size);
47 self.large_grid.entry(cell).or_default().push(entity);
48 self.largest_large_radius = self.largest_large_radius.max(radius);
49 }
50 }
51
52 pub fn in_aabr<'a>(&'a self, aabr: Aabr<i32>) -> impl Iterator<Item = specs::Entity> + 'a {
57 let iter = |max_entity_radius, grid: &'a hashbrown::HashMap<_, _, _>, lg2_cell_size| {
58 let min = aabr.min - max_entity_radius as i32;
60 let max = aabr.max + max_entity_radius as i32;
61 let min = min.map(|e| e >> lg2_cell_size);
63 let max = max.map(|e| (e + (1 << lg2_cell_size) - 1) >> lg2_cell_size);
64
65 (min.x..=max.x)
66 .flat_map(move |x| (min.y..=max.y).map(move |y| Vec2::new(x, y)))
67 .flat_map(move |cell| grid.get(&cell).into_iter().flatten())
68 .copied()
69 };
70
71 iter(self.radius_cutoff, &self.grid, self.lg2_cell_size).chain(iter(
72 self.largest_large_radius,
73 &self.large_grid,
74 self.lg2_large_cell_size,
75 ))
76 }
77
78 pub fn in_circle_aabr(
86 &self,
87 center: Vec2<f32>,
88 radius: f32,
89 ) -> impl Iterator<Item = specs::Entity> + '_ {
90 let center = center.map(|e| e as i32);
91 let radius = radius.ceil() as i32;
92 const CENTER_TRUNCATION_ERROR: i32 = 1;
94 let max_dist = radius + CENTER_TRUNCATION_ERROR;
95
96 let aabr = Aabr {
97 min: center - max_dist,
98 max: center + max_dist,
99 };
100
101 self.in_aabr(aabr)
102 }
103
104 pub fn clear(&mut self) {
105 self.grid.clear();
106 self.large_grid.clear();
107 self.largest_large_radius = self.radius_cutoff;
108 }
109}