Skip to main content

brep_kernel/abi/
modeling_b.rs

1use super::*;
2
3#[derive(Deserialize)]
4pub(crate) struct TangentLoftRequest {
5    pub(crate) sections: Vec<Vec<NurbsCurve>>,
6    pub(crate) start_direction: Vec3,
7    pub(crate) end_direction: Vec3,
8}
9
10#[wasm_bindgen]
11pub fn loft_profile_brep_closed_json(request_json: &str) -> Result<String, JsValue> {
12    let request: LoftBrepRequest =
13        serde_json::from_str(request_json).map_err(|error| javascript_error(error.to_string()))?;
14    let solid = loft_profile_brep_closed(&request.sections).map_err(javascript_error)?;
15    serde_json::to_string(&solid).map_err(|error| javascript_error(error.to_string()))
16}
17
18#[wasm_bindgen]
19pub fn loft_profile_brep_closed_buffer(request_json: &str) -> Result<WasmSolidBuffer, JsValue> {
20    let request: LoftBrepRequest =
21        serde_json::from_str(request_json).map_err(|error| javascript_error(error.to_string()))?;
22    let solid = loft_profile_brep_closed(&request.sections).map_err(javascript_error)?;
23    solid_buffer(&solid, "{}".into())
24}
25
26#[wasm_bindgen]
27pub fn loft_profile_brep_tangent_json(request_json: &str) -> Result<String, JsValue> {
28    let request: TangentLoftRequest =
29        serde_json::from_str(request_json).map_err(|error| javascript_error(error.to_string()))?;
30    let solid = loft_profile_brep_tangent(
31        &request.sections,
32        request.start_direction,
33        request.end_direction,
34    )
35    .map_err(javascript_error)?;
36    serde_json::to_string(&solid).map_err(|error| javascript_error(error.to_string()))
37}
38
39#[wasm_bindgen]
40pub fn loft_profile_brep_tangent_buffer(request_json: &str) -> Result<WasmSolidBuffer, JsValue> {
41    let request: TangentLoftRequest =
42        serde_json::from_str(request_json).map_err(|error| javascript_error(error.to_string()))?;
43    let solid = loft_profile_brep_tangent(
44        &request.sections,
45        request.start_direction,
46        request.end_direction,
47    )
48    .map_err(javascript_error)?;
49    solid_buffer(&solid, "{}".into())
50}
51
52#[wasm_bindgen]
53pub fn loft_profile_brep_guided_buffer(request_json: &str) -> Result<WasmSolidBuffer, JsValue> {
54    let request: GuidedLoftRequest =
55        serde_json::from_str(request_json).map_err(|error| javascript_error(error.to_string()))?;
56    let solid = guided_loft_dispatch(&request).map_err(javascript_error)?;
57    solid_buffer(&solid, "{}".into())
58}
59
60#[wasm_bindgen]
61pub fn sweep_profile_along_path_json(request_json: &str) -> Result<String, JsValue> {
62    let request: SweepRequest =
63        serde_json::from_str(request_json).map_err(|error| javascript_error(error.to_string()))?;
64    let solid = sweep_profile_along_path(&request.profile, &request.path, request.name.as_deref())
65        .map_err(javascript_error)?;
66    serde_json::to_string(&solid).map_err(|error| javascript_error(error.to_string()))
67}
68
69#[wasm_bindgen]
70pub fn sweep_profile_along_path_buffer(request_json: &str) -> Result<WasmSolidBuffer, JsValue> {
71    let request: SweepRequest =
72        serde_json::from_str(request_json).map_err(|error| javascript_error(error.to_string()))?;
73    let solid = sweep_profile_along_path(&request.profile, &request.path, request.name.as_deref())
74        .map_err(javascript_error)?;
75    solid_buffer(&solid, "{}".into())
76}
77
78#[derive(Deserialize)]
79pub(crate) struct TwistedSweepRequest {
80    pub(crate) profile: Vec<NurbsCurve>,
81    pub(crate) path: NurbsCurve,
82    /// Total twist about the path tangent, radians, linear in arc length.
83    pub(crate) twist_angle: f64,
84    #[serde(default)]
85    pub(crate) name: Option<String>,
86}
87
88#[wasm_bindgen]
89pub fn sweep_profile_twisted_json(request_json: &str) -> Result<String, JsValue> {
90    let request: TwistedSweepRequest =
91        serde_json::from_str(request_json).map_err(|error| javascript_error(error.to_string()))?;
92    let solid = sweep_profile_twisted(
93        &request.profile,
94        &request.path,
95        request.twist_angle,
96        request.name.as_deref(),
97    )
98    .map_err(javascript_error)?;
99    serde_json::to_string(&solid).map_err(|error| javascript_error(error.to_string()))
100}
101
102#[wasm_bindgen]
103pub fn sweep_profile_twisted_buffer(request_json: &str) -> Result<WasmSolidBuffer, JsValue> {
104    let request: TwistedSweepRequest =
105        serde_json::from_str(request_json).map_err(|error| javascript_error(error.to_string()))?;
106    let solid = sweep_profile_twisted(
107        &request.profile,
108        &request.path,
109        request.twist_angle,
110        request.name.as_deref(),
111    )
112    .map_err(javascript_error)?;
113    solid_buffer(&solid, "{}".into())
114}
115
116#[wasm_bindgen]
117pub fn sweep_profile_helix_json(request_json: &str) -> Result<String, JsValue> {
118    let request: HelixSweepRequest =
119        serde_json::from_str(request_json).map_err(|error| javascript_error(error.to_string()))?;
120    let solid = sweep_profile_helix(
121        &request.profile,
122        request.axis_origin,
123        request.axis_direction,
124        request.helix_radius,
125        request.pitch,
126        request.turns,
127        request.name.as_deref(),
128    )
129    .map_err(javascript_error)?;
130    serde_json::to_string(&solid).map_err(|error| javascript_error(error.to_string()))
131}
132
133#[wasm_bindgen]
134pub fn sweep_profile_helix_buffer(request_json: &str) -> Result<WasmSolidBuffer, JsValue> {
135    let request: HelixSweepRequest =
136        serde_json::from_str(request_json).map_err(|error| javascript_error(error.to_string()))?;
137    let solid = sweep_profile_helix(
138        &request.profile,
139        request.axis_origin,
140        request.axis_direction,
141        request.helix_radius,
142        request.pitch,
143        request.turns,
144        request.name.as_deref(),
145    )
146    .map_err(javascript_error)?;
147    solid_buffer(&solid, "{}".into())
148}
149
150#[wasm_bindgen]
151pub fn transform_brep_json(request_json: &str) -> Result<String, JsValue> {
152    let request: TransformBrepRequest =
153        serde_json::from_str(request_json).map_err(|error| javascript_error(error.to_string()))?;
154    let transform = AffineTransform::new(request.matrix).map_err(javascript_error)?;
155    let solid = transform_brep(&request.solid, transform, request.reverse_orientation)
156        .map_err(javascript_error)?;
157    serde_json::to_string(&solid).map_err(|error| javascript_error(error.to_string()))
158}
159
160#[wasm_bindgen]
161pub fn mirror_brep_json(request_json: &str) -> Result<String, JsValue> {
162    let request: MirrorBrepRequest =
163        serde_json::from_str(request_json).map_err(|error| javascript_error(error.to_string()))?;
164    let solid = mirror_brep(&request.solid, request.plane_point, request.plane_normal)
165        .map_err(javascript_error)?;
166    serde_json::to_string(&solid).map_err(|error| javascript_error(error.to_string()))
167}
168
169#[wasm_bindgen]
170pub fn mirror_brep_buffer(request_json: &str) -> Result<WasmSolidBuffer, JsValue> {
171    let request: MirrorBrepRequest =
172        serde_json::from_str(request_json).map_err(|error| javascript_error(error.to_string()))?;
173    let solid = mirror_brep(&request.solid, request.plane_point, request.plane_normal)
174        .map_err(javascript_error)?;
175    solid_buffer(&solid, "{}".into())
176}
177
178/// Cut a solid by a plane (Golovanov §6.4). Returns `{ "below": <solid>,
179/// "above": <solid> }` — the −n and +n pieces of the split. Errors with
180/// "plane does not intersect the solid" when the plane misses the body.
181#[wasm_bindgen]
182pub fn split_solid_by_plane_json(request_json: &str) -> Result<String, JsValue> {
183    let request: SplitByPlaneRequest =
184        serde_json::from_str(request_json).map_err(|error| javascript_error(error.to_string()))?;
185    let (below, above) =
186        split_solid_by_plane(&request.solid, request.plane_point, request.plane_normal)
187            .map_err(javascript_error)?;
188    let result = serde_json::json!({ "below": below, "above": above });
189    serde_json::to_string(&result).map_err(|error| javascript_error(error.to_string()))
190}
191
192/// Cut a solid by an analytic tool surface (Golovanov §6.4). The request is
193/// `{ "solid": <solid>, "tool": { "type": "cylinder"|"sphere"|"cone"|"torus"|
194/// "plane", ... } }`. Returns `{ "pieces": [<inside>, <outside>] }` (for a
195/// plane, `[below, above]`). Errors with "tool surface does not divide the
196/// solid" when the tool does not cleanly cut the body.
197#[wasm_bindgen]
198pub fn split_solid_by_surface_json(request_json: &str) -> Result<String, JsValue> {
199    let request: SplitBySurfaceRequest =
200        serde_json::from_str(request_json).map_err(|error| javascript_error(error.to_string()))?;
201    let pieces = split_solid_by_surface(&request.solid, &request.tool).map_err(javascript_error)?;
202    let result = serde_json::json!({ "pieces": pieces });
203    serde_json::to_string(&result).map_err(|error| javascript_error(error.to_string()))
204}
205
206/// Cut a solid by the analytic carrier of a selected face's `surface` (Golovanov
207/// §6.4). The face may be a plane, cylinder, cone, or sphere; the kernel
208/// recognizes its analytic type and extends it to span the body. Returns
209/// `{ "pieces": [<below/inside>, <above/outside>] }`. Errors on non-analytic
210/// faces or when the carrier does not cleanly divide the body.
211#[wasm_bindgen]
212pub fn split_solid_by_face_surface_json(request_json: &str) -> Result<String, JsValue> {
213    let request: SplitByFaceSurfaceRequest =
214        serde_json::from_str(request_json).map_err(|error| javascript_error(error.to_string()))?;
215    let pieces =
216        split_solid_by_face_surface(&request.solid, &request.surface).map_err(javascript_error)?;
217    let result = serde_json::json!({ "pieces": pieces });
218    serde_json::to_string(&result).map_err(|error| javascript_error(error.to_string()))
219}
220
221#[wasm_bindgen]
222pub fn solid_mass_properties_json(solid_json: &str) -> Result<String, JsValue> {
223    let solid: BrepSolid =
224        serde_json::from_str(solid_json).map_err(|error| javascript_error(error.to_string()))?;
225    let properties = solid_mass_properties(&solid).map_err(javascript_error)?;
226    serde_json::to_string(&properties).map_err(|error| javascript_error(error.to_string()))
227}
228
229#[wasm_bindgen]
230pub fn solid_mass_properties_full_json(solid_json: &str) -> Result<String, JsValue> {
231    let solid: BrepSolid =
232        serde_json::from_str(solid_json).map_err(|error| javascript_error(error.to_string()))?;
233    let properties = solid_mass_properties_full(&solid).map_err(javascript_error)?;
234    serde_json::to_string(&properties).map_err(|error| javascript_error(error.to_string()))
235}
236
237#[wasm_bindgen]
238pub fn face_metrics_json(face_json: &str) -> Result<String, JsValue> {
239    let face: FaceRecord =
240        serde_json::from_str(face_json).map_err(|error| javascript_error(error.to_string()))?;
241    let metrics = FaceMetrics {
242        parameter_space_area: parameter_space_area(&face).map_err(javascript_error)?,
243        area: face_area(&face).map_err(javascript_error)?,
244        volume_contribution: face_volume_contribution(&face).map_err(javascript_error)?,
245        trim_polygons: trim_polygons(&face).map_err(javascript_error)?,
246    };
247    serde_json::to_string(&metrics).map_err(|error| javascript_error(error.to_string()))
248}
249
250#[wasm_bindgen]
251pub fn tessellate_face_json(request_json: &str) -> Result<String, JsValue> {
252    let request: TessellateFaceRequest =
253        serde_json::from_str(request_json).map_err(|error| javascript_error(error.to_string()))?;
254    let mesh = tessellate_face(
255        &request.face,
256        TessellationOptions {
257            slabs_per_span_u: request.slabs_per_span_u,
258            steps_per_span_v: request.steps_per_span_v,
259        },
260        request.face.id as u32,
261    )
262    .map_err(javascript_error)?;
263    serde_json::to_string(&mesh).map_err(|error| javascript_error(error.to_string()))
264}
265
266#[wasm_bindgen]
267pub fn tessellate_brep_json(request_json: &str) -> Result<String, JsValue> {
268    let request: TessellateBrepRequest =
269        serde_json::from_str(request_json).map_err(|error| javascript_error(error.to_string()))?;
270    let mesh = tessellate_brep(
271        &request.solid,
272        TessellationOptions {
273            slabs_per_span_u: request.slabs_per_span_u,
274            steps_per_span_v: request.steps_per_span_v,
275        },
276    )
277    .map_err(javascript_error)?;
278    serde_json::to_string(&mesh).map_err(|error| javascript_error(error.to_string()))
279}
280
281#[wasm_bindgen]
282pub fn classify_points_json(request_json: &str) -> Result<String, JsValue> {
283    let request: ClassifyPointsRequest =
284        serde_json::from_str(request_json).map_err(|error| javascript_error(error.to_string()))?;
285    let classifications = request
286        .points
287        .into_iter()
288        .map(|point| classify_point(point, &request.solid, request.tolerance))
289        .collect::<Result<Vec<_>, _>>()
290        .map_err(javascript_error)?;
291    serde_json::to_string(&classifications).map_err(|error| javascript_error(error.to_string()))
292}
293
294#[wasm_bindgen]
295pub fn arrange_segments_json(request_json: &str) -> Result<String, JsValue> {
296    let request: ArrangeSegmentsRequest =
297        serde_json::from_str(request_json).map_err(|error| javascript_error(error.to_string()))?;
298    let regions =
299        arrange_segments(&request.segments, request.tolerance).map_err(javascript_error)?;
300    serde_json::to_string(&regions).map_err(|error| javascript_error(error.to_string()))
301}
302
303#[wasm_bindgen]
304pub fn build_pcurve_json(request_json: &str) -> Result<String, JsValue> {
305    let request: BuildPcurveRequest =
306        serde_json::from_str(request_json).map_err(|error| javascript_error(error.to_string()))?;
307    let pcurve =
308        build_pcurve_on_surface(&request.surface, &request.curve).map_err(javascript_error)?;
309    serde_json::to_string(&pcurve).map_err(|error| javascript_error(error.to_string()))
310}
311
312#[wasm_bindgen]
313pub fn build_imprints_json(request_json: &str) -> Result<String, JsValue> {
314    let request: BuildImprintsRequest =
315        serde_json::from_str(request_json).map_err(|error| javascript_error(error.to_string()))?;
316    let result = build_imprints(&request.solid_a, &request.solid_b, &request.options)
317        .map_err(javascript_error)?;
318    serde_json::to_string(&result).map_err(|error| javascript_error(error.to_string()))
319}
320
321#[wasm_bindgen]
322pub fn apply_edge_splits_json(request_json: &str) -> Result<String, JsValue> {
323    let request: ApplyEdgeSplitsRequest =
324        serde_json::from_str(request_json).map_err(|error| javascript_error(error.to_string()))?;
325    let result = apply_edge_splits(&request.solid, request.operand, &request.imprint)
326        .map_err(javascript_error)?;
327    serde_json::to_string(&result).map_err(|error| javascript_error(error.to_string()))
328}
329
330#[wasm_bindgen]
331pub fn fragment_faces_json(request_json: &str) -> Result<String, JsValue> {
332    let request: FragmentFacesRequest =
333        serde_json::from_str(request_json).map_err(|error| javascript_error(error.to_string()))?;
334    let result = fragment_solid(&request.solid, request.operand, &request.imprint)
335        .map_err(javascript_error)?;
336    serde_json::to_string(&result).map_err(|error| javascript_error(error.to_string()))
337}
338
339#[wasm_bindgen]
340pub fn boolean_brep_json(request_json: &str) -> Result<String, JsValue> {
341    let request: BooleanRequest =
342        serde_json::from_str(request_json).map_err(|error| javascript_error(error.to_string()))?;
343    let result = boolean_operation(
344        &request.first,
345        &request.second,
346        request.operation,
347        &request.options,
348    )
349    .map_err(javascript_error)?;
350    serde_json::to_string(&result).map_err(|error| javascript_error(error.to_string()))
351}
352
353#[wasm_bindgen]
354pub fn boolean_brep_diagnostics_json(request_json: &str) -> Result<String, JsValue> {
355    let request: BooleanRequest =
356        serde_json::from_str(request_json).map_err(|error| javascript_error(error.to_string()))?;
357    let result = boolean_operation_with_diagnostics(
358        &request.first,
359        &request.second,
360        request.operation,
361        &request.options,
362    )
363    .map_err(javascript_error)?;
364    serde_json::to_string(&result).map_err(|error| javascript_error(error.to_string()))
365}
366
367#[wasm_bindgen]
368pub fn offset_surface_json(request_json: &str) -> Result<String, JsValue> {
369    let request: OffsetSurfaceRequest =
370        serde_json::from_str(request_json).map_err(|error| javascript_error(error.to_string()))?;
371    let surface = offset_surface(&request.face, request.distance, request.planar_extension)
372        .map_err(javascript_error)?;
373    serde_json::to_string(&surface).map_err(|error| javascript_error(error.to_string()))
374}
375
376#[derive(Deserialize)]
377pub(crate) struct SolveAssemblyRequest {
378    pub(crate) bodies: Vec<AssemblyBody>,
379    pub(crate) mates: Vec<AssemblyMate>,
380    #[serde(default)]
381    pub(crate) options: AssemblySolveOptions,
382}
383
384#[wasm_bindgen]
385pub fn solve_assembly_json(request_json: &str) -> Result<String, JsValue> {
386    let request: SolveAssemblyRequest =
387        serde_json::from_str(request_json).map_err(|error| javascript_error(error.to_string()))?;
388    let solution = solve_assembly(&request.bodies, &request.mates, &request.options)
389        .map_err(javascript_error)?;
390    serde_json::to_string(&solution).map_err(|error| javascript_error(error.to_string()))
391}
392
393#[derive(Deserialize)]
394pub(crate) struct SegmentMeshRequest {
395    /// Flat xyz triples.
396    pub(crate) positions: Vec<f64>,
397    /// Triangle indices; empty = raw soup (STL-style, 3 positions/triangle).
398    #[serde(default)]
399    pub(crate) indices: Vec<u32>,
400    #[serde(default)]
401    pub(crate) options: SegmentOptions,
402}
403
404#[wasm_bindgen]
405pub fn segment_mesh_faces_json(request_json: &str) -> Result<String, JsValue> {
406    let request: SegmentMeshRequest =
407        serde_json::from_str(request_json).map_err(|error| javascript_error(error.to_string()))?;
408    let segmentation = segment_mesh_faces(&request.positions, &request.indices, &request.options)
409        .map_err(javascript_error)?;
410    serde_json::to_string(&segmentation).map_err(|error| javascript_error(error.to_string()))
411}
412
413#[wasm_bindgen]
414pub fn mesh_regions_to_brep_json(request_json: &str) -> Result<String, JsValue> {
415    let request: SegmentMeshRequest =
416        serde_json::from_str(request_json).map_err(|error| javascript_error(error.to_string()))?;
417    let solid = mesh_regions_to_brep(&request.positions, &request.indices, &request.options)
418        .map_err(javascript_error)?;
419    serde_json::to_string(&solid).map_err(|error| javascript_error(error.to_string()))
420}
421
422#[wasm_bindgen]
423pub fn mesh_regions_to_brep_buffer(request_json: &str) -> Result<WasmSolidBuffer, JsValue> {
424    let request: SegmentMeshRequest =
425        serde_json::from_str(request_json).map_err(|error| javascript_error(error.to_string()))?;
426    let solid = mesh_regions_to_brep(&request.positions, &request.indices, &request.options)
427        .map_err(javascript_error)?;
428    solid_buffer(&solid, "{}".into())
429}
430
431#[derive(Deserialize)]
432pub(crate) struct ThickenSheetRequest {
433    /// The sheet as an untrimmed surface patch over its full domain.
434    pub(crate) surface: NurbsSurface,
435    /// Signed thickness (positive = along the sheet normal Su×Sv).
436    pub(crate) thickness: f64,
437    /// Split the thickness half per side (sheet becomes the mid-surface).
438    #[serde(default)]
439    pub(crate) symmetric: bool,
440}
441
442#[wasm_bindgen]
443pub fn thicken_face_sheet_json(request_json: &str) -> Result<String, JsValue> {
444    let request: ThickenSheetRequest =
445        serde_json::from_str(request_json).map_err(|error| javascript_error(error.to_string()))?;
446    let solid = thicken_face_sheet(&request.surface, request.thickness, request.symmetric)
447        .map_err(javascript_error)?;
448    serde_json::to_string(&solid).map_err(|error| javascript_error(error.to_string()))
449}
450
451#[wasm_bindgen]
452pub fn thicken_face_sheet_buffer(request_json: &str) -> Result<WasmSolidBuffer, JsValue> {
453    let request: ThickenSheetRequest =
454        serde_json::from_str(request_json).map_err(|error| javascript_error(error.to_string()))?;
455    let solid = thicken_face_sheet(&request.surface, request.thickness, request.symmetric)
456        .map_err(javascript_error)?;
457    solid_buffer(&solid, "{}".into())
458}
459
460#[derive(Deserialize)]
461pub(crate) struct ThickenTrimmedSheetRequest {
462    pub(crate) surface: NurbsSurface,
463    /// Pcurve trim loops on the sheet: outer loop first (counter-clockwise),
464    /// optional holes (clockwise).
465    pub(crate) loops: Vec<Vec<NurbsCurve>>,
466    pub(crate) thickness: f64,
467    #[serde(default)]
468    pub(crate) symmetric: bool,
469}
470
471#[wasm_bindgen]
472pub fn thicken_trimmed_sheet_json(request_json: &str) -> Result<String, JsValue> {
473    let request: ThickenTrimmedSheetRequest =
474        serde_json::from_str(request_json).map_err(|error| javascript_error(error.to_string()))?;
475    let solid = thicken_trimmed_sheet(
476        &request.surface,
477        &request.loops,
478        request.thickness,
479        request.symmetric,
480    )
481    .map_err(javascript_error)?;
482    serde_json::to_string(&solid).map_err(|error| javascript_error(error.to_string()))
483}
484
485#[wasm_bindgen]
486pub fn thicken_trimmed_sheet_buffer(request_json: &str) -> Result<WasmSolidBuffer, JsValue> {
487    let request: ThickenTrimmedSheetRequest =
488        serde_json::from_str(request_json).map_err(|error| javascript_error(error.to_string()))?;
489    let solid = thicken_trimmed_sheet(
490        &request.surface,
491        &request.loops,
492        request.thickness,
493        request.symmetric,
494    )
495    .map_err(javascript_error)?;
496    solid_buffer(&solid, "{}".into())
497}
498
499#[wasm_bindgen]
500pub fn offset_face_carrier_json(request_json: &str) -> Result<String, JsValue> {
501    let request: OffsetFaceCarrierRequest =
502        serde_json::from_str(request_json).map_err(|error| javascript_error(error.to_string()))?;
503    let carrier = offset_face_carrier(
504        &request.solid,
505        request.face_id,
506        request.distance,
507        request.planar_extension,
508    )
509    .map_err(javascript_error)?;
510    serde_json::to_string(&carrier).map_err(|error| javascript_error(error.to_string()))
511}
512
513#[wasm_bindgen]
514pub fn offset_shell_json(request_json: &str) -> Result<String, JsValue> {
515    let request: OffsetShellRequest =
516        serde_json::from_str(request_json).map_err(|error| javascript_error(error.to_string()))?;
517    let result = offset_shell(&request.solid, &request.opening_face_ids, request.distance)
518        .map_err(javascript_error)?;
519    serde_json::to_string(&result).map_err(|error| javascript_error(error.to_string()))
520}
521
522#[wasm_bindgen]
523pub fn offset_shell_diagnostics_json(request_json: &str) -> Result<String, JsValue> {
524    let request: OffsetShellDiagnosticsRequest =
525        serde_json::from_str(request_json).map_err(|error| javascript_error(error.to_string()))?;
526    let result = offset_shell_with_diagnostics(
527        &request.solid,
528        &request.opening_face_ids,
529        request.distance,
530        request.tolerances,
531    )
532    .map_err(javascript_error)?;
533    serde_json::to_string(&result).map_err(|error| javascript_error(error.to_string()))
534}
535
536#[wasm_bindgen]
537pub fn export_step_json(request_json: &str) -> Result<String, JsValue> {
538    let request: ExportStepRequest =
539        serde_json::from_str(request_json).map_err(|error| javascript_error(error.to_string()))?;
540    export_step(
541        &request.solids,
542        &request.name,
543        &request.unit,
544        &request.timestamp,
545    )
546    .map_err(javascript_error)
547}
548
549#[wasm_bindgen]
550pub fn merge_curve_continuations_json(request_json: &str) -> Result<String, JsValue> {
551    let request: CoalesceRequest =
552        serde_json::from_str(request_json).map_err(|error| javascript_error(error.to_string()))?;
553    let solid = merge_curve_continuation_edges(&request.solid, request.tolerance)
554        .map_err(javascript_error)?;
555    serde_json::to_string(&solid).map_err(|error| javascript_error(error.to_string()))
556}
557
558#[wasm_bindgen]
559pub fn solve_sketch_json(request_json: &str) -> Result<String, JsValue> {
560    solve_sketch_from_json(request_json).map_err(javascript_error)
561}