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: serde_json::to_string(&names)
45 .map_err(|error| javascript_error(error.to_string()))?,
46 metadata_json,
47 })
48}
49
50#[wasm_bindgen]
52pub struct WasmMeshBuffers {
53 pub(crate) positions: Vec<f64>,
54 pub(crate) normals: Vec<f64>,
55 pub(crate) indices: Vec<u32>,
56 pub(crate) face_ids: Vec<u32>,
57}
58
59#[wasm_bindgen]
60impl WasmMeshBuffers {
61 pub fn take_positions(&mut self) -> Vec<f64> {
62 std::mem::take(&mut self.positions)
63 }
64
65 pub fn take_normals(&mut self) -> Vec<f64> {
66 std::mem::take(&mut self.normals)
67 }
68
69 pub fn take_indices(&mut self) -> Vec<u32> {
70 std::mem::take(&mut self.indices)
71 }
72
73 pub fn take_face_ids(&mut self) -> Vec<u32> {
74 std::mem::take(&mut self.face_ids)
75 }
76}
77
78thread_local! {
95 static SOLID_REGISTRY: std::cell::RefCell<SolidRegistry> =
96 std::cell::RefCell::new(SolidRegistry::new());
97}
98
99pub(crate) struct SolidRegistry {
100 pub(crate) next: u32,
101 pub(crate) solids: std::collections::HashMap<u32, BrepSolid>,
102}
103
104impl SolidRegistry {
105 fn new() -> Self {
106 Self {
107 next: 1,
108 solids: std::collections::HashMap::new(),
109 }
110 }
111 fn insert(&mut self, solid: BrepSolid) -> u32 {
112 let handle = self.next;
113 self.next = self.next.wrapping_add(1).max(1);
114 self.solids.insert(handle, solid);
115 handle
116 }
117}
118
119pub(crate) fn register_solid_value(solid: BrepSolid) -> u32 {
120 SOLID_REGISTRY.with(|registry| registry.borrow_mut().insert(solid))
121}
122
123pub(crate) fn with_registered_solid<T>(
125 handle: u32,
126 f: impl FnOnce(&BrepSolid) -> Result<T, JsValue>,
127) -> Result<T, JsValue> {
128 SOLID_REGISTRY.with(|registry| {
129 let registry = registry.borrow();
130 let solid = registry
131 .solids
132 .get(&handle)
133 .ok_or_else(|| javascript_error(format!("unknown solid handle {handle}")))?;
134 f(solid)
135 })
136}
137
138pub(crate) fn with_registered_solid_typed<T>(
146 handle: u32,
147 f: impl FnOnce(&BrepSolid) -> Result<T, crate::KernelRefusal>,
148) -> Result<T, crate::KernelRefusal> {
149 SOLID_REGISTRY.with(|registry| {
150 let registry = registry.borrow();
151 let solid = registry.solids.get(&handle).ok_or_else(|| {
152 crate::KernelRefusal::input(
153 crate::KernelStage::Collect,
154 "handle",
155 format!("unknown solid handle {handle}"),
156 )
157 })?;
158 f(solid)
159 })
160}
161
162pub(crate) fn with_registered_solid_str<T>(
163 handle: u32,
164 f: impl FnOnce(&BrepSolid) -> Result<T, String>,
165) -> Result<T, String> {
166 SOLID_REGISTRY.with(|registry| {
167 let registry = registry.borrow();
168 let solid = registry
169 .solids
170 .get(&handle)
171 .ok_or_else(|| format!("unknown solid handle {handle}"))?;
172 f(solid)
173 })
174}
175
176pub(crate) fn with_two_registered_solids<T, E: From<crate::KernelRefusal>>(
183 a: u32,
184 b: u32,
185 f: impl FnOnce(&BrepSolid, &BrepSolid) -> Result<T, E>,
186) -> Result<T, E> {
187 SOLID_REGISTRY.with(|registry| {
188 let registry = registry.borrow();
189 let handle = |id: u32| -> Result<&BrepSolid, E> {
190 registry.solids.get(&id).ok_or_else(|| {
191 crate::KernelRefusal::input(
192 crate::KernelStage::Collect,
193 "solid_handle",
194 format!("unknown solid handle {id}"),
195 )
196 .into()
197 })
198 };
199 let sa = handle(a)?;
200 let sb = handle(b)?;
201 f(sa, sb)
202 })
203}
204
205pub(crate) fn replace_registered_solid(handle: u32, solid: BrepSolid) -> Result<(), String> {
212 SOLID_REGISTRY.with(|registry| {
213 let mut registry = registry.borrow_mut();
214 match registry.solids.get_mut(&handle) {
215 Some(slot) => {
216 *slot = solid;
217 Ok(())
218 }
219 None => Err(format!("unknown solid handle {handle}")),
220 }
221 })
222}
223
224pub(crate) fn free_registered_solid(handle: u32) {
228 SOLID_REGISTRY.with(|registry| {
229 registry.borrow_mut().solids.remove(&handle);
230 });
231}
232
233pub(crate) fn take_registered_solid(handle: u32) -> Option<BrepSolid> {
236 SOLID_REGISTRY.with(|registry| registry.borrow_mut().solids.remove(&handle))
237}
238
239#[wasm_bindgen]
242pub fn register_solid_buffer(data: &[f64], names_json: &str) -> Result<u32, JsValue> {
243 let solid = decode_solid_buffer(data, names_json)?;
244 let solid = validate_imported_solid(solid, "register_solid_buffer")?;
245 Ok(register_solid_value(solid))
246}
247
248#[wasm_bindgen]
250pub fn register_solid_json(solid_json: &str) -> Result<u32, JsValue> {
251 let solid: BrepSolid =
252 serde_json::from_str(solid_json).map_err(|error| javascript_error(error.to_string()))?;
253 let solid = validate_imported_solid(solid, "register_solid_json")?;
254 Ok(register_solid_value(solid))
255}
256
257#[wasm_bindgen]
259pub fn free_solid(handle: u32) {
260 SOLID_REGISTRY.with(|registry| {
261 registry.borrow_mut().solids.remove(&handle);
262 });
263}
264
265pub fn registered_solid_clone(handle: u32) -> Result<BrepSolid, String> {
272 with_registered_solid_str(handle, |solid| Ok(solid.clone()))
273}
274
275#[wasm_bindgen]
277pub fn registered_solid_count() -> usize {
278 SOLID_REGISTRY.with(|registry| registry.borrow().solids.len())
279}
280
281#[wasm_bindgen]
285pub fn boolean_handle(
286 a: u32,
287 b: u32,
288 operation: &str,
289 tolerance: f64,
290 merge_coplanar_faces: bool,
291) -> Result<u32, JsValue> {
292 let operation = match operation {
293 "union" => BooleanOperation::Union,
294 "intersect" => BooleanOperation::Intersect,
295 "subtract" => BooleanOperation::Subtract,
296 _ => return Err(javascript_error("unknown boolean operation".into())),
297 };
298 let result = SOLID_REGISTRY.with(|registry| {
299 let registry = registry.borrow();
300 let sa = registry
301 .solids
302 .get(&a)
303 .ok_or_else(|| javascript_error(format!("unknown solid handle {a}")))?;
304 let sb = registry
305 .solids
306 .get(&b)
307 .ok_or_else(|| javascript_error(format!("unknown solid handle {b}")))?;
308 boolean_operation(
309 sa,
310 sb,
311 operation,
312 &BooleanOptions {
313 tolerance,
314 merge_coplanar_faces,
315 ..BooleanOptions::default()
316 },
317 )
318 .map_err(crate::abi::geometry::javascript_refusal)
319 })?;
320 Ok(register_solid_value(result))
321}
322
323#[wasm_bindgen]
326pub fn tessellate_handle(handle: u32, chord_tolerance: f64) -> Result<WasmMeshBuffers, JsValue> {
327 with_registered_solid(handle, |solid| {
328 let mesh = tessellate_brep_watertight(solid, chord_tolerance).map_err(javascript_error)?;
329 Ok(WasmMeshBuffers {
330 positions: mesh.positions,
331 normals: mesh.normals,
332 indices: mesh.indices,
333 face_ids: mesh.face_ids,
334 })
335 })
336}
337
338#[wasm_bindgen]
340pub fn mass_properties_handle(handle: u32) -> Result<String, JsValue> {
341 with_registered_solid(handle, |solid| {
342 let _caller = crate::mass_caller("abi.mass_properties");
343 let properties = solid_mass_properties(solid).map_err(javascript_error)?;
344 serde_json::to_string(&properties).map_err(|error| javascript_error(error.to_string()))
345 })
346}
347
348#[wasm_bindgen]
352pub fn transform_handle(
353 handle: u32,
354 matrix: &[f64],
355 reverse_orientation: bool,
356) -> Result<u32, JsValue> {
357 let matrix: [f64; 16] = matrix
358 .try_into()
359 .map_err(|_| javascript_error("transform matrix must contain 16 values".into()))?;
360 let transform = AffineTransform::new(matrix).map_err(javascript_error)?;
361 let result = with_registered_solid(handle, |solid| {
362 transform_brep(solid, transform, reverse_orientation).map_err(javascript_error)
363 })?;
364 Ok(register_solid_value(result))
365}
366
367#[wasm_bindgen]
370pub fn face_names_handle(handle: u32) -> Result<String, JsValue> {
371 with_registered_solid(handle, |solid| {
372 let mut map: Vec<(u64, Option<String>)> = Vec::new();
373 for shell in &solid.shells {
374 for face in &shell.faces {
375 map.push((face.id, face.name.clone()));
376 }
377 }
378 serde_json::to_string(&map).map_err(|error| javascript_error(error.to_string()))
379 })
380}
381
382pub fn boolean_handle_native(
394 a: u32,
395 b: u32,
396 operation: BooleanOperation,
397 options: &BooleanOptions,
398) -> Result<u32, String> {
399 let result =
400 with_two_registered_solids(a, b, |sa, sb| boolean_operation(sa, sb, operation, options))?;
401 Ok(register_solid_value(result))
402}