Tests: the arc-touching cut is checked by its volume and area, not its face count

cut_whose_end_touches_an_arc_side_leaves_no_sliver compared the touching cut's
face count with a clear cut's, a count of how the kernel splits its faces. It
now compares what the two parts are.

The plate's arc runs from (0, 20) through (-10, 10) to (0, 0): centre (0, 10),
r 10, so it reaches x = -10 only at y = 10. The r 5 cut along x about
(y, z) = (12.5, 12.5) spans x -10..7.5 (touching) or -10.1..7.4 (clear). Both
open the same patch of the arc; the slice x 7.4..7.5 lies wholly inside the
plate (y 7.5..17.5, z 7.5..17.5 in 0..20 x 0..27.5). So
  V(clear) - V(touching) = pi 5^2 0.1 = 7.853982 mm^3
  A(touching) - A(clear) = 2 pi 5 0.1 = 3.141593 mm^2 (the hole wall; the
  floor disc is the same)
both to 1e-4 (the measure integrates the exact faces to 1e-8). A sliver of the
arc left where the end touches adds about a square millimetre of faces.

Seed 14's half (the fuzz generator's seed, then a shell) is pinned as its own
test, shell_after_a_cut_whose_end_touches_an_arc_side, with the commands the
generator gives today: the touching cut, then a 2 mm shell opening the top
face y = 20. It fails at the shell (SMLib status 1001), a kernel gap.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
jyviko
2026-10-30 06:37:31 -04:00
committed by Irakli Kourtis
parent 21c1ed541e
commit 03054211b3
+27 -7
View File
@@ -57,8 +57,12 @@ fn shell_with_a_hole_through_a_curved_side() {
/// A cut whose end only touches the plate's arc side (#897, robustness seed 14): the end lies
/// tangent to the arc at its apex, the direct boolean fails, and the last-resort nudge used to
/// push the end into the arc, leaving a sliver of it a tenth of a millimetre wide that a shell
/// then couldn't offset. The nudge the other way parts them: the same faces as a cut clear of
/// the apex, and seed 14 shells and fillets again.
/// then couldn't offset. The touching cut must make the same part as a cut 0.1 clear of the
/// apex (x = −10.1 .. 7.4 instead of −10 .. 7.5), less the hole's last 0.1 mm: the arc (centre
/// (0, 10), r 10) reaches x = −10 only at y = 10, so both cuts open the same patch of it, and
/// the slice x = 7.4 .. 7.5 of the r 5 hole lies wholly inside the plate. The touching cut has
/// π 5² 0.1 less volume and 2π 5 0.1 more area (the longer hole wall; the floor disc is the
/// same); a sliver left on the arc adds about a square millimetre of faces.
#[test]
fn cut_whose_end_touches_an_arc_side_leaves_no_sliver() {
let plate = |x: f64| {
@@ -72,11 +76,27 @@ fn cut_whose_end_touches_an_arc_side_leaves_no_sliver() {
]))
};
let (touching, clear) = (plate(-10.0), plate(-10.1));
let faces = |s: &Session| s.model.state().bodies.iter().map(|b| b.body.face_count()).sum::<usize>();
assert_eq!(faces(&touching), faces(&clear), "a sliver face was left where the cut's end touches the arc");
let r = fuzz::run(14, 8);
let kinds: Vec<&str> = r.steps.iter().map(|s| s.kind).collect();
assert!(r.outcome.kind == "ok" && kinds.contains(&"shell"), "seed 14: {:?} {kinds:?}\n{}", r.outcome, r.script());
let area = |s: &Session| s.model.state().bodies.iter().map(|b| solidcraft_kernel::measure(&b.body).map(|m| m.area).unwrap_or(0.0)).sum::<f64>();
let dv = total_volume(&clear) - total_volume(&touching);
assert!((dv - PI * 25.0 * 0.1).abs() < 1e-4, "volume: clear − touching = {dv}, not π 5² 0.1");
let da = area(&touching) - area(&clear);
assert!((da - 2.0 * PI * 5.0 * 0.1).abs() < 1e-4, "area: touching − clear = {da}, not 2π 5 0.1: a sliver where the cut's end touches the arc");
assert_eq!(touching.model.state().bodies.len(), 1);
}
/// Robustness seed 14 (#897) as the generator made it: the touching cut above, then a shell
/// opening the plate's top face (y = 20). Every step builds and the body is a sound solid.
#[test]
fn shell_after_a_cut_whose_end_touches_an_arc_side() {
script(json!([
{"command": "sketch.create", "params": {"plane": "XY"}},
{"command": "sketch.line", "params": {"points": [[0, 0], [42.5, 0], [42.5, 20.0], [0, 20.0]]}},
{"command": "sketch.arc.three_point", "params": {"end": [0, 0], "start": [0, 20.0], "through": [-10.0, 10.0]}},
{"command": "sketch.finish", "params": {}},
{"command": "solid.extrude", "params": {"distance": 27.5}},
{"command": "solid.cylinder", "params": {"axis": [1.0, 0.0, 0.0], "base": [-10.000000000000002, 12.5, 12.5], "height": 17.5, "operation": "cut", "radius": 5.0}},
{"command": "solid.shell", "params": {"faces": [[21.25, 19.999999999999993, 13.749999999999998]], "thickness": 2.0}}
]));
}
/// #827: a hinge barrel joined to a laptop lid through its mounting leaf. The barrel's top lies