Sheet metal: sew the folded-material guard per piece so adjacent flanges cut (#296) (#355)

The guard that refuses machining through bends sewed every bend zone and
nonparallel panel into one solid. Two bends meeting at an open corner relief
share only an edge, so that sew failed with "nonmanifold edge contact" and any
cut on the base was refused. Sew and test each piece on its own instead.

Reference case 75-sm-bracket-holes now passes; its known_failure mark is removed.

Fixes #296


Claude-Session: https://claude.ai/code/session_01RjGw4gA5ZvKrU8MQP6sBgT

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
bherbruckandClaude Opus 5.5 authored and GitHub committed 2026-10-12 14:27:40 -04:00
1 parent 7db66bb824
commit 2ebceb6918
6 files changed
+42 -13

No files matched your search

+1 -1
View File
@@ -687,7 +687,7 @@ pub(super) fn sheet_cut(
plans.push((sh.body.clone(), Some((sh, mb.body.clone()))));
continue;
}
if let Some(bends) = sh.unmodeled_solid(&ss.plane)? {
for bends in sh.unmodeled_solids(&ss.plane)? {
for tool in tools {
if kernel::boolean(&bends, tool, kernel::BoolOp::Intersect)?.is_some() {
return Err(DocError::Invalid(
+7 -7
View File
@@ -879,10 +879,13 @@ impl SheetBody {
Ok(body)
}
/// Actual curved material, used to certify unsupported folded machining before mutation.
pub(crate) fn unmodeled_solid(&self, plane: &Plane) -> Result<Option<Body>> {
/// Actual curved material, used to certify unsupported folded machining before mutation:
/// one solid per bend zone or nonparallel panel. Each is sewn on its own, because the
/// selected pieces need not form a manifold solid together (two bends meeting at an open
/// corner relief touch only along an edge).
pub(crate) fn unmodeled_solids(&self, plane: &Plane) -> Result<Vec<Body>> {
if self.flat || self.flanges.is_empty() {
return Ok(None);
return Ok(Vec::new());
}
let mut work = FlatWork::new();
let cells: Vec<_> = self
@@ -893,10 +896,7 @@ impl SheetBody {
Piece::Panel(pi) => apply_vector(&self.world(pi), Vec3::Z).cross(plane.normal()).len() > 1e-6,
})
.collect();
if cells.is_empty() {
return Ok(None);
}
Ok(Some(kernel::sew(&self.faces(&cells, 0.0, self.t, &mut work)?)?))
cells.iter().map(|c| Ok(kernel::sew(&self.faces(std::slice::from_ref(c), 0.0, self.t, &mut work)?)?)).collect()
}
fn through_pocket_regions(&self, work: &mut FlatWork) -> Result<Vec<Region2>> {