Tests: the knife-edge R2 fillet is checked once, in closed form

fillet_the_knife_edge_at_the_tip (features_more_tests.rs) and
blend_a_knife_edge_where_a_curved_wall_runs_out (tests/robustness.rs) build
the same #851 part with the same script, round the same knife edge at
(62 1/6, 0, 5) with R2 and measure the removed volume through the same display
plan. The first integrated the removed area on a grid (5e-4); the second has
it in closed form. Drop the first and keep its tolerance on the second.

The ball 2 from the back face y = 0 and from the r 21 wall about (62 1/6, -21)
is centred at (62 1/6 - sqrt(168), -2). The removed section is the trapezoid
wall centre, tip, (kx, 0), ball centre (sqrt(168) wide, 21 and 2 high) less the
wall's sector theta = acos(19/23) and the ball's sector pi - theta:
  10 (11.5 sqrt(168) - 220.5 theta - 2 (pi - theta)) = 119.648812 mm^3
the constant the kept test has; the dropped test's grid gives 119.6487 at a
0.004 x 0.001 step. The kept test's fillet bound goes from 0.5 to 5e-4 of
that (0.0598), the dropped test's. Its chamfer row (159.236451, the chord
triangle less the wall's segment) already says the chamfer takes more.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
jyviko
2026-10-30 06:37:40 -04:00
committed by Irakli Kourtis
parent 03054211b3
commit 5e7e1485c0
2 changed files with 7 additions and 37 deletions
@@ -1725,38 +1725,6 @@ fn fillet_straight_edges_that_end_at_the_arc_wall() {
}
}
/// The vertical knife edge at the tip (the arc and the back face meeting at no angle) rounds to
/// the ball 2 from both, about 13 back from the tip: the cusp beyond the ball, on the tip's side
/// of its contacts, all the way up.
#[test]
fn fillet_the_knife_edge_at_the_tip() {
let cx = 62.166666666666664;
let (kx, ky) = (cx - (23.0f64 * 23.0 - 19.0 * 19.0).sqrt(), -2.0);
let (hx, hy) = (0.002, 0.0005);
let mut area = 0.0;
let mut x = kx + hx / 2.0;
while x < cx {
let lo = -21.0 + (441.0 - (x - cx) * (x - cx)).max(0.0).sqrt();
for j in 0..((0.0 - lo) / hy).ceil() as usize {
let (y0, y1) = (lo + j as f64 * hy, (lo + (j + 1) as f64 * hy).min(0.0));
let y = (y0 + y1) * 0.5;
let a = (y - ky).atan2(x - kx);
if (x - kx).hypot(y - ky) > 2.0 && a >= (-21.0 - ky).atan2(cx - kx) {
area += (y1 - y0) * hx;
}
}
x += hx;
}
let mut s = knife_edge_part();
let before = planned(&s);
run(&mut s, "solid.fillet", json!({"edges": [[cx, 0.0, 5.0]], "radius": 2}));
let after = planned(&s);
assert!(rel(before - after, area * 10.0) < 5e-4, "removed {} vs {}", before - after, area * 10.0);
let mut s = knife_edge_part();
run(&mut s, "solid.chamfer", json!({"edges": [[cx, 0.0, 5.0]], "distance": 2}));
assert!(before - planned(&s) > before - after, "the chamfer takes the ball's bulge off too");
}
/// Rounds of the edges at the arc's top front corner, two or all three together (r 2): they meet
/// in creases (with all three, a piece of sphere fills the corner). Each set takes off its rounds
/// alone, less what each alone takes in a box about the corner, plus what they take there
+7 -5
View File
@@ -500,18 +500,20 @@ fn planned_volume(s: &Session) -> f64 {
/// #851: the knife edge where the wall runs out has opposite normals on its two faces. It rounds
/// to the ball that fits there and chamfers with the plane through that ball's contacts (the cusp
/// area less the wall's sector and the ball's, or the chord triangle less the wall's segment,
/// times the 10 mm height).
/// times the 10 mm height). The ball 2 from both faces sits at (62⅙ − √168, −2); the round takes
/// 10 (11.5 √168 − 220.5 θ − 2 (π − θ)), θ = acos(19/23), within 5e-4 of it.
#[test]
fn blend_a_knife_edge_where_a_curved_wall_runs_out() {
let knife = json!([[62.1667, 0, 5]]);
for (command, params, removed) in
[("solid.fillet", json!({"edges": knife, "radius": 2}), 119.648_812), ("solid.chamfer", json!({"edges": knife, "distance": 2}), 159.236_451)]
{
for (command, params, removed, within) in [
("solid.fillet", json!({"edges": knife, "radius": 2}), 119.648_812, 119.648_812 * 5e-4),
("solid.chamfer", json!({"edges": knife, "distance": 2}), 159.236_451, 0.5),
] {
let mut s = knife_edge_part();
let before = planned_volume(&s);
s.execute(command, &params).unwrap_or_else(|e| panic!("{command}: {e}"));
let after = planned_volume(&s);
assert!((before - after - removed).abs() < 0.5, "{command}: removed {}, expected {removed}", before - after);
assert!((before - after - removed).abs() < within, "{command}: removed {}, expected {removed}", before - after);
for b in &s.model.state().bodies {
assert!(b.body.validity().is_empty(), "{command}: {:?}", b.body.validity());
}