diff --git a/crates/engine/src/boolean_regression_tests.rs b/crates/engine/src/boolean_regression_tests.rs index 6efbc8f5f7..76910333cc 100644 --- a/crates/engine/src/boolean_regression_tests.rs +++ b/crates/engine/src/boolean_regression_tests.rs @@ -582,16 +582,24 @@ fn oblique_cuts_through_a_chamfered_ring_are_exact() { let script: Value = serde_json::from_str(include_str!("../../../examples/regressions/oblique_cuts_through_chamfered_ring.json")).unwrap(); let steps = script.get("commands").and_then(Value::as_array).unwrap(); let mut s = Session::default(); - let mut volumes = Vec::new(); + // The ring after the move and after each cut, and what each cut took away (the ring before it + // less the ring after it: a small body that measures to its own accuracy, where the difference + // of the whole ring's volumes is lost in the integration's 1e-6 of 1149 mm³). + let mut rings: Vec = Vec::new(); for step in steps { let reply = s.execute(step["command"].as_str().unwrap(), &step["params"]).unwrap(); if step["command"] == "solid.extrude" { assert!(reply["warning"].is_null(), "{reply}"); } if matches!(step["command"].as_str(), Some("solid.move" | "solid.extrude")) { - volumes.push(s.model.state().body("R").unwrap().body.mesh(&solidcraft_kernel::MeshTolerance::chord(1e-5)).unwrap().measure().volume); + rings.push(s.model.state().body("R").unwrap().body.clone()); } } + let taken = |k: usize| -> f64 { + let piece = solidcraft_kernel::boolean(&rings[k], &rings[k + 1], solidcraft_kernel::BoolOp::Cut).unwrap().unwrap(); + solidcraft_kernel::measure(&piece).unwrap().volume + }; + let volumes: Vec = rings.iter().map(|b| b.mesh(&solidcraft_kernel::MeshTolerance::chord(1e-5)).unwrap().measure().volume).collect(); // Pappus: the profile's moment about the axis turned through 240°. let profile = [(16.6, 0.0), (17.5, 0.0), (18.5, 1.0), (18.5, 7.0), (17.5, 8.0), (16.6, 8.0), (16.4, 7.8), (16.4, 0.2)]; let moment: f64 = (0..profile.len()) @@ -601,14 +609,14 @@ fn oblique_cuts_through_a_chamfered_ring_are_exact() { }) .sum(); let ring = moment.abs() * 4.0 * std::f64::consts::PI / 3.0; - let [whole, first, second, notched] = volumes[..] else { panic!("{volumes:?}") }; + let [whole, _, _, _] = volumes[..] else { panic!("{volumes:?}") }; // Volumes from meshes at 1e-5 mm: within a few millionths of the ring's. assert!((whole - ring).abs() < 1e-5 * ring, "{whole} vs {ring}"); // The ring and the two prisms are mirror images across XZ. - let (cut1, cut2) = (whole - first, first - second); - assert!(cut1 > 5.0 && (cut1 - cut2).abs() < 1e-6, "{cut1} vs {cut2}"); - let notch = ring_notch(); - assert!(((second - notched) - notch).abs() < 1e-4, "{} vs {notch}", second - notched); + let (cut1, cut2) = (taken(0), taken(1)); + assert!(cut1 > 5.0 && (cut1 - cut2).abs() < 1e-6 * cut1, "{cut1} vs {cut2}"); + let (notched, notch) = (taken(2), ring_notch()); + assert!((notched - notch).abs() < 1e-5 * notch, "{notched} vs {notch}"); let state = s.model.state(); let body = &state.body("R").unwrap().body; assert!(body.validity().is_empty(), "{:?}", body.validity()); @@ -621,8 +629,7 @@ fn oblique_cuts_through_a_chamfered_ring_are_exact() { ); assert!(coarse < fine && coarse > fine - 2.0, "area meshed at 0.05: {coarse} vs {fine}"); println!( - "ring {whole:.6} / {ring:.6} mm³; cuts {cut1:.6}, {cut2:.6}; notch {:.6} / {notch:.6}; area meshed at 0.05 {coarse:.4} / {fine:.4}", - second - notched + "ring {whole:.6} / {ring:.6} mm³; cuts {cut1:.6}, {cut2:.6}; notch {notched:.6} / {notch:.6}; area meshed at 0.05 {coarse:.4} / {fine:.4}" ); } @@ -634,17 +641,18 @@ fn notch_into_a_ring_chamfer_is_cut_exactly() { let script: Value = serde_json::from_str(include_str!("../../../examples/regressions/oblique_cuts_through_chamfered_ring.json")).unwrap(); let steps = script.get("commands").and_then(Value::as_array).unwrap(); let mut s = Session::default(); - let measure = - |s: &Session| s.model.state().body("R").unwrap().body.mesh(&solidcraft_kernel::MeshTolerance::chord(1e-5)).unwrap().measure().volume; s.run_script(&Value::Array(steps[..5].to_vec())).unwrap(); - let before = measure(&s); + let before = s.model.state().body("R").unwrap().body.clone(); // The notch's sketch and its cut. for step in &steps[steps.len() - 4..] { let reply = s.execute(step["command"].as_str().unwrap(), &step["params"]).unwrap(); assert!(reply["warning"].is_null(), "{reply}"); } - let (got, want) = (before - measure(&s), ring_notch()); - assert!((got - want).abs() < 1e-4, "{got} vs {want}"); + // What the cut took: the ring before it less the ring after it, measured as a body of its own + // (the difference of the two rings' volumes is lost in the integration's 1e-6 of 1149 mm³). + let piece = solidcraft_kernel::boolean(&before, &s.model.state().body("R").unwrap().body, solidcraft_kernel::BoolOp::Cut).unwrap().unwrap(); + let (got, want) = (solidcraft_kernel::measure(&piece).unwrap().volume, ring_notch()); + assert!((got - want).abs() < 1e-5 * want, "{got} vs {want}"); } /// What the ring's notch takes: a band 0.9 wide about a radius, from 17.6 out along it, and from