kernel: G2 corners at concave corners, mixed ones refused

The inner corner of a notch, three concave r5 rounds, takes the set-back G2
patch as a convex corner does: one valid solid with the ball corner's 13
faces, seam jump 6.3e-4 per mm clear of the hole's corners against the
ball's 0.2. A corner of two convex rounds and a concave one is refused as not
supported: SMLib sets back only corners of one convexity.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
jyviko
2026-10-26 13:33:03 -04:00
committed by Irakli Kourtis
parent 8fbb575a5e
commit 8089137776
2 changed files with 44 additions and 2 deletions
+3 -2
View File
@@ -233,8 +233,9 @@ pub fn fillet_setback(body: &Body, edges: &[Vec3], radius: f64, setbacks: &[(Vec
/// its vertex and the distance its patch starts along each edge there (the others take
/// [`crate::DEFAULT_SETBACK_FACTOR`] times the radius), SMLib leaves it open, and a patch that
/// meets the rounds and the faces round it to the second order fills it. The faces are sewn
/// into one solid. Without such a corner this is [`fillet`]. Refused: a corner where an edge is
/// not rounded (SMLib sets back only corners where all are), a setback that does not reach past
/// into one solid, convex corners and concave ones alike. Without such a corner this is
/// [`fillet`]. Refused: a corner where an edge is not rounded, or whose edges are not all of one
/// convexity (SMLib sets back only corners where all are rounded, alike), a setback that does not reach past
/// where the rounds would meet, a hole that is no height field over its plane or a patch that
/// does not meet its neighbours within the tolerances.
pub fn fillet_g2_corners(body: &Body, edges: &[Vec3], radius: f64, setbacks: &[(Vec3, f64)]) -> Result<Body> {
+41
View File
@@ -164,3 +164,44 @@ fn what_the_g2_corner_cannot_build_is_refused() {
let plain = fillet(&body, &edges[..2], 5.0).unwrap();
assert_eq!(measure(&two).unwrap().faces, measure(&plain).unwrap().faces);
}
/// The 60 x 40 x 20 box with a 20 x 20 x 10 notch cut from its top corner (60, 40, 20): its
/// inner corner (40, 20, 10) where three concave edges meet, and the notch's outer corner
/// (60, 20, 10) where the concave edge along x meets two convex ones.
fn notched() -> Body {
let a = box_solid(Vec3::ZERO, Vec3::new(60.0, 40.0, 20.0)).unwrap();
let b = box_solid(Vec3::new(40.0, 20.0, 10.0), Vec3::new(70.0, 50.0, 30.0)).unwrap();
boolean(&a, &b, BoolOp::Cut).unwrap().unwrap()
}
/// The notch's inner corner, three concave r5 rounds (ladder 07/019): set back 7.5 and filled,
/// one closed valid solid with the faces the ball corner has, the patch's seams G2 clear of the
/// hole's corners where the ball's jump 1/r.
#[test]
fn a_concave_corner_takes_the_g2_patch_too() {
let body = notched();
let edges = [Vec3::new(50.0, 20.0, 10.0), Vec3::new(40.0, 30.0, 10.0), Vec3::new(40.0, 20.0, 15.0)];
let ball = fillet(&body, &edges, 5.0).unwrap();
let g2 = fillet_g2_corners(&body, &edges, 5.0, &[]).unwrap();
assert!(g2.validity().is_empty(), "{:?}", g2.validity());
let v = crate::validity::validity(&g2);
assert!(v.ok(), "{v:?}");
let (m, mb) = (measure(&g2).unwrap(), measure(&ball).unwrap());
let (_, clear, n) = corner_seams(&g2, 0.15);
let (_, ball_clear, _) = corner_seams(&ball, 0.15);
eprintln!("concave G2 corner: {} faces (ball {}), volume {:.4} (ball {:.4}), jump clear of the corners {clear:.3e} ({n} stations), ball's {ball_clear:.3e}", m.faces, mb.faces, m.volume, mb.volume);
assert_eq!(m.faces, mb.faces);
assert!(clear <= CURVATURE_SHARE / 5.0 && ball_clear > 0.19, "{clear} {ball_clear}");
}
/// The notch's outer corner, two convex rounds and a concave one: SMLib sets back only a corner
/// of one convexity, so the G2 corner is refused as not supported (the rolling ball builds).
#[test]
fn a_mixed_convexity_corner_is_refused() {
let body = notched();
let edges = [Vec3::new(50.0, 20.0, 10.0), Vec3::new(60.0, 30.0, 10.0), Vec3::new(60.0, 20.0, 15.0)];
assert!(fillet(&body, &edges, 5.0).is_ok());
let err = fillet_g2_corners(&body, &edges, 5.0, &[]).unwrap_err().to_string();
eprintln!("mixed corner: {err}");
assert!(err.contains("not supported yet"), "{err}");
}