use crate::cell::AABBGridCell;
use crate::storage::{cell_range, SparseStorage};
use crate::AABB;
use slotmapd::{new_key_type, SlotMap};
pub type AABBGridObjects<O, AB> = SlotMap<AABBGridHandle, StoreObject<O, AB>>;
new_key_type! {
pub struct AABBGridHandle;
}
#[derive(Clone, Copy)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct StoreObject<O: Copy, AB: AABB> {
pub obj: O,
pub aabb: AB,
}
#[derive(Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct AABBGrid<O: Copy, AB: AABB> {
storage: SparseStorage<AABBGridCell>,
objects: AABBGridObjects<O, AB>,
}
impl<O: Copy, AB: AABB> AABBGrid<O, AB> {
pub fn new(cell_size: i32) -> Self {
Self {
storage: SparseStorage::new(cell_size),
objects: AABBGridObjects::default(),
}
}
pub fn clear(&mut self) -> impl Iterator<Item = (AB, O)> {
self.storage = SparseStorage::new(self.storage.cell_size());
let objs = std::mem::take(&mut self.objects);
objs.into_iter().map(|(_, o)| (o.aabb, o.obj))
}
pub fn insert(&mut self, aabb: AB, obj: O) -> AABBGridHandle {
let Self {
storage, objects, ..
} = self;
let h = objects.insert(StoreObject { obj, aabb });
cells_apply(storage, &aabb, |cell, sing_cell| {
cell.objs.push((h, sing_cell));
});
h
}
pub fn set_aabb(&mut self, handle: AABBGridHandle, aabb: AB) {
let obj = self
.objects
.get_mut(handle)
.expect("Object not in grid anymore");
let storage = &mut self.storage;
let old_ll = storage.cell_mut(obj.aabb.ll()).0;
let old_ur = storage.cell_mut(obj.aabb.ur()).0;
let ll = storage.cell_mut(aabb.ll()).0;
let ur = storage.cell_mut(aabb.ur()).0;
obj.aabb = aabb;
if old_ll == ll && old_ur == ur {
return;
}
for id in cell_range(old_ll, old_ur) {
let cell = storage.cell_mut_unchecked(id);
let p = match cell.objs.iter().position(|(x, _)| *x == handle) {
Some(x) => x,
None => return,
};
cell.objs.swap_remove(p);
}
let sing_cell = ll == ur;
for id in cell_range(ll, ur) {
let cell = storage.cell_mut_unchecked(id);
cell.objs.push((handle, sing_cell))
}
}
pub fn remove(&mut self, handle: AABBGridHandle) -> Option<O> {
let st = self.objects.remove(handle)?;
let storage = &mut self.storage;
cells_apply(storage, &st.aabb, |cell, _| {
for i in 0..cell.objs.len() {
if cell.objs[i].0 == handle {
cell.objs.swap_remove(i);
return;
}
}
});
Some(st.obj)
}
pub fn handles(&self) -> impl Iterator<Item = AABBGridHandle> + '_ {
self.objects.keys()
}
pub fn objects(&self) -> impl Iterator<Item = &O> + '_ {
self.objects.values().map(|x| &x.obj)
}
pub fn get(&self, id: AABBGridHandle) -> Option<&StoreObject<O, AB>> {
self.objects.get(id)
}
pub fn get_mut(&mut self, id: AABBGridHandle) -> Option<&mut StoreObject<O, AB>> {
self.objects.get_mut(id)
}
pub fn storage(&self) -> &SparseStorage<AABBGridCell> {
&self.storage
}
pub fn query(&self, aabb: AB) -> impl Iterator<Item = (AABBGridHandle, &AB, &O)> + '_ {
self.query_broad(aabb).filter_map(move |h| {
let obj = unsafe { self.objects.get_unchecked(h) };
if aabb.intersects(&obj.aabb) {
Some((h, &obj.aabb, &obj.obj))
} else {
None
}
})
}
pub fn query_broad(&self, bbox: AB) -> impl Iterator<Item = AABBGridHandle> + '_ {
let storage = &self.storage;
let ll_id = storage.cell_id(bbox.ll());
let ur_id = storage.cell_id(bbox.ur());
let iter = cell_range(ll_id, ur_id)
.flat_map(move |id| storage.cell(id))
.flat_map(|x| x.objs.iter().copied());
if ll_id == ur_id {
QueryIter::Simple(iter)
} else {
QueryIter::Dedup(
fnv::FnvHashSet::with_hasher(fnv::FnvBuildHasher::default()),
iter,
)
}
}
pub fn query_visitor(&self, aabb: AB, mut visitor: impl FnMut(AABBGridHandle, &AB, &O)) {
self.query_broad_visitor(aabb, move |h| {
let obj = unsafe { self.objects.get_unchecked(h) };
if aabb.intersects(&obj.aabb) {
visitor(h, &obj.aabb, &obj.obj)
}
})
}
pub fn query_broad_visitor(&self, bbox: AB, mut visitor: impl FnMut(AABBGridHandle)) {
let storage = &self.storage;
let ll_id = storage.cell_id(bbox.ll());
let ur_id = storage.cell_id(bbox.ur());
if ll_id == ur_id {
let cell = storage.cell(ll_id).unwrap();
for (h, _) in cell.objs.iter() {
visitor(*h);
}
return;
}
let mut dedup = fnv::FnvHashSet::with_hasher(fnv::FnvBuildHasher::default());
for celly in ll_id.1..=ur_id.1 {
for cellx in ll_id.0..=ur_id.0 {
let cell = match storage.cell((cellx, celly)) {
Some(x) => x,
None => continue,
};
for (h, sing_cell) in cell.objs.iter() {
if *sing_cell {
visitor(*h);
continue;
}
if dedup.insert(*h) {
visitor(*h);
}
}
}
}
}
pub fn len(&self) -> usize {
self.objects.len()
}
pub fn is_empty(&self) -> bool {
self.objects.is_empty()
}
}
fn cells_apply<AB: AABB>(
storage: &mut SparseStorage<AABBGridCell>,
bbox: &AB,
f: impl Fn(&mut AABBGridCell, bool),
) {
let ll = storage.cell_mut(bbox.ll()).0;
let ur = storage.cell_mut(bbox.ur()).0;
for id in cell_range(ll, ur) {
f(storage.cell_mut_unchecked(id), ll == ur)
}
}
enum QueryIter<T: Iterator<Item = (AABBGridHandle, bool)>> {
Simple(T),
Dedup(fnv::FnvHashSet<AABBGridHandle>, T),
}
impl<T: Iterator<Item = (AABBGridHandle, bool)>> Iterator for QueryIter<T> {
type Item = AABBGridHandle;
fn next(&mut self) -> Option<Self::Item> {
match self {
QueryIter::Simple(x) => x.next().map(|(x, _)| x),
QueryIter::Dedup(seen, x) => {
for (v, sing_cell) in x {
if sing_cell {
return Some(v);
}
if seen.insert(v) {
return Some(v);
}
}
None
}
}
}
}