mirror of
https://github.com/bherbruck/solidcraft.git
synced 2026-11-03 02:25:55 +00:00
Tests: a corner patch of rounds 2/3/4 takes no more than the strips leave in its block
three_rounds_at_a_corner bounded the patch's extra cut at 3 mm³ beyond the strips, a figure with no derivation; SMLib's all-at-once body at radii 2, 3, 4 takes 3.099 (V 7878.579574 against strips 7881.678). That body is the strips' outside the block its patch lies in: its rounds are the strips' cylinders ending at a's section y = rc, b's x = 20 − rc and c's rails where they meet a's and b's (the patch's four corners, now asserted), so the patch takes at most what the strips leave in that block (11.86 at 2/2/3, 32.69 at 2/3/4). The lower bound is that block; the upper one, at most the strips' volume, stays. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -298,6 +298,30 @@ mod tests {
|
||||
8000.0 - full + (sum - union) * hh * hh
|
||||
}
|
||||
|
||||
/// What the strips leave of the corner block where a patch over the corner of rounds `ra`,
|
||||
/// `rb`, `rc` on a, b, c lies: beyond a's end section (y < rc), b's (x > 20 − rc) and c's end
|
||||
/// (z > 20 − max(ra, rb), where c's rails meet a's and b's), the box's material that no
|
||||
/// strip removes, by columns along z. Outside that block such a body is the strips' (its
|
||||
/// rounds are the strips' cylinders up to those ends), so its patch takes at most this
|
||||
/// beyond them.
|
||||
fn corner_block(ra: f64, rb: f64, rc: f64) -> f64 {
|
||||
let len = |d: f64, r: f64| if d < r { r - (r * r - (r - d) * (r - d)).max(0.0).sqrt() } else { 0.0 };
|
||||
let (n, depth) = (2000, ra.max(rb));
|
||||
let h = rc / n as f64;
|
||||
let mut kept = 0.0;
|
||||
for i in 0..n {
|
||||
let dx = (i as f64 + 0.5) * h;
|
||||
for j in 0..n {
|
||||
let dy = (j as f64 + 0.5) * h;
|
||||
if (rc - dx).powi(2) + (rc - dy).powi(2) > rc * rc && dx < rc && dy < rc {
|
||||
continue;
|
||||
}
|
||||
kept += depth - len(dx, ra).max(len(dy, rb)).min(depth);
|
||||
}
|
||||
}
|
||||
kept * h * h
|
||||
}
|
||||
|
||||
/// Largest angle (degrees) between the two faces' normals along edges between curved faces.
|
||||
fn kink(b: &Body) -> f64 {
|
||||
let rec = Faces::of(b).unwrap();
|
||||
@@ -484,15 +508,29 @@ mod tests {
|
||||
assert!(r.validity().is_empty(), "{:?}", r.validity());
|
||||
assert!((vol(&r) - sphere).abs() < 1e-11 * sphere, "{} vs {sphere}", vol(&r));
|
||||
assert!(kink(&r) < 0.01);
|
||||
// Different radii: a smooth patch over the corner, slightly more than the strips take.
|
||||
// Different radii: a smooth patch over the corner, more than the strips take, and no more
|
||||
// than they leave in the block it lies in: its rounds end at a's section y = rc, b's
|
||||
// x = 20 − rc, and c's rails where they meet a's and b's (z = 20 − ra, z = 20 − rb), the
|
||||
// patch's four corners. (2, 2, 3): 1.168 beyond the strips, of the 11.86 the block keeps;
|
||||
// (2, 3, 4): 3.099 of 32.69.
|
||||
for (rs, sel) in [((2.0, 2.0, 3.0), fillet(&ab, &[c], 3.0)), ((2.0, 3.0, 4.0), fillet_radii(&bx, &[(a, 2.0), (b, 3.0), (c, 4.0)]))] {
|
||||
let r = sel.unwrap();
|
||||
assert_eq!(r.face_count(), 10);
|
||||
assert_eq!(r.unmeshed_faces(), 0);
|
||||
let k = kink(&r);
|
||||
assert!(k < 0.05, "kink {k}°");
|
||||
let (v, s) = (vol(&r), strips(rs.0, rs.1, rs.2));
|
||||
assert!(v < s + 0.05 && v > s - 3.0, "{v} vs {s}");
|
||||
let (ra, rb, rc) = rs;
|
||||
let ends = [
|
||||
Vec3::new(20.0 - ra, rc, 20.0),
|
||||
Vec3::new(20.0, rc, 20.0 - ra),
|
||||
Vec3::new(20.0 - rc, rb, 20.0),
|
||||
Vec3::new(20.0 - rc, 0.0, 20.0 - rb),
|
||||
];
|
||||
for p in ends {
|
||||
assert!(vertices(&r).iter().any(|q| q.dist(p) < 1e-9), "{rs:?}: no patch corner at {p:?}");
|
||||
}
|
||||
let (v, s) = (vol(&r), strips(ra, rb, rc));
|
||||
assert!(v < s + 0.05 && v > s - corner_block(ra, rb, rc), "{v} vs {s}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user