use super::arrangement::Tri;
#[inline]
pub(crate) fn tetra_volume6(a: &[f64; 3], b: &[f64; 3], c: &[f64; 3], o: &[f64; 3]) -> f64 {
let a = [a[0] - o[0], a[1] - o[1], a[2] - o[2]];
let b = [b[0] - o[0], b[1] - o[1], b[2] - o[2]];
let c = [c[0] - o[0], c[1] - o[1], c[2] - o[2]];
let cr = [
b[1] * c[2] - b[2] * c[1],
b[2] * c[0] - b[0] * c[2],
b[0] * c[1] - b[1] * c[0],
];
a[0] * cr[0] + a[1] * cr[1] + a[2] * cr[2]
}
pub(crate) fn signed_volume6(tris: &[Tri]) -> f64 {
let mut lo = [f64::MAX; 3];
let mut hi = [f64::MIN; 3];
for t in tris {
for v in t {
for k in 0..3 {
lo[k] = lo[k].min(v[k]);
hi[k] = hi[k].max(v[k]);
}
}
}
if tris.is_empty() {
return 0.0;
}
let o = [
(lo[0] + hi[0]) * 0.5,
(lo[1] + hi[1]) * 0.5,
(lo[2] + hi[2]) * 0.5,
];
tris.iter()
.map(|t| tetra_volume6(&t[0], &t[1], &t[2], &o))
.sum()
}
pub(crate) fn signed_volume_of(tris: &[Tri]) -> f64 {
signed_volume6(tris) / 6.0
}
#[cfg(test)]
mod tests {
use super::*;
fn box_with_sliver_crack(offset: [f64; 3]) -> Vec<Tri> {
let lo = [offset[0], offset[1], offset[2]];
let hi = [offset[0] + 2.2, offset[1] + 2.2, offset[2] + 2.2];
let eps = 0.9; let p0 = [lo[0], lo[1], lo[2]];
let p1 = [hi[0], lo[1], lo[2]];
let p2 = [hi[0], hi[1], lo[2]];
let p3 = [lo[0], hi[1], lo[2]];
let p4 = [lo[0], lo[1], hi[2]];
let p5 = [hi[0], lo[1], hi[2]];
let p6 = [hi[0], hi[1], hi[2]];
let p6_cracked = [hi[0] + eps, hi[1] + eps * 0.6, hi[2] + eps * 1.3];
let p7 = [lo[0], hi[1], hi[2]];
vec![
[p0, p3, p2],
[p0, p2, p1],
[p4, p5, p6_cracked],
[p4, p6, p7],
[p0, p4, p7],
[p0, p7, p3],
[p1, p2, p6],
[p1, p6, p5],
[p0, p1, p5],
[p0, p5, p4],
[p3, p7, p6],
[p3, p6, p2],
]
}
#[test]
fn far_from_origin_sliver_crack_does_not_flip_the_sign_198779() {
let near = box_with_sliver_crack([0.0, 0.0, 0.0]);
let far = box_with_sliver_crack([300.0, 250.0, 410.0]);
let v_near = signed_volume6(&near);
let v_far = signed_volume6(&far);
assert!(
v_near > 0.0,
"control (near origin) should read outward-wound positive, got {v_near}"
);
assert!(
v_far > 0.0,
"far-from-origin operand flipped sign to {v_far} (near-origin control was \
{v_near}): the AABB-centre reference should make the sign independent of \
where the operand sits, same defect shape as #198779"
);
}
}