use crate::mesh::Mesh;
pub(crate) const WORLD_FRAME_OFFSET_M: f64 = 10_000.0;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) enum WorldFrameCase {
AtOrigin,
FarBaked,
}
pub(crate) const WORLD_FRAME_CASES: [WorldFrameCase; 2] =
[WorldFrameCase::AtOrigin, WorldFrameCase::FarBaked];
impl WorldFrameCase {
pub(crate) fn offset(self) -> [f64; 3] {
match self {
WorldFrameCase::AtOrigin => [0.0, 0.0, 0.0],
WorldFrameCase::FarBaked => [WORLD_FRAME_OFFSET_M, 0.0, 0.0],
}
}
}
pub(crate) fn placed_box_mesh(case: WorldFrameCase, min: [f64; 3], max: [f64; 3]) -> Mesh {
let off = case.offset();
let c = |sx: usize, sy: usize, sz: usize| {
[
(if sx == 0 { min[0] } else { max[0] }) + off[0],
(if sy == 0 { min[1] } else { max[1] }) + off[1],
(if sz == 0 { min[2] } else { max[2] }) + off[2],
]
};
let corners = [
c(0, 0, 0),
c(1, 0, 0),
c(1, 1, 0),
c(0, 1, 0),
c(0, 0, 1),
c(1, 0, 1),
c(1, 1, 1),
c(0, 1, 1),
];
let faces: [[usize; 4]; 6] = [
[0, 3, 2, 1],
[4, 5, 6, 7],
[0, 1, 5, 4],
[2, 3, 7, 6],
[0, 4, 7, 3],
[1, 2, 6, 5],
];
let mut m = Mesh::new();
for f in &faces {
let a = corners[f[0]];
let b = corners[f[1]];
let d = corners[f[2]];
let e1 = [b[0] - a[0], b[1] - a[1], b[2] - a[2]];
let e2 = [d[0] - a[0], d[1] - a[1], d[2] - a[2]];
let n = [
e1[1] * e2[2] - e1[2] * e2[1],
e1[2] * e2[0] - e1[0] * e2[2],
e1[0] * e2[1] - e1[1] * e2[0],
];
let len = (n[0] * n[0] + n[1] * n[1] + n[2] * n[2]).sqrt().max(1e-30);
let nn = [(n[0] / len) as f32, (n[1] / len) as f32, (n[2] / len) as f32];
let base = (m.positions.len() / 3) as u32;
for &i in f {
m.positions.extend_from_slice(&[
corners[i][0] as f32,
corners[i][1] as f32,
corners[i][2] as f32,
]);
m.normals.extend_from_slice(&nn);
}
m.indices
.extend_from_slice(&[base, base + 1, base + 2, base, base + 2, base + 3]);
}
m
}
pub(crate) fn ulp32(magnitude: f64) -> f64 {
let f = (magnitude.abs()) as f32;
if f == 0.0 {
return f64::from(f32::from_bits(1));
}
f64::from(f32::from_bits(f.to_bits() + 1)) - f64::from(f)
}
pub(crate) fn normal_projected_noise_bound(normal: [f64; 3], meshes: &[&Mesh]) -> f64 {
let mut extent = [0.0f64; 3];
for mesh in meshes {
for (i, &p) in mesh.positions.iter().enumerate() {
let a = i % 3;
let c = f64::from(p).abs();
if c > extent[a] {
extent[a] = c;
}
}
}
normal[0].abs() * ulp32(extent[0])
+ normal[1].abs() * ulp32(extent[1])
+ normal[2].abs() * ulp32(extent[2])
}
pub(crate) fn mesh_volume(mesh: &Mesh) -> f64 {
let p = |i: u32| {
let k = i as usize * 3;
[
f64::from(mesh.positions[k]),
f64::from(mesh.positions[k + 1]),
f64::from(mesh.positions[k + 2]),
]
};
let mut v = 0.0;
for t in mesh.indices.chunks_exact(3) {
let (a, b, c) = (p(t[0]), p(t[1]), p(t[2]));
v += (a[0] * (b[1] * c[2] - b[2] * c[1])
- a[1] * (b[0] * c[2] - b[2] * c[0])
+ a[2] * (b[0] * c[1] - b[1] * c[0]))
/ 6.0;
}
v.abs()
}