fix(sheet): a box or cylinder cut along the sheet normal is flat machining (#541) (#550)

A Box cut, or a Cylinder cut whose axis is the sheet's normal, machines a sheet metal body like the extrude cut of its footprint: through the sheet it's a cut-out (a cylinder an exact round one in the flat pattern and DXF), part way it's a pocket. Primitives at other angles or across a bend are still refused. Un-ignores the #541 regression test. Fixes #541.

Co-authored-by: jonaswre <[email protected]>
This commit is contained in:
Jonas Wrede authored and GitHub committed 2026-10-13 04:29:31 -04:00
1 parent 9e2a1eb993
commit 94ab54d1f5
4 files changed
+185 -54

No files matched your search

+28 -1
View File
@@ -2500,7 +2500,6 @@ fn a_hole_on_a_folded_panel_keeps_the_name_of_its_sketch_circle() {
}
#[test]
#[ignore = "fails until #541 is fixed"]
fn a_box_cut_straight_through_a_flat_sheet_is_a_cutout_like_the_extrude_cut() {
// A 10 x 10 box perpendicular to the sheet and through its whole thickness removes exactly
// what a sketch rectangle extruded through all removes, which is accepted today.
@@ -2518,6 +2517,34 @@ fn a_box_cut_straight_through_a_flat_sheet_is_a_cutout_like_the_extrude_cut() {
run(&mut s, "sheet.unfold", json!({}));
run(&mut s, "sheet.refold", json!({}));
assert!((volume(&mut s) - 14750.0).abs() < 1e-6);
// A cylinder along the sheet normal is a round hole, exact in the flat pattern and DXF.
run(&mut s, "solid.cylinder", json!({"base": [70, 30, -1], "radius": 5, "height": 5, "operation": "cut"}));
assert_eq!(flat(&mut s)["cutouts"].as_array().map(Vec::len), Some(2));
let dxf = run(&mut s, "sheet.export_dxf", json!({}))["dxf"].as_str().unwrap_or_default().to_string();
assert!(dxf.contains("CIRCLE"), "the hole stays a circle");
assert!((volume(&mut s) - (14750.0 - PI * 25.0 * 2.5)).abs() < 0.5);
// A box that only dents the top face is a pocket of constant depth.
run(&mut s, "solid.box", json!({"corner": [50, 10, 1.5], "length": 10, "width": 10, "height": 5, "operation": "cut"}));
let f = flat(&mut s);
assert_eq!(f["pockets"].as_array().map(Vec::len), Some(1));
assert_eq!(f["pockets"][0]["depth_mm"], 1.0);
// A box across a folded bend, or a cylinder lying in the sheet, is still 3D machining
// and still refused atomically.
let mut tilted = Session::default();
base(&mut tilted, 100.0, 60.0);
run(&mut tilted, "sheet.flange", json!({"edges": [[50, 0, 2.5]], "height": 20}));
let before = tilted.doc.to_json();
let error = tilted
.execute("solid.box", &json!({"corner": [40, -10, -5], "length": 20, "width": 20, "height": 40, "operation": "cut"}))
.unwrap_err()
.to_string();
assert!(error.contains("bend") || error.contains("preserv"), "{error}");
assert_eq!(tilted.doc.to_json(), before);
let error = s
.execute("solid.cylinder", &json!({"base": [10, 50, 1.25], "axis": "X", "radius": 1, "height": 20, "operation": "cut"}))
.unwrap_err()
.to_string();
assert!(error.contains("preserv"), "{error}");
}
#[test]