use super::isosurface_stuffing::{par_map, BackgroundGrid, MeshOracle};
use super::VolumeMeshParameters;
use crate::bounding_volume::Aabb;
#[cfg(not(feature = "std"))]
use crate::math::ComplexField;
use crate::math::{Real, Vector};
use crate::utils::hashmap::HashMap;
use alloc::vec::Vec;
const CORNERS: [[i32; 3]; 8] = [
[0, 0, 0],
[1, 0, 0],
[0, 1, 0],
[1, 1, 0],
[0, 0, 1],
[1, 0, 1],
[0, 1, 1],
[1, 1, 1],
];
struct Octree {
origin: Vector,
half: Real,
levels: u32,
dims: [i32; 3],
subdivided: HashMap<(u32, [i32; 3]), ()>,
}
impl Octree {
fn width(&self, level: u32) -> i32 {
2 << level
}
fn count(&self, level: u32) -> [i32; 3] {
core::array::from_fn(|k| self.dims[k] << (self.levels - level))
}
fn in_range(&self, level: u32, c: [i32; 3]) -> bool {
let count = self.count(level);
(0..3).all(|k| c[k] >= 0 && c[k] < count[k])
}
fn is_subdivided(&self, level: u32, c: [i32; 3]) -> bool {
self.subdivided.contains_key(&(level, c))
}
fn corner(&self, level: u32, c: [i32; 3], offset: [i32; 3]) -> [i32; 3] {
let width = self.width(level);
core::array::from_fn(|k| (c[k] + offset[k]) * width)
}
fn center(&self, level: u32, c: [i32; 3]) -> [i32; 3] {
let width = self.width(level);
core::array::from_fn(|k| c[k] * width + width / 2)
}
fn point(&self, v: [i32; 3]) -> Vector {
self.origin + Vector::new(v[0] as Real, v[1] as Real, v[2] as Real) * self.half
}
fn covering_leaf(&self, level: u32, c: [i32; 3]) -> Option<(u32, [i32; 3])> {
if !self.in_range(level, c) {
return None;
}
let mut current = self.levels;
loop {
let shifted: [i32; 3] = core::array::from_fn(|k| c[k] >> (current - level));
if !self.is_subdivided(current, shifted) {
return Some((current, shifted));
}
if current == level {
return None;
}
current -= 1;
}
}
fn split(&mut self, level: u32, c: [i32; 3]) {
debug_assert!(level > 0, "a finest octant has no children");
let _ = self.subdivided.insert((level, c), ());
}
fn leaves(&self) -> Vec<(u32, [i32; 3])> {
let mut leaves = Vec::new();
let mut stack: Vec<(u32, [i32; 3])> = Vec::new();
let roots = self.count(self.levels);
for k in 0..roots[2] {
for j in 0..roots[1] {
for i in 0..roots[0] {
stack.push((self.levels, [i, j, k]));
}
}
}
while let Some((level, c)) = stack.pop() {
if level > 0 && self.is_subdivided(level, c) {
for offset in CORNERS {
stack.push((level - 1, core::array::from_fn(|k| c[k] * 2 + offset[k])));
}
} else {
leaves.push((level, c));
}
}
leaves
}
fn has_finer_vertex(&self, level: u32, v: [i32; 3]) -> bool {
if level == 0 {
return false;
}
let finer = level - 1;
let width = self.width(finer);
if (0..3).any(|k| v[k].rem_euclid(width) != 0) {
return false;
}
let base: [i32; 3] = core::array::from_fn(|k| v[k] / width);
CORNERS.iter().any(|offset| {
let c: [i32; 3] = core::array::from_fn(|k| base[k] - offset[k]);
matches!(self.covering_leaf(finer, c), Some((leaf, _)) if leaf <= finer)
})
}
}
fn face_center(octree: &Octree, level: u32, c: [i32; 3], axis: usize, positive: bool) -> [i32; 3] {
let corners = face_corners(axis, positive).map(|offset| octree.corner(level, c, offset));
core::array::from_fn(|k| (corners[0][k] + corners[2][k]) / 2)
}
fn face_corners(axis: usize, positive: bool) -> [[i32; 3]; 4] {
let (u, v) = ((axis + 1) % 3, (axis + 2) % 3);
let base = i32::from(positive);
[[0, 0], [1, 0], [1, 1], [0, 1]].map(|[du, dv]| {
let mut corner = [0; 3];
corner[axis] = base;
corner[u] = du;
corner[v] = dv;
corner
})
}
pub(super) fn cover_octree_grid(
oracle: &MeshOracle,
aabb: Aabb,
params: &VolumeMeshParameters,
) -> Option<BackgroundGrid> {
let cell_size = params.cell_size;
let fine = cell_size / (1 << params.cover_subdivisions) as Real;
let levels = params.cover_subdivisions;
let coarse_width = cell_size;
let margin = cell_size * 2.0;
let origin = aabb.mins - Vector::splat(margin);
let dims: [i32; 3] = core::array::from_fn(|k| {
let extent = aabb.maxs[k] - aabb.mins[k] + margin * 2.0;
((extent / coarse_width).ceil() as i32).max(1)
});
let mut octree = Octree {
origin,
half: fine * 0.5,
levels,
dims,
subdivided: HashMap::default(),
};
let roots = octree.count(levels);
let mut frontier: Vec<[i32; 3]> = Vec::new();
for k in 0..roots[2] {
for j in 0..roots[1] {
for i in 0..roots[0] {
frontier.push([i, j, k]);
}
}
}
for level in (1..=levels).rev() {
let decisions: Vec<bool> = par_map(&frontier, |c| {
let octant = Aabb::new(
octree.point(octree.corner(level, *c, [0, 0, 0])),
octree.point(octree.corner(level, *c, [1, 1, 1])),
);
oracle.crosses_region(&octant)
});
let mut next = Vec::new();
for (c, split) in frontier.iter().zip(&decisions) {
if *split {
octree.split(level, *c);
for offset in CORNERS {
next.push(core::array::from_fn(|k| c[k] * 2 + offset[k]));
}
}
}
frontier = next;
if frontier.is_empty() {
break;
}
}
balance(&mut octree);
Some(background_grid(&octree))
}
fn balance(octree: &mut Octree) {
loop {
let leaves = octree.leaves();
let decisions: Vec<bool> = par_map(&leaves, |&(level, c)| {
if level == 0 {
return false;
}
let span = 1 << level;
let mut split = false;
'shell: for axis in 0..3 {
for side in [-1, span] {
for a in -1..=span {
for b in -1..=span {
let mut offset = [0; 3];
offset[axis] = side;
offset[(axis + 1) % 3] = a;
offset[(axis + 2) % 3] = b;
let neighbor: [i32; 3] =
core::array::from_fn(|k| c[k] * span + offset[k]);
let Some((neighbor_level, _)) = octree.covering_leaf(0, neighbor)
else {
continue;
};
if neighbor_level + 1 < level {
split = true;
break 'shell;
}
}
}
}
}
split
});
let mut changed = false;
for (&(level, c), split) in leaves.iter().zip(&decisions) {
if *split {
octree.split(level, c);
changed = true;
}
}
if !changed {
break;
}
}
}
fn background_grid(octree: &Octree) -> BackgroundGrid {
let leaves = octree.leaves();
let per_leaf: Vec<Vec<[[i32; 3]; 4]>> =
par_map(&leaves, |&(level, c)| leaf_cells(octree, level, c));
let coord_cells: Vec<[[i32; 3]; 4]> = per_leaf.into_iter().flatten().collect();
let mut coords: Vec<[i32; 3]> = coord_cells.iter().flatten().copied().collect();
#[cfg(feature = "parallel")]
{
use rayon::prelude::*;
coords.par_sort_unstable();
}
#[cfg(not(feature = "parallel"))]
coords.sort_unstable();
coords.dedup();
let mut ids: HashMap<[i32; 3], u32> = HashMap::default();
for (id, v) in coords.iter().enumerate() {
let _ = ids.insert(*v, id as u32);
}
let points = par_map(&coords, |v| octree.point(*v));
let cells = par_map(&coord_cells, |quad| quad.map(|v| ids[&v]));
BackgroundGrid { points, cells }
}
fn leaf_cells(octree: &Octree, level: u32, c: [i32; 3]) -> Vec<[[i32; 3]; 4]> {
let mut cells = Vec::new();
let center = octree.center(level, c);
for axis in 0..3 {
for positive in [false, true] {
let face: [[i32; 3]; 4] =
face_corners(axis, positive).map(|offset| octree.corner(level, c, offset));
let mut neighbor = c;
neighbor[axis] += if positive { 1 } else { -1 };
if octree.in_range(level, neighbor) && octree.is_subdivided(level, neighbor) {
let middle: [i32; 3] = core::array::from_fn(|k| (face[0][k] + face[2][k]) / 2);
for e in 0..4 {
let (a, b) = (face[e], face[(e + 1) % 4]);
let midpoint: [i32; 3] = core::array::from_fn(|k| (a[k] + b[k]) / 2);
if octree.has_finer_vertex(level, midpoint) {
cells.push([middle, center, a, midpoint]);
cells.push([middle, center, midpoint, b]);
} else {
cells.push([middle, center, a, b]);
}
}
continue;
}
match octree.covering_leaf(level, neighbor) {
Some((neighbor_level, neighbor_c)) if neighbor_level == level => {
if !positive {
continue;
}
let opposite = octree.center(neighbor_level, neighbor_c);
for e in 0..4 {
let (a, b) = (face[e], face[(e + 1) % 4]);
let midpoint: [i32; 3] = core::array::from_fn(|k| (a[k] + b[k]) / 2);
if octree.has_finer_vertex(level, midpoint) {
cells.push([center, opposite, a, midpoint]);
cells.push([center, opposite, midpoint, b]);
} else {
cells.push([center, opposite, a, b]);
}
}
}
other => {
let diagonal = other
.and_then(|(neighbor_level, neighbor_c)| {
let middle =
face_center(octree, neighbor_level, neighbor_c, axis, !positive);
face.iter().position(|v| *v == middle)
})
.unwrap_or(0);
let (a, b, cc, d) = (
face[diagonal],
face[(diagonal + 1) % 4],
face[(diagonal + 2) % 4],
face[(diagonal + 3) % 4],
);
cells.push([center, a, b, cc]);
cells.push([center, a, cc, d]);
}
}
}
}
cells
}