Fillet rig: the geometry of the failing fillet and chamfer unit tests, as cases

The fillet and chamfer unit tests that checked geometry become fillets rig cases,
built through commands with answers derived by hand (each method field gives the
derivation): a plate outline and a disc rim as tall as or past their wall, a
notched block's outline at R7 and R8, a cube corner as wide as its faces (refused,
and reduced), the 1668 wall at R7 alone and both sides, the 2852 U shell at R30
(refused, naming 25.24), the 851 knife edge (R2, chamfers 0.5/2/5 on three
constructions), the arc top edge at the full wall height and at 9.5, the 851
table of selections, the 556 top edge ending on the boss wall, the 2893
cylinder-rim chamfer refusals and the elliptical rim, seed 33's full round, the
sloped basin rim blends (single edges with exact volumes, loops with the slab's
box), and three action-matrix chamfers and fillets. fillets/851's three-edge
corner gets its volume (67.051 removed, re-derived on a grid; the engine test had
67.05). Chamfers whose leg runs off the face beside the edge are refused and rounds
past a face on its tangent side build, as the owner ruled on 2026-10-30. The cases
that fail today are on KNOWN_FAILING with their cause.

The unit tests are removed, except two cut to what no command can express: the
per-edge-radius refusal at a cube corner and the chamfer of a cylinder's seam.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
jyviko
2026-10-30 06:55:35 -04:00
committed by Irakli Kourtis
parent b6d3c8b808
commit ebd1b15098
134 changed files with 5784 additions and 523 deletions
-85
View File
@@ -497,29 +497,6 @@ fn planned_volume(s: &Session) -> f64 {
s.model.state().bodies.iter().map(|b| b.body.mesh_plan(&solidcraft_kernel::MeshTolerance::chord(2e-4)).unwrap().evaluate().measure().volume).sum()
}
/// #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). 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, 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() < within, "{command}: removed {}, expected {removed}", before - after);
for b in &s.model.state().bodies {
assert!(b.body.validity().is_empty(), "{command}: {:?}", b.body.validity());
}
}
}
/// #851: the arc's top edge runs out tangent to the back face at the knife edge's top. The blend
/// is cut by that face along a curve that touches the wall's contact at the tip.
#[test]
@@ -539,53 +516,6 @@ fn blend_an_arc_edge_that_runs_out_tangent_to_a_face() {
}
}
/// #851: every selection of the issue's table works, picked together or one after the other as
/// the issue lists them, on the part with the wall that meets the front face square and runs out
/// tangent into the back face (the top front edge, the arc's top edge, the front upright at the
/// arc, the front-left upright and the knife edge at the tip). Each makes a sound solid the
/// display plan can mesh, and takes less than its edges would one by one where they meet.
#[test]
fn blend_corners_where_edges_meet_on_a_curved_wall() {
let (tf, at, fu, fl, kn) =
(json!([20, -21, 10]), json!([47.3174, -6.1508, 10]), json!([41.1667, -21, 5]), json!([0, -21, 5]), json!([62.1667, 0, 5]));
let fillet = |edges: Value| json!({"command": "solid.fillet", "params": {"edges": edges, "radius": 2}});
let chamfer = |edges: Value| json!({"command": "solid.chamfer", "params": {"edges": edges, "distance": 2}});
let base = planned_volume(&knife_edge_part());
let rows: Vec<(&str, Vec<Value>)> = vec![
("three at the corner", vec![fillet(json!([tf, at, fu]))]),
("top front and arc", vec![fillet(json!([tf, at]))]),
("arc and upright", vec![fillet(json!([at, fu]))]),
("top front and upright", vec![fillet(json!([tf, fu]))]),
("arc alone", vec![fillet(json!([at]))]),
("top front, then the front-left upright", vec![fillet(json!([tf])), fillet(json!([fl]))]),
("top front and front-left together", vec![fillet(json!([tf, fl]))]),
("the knife edge", vec![fillet(json!([kn]))]),
("chamfer: the knife edge", vec![chamfer(json!([kn]))]),
("chamfer: the arc", vec![chamfer(json!([at]))]),
("chamfer: the arc and the top front", vec![chamfer(json!([at, tf]))]),
("arc, then top front", vec![fillet(json!([at])), fillet(json!([tf]))]),
("top front, then upright", vec![fillet(json!([tf])), fillet(json!([fu]))]),
];
for (name, steps) in rows {
let mut s = knife_edge_part();
for step in &steps {
let (c, p) = (step["command"].as_str().unwrap_or(""), &step["params"]);
s.execute(c, p).unwrap_or_else(|e| panic!("{name}: {c} {p}: {e}"));
}
for b in &s.model.state().bodies {
assert!(b.body.validity().is_empty(), "{name}: {:?}", b.body.validity());
assert!(b.body.mesh_plan(&solidcraft_kernel::MeshTolerance::chord(2e-4)).is_ok(), "{name}: the display plan refuses the body");
}
let removed = base - planned_volume(&s);
assert!(removed > 0.0 && removed < 250.0, "{name}: removed {removed}");
}
// The three edges end in a sphere: the volume of the rounds and the ball's corner.
let mut s = knife_edge_part();
s.execute("solid.fillet", &fillet(json!([tf, at, fu]))["params"]).unwrap_or_else(|e| panic!("three at the corner: {e}"));
let removed = base - planned_volume(&s);
assert!((removed - 67.05).abs() < 0.15, "three at the corner: removed {removed}, expected 67.05");
}
/// Seed 20 cuts a patterned cylinder's holes through a filleted plate. The lenient retry of a
/// face's parameter boundary (#970) searched the whole cylinder for a point and found it across
/// the seam, half a turn away; the face was divided wrongly and the cut failed. Such a boundary
@@ -597,21 +527,6 @@ fn a_boundary_found_across_a_seam_is_not_used() {
assert!(r.steps.iter().any(|s| s.kind == "circular pattern"), "the pattern must build, not be skipped as unsupported: {:?}", r.unsupported);
}
/// Seed 33 ends in a fillet on its second body (#854's corner blends build it differently from
/// before). Its display plan and its measured volume agree for every body (on main before #854,
/// that body read 4439.42 through the display plan and 4443.51 measured).
#[test]
fn seed_33_display_plan_and_measure_agree() {
let r = fuzz::run(33, 8);
assert_eq!(r.outcome.kind, "ok", "seed 33: {:?}\n{}", r.outcome, r.script());
let s = script(r.script());
for b in &s.model.state().bodies {
let planned = b.body.mesh_plan(&solidcraft_kernel::MeshTolerance::chord(2e-4)).unwrap().evaluate().measure().volume;
let measured = solidcraft_kernel::measure(&b.body).unwrap().volume;
assert!((planned - measured).abs() < 2e-5 * measured, "{}: planned {planned}, measured {measured}", b.name);
}
}
/// A chamfer on a concave edge fills the corner, so it adds material, as a fillet there does. The
/// fuzzer expected every chamfer to shrink the body and reported these as a wrong volume (about
/// 1 % of the designs of a 6,000-seed run; seed 7100465: a box, a shell, a chamfer of an inside
-15
View File
@@ -1070,21 +1070,6 @@ mod tests {
}
}
#[test]
fn a_blend_ends_where_a_joined_boss_turns_back_round_its_end() {
// The box's top right edge runs into the cylinder at (40, 8, 20): the blend's end lies on
// the cylinder where the box was, now laid bare.
let body = box_and_boss();
let v0 = vol(&body);
for (round, area) in [(true, (1.0 - std::f64::consts::PI / 4.0) * 0.64), (false, 0.32)] {
let out = blend(&body, &[Vec3::new(40.0, 4.0, 20.0)], 0.8, round).unwrap();
assert!(out.validity().is_empty(), "{:?}", out.validity());
assert_eq!(out.lumps().unwrap().len(), 1);
let removed = v0 - vol(&out);
assert!((removed - area * 8.0).abs() < area * 8.0 * 1e-3, "{removed} vs {}", area * 8.0);
}
}
#[test]
fn a_blend_along_a_boss_ends_on_the_box_side_beside_it() {
// The boss's bottom edge outside the box (a half circle) ends at the box's side, square to
+5 -89
View File
@@ -298,81 +298,12 @@ mod tests {
}
}
/// A chamfer of a basin's rim loop whose leg would run off the 1 mm rim over the slab's front
/// edge is refused as too large, naming the largest that fits, just below the rim's width
/// (the fit search's step). (The loop's blends that fit, with their exact mitred volumes,
/// are the rig's fillets/1080-*-equal-slope-basin-* cases.)
#[test]
fn sloped_rim_fillets_stay_inside_the_material() {
use solidcraft_geom::{Loop2, Plane, Vec2};
for margin in [0.5, 1.0] {
let rectangle = |x0, y0, x1, y1| Loop2::polygon(&[Vec2::new(x0, y0), Vec2::new(x1, y0), Vec2::new(x1, y1), Vec2::new(x0, y1)]);
let slab = box_solid(Vec3::ZERO, Vec3::new(100.0, 60.0, 30.0)).unwrap();
let pocket = crate::loft(&[
(Plane::XY.offset(30.0), rectangle(20.0, margin, 80.0, 50.0)),
(Plane::XY.offset(10.0), rectangle(30.0, 20.0, 70.0, 40.0)),
])
.unwrap();
let basin = crate::boolean(&slab, &pocket, crate::BoolOp::Cut).unwrap().unwrap();
let picks = [Vec3::new(50.0, margin, 30.0), Vec3::new(80.0, 27.0, 30.0), Vec3::new(50.0, 50.0, 30.0), Vec3::new(20.0, 27.0, 30.0)];
// R4 runs over the thin rim's top past the slab's front edge (a cliff): it is built
// as if the top went on and cut from the slab (the blend-overflow decision,
// 237f0ae74), so nothing of it lies outside the slab.
for count in [1, 2, 4] {
for r in [4.0, margin * 0.5] {
let result = fillet(&basin, &picks[..count], r).unwrap_or_else(|e| panic!("{margin}, {count}, {r}: {e}"));
assert!(result.validity().is_empty(), "{margin}, {count}, {r}: {:?}", result.validity());
assert!(vol(&result) < vol(&basin));
for p in vertices(&result) {
assert!(
p.x >= 0.0 && p.x <= 100.0 && p.y >= 0.0 && p.y <= 60.0 && p.z >= 0.0 && p.z <= 30.0 + 1e-8,
"{margin}, {count}, {r}: {p:?}"
);
}
}
}
}
}
#[test]
fn chamfers_meet_on_unequal_sloped_rim_walls() {
use solidcraft_geom::{Loop2, Plane, Vec2};
for margin in [1.0, 4.0] {
let rectangle = |x0, y0, x1, y1| Loop2::polygon(&[Vec2::new(x0, y0), Vec2::new(x1, y0), Vec2::new(x1, y1), Vec2::new(x0, y1)]);
let slab = box_solid(Vec3::ZERO, Vec3::new(100.0, 60.0, 30.0)).unwrap();
let pocket = crate::loft(&[
(Plane::XY.offset(30.0), rectangle(20.0, margin, 80.0, 50.0)),
(Plane::XY.offset(10.0), rectangle(30.0, 20.0, 70.0, 40.0)),
])
.unwrap();
let basin = crate::boolean(&slab, &pocket, crate::BoolOp::Cut).unwrap().unwrap();
let picks = [Vec3::new(50.0, margin, 30.0), Vec3::new(80.0, 27.0, 30.0), Vec3::new(50.0, 50.0, 30.0), Vec3::new(20.0, 27.0, 30.0)];
for count in [2, 3, 4] {
if margin == 1.0 {
assert!(crate::chamfer(&basin, &picks[..count], 2.0).is_err());
assert!(crate::chamfer(&basin, &picks[..count], 1.0).is_err());
}
let distance = if margin == 1.0 { 0.5 } else { 2.0 };
let result = crate::chamfer(&basin, &picks[..count], distance).unwrap();
assert!(result.validity().is_empty());
assert_eq!(result.unmeshed_faces(), 0);
assert!(vol(&result) < vol(&basin));
assert!(vol(&basin) - vol(&result) < distance.powi(2) * (60.0 + 50.0 - margin));
let reverse: Vec<_> = picks[..count].iter().copied().rev().collect();
let reversed = crate::chamfer(&basin, &reverse, distance).unwrap();
assert!((vol(&result) - vol(&reversed)).abs() < 1e-6);
// These are exact planes, with every boundary on its owning face.
let rec = Faces::of(&result).unwrap();
for f in 0..rec.rec.faces.len() {
let Some(n) = rec.plane_normal(f) else { continue };
let points: Vec<Vec3> = rec.uses(f).filter_map(|u| rec.ends(u.edge as usize)).flat_map(|(a, b)| [a, b]).collect();
let origin = points[0];
for p in points {
assert!((p - origin).dot(n).abs() < 1e-7);
}
}
}
}
}
#[test]
fn equal_slope_rim_loops_stay_inside_the_material() {
fn a_rim_loop_chamfer_running_off_its_rim_is_refused_naming_the_largest() {
use solidcraft_geom::{Loop2, Plane, Vec2};
let rectangle = |x0, y0, x1, y1| Loop2::polygon(&[Vec2::new(x0, y0), Vec2::new(x1, y0), Vec2::new(x1, y1), Vec2::new(x0, y1)]);
let slab = box_solid(Vec3::ZERO, Vec3::new(100.0, 60.0, 30.0)).unwrap();
@@ -381,10 +312,6 @@ mod tests {
.unwrap();
let basin = crate::boolean(&slab, &pocket, crate::BoolOp::Cut).unwrap().unwrap();
let picks = [Vec3::new(50.0, 1.0, 30.0), Vec3::new(80.0, 27.0, 30.0), Vec3::new(50.0, 50.0, 30.0), Vec3::new(20.0, 27.0, 30.0)];
// The 2 mm chamfer's leg would run off the 1 mm rim's top over the slab's front edge and
// lower the front face: refused as too large, naming the largest that fits, below the
// rim's width (a full-width chamfer is refused too), the owner's blend-overflow ruling of
// 2026-10-30.
let message = match crate::chamfer(&basin, &picks, 2.0) {
Err(KernelError::TooLarge(m)) => m,
Err(e) => panic!("refused, but not as too large: {e}"),
@@ -392,16 +319,5 @@ mod tests {
};
let largest: f64 = message.rsplit("that fits is ").next().and_then(|t| t.trim_end_matches(" mm").parse().ok()).unwrap_or(0.0);
assert!((1.0 - 1e-3 - 1e-12..1.0).contains(&largest), "{message}");
// Past the 1 mm rim the R4 round runs over the slab's front edge on its tangent side (a
// cliff) and is cut from the slab (the same ruling): nothing escapes it.
for (round, size) in [(true, 4.0), (false, 0.5), (true, 0.5)] {
let result = if round { fillet(&basin, &picks, size) } else { crate::chamfer(&basin, &picks, size) };
let result = result.unwrap_or_else(|e| panic!("round={round}, {size}: {e}"));
assert!(result.validity().is_empty(), "round={round}, {size}: {:?}", result.validity());
assert!(vol(&result) < vol(&basin));
for p in vertices(&result) {
assert!(p.x >= 0.0 && p.x <= 100.0 && p.y >= 0.0 && p.y <= 60.0 && p.z >= 0.0 && p.z <= 30.0 + 1e-8, "round={round}, {size}: {p:?}");
}
}
}
}
@@ -8,7 +8,7 @@ use std::f64::consts::PI;
use solidcraft_geom::{Loop2, Plane, Region2, Vec2, Vec3};
use crate::build::{box_solid, extrude, extrude_tapered};
use crate::{Body, BoolOp, ChamferSide, KernelError, boolean, chamfer, chamfer_sides};
use crate::{Body, BoolOp, ChamferSide, boolean, chamfer, chamfer_sides};
const TOL: f64 = 1e-3;
@@ -193,35 +193,13 @@ fn cone_rim() {
assert!(rel(base - volume(&out), removed) < 3e-3, "{} vs {removed}", base - volume(&out));
}
/// A cylinder's seam is smooth: no edge there to chamfer. (The rim chamfers too large for the
/// faces, past the bottom, past the wall and of an elliptical rim are the rig's
/// fillets/2893-chamfer-* cases; the seam's place is the kernel's, so it stays here.)
#[test]
fn too_large_or_unsupported_is_refused() {
let c = cylinder(0.0);
// Across the whole top: the cone would end in a point.
assert!(chamfer_sides(&c, &[RIM], 10.0, ChamferSide::Distance(3.0), false).is_err());
assert!(chamfer_sides(&c, &[RIM], 12.0, ChamferSide::Distance(3.0), false).is_err());
// Down past the bottom.
assert!(chamfer_sides(&c, &[RIM], 2.0, ChamferSide::Distance(25.0), false).is_err());
// An angle that runs past the wall.
assert!(chamfer_sides(&c, &[RIM], 2.0, ChamferSide::Angle(PI / 2.0 + 0.01), false).is_err());
// A cylinder's seam is smooth: nothing to chamfer.
assert!(chamfer_sides(&c, &[Vec3::new(10.0, 0.0, 10.0)], 2.0, ChamferSide::Distance(3.0), false).is_err());
// A tilted cylinder cut flat: its rim on the cut is an ellipse, which the loop chamfer does
// not take. Refused as not supported, never a wrong solid.
let tilted = crate::build::cylinder(Vec3::new(0.0, 0.0, -10.0), Vec3::new(1.0, 0.0, 2.0), 5.0, 40.0).unwrap();
let cut = box_solid(Vec3::new(-50.0, -50.0, 10.0), Vec3::new(50.0, 50.0, 50.0)).unwrap();
let t = boolean(&tilted, &cut, BoolOp::Cut).unwrap().unwrap();
let rim = t
.record()
.edges
.iter()
.filter_map(|e| solidcraft_geom::brep::eval::CurveEval::new(e.parameters()).ok()?.point(0.5 * (e.interval[0] + e.interval[1])))
.find(|m| (m.z - 10.0).abs() < 1e-6)
.unwrap();
match chamfer_sides(&t, &[rim], 1.0, ChamferSide::Distance(2.0), false) {
Err(KernelError::Failed(m)) => assert!(m.starts_with("not supported yet"), "{m}"),
Err(e) => panic!("{e}"),
Ok(_) => panic!("an unequal chamfer of an elliptical rim was built"),
}
}
/// The top loop of a plate with rounded corners: lines and quarter circles, planar and
-16
View File
@@ -166,22 +166,6 @@ fn off_tip(x: f64, y: f64) -> bool {
(x - k.x).hypot(y - k.y) > 2.0 && a >= (-21.0 - k.y).atan2(CX - k.x) && a <= std::f64::consts::FRAC_PI_2
}
/// The knife-edge tip (the arc and the top line meeting at no angle) rounds to the ball 2 from
/// both, 13 back from the tip; its chamfer cuts the cusp at the chord between the same contacts.
#[test]
fn a_knife_edge_tip_rounds_where_the_ball_fits() {
let k = tip_ball();
let round = over_cusp(k.x - 1.0, |x, y| if off_tip(x, y) { 1.0 } else { 0.0 }) * 10.0;
let got = removed(true, &[TIP]);
assert!((got - round).abs() < round * 1e-3, "round: removed {got} vs {round}");
// The chord from the top line's contact to the arc's.
let (a, b) = (Vec2::new(k.x, 0.0), k + (Vec2::new(CX, -21.0) - k) * (2.0 / 23.0));
let beyond = |x: f64, y: f64| (b.x - a.x) * (y - a.y) - (b.y - a.y) * (x - a.x) > 0.0;
let flat = over_cusp(k.x - 1.0, |x, y| if beyond(x, y) { 1.0 } else { 0.0 }) * 10.0;
let got = removed(false, &[TIP]);
assert!((got - flat).abs() < flat * 1e-3, "chamfer: removed {got} vs {flat}");
}
/// The tip's round with the arc's or the back edge's at the top, where all three meet: as at
/// the front corner, each alone less what both would take twice — over the tip's corner region,
/// the other's (above 8 + √(4 − d²), d across from its ball's path).
-81
View File
@@ -103,84 +103,3 @@ fn chamfers_meeting_at_a_corner_still_build() {
assert!(crate::chamfer(&b, &edges, 5.0).is_ok());
assert!(crate::fillet(&b, &edges, 5.0).is_ok());
}
/// #1668: a box shelled outward 2 mm, open at the bottom. R5 on its top outer edge alone leaves
/// the sharp inside corner 2 mm away on its ball's side, 0.76 mm inside the round; it reaches
/// the corner only past 2√2 / (√2 - 1) ≈ 6.83 mm. With the inside edge rounded in the same
/// fillet, the two build as one feature as they do one after the other: the outer round takes
/// (1 - π/4) · 25 mm² along 104 mm, the inner one adds it along 100 mm.
#[test]
fn rounds_on_both_sides_of_a_wall_build_as_one_fillet() {
let outer = box_solid(Vec3::new(-52.0, -32.0, 0.0), Vec3::new(52.0, 32.0, 42.0)).unwrap();
let shelled = cut(&outer, [-50.0, -30.0, -1.0], [50.0, 30.0, 40.0]);
let v0 = 104.0 * 64.0 * 42.0 - 100.0 * 60.0 * 40.0;
let (out_edge, in_edge) = (Vec3::new(0.0, 32.0, 42.0), Vec3::new(0.0, 30.0, 40.0));
let section = (1.0 - std::f64::consts::FRAC_PI_4) * 25.0;
let alone = crate::fillet(&shelled, &[out_edge], 5.0).unwrap();
assert!(alone.validity().is_empty(), "{:?}", alone.validity());
let want = shelled.volume_at(0.01).unwrap() - section * 104.0;
assert!((crate::measure(&alone).unwrap().volume - want).abs() < 1e-4 * want);
// R7 alone passes the inside corner: the round is cut from the wall as if the hollow were
// not there, which opens a slit along the hollow's 100 mm. Its section (1 - π/4)·49 along
// 104, less its part over the hollow, the square [25, 30] × [35, 40] outside the circle about
// (25, 35) of radius 7: 5 (5 - √24) - (F(5) - F(√24)), F(t) = (t √(49 - t²) + 49 asin(t/7)) / 2.
let f = |t: f64| 0.5 * (t * (49.0 - t * t).sqrt() + 49.0 * (t / 7.0).asin());
let over = 5.0 * (5.0 - 24f64.sqrt()) - (f(5.0) - f(24f64.sqrt()));
let section7 = (1.0 - std::f64::consts::FRAC_PI_4) * 49.0;
let wide = crate::fillet(&shelled, &[out_edge], 7.0).unwrap();
assert!(wide.validity().is_empty(), "{:?}", wide.validity());
let want = v0 - (section7 * 104.0 - over * 100.0);
let v = crate::measure(&wide).unwrap().volume;
assert!((v - want).abs() < 1e-7 * want, "{v} vs {want}");
let both = crate::fillet(&shelled, &[out_edge, in_edge], 5.0).unwrap();
assert!(both.validity().is_empty(), "{:?}", both.validity());
let want = shelled.volume_at(0.01).unwrap() - section * 104.0 + section * 100.0;
let v = crate::measure(&both).unwrap().volume;
assert!((v - want).abs() < 1e-4 * want, "{v} vs {want}");
let stepped = crate::fillet(&crate::fillet(&shelled, &[in_edge], 5.0).unwrap(), &[out_edge], 5.0).unwrap();
assert!((crate::measure(&stepped).unwrap().volume - v).abs() < 1e-4 * want);
// Both at R7: the arcs, about (25, 35) and (23, 33), cross only outside both quarter arcs,
// and the inner round's material holds the part of the outer round over the hollow (at least
// 9.7 mm from (23, 33)), so the wall stays closed: the outer round takes its whole section
// along 104 and the inner one adds it along 100.
let both = crate::fillet(&shelled, &[out_edge, in_edge], 7.0).unwrap();
assert!(both.validity().is_empty(), "{:?}", both.validity());
let want = v0 - section7 * 4.0;
let v = crate::measure(&both).unwrap().volume;
assert!((v - want).abs() < 1e-7 * want, "{v} vs {want}");
}
/// A shell 3 mm thick bent over like an upside-down U: 60 wide, 20 long, 50 high, its top
/// plate from z = 47 to 50 and its walls from x = 0 to 3 and 57 to 60.
fn bent_shell() -> Body {
let b = box_solid(Vec3::new(0.0, 0.0, 0.0), Vec3::new(60.0, 20.0, 50.0)).unwrap();
cut(&b, [3.0, -1.0, -1.0], [57.0, 21.0, 47.0])
}
/// The corner left by a round of radius `r` on a 90° edge, per unit length.
fn corner(r: f64) -> f64 {
r * r * (1.0 - std::f64::consts::FRAC_PI_4)
}
/// An outside round concentric with the inside one keeps the wall 3 mm thick: the inside round
/// lies inside the outside one's wedge, but on its ball's side of the arc, which the round
/// leaves as it is. It used to be refused as running into other geometry.
#[test]
fn outside_round_concentric_with_the_inside_round_of_a_wall_fits() {
let s = bent_shell();
let inside = [Vec3::new(3.0, 10.0, 47.0), Vec3::new(57.0, 10.0, 47.0)];
let outside = [Vec3::new(0.0, 10.0, 50.0), Vec3::new(60.0, 10.0, 50.0)];
let a = crate::fillet(&s, &inside, 15.0).unwrap();
let b = crate::fillet(&a, &outside, 18.0).unwrap();
assert!(b.validity().is_empty(), "{:?}", b.validity());
// The inside rounds fill their corners, the outside ones take theirs away.
let want = s.volume_at(0.01).unwrap() + 2.0 * 20.0 * (corner(15.0) - corner(18.0));
let got = b.volume_at(0.01).unwrap();
assert!((got - want).abs() < 1e-3 * want, "{got} for {want}");
// Larger, the outside round's centre moves off the inside one's: it runs into the hollow
// where its arc crosses the inside round's, at r = (18√2 - 15) / (√2 - 1) ≈ 25.24 mm.
let m = too_large(crate::fillet(&a, &outside, 30.0));
let largest: f64 = m.rsplit("that fits is ").next().and_then(|t| t.trim_end_matches(" mm").parse().ok()).unwrap_or(0.0);
let limit = (18.0 * 2f64.sqrt() - 15.0) / (2f64.sqrt() - 1.0);
assert!(largest <= limit && largest > limit - 0.5, "{m}");
}
-66
View File
@@ -56,19 +56,6 @@ fn part_cut_from_a_box() -> Body {
boolean(&slab, &disc, BoolOp::Cut).unwrap().unwrap()
}
/// Area a chamfer of distance `d` takes off the cusp: the triangle between the plane's contact,
/// the tip and the wall's contact, less the wall's circular segment.
fn chamfered_area(d: f64) -> f64 {
let beta = ((R_WALL - d) / (R_WALL + d)).acos();
let o = (TIP_X - (4.0 * R_WALL * d).sqrt(), -d);
let c = (TIP_X, -R_WALL);
let k = R_WALL / (R_WALL + d);
let q2 = (c.0 + (o.0 - c.0) * k, c.1 + (o.1 - c.1) * k);
let (t1, tip) = ((o.0, 0.0), (TIP_X, 0.0));
let triangle = 0.5 * ((tip.0 - t1.0) * (q2.1 - t1.1) - (q2.0 - t1.0) * (tip.1 - t1.1)).abs();
triangle - 0.5 * R_WALL * R_WALL * (beta - beta.sin())
}
#[test]
fn fillet_the_knife_edge() {
for (name, body) in [("plate first", part()), ("corner first", part_other_order()), ("cut from a box", part_cut_from_a_box())] {
@@ -84,21 +71,6 @@ fn fillet_the_knife_edge() {
}
}
#[test]
fn chamfer_the_knife_edge() {
for (name, body) in [("plate first", part()), ("corner first", part_other_order()), ("cut from a box", part_cut_from_a_box())] {
let before = measure(&body).unwrap().volume;
for d in [0.5, 2.0, 5.0] {
let cut = chamfer(&body, &[knife()], d).unwrap_or_else(|e| panic!("{name} d={d}: {e}"));
assert!(cut.validity().is_empty(), "{name} d={d}: {:?}", cut.validity());
assert_eq!(cut.face_count(), body.face_count() + 1, "{name} d={d}: one chamfer face");
let v = measure(&cut).unwrap().volume;
let expected = before - HEIGHT * chamfered_area(d);
assert!((v - expected).abs() < 1e-3 * expected.abs(), "{name} d={d}: volume {v}, expected {expected}");
}
}
}
/// A ball that does not fit between the faces, and sizes at the ends of the range, are refused
/// or blended; they never panic or give an invalid solid.
#[test]
@@ -231,44 +203,6 @@ fn arc_top_edge_sizes_never_panic() {
}
}
/// At the full wall height the fitted contact coincides with the bottom arc. A round there uses
/// the wall up (the blend-overflow decision, 237f0ae74: a round may use up a face), taking the
/// whole corner between the wall and the top; a chamfer of the wall's full height is refused as
/// too large (it would leave the wall a zero-area face, #1113). Just below the limit the wall
/// still has area and both build. Face order and mirrored edge directions do not change either
/// outcome.
#[test]
fn arc_top_blend_uses_up_the_wall_and_refuses_a_collapsed_one() {
for body in [part(), part_other_order(), part_cut_from_a_box()] {
for z in [1.0, -1.0] {
let matrix = [[1.0, 0.0, 0.0, 0.0], [0.0, 1.0, 0.0, 0.0], [0.0, 0.0, z, 0.0], [0.0, 0.0, 0.0, 1.0]];
let body = transform_matrix(&body, matrix).unwrap();
let at = arc_top();
let pick = [Vec3::new(at.x, at.y, at.z * z)];
let before = planned_volume(&body);
for round in [true, false] {
let blend = |r| if round { fillet(&body, &pick, r) } else { chamfer(&body, &pick, r) };
if round {
let made = blend(HEIGHT).unwrap();
assert!(made.validity().is_empty(), "mirror={z}: {:?}", made.validity());
assert_eq!(made.face_count(), body.face_count(), "mirror={z}: the round takes the wall's place");
let removed = before - planned_volume(&made);
let expected = arc_top_removed(HEIGHT, true);
assert!((removed - expected).abs() < 0.01 * expected + 0.01, "mirror={z}: removed {removed}, expected {expected}");
} else {
let error = blend(HEIGHT).unwrap_err();
assert!(matches!(error, KernelError::TooLarge(_)), "mirror={z}: {error}");
}
let made = blend(HEIGHT - 0.5).unwrap();
assert!(made.validity().is_empty(), "round={round}, mirror={z}: {:?}", made.validity());
let removed = before - planned_volume(&made);
let expected = arc_top_removed(HEIGHT - 0.5, round);
assert!((removed - expected).abs() < 0.01 * expected + 0.01, "round={round}, mirror={z}: removed {removed}, expected {expected}");
}
}
}
}
fn tf() -> Vec3 {
Vec3::new(20.0, -R_WALL, HEIGHT)
}
+8 -141
View File
@@ -287,59 +287,6 @@ fn fillet_ending_across_two_faces() {
assert!((lost - removed).abs() < 0.07, "{lost} vs {removed}");
}
#[test]
fn loop_fillet_as_tall_as_its_wall_consumes_it() {
// The removed cross-section (a square of side r less a quarter disc) and its centroid's
// distance from the wall: r(10 − 3π) / (3(4 − π)).
let spandrel = |r: f64| ((1.0 - PI / 4.0) * r * r, r * (10.0 - 3.0 * PI) / (3.0 * (4.0 - PI)));
// #190: a disc 13 in radius and 2 high, its top circle rounded by 2. Pappus for the ring.
let disc = cylinder(Vec3::ZERO, Vec3::Z, 13.0, 2.0).unwrap();
let f = fillet(&disc, &[Vec3::new(0.0, 13.0, 2.0), Vec3::new(0.0, -13.0, 2.0)], 2.0).unwrap();
let (a, c) = spandrel(2.0);
let want = PI * 169.0 * 2.0 - a * 2.0 * PI * (13.0 - c);
let m = measure(&f).unwrap();
assert!(rel(m.volume, want) < 2e-4, "{} vs {want}", m.volume);
// Top, round and bottom: the wall is gone.
assert_eq!(m.merged.faces, 3, "{:?}", m.merged);
assert!(f.validity().is_empty(), "{:?}", f.validity());
// A 40 x 30 x 5 plate, its whole top outline rounded by 5 (mitred at the corners).
let plate = box_solid(Vec3::ZERO, Vec3::new(40.0, 30.0, 5.0)).unwrap();
let top = [Vec3::new(20.0, 0.0, 5.0), Vec3::new(40.0, 15.0, 5.0), Vec3::new(20.0, 30.0, 5.0), Vec3::new(0.0, 15.0, 5.0)];
let f = fillet(&plate, &top, 5.0).unwrap();
let (a, c) = spandrel(5.0);
let want = 6000.0 - a * 2.0 * ((40.0 - 2.0 * c) + (30.0 - 2.0 * c));
let m = measure(&f).unwrap();
assert!(rel(m.volume, want) < 2e-4, "{} vs {want}", m.volume);
assert!(f.validity().is_empty(), "{:?}", f.validity());
// Taller than the wall the round overflows on its tangent side, past the wall's bottom
// edge: it is built on the wall continued down and cut from the disc (the owner's
// blend-overflow ruling, 2026-10-30), keeping its radius. Its section in (ρ, z) is the r
// square at the edge outside the circle about (13 − r, 2 − r), above z = 0: with
// t = z − (2 − r) = r sin θ and ρ(θ) = 13 − r + r cos θ the disc keeps
// π (169·2 − ∫ (169 − ρ²) dz), θ from asin((r − 2) / r) (957.692239 at r = 2.5).
let kept = |r: f64| {
let (n, lo) = (20000, ((r - 2.0) / r).asin());
let taken: f64 = (0..n)
.map(|i| {
let th = lo + (f64::from(i) + 0.5) * (PI / 2.0 - lo) / f64::from(n);
let rho = 13.0 - r + r * th.cos();
(169.0 - rho * rho) * r * th.cos()
})
.sum::<f64>()
* (PI / 2.0 - lo)
/ f64::from(n);
PI * (169.0 * 2.0 - taken)
};
assert!(rel(kept(2.0), PI * 169.0 * 2.0 - spandrel(2.0).0 * 2.0 * PI * (13.0 - spandrel(2.0).1)) < 1e-9);
assert!((kept(2.5) - 957.692239).abs() < 1e-6, "{}", kept(2.5));
for r in [2.0 + 1e-3, 2.5] {
let f = fillet(&disc, &[Vec3::new(0.0, 13.0, 2.0), Vec3::new(0.0, -13.0, 2.0)], r).unwrap_or_else(|e| panic!("{r}: {e}"));
assert!(f.validity().is_empty(), "{r}: {:?}", f.validity());
let v = measure(&f).unwrap().volume;
assert!(rel(v, kept(r)) < 1e-6, "{r}: {v} vs {}", kept(r));
}
}
#[test]
fn fillet_consuming_a_side_face_makes_a_full_round() {
// 14 x 6 x 10: r = 3 on the four vertical edges uses up both 6 mm end faces (#199).
@@ -393,63 +340,6 @@ fn fillet_max_finds_the_largest_radius_that_works() {
assert_eq!(fillet_max(&b, &[Vec3::new(500.0, 0.0, 5.0)], 1.0).unwrap_err().to_string(), e.to_string());
}
/// Rounds past the bottom of a wall (a cliff) are built as if the wall went on and cut from the
/// part (the blend-overflow decision, 237f0ae74), never refused as too large: a disc's top edge
/// past its 2 mm wall, and a block's top outline past the 7 mm wall over a notch.
#[test]
fn rounds_past_the_bottom_of_a_wall_are_cut_from_the_part() {
// A 2 mm disc's top edge at 2.5 runs past the wall's bottom edge (a cliff): the round is
// built as if the wall went on down and cut from the disc (the blend-overflow decision,
// 237f0ae74), not refused. Its section in (ρ, z), the 2.5 square at the edge outside the
// circle about (10.5, -0.5) above z = 0, turned about the axis: with t = z + 0.5 =
// 2.5 sin θ, the round's inner radius ρ(θ) = 10.5 + 2.5 cos θ, the disc keeps
// π (169·2 − ∫ (169 − ρ²) dz) (2 mm: Pappus, as `loop_fillet_as_tall_as_its_wall_consumes_it`).
use std::f64::consts::FRAC_PI_2;
let disc = cylinder(Vec3::ZERO, Vec3::Z, 13.0, 2.0).unwrap();
let top = [Vec3::new(0.0, 13.0, 2.0), Vec3::new(0.0, -13.0, 2.0)];
let past = fillet(&disc, &top, 2.5).unwrap();
let (n, lo) = (20000, (0.5f64 / 2.5).asin());
let taken: f64 = (0..n)
.map(|i| {
let th = lo + (i as f64 + 0.5) * (FRAC_PI_2 - lo) / n as f64;
let rho = 10.5 + 2.5 * th.cos();
(169.0 - rho * rho) * 2.5 * th.cos()
})
.sum::<f64>()
* (FRAC_PI_2 - lo)
/ n as f64;
let want = PI * (169.0 * 2.0 - taken);
assert!(rel(measure(&past).unwrap().volume, want) < 1e-6, "{} vs {want}", measure(&past).unwrap().volume);
// Walls of different heights, a 7 mm one over a notch: R7 uses that wall up (a round may),
// and R8 runs past its bottom edge into the notch (a cliff) and is cut by it. The outline's
// mitred round takes (1 − π/4) r² along the outline less 8 times its centroid's distance
// from the faces, r (10 − 3π) / (3 (4 − π)); at R8 less its part inside the notch
// [35, 40] × [0, 5] × [2, 3], where each of the corner's two rounds reaches g = 8 − √(64 − t²)
// in from its face at t = z − 2 on its side of the mitre: ∫₀¹ 2 (5g − g²/2) dt.
let notched = boolean(
&box_solid(Vec3::ZERO, Vec3::new(40.0, 30.0, 10.0)).unwrap(),
&box_solid(Vec3::new(35.0, -1.0, -1.0), Vec3::new(41.0, 5.0, 3.0)).unwrap(),
BoolOp::Cut,
)
.unwrap()
.unwrap();
let outline = [Vec3::new(20.0, 0.0, 10.0), Vec3::new(40.0, 15.0, 10.0), Vec3::new(20.0, 30.0, 10.0), Vec3::new(0.0, 15.0, 10.0)];
let mitred = |r: f64| (1.0 - PI / 4.0) * r * r * (140.0 - 8.0 * r * (10.0 - 3.0 * PI) / (3.0 * (4.0 - PI)));
let in_notch: f64 = (0..n)
.map(|i| {
let t = (i as f64 + 0.5) / n as f64;
let g = 8.0 - (64.0 - t * t).sqrt();
2.0 * (5.0 * g - g * g / 2.0)
})
.sum::<f64>()
/ n as f64;
for (r, want) in [(7.0, 11925.0 - mitred(7.0)), (8.0, 11925.0 - (mitred(8.0) - in_notch))] {
let b = fillet(&notched, &outline, r).unwrap();
assert!(b.validity().is_empty(), "{r}: {:?}", b.validity());
assert!(rel(measure(&b).unwrap().volume, want) < 1e-6, "{r}: {} vs {want}", measure(&b).unwrap().volume);
}
}
/// Edges that share no face get their own largest radius: a 2 mm fin's top edge takes at most
/// its thickness, while a corner of the block it stands on, far from it, keeps the 4 asked for.
/// Edges that limit each other (the post's four, sharing faces) still share one.
@@ -483,24 +373,14 @@ fn fillet_max_each_reduces_only_where_the_radius_does_not_fit() {
assert_eq!(fillet_max_each(&post, &mids, 3.5).unwrap().map(|x| x.0), Some(vec![3.0; 4]));
}
/// A corner's rounds too large for its faces are refused as too large, so a fit can reduce
/// them, also where only the corner build finds it (the edge-by-edge blend failing otherwise).
/// A corner's rounds with a radius per edge, one wider than its faces, are refused as too large,
/// so a fit can reduce them. (The same corner at one radius as wide as the faces, and its fit,
/// are the rig's fillets/477-fillet-cube-corner-rounds-as-wide-as-faces-* cases; no command
/// takes a radius per edge.)
#[test]
fn corner_rounds_larger_than_their_faces_are_too_large() {
let (l, eps) = (20.0, 1e-9);
let b = box_solid(Vec3::ZERO, Vec3::new(l, l, l)).unwrap();
let b = box_solid(Vec3::ZERO, Vec3::new(20.0, 20.0, 20.0)).unwrap();
let corner = [Vec3::new(10.0, 0.0, 0.0), Vec3::new(0.0, 10.0, 0.0), Vec3::new(0.0, 0.0, 10.0)];
// As wide as the faces: the first edge's round uses up its neighbour, then the edge-by-edge
// blend can't find it; the corner build is what says the radius is too large.
let e = fillet(&b, &corner, l).unwrap_err();
assert!(matches!(e, KernelError::TooLarge(_)), "{e}");
let (r, body) = fillet_max(&b, &corner, l).unwrap().unwrap();
assert!((r - 19.99).abs() < eps, "{r}");
assert!(body.validity().is_empty(), "{:?}", body.validity());
// Three rounds along the edges past the corner cube, and the cube less its sphere octant.
let removed = 3.0 * (1.0 - PI / 4.0) * r * r * (l - r) + r * r * r * (1.0 - PI / 6.0);
assert!(rel(measure(&body).unwrap().volume, l * l * l - removed) < 2e-4);
// Different radii per edge, one wider than its faces.
let sel: Vec<(Vec3, f64)> = corner.iter().copied().zip([21.0, 5.0, 5.0]).collect();
let e = crate::blend_corner::fillet_radii(&b, &sel).unwrap_err();
assert!(matches!(e, KernelError::TooLarge(_)), "{e}");
@@ -1225,12 +1105,12 @@ fn chamfer_sloped_basin_rim() {
}
/// A chamfer wider than a basin's thin rim (`chamfer_sloped_basin_rim`'s basin with the rim
/// `margin` wide at the top) would run its leg off the rim's top, over the slab's front edge,
/// and lower the front face (a 2 mm chamfer on the 1 mm rim takes its top from 30 to 29.382):
/// `margin` wide at the top) would run its leg off the rim's top, over the slab's front edge:
/// refused as too large, naming the largest size that fits, the body unchanged (the owner's
/// blend-overflow ruling, 2026-10-30). As wide as the rim it would use the rim's top up: refused
/// too, so the largest that fits is the size just below the rim's width (the fit search's step,
/// three significant digits of the size asked for). A smaller chamfer builds.
/// three significant digits of the size asked for). (The chamfers that fit, with their exact
/// volumes, are the rig's fillets/1080-chamfer-sloped-basin-* cases.)
#[test]
fn chamfer_wider_than_sloped_basin_rim_is_refused_naming_the_largest() {
let rectangle = |x0, y0, x1, y1| Loop2::polygon(&[Vec2::new(x0, y0), Vec2::new(x1, y0), Vec2::new(x1, y1), Vec2::new(x0, y1)]);
@@ -1254,19 +1134,6 @@ fn chamfer_wider_than_sloped_basin_rim_is_refused_naming_the_largest() {
assert!((margin - step - 1e-12..margin).contains(&largest), "{margin}, {distance}: {message}");
assert_eq!(measure(&b).unwrap().volume, before);
}
// Half the rim's width fits: as `chamfer_sloped_basin_rim`, the triangle of legs d on the
// top and d down the wall (towards (20, 10), its run 20 − margin over the drop 20) takes
// d · drop / 2 with drop = 20 d / √((20 − margin)² + 400), its length 60 − h between the
// sloped end walls at depth h, so its volume is that area times 60 − drop / 3.
for margin in [0.5, 1.0] {
let b = basin(margin);
let d = margin * 0.5;
let smaller = chamfer(&b, &[Vec3::new(50.0, margin, 30.0)], d).unwrap();
assert!(smaller.validity().is_empty(), "{margin}: {:?}", smaller.validity());
let drop = 20.0 * d / ((20.0 - margin).powi(2) + 400.0).sqrt();
let want = measure(&b).unwrap().volume - d * drop / 2.0 * (60.0 - drop / 3.0);
assert!(rel(measure(&smaller).unwrap().volume, want) < 1e-8, "{margin}: {} vs {want}", measure(&smaller).unwrap().volume);
}
}
#[test]
@@ -0,0 +1,21 @@
{
"sources": [
"tangency-labs/solidcraft#1080"
],
"what": "all four top rim edges of a basin whose walls all slope 10 over 20, its front rim 1 mm wide, chamfered 0.5",
"source": "invariants",
"method": "slab 100 x 60 x 30 less the loft from the rectangle (20, 1)-(80, 50) at z = 30 to (30, 11)-(70, 40) at z = 10 (planar walls, a prismatoid: 20/6 (A_top + A_bottom + 4 A_mid)): V0 = 140333.333333. the rim's corners are re-entrant (the pocket's corners), where the blends of two sides meet; with sloped walls of different slopes that meeting has no closed form here. Nothing may leave the slab: the box is the slab's, which keeps its outside faces whole.",
"body_count": 1,
"bbox": {
"min": [
0,
0,
0
],
"max": [
100,
60,
30
]
}
}
@@ -0,0 +1,105 @@
{
"commands": [
{
"command": "solid.box",
"params": {
"length": 100,
"width": 60,
"height": 30,
"body_name": "Slab"
}
},
{
"command": "sketch.create",
"params": {
"plane": "XY",
"offset": 30,
"name": "Top"
}
},
{
"command": "sketch.rectangle.two_point",
"params": {
"p0": [
20,
1
],
"p1": [
80,
50
]
}
},
{
"command": "sketch.finish",
"params": {}
},
{
"command": "sketch.create",
"params": {
"plane": "XY",
"offset": 10,
"name": "Bottom"
}
},
{
"command": "sketch.rectangle.two_point",
"params": {
"p0": [
30,
11
],
"p1": [
70,
40
]
}
},
{
"command": "sketch.finish",
"params": {}
},
{
"command": "solid.loft",
"params": {
"sections": [
{
"sketch": "Top"
},
{
"sketch": "Bottom"
}
],
"operation": "cut"
}
},
{
"command": "solid.chamfer",
"params": {
"edges": [
[
50,
1,
30
],
[
80,
27,
30
],
[
50,
50,
30
],
[
20,
27,
30
]
],
"distance": 0.5
}
}
]
}
@@ -0,0 +1,10 @@
{
"sources": [
"tangency-labs/solidcraft#1080"
],
"what": "all four top rim edges of a basin whose walls all slope 10 over 20, its front rim 1 mm wide, chamfered 2: the front chamfer's leg runs off the rim, so it is refused, naming the largest distance that fits",
"source": "analytic",
"method": "slab 100 x 60 x 30 less the loft from the rectangle (20, 1)-(80, 50) at z = 30 to (30, 11)-(70, 40) at z = 10 (planar walls, a prismatoid: 20/6 (A_top + A_bottom + 4 A_mid)): V0 = 140333.333333. The front chamfer's leg on the 1 mm rim would reach y = -1, over the slab's front face: refused (the owner's ruling of 2026-10-30).",
"outcome": "refused",
"refusal": "the largest distance that fits is"
}
@@ -0,0 +1,105 @@
{
"commands": [
{
"command": "solid.box",
"params": {
"length": 100,
"width": 60,
"height": 30,
"body_name": "Slab"
}
},
{
"command": "sketch.create",
"params": {
"plane": "XY",
"offset": 30,
"name": "Top"
}
},
{
"command": "sketch.rectangle.two_point",
"params": {
"p0": [
20,
1
],
"p1": [
80,
50
]
}
},
{
"command": "sketch.finish",
"params": {}
},
{
"command": "sketch.create",
"params": {
"plane": "XY",
"offset": 10,
"name": "Bottom"
}
},
{
"command": "sketch.rectangle.two_point",
"params": {
"p0": [
30,
11
],
"p1": [
70,
40
]
}
},
{
"command": "sketch.finish",
"params": {}
},
{
"command": "solid.loft",
"params": {
"sections": [
{
"sketch": "Top"
},
{
"sketch": "Bottom"
}
],
"operation": "cut"
}
},
{
"command": "solid.chamfer",
"params": {
"edges": [
[
50,
1,
30
],
[
80,
27,
30
],
[
50,
50,
30
],
[
20,
27,
30
]
],
"distance": 2
}
}
]
}
@@ -0,0 +1,10 @@
{
"sources": [
"tangency-labs/solidcraft#1080"
],
"what": "the 0.5 mm front rim of a sloped basin's top chamfered 4: its leg on the top runs off the rim over the slab's front face, so it is refused, naming the largest distance that fits",
"source": "analytic",
"method": "slab 100 x 60 x 30 less the loft from the rectangle (20, 0.5)-(80, 50) at z = 30 to (30, 20)-(70, 40) at z = 10 (planar walls, a prismatoid: 20/6 (A_top + A_bottom + 4 A_mid)): V0 = 144266.666667. The chamfer's leg on the rim's top (0.5 mm wide) would reach y = -3.5, off the rim and over the slab's front face y = 0, lowering that face: the owner's ruling of 2026-10-30 refuses a chamfer whose leg runs off the face beside its edge, naming the largest distance that fits.",
"outcome": "refused",
"refusal": "the largest distance that fits is"
}
@@ -0,0 +1,90 @@
{
"commands": [
{
"command": "solid.box",
"params": {
"length": 100,
"width": 60,
"height": 30,
"body_name": "Slab"
}
},
{
"command": "sketch.create",
"params": {
"plane": "XY",
"offset": 30,
"name": "Top"
}
},
{
"command": "sketch.rectangle.two_point",
"params": {
"p0": [
20,
0.5
],
"p1": [
80,
50
]
}
},
{
"command": "sketch.finish",
"params": {}
},
{
"command": "sketch.create",
"params": {
"plane": "XY",
"offset": 10,
"name": "Bottom"
}
},
{
"command": "sketch.rectangle.two_point",
"params": {
"p0": [
30,
20
],
"p1": [
70,
40
]
}
},
{
"command": "sketch.finish",
"params": {}
},
{
"command": "solid.loft",
"params": {
"sections": [
{
"sketch": "Top"
},
{
"sketch": "Bottom"
}
],
"operation": "cut"
}
},
{
"command": "solid.chamfer",
"params": {
"edges": [
[
50,
0.5,
30
]
],
"distance": 4
}
}
]
}
@@ -0,0 +1,10 @@
{
"sources": [
"tangency-labs/solidcraft#1080"
],
"what": "the 0.5 mm front rim of a sloped basin's top chamfered 0.5: as wide as the rim, the chamfer would use the rim's top up: refused",
"source": "analytic",
"method": "slab 100 x 60 x 30 less the loft from the rectangle (20, 0.5)-(80, 50) at z = 30 to (30, 20)-(70, 40) at z = 10 (planar walls, a prismatoid: 20/6 (A_top + A_bottom + 4 A_mid)): V0 = 144266.666667. A chamfer as wide as the face beside its edge uses it up: full-width chamfers are refused (the owner's ruling of 2026-10-30).",
"outcome": "refused",
"refusal": "the largest distance that fits is"
}
@@ -0,0 +1,90 @@
{
"commands": [
{
"command": "solid.box",
"params": {
"length": 100,
"width": 60,
"height": 30,
"body_name": "Slab"
}
},
{
"command": "sketch.create",
"params": {
"plane": "XY",
"offset": 30,
"name": "Top"
}
},
{
"command": "sketch.rectangle.two_point",
"params": {
"p0": [
20,
0.5
],
"p1": [
80,
50
]
}
},
{
"command": "sketch.finish",
"params": {}
},
{
"command": "sketch.create",
"params": {
"plane": "XY",
"offset": 10,
"name": "Bottom"
}
},
{
"command": "sketch.rectangle.two_point",
"params": {
"p0": [
30,
20
],
"p1": [
70,
40
]
}
},
{
"command": "sketch.finish",
"params": {}
},
{
"command": "solid.loft",
"params": {
"sections": [
{
"sketch": "Top"
},
{
"sketch": "Bottom"
}
],
"operation": "cut"
}
},
{
"command": "solid.chamfer",
"params": {
"edges": [
[
50,
0.5,
30
]
],
"distance": 0.5
}
}
]
}
@@ -0,0 +1,25 @@
{
"sources": [
"tangency-labs/solidcraft#1080"
],
"what": "the 0.5 mm front rim of a sloped basin's top chamfered 0.25, half the rim's width: it fits",
"source": "analytic",
"method": "slab 100 x 60 x 30 less the loft from the rectangle (20, 0.5)-(80, 50) at z = 30 to (30, 20)-(70, 40) at z = 10 (planar walls, a prismatoid: 20/6 (A_top + A_bottom + 4 A_mid)): V0 = 144266.666667. The chamfer's triangle in (y, z): the edge (0.5, 30), its leg on the top to (0.25, 30) and d down the wall to (0.5 + d (20-0.5)/L, 30 - 20 d/L), L = sqrt((20-0.5)^2 + 400). At height z the blend runs between the sloped end walls x = 20 + (30-z)/2 and 80 - (30-z)/2 extended, which cut it: its length there is 30 + z, so it takes Int Int (30 + z) dy dz over its section (y, z). Removed (shoelace for the area and its first moment) 1.341165. V = 144265.325501",
"body_count": 1,
"volume_mm3": 144265.32550144705,
"bbox": {
"min": [
0,
0,
0
],
"max": [
100,
60,
30
]
},
"tolerance": {
"rel": 1e-06
}
}
@@ -0,0 +1,90 @@
{
"commands": [
{
"command": "solid.box",
"params": {
"length": 100,
"width": 60,
"height": 30,
"body_name": "Slab"
}
},
{
"command": "sketch.create",
"params": {
"plane": "XY",
"offset": 30,
"name": "Top"
}
},
{
"command": "sketch.rectangle.two_point",
"params": {
"p0": [
20,
0.5
],
"p1": [
80,
50
]
}
},
{
"command": "sketch.finish",
"params": {}
},
{
"command": "sketch.create",
"params": {
"plane": "XY",
"offset": 10,
"name": "Bottom"
}
},
{
"command": "sketch.rectangle.two_point",
"params": {
"p0": [
30,
20
],
"p1": [
70,
40
]
}
},
{
"command": "sketch.finish",
"params": {}
},
{
"command": "solid.loft",
"params": {
"sections": [
{
"sketch": "Top"
},
{
"sketch": "Bottom"
}
],
"operation": "cut"
}
},
{
"command": "solid.chamfer",
"params": {
"edges": [
[
50,
0.5,
30
]
],
"distance": 0.25
}
}
]
}
@@ -0,0 +1,10 @@
{
"sources": [
"tangency-labs/solidcraft#1080"
],
"what": "the 1 mm front rim of a sloped basin's top chamfered 2: its leg on the top runs off the rim over the slab's front face, so it is refused, naming the largest distance that fits",
"source": "analytic",
"method": "slab 100 x 60 x 30 less the loft from the rectangle (20, 1)-(80, 50) at z = 30 to (30, 20)-(70, 40) at z = 10 (planar walls, a prismatoid: 20/6 (A_top + A_bottom + 4 A_mid)): V0 = 144533.333333. The chamfer's leg on the rim's top (1 mm wide) would reach y = -1, off the rim and over the slab's front face y = 0, lowering that face: the owner's ruling of 2026-10-30 refuses a chamfer whose leg runs off the face beside its edge, naming the largest distance that fits.",
"outcome": "refused",
"refusal": "the largest distance that fits is"
}
@@ -0,0 +1,90 @@
{
"commands": [
{
"command": "solid.box",
"params": {
"length": 100,
"width": 60,
"height": 30,
"body_name": "Slab"
}
},
{
"command": "sketch.create",
"params": {
"plane": "XY",
"offset": 30,
"name": "Top"
}
},
{
"command": "sketch.rectangle.two_point",
"params": {
"p0": [
20,
1
],
"p1": [
80,
50
]
}
},
{
"command": "sketch.finish",
"params": {}
},
{
"command": "sketch.create",
"params": {
"plane": "XY",
"offset": 10,
"name": "Bottom"
}
},
{
"command": "sketch.rectangle.two_point",
"params": {
"p0": [
30,
20
],
"p1": [
70,
40
]
}
},
{
"command": "sketch.finish",
"params": {}
},
{
"command": "solid.loft",
"params": {
"sections": [
{
"sketch": "Top"
},
{
"sketch": "Bottom"
}
],
"operation": "cut"
}
},
{
"command": "solid.chamfer",
"params": {
"edges": [
[
50,
1,
30
]
],
"distance": 2
}
}
]
}
@@ -0,0 +1,10 @@
{
"sources": [
"tangency-labs/solidcraft#1080"
],
"what": "the 1 mm front rim of a sloped basin's top chamfered 3: its leg on the top runs off the rim over the slab's front face, so it is refused, naming the largest distance that fits",
"source": "analytic",
"method": "slab 100 x 60 x 30 less the loft from the rectangle (20, 1)-(80, 50) at z = 30 to (30, 20)-(70, 40) at z = 10 (planar walls, a prismatoid: 20/6 (A_top + A_bottom + 4 A_mid)): V0 = 144533.333333. The chamfer's leg on the rim's top (1 mm wide) would reach y = -2, off the rim and over the slab's front face y = 0, lowering that face: the owner's ruling of 2026-10-30 refuses a chamfer whose leg runs off the face beside its edge, naming the largest distance that fits.",
"outcome": "refused",
"refusal": "the largest distance that fits is"
}
@@ -0,0 +1,90 @@
{
"commands": [
{
"command": "solid.box",
"params": {
"length": 100,
"width": 60,
"height": 30,
"body_name": "Slab"
}
},
{
"command": "sketch.create",
"params": {
"plane": "XY",
"offset": 30,
"name": "Top"
}
},
{
"command": "sketch.rectangle.two_point",
"params": {
"p0": [
20,
1
],
"p1": [
80,
50
]
}
},
{
"command": "sketch.finish",
"params": {}
},
{
"command": "sketch.create",
"params": {
"plane": "XY",
"offset": 10,
"name": "Bottom"
}
},
{
"command": "sketch.rectangle.two_point",
"params": {
"p0": [
30,
20
],
"p1": [
70,
40
]
}
},
{
"command": "sketch.finish",
"params": {}
},
{
"command": "solid.loft",
"params": {
"sections": [
{
"sketch": "Top"
},
{
"sketch": "Bottom"
}
],
"operation": "cut"
}
},
{
"command": "solid.chamfer",
"params": {
"edges": [
[
50,
1,
30
]
],
"distance": 3
}
}
]
}
@@ -0,0 +1,10 @@
{
"sources": [
"tangency-labs/solidcraft#1080"
],
"what": "the 1 mm front rim of a sloped basin's top chamfered 1: as wide as the rim, the chamfer would use the rim's top up: refused",
"source": "analytic",
"method": "slab 100 x 60 x 30 less the loft from the rectangle (20, 1)-(80, 50) at z = 30 to (30, 20)-(70, 40) at z = 10 (planar walls, a prismatoid: 20/6 (A_top + A_bottom + 4 A_mid)): V0 = 144533.333333. A chamfer as wide as the face beside its edge uses it up: full-width chamfers are refused (the owner's ruling of 2026-10-30).",
"outcome": "refused",
"refusal": "the largest distance that fits is"
}
@@ -0,0 +1,90 @@
{
"commands": [
{
"command": "solid.box",
"params": {
"length": 100,
"width": 60,
"height": 30,
"body_name": "Slab"
}
},
{
"command": "sketch.create",
"params": {
"plane": "XY",
"offset": 30,
"name": "Top"
}
},
{
"command": "sketch.rectangle.two_point",
"params": {
"p0": [
20,
1
],
"p1": [
80,
50
]
}
},
{
"command": "sketch.finish",
"params": {}
},
{
"command": "sketch.create",
"params": {
"plane": "XY",
"offset": 10,
"name": "Bottom"
}
},
{
"command": "sketch.rectangle.two_point",
"params": {
"p0": [
30,
20
],
"p1": [
70,
40
]
}
},
{
"command": "sketch.finish",
"params": {}
},
{
"command": "solid.loft",
"params": {
"sections": [
{
"sketch": "Top"
},
{
"sketch": "Bottom"
}
],
"operation": "cut"
}
},
{
"command": "solid.chamfer",
"params": {
"edges": [
[
50,
1,
30
]
],
"distance": 1
}
}
]
}
@@ -0,0 +1,25 @@
{
"sources": [
"tangency-labs/solidcraft#1080"
],
"what": "the 1 mm front rim of a sloped basin's top chamfered 0.5, half the rim's width: it fits",
"source": "analytic",
"method": "slab 100 x 60 x 30 less the loft from the rectangle (20, 1)-(80, 50) at z = 30 to (30, 20)-(70, 40) at z = 10 (planar walls, a prismatoid: 20/6 (A_top + A_bottom + 4 A_mid)): V0 = 144533.333333. The chamfer's triangle in (y, z): the edge (1, 30), its leg on the top to (0.5, 30) and d down the wall to (1 + d (20-1)/L, 30 - 20 d/L), L = sqrt((20-1)^2 + 400). At height z the blend runs between the sloped end walls x = 20 + (30-z)/2 and 80 - (30-z)/2 extended, which cut it: its length there is 30 + z, so it takes Int Int (30 + z) dy dz over its section (y, z). Removed (shoelace for the area and its first moment) 5.426545. V = 144527.906788",
"body_count": 1,
"volume_mm3": 144527.9067880851,
"bbox": {
"min": [
0,
0,
0
],
"max": [
100,
60,
30
]
},
"tolerance": {
"rel": 1e-06
}
}
@@ -0,0 +1,90 @@
{
"commands": [
{
"command": "solid.box",
"params": {
"length": 100,
"width": 60,
"height": 30,
"body_name": "Slab"
}
},
{
"command": "sketch.create",
"params": {
"plane": "XY",
"offset": 30,
"name": "Top"
}
},
{
"command": "sketch.rectangle.two_point",
"params": {
"p0": [
20,
1
],
"p1": [
80,
50
]
}
},
{
"command": "sketch.finish",
"params": {}
},
{
"command": "sketch.create",
"params": {
"plane": "XY",
"offset": 10,
"name": "Bottom"
}
},
{
"command": "sketch.rectangle.two_point",
"params": {
"p0": [
30,
20
],
"p1": [
70,
40
]
}
},
{
"command": "sketch.finish",
"params": {}
},
{
"command": "solid.loft",
"params": {
"sections": [
{
"sketch": "Top"
},
{
"sketch": "Bottom"
}
],
"operation": "cut"
}
},
{
"command": "solid.chamfer",
"params": {
"edges": [
[
50,
1,
30
]
],
"distance": 0.5
}
}
]
}
@@ -0,0 +1,24 @@
{
"sources": [
"tangency-labs/solidcraft#1080"
],
"what": "all four top rim edges of a basin whose walls all slope 10 over 20, its front rim 1 mm wide, rounded R 0.5",
"source": "invariants",
"method": "slab 100 x 60 x 30 less the loft from the rectangle (20, 1)-(80, 50) at z = 30 to (30, 11)-(70, 40) at z = 10 (planar walls, a prismatoid: 20/6 (A_top + A_bottom + 4 A_mid)): V0 = 140333.333333. the rim's corners are re-entrant (the pocket's corners), where the blends of two sides meet; with sloped walls of different slopes that meeting has no closed form here. Nothing may leave the slab: the box is the slab's, which keeps its outside faces whole.",
"body_count": 1,
"bbox": {
"min": [
0,
0,
0
],
"max": [
100,
60,
30
]
},
"continuity": {
"order": "g1"
}
}
@@ -0,0 +1,105 @@
{
"commands": [
{
"command": "solid.box",
"params": {
"length": 100,
"width": 60,
"height": 30,
"body_name": "Slab"
}
},
{
"command": "sketch.create",
"params": {
"plane": "XY",
"offset": 30,
"name": "Top"
}
},
{
"command": "sketch.rectangle.two_point",
"params": {
"p0": [
20,
1
],
"p1": [
80,
50
]
}
},
{
"command": "sketch.finish",
"params": {}
},
{
"command": "sketch.create",
"params": {
"plane": "XY",
"offset": 10,
"name": "Bottom"
}
},
{
"command": "sketch.rectangle.two_point",
"params": {
"p0": [
30,
11
],
"p1": [
70,
40
]
}
},
{
"command": "sketch.finish",
"params": {}
},
{
"command": "solid.loft",
"params": {
"sections": [
{
"sketch": "Top"
},
{
"sketch": "Bottom"
}
],
"operation": "cut"
}
},
{
"command": "solid.fillet",
"params": {
"edges": [
[
50,
1,
30
],
[
80,
27,
30
],
[
50,
50,
30
],
[
20,
27,
30
]
],
"radius": 0.5
}
}
]
}
@@ -0,0 +1,24 @@
{
"sources": [
"tangency-labs/solidcraft#1080"
],
"what": "all four top rim edges of a basin whose walls all slope 10 over 20, its front rim 1 mm wide, rounded R 4: past the rim the front round runs over the slab's front face and is cut from the slab",
"source": "invariants",
"method": "slab 100 x 60 x 30 less the loft from the rectangle (20, 1)-(80, 50) at z = 30 to (30, 11)-(70, 40) at z = 10 (planar walls, a prismatoid: 20/6 (A_top + A_bottom + 4 A_mid)): V0 = 140333.333333. the rim's corners are re-entrant (the pocket's corners), where the blends of two sides meet; with sloped walls of different slopes that meeting has no closed form here. Nothing may leave the slab: the box is the slab's, which keeps its outside faces whole.",
"body_count": 1,
"bbox": {
"min": [
0,
0,
0
],
"max": [
100,
60,
30
]
},
"continuity": {
"order": "g1"
}
}
@@ -0,0 +1,105 @@
{
"commands": [
{
"command": "solid.box",
"params": {
"length": 100,
"width": 60,
"height": 30,
"body_name": "Slab"
}
},
{
"command": "sketch.create",
"params": {
"plane": "XY",
"offset": 30,
"name": "Top"
}
},
{
"command": "sketch.rectangle.two_point",
"params": {
"p0": [
20,
1
],
"p1": [
80,
50
]
}
},
{
"command": "sketch.finish",
"params": {}
},
{
"command": "sketch.create",
"params": {
"plane": "XY",
"offset": 10,
"name": "Bottom"
}
},
{
"command": "sketch.rectangle.two_point",
"params": {
"p0": [
30,
11
],
"p1": [
70,
40
]
}
},
{
"command": "sketch.finish",
"params": {}
},
{
"command": "solid.loft",
"params": {
"sections": [
{
"sketch": "Top"
},
{
"sketch": "Bottom"
}
],
"operation": "cut"
}
},
{
"command": "solid.fillet",
"params": {
"edges": [
[
50,
1,
30
],
[
80,
27,
30
],
[
50,
50,
30
],
[
20,
27,
30
]
],
"radius": 4
}
}
]
}
@@ -0,0 +1,13 @@
{
"sources": [
"tangency-labs/solidcraft#1080"
],
"what": "a 40 x 30 x 10 block with a 5 x 5 x 3 notch at a bottom corner, its top outline rounded R7: the round uses up the 7 mm wall over the notch",
"source": "analytic",
"method": "block 12000 less the notch 75: 11925. The outline's mitred round takes (1-pi/4) r^2 (140 - 8c), c = r (10-3pi)/(3(4-pi)) (the prisms ending on the 45 deg mitres). R7 reaches z = 3, the notch's top: it uses the 7 mm wall over the notch up and none of it lies in the notch. V = 10584.365507",
"body_count": 1,
"volume_mm3": 10584.365507210565,
"continuity": {
"order": "g1"
}
}
@@ -0,0 +1,55 @@
{
"commands": [
{
"command": "solid.box",
"params": {
"length": 40,
"width": 30,
"height": 10
}
},
{
"command": "solid.box",
"params": {
"length": 6,
"width": 6,
"height": 4,
"corner": [
35,
-1,
-1
],
"operation": "cut"
}
},
{
"command": "solid.fillet",
"params": {
"edges": [
[
20,
0,
10
],
[
40,
15,
10
],
[
20,
30,
10
],
[
0,
15,
10
]
],
"radius": 7,
"tangent_chain": false
}
}
]
}
@@ -0,0 +1,13 @@
{
"sources": [
"tangency-labs/solidcraft#1080"
],
"what": "a 40 x 30 x 10 block with a 5 x 5 x 3 notch at a bottom corner, its top outline rounded R8: the round runs past the 7 mm wall over the notch into the notch and is cut by it",
"source": "analytic",
"method": "block 12000 less the notch 75: 11925. The outline's mitred round takes (1-pi/4) r^2 (140 - 8c), c = r (10-3pi)/(3(4-pi)) (the prisms ending on the 45 deg mitres). R8 reaches z = 2, into the notch [35,40] x [0,5] x [0,3]: at z = 2 + t each round's strip is g = 8 - sqrt(64 - t^2) in from its face, the two strips' union in the notch's 5 x 5 square 2(5g - g^2/2); its part in the notch, Int_0^1 2(5g - g^2/2) dt = 0.208039, is not material and is not taken. V = 10198.718039",
"body_count": 1,
"volume_mm3": 10198.718038815705,
"continuity": {
"order": "g1"
}
}
@@ -0,0 +1,55 @@
{
"commands": [
{
"command": "solid.box",
"params": {
"length": 40,
"width": 30,
"height": 10
}
},
{
"command": "solid.box",
"params": {
"length": 6,
"width": 6,
"height": 4,
"corner": [
35,
-1,
-1
],
"operation": "cut"
}
},
{
"command": "solid.fillet",
"params": {
"edges": [
[
20,
0,
10
],
[
40,
15,
10
],
[
20,
30,
10
],
[
0,
15,
10
]
],
"radius": 8,
"tangent_chain": false
}
}
]
}
@@ -0,0 +1,28 @@
{
"sources": [
"tangency-labs/solidcraft#1080"
],
"what": "the 0.5 mm front rim of a sloped basin's top rounded R0.25: it fits on the rim",
"source": "analytic",
"method": "slab 100 x 60 x 30 less the loft from the rectangle (20, 0.5)-(80, 50) at z = 30 to (30, 20)-(70, 40) at z = 10 (planar walls, a prismatoid: 20/6 (A_top + A_bottom + 4 A_mid)): V0 = 144266.666667. The wall leans (20-0.5) out over 20 down: the faces meet at 134.2748 deg, so the round's contacts lie r cot(t/2) = 0.105412 from the edge, on the top at y = 0.394588 and down the wall, its centre under the top contact at z = 30 - r. At height z the blend runs between the sloped end walls x = 20 + (30-z)/2 and 80 - (30-z)/2 extended, which cut it: its length there is 30 + z, so it takes Int Int (30 + z) dy dz over its section (y, z). Removed 0.084803. V = 144266.581864",
"body_count": 1,
"volume_mm3": 144266.58186392413,
"bbox": {
"min": [
0,
0,
0
],
"max": [
100,
60,
30
]
},
"tolerance": {
"rel": 1e-06
},
"continuity": {
"order": "g1"
}
}
@@ -0,0 +1,90 @@
{
"commands": [
{
"command": "solid.box",
"params": {
"length": 100,
"width": 60,
"height": 30,
"body_name": "Slab"
}
},
{
"command": "sketch.create",
"params": {
"plane": "XY",
"offset": 30,
"name": "Top"
}
},
{
"command": "sketch.rectangle.two_point",
"params": {
"p0": [
20,
0.5
],
"p1": [
80,
50
]
}
},
{
"command": "sketch.finish",
"params": {}
},
{
"command": "sketch.create",
"params": {
"plane": "XY",
"offset": 10,
"name": "Bottom"
}
},
{
"command": "sketch.rectangle.two_point",
"params": {
"p0": [
30,
20
],
"p1": [
70,
40
]
}
},
{
"command": "sketch.finish",
"params": {}
},
{
"command": "solid.loft",
"params": {
"sections": [
{
"sketch": "Top"
},
{
"sketch": "Bottom"
}
],
"operation": "cut"
}
},
{
"command": "solid.fillet",
"params": {
"edges": [
[
50,
0.5,
30
]
],
"radius": 0.25
}
}
]
}
@@ -0,0 +1,24 @@
{
"sources": [
"tangency-labs/solidcraft#1080"
],
"what": "all four of the top rim edges of a sloped basin with a 0.5 mm front rim rounded R4: past the thin rim the rounds run over the slab's front face and are cut from the slab",
"source": "invariants",
"method": "slab 100 x 60 x 30 less the loft from the rectangle (20, 0.5)-(80, 50) at z = 30 to (30, 20)-(70, 40) at z = 10 (planar walls, a prismatoid: 20/6 (A_top + A_bottom + 4 A_mid)): V0 = 144266.666667. the rim's corners are re-entrant (the pocket's corners), where the blends of two sides meet; with sloped walls of different slopes that meeting has no closed form here. Nothing may leave the slab: the box is the slab's, which keeps its outside faces whole.",
"body_count": 1,
"bbox": {
"min": [
0,
0,
0
],
"max": [
100,
60,
30
]
},
"continuity": {
"order": "g1"
}
}
@@ -0,0 +1,105 @@
{
"commands": [
{
"command": "solid.box",
"params": {
"length": 100,
"width": 60,
"height": 30,
"body_name": "Slab"
}
},
{
"command": "sketch.create",
"params": {
"plane": "XY",
"offset": 30,
"name": "Top"
}
},
{
"command": "sketch.rectangle.two_point",
"params": {
"p0": [
20,
0.5
],
"p1": [
80,
50
]
}
},
{
"command": "sketch.finish",
"params": {}
},
{
"command": "sketch.create",
"params": {
"plane": "XY",
"offset": 10,
"name": "Bottom"
}
},
{
"command": "sketch.rectangle.two_point",
"params": {
"p0": [
30,
20
],
"p1": [
70,
40
]
}
},
{
"command": "sketch.finish",
"params": {}
},
{
"command": "solid.loft",
"params": {
"sections": [
{
"sketch": "Top"
},
{
"sketch": "Bottom"
}
],
"operation": "cut"
}
},
{
"command": "solid.fillet",
"params": {
"edges": [
[
50,
0.5,
30
],
[
80,
27,
30
],
[
50,
50,
30
],
[
20,
27,
30
]
],
"radius": 4
}
}
]
}
@@ -0,0 +1,28 @@
{
"sources": [
"tangency-labs/solidcraft#1080"
],
"what": "the 0.5 mm front rim of a sloped basin's top rounded R4: the round runs over the rim's top past the slab's front face (a cliff) and is cut from the slab",
"source": "analytic",
"method": "slab 100 x 60 x 30 less the loft from the rectangle (20, 0.5)-(80, 50) at z = 30 to (30, 20)-(70, 40) at z = 10 (planar walls, a prismatoid: 20/6 (A_top + A_bottom + 4 A_mid)): V0 = 144266.666667. The wall leans (20-0.5) out over 20 down: the faces meet at 134.2748 deg, so the round's contacts lie r cot(t/2) = 1.686591 from the edge, on the top at y = -1.186591 and down the wall, its centre under the top contact at z = 30 - r. The round is built as if the top went on past y = 0 and cut from the slab (a round past a face on its tangent side builds: the owner's ruling of 2026-10-30), so its section counts only at y >= 0. At height z the blend runs between the sloped end walls x = 20 + (30-z)/2 and 80 - (30-z)/2 extended, which cut it: its length there is 30 + z, so it takes Int Int (30 + z) dy dz over its section (y, z). Removed 17.395317. V = 144249.271350",
"body_count": 1,
"volume_mm3": 144249.27134953788,
"bbox": {
"min": [
0,
0,
0
],
"max": [
100,
60,
30
]
},
"tolerance": {
"rel": 1e-06
},
"continuity": {
"order": "g1"
}
}
@@ -0,0 +1,90 @@
{
"commands": [
{
"command": "solid.box",
"params": {
"length": 100,
"width": 60,
"height": 30,
"body_name": "Slab"
}
},
{
"command": "sketch.create",
"params": {
"plane": "XY",
"offset": 30,
"name": "Top"
}
},
{
"command": "sketch.rectangle.two_point",
"params": {
"p0": [
20,
0.5
],
"p1": [
80,
50
]
}
},
{
"command": "sketch.finish",
"params": {}
},
{
"command": "sketch.create",
"params": {
"plane": "XY",
"offset": 10,
"name": "Bottom"
}
},
{
"command": "sketch.rectangle.two_point",
"params": {
"p0": [
30,
20
],
"p1": [
70,
40
]
}
},
{
"command": "sketch.finish",
"params": {}
},
{
"command": "solid.loft",
"params": {
"sections": [
{
"sketch": "Top"
},
{
"sketch": "Bottom"
}
],
"operation": "cut"
}
},
{
"command": "solid.fillet",
"params": {
"edges": [
[
50,
0.5,
30
]
],
"radius": 4
}
}
]
}
@@ -0,0 +1,24 @@
{
"sources": [
"tangency-labs/solidcraft#1080"
],
"what": "all four of the top rim edges of a sloped basin with a 1 mm front rim rounded R0.5",
"source": "invariants",
"method": "slab 100 x 60 x 30 less the loft from the rectangle (20, 1)-(80, 50) at z = 30 to (30, 20)-(70, 40) at z = 10 (planar walls, a prismatoid: 20/6 (A_top + A_bottom + 4 A_mid)): V0 = 144533.333333. the rim's corners are re-entrant (the pocket's corners), where the blends of two sides meet; with sloped walls of different slopes that meeting has no closed form here. Nothing may leave the slab: the box is the slab's, which keeps its outside faces whole.",
"body_count": 1,
"bbox": {
"min": [
0,
0,
0
],
"max": [
100,
60,
30
]
},
"continuity": {
"order": "g1"
}
}
@@ -0,0 +1,105 @@
{
"commands": [
{
"command": "solid.box",
"params": {
"length": 100,
"width": 60,
"height": 30,
"body_name": "Slab"
}
},
{
"command": "sketch.create",
"params": {
"plane": "XY",
"offset": 30,
"name": "Top"
}
},
{
"command": "sketch.rectangle.two_point",
"params": {
"p0": [
20,
1
],
"p1": [
80,
50
]
}
},
{
"command": "sketch.finish",
"params": {}
},
{
"command": "sketch.create",
"params": {
"plane": "XY",
"offset": 10,
"name": "Bottom"
}
},
{
"command": "sketch.rectangle.two_point",
"params": {
"p0": [
30,
20
],
"p1": [
70,
40
]
}
},
{
"command": "sketch.finish",
"params": {}
},
{
"command": "solid.loft",
"params": {
"sections": [
{
"sketch": "Top"
},
{
"sketch": "Bottom"
}
],
"operation": "cut"
}
},
{
"command": "solid.fillet",
"params": {
"edges": [
[
50,
1,
30
],
[
80,
27,
30
],
[
50,
50,
30
],
[
20,
27,
30
]
],
"radius": 0.5
}
}
]
}
@@ -0,0 +1,28 @@
{
"sources": [
"tangency-labs/solidcraft#1080"
],
"what": "the 1 mm front rim of a sloped basin's top rounded R0.5: it fits on the rim",
"source": "analytic",
"method": "slab 100 x 60 x 30 less the loft from the rectangle (20, 1)-(80, 50) at z = 30 to (30, 20)-(70, 40) at z = 10 (planar walls, a prismatoid: 20/6 (A_top + A_bottom + 4 A_mid)): V0 = 144533.333333. The wall leans (20-1) out over 20 down: the faces meet at 133.5312 deg, so the round's contacts lie r cot(t/2) = 0.214656 from the edge, on the top at y = 0.785344 and down the wall, its centre under the top contact at z = 30 - r. At height z the blend runs between the sloped end walls x = 20 + (30-z)/2 and 80 - (30-z)/2 extended, which cut it: its length there is 30 + z, so it takes Int Int (30 + z) dy dz over its section (y, z). Removed 0.356729. V = 144532.976604",
"body_count": 1,
"volume_mm3": 144532.976604295,
"bbox": {
"min": [
0,
0,
0
],
"max": [
100,
60,
30
]
},
"tolerance": {
"rel": 1e-06
},
"continuity": {
"order": "g1"
}
}
@@ -0,0 +1,90 @@
{
"commands": [
{
"command": "solid.box",
"params": {
"length": 100,
"width": 60,
"height": 30,
"body_name": "Slab"
}
},
{
"command": "sketch.create",
"params": {
"plane": "XY",
"offset": 30,
"name": "Top"
}
},
{
"command": "sketch.rectangle.two_point",
"params": {
"p0": [
20,
1
],
"p1": [
80,
50
]
}
},
{
"command": "sketch.finish",
"params": {}
},
{
"command": "sketch.create",
"params": {
"plane": "XY",
"offset": 10,
"name": "Bottom"
}
},
{
"command": "sketch.rectangle.two_point",
"params": {
"p0": [
30,
20
],
"p1": [
70,
40
]
}
},
{
"command": "sketch.finish",
"params": {}
},
{
"command": "solid.loft",
"params": {
"sections": [
{
"sketch": "Top"
},
{
"sketch": "Bottom"
}
],
"operation": "cut"
}
},
{
"command": "solid.fillet",
"params": {
"edges": [
[
50,
1,
30
]
],
"radius": 0.5
}
}
]
}
@@ -0,0 +1,24 @@
{
"sources": [
"tangency-labs/solidcraft#1080"
],
"what": "two of the top rim edges of a sloped basin with a 1 mm front rim rounded R4: past the thin rim the rounds run over the slab's front face and are cut from the slab",
"source": "invariants",
"method": "slab 100 x 60 x 30 less the loft from the rectangle (20, 1)-(80, 50) at z = 30 to (30, 20)-(70, 40) at z = 10 (planar walls, a prismatoid: 20/6 (A_top + A_bottom + 4 A_mid)): V0 = 144533.333333. the rim's corners are re-entrant (the pocket's corners), where the blends of two sides meet; with sloped walls of different slopes that meeting has no closed form here. Nothing may leave the slab: the box is the slab's, which keeps its outside faces whole.",
"body_count": 1,
"bbox": {
"min": [
0,
0,
0
],
"max": [
100,
60,
30
]
},
"continuity": {
"order": "g1"
}
}
@@ -0,0 +1,95 @@
{
"commands": [
{
"command": "solid.box",
"params": {
"length": 100,
"width": 60,
"height": 30,
"body_name": "Slab"
}
},
{
"command": "sketch.create",
"params": {
"plane": "XY",
"offset": 30,
"name": "Top"
}
},
{
"command": "sketch.rectangle.two_point",
"params": {
"p0": [
20,
1
],
"p1": [
80,
50
]
}
},
{
"command": "sketch.finish",
"params": {}
},
{
"command": "sketch.create",
"params": {
"plane": "XY",
"offset": 10,
"name": "Bottom"
}
},
{
"command": "sketch.rectangle.two_point",
"params": {
"p0": [
30,
20
],
"p1": [
70,
40
]
}
},
{
"command": "sketch.finish",
"params": {}
},
{
"command": "solid.loft",
"params": {
"sections": [
{
"sketch": "Top"
},
{
"sketch": "Bottom"
}
],
"operation": "cut"
}
},
{
"command": "solid.fillet",
"params": {
"edges": [
[
50,
1,
30
],
[
80,
27,
30
]
],
"radius": 4
}
}
]
}
@@ -0,0 +1,24 @@
{
"sources": [
"tangency-labs/solidcraft#1080"
],
"what": "all four of the top rim edges of a sloped basin with a 1 mm front rim rounded R4: past the thin rim the rounds run over the slab's front face and are cut from the slab",
"source": "invariants",
"method": "slab 100 x 60 x 30 less the loft from the rectangle (20, 1)-(80, 50) at z = 30 to (30, 20)-(70, 40) at z = 10 (planar walls, a prismatoid: 20/6 (A_top + A_bottom + 4 A_mid)): V0 = 144533.333333. the rim's corners are re-entrant (the pocket's corners), where the blends of two sides meet; with sloped walls of different slopes that meeting has no closed form here. Nothing may leave the slab: the box is the slab's, which keeps its outside faces whole.",
"body_count": 1,
"bbox": {
"min": [
0,
0,
0
],
"max": [
100,
60,
30
]
},
"continuity": {
"order": "g1"
}
}
@@ -0,0 +1,105 @@
{
"commands": [
{
"command": "solid.box",
"params": {
"length": 100,
"width": 60,
"height": 30,
"body_name": "Slab"
}
},
{
"command": "sketch.create",
"params": {
"plane": "XY",
"offset": 30,
"name": "Top"
}
},
{
"command": "sketch.rectangle.two_point",
"params": {
"p0": [
20,
1
],
"p1": [
80,
50
]
}
},
{
"command": "sketch.finish",
"params": {}
},
{
"command": "sketch.create",
"params": {
"plane": "XY",
"offset": 10,
"name": "Bottom"
}
},
{
"command": "sketch.rectangle.two_point",
"params": {
"p0": [
30,
20
],
"p1": [
70,
40
]
}
},
{
"command": "sketch.finish",
"params": {}
},
{
"command": "solid.loft",
"params": {
"sections": [
{
"sketch": "Top"
},
{
"sketch": "Bottom"
}
],
"operation": "cut"
}
},
{
"command": "solid.fillet",
"params": {
"edges": [
[
50,
1,
30
],
[
80,
27,
30
],
[
50,
50,
30
],
[
20,
27,
30
]
],
"radius": 4
}
}
]
}
@@ -0,0 +1,28 @@
{
"sources": [
"tangency-labs/solidcraft#1080"
],
"what": "the 1 mm front rim of a sloped basin's top rounded R4: the round runs over the rim's top past the slab's front face (a cliff) and is cut from the slab",
"source": "analytic",
"method": "slab 100 x 60 x 30 less the loft from the rectangle (20, 1)-(80, 50) at z = 30 to (30, 20)-(70, 40) at z = 10 (planar walls, a prismatoid: 20/6 (A_top + A_bottom + 4 A_mid)): V0 = 144533.333333. The wall leans (20-1) out over 20 down: the faces meet at 133.5312 deg, so the round's contacts lie r cot(t/2) = 1.717246 from the edge, on the top at y = -0.717246 and down the wall, its centre under the top contact at z = 30 - r. The round is built as if the top went on past y = 0 and cut from the slab (a round past a face on its tangent side builds: the owner's ruling of 2026-10-30), so its section counts only at y >= 0. At height z the blend runs between the sloped end walls x = 20 + (30-z)/2 and 80 - (30-z)/2 extended, which cut it: its length there is 30 + z, so it takes Int Int (30 + z) dy dz over its section (y, z). Removed 21.818658. V = 144511.514676",
"body_count": 1,
"volume_mm3": 144511.5146755704,
"bbox": {
"min": [
0,
0,
0
],
"max": [
100,
60,
30
]
},
"tolerance": {
"rel": 1e-06
},
"continuity": {
"order": "g1"
}
}
@@ -0,0 +1,90 @@
{
"commands": [
{
"command": "solid.box",
"params": {
"length": 100,
"width": 60,
"height": 30,
"body_name": "Slab"
}
},
{
"command": "sketch.create",
"params": {
"plane": "XY",
"offset": 30,
"name": "Top"
}
},
{
"command": "sketch.rectangle.two_point",
"params": {
"p0": [
20,
1
],
"p1": [
80,
50
]
}
},
{
"command": "sketch.finish",
"params": {}
},
{
"command": "sketch.create",
"params": {
"plane": "XY",
"offset": 10,
"name": "Bottom"
}
},
{
"command": "sketch.rectangle.two_point",
"params": {
"p0": [
30,
20
],
"p1": [
70,
40
]
}
},
{
"command": "sketch.finish",
"params": {}
},
{
"command": "solid.loft",
"params": {
"sections": [
{
"sketch": "Top"
},
{
"sketch": "Bottom"
}
],
"operation": "cut"
}
},
{
"command": "solid.fillet",
"params": {
"edges": [
[
50,
1,
30
]
],
"radius": 4
}
}
]
}
@@ -0,0 +1,11 @@
{
"sources": [
"tangency-labs/solidcraft#1113",
"tangency-labs/solidcraft#851"
],
"what": "the top edge of #851's concave R21 wall chamfered 10, the wall's full height: refused as too large",
"source": "analytic",
"method": "a chamfer as tall as the wall would leave the wall a face of no area (its two boundary arcs on one line): refused as too large (#1113), naming the largest distance that fits",
"outcome": "refused",
"refusal": "the largest distance that fits is"
}
@@ -0,0 +1,79 @@
{
"commands": [
{
"command": "solid.box",
"params": {
"length": 41.166666666666664,
"width": 21,
"height": 10,
"corner": [
0,
-21,
0
],
"body_name": "Plate"
}
},
{
"command": "solid.box",
"params": {
"length": 21,
"width": 21,
"height": 10,
"corner": [
41.166666666666664,
-21,
0
],
"body_name": "Corner"
}
},
{
"command": "solid.cylinder",
"params": {
"radius": 21,
"height": 10,
"base": [
62.166666666666664,
-21,
0
],
"body_name": "Round"
}
},
{
"command": "solid.combine",
"params": {
"target": "Corner",
"tools": [
"Round"
],
"operation": "cut"
}
},
{
"command": "solid.combine",
"params": {
"target": "Plate",
"tools": [
"Corner"
],
"operation": "join"
}
},
{
"command": "solid.chamfer",
"params": {
"edges": [
[
47.31742426174917,
-6.150757595082503,
10
]
],
"distance": 10,
"tangent_chain": false
}
}
]
}
@@ -0,0 +1,14 @@
{
"sources": [
"tangency-labs/solidcraft#1668",
"tangency-labs/solidcraft#1080"
],
"what": "R7 rounds of the outer top edge and the inside edge of a 2 mm wall in one fillet: the inside round holds the material the outer one runs over, so the wall stays closed",
"source": "analytic",
"method": "as 1668-fillet-both-sides-of-thin-wall at R7: the inside (concave) round adds (1-pi/4) 49 along 100 about (23, 33); the outer one's part over the hollow lies at least 9.7 from (23, 33), inside the added material, so it takes its whole section (1-pi/4) 49 along 104. V = 39552 - (1-pi/4) 49 x 4 = 39509.938040",
"body_count": 1,
"volume_mm3": 39509.9380400259,
"continuity": {
"order": "g1"
}
}
@@ -0,0 +1,52 @@
{
"commands": [
{
"command": "solid.box",
"params": {
"length": 100,
"width": 60,
"height": 40,
"corner": [
-50,
-30,
0
],
"body_name": "Case"
}
},
{
"command": "solid.shell",
"params": {
"body": "Case",
"faces": [
[
0,
0,
0
]
],
"thickness": 2,
"direction": "outside"
}
},
{
"command": "solid.fillet",
"params": {
"edges": [
[
0,
32,
42
],
[
0,
30,
40
]
],
"radius": 7,
"body": "Case"
}
}
]
}
@@ -0,0 +1,14 @@
{
"sources": [
"tangency-labs/solidcraft#1668",
"tangency-labs/solidcraft#1080"
],
"what": "an R7 round of the outer top edge of a 2 mm wall alone: past the sharp inside corner it is cut from the wall as if the hollow were not there, opening a slit along the hollow",
"source": "analytic",
"method": "box 100x60x40 shelled outward 2 mm open at the bottom: 104x64x42 less 100x60x40 = 39552. The round's circle about (y, z) = (25, 35), r 7, takes (1-pi/4) 49 along the edge's 104, less its part over the hollow (y < 30, z < 40), the square [25,30]x[35,40] outside the circle: Int_sqrt24^5 (5 - sqrt(49-u^2)) du = 5(5-sqrt24) - (F(5) - F(sqrt24)), F(t) = (t sqrt(49-t^2) + 49 asin(t/7))/2, = 0.005068, along the hollow's 100 (the end walls x = +-50..52 are solid). V = 38458.895826",
"body_count": 1,
"volume_mm3": 38458.89582646349,
"continuity": {
"order": "g1"
}
}
@@ -0,0 +1,47 @@
{
"commands": [
{
"command": "solid.box",
"params": {
"length": 100,
"width": 60,
"height": 40,
"corner": [
-50,
-30,
0
],
"body_name": "Case"
}
},
{
"command": "solid.shell",
"params": {
"body": "Case",
"faces": [
[
0,
0,
0
]
],
"thickness": 2,
"direction": "outside"
}
},
{
"command": "solid.fillet",
"params": {
"edges": [
[
0,
32,
42
]
],
"radius": 7,
"body": "Case"
}
}
]
}
@@ -0,0 +1,14 @@
{
"sources": [
"tangency-labs/solidcraft#190",
"tangency-labs/solidcraft#318"
],
"what": "an R2.5 round of the top rim of a disc R13 x 2: the round runs past the bottom of its 2 mm wall (a cliff) and is built as if the wall went on, cut by the bottom face",
"source": "analytic",
"method": "the round's circle in (rho, z): centre (10.5, -0.5), radius 2.5 (tangent to the top z = 2 and the wall rho = 13). Above z = 0 the disc keeps rho <= 10.5 + sqrt(6.25 - (z+0.5)^2); with z + 0.5 = 2.5 sin t (t from asin(0.2) to pi/2) the part taken is pi Int (169 - rho^2) dz = pi Int (169 - (10.5 + 2.5 cos t)^2) 2.5 cos t dt = 104.166078. V = pi 338 - that. The bottom face is left a disc of radius 10.5 + sqrt(6) = 12.949: the wall is used up.",
"body_count": 1,
"volume_mm3": 957.6922389452784,
"continuity": {
"order": "g1"
}
}
@@ -0,0 +1,24 @@
{
"commands": [
{
"command": "solid.cylinder",
"params": {
"radius": 13,
"height": 2
}
},
{
"command": "solid.fillet",
"params": {
"edges": [
[
13,
0,
2
]
],
"radius": 2.5
}
}
]
}
@@ -0,0 +1,11 @@
{
"sources": [
"tangency-labs/solidcraft#2852",
"tangency-labs/solidcraft#1080"
],
"what": "a 3 mm U shell (60 x 20 x 50) whose inside top edges are rounded R15: its outside edges rounded R30 would cross into the hollow and cut the top plate off the walls, so it is refused, naming the largest radius that fits",
"source": "analytic",
"method": "both rounds' centres lie on the corner's bisector x + z = 50: the outside one's at (R, 50 - R), the inside one's at (18, 32), r 15. Along the bisector from the corner (0, 50) the outside arc's middle lies at R (sqrt2 - 1), the inside arc's at 18 sqrt2 - 15: they meet at R = (18 sqrt2 - 15)/(sqrt2 - 1) = 25.2426. Past that the round crosses the wall along the whole 20 mm and would part the top from the walls (the owner's ruling of 2026-10-30: refused as too large, naming the largest that fits, 25.24).",
"outcome": "refused",
"refusal": "the largest radius that fits is 25.2"
}
@@ -0,0 +1,62 @@
{
"commands": [
{
"command": "solid.box",
"params": {
"length": 60,
"width": 20,
"height": 50
}
},
{
"command": "solid.box",
"params": {
"length": 54,
"width": 22,
"height": 48,
"corner": [
3,
-1,
-1
],
"operation": "cut"
}
},
{
"command": "solid.fillet",
"params": {
"edges": [
[
3,
10,
47
],
[
57,
10,
47
]
],
"radius": 15
}
},
{
"command": "solid.fillet",
"params": {
"edges": [
[
0,
10,
50
],
[
60,
10,
50
]
],
"radius": 30
}
}
]
}
@@ -0,0 +1,10 @@
{
"sources": [
"tangency-labs/solidcraft#2893"
],
"what": "the top rim of a cylinder r10 x 20 chamfered 2 across the top at 90.573 deg from it: refused",
"source": "analytic",
"method": "at more than 90 deg from the top the chamfer runs out through the wall instead of down it: no chamfer of the rim between the top and the wall has those sizes, so the right answer is a refusal saying why",
"outcome": "refused",
"refusal": "angle"
}
@@ -0,0 +1,25 @@
{
"commands": [
{
"command": "solid.cylinder",
"params": {
"radius": 10,
"height": 20
}
},
{
"command": "solid.chamfer",
"params": {
"edges": [
[
10,
0,
20
]
],
"distance": 2,
"angle": "90.573 deg"
}
}
]
}
@@ -0,0 +1,10 @@
{
"sources": [
"tangency-labs/solidcraft#2893"
],
"what": "the top rim of a cylinder r10 x 20 chamfered 10 across the top and 3 down the wall: refused",
"source": "analytic",
"method": "10 across the top reaches the axis: the cone would end in a point: no chamfer of the rim between the top and the wall has those sizes, so the right answer is a refusal saying why",
"outcome": "refused",
"refusal": "larger than"
}
@@ -0,0 +1,25 @@
{
"commands": [
{
"command": "solid.cylinder",
"params": {
"radius": 10,
"height": 20
}
},
{
"command": "solid.chamfer",
"params": {
"edges": [
[
10,
0,
20
]
],
"distance": 10,
"distance2": 3
}
}
]
}
@@ -0,0 +1,11 @@
{
"sources": [
"tangency-labs/solidcraft#2893"
],
"what": "a cylinder r5 tilted 26.6 deg from Z cut flat at z = 10, its elliptical rim chamfered 1 and 2: built, or refused as not supported, never a wrong solid",
"source": "invariants",
"method": "the axis (1, 0, 2)/sqrt5 through (0, 0, -10) meets z = 10 at (10, 0, 10); the rim is the ellipse there with semi-axes 5 (along y) and 5 sqrt5/2 (along x); (10, 5, 10) is on it. An unequal chamfer of an ellipse has no closed-form volume: one closed valid solid, or a refusal that names the rim as not supported yet (never an SMLib status).",
"outcome": "solid_or_refused",
"refusal": "not supported yet",
"body_count": 1
}
@@ -0,0 +1,49 @@
{
"commands": [
{
"command": "solid.cylinder",
"params": {
"radius": 5,
"height": 40,
"base": [
0,
0,
-10
],
"axis": [
1,
0,
2
]
}
},
{
"command": "solid.box",
"params": {
"length": 100,
"width": 100,
"height": 40,
"corner": [
-50,
-50,
10
],
"operation": "cut"
}
},
{
"command": "solid.chamfer",
"params": {
"edges": [
[
10,
5,
10
]
],
"distance": 1,
"distance2": 2
}
}
]
}
@@ -0,0 +1,10 @@
{
"sources": [
"tangency-labs/solidcraft#2893"
],
"what": "the top rim of a cylinder r10 x 20 chamfered 2 across the top and 25 down a 20 mm wall: refused",
"source": "analytic",
"method": "25 down the 20 mm wall runs past the bottom face: no chamfer of the rim between the top and the wall has those sizes, so the right answer is a refusal saying why",
"outcome": "refused",
"refusal": "larger than"
}
@@ -0,0 +1,25 @@
{
"commands": [
{
"command": "solid.cylinder",
"params": {
"radius": 10,
"height": 20
}
},
{
"command": "solid.chamfer",
"params": {
"edges": [
[
10,
0,
20
]
],
"distance": 2,
"distance2": 25
}
}
]
}
@@ -0,0 +1,10 @@
{
"sources": [
"tangency-labs/solidcraft#2893"
],
"what": "the top rim of a cylinder r10 x 20 chamfered 12 across the top and 3 down the wall: refused",
"source": "analytic",
"method": "12 across a top of radius 10 runs past the axis: no chamfer of the rim between the top and the wall has those sizes, so the right answer is a refusal saying why",
"outcome": "refused",
"refusal": "larger than"
}
@@ -0,0 +1,25 @@
{
"commands": [
{
"command": "solid.cylinder",
"params": {
"radius": 10,
"height": 20
}
},
{
"command": "solid.chamfer",
"params": {
"edges": [
[
10,
0,
20
]
],
"distance": 12,
"distance2": 3
}
}
]
}
@@ -0,0 +1,14 @@
{
"sources": [
"tangency-labs/solidcraft#318",
"tangency-labs/solidcraft#190"
],
"what": "a 40 x 30 x 5 plate's whole top outline rounded R5, as tall as its walls: each round uses its wall up, the four mitred at the corners",
"source": "analytic",
"method": "each round removes the spandrel (1-pi/4) r^2 = 5.365046; at a convex corner the two prisms end on the 45 deg mitre, so each is as long as its edge less twice its centroid's distance from the faces, c = r (10-3pi)/(3(4-pi)) = 1.116840: removed = (1-pi/4) 25 (140 - 8c). V = 6000 - removed.",
"body_count": 1,
"volume_mm3": 5296.828741826954,
"continuity": {
"order": "g1"
}
}
@@ -0,0 +1,41 @@
{
"commands": [
{
"command": "solid.box",
"params": {
"length": 40,
"width": 30,
"height": 5
}
},
{
"command": "solid.fillet",
"params": {
"edges": [
[
20,
0,
5
],
[
40,
15,
5
],
[
20,
30,
5
],
[
0,
15,
5
]
],
"radius": 5,
"tangent_chain": false
}
}
]
}
@@ -0,0 +1,13 @@
{
"sources": [
"tangency-labs/solidcraft#477"
],
"what": "the three edges at a 20 mm cube's corner rounded R20 with fit reduce: reduced to the largest that fits, just under 20",
"source": "analytic",
"method": "at radius r the three rounds run (1-pi/4) r^2 along 20 - r past the corner cube [0,r]^3, which loses r^3 less its ball's octant: removed = 3 (1-pi/4) r^2 (20-r) + r^3 (1-pi/6). The search stops within 0.01 of 20; at r = 19.99, V = 4191.931514, and the volume changes 0.3 mm^3 per 0.001 mm of radius there, so the case's tolerance (4.2 mm^3) holds r within 0.013 of it.",
"body_count": 1,
"volume_mm3": 4191.9315140872695,
"continuity": {
"order": "g1"
}
}
@@ -0,0 +1,36 @@
{
"commands": [
{
"command": "solid.box",
"params": {
"length": 20,
"width": 20,
"height": 20
}
},
{
"command": "solid.fillet",
"params": {
"edges": [
[
10,
0,
0
],
[
0,
10,
0
],
[
0,
0,
10
]
],
"radius": 20,
"fit": "reduce"
}
}
]
}
@@ -0,0 +1,10 @@
{
"sources": [
"tangency-labs/solidcraft#477"
],
"what": "the three edges at a 20 mm cube's corner rounded R20, as wide as their faces: refused as too large, naming the largest radius that fits",
"source": "analytic",
"method": "at r = 20 each round uses both its faces up and the corner's ball would be the cube's far corner: no edge is left to end the rounds on. Refused as too large, so a fit can reduce it.",
"outcome": "refused",
"refusal": "the largest radius that fits is"
}
@@ -0,0 +1,35 @@
{
"commands": [
{
"command": "solid.box",
"params": {
"length": 20,
"width": 20,
"height": 20
}
},
{
"command": "solid.fillet",
"params": {
"edges": [
[
10,
0,
0
],
[
0,
10,
0
],
[
0,
0,
10
]
],
"radius": 20
}
}
]
}
@@ -0,0 +1,21 @@
{
"sources": [
"tangency-labs/solidcraft#5835"
],
"what": "all four of the top rim edges of a sloped basin whose walls slope unequally, its front rim 1 mm wide, chamfered 0.5: the chamfers meet at the rim's corners",
"source": "invariants",
"method": "slab 100 x 60 x 30 less the loft from the rectangle (20, 1)-(80, 50) at z = 30 to (30, 20)-(70, 40) at z = 10 (planar walls, a prismatoid: 20/6 (A_top + A_bottom + 4 A_mid)): V0 = 144533.333333. the rim's corners are re-entrant (the pocket's corners), where the blends of two sides meet; with sloped walls of different slopes that meeting has no closed form here. Nothing may leave the slab: the box is the slab's, which keeps its outside faces whole.",
"body_count": 1,
"bbox": {
"min": [
0,
0,
0
],
"max": [
100,
60,
30
]
}
}
@@ -0,0 +1,105 @@
{
"commands": [
{
"command": "solid.box",
"params": {
"length": 100,
"width": 60,
"height": 30,
"body_name": "Slab"
}
},
{
"command": "sketch.create",
"params": {
"plane": "XY",
"offset": 30,
"name": "Top"
}
},
{
"command": "sketch.rectangle.two_point",
"params": {
"p0": [
20,
1
],
"p1": [
80,
50
]
}
},
{
"command": "sketch.finish",
"params": {}
},
{
"command": "sketch.create",
"params": {
"plane": "XY",
"offset": 10,
"name": "Bottom"
}
},
{
"command": "sketch.rectangle.two_point",
"params": {
"p0": [
30,
20
],
"p1": [
70,
40
]
}
},
{
"command": "sketch.finish",
"params": {}
},
{
"command": "solid.loft",
"params": {
"sections": [
{
"sketch": "Top"
},
{
"sketch": "Bottom"
}
],
"operation": "cut"
}
},
{
"command": "solid.chamfer",
"params": {
"edges": [
[
50,
1,
30
],
[
80,
27,
30
],
[
50,
50,
30
],
[
20,
27,
30
]
],
"distance": 0.5
}
}
]
}
@@ -0,0 +1,10 @@
{
"sources": [
"tangency-labs/solidcraft#5835"
],
"what": "the front and right top rim edges of a sloped basin with a 1 mm front rim chamfered 2: the front chamfer's leg runs off the rim, so it is refused, naming the largest distance that fits",
"source": "analytic",
"method": "slab 100 x 60 x 30 less the loft from the rectangle (20, 1)-(80, 50) at z = 30 to (30, 20)-(70, 40) at z = 10 (planar walls, a prismatoid: 20/6 (A_top + A_bottom + 4 A_mid)): V0 = 144533.333333. The front chamfer's leg on the 1 mm rim would reach y = -1, over the slab's front face: refused (the owner's ruling of 2026-10-30).",
"outcome": "refused",
"refusal": "the largest distance that fits is"
}
@@ -0,0 +1,95 @@
{
"commands": [
{
"command": "solid.box",
"params": {
"length": 100,
"width": 60,
"height": 30,
"body_name": "Slab"
}
},
{
"command": "sketch.create",
"params": {
"plane": "XY",
"offset": 30,
"name": "Top"
}
},
{
"command": "sketch.rectangle.two_point",
"params": {
"p0": [
20,
1
],
"p1": [
80,
50
]
}
},
{
"command": "sketch.finish",
"params": {}
},
{
"command": "sketch.create",
"params": {
"plane": "XY",
"offset": 10,
"name": "Bottom"
}
},
{
"command": "sketch.rectangle.two_point",
"params": {
"p0": [
30,
20
],
"p1": [
70,
40
]
}
},
{
"command": "sketch.finish",
"params": {}
},
{
"command": "solid.loft",
"params": {
"sections": [
{
"sketch": "Top"
},
{
"sketch": "Bottom"
}
],
"operation": "cut"
}
},
{
"command": "solid.chamfer",
"params": {
"edges": [
[
50,
1,
30
],
[
80,
27,
30
]
],
"distance": 2
}
}
]
}
@@ -0,0 +1,21 @@
{
"sources": [
"tangency-labs/solidcraft#5835"
],
"what": "two of the top rim edges of a sloped basin whose walls slope unequally, its front rim 4 mm wide, chamfered 2: the chamfers meet at the rim's corners",
"source": "invariants",
"method": "slab 100 x 60 x 30 less the loft from the rectangle (20, 4)-(80, 50) at z = 30 to (30, 20)-(70, 40) at z = 10 (planar walls, a prismatoid: 20/6 (A_top + A_bottom + 4 A_mid)): V0 = 146133.333333. the rim's corners are re-entrant (the pocket's corners), where the blends of two sides meet; with sloped walls of different slopes that meeting has no closed form here. Nothing may leave the slab: the box is the slab's, which keeps its outside faces whole.",
"body_count": 1,
"bbox": {
"min": [
0,
0,
0
],
"max": [
100,
60,
30
]
}
}
@@ -0,0 +1,95 @@
{
"commands": [
{
"command": "solid.box",
"params": {
"length": 100,
"width": 60,
"height": 30,
"body_name": "Slab"
}
},
{
"command": "sketch.create",
"params": {
"plane": "XY",
"offset": 30,
"name": "Top"
}
},
{
"command": "sketch.rectangle.two_point",
"params": {
"p0": [
20,
4
],
"p1": [
80,
50
]
}
},
{
"command": "sketch.finish",
"params": {}
},
{
"command": "sketch.create",
"params": {
"plane": "XY",
"offset": 10,
"name": "Bottom"
}
},
{
"command": "sketch.rectangle.two_point",
"params": {
"p0": [
30,
20
],
"p1": [
70,
40
]
}
},
{
"command": "sketch.finish",
"params": {}
},
{
"command": "solid.loft",
"params": {
"sections": [
{
"sketch": "Top"
},
{
"sketch": "Bottom"
}
],
"operation": "cut"
}
},
{
"command": "solid.chamfer",
"params": {
"edges": [
[
50,
4,
30
],
[
80,
27,
30
]
],
"distance": 2
}
}
]
}
@@ -0,0 +1,21 @@
{
"sources": [
"tangency-labs/solidcraft#5835"
],
"what": "all four of the top rim edges of a sloped basin whose walls slope unequally, its front rim 4 mm wide, chamfered 2: the chamfers meet at the rim's corners",
"source": "invariants",
"method": "slab 100 x 60 x 30 less the loft from the rectangle (20, 4)-(80, 50) at z = 30 to (30, 20)-(70, 40) at z = 10 (planar walls, a prismatoid: 20/6 (A_top + A_bottom + 4 A_mid)): V0 = 146133.333333. the rim's corners are re-entrant (the pocket's corners), where the blends of two sides meet; with sloped walls of different slopes that meeting has no closed form here. Nothing may leave the slab: the box is the slab's, which keeps its outside faces whole.",
"body_count": 1,
"bbox": {
"min": [
0,
0,
0
],
"max": [
100,
60,
30
]
}
}
@@ -0,0 +1,105 @@
{
"commands": [
{
"command": "solid.box",
"params": {
"length": 100,
"width": 60,
"height": 30,
"body_name": "Slab"
}
},
{
"command": "sketch.create",
"params": {
"plane": "XY",
"offset": 30,
"name": "Top"
}
},
{
"command": "sketch.rectangle.two_point",
"params": {
"p0": [
20,
4
],
"p1": [
80,
50
]
}
},
{
"command": "sketch.finish",
"params": {}
},
{
"command": "sketch.create",
"params": {
"plane": "XY",
"offset": 10,
"name": "Bottom"
}
},
{
"command": "sketch.rectangle.two_point",
"params": {
"p0": [
30,
20
],
"p1": [
70,
40
]
}
},
{
"command": "sketch.finish",
"params": {}
},
{
"command": "solid.loft",
"params": {
"sections": [
{
"sketch": "Top"
},
{
"sketch": "Bottom"
}
],
"operation": "cut"
}
},
{
"command": "solid.chamfer",
"params": {
"edges": [
[
50,
4,
30
],
[
80,
27,
30
],
[
50,
50,
30
],
[
20,
27,
30
]
],
"distance": 2
}
}
]
}
@@ -0,0 +1,11 @@
{
"sources": [
"tangency-labs/solidcraft#851",
"tangency-labs/solidcraft#854"
],
"what": "on #851's knife-edge part (tessellation/1263): the arc's top edge chamfered 2",
"source": "invariants",
"method": "a 2 mm chamfer fits on these edges (the arc's chamfer is a cone cut by the back face where the arc runs into it); one closed valid solid whose display mesh closes is the right answer",
"body_count": 1,
"watertight": true
}
@@ -0,0 +1,79 @@
{
"commands": [
{
"command": "solid.box",
"params": {
"length": 41.166666666666664,
"width": 21,
"height": 10,
"corner": [
0,
-21,
0
],
"body_name": "Plate"
}
},
{
"command": "solid.box",
"params": {
"length": 21,
"width": 21,
"height": 10,
"corner": [
41.166666666666664,
-21,
0
],
"body_name": "Corner"
}
},
{
"command": "solid.cylinder",
"params": {
"radius": 21,
"height": 10,
"base": [
62.166666666666664,
-21,
0
],
"body_name": "Round"
}
},
{
"command": "solid.combine",
"params": {
"target": "Corner",
"tools": [
"Round"
],
"operation": "cut"
}
},
{
"command": "solid.combine",
"params": {
"target": "Plate",
"tools": [
"Corner"
],
"operation": "join"
}
},
{
"command": "solid.chamfer",
"params": {
"edges": [
[
47.31742426174917,
-6.150757595082503,
10
]
],
"distance": 2,
"tangent_chain": false
}
}
]
}
@@ -0,0 +1,11 @@
{
"sources": [
"tangency-labs/solidcraft#851",
"tangency-labs/solidcraft#854"
],
"what": "on #851's knife-edge part (tessellation/1263): the arc's top edge and the top front edge together chamfered 2",
"source": "invariants",
"method": "a 2 mm chamfer fits on these edges (the arc's chamfer is a cone cut by the back face where the arc runs into it); one closed valid solid whose display mesh closes is the right answer",
"body_count": 1,
"watertight": true
}
@@ -0,0 +1,84 @@
{
"commands": [
{
"command": "solid.box",
"params": {
"length": 41.166666666666664,
"width": 21,
"height": 10,
"corner": [
0,
-21,
0
],
"body_name": "Plate"
}
},
{
"command": "solid.box",
"params": {
"length": 21,
"width": 21,
"height": 10,
"corner": [
41.166666666666664,
-21,
0
],
"body_name": "Corner"
}
},
{
"command": "solid.cylinder",
"params": {
"radius": 21,
"height": 10,
"base": [
62.166666666666664,
-21,
0
],
"body_name": "Round"
}
},
{
"command": "solid.combine",
"params": {
"target": "Corner",
"tools": [
"Round"
],
"operation": "cut"
}
},
{
"command": "solid.combine",
"params": {
"target": "Plate",
"tools": [
"Corner"
],
"operation": "join"
}
},
{
"command": "solid.chamfer",
"params": {
"edges": [
[
47.31742426174917,
-6.150757595082503,
10
],
[
20,
-21,
10
]
],
"distance": 2,
"tangent_chain": false
}
}
]
}
@@ -0,0 +1,14 @@
{
"sources": [
"tangency-labs/solidcraft#851",
"tangency-labs/solidcraft#1113"
],
"what": "the top edge of #851's concave R21 wall chamfered 9.5, just under its height",
"source": "analytic",
"method": "plate x 0..41.1667, y -21..0 and the corner x 41.1667..62.1667 less the cylinder r 21 about (62.1667, -21), 10 high (tessellation/1263): V0 = 10 (62.1667 x 21 - pi 21^2/4) = 9591.394099. The blend's section in (rho, z) about the wall's axis, the triangle (rho - 21) + (10 - z) <= 9.5, is swept round it from the front face (square to the arc) to the back face y = 0, which the arc runs into tangent at the tip: at radius rho the part spans the angle asin(21/rho), so the blend takes Int_21^30.5 rho asin(21/rho) h(rho) drho with h(rho) = s - (rho - 21): 1180.944160. V = 8410.449939",
"body_count": 1,
"volume_mm3": 8410.449939154401,
"continuity": {
"order": "g0"
}
}
@@ -0,0 +1,79 @@
{
"commands": [
{
"command": "solid.box",
"params": {
"length": 41.166666666666664,
"width": 21,
"height": 10,
"corner": [
0,
-21,
0
],
"body_name": "Plate"
}
},
{
"command": "solid.box",
"params": {
"length": 21,
"width": 21,
"height": 10,
"corner": [
41.166666666666664,
-21,
0
],
"body_name": "Corner"
}
},
{
"command": "solid.cylinder",
"params": {
"radius": 21,
"height": 10,
"base": [
62.166666666666664,
-21,
0
],
"body_name": "Round"
}
},
{
"command": "solid.combine",
"params": {
"target": "Corner",
"tools": [
"Round"
],
"operation": "cut"
}
},
{
"command": "solid.combine",
"params": {
"target": "Plate",
"tools": [
"Corner"
],
"operation": "join"
}
},
{
"command": "solid.chamfer",
"params": {
"edges": [
[
47.31742426174917,
-6.150757595082503,
10
]
],
"distance": 9.5,
"tangent_chain": false
}
}
]
}
@@ -0,0 +1,13 @@
{
"sources": [
"tangency-labs/solidcraft#851"
],
"what": "the knife edge where #851's concave R21 wall runs out tangent into the back face, chamfered 0.5: the plane through the contacts of the ball of radius 0.5",
"source": "analytic",
"method": "plate x 0..41.1667, y -21..0 and the corner x 41.1667..62.1667 less the cylinder r 21 about (62.1667, -21), 10 high (tessellation/1263): V0 = 10 (62.1667 x 21 - pi 21^2/4) = 9591.394099. The chamfer cuts along the chord between the contacts of the ball of radius d = 0.5 that fits there (as the R0.5 round's): on the back face at x = 62.1667 - sqrt(84 d), on the wall where the line from its axis to the ball's centre meets it. It takes the triangle plane contact, tip, wall contact less the wall's circular segment R^2/2 (b - sin b), b = acos((21-d)/(21+d)): 2.114982 mm^2, times 10. V = 9570.244281",
"body_count": 1,
"volume_mm3": 9570.244281078343,
"continuity": {
"order": "g0"
}
}
@@ -0,0 +1,79 @@
{
"commands": [
{
"command": "solid.box",
"params": {
"length": 41.166666666666664,
"width": 21,
"height": 10,
"corner": [
0,
-21,
0
],
"body_name": "Plate"
}
},
{
"command": "solid.box",
"params": {
"length": 21,
"width": 21,
"height": 10,
"corner": [
41.166666666666664,
-21,
0
],
"body_name": "Corner"
}
},
{
"command": "solid.cylinder",
"params": {
"radius": 21,
"height": 10,
"base": [
62.166666666666664,
-21,
0
],
"body_name": "Round"
}
},
{
"command": "solid.combine",
"params": {
"target": "Corner",
"tools": [
"Round"
],
"operation": "cut"
}
},
{
"command": "solid.combine",
"params": {
"target": "Plate",
"tools": [
"Corner"
],
"operation": "join"
}
},
{
"command": "solid.chamfer",
"params": {
"edges": [
[
62.166666666666664,
0,
5
]
],
"distance": 0.5,
"tangent_chain": false
}
}
]
}
@@ -0,0 +1,13 @@
{
"sources": [
"tangency-labs/solidcraft#851"
],
"what": "the knife edge where #851's concave R21 wall runs out tangent into the back face, chamfered 2, the part made as one box less the wall's cylinder: the plane through the contacts of the ball of radius 2",
"source": "analytic",
"method": "plate x 0..41.1667, y -21..0 and the corner x 41.1667..62.1667 less the cylinder r 21 about (62.1667, -21), 10 high (tessellation/1263): V0 = 10 (62.1667 x 21 - pi 21^2/4) = 9591.394099. The chamfer cuts along the chord between the contacts of the ball of radius d = 2 that fits there (as the R2 round's): on the back face at x = 62.1667 - sqrt(84 d), on the wall where the line from its axis to the ball's centre meets it. It takes the triangle plane contact, tip, wall contact less the wall's circular segment R^2/2 (b - sin b), b = acos((21-d)/(21+d)): 15.923645 mm^2, times 10. V = 9432.157649",
"body_count": 1,
"volume_mm3": 9432.15764867435,
"continuity": {
"order": "g0"
}
}
@@ -0,0 +1,44 @@
{
"commands": [
{
"command": "solid.box",
"params": {
"length": 62.166666666666664,
"width": 21,
"height": 10,
"corner": [
0,
-21,
0
]
}
},
{
"command": "solid.cylinder",
"params": {
"radius": 21,
"height": 10,
"base": [
62.166666666666664,
-21,
0
],
"operation": "cut"
}
},
{
"command": "solid.chamfer",
"params": {
"edges": [
[
62.166666666666664,
0,
5
]
],
"distance": 2,
"tangent_chain": false
}
}
]
}
@@ -0,0 +1,13 @@
{
"sources": [
"tangency-labs/solidcraft#851"
],
"what": "the knife edge where #851's concave R21 wall runs out tangent into the back face, chamfered 2, the part drawn as one sketch and extruded (fillets/851's construction): the plane through the contacts of the ball of radius 2",
"source": "analytic",
"method": "plate x 0..41.1667, y -21..0 and the corner x 41.1667..62.1667 less the cylinder r 21 about (62.1667, -21), 10 high (tessellation/1263): V0 = 10 (62.1667 x 21 - pi 21^2/4) = 9591.394099. The chamfer cuts along the chord between the contacts of the ball of radius d = 2 that fits there (as the R2 round's): on the back face at x = 62.1667 - sqrt(84 d), on the wall where the line from its axis to the ball's centre meets it. It takes the triangle plane contact, tip, wall contact less the wall's circular segment R^2/2 (b - sin b), b = acos((21-d)/(21+d)): 15.923645 mm^2, times 10. V = 9432.157649",
"body_count": 1,
"volume_mm3": 9432.15764867435,
"continuity": {
"order": "g0"
}
}
@@ -0,0 +1,120 @@
{
"commands": [
{
"command": "sketch.create",
"params": {
"plane": "XY"
}
},
{
"command": "sketch.rectangle.two_point",
"params": {
"p0": [
0,
0
],
"p1": [
41.5,
-21
]
}
},
{
"command": "sketch.dimension",
"params": {
"entities": [
"l2"
],
"text_at": [
36.5,
-8.5
],
"value": "21 mm"
}
},
{
"command": "sketch.line",
"params": {
"infer": true,
"points": [
"p2",
[
61.5,
-21
]
]
}
},
{
"command": "sketch.dimension",
"params": {
"entities": [
"l5"
],
"text_at": [
54.5,
-26.5
],
"value": "21"
}
},
{
"command": "sketch.circle.center",
"params": {
"center": "l5.end",
"radius": 21
}
},
{
"command": "sketch.line",
"params": {
"infer": true,
"points": [
"p3",
[
62.166666666666664,
0
]
]
}
},
{
"command": "sketch.constraint.tangent",
"params": {
"a": "c1",
"b": "l6"
}
},
{
"command": "sketch.finish",
"params": {}
},
{
"command": "solid.extrude",
"params": {
"direction": "positive",
"distance": "10 mm",
"operation": "new",
"profiles": [
0,
1
],
"sketch": 1
}
},
{
"command": "solid.chamfer",
"params": {
"edges": [
[
62.166666666666664,
0,
5
]
],
"distance": 2,
"tangent_chain": false
}
}
]
}
@@ -0,0 +1,13 @@
{
"sources": [
"tangency-labs/solidcraft#851"
],
"what": "the knife edge where #851's concave R21 wall runs out tangent into the back face, chamfered 2: the plane through the contacts of the ball of radius 2",
"source": "analytic",
"method": "plate x 0..41.1667, y -21..0 and the corner x 41.1667..62.1667 less the cylinder r 21 about (62.1667, -21), 10 high (tessellation/1263): V0 = 10 (62.1667 x 21 - pi 21^2/4) = 9591.394099. The chamfer cuts along the chord between the contacts of the ball of radius d = 2 that fits there (as the R2 round's): on the back face at x = 62.1667 - sqrt(84 d), on the wall where the line from its axis to the ball's centre meets it. It takes the triangle plane contact, tip, wall contact less the wall's circular segment R^2/2 (b - sin b), b = acos((21-d)/(21+d)): 15.923645 mm^2, times 10. V = 9432.157649",
"body_count": 1,
"volume_mm3": 9432.15764867435,
"continuity": {
"order": "g0"
}
}
@@ -0,0 +1,79 @@
{
"commands": [
{
"command": "solid.box",
"params": {
"length": 41.166666666666664,
"width": 21,
"height": 10,
"corner": [
0,
-21,
0
],
"body_name": "Plate"
}
},
{
"command": "solid.box",
"params": {
"length": 21,
"width": 21,
"height": 10,
"corner": [
41.166666666666664,
-21,
0
],
"body_name": "Corner"
}
},
{
"command": "solid.cylinder",
"params": {
"radius": 21,
"height": 10,
"base": [
62.166666666666664,
-21,
0
],
"body_name": "Round"
}
},
{
"command": "solid.combine",
"params": {
"target": "Corner",
"tools": [
"Round"
],
"operation": "cut"
}
},
{
"command": "solid.combine",
"params": {
"target": "Plate",
"tools": [
"Corner"
],
"operation": "join"
}
},
{
"command": "solid.chamfer",
"params": {
"edges": [
[
62.166666666666664,
0,
5
]
],
"distance": 2,
"tangent_chain": false
}
}
]
}
@@ -0,0 +1,13 @@
{
"sources": [
"tangency-labs/solidcraft#851"
],
"what": "the knife edge where #851's concave R21 wall runs out tangent into the back face, chamfered 5: the plane through the contacts of the ball of radius 5",
"source": "analytic",
"method": "plate x 0..41.1667, y -21..0 and the corner x 41.1667..62.1667 less the cylinder r 21 about (62.1667, -21), 10 high (tessellation/1263): V0 = 10 (62.1667 x 21 - pi 21^2/4) = 9591.394099. The chamfer cuts along the chord between the contacts of the ball of radius d = 5 that fits there (as the R5 round's): on the back face at x = 62.1667 - sqrt(84 d), on the wall where the line from its axis to the ball's centre meets it. It takes the triangle plane contact, tip, wall contact less the wall's circular segment R^2/2 (b - sin b), b = acos((21-d)/(21+d)): 56.370971 mm^2, times 10. V = 9027.684392",
"body_count": 1,
"volume_mm3": 9027.684392451565,
"continuity": {
"order": "g0"
}
}
@@ -0,0 +1,79 @@
{
"commands": [
{
"command": "solid.box",
"params": {
"length": 41.166666666666664,
"width": 21,
"height": 10,
"corner": [
0,
-21,
0
],
"body_name": "Plate"
}
},
{
"command": "solid.box",
"params": {
"length": 21,
"width": 21,
"height": 10,
"corner": [
41.166666666666664,
-21,
0
],
"body_name": "Corner"
}
},
{
"command": "solid.cylinder",
"params": {
"radius": 21,
"height": 10,
"base": [
62.166666666666664,
-21,
0
],
"body_name": "Round"
}
},
{
"command": "solid.combine",
"params": {
"target": "Corner",
"tools": [
"Round"
],
"operation": "cut"
}
},
{
"command": "solid.combine",
"params": {
"target": "Plate",
"tools": [
"Corner"
],
"operation": "join"
}
},
{
"command": "solid.chamfer",
"params": {
"edges": [
[
62.166666666666664,
0,
5
]
],
"distance": 5,
"tangent_chain": false
}
}
]
}

Some files were not shown because too many files have changed in this diff Show More