From 0bea4631be4eab6f56ef99010765cb30bd0e0e04 Mon Sep 17 00:00:00 2001 From: jyviko <2501648+jyviko@users.noreply.github.com> Date: Sun, 25 Oct 2026 19:51:02 -0400 Subject: [PATCH] kernel: IGES trim pieces that miss their meeting point are closed onto it The pieces of an IGES trim curve run on from one another, and the sewer made each meeting point one vertex, but left a piece that missed it where it was, the gap on the vertex's tolerance: an edge 0.01 mm short of its corner, 2000 times the file's resolution, which SMLib refuses (SmTrimmingTools #0, SmBrep line or clamped B-spline piece that misses it is made to end there exactly; any other piece that misses keeps its ends, and the gap is reported. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_0113gDVmStT5tCGKW9Fxgc5K --- crates/kernel/src/iges_in/tests.rs | 48 ++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/crates/kernel/src/iges_in/tests.rs b/crates/kernel/src/iges_in/tests.rs index 4abed67300..9a120751ef 100644 --- a/crates/kernel/src/iges_in/tests.rs +++ b/crates/kernel/src/iges_in/tests.rs @@ -361,6 +361,54 @@ fn surfaces_in_separate_groups_remain_separate_parts() { } } +/// The box of [`trimmed_surfaces_sew_into_a_solid`] with its edge (0, 0, 0)–(0, 20, 0) stopping +/// 0.01 mm short of its corner in both faces that use it, its next pieces starting at the +/// corner. The pieces of a trim curve run on from one another, so the edge ends at the corner the +/// other three edges there agree on, exactly: a closed box SMLib finds valid. The edge was left +/// short with the gap on the vertex's tolerance, 2000 times the file's resolution (#3845). +#[test] +fn trim_pieces_that_miss_their_corner_are_closed_onto_it() { + let c = + |i: usize| -> [f64; 3] { [if i & 1 != 0 { 10.0 } else { 0.0 }, if i & 2 != 0 { 20.0 } else { 0.0 }, if i & 4 != 0 { 30.0 } else { 0.0 }] }; + let short = [0.0, 19.99, 0.0]; + let quads = [[0, 2, 3, 1], [4, 5, 7, 6], [0, 1, 5, 4], [2, 6, 7, 3], [0, 4, 6, 2], [1, 3, 7, 5]]; + let mut ents: Vec<(i64, i64, String)> = Vec::new(); + let fmt = |p: [f64; 3]| format!("{:?},{:?},{:?}", p[0], p[1], p[2]); + for q in quads { + let (a, b, cc, d) = (c(q[0]), c(q[1]), c(q[2]), c(q[3])); + let surf = format!("1,1,1,1,0,0,1,0,0,0.,0.,1.,1.,0.,0.,1.,1.,1.,1.,1.,1.,{},{},{},{},0.,1.,0.,1.", fmt(a), fmt(b), fmt(d), fmt(cc)); + ents.push((128, 0, surf)); + let s_de = 2 * ents.len() - 1; + let mut lines = Vec::new(); + for (p0, p1) in [(a, b), (b, cc), (cc, d), (d, a)] { + // The short edge: its end at (0, 20, 0) is 0.01 short. + let (p0, p1) = match (p0, p1) { + ([0.0, 0.0, 0.0], [0.0, 20.0, 0.0]) => (p0, short), + ([0.0, 20.0, 0.0], [0.0, 0.0, 0.0]) => (short, p1), + x => x, + }; + ents.push((110, 0, format!("{},{}", fmt(p0), fmt(p1)))); + lines.push(2 * ents.len() - 1); + } + ents.push((102, 0, format!("4,{}", lines.iter().map(|x| x.to_string()).collect::>().join(",")))); + let comp = 2 * ents.len() - 1; + ents.push((142, 0, format!("0,{s_de},0,{comp},2"))); + let cos = 2 * ents.len() - 1; + ents.push((144, 0, format!("{s_de},1,0,{cos}"))); + } + let imp = iges_import(&iges_file(&ents)).unwrap(); + assert!(imp.warnings.is_empty(), "{:?}", imp.warnings); + assert!(imp.bodies[0].closed); + let body = &imp.bodies[0].body; + let check = body.smlib().unwrap().check(solidcraft_smlib::CheckLevel::All).unwrap(); + assert!(check.is_valid(), "{check}"); + for v in &body.record().vertices { + assert!(v.tolerance <= body.record().tolerance, "a vertex {:?} kept a gap in its tolerance {}", v.point, v.tolerance); + } + let m = measure(body).unwrap(); + assert!(rel(m.volume, 6000.0) < 1e-6 && rel(m.area, 2200.0) < 1e-6, "{} {}", m.volume, m.area); +} + #[test] fn a_drill_point_round_trips_through_iges() { // A blind hole with a cone tip: the tip's face closes at its apex (its seam runs out to the