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