use super::helpers::{norm3, sub3};
#[derive(Debug, Clone)]
pub struct VoronoiSdf {
pub seeds: Vec<[f64; 3]>,
}
impl VoronoiSdf {
pub fn new(seeds: Vec<[f64; 3]>) -> Self {
Self { seeds }
}
pub fn evaluate(&self, p: [f64; 3]) -> f64 {
if self.seeds.is_empty() {
return f64::MAX;
}
let mut d1 = f64::MAX;
let mut d2 = f64::MAX;
for &s in &self.seeds {
let d = norm3(sub3(p, s));
if d < d1 {
d2 = d1;
d1 = d;
} else if d < d2 {
d2 = d;
}
}
(d2 - d1) * 0.5
}
pub fn nearest_seed(&self, p: [f64; 3]) -> usize {
self.seeds
.iter()
.enumerate()
.min_by(|(_, a), (_, b)| {
norm3(sub3(p, **a))
.partial_cmp(&norm3(sub3(p, **b)))
.unwrap_or(std::cmp::Ordering::Equal)
})
.map(|(i, _)| i)
.unwrap_or(0)
}
pub fn cell_ids(&self, nx: usize, ny: usize, nz: usize, bounds: [f64; 6]) -> Vec<usize> {
let dx = (bounds[1] - bounds[0]) / nx as f64;
let dy = (bounds[3] - bounds[2]) / ny as f64;
let dz = (bounds[5] - bounds[4]) / nz as f64;
let mut ids = Vec::with_capacity(nx * ny * nz);
for iz in 0..nz {
for iy in 0..ny {
for ix in 0..nx {
let p = [
bounds[0] + (ix as f64 + 0.5) * dx,
bounds[2] + (iy as f64 + 0.5) * dy,
bounds[4] + (iz as f64 + 0.5) * dz,
];
ids.push(self.nearest_seed(p));
}
}
}
ids
}
}