///|
/// 08-snap-fit-test-strip
///
/// A working example that generates a STEP model for a snap-fit test strip.
/// It creates a series of cantilever snap arms and matching receiver slots
/// with varying interference levels to test print tolerances.
///
/// Usage (stdout):
/// moon run --target native examples/08-snap-fit-test-strip -- --interference 0.5 > test-strip.step
async fn main {
let base_args_spec = {
"clearance": @cli.opt_double(
0.2,
help="Nominal clearance between arm and receiver (mm)",
min=0.0,
),
"interference": @cli.opt_double(
0.4,
help="Base hook interference (mm)",
min=0.0,
),
"stepCount": @cli.opt_double(5.0, help="Number of test steps", min=1.0),
"interferenceStep": @cli.opt_double(
0.1,
help="Amount to increase interference at each step (mm)",
),
"snapClearance": @cli.opt_double(
0.5,
help="Vertical engage clearance (mm)",
min=0.0,
),
"armThickness": @cli.opt_double(
1.5,
help="Cantilever arm thickness (mm)",
min=0.5,
),
"armWidth": @cli.opt_double(10.0, help="Snap arm width (mm)", min=2.0),
}
let args_spec = @cli.with_translate(@common.with_output_args(base_args_spec))
guard @cli.parse(
args_spec,
prog="08-snap-fit-test-strip",
description="Generate a snap-fit tolerance test strip.",
)
is Some(args) else {
return
}
let clearance = args.double("clearance")
let base_interference = args.double("interference")
let step_count = args.double("stepCount").to_int()
let interference_step = args.double("interferenceStep")
let snap_clearance = args.double("snapClearance")
let arm_thickness = args.double("armThickness")
let arm_width = args.double("armWidth")
let output = @common.output_paths(args)
let (tx, ty, tz) = match args.translate_xyz() {
Some(v) => v
None => {
@cli.eprintln("error: invalid translation")
return
}
}
// Constants
let arm_height = 20.0
let base_height = 5.0
let step_spacing = arm_width + 10.0
let receiver_length = 15.0
let hook_height = 3.0
let mut design = @cad.Design::new(
name="snap-fit-test",
documentation=args.documentation(),
)
// 1. Generate the test strip (Arms)
let strip_length = Double::from_int(step_count) * step_spacing
let arm_base_strip = @cad.Cuboid::new(strip_length, 15.0, base_height)
.with_name("arm-base")
.with_color(@cad.Rgb::cyan())
.translate(x=tx, y=ty, z=tz)
design = design.add(arm_base_strip)
for i in 0.. World Z (Up)
// Local Z (Width) -> World X (Along strip)
// Local X (Thickness) -> World Y (Across strips)
.rotate_x(90.0) // Local Y -> World Z, Local Z -> World -Y
.rotate_z(90.0) // World X -> World Y, World -Y -> World X
.translate(
x=tx + x_offset - arm_width / 2.0,
y=ty + 7.5 - arm_thickness / 2.0,
z=tz + base_height,
)
design = design.add(arm)
}
// 2. Generate the Receiver Strip
let receiver_y_offset = 30.0
let receiver_base_strip = @cad.Cuboid::new(
strip_length, receiver_length, base_height,
)
.with_name("receiver-base")
.with_color(@cad.Rgb::blue())
.translate(x=tx, y=ty + receiver_y_offset, z=tz)
design = design.add(receiver_base_strip)
for i in 0..