///|
/// 06-stackable-spacer-tower
///
/// A set of stackable spacers with full-height tapers that let them stack
/// reliably despite print tolerances.
///
/// Usage (stdout):
///   moon run --target native examples/06-stackable-spacer-tower -- --count 3 > tower.step
async fn main {
  let base_args_spec = {
    "count": @cli.opt_double(
      1.0,
      help="Number of spacers in the tower",
      min=1.0,
    ),
    "id": @cli.opt_double(10.0, help="Inner diameter of the hole (mm)", min=1.0),
    "mid": @cli.opt_double(
      15.0,
      help="Diameter of the interlocking feature (mm)",
      min=2.0,
    ),
    "od": @cli.opt_double(
      25.0,
      help="Outer diameter of the spacer (mm)",
      min=3.0,
    ),
    "height": @cli.opt_double(
      5.0,
      help="Height of the spacer body (mm)",
      min=1.0,
    ),
    "clickHeight": @cli.opt_double(
      2.0,
      help="Height of the interlocking protrusion (mm)",
      min=0.5,
    ),
    "resolution": @cli.opt_double(64.0, help="Circle segments", min=3.0),
  }
  let args_spec = @cli.with_translate(@common.with_output_args(base_args_spec))
  guard @cli.parse(
      args_spec,
      prog="06-stackable-spacer-tower",
      description="Generate a stackable spacer tower.",
    )
    is Some(args) else {
    return
  }
  let count = args.double("count").to_int()
  let id = args.double("id")
  let mid = args.double("mid")
  let od = args.double("od")
  let height = args.double("height")
  let click_height = args.double("clickHeight")
  let resolution = args.double("resolution").to_int()
  let output = @common.output_paths(args)
  let (tx, ty, tz) = match args.translate_xyz() {
    Some(v) => v
    None => {
      @cli.eprintln("error: invalid translation")
      return
    }
  }

  // Basic validation
  if id >= mid {
    @cli.eprintln(
      "error: inner diameter (\{id}) must be less than middle diameter (\{mid})",
    )
    abort("")
  }
  if mid >= od {
    @cli.eprintln(
      "error: middle diameter (\{mid}) must be less than outer diameter (\{od})",
    )
    abort("")
  }
  if click_height >= height {
    @cli.eprintln(
      "error: clickHeight (\{click_height}) must be less than height (\{height})",
    )
    abort("")
  }
  let mut design = @cad.Design::new(
    name="spacer-tower",
    documentation=args.documentation(),
  )

  // Full-height draft: the female bore narrows over the whole body height and
  // the male outer surface narrows at the same cone angle over its full
  // height. This self-centres the parts and gives a constant clearance, so
  // print tolerances do not stop them stacking.
  let mut taper_d = 0.2
  if taper_d > (mid - id) * 0.3 {
    taper_d = (mid - id) * 0.3
  }
  if taper_d > (od - mid) * 0.3 {
    taper_d = (od - mid) * 0.3
  }
  let fit_clear = 0.05
  let colors = [@cad.Rgb::orange(), @cad.Rgb::green(), @cad.Rgb::blue()]
  for i in 0.. Array[@cad.SceneNode] {
  let body_steps : Int32 = 8
  let click_steps : Int32 = 4
  let outer_circle = @cad.Profile2D::circle(od, segments=resolution)
  // Holes are wound opposite to the outer boundary.
  let inner_circle = @cad.Profile2D::circle(id, segments=resolution).rev()
  let nodes : Array[@cad.SceneNode] = []

  // Female bore: largest at the bottom, narrowing to mid + fit_clear at the
  // top. Each layer uses its mid-height diameter to keep the stair-step small.
  let body_step_h = height / Double::from_int(body_steps)
  for k in 0..