mirror of
https://github.com/bherbruck/solidcraft.git
synced 2026-11-03 02:25:55 +00:00
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:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user