Kernel tests: rim rounds meeting at a concave corner are mitred, not swept

The owner's final ruling of 2026-10-30 reverses the swept corner 6539c070a
and 8dc344d22 used: rim rounds meeting at a concave corner beside an
unpicked sharp edge are mitred by default (a user who wants it swept rounds
the corner edge too; a swept corner with a sharp inner edge is a future
option). SMLib's swept result is the defect, so both tests now expect the
mitre and fail today on it.

rounds_that_fit_are_closed. At depth u the section is the outline moved in
by d = r - sqrt(r^2 - (r - u)^2) with every corner mitred: the area less
L d, plus d^2 at each of the six convex corners (the two strips overlap in
a d x d square) and less d^2 at each of the six concave ones (the mitre
also takes the d x d square beyond both strips), the overlap of the two
spandrel prisms being r^3 (5/3 - pi/2) per corner over the round. Six and
six cancel, so both ends remove 2 L r^2 (1 - pi/4) with L = 107.6:
11.545566 (the swept corners gave 11.514718).

fillet_tabbed_plate_outer_loop_and_partial_selection_after_hole. Where both
sides of a concave corner (+-4, sqrt(609)) move, the moved R25 arc and the
moved side x = 4 - d now meet where they cross,
y = sqrt((25 - d)^2 - (4 - d)^2), as where only one side moves; the swept
arc branch goes. Check: A(0,0) - A(d,d) agrees with the Steiner form for a
mitred outline, L d - d^2 (pi + theta - 2 tan(theta/2)), to second order
(17.190976 against 17.190968 at d = 0.1; the arc's curvature moves the
mitre point at third order, which the Green's-theorem area has exactly).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
jyviko
2026-10-30 06:40:49 -04:00
committed by Irakli Kourtis
parent 4d7553dd8b
commit 21c1ed541e
2 changed files with 16 additions and 23 deletions
+9 -9
View File
@@ -51,15 +51,16 @@ fn overlapping_rounds_are_refused() {
/// Below half the wall the rounds fit: a closed solid with a round on every edge. Each end face's
/// round section at depth u into the round is the end face's outline moved in by
/// d = r − √(r² − (r − u)²), each edge parallel to itself: the area less L d (L the outline's
/// and the window's length together, 2 · 41.5 + 2 · 12.3 = 107.6), plus d² at each of the six
/// convex corners (two rounds mitred) and less π d² / 4 at each of the six concave ones, the two
/// shoulders and the window's four corners (two rounds meeting at a concave corner beside an
/// unpicked sharp edge are swept round it, the owner's ruling of 2026-10-30). Over the round,
/// ∫ d = r² (1 − π/4) and ∫ d² = r³ (5/3 − π/2), at both ends.
/// d = r − √(r² − (r − u)²), each edge parallel to itself and every corner mitred (two rounds
/// meeting at a corner beside an unpicked sharp edge, convex or concave: the owner's ruling of
/// 2026-10-30): the area less L d (L the outline's and the window's length together,
/// 2 · 41.5 + 2 · 12.3 = 107.6), plus d² at each of the six convex corners (the two strips
/// overlap) and less d² at each of the six concave ones (the two shoulders and the window's four
/// corners: the mitre takes the d × d square beyond both strips). The corner terms cancel, so
/// both ends remove 2 L ∫ d = 2 L r² (1 − π/4).
#[test]
fn rounds_that_fit_are_closed() {
use std::f64::consts::{FRAC_PI_2, FRAC_PI_4};
use std::f64::consts::FRAC_PI_4;
let p = part();
let r = 0.5;
let b = crate::fillet(&p, &edges(), r).unwrap();
@@ -69,8 +70,7 @@ fn rounds_that_fit_are_closed() {
let part_volume = 14.0 * (21.5 * 10.0 + (top - a) * 10.0 - 5.2 * 7.1);
assert!((crate::measure(&p).unwrap().volume - part_volume).abs() < 1e-9 * part_volume);
let length = 2.0 * (21.5 + 20.0) + 2.0 * (5.2 + 7.1);
let corners = 6.0 - 6.0 * FRAC_PI_4;
let removed = 2.0 * (length * r * r * (1.0 - FRAC_PI_4) - corners * r * r * r * (5.0 / 3.0 - FRAC_PI_2));
let removed = 2.0 * length * r * r * (1.0 - FRAC_PI_4);
let v = crate::measure(&b).unwrap().volume;
assert!((v - (part_volume - removed)).abs() < 1e-7 * part_volume, "{v} vs {}", part_volume - removed);
}
+7 -14
View File
@@ -1953,23 +1953,16 @@ fn fillet_sharp_arc_and_arc_loop() {
/// with the R25 arc moved in by `da` and the tab's run (its sides, R2 corners and top) by `dt`,
/// each element parallel to itself, by Green's theorem: an arc about c of radius ρ from a to b
/// gives ½ (ρ² (b − a) + ρ (cx (sin b − sin a) − cy (cos b − cos a))), a segment p→q ½ (p × q).
/// Where only one side of a concave corner at (±4, y) moves the elements meet where they cross
/// (the round runs into the other wall); where both do, the corner is swept, an arc of radius d
/// about the corner (the owner's ruling for rounds meeting at a concave corner, 2026-10-30).
/// At the concave corners (±4, y) the moved elements meet where they cross: where one side moves
/// the round runs into the other wall, where both do the two rounds are mitred (the owner's
/// ruling for rounds meeting at a concave corner beside an unpicked sharp edge, 2026-10-30).
fn tabbed_plate_area(da: f64, dt: f64) -> f64 {
let (y, cy) = ((625.0_f64 - 16.0).sqrt(), 280.0 / 9.0);
let theta = (4.0_f64 / 25.0).acos();
let cy = 280.0 / 9.0;
let (big, rho) = (25.0 - da, 2.0 - dt);
let tab = rho * rho * PI + 2.0 * rho * (2.0 + cy) + 4.0 * (cy + rho);
if da > 0.0 && dt > 0.0 {
assert!((da - dt).abs() < 1e-15, "a swept corner of one size");
let corner = -da * da * theta + da * (4.0 * theta.sin() + y * (1.0 - theta.cos()));
0.5 * (big * big * (PI + 2.0 * theta) + 2.0 * corner + tab) + (4.0 - dt) * (cy - y)
} else {
let yc = (big * big - (4.0 - dt).powi(2)).sqrt();
let at = yc.atan2(4.0 - dt);
0.5 * (big * big * (PI + 2.0 * at) + tab) + (4.0 - dt) * (cy - yc)
}
let yc = (big * big - (4.0 - dt).powi(2)).sqrt();
let at = yc.atan2(4.0 - dt);
0.5 * (big * big * (PI + 2.0 * at) + tab) + (4.0 - dt) * (cy - yc)
}
#[test]