diff --git a/crates/quadtree/src/lib.rs b/crates/quadtree/src/lib.rs index 95095a50..4a7f4d18 100644 --- a/crates/quadtree/src/lib.rs +++ b/crates/quadtree/src/lib.rs @@ -1,7 +1,10 @@ use glam::Vec2; use quadrants::{Quadrants, Rect}; +use tree::Tree; +mod packed; mod quadrants; +mod tree; pub struct Tree where diff --git a/crates/quadtree/src/packed.rs b/crates/quadtree/src/packed.rs new file mode 100644 index 00000000..db36552e --- /dev/null +++ b/crates/quadtree/src/packed.rs @@ -0,0 +1,37 @@ +use std::ops::{Deref, DerefMut}; + +pub(super) struct Packed(Vec); + +impl Packed { + pub(super) fn new() -> Self { + Self(Vec::new()) + } + + /// Removes an item from the Vec with O(1) efficiency. + /// + /// It can move another item to the new position as a side effect. The + /// original index of the moved item is returned in such a case. + pub(super) fn swap_remove(&mut self, index: usize) -> (T, Option) { + let removed = self.0.swap_remove(index); + let moved = if index < self.0.len() { + Some(self.0.len()) + } else { + None + }; + (removed, moved) + } +} + +impl Deref for Packed { + type Target = Vec; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for Packed { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} diff --git a/crates/quadtree/src/tree.rs b/crates/quadtree/src/tree.rs new file mode 100644 index 00000000..fc1c6a04 --- /dev/null +++ b/crates/quadtree/src/tree.rs @@ -0,0 +1,116 @@ +use crate::{packed::Packed, quadrants::Quadrants}; + +pub(super) struct Tree +where + S: Default, +{ + inner: Packed, + leafs: Packed>, +} + +impl Tree +where + S: Default, +{ + pub(super) fn new() -> Self { + let mut inner = Packed::new(); + // Add empty root. + inner.push(Inner::new(usize::MAX, Quadrants::default())); + Self { + inner, + leafs: Packed::new(), + } + } + + pub(super) fn get_leaf_mut(&self, index: usize) -> Option<&mut S> { + self.leafs.get_mut(index).map(|l| &mut l.item) + } + + // TODO remove + // TODO replace (auto crate the replacement) + + fn replace(&mut self, node: Node, replacement: Option) -> Option { + let (removed_parent, moved, item) = match node { + Node::Inner(index) => { + if index == 0 { + panic!("Cannot remove or replace root node."); + } + + let (removed, moved) = self.inner.swap_remove(index); + (removed.parent, moved.map(|index| Node::Inner(index)), None) + } + Node::Leaf(index) => { + let (removed, moved) = self.leafs.swap_remove(index); + ( + removed.parent, + moved.map(|index| Node::Leaf(index)), + Some(removed.item), + ) + } + }; + + self.inner + .get_mut(removed_parent) + .unwrap() + .replace_child(node, replacement); + + if let Some(moved) = moved { + let moved_parent = match node { + Node::Inner(index) => self.inner.get(index).unwrap().parent, + Node::Leaf(index) => self.leafs.get(index).unwrap().parent, + }; + + self.inner + .get_mut(moved_parent) + .unwrap() + .replace_child(moved, Some(node)); + } + + item + } +} + +// TODO rename to Node +#[derive(Clone, Copy, PartialEq, Eq)] +enum Node { + // TODO consider compressing usize to something smaller & saving the extra + // byte for enum + Inner(usize), + Leaf(usize), +} + +struct Inner { + // TODO consider using MAX value for no parent + // TODO consider using something smaller than usize + parent: usize, + children: Quadrants, +} + +impl Inner { + fn new(parent: usize, children: Quadrants) -> Self { + Self { parent, children } + } + + fn replace_child(&mut self, old: Node, new: Option) { + self.children.replace(&old, new); + } +} + +struct Leaf { + // TODO consider using something smaller than usize + parent: usize, + // TODO consider using different array len + item: S, +} + +impl Leaf +where + S: Default, +{ + fn new(parent: usize) -> Self { + Self { + parent, + item: S::default(), + } + } +}