1use super::*;
2
3#[wasm_bindgen]
4pub struct WasmNurbsCurve {
5 pub(crate) curve: NurbsCurve,
6}
7
8#[wasm_bindgen]
9pub struct WasmNurbsSurface {
10 pub(crate) surface: NurbsSurface,
11}
12
13#[wasm_bindgen]
17pub struct WasmSolidBuffer {
18 pub(crate) data: Vec<f64>,
19 pub(crate) names_json: String,
20 pub(crate) metadata_json: String,
21}
22
23#[wasm_bindgen]
24impl WasmSolidBuffer {
25 pub fn take_data(&mut self) -> Vec<f64> {
26 std::mem::take(&mut self.data)
27 }
28
29 pub fn names_json(&self) -> String {
30 self.names_json.clone()
31 }
32
33 pub fn metadata_json(&self) -> String {
36 self.metadata_json.clone()
37 }
38}
39
40pub(crate) fn solid_buffer(solid: &BrepSolid, metadata_json: String) -> Result<WasmSolidBuffer, JsValue> {
41 let (data, names) = encode_solid(solid).map_err(javascript_error)?;
42 Ok(WasmSolidBuffer {
43 data,
44 names_json: json_out(&names)?,
45 metadata_json,
46 })
47}
48
49#[wasm_bindgen]
51pub struct WasmMeshBuffers {
52 pub(crate) positions: Vec<f64>,
53 pub(crate) normals: Vec<f64>,
54 pub(crate) indices: Vec<u32>,
55 pub(crate) face_ids: Vec<u32>,
56}
57
58#[wasm_bindgen]
59impl WasmMeshBuffers {
60 pub fn take_positions(&mut self) -> Vec<f64> {
61 std::mem::take(&mut self.positions)
62 }
63
64 pub fn take_normals(&mut self) -> Vec<f64> {
65 std::mem::take(&mut self.normals)
66 }
67
68 pub fn take_indices(&mut self) -> Vec<u32> {
69 std::mem::take(&mut self.indices)
70 }
71
72 pub fn take_face_ids(&mut self) -> Vec<u32> {
73 std::mem::take(&mut self.face_ids)
74 }
75}
76
77thread_local! {
94 static SOLID_REGISTRY: std::cell::RefCell<SolidRegistry> =
95 std::cell::RefCell::new(SolidRegistry::new());
96}
97
98pub(crate) struct SolidRegistry {
99 pub(crate) next: u32,
100 pub(crate) solids: std::collections::HashMap<u32, BrepSolid>,
101}
102
103impl SolidRegistry {
104 fn new() -> Self {
105 Self {
106 next: 1,
107 solids: std::collections::HashMap::new(),
108 }
109 }
110 fn insert(&mut self, solid: BrepSolid) -> u32 {
111 let handle = self.next;
112 self.next = self.next.wrapping_add(1).max(1);
113 self.solids.insert(handle, solid);
114 handle
115 }
116}
117
118pub(crate) fn register_solid_value(solid: BrepSolid) -> u32 {
119 SOLID_REGISTRY.with(|registry| registry.borrow_mut().insert(solid))
120}
121
122pub(crate) fn with_registered_solid<T>(
124 handle: u32,
125 f: impl FnOnce(&BrepSolid) -> Result<T, JsValue>,
126) -> Result<T, JsValue> {
127 SOLID_REGISTRY.with(|registry| {
128 let registry = registry.borrow();
129 let solid = registry
130 .solids
131 .get(&handle)
132 .ok_or_else(|| javascript_error(format!("unknown solid handle {handle}")))?;
133 f(solid)
134 })
135}
136
137pub(crate) fn with_registered_solid_typed<T>(
145 handle: u32,
146 f: impl FnOnce(&BrepSolid) -> Result<T, crate::KernelRefusal>,
147) -> Result<T, crate::KernelRefusal> {
148 SOLID_REGISTRY.with(|registry| {
149 let registry = registry.borrow();
150 let solid = registry.solids.get(&handle).ok_or_else(|| {
151 crate::KernelRefusal::input(
152 crate::KernelStage::Collect,
153 "handle",
154 format!("unknown solid handle {handle}"),
155 )
156 })?;
157 f(solid)
158 })
159}
160
161pub(crate) fn with_registered_solid_str<T>(
162 handle: u32,
163 f: impl FnOnce(&BrepSolid) -> Result<T, String>,
164) -> Result<T, String> {
165 SOLID_REGISTRY.with(|registry| {
166 let registry = registry.borrow();
167 let solid = registry
168 .solids
169 .get(&handle)
170 .ok_or_else(|| format!("unknown solid handle {handle}"))?;
171 f(solid)
172 })
173}
174
175pub(crate) fn with_two_registered_solids<T, E: From<crate::KernelRefusal>>(
182 a: u32,
183 b: u32,
184 f: impl FnOnce(&BrepSolid, &BrepSolid) -> Result<T, E>,
185) -> Result<T, E> {
186 SOLID_REGISTRY.with(|registry| {
187 let registry = registry.borrow();
188 let handle = |id: u32| -> Result<&BrepSolid, E> {
189 registry.solids.get(&id).ok_or_else(|| {
190 crate::KernelRefusal::input(
191 crate::KernelStage::Collect,
192 "solid_handle",
193 format!("unknown solid handle {id}"),
194 )
195 .into()
196 })
197 };
198 let sa = handle(a)?;
199 let sb = handle(b)?;
200 f(sa, sb)
201 })
202}
203
204pub(crate) fn replace_registered_solid(handle: u32, solid: BrepSolid) -> Result<(), String> {
211 SOLID_REGISTRY.with(|registry| {
212 let mut registry = registry.borrow_mut();
213 match registry.solids.get_mut(&handle) {
214 Some(slot) => {
215 *slot = solid;
216 Ok(())
217 }
218 None => Err(format!("unknown solid handle {handle}")),
219 }
220 })
221}
222
223pub(crate) fn free_registered_solid(handle: u32) {
227 SOLID_REGISTRY.with(|registry| {
228 registry.borrow_mut().solids.remove(&handle);
229 });
230}
231
232pub(crate) fn take_registered_solid(handle: u32) -> Option<BrepSolid> {
235 SOLID_REGISTRY.with(|registry| registry.borrow_mut().solids.remove(&handle))
236}
237
238#[wasm_bindgen]
241pub fn register_solid_buffer(data: &[f64], names_json: &str) -> Result<u32, JsValue> {
242 let solid = decode_solid_buffer(data, names_json)?;
243 let solid = validate_imported_solid(solid, "register_solid_buffer")?;
244 Ok(register_solid_value(solid))
245}
246
247#[wasm_bindgen]
249pub fn register_solid_json(solid_json: &str) -> Result<u32, JsValue> {
250 let solid: BrepSolid = json_in(solid_json)?;
251 let solid = validate_imported_solid(solid, "register_solid_json")?;
252 Ok(register_solid_value(solid))
253}
254
255#[wasm_bindgen]
257pub fn free_solid(handle: u32) {
258 SOLID_REGISTRY.with(|registry| {
259 registry.borrow_mut().solids.remove(&handle);
260 });
261}
262
263pub fn registered_solid_clone(handle: u32) -> Result<BrepSolid, String> {
270 with_registered_solid_str(handle, |solid| Ok(solid.clone()))
271}
272
273#[wasm_bindgen]
275pub fn registered_solid_count() -> usize {
276 SOLID_REGISTRY.with(|registry| registry.borrow().solids.len())
277}
278
279#[wasm_bindgen]
283pub fn boolean_handle(
284 a: u32,
285 b: u32,
286 operation: &str,
287 tolerance: f64,
288 merge_coplanar_faces: bool,
289) -> Result<u32, JsValue> {
290 let operation = match operation {
291 "union" => BooleanOperation::Union,
292 "intersect" => BooleanOperation::Intersect,
293 "subtract" => BooleanOperation::Subtract,
294 _ => return Err(javascript_error("unknown boolean operation".into())),
295 };
296 let result = SOLID_REGISTRY.with(|registry| {
297 let registry = registry.borrow();
298 let sa = registry
299 .solids
300 .get(&a)
301 .ok_or_else(|| javascript_error(format!("unknown solid handle {a}")))?;
302 let sb = registry
303 .solids
304 .get(&b)
305 .ok_or_else(|| javascript_error(format!("unknown solid handle {b}")))?;
306 boolean_operation(
307 sa,
308 sb,
309 operation,
310 &BooleanOptions {
311 tolerance,
312 merge_coplanar_faces,
313 ..BooleanOptions::default()
314 },
315 )
316 .map_err(crate::abi::geometry::javascript_refusal)
317 })?;
318 Ok(register_solid_value(result))
319}
320
321#[wasm_bindgen]
324pub fn tessellate_handle(handle: u32, chord_tolerance: f64) -> Result<WasmMeshBuffers, JsValue> {
325 with_registered_solid(handle, |solid| {
326 let mesh = tessellate_brep_watertight(solid, chord_tolerance).map_err(javascript_error)?;
327 Ok(WasmMeshBuffers {
328 positions: mesh.positions,
329 normals: mesh.normals,
330 indices: mesh.indices,
331 face_ids: mesh.face_ids,
332 })
333 })
334}
335
336#[wasm_bindgen]
338pub fn mass_properties_handle(handle: u32) -> Result<String, JsValue> {
339 with_registered_solid(handle, |solid| {
340 let _caller = crate::mass_caller("abi.mass_properties");
341 let properties = solid_mass_properties(solid).map_err(javascript_error)?;
342 json_out(&properties)
343 })
344}
345
346#[wasm_bindgen]
350pub fn transform_handle(
351 handle: u32,
352 matrix: &[f64],
353 reverse_orientation: bool,
354) -> Result<u32, JsValue> {
355 let matrix: [f64; 16] = matrix
356 .try_into()
357 .map_err(|_| javascript_error("transform matrix must contain 16 values".into()))?;
358 let transform = AffineTransform::new(matrix).map_err(javascript_error)?;
359 let result = with_registered_solid(handle, |solid| {
360 transform_brep(solid, transform, reverse_orientation).map_err(javascript_error)
361 })?;
362 Ok(register_solid_value(result))
363}
364
365#[wasm_bindgen]
368pub fn face_names_handle(handle: u32) -> Result<String, JsValue> {
369 with_registered_solid(handle, |solid| {
370 let mut map: Vec<(u64, Option<String>)> = Vec::new();
371 for shell in &solid.shells {
372 for face in &shell.faces {
373 map.push((face.id, face.name.clone()));
374 }
375 }
376 json_out(&map)
377 })
378}
379
380pub fn boolean_handle_native(
392 a: u32,
393 b: u32,
394 operation: BooleanOperation,
395 options: &BooleanOptions,
396) -> Result<u32, String> {
397 let result =
398 with_two_registered_solids(a, b, |sa, sb| boolean_operation(sa, sb, operation, options))?;
399 Ok(register_solid_value(result))
400}