Ring tests: a cut's volume is the piece it took, not the difference of the ring's volumes

notch_into_a_ring_chamfer_is_cut_exactly measured the notch as the ring's mesh volume before less
after (0.2906 against the integral's 0.28665) and oblique_cuts_through_a_chamfered_ring_are_exact
compared the two mirrored cuts the same way (3.3e-4 apart). The cut is right: the ring less the
cut ring is a piece of 0.2866521 mm³, the integral to 2e-6. A difference of two 1149 mm³ volumes
is not: the re-tessellated ring's mesh volume moves by 4e-3, and SMLib's mass properties (at
their finest, 1e-4 asked) by 1.5e-6 of the ring, 1.7e-3. Each cut is now measured as the piece it
took away (the ring before less the ring after, an SMLib boolean), to 1e-5 of the integral and
1e-6 between the two mirrored cuts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
jyviko
2026-10-29 02:10:31 -04:00
committed by Irakli Kourtis
parent b6b59e7b3b
commit ac52443dfb
+22 -14
View File
@@ -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<solidcraft_kernel::Body> = 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<f64> = 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