///|
/// 19-raspberry-pi-mount-plate
///
/// A working example that generates a STEP model for: A mounting plate with
/// programmable hole patterns and cable strain-relief geometry.
///
/// Usage (stdout):
/// moon run --target native examples/19-raspberry-pi-mount-plate -- --width 80 --length 70 > rpi-plate.step
async fn main {
let base_args_spec = {
"width": @cli.opt_double(
85.0,
help="Width of the mounting plate (mm)",
min=65.0,
),
"length": @cli.opt_double(
75.0,
help="Length of the mounting plate (mm)",
min=55.0,
),
"thickness": @cli.opt_double(3.0, help="Plate thickness (mm)", min=1.0),
"holeDiameter": @cli.opt_double(
3.0,
help="Mounting hole diameter (mm, RPi standard is 2.75-3.0)",
min=1.0,
),
"slotLength": @cli.opt_double(
12.0,
help="Cable tie slot length (mm)",
min=5.0,
),
"slotWidth": @cli.opt_double(3.0, help="Cable tie slot width (mm)", min=1.0),
}
let args_spec = @cli.with_translate(@common.with_output_args(base_args_spec))
guard @cli.parse(
args_spec,
prog="19-raspberry-pi-mount-plate",
description="Generate a Raspberry Pi mount plate STEP model.",
)
is Some(args) else {
return
}
let width = args.double("width")
let length = args.double("length")
let thickness = args.double("thickness")
let hole_diameter = args.double("holeDiameter")
let slot_length = args.double("slotLength")
let slot_width = args.double("slotWidth")
// Adjacent slots are 20 mm apart; longer slots would touch and merge into
// one non-manifold hole.
if slot_length >= 20.0 {
@cli.eprintln(
"error: --slotLength must be less than 20 (the slot spacing) so adjacent slots do not merge",
)
abort("")
}
let output = @common.output_paths(args)
let (tx, ty, tz) = match args.translate_xyz() {
Some(v) => v
None => {
@cli.eprintln("error: invalid translation")
return
}
}
let plate = raspberry_pi_mount_plate(
width, length, thickness, hole_diameter, slot_length, slot_width,
)
.with_name("rpi-mount-plate")
.with_color(@cad.Rgb::green())
.translate(x=tx - width / 2.0, y=ty - length / 2.0, z=tz)
let design = @cad.Design::new(
name="raspberry-pi-mount-plate",
documentation=args.documentation(),
).add(plate)
@common.write_output(design, output)
}
///|
fn raspberry_pi_mount_plate(
width : Double,
length : Double,
thickness : Double,
hole_diameter : Double,
slot_length : Double,
slot_width : Double,
) -> @cad.Shape {
let outer = @cad.Profile2D::rounded_rect(width, length, 3.0)
// Raspberry Pi standard hole pattern: 58mm x 49mm
let rpi_w = 58.0
let rpi_h = 49.0
let off_x = (width - rpi_w) / 2.0
let off_y = (length - rpi_h) / 2.0
let holes = []
// Mounting holes
let hole_locs = [
(off_x, off_y),
(off_x + rpi_w, off_y),
(off_x + rpi_w, off_y + rpi_h),
(off_x, off_y + rpi_h),
]
for loc in hole_locs {
let (hx, hy) = loc
holes.push(
@cad.Profile2D::circle(hole_diameter)
.map(fn(p) { (p.0 + hx, p.1 + hy) })
.rev(),
)
}
// Strain relief slots
// Left slots
for i in 0..<2 {
let sy = off_y + 10.0 + Double::from_int(i) * 20.0
let sx = off_x / 2.0
let hole = [
(sx - slot_width / 2.0, sy - slot_length / 2.0),
(sx + slot_width / 2.0, sy - slot_length / 2.0),
(sx + slot_width / 2.0, sy + slot_length / 2.0),
(sx - slot_width / 2.0, sy + slot_length / 2.0),
].rev()
holes.push(hole)
}
// Right slots
for i in 0..<2 {
let sy = off_y + 10.0 + Double::from_int(i) * 20.0
let sx = width - off_x / 2.0
let hole = [
(sx - slot_width / 2.0, sy - slot_length / 2.0),
(sx + slot_width / 2.0, sy - slot_length / 2.0),
(sx + slot_width / 2.0, sy + slot_length / 2.0),
(sx - slot_width / 2.0, sy + slot_length / 2.0),
].rev()
holes.push(hole)
}
@cad.ExtrudedProfile::new(outer, thickness, holes~)
}