use super::*;
use crate::Vector3;
fn box_mesh(min: (f64, f64, f64), max: (f64, f64, f64)) -> Mesh {
let c = |x: f64, y: f64, z: f64| Point3::new(x, y, z);
let corners = [
c(min.0, min.1, min.2), c(max.0, min.1, min.2), c(max.0, max.1, min.2), c(min.0, max.1, min.2), c(min.0, min.1, max.2), c(max.0, min.1, max.2), c(max.0, max.1, max.2), c(min.0, max.1, max.2), ];
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::with_capacity(24, 36);
for idx in &faces {
let e1 = corners[idx[1]] - corners[idx[0]];
let e2 = corners[idx[2]] - corners[idx[0]];
let n = e1
.cross(&e2)
.try_normalize(1e-10)
.unwrap_or(Vector3::new(0.0, 0.0, 1.0));
let b = m.vertex_count() as u32;
m.add_vertex(corners[idx[0]], n);
m.add_vertex(corners[idx[1]], n);
m.add_vertex(corners[idx[2]], n);
m.add_vertex(corners[idx[3]], n);
m.add_triangle(b, b + 1, b + 2);
m.add_triangle(b, b + 2, b + 3);
}
m
}
#[test]
fn cut_changed_mesh_volume_drift_boundary_is_1e_3_relative() {
let cube = box_mesh((0.0, 0.0, 0.0), (1.0, 1.0, 1.0));
let vol_after = mesh_signed_volume(&cube).abs();
assert!((vol_after - 1.0).abs() < 1e-6, "sanity: unit cube volume ~1.0, got {vol_after}");
let tris = cube.triangle_count();
let not_changed = cut_changed_mesh(&cube, tris, 0.99901);
assert!(
!not_changed,
"a 0.099% volume drift is inside the 0.1% tolerance and must read as unchanged"
);
let changed = cut_changed_mesh(&cube, tris, 0.99899);
assert!(
changed,
"a 0.101% volume drift exceeds the 0.1% tolerance and must read as changed"
);
}
fn needle_and_anchor(poke: f64) -> Mesh {
let mut m = Mesh::with_capacity(6, 6);
let n = Vector3::new(0.0, 0.0, 1.0);
m.add_vertex(Point3::new(0.5, 0.5, 0.5), n);
m.add_vertex(Point3::new(0.5, 0.5, 0.6), n);
m.add_vertex(Point3::new(1.0 + poke, 0.5, 0.5), n);
m.add_triangle(0, 1, 2);
m.add_vertex(Point3::new(0.2, 0.2, 0.2), n);
m.add_vertex(Point3::new(0.3, 0.2, 0.2), n);
m.add_vertex(Point3::new(0.2, 0.3, 0.2), n);
m.add_triangle(3, 4, 5);
m
}
#[test]
fn drop_faces_outside_host_vertex_clearance_boundary_is_1e_3() {
let host = box_mesh((0.0, 0.0, 0.0), (1.0, 1.0, 1.0));
let kept = needle_and_anchor(0.0009);
let kept_tris_before = kept.triangle_count();
let out_kept = drop_faces_outside_host(kept, &host);
assert_eq!(
out_kept.triangle_count(),
kept_tris_before,
"a 0.9mm poke is within the 1mm vertex clearance; nothing should be dropped"
);
let dropped = needle_and_anchor(0.0011);
let out_dropped = drop_faces_outside_host(dropped, &host);
assert_eq!(
out_dropped.triangle_count(),
1,
"a 1.1mm poke exceeds the 1mm vertex clearance; the needle triangle must be dropped, \
leaving only the anchor triangle"
);
}