test: failing regression test for #263: sheet.fold accepts a fixed point that is not on the sheet (#278)

* test: reproduce #263 (sheet.fold accepts a fixed point that is not on the sheet)

* fix(sheet): refuse a fold's fixed point that lies off the sheet's material (#263)

A fixed point inside a cut-out or outside the base outline (in the panel's
thickness) silently picked a side. Refuse it with an error that names the
point; side-face picks and points on other panels keep working.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01RjGw4gA5ZvKrU8MQP6sBgT

---------

Co-authored-by: bherbruck <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
This commit is contained in:
authored and GitHub committed 2026-10-12 10:56:29 -04:00
1 parent b45cae1e48
commit 93fd18eaad
2 files changed
+42 -1

No files matched your search

+23 -1
View File
@@ -1355,7 +1355,29 @@ impl SheetBody {
}
(None, Some(p)) => {
let q = apply_point(&inv, p);
Vec2::new(q.x, q.y).dot(n) < l0
let q2 = Vec2::new(q.x, q.y);
// A point in the panel's slab must be on material: inside the outline and
// outside every cut-out (a side face of either counts as material).
let near = |poly: &[Vec2]| {
let m = poly.len();
(0..m).any(|i| match (poly.get(i), poly.get((i + 1) % m)) {
(Some(&a), Some(&b)) => {
let d = b - a;
let t = if d.len2() > 1e-18 { ((q2 - a).dot(d) / d.len2()).clamp(0.0, 1.0) } else { 0.0 };
(a + d * t).dist(q2) < 1e-3
}
_ => false,
})
};
let in_slab = q.z > -1e-4 && q.z < self.t + 1e-4;
let in_hole = self.holes.iter().any(|h| h.contains(q2) && !near(&h.outer.ccw().polyline(1e-3)));
if in_slab && ((!point_in(&pts, q2) && !near(&pts)) || in_hole) {
return Err(DocError::Invalid(format!(
"the fixed point ({:.3}, {:.3}, {:.3}) is not on the sheet: pick a point on the face of the side that stays",
p.x, p.y, p.z
)));
}
q2.dot(n) < l0
}
(None, None) => side_area(n) <= side_area(n * -1.0),
};