mirror of
https://github.com/bherbruck/solidcraft.git
synced 2026-11-04 19:15:57 +00:00
Kernel tests: the box rounded after separate bottom rounds takes its exact volume
issue2422_vertical_after_separate_bottom_rounds compared the face count and volume (within 0.05) of the vertical round, picked with and without its bottom mitre, against the same round picked alone, and required every face meshed. It now holds each of the three picks, on the 40 x 80 x 27 box and on the same shelled 1 mm open at the top, to the exact volume; the corner probes stay. Proof. Horizontal sections, s up from the bottom. Below s = r the four separate R2 bottom rounds (mitred at the corners) leave the rectangle moved in by d = r - rho, rho = sqrt(r^2 - (r - s)^2), and where the vertical round meets them (a sphere octant) its corner is a quarter disc of radius rho: (L - 2d)(W - 2d) - (1 - pi/4) rho^2. Above, LW - (1 - pi/4) r^2. With the integrals over the bottom r of rho (pi r^2 / 4), rho^2 (2 r^3 / 3), d (r^2 (1 - pi/4)) and d^2 (r^3 (5/3 - pi/2)): V = LW r - 2 (L + W) r^2 (1 - pi/4) + 4 r^3 (5/3 - pi/2) - (1 - pi/4) 2 r^3 / 3 + (H - r)(LW - (1 - pi/4) r^2) = 86174.445361; with four such corners it is issue1557_all_vertical_corners_match_analytic _volume's formula exactly. The shell's cavity, 38 x 78 x 26, is clear of both rounds (along the corner's diagonal the R2 arc stays 2 - sqrt(2) in, the cavity's corner is 1 in), so the cup is V - 77064. Graded at 1e-6. Today SMLib's check refuses the bottom rounds' result (edge and vertex tolerance 0.97 against 0.01), as before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -168,28 +168,40 @@ mod tests {
|
||||
assert!(fillet_radii(&rounded, &[(seam, 2.0)]).is_err());
|
||||
}
|
||||
|
||||
/// A 40 x 80 x 27 box (and the same shelled 1 mm, open at the top) with its bottom edges
|
||||
/// rounded R2 as four separate fillets (mitred at the bottom corners), then one vertical
|
||||
/// edge R2: the same solid whichever of its picks comes first. Horizontal sections: below
|
||||
/// z = r above the bottom, s up, the rectangle moved in by d = r − ρ, ρ = √(r² − (r − s)²),
|
||||
/// with the rounded corner a quarter disc of radius ρ less than its square (the sphere octant
|
||||
/// where the three rounds meet); above, the rectangle less that corner at r. With
|
||||
/// ∫ ρ = π r² / 4, ∫ ρ² = 2 r³ / 3, ∫ d = r² (1 − π/4) and ∫ d² = r³ (5/3 − π/2) over the
|
||||
/// bottom r. The shell's cavity, 38 x 78 x 26, lies clear of both rounds (the bottom round's
|
||||
/// arc passes 2 − √2 from the outer corner along the diagonal, the cavity's corner 1).
|
||||
#[test]
|
||||
fn issue2422_vertical_after_separate_bottom_rounds() {
|
||||
use std::f64::consts::{FRAC_PI_2, FRAC_PI_4};
|
||||
let origin = Vec3::new(-5.0, 7.2, -2.0);
|
||||
let b = box_solid(origin, origin + Vec3::new(40.0, 80.0, 27.0)).unwrap();
|
||||
let (l, w, h, r) = (40.0, 80.0, 27.0, 2.0);
|
||||
let b = box_solid(origin, origin + Vec3::new(l, w, h)).unwrap();
|
||||
let bottom = [Vec3::new(15.0, 7.2, -2.0), Vec3::new(35.0, 47.2, -2.0), Vec3::new(15.0, 87.2, -2.0), Vec3::new(-5.0, 47.2, -2.0)];
|
||||
let spandrel = 1.0 - FRAC_PI_4;
|
||||
let solid = l * w * r - 2.0 * (l + w) * r * r * spandrel + 4.0 * r * r * r * (5.0 / 3.0 - FRAC_PI_2) - spandrel * 2.0 * r * r * r / 3.0
|
||||
+ (h - r) * (l * w - spandrel * r * r);
|
||||
let cavity = (l - 2.0) * (w - 2.0) * (h - 1.0);
|
||||
// The issue has no design attached. Reconstruct its outside corner and bottom mitre,
|
||||
// using the reported picks, with and without the open cavity visible in the screenshot.
|
||||
let picks = [Vec3::new(-5.0, 87.2, 12.5), Vec3::new(-4.283446394180081, 86.48344639418008, -1.5001085324947512)];
|
||||
for base in [b.clone(), crate::shell(&b, &[Vec3::new(15.0, 47.2, 25.0)], 1.0).unwrap()] {
|
||||
for (base, want) in [(b.clone(), solid), (crate::shell(&b, &[Vec3::new(15.0, 47.2, 25.0)], 1.0).unwrap(), solid - cavity)] {
|
||||
// Each fillet with its tangent chain, as the Fillet feature asks for it by default
|
||||
// (tangent propagation).
|
||||
let mut rounded = base;
|
||||
for edge in bottom {
|
||||
rounded = fillet(&rounded, &crate::tangent_chain(&rounded, &[edge]).unwrap(), 2.0).unwrap();
|
||||
}
|
||||
let reference = fillet(&rounded, &crate::tangent_chain(&rounded, &picks[..1]).unwrap(), 2.0).unwrap();
|
||||
for selection in [picks, [picks[1], picks[0]]] {
|
||||
let result = fillet(&rounded, &crate::tangent_chain(&rounded, &selection).unwrap(), 2.0).unwrap();
|
||||
assert_eq!(result.face_count(), reference.face_count());
|
||||
assert_eq!(result.unmeshed_faces(), 0);
|
||||
for selection in [&picks[..1], &picks[..], &[picks[1], picks[0]][..]] {
|
||||
let result = fillet(&rounded, &crate::tangent_chain(&rounded, selection).unwrap(), 2.0).unwrap();
|
||||
assert!(result.validity().is_empty(), "{:?}", result.validity());
|
||||
assert!((vol(&result) - vol(&reference)).abs() < 0.05);
|
||||
assert!((vol(&result) - want).abs() < 1e-6 * want, "{selection:?}: {} vs {want}", vol(&result));
|
||||
assert!(!result.contains(Vec3::new(-4.9, 87.1, 10.0)));
|
||||
assert!(result.contains(Vec3::new(-4.1, 86.3, 10.0)));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user