use crate::mesh::Mesh;
use rustc_hash::FxHashMap;
pub(crate) fn dedup_cut_vertices(cut: &Mesh, host: &Mesh) -> Mesh {
let cn = cut.positions.len() / 3;
if cn == 0 {
return cut.clone();
}
let mut mag = 1.0f32;
for &c in host.positions.iter().chain(cut.positions.iter()) {
mag = mag.max(c.abs());
}
let tol = (mag as f64) * (4.0 / 8_388_608.0);
let tol2 = tol * tol;
let cell = (tol * 4.0).max(f64::MIN_POSITIVE);
let key = |p: [f64; 3]| {
[
(p[0] / cell).floor() as i64,
(p[1] / cell).floor() as i64,
(p[2] / cell).floor() as i64,
]
};
let d2 = |a: [f64; 3], b: [f64; 3]| {
let d = [a[0] - b[0], a[1] - b[1], a[2] - b[2]];
d[0] * d[0] + d[1] * d[1] + d[2] * d[2]
};
let mut pool: FxHashMap<[i64; 3], Vec<[f64; 3]>> = FxHashMap::default();
for i in 0..host.positions.len() / 3 {
let p = [
host.positions[i * 3] as f64,
host.positions[i * 3 + 1] as f64,
host.positions[i * 3 + 2] as f64,
];
pool.entry(key(p)).or_default().push(p);
}
let mut out = cut.clone();
for i in 0..cn {
let p = [
out.positions[i * 3] as f64,
out.positions[i * 3 + 1] as f64,
out.positions[i * 3 + 2] as f64,
];
let base = key(p);
let mut best: Option<(f64, [f64; 3])> = None;
for dx in -1..=1 {
for dy in -1..=1 {
for dz in -1..=1 {
if let Some(b) = pool.get(&[base[0] + dx, base[1] + dy, base[2] + dz]) {
for q in b {
let dd = d2(p, *q);
if dd <= tol2 && best.map(|(x, _)| dd < x).unwrap_or(true) {
best = Some((dd, *q));
}
}
}
}
}
}
match best {
Some((_, q)) => {
out.positions[i * 3] = q[0] as f32;
out.positions[i * 3 + 1] = q[1] as f32;
out.positions[i * 3 + 2] = q[2] as f32;
}
None => pool.entry(base).or_default().push(p),
}
}
out
}