Skip to main content

brepkit_wasm/bindings/
assembly.rs

1//! Assembly management bindings.
2
3#![allow(clippy::missing_errors_doc)]
4
5use wasm_bindgen::prelude::*;
6
7use crate::error::WasmError;
8use crate::handles::solid_id_to_u32;
9use crate::helpers::{mat4_to_array, parse_mat4};
10use crate::kernel::BrepKernel;
11
12#[wasm_bindgen]
13impl BrepKernel {
14    /// Create a new empty assembly. Returns an assembly index.
15    #[wasm_bindgen(js_name = "assemblyNew")]
16    pub fn assembly_new(&mut self, name: &str) -> u32 {
17        self.assemblies
18            .push(brepkit_operations::assembly::Assembly::new(name));
19        #[allow(clippy::cast_possible_truncation)]
20        let idx = (self.assemblies.len() - 1) as u32;
21        idx
22    }
23
24    /// Add a root component to an assembly.
25    ///
26    /// Returns the component ID.
27    #[wasm_bindgen(js_name = "assemblyAddRoot")]
28    #[allow(clippy::needless_pass_by_value)]
29    pub fn assembly_add_root(
30        &mut self,
31        assembly: u32,
32        name: &str,
33        solid: u32,
34        matrix: Vec<f64>,
35    ) -> Result<u32, JsError> {
36        let solid_id = self.resolve_solid(solid)?;
37        let mat = parse_mat4(&matrix)?;
38        let asm = self
39            .assemblies
40            .get_mut(assembly as usize)
41            .ok_or(WasmError::InvalidHandle {
42                entity: "assembly",
43                index: assembly as usize,
44            })?;
45        let cid = asm.add_root_component(name, solid_id, mat);
46        #[allow(clippy::cast_possible_truncation)]
47        Ok(cid as u32)
48    }
49
50    /// Add a child component to a parent in an assembly.
51    ///
52    /// Returns the component ID.
53    #[wasm_bindgen(js_name = "assemblyAddChild")]
54    #[allow(clippy::needless_pass_by_value)]
55    pub fn assembly_add_child(
56        &mut self,
57        assembly: u32,
58        parent: u32,
59        name: &str,
60        solid: u32,
61        matrix: Vec<f64>,
62    ) -> Result<u32, JsError> {
63        let solid_id = self.resolve_solid(solid)?;
64        let mat = parse_mat4(&matrix)?;
65        let asm = self
66            .assemblies
67            .get_mut(assembly as usize)
68            .ok_or(WasmError::InvalidHandle {
69                entity: "assembly",
70                index: assembly as usize,
71            })?;
72        let cid = asm.add_child_component(parent as usize, name, solid_id, mat)?;
73        #[allow(clippy::cast_possible_truncation)]
74        Ok(cid as u32)
75    }
76
77    /// Flatten an assembly into `[(solid, matrix), ...]`.
78    ///
79    /// Returns a JSON string: `[{"solid": u32, "matrix": [16 floats]}, ...]`.
80    #[wasm_bindgen(js_name = "assemblyFlatten")]
81    pub fn assembly_flatten(&self, assembly: u32) -> Result<String, JsError> {
82        let asm = self
83            .assemblies
84            .get(assembly as usize)
85            .ok_or(WasmError::InvalidHandle {
86                entity: "assembly",
87                index: assembly as usize,
88            })?;
89        let flat = asm.flatten();
90        let entries: Vec<serde_json::Value> = flat
91            .iter()
92            .map(|(solid_id, mat)| {
93                serde_json::json!({
94                    "solid": solid_id_to_u32(*solid_id),
95                    "matrix": mat4_to_array(mat),
96                })
97            })
98            .collect();
99        Ok(serde_json::Value::Array(entries).to_string())
100    }
101
102    /// Get the bill of materials for an assembly.
103    ///
104    /// Returns a JSON string: `[{"name": "...", "solidIndex": n, "instanceCount": n}, ...]`.
105    #[wasm_bindgen(js_name = "assemblyBom")]
106    pub fn assembly_bom(&self, assembly: u32) -> Result<String, JsError> {
107        let asm = self
108            .assemblies
109            .get(assembly as usize)
110            .ok_or(WasmError::InvalidHandle {
111                entity: "assembly",
112                index: assembly as usize,
113            })?;
114        let bom = asm.bill_of_materials();
115        let entries: Vec<serde_json::Value> = bom
116            .iter()
117            .map(|entry| {
118                serde_json::json!({
119                    "name": entry.name,
120                    "solidIndex": entry.solid_index,
121                    "instanceCount": entry.instance_count,
122                })
123            })
124            .collect();
125        Ok(serde_json::Value::Array(entries).to_string())
126    }
127}