use crate::grid::point::Point3;
#[inline]
fn tet_volume(a: Point3, b: Point3, c: Point3, d: Point3) -> f64 {
(a - d).dot((b - d).cross(c - d)) / 6.0
}
#[must_use]
#[inline]
pub fn hexahedron_volume(c: &[Point3; 8]) -> f64 {
const TETS: [(usize, usize); 6] = [(1, 3), (3, 2), (2, 6), (6, 4), (4, 5), (5, 1)];
let v: f64 = TETS
.iter()
.map(|&(a, b)| tet_volume(c[0], c[a], c[b], c[7]))
.sum();
v.abs()
}
#[cfg(test)]
mod tests {
use super::*;
fn box_corners(lx: f64, ly: f64, lz: f64) -> [Point3; 8] {
let mut c = [Point3::new(0.0, 0.0, 0.0); 8];
for (idx, slot) in c.iter_mut().enumerate() {
let di = (idx & 1) as f64;
let dj = ((idx >> 1) & 1) as f64;
let dk = ((idx >> 2) & 1) as f64;
*slot = Point3::new(di * lx, dj * ly, dk * lz);
}
c
}
#[test]
fn unit_cube_is_one() {
assert!((hexahedron_volume(&box_corners(1.0, 1.0, 1.0)) - 1.0).abs() < 1e-12);
}
#[test]
fn box_volume_is_lx_ly_lz() {
let v = hexahedron_volume(&box_corners(10.0, 20.0, 3.0));
assert!((v - 600.0).abs() < 1e-9, "got {v}");
}
#[test]
fn sheared_cell_preserves_volume() {
let mut c = box_corners(10.0, 20.0, 3.0);
for corner in &mut c[4..8] {
corner.x += 5.0;
}
let v = hexahedron_volume(&c);
assert!(
(v - 600.0).abs() < 1e-9,
"shear should preserve volume, got {v}"
);
}
}