diff --git a/crates/engine/src/tests.rs b/crates/engine/src/tests.rs index 8d86118c1b..9cb46a158d 100644 --- a/crates/engine/src/tests.rs +++ b/crates/engine/src/tests.rs @@ -427,6 +427,72 @@ fn fillet_the_edges_between_two_overlapping_cylinders() { assert!(rel(v, expect) < 2e-4, "{v} vs {expect}"); } +/// A bar 40 long, 16 wide and 10 tall whose far end is a half disc of radius 8 about (40, 8), +/// with a disc of radius 8 about the same centre sketched on its top (the top's outline +/// projected) and extruded 10 up, joined: the bar's sides run tangent into the cylinder. +/// V0 = 40·16·10 + π·8²·10/2 + π·8²·10. +fn peg(s: &mut Session) -> f64 { + run(s, "sketch.create", json!({"plane": "XY", "name": "Peg"})); + run(s, "sketch.line", json!({"points": [[0, 0], [40, 0]]})); + run(s, "sketch.arc.center_point", json!({"center": [40, 8], "start": [40, 0], "end": [40, 16]})); + run(s, "sketch.line", json!({"points": [[40, 16], [0, 16]]})); + run(s, "sketch.line", json!({"points": [[0, 16], [0, 0]]})); + run(s, "sketch.finish", json!({})); + run(s, "solid.extrude", json!({"sketch": "Peg", "distance": 10, "body_name": "Peg"})); + run(s, "sketch.create", json!({"plane": {"origin": [0, 0, 10], "x_dir": [1, 0, 0], "y_dir": [0, 1, 0]}, "name": "Top"})); + run(s, "sketch.project", json!({"refs": [{"face": [2, 8, 10]}]})); + run(s, "sketch.circle.center", json!({"center": [40, 8], "radius": 8})); + run(s, "sketch.finish", json!({})); + run( + s, + "solid.extrude", + json!({"sketch": "Top", "distance": 10, "operation": "join", "targets": ["Peg"], "profiles": [{"point": [40, 8]}], "exact_regions": true}), + ); + 6400.0 + 960.0 * PI +} + +/// Simpson's rule over [a, b] with `n` (even) intervals. +fn simpson(f: impl Fn(f64) -> f64, a: f64, b: f64, n: usize) -> f64 { + let h = (b - a) / n as f64; + let inner: f64 = (1..n).map(|i| if i % 2 == 1 { 4.0 } else { 2.0 } * f(a + h * i as f64)).sum(); + (f(a) + f(b) + inner) * h / 3.0 +} + +/// The material an r2 round of the peg's front top edge (y = 0, z = 10) takes off: the spandrel +/// (height 2 - sqrt(4 - (2 - y)²) above the round at y) from x = `from` to where the cylinder's +/// wall, x = 40 - sqrt(64 - (8 - y)²), takes over (the round runs into the wall there). +fn peg_front_round(from: f64) -> f64 { + let spandrel = |y: f64| 2.0 - (4.0 - (2.0 - y) * (2.0 - y)).max(0.0).sqrt(); + let wall = |y: f64| 40.0 - (64.0 - (8.0 - y) * (8.0 - y)).max(0.0).sqrt(); + simpson(|y| spandrel(y) * (wall(y) - from), 0.0, 2.0, 20_000) +} + +/// The peg's front top edge rounded r2: SMLib's result holds the cylinder's wall as a rational +/// spline whose parameter range runs more than a turn round. As a cylinder over that range (past +/// 360°) SMLib refused it on the way back (SM_ERR_INVALID_INPUT), so the round seemed to build +/// and the body could not be measured or changed. It stays the spline: the body measures, and a +/// round of the three edges at the bar's other top corner builds on it. +#[test] +fn rounds_on_a_bar_running_tangent_into_a_cylinder() { + let mut s = Session::default(); + let v0 = peg(&mut s); + run(&mut s, "solid.fillet", json!({"edges": [[20, 0, 10]], "radius": 2})); + let (v, expect) = (volume(&mut s), v0 - peg_front_round(0.0)); + assert!(rel(v, expect) < 1e-7, "{v} vs {expect}"); + // The vertical edge, the left top edge and the round's end arc on the left face: each + // spandrel (1 - π/4)·r² along the edge outside the corner cube of side 2, the cube less the + // rolling ball's eighth, 8 - 4π/3. + run(&mut s, "solid.fillet", json!({"edges": [[0, 0, 4], [0, 9, 10], [0, 0.5858, 9.4142]], "radius": 2})); + let strip = (1.0 - PI / 4.0) * 4.0; + let expect = v0 - peg_front_round(2.0) - strip * (8.0 + 14.0) - (8.0 - 4.0 * PI / 3.0); + let v = volume(&mut s); + assert!(rel(v, expect) < 1e-7, "{v} vs {expect}"); + for b in &s.model.state().bodies { + let bad = b.body.validity(); + assert!(bad.is_empty(), "{}: {bad:?}", b.name); + } +} + /// The top outline of two overlapping cylinders whose concave edges were rounded: the walls of /// the rounds meet the cylinders along the rolling-ball contact lines, straight but not lines. #[test] diff --git a/crates/smlib/src/import/analytic.rs b/crates/smlib/src/import/analytic.rs index edf87e2193..f4735e4ef3 100644 --- a/crates/smlib/src/import/analytic.rs +++ b/crates/smlib/src/import/analytic.rs @@ -76,7 +76,7 @@ pub(super) fn analytic(brep: &b::Brep) -> R> { /// A rational spline that is a circular arc swept straight along the arc's axis, as a cylinder /// with the face's range on it: one direction linear (two rows of control points), the second /// row the first moved by one vector at right angles to the circle the first row runs on, the -/// weights alike. `None` where it is not. +/// weights alike. `None` where it is not, or where its range runs more than one turn round. fn extruded_circle(u_knots: &[f64], v_knots: &[f64], net: &[Vec<[f64; 4]>], domain: [[f64; 2]; 2], tol: f64) -> Option<(b::Surface, [[f64; 2]; 2])> { let linear = |k: &[f64]| k.len() == 4 && k[0] == k[1] && k[2] == k[3] && k[1] < k[2]; let (rows, arc_knots, arc_range, line_knots, line_range): ([Vec<[f64; 4]>; 2], &[f64], [f64; 2], &[f64], [f64; 2]) = @@ -117,6 +117,12 @@ fn extruded_circle(u_knots: &[f64], v_knots: &[f64], net: &[Vec<[f64; 4]>], doma prev = a; angle = a; } + // A cylinder's range is at most one turn (SMLib refuses more). A spline whose range runs + // further round (SMLib's own, its parameter range past the face's trims) has no such range: + // it stays the exact spline it is. + if angle.abs() > TAU * (1.0 + 1e-9) { + return None; + } let height = |s: f64| (s - line_knots[1]) / (line_knots[2] - line_knots[1]) * d.len(); let sorted = |a: f64, b: f64| if a <= b { [a, b] } else { [b, a] }; let frame = b::Frame { origin: arr(center), x_axis: arr(x), y_axis: arr(y) }; diff --git a/tests/kernel-cases/fillets/1207-fillet-bar-top-edge-running-tangent-into-cylinder/expected.json b/tests/kernel-cases/fillets/1207-fillet-bar-top-edge-running-tangent-into-cylinder/expected.json new file mode 100644 index 0000000000..c37fb0587c --- /dev/null +++ b/tests/kernel-cases/fillets/1207-fillet-bar-top-edge-running-tangent-into-cylinder/expected.json @@ -0,0 +1,11 @@ +{ + "sources": [ + "tangency-labs/solidcraft#1207" + ], + "what": "an r2 round of a bar's top edge whose side runs tangent into a cylinder: the round seemed to build but its body could not be measured or changed (SMLib refused the cylinder's wall coming back as a cylinder over more than a turn)", + "source": "analytic", + "method": "a bar 40 x 16 x 10 whose far end is a half disc R8 about (40, 8), a disc R8 about the same centre sketched on its top (the top's outline projected) and extruded 10 up, joined: the bar's sides run tangent into the cylinder, V0 = 6400 + 960 pi; the r2 round of the front top edge (y = 0, z = 10) runs into the cylinder's wall: removed = integral over y in [0, 2] of (2 - sqrt(4 - (2 - y)^2)) (40 - sqrt(64 - (8 - y)^2)) dy = 32.3064821881 (Simpson)", + "body_count": 1, + "faces": 9, + "volume_mm3": 9383.622465258068 +} diff --git a/tests/kernel-cases/fillets/1207-fillet-bar-top-edge-running-tangent-into-cylinder/recipe.json b/tests/kernel-cases/fillets/1207-fillet-bar-top-edge-running-tangent-into-cylinder/recipe.json new file mode 100644 index 0000000000..5b1ff79bde --- /dev/null +++ b/tests/kernel-cases/fillets/1207-fillet-bar-top-edge-running-tangent-into-cylinder/recipe.json @@ -0,0 +1,169 @@ +{ + "commands": [ + { + "command": "sketch.create", + "params": { + "plane": "XY", + "name": "Peg" + } + }, + { + "command": "sketch.line", + "params": { + "points": [ + [ + 0, + 0 + ], + [ + 40, + 0 + ] + ] + } + }, + { + "command": "sketch.arc.center_point", + "params": { + "center": [ + 40, + 8 + ], + "start": [ + 40, + 0 + ], + "end": [ + 40, + 16 + ] + } + }, + { + "command": "sketch.line", + "params": { + "points": [ + [ + 40, + 16 + ], + [ + 0, + 16 + ] + ] + } + }, + { + "command": "sketch.line", + "params": { + "points": [ + [ + 0, + 16 + ], + [ + 0, + 0 + ] + ] + } + }, + { + "command": "sketch.finish", + "params": {} + }, + { + "command": "solid.extrude", + "params": { + "sketch": "Peg", + "distance": 10, + "body_name": "Peg" + } + }, + { + "command": "sketch.create", + "params": { + "plane": { + "origin": [ + 0, + 0, + 10 + ], + "x_dir": [ + 1, + 0, + 0 + ], + "y_dir": [ + 0, + 1, + 0 + ] + }, + "name": "Top" + } + }, + { + "command": "sketch.project", + "params": { + "refs": [ + { + "face": [ + 2, + 8, + 10 + ] + } + ] + } + }, + { + "command": "sketch.circle.center", + "params": { + "center": [ + 40, + 8 + ], + "radius": 8 + } + }, + { + "command": "sketch.finish", + "params": {} + }, + { + "command": "solid.extrude", + "params": { + "sketch": "Top", + "distance": 10, + "operation": "join", + "targets": [ + "Peg" + ], + "profiles": [ + { + "point": [ + 40, + 8 + ] + } + ], + "exact_regions": true + } + }, + { + "command": "solid.fillet", + "params": { + "edges": [ + [ + 20, + 0, + 10 + ] + ], + "radius": 2 + } + } + ] +} diff --git a/tests/kernel-cases/fillets/1207-fillet-corner-after-round-running-into-cylinder-solver-residues/expected.json b/tests/kernel-cases/fillets/1207-fillet-corner-after-round-running-into-cylinder-solver-residues/expected.json new file mode 100644 index 0000000000..1ecfd0f084 --- /dev/null +++ b/tests/kernel-cases/fillets/1207-fillet-corner-after-round-running-into-cylinder-solver-residues/expected.json @@ -0,0 +1,11 @@ +{ + "sources": [ + "tangency-labs/solidcraft#1207" + ], + "what": "as 1207-fillet-corner-after-round-running-into-cylinder, with the sketch solver's residues of the reported design", + "source": "analytic", + "method": "the same bar with the sketch solver's residues of the reported design (~1e-10 mm: the front side's ends differ by 3.0e-10 in y, the arc's centre 5.7e-11 off the disc's), length 41.160417754, V0 = 41.160417754 * 16.0000000000762 * 10 + 960 pi; the three r2 rounds at the bar's other top corner (0, 0, 10): the front round's spandrel from x = 2 to the wall (30.5896671706), the vertical edge's and the left top edge's (1 - pi/4) r^2 over 8 and 14, the corner cube of side 2 less the rolling ball's eighth, 8 - 4 pi/3: removed 53.2858385868; the bar being L = 41.160417754 long, the front round runs (L - 40) further: removed + (L - 40)(1 - pi/4) r^2", + "body_count": 1, + "faces": 12, + "volume_mm3": 9547.313838420392 +} diff --git a/tests/kernel-cases/fillets/1207-fillet-corner-after-round-running-into-cylinder-solver-residues/recipe.json b/tests/kernel-cases/fillets/1207-fillet-corner-after-round-running-into-cylinder-solver-residues/recipe.json new file mode 100644 index 0000000000..fd1dbbc715 --- /dev/null +++ b/tests/kernel-cases/fillets/1207-fillet-corner-after-round-running-into-cylinder-solver-residues/recipe.json @@ -0,0 +1,192 @@ +{ + "commands": [ + { + "command": "sketch.create", + "params": { + "plane": "XY", + "name": "Peg" + } + }, + { + "command": "sketch.line", + "params": { + "points": [ + [ + 0.4892940775280783, + 0.05792545052986289 + ], + [ + 41.64971183161969, + 0.05792545083296555 + ] + ] + } + }, + { + "command": "sketch.arc.center_point", + "params": { + "center": [ + 41.64971183108453, + 8.057925450890195 + ], + "start": [ + 41.64971183161969, + 0.05792545083296555 + ], + "end": [ + 41.64971183161969, + 16.05792545083297 + ] + } + }, + { + "command": "sketch.line", + "params": { + "points": [ + [ + 41.64971183161969, + 16.05792545083297 + ], + [ + 0.4892940775280783, + 16.057925450606035 + ] + ] + } + }, + { + "command": "sketch.line", + "params": { + "points": [ + [ + 0.4892940775280783, + 16.057925450606035 + ], + [ + 0.4892940775280783, + 0.05792545052986289 + ] + ] + } + }, + { + "command": "sketch.finish", + "params": {} + }, + { + "command": "solid.extrude", + "params": { + "sketch": "Peg", + "distance": 10, + "body_name": "Peg" + } + }, + { + "command": "sketch.create", + "params": { + "plane": { + "origin": [ + 0, + 0, + 10 + ], + "x_dir": [ + 1, + 0, + 0 + ], + "y_dir": [ + 0, + 1, + 0 + ] + }, + "name": "Top" + } + }, + { + "command": "sketch.project", + "params": { + "refs": [ + { + "face": [ + 2.4892940775280783, + 8.057925450890195, + 10 + ] + } + ] + } + }, + { + "command": "sketch.circle.center", + "params": { + "center": [ + 41.64971183108453, + 8.057925450832967 + ], + "radius": 8.000000000006473 + } + }, + { + "command": "sketch.finish", + "params": {} + }, + { + "command": "solid.extrude", + "params": { + "sketch": "Top", + "distance": 10, + "operation": "join", + "targets": [ + "Peg" + ], + "profiles": [ + { + "point": [ + 41.64971183108453, + 8.057925450832967 + ] + } + ], + "exact_regions": true + } + }, + { + "command": "solid.fillet", + "params": { + "edges": [ + [ + 21.53, + 0.0579, + 10 + ] + ], + "radius": 2 + } + }, + { + "command": "solid.fillet", + "params": { + "edges": [ + [ + 0.4893, + 0.0579, + 4 + ], + [ + 0.4893, + 9.058, + 10 + ], + [ + 0.4893, + 0.6437, + 9.4142 + ] + ], + "radius": 2 + } + } + ] +} diff --git a/tests/kernel-cases/fillets/1207-fillet-corner-after-round-running-into-cylinder/expected.json b/tests/kernel-cases/fillets/1207-fillet-corner-after-round-running-into-cylinder/expected.json new file mode 100644 index 0000000000..2924e30d38 --- /dev/null +++ b/tests/kernel-cases/fillets/1207-fillet-corner-after-round-running-into-cylinder/expected.json @@ -0,0 +1,11 @@ +{ + "sources": [ + "tangency-labs/solidcraft#1207" + ], + "what": "after the round of a bar's top edge running into a cylinder, r2 rounds of the three edges at the bar's other top corner (the vertical edge, the left top edge and the round's end arc): 'one of its freeform faces can't be used'", + "source": "analytic", + "method": "a bar 40 x 16 x 10 whose far end is a half disc R8 about (40, 8), a disc R8 about the same centre sketched on its top (the top's outline projected) and extruded 10 up, joined: the bar's sides run tangent into the cylinder, V0 = 6400 + 960 pi; the three r2 rounds at the bar's other top corner (0, 0, 10): the front round's spandrel from x = 2 to the wall (30.5896671706), the vertical edge's and the left top edge's (1 - pi/4) r^2 over 8 and 14, the corner cube of side 2 less the rolling ball's eighth, 8 - 4 pi/3: removed 53.2858385868", + "body_count": 1, + "faces": 12, + "volume_mm3": 9362.643108859389 +} diff --git a/tests/kernel-cases/fillets/1207-fillet-corner-after-round-running-into-cylinder/recipe.json b/tests/kernel-cases/fillets/1207-fillet-corner-after-round-running-into-cylinder/recipe.json new file mode 100644 index 0000000000..bc4f5fea2e --- /dev/null +++ b/tests/kernel-cases/fillets/1207-fillet-corner-after-round-running-into-cylinder/recipe.json @@ -0,0 +1,192 @@ +{ + "commands": [ + { + "command": "sketch.create", + "params": { + "plane": "XY", + "name": "Peg" + } + }, + { + "command": "sketch.line", + "params": { + "points": [ + [ + 0, + 0 + ], + [ + 40, + 0 + ] + ] + } + }, + { + "command": "sketch.arc.center_point", + "params": { + "center": [ + 40, + 8 + ], + "start": [ + 40, + 0 + ], + "end": [ + 40, + 16 + ] + } + }, + { + "command": "sketch.line", + "params": { + "points": [ + [ + 40, + 16 + ], + [ + 0, + 16 + ] + ] + } + }, + { + "command": "sketch.line", + "params": { + "points": [ + [ + 0, + 16 + ], + [ + 0, + 0 + ] + ] + } + }, + { + "command": "sketch.finish", + "params": {} + }, + { + "command": "solid.extrude", + "params": { + "sketch": "Peg", + "distance": 10, + "body_name": "Peg" + } + }, + { + "command": "sketch.create", + "params": { + "plane": { + "origin": [ + 0, + 0, + 10 + ], + "x_dir": [ + 1, + 0, + 0 + ], + "y_dir": [ + 0, + 1, + 0 + ] + }, + "name": "Top" + } + }, + { + "command": "sketch.project", + "params": { + "refs": [ + { + "face": [ + 2, + 8, + 10 + ] + } + ] + } + }, + { + "command": "sketch.circle.center", + "params": { + "center": [ + 40, + 8 + ], + "radius": 8 + } + }, + { + "command": "sketch.finish", + "params": {} + }, + { + "command": "solid.extrude", + "params": { + "sketch": "Top", + "distance": 10, + "operation": "join", + "targets": [ + "Peg" + ], + "profiles": [ + { + "point": [ + 40, + 8 + ] + } + ], + "exact_regions": true + } + }, + { + "command": "solid.fillet", + "params": { + "edges": [ + [ + 20, + 0, + 10 + ] + ], + "radius": 2 + } + }, + { + "command": "solid.fillet", + "params": { + "edges": [ + [ + 0, + 0, + 4 + ], + [ + 0, + 9, + 10 + ], + [ + 0, + 0.5858, + 9.4142 + ] + ], + "radius": 2 + } + } + ] +} diff --git a/tests/kernel-cases/fillets/9-fillet-g2-corner-of-bar-running-into-cylinder/expected.json b/tests/kernel-cases/fillets/9-fillet-g2-corner-of-bar-running-into-cylinder/expected.json new file mode 100644 index 0000000000..1d01a48246 --- /dev/null +++ b/tests/kernel-cases/fillets/9-fillet-g2-corner-of-bar-running-into-cylinder/expected.json @@ -0,0 +1,14 @@ +{ + "sources": [ + "tangency-labs/solidcraft#9" + ], + "what": "three r2 rounds at a top corner of a bar whose far end runs tangent into a cylinder, with the curvature (g2) corner set back 3: SMLib refused the result coming back (a cylinder over more than a turn)", + "source": "analytic", + "method": "a bar 40 x 16 x 10 whose far end is a half disc R8 about (40, 8), a disc R8 about the same centre sketched on its top (the top's outline projected) and extruded 10 up, joined: the bar's sides run tangent into the cylinder, V0 = 6400 + 960 pi; the rolling-ball answer: the three r2 rounds at the bar's other top corner (0, 0, 10): the front round's spandrel from x = 2 to the wall (30.5896671706), the vertical edge's and the left top edge's (1 - pi/4) r^2 over 8 and 14, the corner cube of side 2 less the rolling ball's eighth, 8 - 4 pi/3: removed 53.2858385868; the G2 patch differs from the ball only within the setback cube of side 3 about the vertex, so V is graded as V0 - removed with 3^3 as its tolerance", + "body_count": 1, + "faces": 12, + "volume_mm3": 9362.643108859389, + "tolerance": { + "rel": 0.002883801046998287 + } +} diff --git a/tests/kernel-cases/fillets/9-fillet-g2-corner-of-bar-running-into-cylinder/recipe.json b/tests/kernel-cases/fillets/9-fillet-g2-corner-of-bar-running-into-cylinder/recipe.json new file mode 100644 index 0000000000..e46fb10aff --- /dev/null +++ b/tests/kernel-cases/fillets/9-fillet-g2-corner-of-bar-running-into-cylinder/recipe.json @@ -0,0 +1,191 @@ +{ + "commands": [ + { + "command": "sketch.create", + "params": { + "plane": "XY", + "name": "Peg" + } + }, + { + "command": "sketch.line", + "params": { + "points": [ + [ + 0, + 0 + ], + [ + 40, + 0 + ] + ] + } + }, + { + "command": "sketch.arc.center_point", + "params": { + "center": [ + 40, + 8 + ], + "start": [ + 40, + 0 + ], + "end": [ + 40, + 16 + ] + } + }, + { + "command": "sketch.line", + "params": { + "points": [ + [ + 40, + 16 + ], + [ + 0, + 16 + ] + ] + } + }, + { + "command": "sketch.line", + "params": { + "points": [ + [ + 0, + 16 + ], + [ + 0, + 0 + ] + ] + } + }, + { + "command": "sketch.finish", + "params": {} + }, + { + "command": "solid.extrude", + "params": { + "sketch": "Peg", + "distance": 10, + "body_name": "Peg" + } + }, + { + "command": "sketch.create", + "params": { + "plane": { + "origin": [ + 0, + 0, + 10 + ], + "x_dir": [ + 1, + 0, + 0 + ], + "y_dir": [ + 0, + 1, + 0 + ] + }, + "name": "Top" + } + }, + { + "command": "sketch.project", + "params": { + "refs": [ + { + "face": [ + 2, + 8, + 10 + ] + } + ] + } + }, + { + "command": "sketch.circle.center", + "params": { + "center": [ + 40, + 8 + ], + "radius": 8 + } + }, + { + "command": "sketch.finish", + "params": {} + }, + { + "command": "solid.extrude", + "params": { + "sketch": "Top", + "distance": 10, + "operation": "join", + "targets": [ + "Peg" + ], + "profiles": [ + { + "point": [ + 40, + 8 + ] + } + ], + "exact_regions": true + } + }, + { + "command": "solid.fillet", + "params": { + "edges": [ + [ + 0, + 0, + 4 + ], + [ + 20, + 0, + 10 + ], + [ + 0, + 8, + 10 + ] + ], + "radius": 2, + "corner": "g2", + "setbacks": [ + { + "vertex": [ + 0, + 0, + 10 + ], + "distance": 3 + } + ], + "tangent_chain": false + } + } + ] +} diff --git a/tests/kernel-cases/fillets/KNOWN_FAILING b/tests/kernel-cases/fillets/KNOWN_FAILING index c86d34c84e..dadf33eb4f 100644 --- a/tests/kernel-cases/fillets/KNOWN_FAILING +++ b/tests/kernel-cases/fillets/KNOWN_FAILING @@ -21,6 +21,7 @@ 2893-chamfer-distance-and-angle-past-the-wall-refused refused for another reason: SMLib SM_ERR_INVALID_INPUT, not a check saying the angle runs past the wall 2893-chamfer-two-distances-elliptical-rim SMLib status 1001 on the elliptical rim's chamfer 2893-chamfer-two-distances-past-the-bottom-refused refused for another reason: SMLib status 1001, not too large +1207-fillet-corner-after-round-running-into-cylinder-solver-residues SMLib's check refuses the round: its corner's surface of revolution is close to singular at its boundary (SmSurface test 5) 4782-fillet-bar-edge-wider-than-both-faces SMLib status 1001: a convex round past both its faces is not yet built by subtraction 5158-fillet-round-just-past-a-10mm-face SMLib status 1001: a convex round 0.01 past its face is not yet built by subtraction (10.0001-10.04 open) 5835-chamfer-sloped-basin-1-mm-rim-0-5-4-edges SMLib status 1001 on the chamfers meeting at the rim's re-entrant corners