brep_kernel/abi/
handles.rs1use 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_str<T>(
143 handle: u32,
144 f: impl FnOnce(&BrepSolid) -> Result<T, String>,
145) -> Result<T, String> {
146 SOLID_REGISTRY.with(|registry| {
147 let registry = registry.borrow();
148 let solid = registry
149 .solids
150 .get(&handle)
151 .ok_or_else(|| format!("unknown solid handle {handle}"))?;
152 f(solid)
153 })
154}
155
156pub(crate) fn with_two_registered_solids<T>(
161 a: u32,
162 b: u32,
163 f: impl FnOnce(&BrepSolid, &BrepSolid) -> Result<T, String>,
164) -> Result<T, String> {
165 SOLID_REGISTRY.with(|registry| {
166 let registry = registry.borrow();
167 let sa = registry
168 .solids
169 .get(&a)
170 .ok_or_else(|| format!("unknown solid handle {a}"))?;
171 let sb = registry
172 .solids
173 .get(&b)
174 .ok_or_else(|| format!("unknown solid handle {b}"))?;
175 f(sa, sb)
176 })
177}
178
179pub(crate) fn free_registered_solid(handle: u32) {
183 SOLID_REGISTRY.with(|registry| {
184 registry.borrow_mut().solids.remove(&handle);
185 });
186}
187
188#[wasm_bindgen]
191pub fn register_solid_buffer(data: &[f64], names_json: &str) -> Result<u32, JsValue> {
192 let names: SolidNames = if names_json.trim().is_empty() {
193 SolidNames::default()
194 } else {
195 serde_json::from_str(names_json).map_err(|error| javascript_error(error.to_string()))?
196 };
197 let solid = decode_solid(data, &names).map_err(javascript_error)?;
198 let solid = TopologyArena::from_brep(&solid)
199 .and_then(|arena| arena.to_brep())
200 .map_err(javascript_error)?;
201 let issues = solid.validate();
202 if !issues.is_empty() {
203 return Err(javascript_error(format!(
204 "register_solid_buffer: invalid topology: {issues:?}"
205 )));
206 }
207 Ok(register_solid_value(solid))
208}
209
210#[wasm_bindgen]
212pub fn register_solid_json(solid_json: &str) -> Result<u32, JsValue> {
213 let solid: BrepSolid =
214 serde_json::from_str(solid_json).map_err(|error| javascript_error(error.to_string()))?;
215 let solid = TopologyArena::from_brep(&solid)
216 .and_then(|arena| arena.to_brep())
217 .map_err(javascript_error)?;
218 let issues = solid.validate();
219 if !issues.is_empty() {
220 return Err(javascript_error(format!(
221 "register_solid_json: invalid topology: {issues:?}"
222 )));
223 }
224 Ok(register_solid_value(solid))
225}
226
227#[wasm_bindgen]
229pub fn free_solid(handle: u32) {
230 SOLID_REGISTRY.with(|registry| {
231 registry.borrow_mut().solids.remove(&handle);
232 });
233}
234
235#[wasm_bindgen]
237pub fn registered_solid_count() -> usize {
238 SOLID_REGISTRY.with(|registry| registry.borrow().solids.len())
239}
240
241#[wasm_bindgen]
245pub fn boolean_handle(
246 a: u32,
247 b: u32,
248 operation: &str,
249 tolerance: f64,
250 merge_coplanar_faces: bool,
251) -> Result<u32, JsValue> {
252 let operation = match operation {
253 "union" => BooleanOperation::Union,
254 "intersect" => BooleanOperation::Intersect,
255 "subtract" => BooleanOperation::Subtract,
256 _ => return Err(javascript_error("unknown boolean operation".into())),
257 };
258 let result = SOLID_REGISTRY.with(|registry| {
259 let registry = registry.borrow();
260 let sa = registry
261 .solids
262 .get(&a)
263 .ok_or_else(|| javascript_error(format!("unknown solid handle {a}")))?;
264 let sb = registry
265 .solids
266 .get(&b)
267 .ok_or_else(|| javascript_error(format!("unknown solid handle {b}")))?;
268 boolean_operation(
269 sa,
270 sb,
271 operation,
272 &BooleanOptions {
273 tolerance,
274 merge_coplanar_faces,
275 ..BooleanOptions::default()
276 },
277 )
278 .map_err(javascript_error)
279 })?;
280 Ok(register_solid_value(result))
281}
282
283#[wasm_bindgen]
286pub fn tessellate_handle(handle: u32, chord_tolerance: f64) -> Result<WasmMeshBuffers, JsValue> {
287 with_registered_solid(handle, |solid| {
288 let mesh = tessellate_brep_watertight(solid, chord_tolerance).map_err(javascript_error)?;
289 Ok(WasmMeshBuffers {
290 positions: mesh.positions,
291 normals: mesh.normals,
292 indices: mesh.indices,
293 face_ids: mesh.face_ids,
294 })
295 })
296}
297
298#[wasm_bindgen]
300pub fn mass_properties_handle(handle: u32) -> Result<String, JsValue> {
301 with_registered_solid(handle, |solid| {
302 let properties = solid_mass_properties(solid).map_err(javascript_error)?;
303 serde_json::to_string(&properties).map_err(|error| javascript_error(error.to_string()))
304 })
305}
306
307#[wasm_bindgen]
311pub fn transform_handle(
312 handle: u32,
313 matrix: &[f64],
314 reverse_orientation: bool,
315) -> Result<u32, JsValue> {
316 let matrix: [f64; 16] = matrix
317 .try_into()
318 .map_err(|_| javascript_error("transform matrix must contain 16 values".into()))?;
319 let transform = AffineTransform::new(matrix).map_err(javascript_error)?;
320 let result = with_registered_solid(handle, |solid| {
321 transform_brep(solid, transform, reverse_orientation).map_err(javascript_error)
322 })?;
323 Ok(register_solid_value(result))
324}
325
326#[wasm_bindgen]
329pub fn face_names_handle(handle: u32) -> Result<String, JsValue> {
330 with_registered_solid(handle, |solid| {
331 let mut map: Vec<(u64, Option<String>)> = Vec::new();
332 for shell in &solid.shells {
333 for face in &shell.faces {
334 map.push((face.id, face.name.clone()));
335 }
336 }
337 serde_json::to_string(&map).map_err(|error| javascript_error(error.to_string()))
338 })
339}
340
341