Skip to main content

brep_kernel/feature_pipeline/sheet_metal/
mod.rs

1//! Exact-BREP sheet metal.
2//!
3//! Sheet metal is modeled as a parametric [`tree::SheetTree`] of flats + bends and
4//! turned into exact-BREP geometry by a single fold-parametric [`evaluate`]: the
5//! folded 3D part at `fold = 1.0`, and the flat pattern (the "unfold") at
6//! `fold = 0.0`. Everything is built from existing kernel ops — no triangle mesh.
7//!
8//! Sheet-metal features author or mutate the tree; unfold evaluates it flat.
9
10pub mod evaluate;
11pub mod flat_pattern;
12pub mod tree;
13
14pub use evaluate::evaluate;
15pub use tree::{Bend, Edge, Flat, Hole, HoleBend, HoleBendKind, SheetTree};
16
17use std::cell::RefCell;
18use std::collections::HashMap;
19
20/// Evaluate and register a folded tree, retaining the evaluator's face and edge
21/// names. Generic solid registration also restamps names and is unsuitable here.
22pub(crate) fn register_folded(tree: SheetTree, name: &str) -> Result<super::AddedSolid, String> {
23    use super::features::common::{collect_edge_names, collect_face_names};
24    let solid = evaluate(&tree, 1.0)?;
25    let face_names = collect_face_names(&solid);
26    let edge_names = collect_edge_names(&solid);
27    let handle = crate::register_solid_value(solid);
28    put_tree(handle, tree);
29    Ok(super::AddedSolid {
30        handle,
31        name: name.to_string(),
32        face_names,
33        edge_names,
34        ..super::AddedSolid::default()
35    })
36}
37
38thread_local! {
39    /// Trees keyed by resident solid handle. Chained features store each updated
40    /// tree under the new handle; history-cache eviction removes it with that handle.
41    static SHEET_TREES: RefCell<HashMap<u32, SheetTree>> = RefCell::new(HashMap::new());
42}
43
44/// Attach `tree` to the resident solid `handle`.
45pub fn put_tree(handle: u32, tree: SheetTree) {
46    SHEET_TREES.with(|trees| {
47        trees.borrow_mut().insert(handle, tree);
48    });
49}
50
51/// The sheet-metal tree of the resident solid `handle`, if it carries one.
52pub fn get_tree(handle: u32) -> Option<SheetTree> {
53    SHEET_TREES.with(|trees| trees.borrow().get(&handle).cloned())
54}
55
56/// Remove the tree when its solid handle is freed. Cached handles retain theirs.
57pub fn remove_tree(handle: u32) {
58    SHEET_TREES.with(|trees| {
59        trees.borrow_mut().remove(&handle);
60    });
61}
62
63/// Drop every stored tree — the full-reset path (`clear_history_cache`, e.g. on a
64/// part/document switch).
65pub fn clear_trees() {
66    SHEET_TREES.with(|trees| trees.borrow_mut().clear());
67}
68
69/// Whether the resident solid `handle` carries a sheet-metal tree — the
70/// SheetTree-free predicate the export lane filters resident solids with (so the
71/// native engine picks the flat-pattern target without touching `SheetTree`).
72pub fn is_sheet_metal_handle(handle: u32) -> bool {
73    SHEET_TREES.with(|trees| trees.borrow().contains_key(&handle))
74}
75
76/// Export the flat pattern of the sheet-metal body `handle` as DXF (R12 ASCII).
77/// Runs the unfold TRANSIENTLY off the resident tree — no feature, no history
78/// mutation. Errors if the handle carries no sheet-metal tree.
79pub fn flat_pattern_dxf(handle: u32) -> Result<String, String> {
80    let tree = get_tree(handle)
81        .ok_or_else(|| "flat pattern: handle is not a sheet-metal body".to_string())?;
82    Ok(flat_pattern::to_dxf(&flat_pattern::build(&tree)?))
83}
84
85/// Export the flat pattern of the sheet-metal body `handle` as SVG — the DXF
86/// sibling of [`flat_pattern_dxf`].
87pub fn flat_pattern_svg(handle: u32) -> Result<String, String> {
88    let tree = get_tree(handle)
89        .ok_or_else(|| "flat pattern: handle is not a sheet-metal body".to_string())?;
90    Ok(flat_pattern::to_svg(&flat_pattern::build(&tree)?))
91}