Through-all holes beside walls: a long thin tool keeps its outside out (#629)

Body::new no longer turns a long thin solid (a through-all hole's tool) inside out on the strength of a coarse mesh volume: it checks again on a fine mesh first. 79 more face.hole actions pass in the action matrix; the remaining no-result cuts stay under #559.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
bherbruckandClaude Opus 5.5 authored and GitHub committed 2026-10-13 05:39:48 -04:00
1 parent 8d58e3b9f9
commit bb60a95289
4 files changed
+115 -87

No files matched your search

+20 -7
View File
@@ -477,13 +477,26 @@ impl Body {
if lo.x.is_finite() { (hi - lo).len() } else { 1.0 }
};
let tol = (span * 0.01).clamp(1e-3, 1.0);
let (v, missing) = guard("orient", || {
let shells = mesh_shells(&solid, tol);
let volume = shells.iter().map(|s| s.to_polygon().volume()).sum::<f64>();
let missing =
shells.iter().flat_map(|s| s.face_iter()).filter(|f| f.surface().is_none_or(|m| m.faces().triangle_iter().next().is_none())).count();
Ok((volume, missing))
})?;
let orient = |tol: f64| {
guard("orient", || {
let shells = mesh_shells(&solid, tol);
let volume = shells.iter().map(|s| s.to_polygon().volume()).sum::<f64>();
let missing = shells
.iter()
.flat_map(|s| s.face_iter())
.filter(|f| f.surface().is_none_or(|m| m.faces().triangle_iter().next().is_none()))
.count();
Ok((volume, missing))
})
};
let (mut v, mut missing) = orient(tol)?;
// A long thin round part (a through hole's tool: a cylinder whose vertices all lie on
// its seam, so they span its length only) meshed that coarsely can come out with a
// negative volume when it is outward already: check finely before turning it inside out.
let fine = (tol * 0.02).max(1e-4);
if v < 0.0 && fine < tol {
(v, missing) = orient(fine)?;
}
if v < 0.0 {
solid.not();
}