Sheet metal: a cut-out with a corner a hair beside a bend line refolds (#1095)
Edges shorter than the model tolerance are dropped from the flat cells, and the refold sews touching corners, so a cut-out across a bend line no longer fails with a degenerate edge.
This commit is contained in:
1 parent
c469adf456
commit
c3aae64a63
4 files changed
+433
-15
No files matched your search
@@ -507,6 +507,139 @@ fn unfold_cut_refold_and_convert() {
|
||||
assert!(t.execute("sheet.convert", &json!({"body": "Block", "face": [50, 30, 2.5]})).is_err());
|
||||
}
|
||||
|
||||
/// A plate (15, -20) (0, 0) (-100, 0) (-100, -20) with a 20 mm inside flange on its slanted edge
|
||||
/// (2 mm sheet, R 2, K 0.5: the folded sheet holds its flat area times the thickness), unfolded,
|
||||
/// and a triangle cut out with a corner on the bend line: where the line ends on the plate's
|
||||
/// edge at (-5, 0), the triangle on the bend or on the base, or in the line's middle. The refold
|
||||
/// failed ("sew: face 10: This wire is not simple.").
|
||||
#[test]
|
||||
fn a_cut_out_with_a_corner_on_a_bend_line_refolds() {
|
||||
// The base (10, -20) (-5, 0) (-100, 0) (-100, -20): 2050; the bend 25 x 3π/2; the flange 25 x 16.
|
||||
let area = 2450.0 + 37.5 * PI;
|
||||
let cases = [
|
||||
([[-5.0, 0.0], [-3.0, -1.0], [-3.0, 1.0]], 2.0),
|
||||
([[-5.0, 0.0], [-7.0, -1.0], [-6.0, -3.0]], 2.5),
|
||||
([[2.5, -10.0], [2.1, -12.8], [-0.3, -9.6]], 4.0),
|
||||
([[2.5, -10.0], [4.7, -9.6], [3.5, -8.0]], 2.0),
|
||||
];
|
||||
for (triangle, cut) in cases {
|
||||
let mut s = Session::default();
|
||||
run(&mut s, "sheet.manage_rules", json!({"name": "Rule", "active": true, "thickness": "2 mm", "k_factor": "0.5", "bend_radius": "2 mm"}));
|
||||
run(&mut s, "sketch.create", json!({"plane": "XY", "name": "Outline"}));
|
||||
run(&mut s, "sketch.line", json!({"points": [[15, -20], [0, 0], [-100, 0], [-100, -20]], "closed": true}));
|
||||
run(&mut s, "sketch.finish", json!({}));
|
||||
run(&mut s, "sheet.flange", json!({"sketch": "Outline", "rule": "Rule"}));
|
||||
run(&mut s, "sheet.flange", json!({"edges": [[7.5, -10, 2]], "height": 20, "radius": 2, "position": "inside"}));
|
||||
// The measure follows the bend by facets.
|
||||
let folded = volume(&mut s);
|
||||
assert!(rel(folded, area * 2.0) < 1e-4, "{folded} vs {}", area * 2.0);
|
||||
run(&mut s, "sheet.unfold", json!({}));
|
||||
run(&mut s, "sketch.create", json!({"plane": "XY", "name": "Cutout"}));
|
||||
run(&mut s, "sketch.line", json!({"points": triangle, "closed": true}));
|
||||
run(&mut s, "sketch.finish", json!({}));
|
||||
run(&mut s, "solid.extrude", json!({"sketch": "Cutout", "through_all": true, "direction": "symmetric", "operation": "cut"}));
|
||||
assert!(rel(volume(&mut s), (area - cut) * 2.0) < 1e-9, "{triangle:?} flat: {}", volume(&mut s));
|
||||
run(&mut s, "sheet.refold", json!({}));
|
||||
let refolded = volume(&mut s);
|
||||
assert!((folded - refolded - cut * 2.0).abs() < 0.01, "{triangle:?} refolded: {refolded}, {} less", folded - refolded);
|
||||
}
|
||||
}
|
||||
|
||||
/// Plates with an inside flange on a slanted edge (2 mm sheet, R 2, K 0.5: the folded sheet
|
||||
/// holds its flat area times the thickness), unfolded, and a triangle cut out across the bend
|
||||
/// line with a corner 0.05 µm beside the line, or on it at x = 84.0764335, a border between
|
||||
/// two cells of the 1e-6 mm grid the sew finds vertices on. The refold failed ("sew: a
|
||||
/// degenerate edge", "sew: face 13: This wire is not closed."); it loses the triangle.
|
||||
#[test]
|
||||
fn a_cut_corner_a_hair_from_a_bend_line_refolds() {
|
||||
let root820 = 820f64.sqrt();
|
||||
let cases = [
|
||||
// Base 1750, bend 25 x 3π/2, flange 25 x 26; a triangle of 4 mm².
|
||||
(
|
||||
[[0.0, 0.0], [100.0, 0.0], [85.0, 20.0], [0.0, 20.0]],
|
||||
[92.5, 10.0, 2.0],
|
||||
30.0,
|
||||
[[87.49999996, 9.99999997], [85.49999996, 7.99999997], [89.49999996, 7.99999997]],
|
||||
2400.0 + 37.5 * PI,
|
||||
4.0,
|
||||
),
|
||||
// The edge is √820 long; the base loses 4 mm along its normal: 2444 − 4√820; the bend
|
||||
// √820 x 3π/2, the flange √820 x 36; a triangle of 3 mm².
|
||||
(
|
||||
[[0.0, 0.0], [100.0, 0.0], [88.0, 26.0], [0.0, 26.0]],
|
||||
[94.0, 13.0, 2.0],
|
||||
40.0,
|
||||
[[84.0764335, 24.9558467078], [82.0764335, 22.9558467078], [86.0764335, 23.9558467078]],
|
||||
2444.0 + root820 * (32.0 + 3.0 * PI / 2.0),
|
||||
3.0,
|
||||
),
|
||||
];
|
||||
for (outline, edge, height, triangle, area, cut) in cases {
|
||||
let mut s = Session::default();
|
||||
run(&mut s, "sheet.manage_rules", json!({"name": "Rule", "active": true, "thickness": "2 mm", "k_factor": "0.5", "bend_radius": "2 mm"}));
|
||||
run(&mut s, "sketch.create", json!({"plane": "XY", "name": "Outline"}));
|
||||
run(&mut s, "sketch.line", json!({"points": outline, "closed": true}));
|
||||
run(&mut s, "sketch.finish", json!({}));
|
||||
run(&mut s, "sheet.flange", json!({"sketch": "Outline", "rule": "Rule"}));
|
||||
run(&mut s, "sheet.flange", json!({"edges": [edge], "height": height, "radius": 2, "position": "inside"}));
|
||||
// The measure follows the bend by facets.
|
||||
let folded = volume(&mut s);
|
||||
assert!(rel(folded, area * 2.0) < 1e-4, "{folded} vs {}", area * 2.0);
|
||||
run(&mut s, "sheet.unfold", json!({}));
|
||||
run(&mut s, "sketch.create", json!({"plane": "XY", "name": "Cutout"}));
|
||||
run(&mut s, "sketch.line", json!({"points": triangle, "closed": true}));
|
||||
run(&mut s, "sketch.finish", json!({}));
|
||||
run(&mut s, "solid.extrude", json!({"sketch": "Cutout", "through_all": true, "direction": "symmetric", "operation": "cut"}));
|
||||
assert!(rel(volume(&mut s), (area - cut) * 2.0) < 1e-9, "flat: {}", volume(&mut s));
|
||||
run(&mut s, "sheet.refold", json!({}));
|
||||
let refolded = volume(&mut s);
|
||||
assert!((folded - refolded - cut * 2.0).abs() < 0.01, "refolded: {refolded}, {} less", folded - refolded);
|
||||
}
|
||||
}
|
||||
|
||||
/// A 100 x 60 plate (2 mm sheet, R 2, K 0.5) with a 42 mm flange (R 1) outside its bottom edge,
|
||||
/// unfolded, and a notch cut off the flat flange's free corner: an arc from the side edge,
|
||||
/// through (0.6, 0.6) from the corner, to the free edge, closed by lines through a point outside
|
||||
/// the sheet. The arc leaves the side edge 1.7997505 mm from the corner, in the folded flange at
|
||||
/// a height of 42 − 1.7997505 = 40.2002495 mm: a border between two cells of the 1e-6 mm grid the
|
||||
/// sew finds vertices on, and the arc's end and the edge's, worked out apart, differ by 7e-13
|
||||
/// mm. The refold failed ("sew: face 5: This wire is not closed."); it loses the notch.
|
||||
#[test]
|
||||
fn a_notch_whose_arc_ends_on_a_grid_border_refolds() {
|
||||
let t = 1.7997505;
|
||||
// The flat flange ends at 39 + the bend allowance (π/2)(R + K T) = 39 + π below the plate.
|
||||
let free = -(42.0 - 1.0 - 2.0 + FRAC_PI_2 * (1.0 + 0.5 * 2.0));
|
||||
let flat = 6000.0 + 100.0 * PI + 100.0 * 39.0;
|
||||
// The notch is the triangle corner, end, end less the circle's segment over its chord; the
|
||||
// circle's centre (a, a) from the corner is as far from (0.6, 0.6) as from the arc's ends.
|
||||
let a = (t * t - 0.72) / (2.0 * t - 2.4);
|
||||
let r2 = 2.0 * (a - 0.6) * (a - 0.6);
|
||||
let angle = 2.0 * (t * 2f64.sqrt() / (2.0 * r2.sqrt())).asin();
|
||||
let notch = t * t / 2.0 - r2 / 2.0 * (angle - angle.sin());
|
||||
assert!((notch - 0.88421).abs() < 1e-5, "{notch}");
|
||||
let mut s = Session::default();
|
||||
run(&mut s, "sheet.manage_rules", json!({"name": "Rule", "active": true, "thickness": "2 mm", "k_factor": "0.5", "bend_radius": "2 mm"}));
|
||||
run(&mut s, "sketch.create", json!({"plane": "XY", "name": "Outline"}));
|
||||
run(&mut s, "sketch.line", json!({"points": [[0, 0], [100, 0], [100, 60], [0, 60]], "closed": true}));
|
||||
run(&mut s, "sketch.finish", json!({}));
|
||||
run(&mut s, "sheet.flange", json!({"sketch": "Outline", "rule": "Rule"}));
|
||||
run(&mut s, "sheet.flange", json!({"edges": [[50, 0, 2]], "height": 42, "radius": 1, "position": "outside"}));
|
||||
// The measure follows the bend by facets.
|
||||
let folded = volume(&mut s);
|
||||
assert!(rel(folded, flat * 2.0) < 1e-4, "{folded} vs {}", flat * 2.0);
|
||||
run(&mut s, "sheet.unfold", json!({}));
|
||||
run(&mut s, "sketch.create", json!({"plane": "XY", "name": "Cutout"}));
|
||||
run(&mut s, "sketch.arc.three_point", json!({"start": [t, free], "through": [0.6, free + 0.6], "end": [0.0, free + t]}));
|
||||
run(&mut s, "sketch.line", json!({"points": [[0.0, free + t], [-1.0, -44.0]]}));
|
||||
run(&mut s, "sketch.line", json!({"points": [[-1.0, -44.0], [t, free]]}));
|
||||
run(&mut s, "sketch.finish", json!({}));
|
||||
run(&mut s, "solid.extrude", json!({"sketch": "Cutout", "through_all": true, "direction": "symmetric", "operation": "cut"}));
|
||||
assert!(rel(volume(&mut s), (flat - notch) * 2.0) < 1e-6, "flat: {}", volume(&mut s));
|
||||
run(&mut s, "sheet.refold", json!({}));
|
||||
let refolded = volume(&mut s);
|
||||
assert!((folded - refolded - notch * 2.0).abs() < 0.01, "refolded: {refolded}, {} less", folded - refolded);
|
||||
}
|
||||
|
||||
/// A sketch line across a 100 x 60 plate's top face at x = 40.
|
||||
fn fold_line(s: &mut Session) {
|
||||
run(s, "sketch.create", json!({"plane": "XY", "offset": 2.5, "name": "FoldLine"}));
|
||||
|
||||
Reference in new issue
Block a user