use crate::octree::*;
use rayon::prelude::*;
pub struct DualGrid {
pub volumes: Vec<[MortonKey; 8]>,
}
impl DualGrid {
pub fn from_octree<T: Copy + Send + Sync>(octree: &HashedOctree<T>) -> Self {
let leaves = octree.leaves(MortonKey::root());
let volumes = leaves
.into_par_iter()
.map(|leaf| {
leaf2vert(leaf)
})
.flat_map_iter(|(vertex_lv, vertex_keys)| {
std::array::IntoIter::new(vertex_keys)
.enumerate()
.take_while(|(_vertex_i, vertex_k)| vertex_k != &MortonKey::none())
.flat_map(move |(vertex_i, vertex_k)| {
let neighbours = vert2leaf(vertex_k, vertex_lv);
std::iter::once(())
.take_while(move |()| {
for neighbour_i in 0..8 {
if neighbour_i == vertex_i {
continue;
}
let neighbour_k = neighbours[neighbour_i];
if !octree.node_exists(neighbour_k) {
continue;
}
if octree.is_subdivided(neighbour_k) {
return false;
}
if neighbour_i < vertex_i {
return false;
}
}
true
})
.map(move |()| {
let mut keys: [MortonKey; 8] =
unsafe { std::mem::MaybeUninit::uninit().assume_init() };
(0..8).for_each(|neighbour_i| {
let mut neighbour_k = neighbours[neighbour_i];
while neighbour_k != MortonKey::none()
&& !octree.node_exists(neighbour_k)
{
neighbour_k = neighbour_k.parent();
}
keys[neighbour_i] = neighbour_k;
});
keys
})
})
})
.collect();
Self { volumes }
}
}
const DIL_X: u64 = 0b001001001001001001001001001001001001001001001001001001001001001u64;
const DIL_Y: u64 = 0b010010010010010010010010010010010010010010010010010010010010010u64;
const DIL_Z: u64 = 0b100100100100100100100100100100100100100100100100100100100100100u64;
fn leaf2vert(key: MortonKey) -> (u32, [MortonKey; 8]) {
let level = key.level();
let level_key: u64 = 1 << (3 * level);
let mut keys: [MortonKey; 8] = unsafe { std::mem::MaybeUninit::uninit().assume_init() };
(0..8u64).into_iter().for_each(|vertex_i| {
let vertex_key = (((key.0 | !DIL_X) + (vertex_i & DIL_X)) & DIL_X)
| (((key.0 | !DIL_Y) + (vertex_i & DIL_Y)) & DIL_Y)
| (((key.0 | !DIL_Z) + (vertex_i & DIL_Z)) & DIL_Z);
keys[vertex_i as usize] = if (vertex_key >= (level_key << 1))
|| ((vertex_key - level_key) & DIL_X) == 0
|| ((vertex_key - level_key) & DIL_Y) == 0
|| ((vertex_key - level_key) & DIL_Z) == 0
{
MortonKey::none()
} else {
MortonKey(vertex_key)
};
});
(level, keys)
}
fn vert2leaf(vertex_k: MortonKey, vertex_lv: u32) -> [MortonKey; 8] {
let dc = vertex_k.0 << (vertex_lv - vertex_k.level()) * 3;
let mut keys: [MortonKey; 8] = unsafe { std::mem::MaybeUninit::uninit().assume_init() };
(0..8u64).into_iter().for_each(|node_i| {
keys[node_i as usize] = MortonKey(
(((dc & DIL_X) - (node_i & DIL_X)) & DIL_X)
| (((dc & DIL_Y) - (node_i & DIL_Y)) & DIL_Y)
| (((dc & DIL_Z) - (node_i & DIL_Z)) & DIL_Z),
);
});
keys
}