mirror of
https://github.com/bherbruck/solidcraft.git
synced 2026-11-04 11:05:56 +00:00
Kernel tests: the barrel's side is the exact surface of revolution of its arc
The barrel's arc has its centre across the axis, so its side is the inner (lemon) zone of a spindle torus, which SMLib's torus does not describe (its meridian is on the X side): SMLib (revolve-spindle) sweeps it as the exact rational surface of revolution. shell_of_a_revolved_barrel asserted an analytic torus of major radius -10. As the owner decided, it now asserts what matters: two flat caps and the curved side, the closed-form volume, 14 mm round at mid height, and after the shell the two offset faces (the inner wall and floor; truck's side was in halves). Needs SMLib with revolve-spindle (pin bump). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -43,13 +43,19 @@ fn check_volume(body: &Body, lo: f64, hi: f64) {
|
||||
#[test]
|
||||
fn shell_of_a_revolved_barrel() {
|
||||
let barrel = barrel();
|
||||
let side = (0..barrel.face_count())
|
||||
.find_map(|i| match face_surface(&barrel, i) {
|
||||
Some(s @ FaceSurface::Torus { major, minor, .. }) if (major - CENTRE).abs() < 1e-6 && (minor - RADIUS).abs() < 1e-6 => Some(s),
|
||||
_ => None,
|
||||
})
|
||||
.expect("barrel side is the inner sheet of a spindle torus");
|
||||
assert!(side.nearest(Vec3::new(15.0, 0.0, HALF_HEIGHT)).unwrap().dist(Vec3::new(14.0, 0.0, HALF_HEIGHT)) < 1e-6);
|
||||
// The side is the inner (lemon) zone of a spindle torus: SMLib's torus describes only its
|
||||
// outer zone, so the side is the exact rational surface of revolution of the arc. Two flat
|
||||
// caps and that side; the solid is the closed-form barrel, 14 mm round at mid height (`contains` asks the display mesh, so a margin round it).
|
||||
assert_eq!(barrel.face_count(), 3);
|
||||
let planes = (0..barrel.face_count()).filter(|i| matches!(face_surface(&barrel, *i), Some(FaceSurface::Plane { .. }))).count();
|
||||
assert_eq!(planes, 2, "two caps and the curved side");
|
||||
let full = integral(RADIUS, 2.0 * HALF_HEIGHT) - integral(RADIUS, 0.0);
|
||||
let volume = measure(&barrel).unwrap().volume;
|
||||
assert!((volume - full).abs() < full * 1e-3, "{volume} vs {full}");
|
||||
for turn in [0.0, 1.0, 2.5, 4.0] {
|
||||
let (c, s) = (f64::cos(turn), f64::sin(turn));
|
||||
assert!(barrel.contains(Vec3::new(13.8 * c, 13.8 * s, HALF_HEIGHT)) && !barrel.contains(Vec3::new(14.2 * c, 14.2 * s, HALF_HEIGHT)));
|
||||
}
|
||||
let result = shell(&barrel, &[Vec3::new(0.0, 0.0, 2.0 * HALF_HEIGHT)], 2.0).unwrap();
|
||||
assert!(result.validity().is_empty(), "{:?}", result.validity());
|
||||
assert_eq!(result.shell_count(), 1);
|
||||
@@ -62,7 +68,8 @@ fn shell_of_a_revolved_barrel() {
|
||||
check_volume(&result, 2.0, 2.0 * HALF_HEIGHT);
|
||||
let history = result.history().expect("exact shell face history");
|
||||
assert_eq!(history.operands, 1);
|
||||
assert_eq!(history.faces.iter().filter(|f| matches!(f.origins.as_slice(), [FaceOrigin::Offset { operand: 0, .. }])).count(), 4);
|
||||
// The inner wall and the inner floor, offsets of the barrel's side and bottom (the top opened).
|
||||
assert_eq!(history.faces.iter().filter(|f| matches!(f.origins.as_slice(), [FaceOrigin::Offset { operand: 0, .. }])).count(), 2);
|
||||
let step = step_export(&[&result], "barrel shell").unwrap();
|
||||
let imported = step_import(&step).unwrap();
|
||||
assert_eq!(imported.bodies.len(), 1);
|
||||
|
||||
Reference in New Issue
Block a user