Skip to main content

cli/
cli.rs

1//! Standalone Rust example: shape creation, booleans, measurements, STEP I/O.
2//!
3//! Build & run from the repo root:
4//!
5//! ```sh
6//! cargo run --release --example cli -p occt-wasm
7//! cargo run --release --example cli -p occt-wasm -- --step output.step
8//! ```
9//!
10//! Note: `--release` is strongly recommended. Debug-mode wasmtime compilation
11//! is ~100x slower than release.
12
13use std::env;
14use std::fs;
15use std::path::PathBuf;
16use std::process::ExitCode;
17
18use occt_wasm::{OcctError, OcctKernel};
19
20fn main() -> ExitCode {
21    println!("occt-wasm Rust CLI Example\n");
22
23    let step_out: Option<PathBuf> = env::args()
24        .collect::<Vec<_>>()
25        .windows(2)
26        .find(|w| w[0] == "--step")
27        .map(|w| PathBuf::from(&w[1]));
28
29    match run(step_out.as_deref()) {
30        Ok(()) => {
31            println!("\nDone.");
32            ExitCode::SUCCESS
33        }
34        Err(e) => {
35            eprintln!("\nError: {e}");
36            ExitCode::FAILURE
37        }
38    }
39}
40
41fn run(step_out: Option<&std::path::Path>) -> Result<(), OcctError> {
42    let mut kernel = OcctKernel::new()?;
43
44    // --- Create shapes ---
45    let box_shape = kernel.make_box(30.0, 20.0, 15.0)?;
46    let cyl = kernel.make_cylinder(6.0, 25.0)?;
47    let sphere = kernel.make_sphere(4.0)?;
48    let moved_sphere = kernel.translate(sphere, 15.0, 10.0, 15.0)?;
49
50    println!("Created: box 30x20x15, cylinder r=6 h=25, sphere r=4");
51
52    // --- Boolean operations ---
53    let with_hole = kernel.cut(box_shape, cyl)?;
54    let final_shape = kernel.fuse(with_hole, moved_sphere)?;
55
56    // --- Measurements ---
57    let vol = kernel.get_volume(final_shape)?;
58    let area = kernel.get_surface_area(final_shape)?;
59    let bbox = kernel.get_bounding_box(final_shape, true)?;
60
61    println!("\nResult:");
62    println!("  Volume:       {vol:.2} mm^3");
63    println!("  Surface area: {area:.2} mm^2");
64    println!(
65        "  Bounding box: [{:.1}, {:.1}, {:.1}] to [{:.1}, {:.1}, {:.1}]",
66        bbox.min.x, bbox.min.y, bbox.min.z, bbox.max.x, bbox.max.y, bbox.max.z
67    );
68
69    // --- Topology counts ---
70    let faces = kernel.get_sub_shapes(final_shape, "Face")?;
71    let edges = kernel.get_sub_shapes(final_shape, "Edge")?;
72    let verts = kernel.get_sub_shapes(final_shape, "Vertex")?;
73    println!(
74        "  Topology:     {} faces, {} edges, {} vertices",
75        faces.len(),
76        edges.len(),
77        verts.len()
78    );
79
80    // --- Tessellate (renderer-ready mesh) ---
81    let mesh = kernel.tessellate(final_shape, 0.1, 0.5)?;
82    println!(
83        "  Mesh:         {} vertices, {} triangles",
84        mesh.positions.len() / 3,
85        mesh.indices.len() / 3
86    );
87
88    // --- STEP export ---
89    let step_data = kernel.export_step(final_shape)?;
90    if let Some(path) = step_out {
91        fs::write(path, &step_data).map_err(|e| OcctError::Operation {
92            operation: "export_step_write".to_owned(),
93            message: format!("write {}: {e}", path.display()),
94        })?;
95        println!("\nSTEP exported to: {}", path.display());
96    } else {
97        println!("\nTip: pass --step output.step to export the result");
98    }
99
100    // --- STEP round-trip ---
101    let reimported = kernel.import_step(&step_data)?;
102    let reimported_vol = kernel.get_volume(reimported)?;
103    println!(
104        "  Round-trip:   export -> import, volume delta = {:.6}",
105        (vol - reimported_vol).abs()
106    );
107
108    Ok(())
109}