use super::*;
#[wasm_bindgen]
pub struct WasmNurbsCurve {
pub(crate) curve: NurbsCurve,
}
#[wasm_bindgen]
pub struct WasmNurbsSurface {
pub(crate) surface: NurbsSurface,
}
#[wasm_bindgen]
pub struct WasmSolidBuffer {
pub(crate) data: Vec<f64>,
pub(crate) names_json: String,
pub(crate) metadata_json: String,
}
#[wasm_bindgen]
impl WasmSolidBuffer {
pub fn take_data(&mut self) -> Vec<f64> {
std::mem::take(&mut self.data)
}
pub fn names_json(&self) -> String {
self.names_json.clone()
}
pub fn metadata_json(&self) -> String {
self.metadata_json.clone()
}
}
pub(crate) fn solid_buffer(solid: &BrepSolid, metadata_json: String) -> Result<WasmSolidBuffer, JsValue> {
let (data, names) = encode_solid(solid).map_err(javascript_error)?;
Ok(WasmSolidBuffer {
data,
names_json: serde_json::to_string(&names)
.map_err(|error| javascript_error(error.to_string()))?,
metadata_json,
})
}
#[wasm_bindgen]
pub struct WasmMeshBuffers {
pub(crate) positions: Vec<f64>,
pub(crate) normals: Vec<f64>,
pub(crate) indices: Vec<u32>,
pub(crate) face_ids: Vec<u32>,
}
#[wasm_bindgen]
impl WasmMeshBuffers {
pub fn take_positions(&mut self) -> Vec<f64> {
std::mem::take(&mut self.positions)
}
pub fn take_normals(&mut self) -> Vec<f64> {
std::mem::take(&mut self.normals)
}
pub fn take_indices(&mut self) -> Vec<u32> {
std::mem::take(&mut self.indices)
}
pub fn take_face_ids(&mut self) -> Vec<u32> {
std::mem::take(&mut self.face_ids)
}
}
thread_local! {
static SOLID_REGISTRY: std::cell::RefCell<SolidRegistry> =
std::cell::RefCell::new(SolidRegistry::new());
}
pub(crate) struct SolidRegistry {
pub(crate) next: u32,
pub(crate) solids: std::collections::HashMap<u32, BrepSolid>,
}
impl SolidRegistry {
fn new() -> Self {
Self {
next: 1,
solids: std::collections::HashMap::new(),
}
}
fn insert(&mut self, solid: BrepSolid) -> u32 {
let handle = self.next;
self.next = self.next.wrapping_add(1).max(1);
self.solids.insert(handle, solid);
handle
}
}
pub(crate) fn register_solid_value(solid: BrepSolid) -> u32 {
SOLID_REGISTRY.with(|registry| registry.borrow_mut().insert(solid))
}
pub(crate) fn with_registered_solid<T>(
handle: u32,
f: impl FnOnce(&BrepSolid) -> Result<T, JsValue>,
) -> Result<T, JsValue> {
SOLID_REGISTRY.with(|registry| {
let registry = registry.borrow();
let solid = registry
.solids
.get(&handle)
.ok_or_else(|| javascript_error(format!("unknown solid handle {handle}")))?;
f(solid)
})
}
pub(crate) fn with_registered_solid_str<T>(
handle: u32,
f: impl FnOnce(&BrepSolid) -> Result<T, String>,
) -> Result<T, String> {
SOLID_REGISTRY.with(|registry| {
let registry = registry.borrow();
let solid = registry
.solids
.get(&handle)
.ok_or_else(|| format!("unknown solid handle {handle}"))?;
f(solid)
})
}
pub(crate) fn with_two_registered_solids<T, E: From<crate::KernelRefusal>>(
a: u32,
b: u32,
f: impl FnOnce(&BrepSolid, &BrepSolid) -> Result<T, E>,
) -> Result<T, E> {
SOLID_REGISTRY.with(|registry| {
let registry = registry.borrow();
let handle = |id: u32| -> Result<&BrepSolid, E> {
registry.solids.get(&id).ok_or_else(|| {
crate::KernelRefusal::input(
crate::KernelStage::Collect,
"solid_handle",
format!("unknown solid handle {id}"),
)
.into()
})
};
let sa = handle(a)?;
let sb = handle(b)?;
f(sa, sb)
})
}
pub(crate) fn replace_registered_solid(handle: u32, solid: BrepSolid) -> Result<(), String> {
SOLID_REGISTRY.with(|registry| {
let mut registry = registry.borrow_mut();
match registry.solids.get_mut(&handle) {
Some(slot) => {
*slot = solid;
Ok(())
}
None => Err(format!("unknown solid handle {handle}")),
}
})
}
pub(crate) fn free_registered_solid(handle: u32) {
SOLID_REGISTRY.with(|registry| {
registry.borrow_mut().solids.remove(&handle);
});
}
#[wasm_bindgen]
pub fn register_solid_buffer(data: &[f64], names_json: &str) -> Result<u32, JsValue> {
let solid = decode_solid_buffer(data, names_json)?;
let solid = validate_imported_solid(solid, "register_solid_buffer")?;
Ok(register_solid_value(solid))
}
#[wasm_bindgen]
pub fn register_solid_json(solid_json: &str) -> Result<u32, JsValue> {
let solid: BrepSolid =
serde_json::from_str(solid_json).map_err(|error| javascript_error(error.to_string()))?;
let solid = validate_imported_solid(solid, "register_solid_json")?;
Ok(register_solid_value(solid))
}
#[wasm_bindgen]
pub fn free_solid(handle: u32) {
SOLID_REGISTRY.with(|registry| {
registry.borrow_mut().solids.remove(&handle);
});
}
pub fn registered_solid_clone(handle: u32) -> Result<BrepSolid, String> {
with_registered_solid_str(handle, |solid| Ok(solid.clone()))
}
#[wasm_bindgen]
pub fn registered_solid_count() -> usize {
SOLID_REGISTRY.with(|registry| registry.borrow().solids.len())
}
#[wasm_bindgen]
pub fn boolean_handle(
a: u32,
b: u32,
operation: &str,
tolerance: f64,
merge_coplanar_faces: bool,
) -> Result<u32, JsValue> {
let operation = match operation {
"union" => BooleanOperation::Union,
"intersect" => BooleanOperation::Intersect,
"subtract" => BooleanOperation::Subtract,
_ => return Err(javascript_error("unknown boolean operation".into())),
};
let result = SOLID_REGISTRY.with(|registry| {
let registry = registry.borrow();
let sa = registry
.solids
.get(&a)
.ok_or_else(|| javascript_error(format!("unknown solid handle {a}")))?;
let sb = registry
.solids
.get(&b)
.ok_or_else(|| javascript_error(format!("unknown solid handle {b}")))?;
boolean_operation(
sa,
sb,
operation,
&BooleanOptions {
tolerance,
merge_coplanar_faces,
..BooleanOptions::default()
},
)
.map_err(crate::abi::geometry::javascript_refusal)
})?;
Ok(register_solid_value(result))
}
#[wasm_bindgen]
pub fn tessellate_handle(handle: u32, chord_tolerance: f64) -> Result<WasmMeshBuffers, JsValue> {
with_registered_solid(handle, |solid| {
let mesh = tessellate_brep_watertight(solid, chord_tolerance).map_err(javascript_error)?;
Ok(WasmMeshBuffers {
positions: mesh.positions,
normals: mesh.normals,
indices: mesh.indices,
face_ids: mesh.face_ids,
})
})
}
#[wasm_bindgen]
pub fn mass_properties_handle(handle: u32) -> Result<String, JsValue> {
with_registered_solid(handle, |solid| {
let properties = solid_mass_properties(solid).map_err(javascript_error)?;
serde_json::to_string(&properties).map_err(|error| javascript_error(error.to_string()))
})
}
#[wasm_bindgen]
pub fn transform_handle(
handle: u32,
matrix: &[f64],
reverse_orientation: bool,
) -> Result<u32, JsValue> {
let matrix: [f64; 16] = matrix
.try_into()
.map_err(|_| javascript_error("transform matrix must contain 16 values".into()))?;
let transform = AffineTransform::new(matrix).map_err(javascript_error)?;
let result = with_registered_solid(handle, |solid| {
transform_brep(solid, transform, reverse_orientation).map_err(javascript_error)
})?;
Ok(register_solid_value(result))
}
#[wasm_bindgen]
pub fn face_names_handle(handle: u32) -> Result<String, JsValue> {
with_registered_solid(handle, |solid| {
let mut map: Vec<(u64, Option<String>)> = Vec::new();
for shell in &solid.shells {
for face in &shell.faces {
map.push((face.id, face.name.clone()));
}
}
serde_json::to_string(&map).map_err(|error| javascript_error(error.to_string()))
})
}
pub fn boolean_handle_native(
a: u32,
b: u32,
operation: BooleanOperation,
options: &BooleanOptions,
) -> Result<u32, String> {
let result =
with_two_registered_solids(a, b, |sa, sb| boolean_operation(sa, sb, operation, options))?;
Ok(register_solid_value(result))
}