use std::fmt;
use *;
pub struct Octree<T: Collider> {
colliders: Vec<T>,
collider_garbage: Vec<Id>,
nodes: Vec<Node>,
garbage: Vec<Id>,
bcube: BCube,
root: Id,
n_colliders: u32,
}
const LINK: usize = 15; const LEAF: u32 = 0xFF_FF_FF_FF;
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub struct Id(u32);
impl Id {
fn none() -> Self {
Id(0)
}
fn is_none(&self) -> bool {
self.0 == 0
}
fn is_some(&self) -> bool {
!self.is_none()
}
}
impl Into<Id> for usize {
fn into(self) -> Id {
Id(self as u32 + 1)
}
}
impl Into<usize> for Id {
fn into(self) -> usize {
(self.0 - 1) as usize
}
}
struct Node {
child: [Id; 16],
}
impl fmt::Display for Node {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.is_leaf() {
let l = self.link();
if l.is_some() {
write!(f, " LINK ")?;
}
for i in 0..=14 {
let id = self.child[i];
if id.is_some() {
let id: usize = id.into();
write!(f, "{} ", id)?;
}
}
} else {
write!(f, "Branch: [")?;
for i in 8..=14 {
let id = self.child[i];
if id.is_some() {
let id: usize = id.into();
write!(f, "{} ", id)?;
}
}
write!(f, "] -D [")?;
for i in 0..8 {
let id = self.child[i];
if id.is_some() {
let id: usize = id.into();
write!(f, "{}:{}", i, id)?;
}
}
write!(f, "];")?;
}
Ok(())
}
}
impl fmt::Debug for Node {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.is_leaf() {
try!(write!(f, "leaf"));
let l = self.link();
if l.is_some() {
try!(write!(f, " link: {:?}", l));
}
Ok(())
} else {
write!(f, "branch: {:?}", self.child)
}
}
}
impl Node {
fn new_leaf() -> Node {
Node {
child: [
Id(LEAF), Id::none(), Id::none(), Id::none(),
Id::none(), Id::none(), Id::none(), Id::none(),
Id::none(), Id::none(), Id::none(), Id::none(),
Id::none(), Id::none(), Id::none(), Id::none()
],
}
}
fn new_branch() -> Node {
Node {
child: [Id::none(); 16],
}
}
fn is_leaf(&self) -> bool {
self.child[0] == Id(LEAF)
}
fn is_branch(&self) -> bool {
!self.is_leaf()
}
fn link(&self) -> Option<usize> {
if self.child[LINK].is_none() {
None
} else {
Some(self.child[LINK].into())
}
}
fn is_empty(&self) -> bool {
assert!(self.is_branch());
for i in &self.child[..=14] { if i.is_some() {
return false }
}
true }
fn branch_is_one(&self) -> Option<usize> {
assert!(self.is_branch());
let mut found = None;
for i in 0..8 { if self.child[i].is_some() {
if found.is_some() { return None;
} else {
found = Some(i);
}
}
}
for i in &self.child[8..=14] { if i.is_some() {
return None }
}
found
}
fn branch_open_slot(&self) -> Option<usize> {
assert!(self.is_branch());
for i in 8..=14 {
if self.child[i].is_none() { return Some(i) }
}
None
}
fn branch_add_collider(&mut self, id: Id) -> Option<()> {
assert!(self.is_branch());
let s = self.branch_open_slot()?;
self.child[s] = id;
Some(())
}
fn branch_remove_collider(&mut self, id: Id) -> Option<()> {
assert!(self.is_branch());
for i in 8..=14 {
if self.child[i] == id {
self.child[i] = Id::none();
return Some(());
}
}
return None;
}
fn leaf_remove_collider(&mut self, id: Id) -> Option<()> {
assert!(self.is_leaf());
for i in 1..=14 {
if self.child[i] == id {
self.child[i] = Id::none();
return Some(());
}
}
return None;
}
fn remove_collider(&mut self, id: Id) -> Option<()> {
if self.is_branch() {
self.branch_remove_collider(id)
} else {
self.leaf_remove_collider(id)
}
}
fn which_child2(c: Vector, p: Vector) -> [bool; 3] {
[p.x < c.x, p.y < c.y, p.z < c.z]
}
fn which_child_bbox(c: Vector, mut p: BBox) -> Option<usize> {
if p.min.x >= c.x - ::std::f32::EPSILON && p.min.x <= c.x + ::std::f32::EPSILON {
p.min.x = p.max.x;
}
if p.min.y >= c.y - ::std::f32::EPSILON && p.min.y <= c.y + ::std::f32::EPSILON {
p.min.y = p.max.y;
}
if p.min.z >= c.z - ::std::f32::EPSILON && p.min.z <= c.z + ::std::f32::EPSILON {
p.min.z = p.max.z;
}
if p.max.x >= c.x - ::std::f32::EPSILON && p.max.x <= c.x + ::std::f32::EPSILON {
p.max.x = p.min.x;
}
if p.max.y >= c.y - ::std::f32::EPSILON && p.max.y <= c.y + ::std::f32::EPSILON {
p.max.y = p.min.y;
}
if p.max.z >= c.z - ::std::f32::EPSILON && p.max.z <= c.z + ::std::f32::EPSILON {
p.max.z = p.min.z;
}
let min = Self::which_child2(c, p.min);
let max = Self::which_child2(c, p.max);
if max != min {
return None;
}
let a = Some(match (min[0], min[1], min[2]) {
(true, true, true) => 0,
(true, true, false) => 1,
(true, false, true) => 2,
(true, false, false) => 3,
(false, true, true) => 4,
(false, true, false) => 5,
(false, false, true) => 6,
(false, false, false) => 7,
});
a
}
fn child_center(ch: usize, c: Vector, h: f32) -> Vector {
match ch {
0 => Vector::new(c.x - h, c.y - h, c.z - h),
1 => Vector::new(c.x - h, c.y - h, c.z + h),
2 => Vector::new(c.x - h, c.y + h, c.z - h),
3 => Vector::new(c.x - h, c.y + h, c.z + h),
4 => Vector::new(c.x + h, c.y - h, c.z - h),
5 => Vector::new(c.x + h, c.y - h, c.z + h),
6 => Vector::new(c.x + h, c.y + h, c.z - h),
7 => Vector::new(c.x + h, c.y + h, c.z + h),
a => panic!("ch must be 0-7, not {}", a),
}
}
fn child_bcube(ch: usize, bcube: BCube) -> BCube {
assert!(bcube.half_len > 0.1);
let half_len = bcube.half_len / 2.0;
let center = Node::child_center(ch, bcube.center, half_len);
BCube { center: center, half_len: half_len }
}
}
impl<T> Octree<T> where T: Collider {
pub fn new() -> Octree<T> {
let o = Octree {
colliders: vec![],
collider_garbage: vec![],
nodes: vec![],
garbage: vec![],
bcube: BCube::empty(),
root: Id::none(),
n_colliders: 0,
};
o
}
pub fn clear(&mut self) {
*self = Self::new();
}
pub fn add(&mut self, point: T) -> Id {
let id = if let Some(id) = self.collider_garbage.pop() {
unsafe {
::std::ptr::copy_nonoverlapping(&point,
&mut self.colliders[{ let id: usize = id.into(); id }], 1);
}
::std::mem::forget(point); id
} else {
self.colliders.push(point);
Id(self.colliders.len() as u32)
};
match self.n_colliders {
0 => self.add_0(id),
_ => self.add_n(id),
}
self.n_colliders += 1;
id
}
fn add_0(&mut self, id: Id) {
assert!(self.n_colliders == 0);
self.nodes.clear();
self.garbage.clear();
self.bcube = self[id].bbox().into();
let i = self.new_branch();
self.nodes[{ let i: usize = i.into(); i }].branch_add_collider(id).unwrap();
self.root = i;
}
fn add_n(&mut self, id: Id) {
assert!(self.n_colliders > 0);
let bbox = self[id].bbox();
while !bbox.collide_bcube(self.bcube) {
self.grow_root(bbox);
}
let bcube = self.bcube;
let root = self.root;
self.add_inside(id, root, bcube);
}
fn grow_root(&mut self, bbox: BBox) {
assert!(!bbox.collide_bcube(self.bcube));
assert!(self.nodes[{ let a: usize = self.root.into(); a }].is_branch());
let old_bc = self.bcube;
self.bcube.extend(bbox);
let ch = Node::which_child_bbox(self.bcube.center, old_bc.to_bbox()).unwrap();
let id = self.new_branch();
self.nodes[{ let a: usize = id.into(); a }].child[ch] = self.root;
self.root = id;
}
fn add_inside(&mut self, id: Id, node_id: Id, bcube: BCube) {
let bbox = self[id].bbox();
let node_id: usize = node_id.into();
assert!(bbox.collide_bcube(bcube));
assert!(self.nodes[node_id].is_branch());
if self.nodes[node_id].branch_add_collider(id).is_none() {
for i in 8..=14 {
let collider = self.nodes[node_id].child[i];
if self.add_down(collider, node_id, bcube) {
self.nodes[node_id].child[i]
= Id::none();
}
}
if self.add_down(id, node_id, bcube) {
return;
}
if self.nodes[node_id].branch_add_collider(id)
.is_none() {
let link_id = self.new_leaf();
self.nodes[node_id].child[LINK]
= link_id;
}
}
}
fn add_down(&mut self, id: Id, node_id: usize, bcube: BCube) -> bool {
let bbox = self[id].bbox();
if let Some(ch) = Node::which_child_bbox(bcube.center, bbox) {
let j = self.nodes[node_id].child[ch];
let bc = Node::child_bcube(ch, bcube);
if j.is_some() {
self.add_inside(id, j, bc);
} else {
let k = self.new_branch();
self.nodes[node_id].child[ch] = k;
self.nodes[{ let k: usize = k.into(); k }]
.branch_add_collider(id)
.unwrap(); }
true
} else {
false
}
}
fn new_node(&mut self, n: Node) -> Id {
if let Some(i) = self.garbage.pop() {
let k: usize = i.into();
self.nodes[k] = n;
k.into()
} else {
self.nodes.push(n);
Id(self.nodes.len() as u32)
}
}
fn new_leaf(&mut self) -> Id {
self.new_node(Node::new_leaf())
}
fn new_branch(&mut self) -> Id {
self.new_node(Node::new_branch())
}
pub fn remove(&mut self, id: Id) -> T {
assert!(self.n_colliders > 0);
let bcube = self.bcube;
let root = self.root;
let clear = self.remove_inside(id, root, bcube).is_some();
self.collider_garbage.push(id);
loop {
let root: usize = self.root.into();
if let Some(ch) = self.nodes[root].branch_is_one() {
self.garbage.push(self.root);
self.root = self.nodes[root].child[ch];
self.bcube = Node::child_bcube(ch, self.bcube);
} else {
break;
}
}
self.n_colliders -= 1;
let mut ret = unsafe { ::std::mem::uninitialized() };
unsafe {
::std::ptr::copy_nonoverlapping(
&self.colliders[{ let id: usize = id.into(); id }], &mut ret, 1);
}
if clear {
assert_eq!(self.n_colliders, 0);
self.clear();
}
ret
}
fn remove_inside(&mut self, id: Id, node_id: Id, bcube: BCube)
-> Option<Id>
{
let bbox = self[id].bbox();
let node_id: usize = node_id.into();
assert!(bbox.collide_bcube(bcube));
assert!(self.nodes[node_id].is_branch());
if let Some(ch) = Node::which_child_bbox(bcube.center, bbox) {
let j = self.nodes[node_id].child[ch];
if j.is_some() {
let bcube = Node::child_bcube(ch, bcube);
if let Some(rm)
= self.remove_inside(id, j, bcube)
{ assert_eq!(j, rm);
self.garbage.push(rm);
self.nodes[node_id].child[ch] =
Id::none();
}
if self.nodes[node_id].is_empty() {
Some(node_id.into())
} else {
None }
} else {
self.remove_from_branch(id, node_id)
}
} else {
self.remove_from_branch(id, node_id)
}
}
fn remove_from_branch(&mut self, id: Id, node_id: usize) -> Option<Id> {
if self.nodes[node_id].remove_collider(id)
.is_some() {
if self.nodes[node_id].is_empty() {
return Some(node_id.into());
} else {
return None;
}
}
let node_id = self.nodes[node_id].link()
.unwrap(); let rm = self.remove_from_branch(id, node_id);
if let Some(rm) = rm {
assert_eq!(rm, self.nodes[node_id].child[LINK]);
self.garbage.push(rm);
self.nodes[node_id].child[LINK] = Id::none();
}
None }
}
impl<T> ::std::ops::Index<Id> for Octree<T> where T: Collider {
type Output = T;
fn index<'a>(&'a self, index: Id) -> &'a T {
let index: usize = index.into();
&self.colliders[index]
}
}
impl<T> ::std::ops::IndexMut<Id> for Octree<T> where T: Collider {
fn index_mut<'a>(&'a mut self, index: Id) -> &'a mut T {
let index: usize = index.into();
&mut self.colliders[index]
}
}
impl<T> fmt::Display for Octree<T> where T: Collider {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.root.is_none() {
write!(f, "No Root\n")?;
} else {
let root: usize = self.root.into();
write!(f, "Root {}:{:?}\n", root, self.bcube)?;
}
for i in 0..self.nodes.len() {
let id: Id = i.into();
if !self.garbage.contains(&id) {
writeln!(f, "{}: {}", i, self.nodes[i])?;
write!(f, "{}: ", i)?;
for j in 8..=14 { let index = self.nodes[i].child[j];
if index.is_some() {
write!(f, "{:?},", self[index].bbox())?;
}
}
writeln!(f, "")?;
}
}
write!(f, "")
}
}
impl<T> fmt::Debug for Octree<T> where T: Collider {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.root.is_none() {
write!(f, "No Root\n")?;
} else {
let root: usize = self.root.into();
write!(f, "root {}\n", root)?;
}
for i in 0..self.nodes.len() {
let id: Id = i.into();
if !self.garbage.contains(&id) {
write!(f, "{}: {:?}\n", i, self.nodes[i])?;
}
}
write!(f, "")
}
}