|
|
|
@ -71,16 +71,12 @@ impl<T: Default + Copy + Eq> ChunkedOctree<T> { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub fn find<'a, W, F>( |
|
|
|
|
&'a self, |
|
|
|
|
from: impl IntoIterator<Item = &'a ChunkPos>, |
|
|
|
|
priority_fn: F, |
|
|
|
|
) -> OctreeIterator<'a, T, W, F> |
|
|
|
|
pub fn find<'a, W, F>(&'a self, priority_fn: F) -> OctreeIterator<'a, T, W, F> |
|
|
|
|
where |
|
|
|
|
W: Ord, |
|
|
|
|
F: Fn(OctreeNode, T) -> Option<W>, |
|
|
|
|
{ |
|
|
|
|
OctreeIterator::new(self, from, priority_fn) |
|
|
|
|
OctreeIterator::new(self, priority_fn) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -102,27 +98,22 @@ where |
|
|
|
|
P: Ord, |
|
|
|
|
F: Fn(OctreeNode, T) -> Option<P>, |
|
|
|
|
{ |
|
|
|
|
fn new( |
|
|
|
|
octree: &'a ChunkedOctree<T>, |
|
|
|
|
from: impl IntoIterator<Item = &'a ChunkPos>, |
|
|
|
|
priority_fn: F, |
|
|
|
|
) -> Self { |
|
|
|
|
fn new(octree: &'a ChunkedOctree<T>, priority_fn: F) -> Self { |
|
|
|
|
let mut result = Self { |
|
|
|
|
octree, |
|
|
|
|
checked: Default::default(), |
|
|
|
|
queue: Default::default(), |
|
|
|
|
priority_fn, |
|
|
|
|
}; |
|
|
|
|
for pos in from { |
|
|
|
|
let node_pos: ZOrderIndex = (*pos).try_into().unwrap(); |
|
|
|
|
result.search_region(node_pos >> octree.depth); |
|
|
|
|
for region_pos in octree.regions.keys() { |
|
|
|
|
result.search_region(*region_pos); |
|
|
|
|
} |
|
|
|
|
result |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fn search_region(&mut self, region_pos: ZOrderIndex) { |
|
|
|
|
if self.checked.insert(region_pos) { |
|
|
|
|
self.push_item((self.octree.depth, region_pos).into()); |
|
|
|
|
self.push_item(OctreeNode::new(self.octree.depth, region_pos)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -198,30 +189,38 @@ impl OctreeNode { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub fn children(&self) -> Option<[Self; 8]> { |
|
|
|
|
(self.level > 0).then(|| from_fn(|i| self.child_unchecked(i as u64))) |
|
|
|
|
(self.level > 0).then(|| { |
|
|
|
|
let (level, pos) = (self.level - 1, self.pos << 1); |
|
|
|
|
from_fn(|i| Self::new(level, pos | i as u64)) |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub fn siblings(&self) -> [Self; 8] { |
|
|
|
|
let pos = self.pos & !0b111; |
|
|
|
|
from_fn(|i| Self::new(self.level, pos | i as u64)) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub fn neighbors(&self) -> [Self; 26] { |
|
|
|
|
#[rustfmt::skip] |
|
|
|
|
const DIRECTIONS: [(i32, i32, i32); 26] = [ |
|
|
|
|
// Sides
|
|
|
|
|
(-1, 0, 0), (1, 0, 0), (0, -1, 0), (0, 1, 0), (0, 0, -1), (0, 0, 1), |
|
|
|
|
// Edges
|
|
|
|
|
(-1, -1, 0), (-1, 1, 0), (-1, 0, -1), (-1, 0, 1), |
|
|
|
|
( 0, -1, -1), ( 0, -1, 1), ( 0, 1, -1), ( 0, 1, 1), |
|
|
|
|
( 1, -1, 0), ( 1, 1, 0), ( 1, 0, -1), ( 1, 0, 1), |
|
|
|
|
// Corners
|
|
|
|
|
(-1, -1, -1), ( 1, -1, -1), (-1, 1, -1), ( 1, 1, -1), |
|
|
|
|
(-1, -1, 1), ( 1, -1, 1), (-1, 1, 1), ( 1, 1, 1), |
|
|
|
|
]; |
|
|
|
|
|
|
|
|
|
let (pos_x, pos_y, pos_z) = self.pos.into(); |
|
|
|
|
let mut result = [OctreeNode::default(); 26]; |
|
|
|
|
let mut index = 0; |
|
|
|
|
for x in -1..1 { |
|
|
|
|
for y in -1..1 { |
|
|
|
|
for z in -1..1 { |
|
|
|
|
if x != 0 && y != 0 && z != 0 { |
|
|
|
|
let pos = zorder(pos_x + x, pos_y + y, pos_z + z); |
|
|
|
|
result[index] = OctreeNode::new(self.level, pos); |
|
|
|
|
index += 1; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
result |
|
|
|
|
DIRECTIONS.map(|(x, y, z)| Self::new(self.level, zorder(pos_x + x, pos_y + y, pos_z + z))) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub fn region(&self) -> ChunkRegion { |
|
|
|
|
let min = (self.pos << self.level).into(); |
|
|
|
|
let max = min + IVec3::splat((1 << self.level) - 1); |
|
|
|
|
let max = min + IVec3::splat(!(!0 << self.level)); |
|
|
|
|
ChunkRegion::new_unchecked(min, max) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -231,19 +230,7 @@ impl OctreeNode { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fn children_index(&self, depth: usize) -> Option<usize> { |
|
|
|
|
(self.level > 0).then(|| self.child_unchecked(0).index(depth)) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// Returns the child of this node with the specified index (within `0..8`).
|
|
|
|
|
/// No safety checks are done to ensure that `level` or `index` are valid.
|
|
|
|
|
fn child_unchecked(&self, index: u64) -> Self { |
|
|
|
|
Self::new(self.level - 1, (self.pos << 1) | index) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
impl Into<OctreeNode> for (usize, ZOrderIndex) { |
|
|
|
|
fn into(self) -> OctreeNode { |
|
|
|
|
OctreeNode::new(self.0, self.1) |
|
|
|
|
(self.level > 0).then(|| Self::new(self.level - 1, self.pos << 1).index(depth)) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -271,7 +258,7 @@ impl<T: Default + Copy + Eq, P: Ord> Eq for PriorityItem<T, P> {} |
|
|
|
|
|
|
|
|
|
impl<T: Default + Copy + Eq, P: Ord> PartialEq for PriorityItem<T, P> { |
|
|
|
|
fn eq(&self, other: &Self) -> bool { |
|
|
|
|
self.priority.eq(&other.priority) |
|
|
|
|
(self.priority == other.priority) && (self.node == other.node) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -293,6 +280,10 @@ mod tests { |
|
|
|
|
|
|
|
|
|
#[test] |
|
|
|
|
fn update() { |
|
|
|
|
let node = |level: usize, pos: (i32, i32, i32)| -> OctreeNode { |
|
|
|
|
OctreeNode::new(level, pos.try_into().unwrap()) |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
let mut octree = ChunkedOctree::<bool>::new(3); |
|
|
|
|
|
|
|
|
|
assert_eq!(false, octree.get((0, 0, 0))); |
|
|
|
@ -302,28 +293,28 @@ mod tests { |
|
|
|
|
octree.update((0, 0, 0).into(), |_, _, parent| *parent = true); |
|
|
|
|
assert_eq!(true, octree.get((0, 0, 0))); |
|
|
|
|
|
|
|
|
|
assert_eq!(true, octree.get((0, zorder(0, 0, 0)))); |
|
|
|
|
assert_eq!(true, octree.get((1, zorder(0, 0, 0)))); |
|
|
|
|
assert_eq!(true, octree.get((2, zorder(0, 0, 0)))); |
|
|
|
|
assert_eq!(true, octree.get((3, zorder(0, 0, 0)))); |
|
|
|
|
assert_eq!(true, octree.get(node(0, (0, 0, 0)))); |
|
|
|
|
assert_eq!(true, octree.get(node(1, (0, 0, 0)))); |
|
|
|
|
assert_eq!(true, octree.get(node(2, (0, 0, 0)))); |
|
|
|
|
assert_eq!(true, octree.get(node(3, (0, 0, 0)))); |
|
|
|
|
|
|
|
|
|
assert_eq!(false, octree.get((0, zorder(1, 1, 1)))); |
|
|
|
|
assert_eq!(false, octree.get((1, zorder(2, 2, 2)))); |
|
|
|
|
assert_eq!(false, octree.get((2, zorder(4, 4, 4)))); |
|
|
|
|
assert_eq!(false, octree.get((3, zorder(8, 8, 8)))); |
|
|
|
|
assert_eq!(false, octree.get(node(0, (1, 1, 1)))); |
|
|
|
|
assert_eq!(false, octree.get(node(1, (2, 2, 2)))); |
|
|
|
|
assert_eq!(false, octree.get(node(2, (4, 4, 4)))); |
|
|
|
|
assert_eq!(false, octree.get(node(3, (8, 8, 8)))); |
|
|
|
|
|
|
|
|
|
assert_eq!(false, octree.get((0, zorder(-1, -1, -1)))); |
|
|
|
|
assert_eq!(false, octree.get((1, zorder(-1, -1, -1)))); |
|
|
|
|
assert_eq!(false, octree.get((2, zorder(-1, -1, -1)))); |
|
|
|
|
assert_eq!(false, octree.get((3, zorder(-1, -1, -1)))); |
|
|
|
|
assert_eq!(false, octree.get(node(0, (-1, -1, -1)))); |
|
|
|
|
assert_eq!(false, octree.get(node(1, (-1, -1, -1)))); |
|
|
|
|
assert_eq!(false, octree.get(node(2, (-1, -1, -1)))); |
|
|
|
|
assert_eq!(false, octree.get(node(3, (-1, -1, -1)))); |
|
|
|
|
|
|
|
|
|
octree.update(ChunkPos::new(-12, -17, -42), |_, _, parent| *parent = true); |
|
|
|
|
assert_eq!(true, octree.get((-12, -17, -42))); |
|
|
|
|
|
|
|
|
|
assert_eq!(true, octree.get((0, zorder(-12, -17, -42)))); |
|
|
|
|
assert_eq!(true, octree.get((1, zorder(-6, -9, -21)))); |
|
|
|
|
assert_eq!(true, octree.get((2, zorder(-3, -5, -11)))); |
|
|
|
|
assert_eq!(true, octree.get((3, zorder(-2, -3, -6)))); |
|
|
|
|
assert_eq!(true, octree.get(node(0, (-12, -17, -42)))); |
|
|
|
|
assert_eq!(true, octree.get(node(1, (-6, -9, -21)))); |
|
|
|
|
assert_eq!(true, octree.get(node(2, (-3, -5, -11)))); |
|
|
|
|
assert_eq!(true, octree.get(node(3, (-2, -3, -6)))); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#[test] |
|
|
|
@ -336,9 +327,9 @@ mod tests { |
|
|
|
|
octree.update(( 0, 16, -1).into(), |_, _, parent| *parent = true); |
|
|
|
|
octree.update(( 9, 9, 9).into(), |_, _, parent| *parent = true); |
|
|
|
|
|
|
|
|
|
let from = ChunkPos::new(8, 8, 8); |
|
|
|
|
let mut iterator = octree.find([&from], |node, value| { |
|
|
|
|
value.then(|| -node.region().distance_to_squared(from)) |
|
|
|
|
let pos = ChunkPos::new(8, 8, 8); |
|
|
|
|
let mut iterator = octree.find(|node, value| { |
|
|
|
|
value.then(|| -node.region().distance_to_squared(pos)) |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
assert_eq!(Some((( 8, 8, 8).into(), true, -(0*0 + 0*0 + 0*0))), iterator.next()); |
|
|
|
|