Sheet metal: sheet.perforate, a perforation field exported to the flat pattern and DXF (#732) (#1041)
Adds sheet.perforate: round holes on a staggered or square grid over the flat sheet, kept clear of edges, cut-outs and bend zones. The holes go to the flat pattern, the DXF and the measured volume rather than the B-rep, so a panel can carry many thousands of them.
This commit is contained in:
1 parent
d399effbf7
commit
54a8c807bf
23 files changed
+413
-6
No files matched your search
@@ -20,6 +20,9 @@ pub static COMMANDS: &[CommandSpec] = &[
|
||||
position?: inside|outside|middle, flip?, body?; type?: base|edge|contour (default from the inputs); name?, body_name? (the new body). \
|
||||
Thickness, K-factor and bend radius come from the rule (sheet.manage_rules); passing them here is refused",
|
||||
),
|
||||
CommandSpec::new("sheet.perforate", "Perforate", perforate).at("SHEET METAL", "CREATE").icon("hem").params(
|
||||
"diameter, pitch: expr; margin?: expr (clear of edges, cut-outs and bends; default: the diameter); pattern?: staggered (60°, default) | square; body? - a perforation field over the whole flat sheet: holes in the flat pattern (perforations), the DXF (layer PERFORATION) and the measured volume, not cut into the B-rep (#732)",
|
||||
),
|
||||
CommandSpec::new("sheet.hem", "Hem", hem)
|
||||
.at("SHEET METAL", "CREATE")
|
||||
.icon("hem")
|
||||
@@ -186,6 +189,23 @@ fn flange(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
}
|
||||
}
|
||||
|
||||
fn perforate(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
let cmd = "sheet.perforate";
|
||||
let diameter = req_expr(cmd, p, "diameter")?;
|
||||
check_expr(s, &diameter, Kind::Length, cmd, "diameter")?;
|
||||
let pitch = req_expr(cmd, p, "pitch")?;
|
||||
check_expr(s, &pitch, Kind::Length, cmd, "pitch")?;
|
||||
let margin = expr(p, "margin");
|
||||
if let Some(m) = &margin {
|
||||
check_expr(s, m, Kind::Length, cmd, "margin")?;
|
||||
}
|
||||
let pattern = str_(p, "pattern").map(str::to_string);
|
||||
if pattern.as_deref().is_some_and(|t| t != "staggered" && t != "square") {
|
||||
return Err(bad(cmd, "`pattern` is \"staggered\" (60°, default) or \"square\""));
|
||||
}
|
||||
add_feature(s, p, FeatureKind::SheetPerforate { diameter, pitch, margin, pattern, body: str_(p, "body").map(str::to_string) })
|
||||
}
|
||||
|
||||
fn hem(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
let cmd = "sheet.hem";
|
||||
let edges = points(p, "edges", cmd)?;
|
||||
@@ -442,7 +462,24 @@ fn flat_json(sh: &SheetBody) -> Result<Value> {
|
||||
.iter()
|
||||
.map(|b| json!({"start": [b.base.x, b.base.y, b.base.z], "axis": [b.axis.x, b.axis.y, b.axis.z], "diameter": b.radius * 2.0, "length": b.height.abs()}))
|
||||
.collect();
|
||||
let mut out = json!({"body": sh.body, "rule": sh.rule, "thickness": sh.t, "k_factor": sh.k, "flat_size_mm": [w, h, sh.t], "outline": outline, "cutouts": holes, "cutout_shapes": hole_shapes, "pockets": pockets, "bends": bends, "unfolded": sh.flat});
|
||||
let mut perforations = Vec::new();
|
||||
for p in &sh.perforations {
|
||||
let n = sh.perforation_holes(p)?.len();
|
||||
perforations.push(json!({"feature": p.feature, "diameter": p.diameter, "pitch": p.pitch, "margin": p.margin,
|
||||
"pattern": if p.square { "square" } else { "staggered" }, "count": n,
|
||||
"open_area_mm2": n as f64 * std::f64::consts::PI * (p.diameter / 2.0).powi(2)}));
|
||||
}
|
||||
let bend_zones: Vec<Value> = sh
|
||||
.bend_zones()
|
||||
.iter()
|
||||
.map(|z| {
|
||||
let pts = z.outer.polyline(1e-3);
|
||||
let f = |g: fn(&Vec2) -> f64, m: fn(f64, f64) -> f64, s: f64| pts.iter().map(g).fold(s, m);
|
||||
json!([f(|p| p.x, f64::min, f64::MAX), f(|p| p.x, f64::max, f64::MIN), f(|p| p.y, f64::min, f64::MAX), f(|p| p.y, f64::max, f64::MIN)])
|
||||
})
|
||||
.collect();
|
||||
let mut out = json!({"body": sh.body, "rule": sh.rule, "thickness": sh.t, "k_factor": sh.k, "flat_size_mm": [w, h, sh.t], "outline": outline, "cutouts": holes, "cutout_shapes": hole_shapes, "pockets": pockets, "bends": bends, "unfolded": sh.flat,
|
||||
"perforations": perforations, "bend_zones": bend_zones});
|
||||
if !bores.is_empty() {
|
||||
out["bores"] = Value::Array(bores);
|
||||
}
|
||||
@@ -472,6 +509,17 @@ pub fn flat_dxf(sh: &SheetBody) -> Result<String> {
|
||||
for p in &pockets {
|
||||
layers.insert(pocket_layer(p));
|
||||
}
|
||||
let perforation: Vec<(Vec2, f64)> = sh
|
||||
.perforations
|
||||
.iter()
|
||||
.map(|p| sh.perforation_holes(p).map(|h| h.into_iter().map(|c| (c, p.diameter / 2.0)).collect::<Vec<_>>()))
|
||||
.collect::<std::result::Result<Vec<_>, _>>()?
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.collect();
|
||||
if !perforation.is_empty() {
|
||||
layers.insert("PERFORATION".to_string());
|
||||
}
|
||||
let mut out = String::new();
|
||||
let mut w = |c: i32, v: &str| out.push_str(&format!("{c}\n{v}\n"));
|
||||
w(0, "SECTION");
|
||||
@@ -559,6 +607,14 @@ pub fn flat_dxf(sh: &SheetBody) -> Result<String> {
|
||||
for b in sh.bends() {
|
||||
line(&mut w, if b.up { "BEND_UP" } else { "BEND_DOWN" }, b.start, b.end);
|
||||
}
|
||||
for (c, r) in &perforation {
|
||||
w(0, "CIRCLE");
|
||||
w(8, "PERFORATION");
|
||||
w(10, &c.x.to_string());
|
||||
w(20, &c.y.to_string());
|
||||
w(30, "0");
|
||||
w(40, &r.to_string());
|
||||
}
|
||||
w(0, "ENDSEC");
|
||||
w(0, "EOF");
|
||||
Ok(out)
|
||||
|
||||
Reference in new issue
Block a user