fix: imprint each surface once when fusing partial face contacts (#751)
Robustness seed 16 failed in most runs: the imprint split a block's side along both halves of a cylinder's round side, and the second split re-traced the first circle, sometimes leaving a sliver the glue could not match. The imprint now splits along each surface once (10/10 runs pass, 3/12 before). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
6f4a9d96fb
commit
11c03fb0ab
1 file changed
+25
@@ -473,6 +473,23 @@ fn faces_in(body: &Body, n: Vec3, d: f64, tol: f64) -> Vec<usize> {
|
||||
planes(body).into_iter().filter(|(_, p)| p.n.dot(n) > 1.0 - 1e-9 && (p.d - d).abs() < tol).map(|(i, _)| i).collect()
|
||||
}
|
||||
|
||||
/// Do faces `i` and `j` of `body` lie on one plane or one cylinder?
|
||||
fn same_surface(body: &Body, i: usize, j: usize, tol: f64) -> bool {
|
||||
match (crate::face_surface(body, i), crate::face_surface(body, j)) {
|
||||
(Some(crate::FaceSurface::Plane { normal: n1, point: p1 }), Some(crate::FaceSurface::Plane { normal: n2, point: p2 })) => {
|
||||
n1.dot(n2) > 1.0 - 1e-9 && n1.dot(p2 - p1).abs() < tol
|
||||
}
|
||||
(Some(crate::FaceSurface::Cylinder { .. }), Some(crate::FaceSurface::Cylinder { .. })) => {
|
||||
let c = cylinders(body);
|
||||
match (c.iter().find(|x| x.index == i), c.iter().find(|x| x.index == j)) {
|
||||
(Some(x), Some(y)) => same_cylinder(x, y, tol),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// `body` (with its history `h` over its operand) with its faces in the plane (n, d) split
|
||||
/// where the faces of `tool` next to the tool's faces in the opposite plane cross them: the
|
||||
/// outline of the tool's contact imprinted on the body's.
|
||||
@@ -488,7 +505,15 @@ fn imprinted(body: Body, mut h: Option<History>, n: Vec3, d: f64, tool: &Body, t
|
||||
beside.sort_unstable();
|
||||
beside.dedup();
|
||||
let mut body = body;
|
||||
// One split per surface: the halves of a round side lie on one cylinder, and splitting
|
||||
// along it again re-traces the line already there, leaving a sliver (or not) depending
|
||||
// on how the second trace falls.
|
||||
let mut used: Vec<usize> = Vec::new();
|
||||
for t in beside {
|
||||
if used.iter().any(|u| same_surface(tool, *u, t, tol)) {
|
||||
continue;
|
||||
}
|
||||
used.push(t);
|
||||
let faces = faces_in(&body, n, d, tol);
|
||||
if faces.is_empty() {
|
||||
break;
|
||||
|
||||
Reference in new issue
Block a user