fix: reject planar joins that displace original faces

This commit is contained in:
bherbruck committed 2026-10-10 22:53:44 -04:00
1 parent 74fed469dc
commit fc8b71956c
3 files changed
+94 -3

No files matched your search

+31
View File
@@ -317,6 +317,37 @@ fn planar_booleans_with_coincident_faces() {
assert!(rel(measure(&i).unwrap().volume, 250.0) < 1e-9);
}
#[test]
fn stepped_logo_join_never_moves_faces_to_hide_an_edge_pinch() {
let mut body = box_solid(Vec3::ZERO, Vec3::new(10.0, 20.0, 10.0)).unwrap();
for (i, (lo, hi)) in
[(Vec3::new(0.0, 0.0, 10.0), Vec3::new(10.0, 10.0, 20.0)), (Vec3::new(-10.0, 0.0, 10.0), Vec3::new(0.0, 10.0, 20.0))].into_iter().enumerate()
{
let tool = box_solid(lo, hi).unwrap();
body = boolean(&body, &tool, BoolOp::Union).unwrap().unwrap();
assert!(body.validity().is_empty());
let m = measure(&body).unwrap();
assert!((m.volume - (3000.0 + i as f64 * 1000.0)).abs() < 1e-6, "join {i}: {}", m.volume);
assert!((m.bbox.max.z - 20.0).abs() < 1e-9, "join {i}: {}", m.bbox.max.z);
let tops =
body.faces(0.01).unwrap().iter().filter(|f| f.plane_normal.is_some_and(|n| n.z > 0.999999) && (f.centroid.z - 20.0).abs() < 1e-9).count();
assert_eq!(tops, 1, "join {i}: the top must be a single selectable face");
assert!(m.bbox.min.dist(Vec3::new(if i == 0 { 0.0 } else { -10.0 }, 0.0, 0.0)) < 1e-9);
assert!(m.bbox.max.dist(Vec3::new(10.0, 20.0, 20.0)) < 1e-9);
}
let tool = box_solid(Vec3::new(-10.0, 10.0, 10.0), Vec3::new(0.0, 20.0, 20.0)).unwrap();
let error = boolean(&body, &tool, BoolOp::Union).unwrap_err();
assert!(error.to_string().contains("zero-thickness edge contact"), "{error}");
// An intentional overlap removes the pinch without any automatic displacement.
let overlap = box_solid(Vec3::new(-10.0, 10.0, 10.0), Vec3::new(0.1, 20.0, 20.0)).unwrap();
let joined = boolean(&body, &overlap, BoolOp::Union).unwrap().unwrap();
assert!(joined.validity().is_empty());
let m = measure(&joined).unwrap();
assert!((m.volume - 5010.0).abs() < 1e-6);
assert!(m.bbox.min.dist(Vec3::new(-10.0, 0.0, 0.0)) < 1e-9);
assert!(m.bbox.max.dist(Vec3::new(10.0, 20.0, 20.0)) < 1e-9);
}
#[test]
fn corner_boss_on_stepped_case_has_one_exact_top_face() {
let outer = box_solid(Vec3::new(-50.0, -25.0, 0.0), Vec3::new(50.0, 25.0, 25.0)).unwrap();