# Chest of drawers, as a woodworker plans one: sides, a bottom and front rails in solid oak, a
# plywood back, a top with rounded corners on tapered legs; two small drawers over three graduated
# ones, each drawer a real box (front, sides, back, a bottom), the middle one pulled out to show
# it; turned knobs; the sizes to cut dimensioned.
from math import *
units("cm")

oak, oak2, ply, brass = "#c49a6c", "#a97c50", "#e3d0a6", "#c9a35a"
floor_c, wall_c, pine = "#d6cfc2", "#eeebe4", "#e0c48f"
W, D, H, LEG = 90, 45, 95, 12       # outside sizes; the legs' height
T, TOPT, RAIL = 1.8, 2.4, 1.2       # the boards, the top, the rails between drawers
GAP = 0.3                           # round each drawer front

# ---------- the room: a floor, the wall behind ----------
floor_ = box(300, 190, 2, at=(-110, -120, -2), name="floor", color=floor_c)
wall = box(300, 4, 170, at=(-110, D + 8, 0), name="wall", color=wall_c)

# ---------- the carcass ----------
def leg(x, y):
    # tapered: 3.2 square at the floor, 4.6 under the carcass
    return loft([rect(x, y, 3.2, 3.2, center=True, offset=0), rect(x, y, 4.6, 4.6, center=True, offset=LEG)], name="leg", color=oak2)
legs = [leg(x, y) for x in (3, W - 3) for y in (3, D - 3)]
Z0 = LEG
CH = H - LEG - TOPT                  # the sides' height
sides = [box(T, D, CH, at=(x, 0, Z0), name="side", color=oak) for x in (0, W - T)]
bottom = box(W - 2 * T, D - 0.6, T, at=(T, 0, Z0), name="bottom", color=oak)
back = box(W - 2 * T, 0.6, CH, at=(T, D - 0.6, Z0), name="back panel", color=ply)
top = box(W + 2, D + 1.5, TOPT, at=(-1, -1.5, H - TOPT), name="top", color=oak)
top.fillet(1.2, edges="vertical")
top.chamfer(0.4, edges="top")

# the rows of drawers, bottom up: three graduated, then two small side by side
rows, z = [], Z0 + T
for h in (22, 20, 18, 14):
    rows.append((z, z + h))
    z += h + RAIL
rails = [box(W - 2 * T, 2, RAIL, at=(T, 0, a1), name="rail", color=oak) for a0, a1 in rows]
muntin = box(RAIL, 2, rows[3][1] - rows[3][0], at=(W / 2 - RAIL / 2, 0, rows[3][0]), name="muntin", color=oak)

# ---------- the drawers ----------
def knob(x, y, z):
    k = cylinder(0.8, 1.3, at=(x, y - 1.3, z), axis="y", sides=16) + sphere(1.5, at=(x, y - 2.1, z), sides=16)
    k.paint(brass)
    k.name = "knob"
    return k

def drawer(x0, x1, za, zb, out, name):
    w, h = x1 - x0 - 2 * GAP, zb - za - 2 * GAP
    y = -out                         # pulled out this far towards the front
    parts = [box(w, 2, h, at=(x0 + GAP, y, za + GAP), name="front", color=oak)]
    bx, bz, bw, bh, bd = x0 + GAP + 0.8, za + GAP + 0.6, w - 1.6, h - 2.4, D - 6
    parts.append(box(1.2, bd, bh, at=(bx, y + 2, bz), name="side", color=ply))
    parts.append(box(1.2, bd, bh, at=(bx + bw - 1.2, y + 2, bz), name="side", color=ply))
    parts.append(box(bw - 2.4, 1.2, bh - 1.4, at=(bx + 1.2, y + 2 + bd - 1.2, bz + 1.4), name="back", color=ply))
    parts.append(box(bw - 2.4, bd - 1.2, 0.6, at=(bx + 1.2, y + 2, bz + 0.6), name="bottom", color=ply))
    mid = (za + zb) / 2
    xs = [(x0 + x1) / 2] if x1 - x0 < 60 else [x0 + (x1 - x0) * 0.25, x0 + (x1 - x0) * 0.75]
    for kx in xs:
        parts.append(knob(kx, y, mid))
    return group(parts, name=name)

drawers = [
    drawer(T, W - T, rows[0][0], rows[0][1], 0, "drawer 1"),
    drawer(T, W - T, rows[1][0], rows[1][1], 26, "drawer 2"),
    drawer(T, W - T, rows[2][0], rows[2][1], 0, "drawer 3"),
    drawer(T, W / 2 - RAIL / 2, rows[3][0], rows[3][1], 0, "drawer 4"),
    drawer(W / 2 + RAIL / 2, W - T, rows[3][0], rows[3][1], 0, "drawer 5"),
]

# ---------- the workshop round it: boards stacked by the wall, a folded rule on the top ----------
boards = [box(95, 14 + 2 * i, 2, at=(-105, 8 + 3 * i, 2 * i), name="board", color=pine) for i in range(3)]
for i, b in enumerate(boards):
    b.rotate(4 - 3 * i, axis="z")
rule = box(23, 1.6, 0.6, at=(14, 12, H), name="folding rule", color="#e8c43a")
rule2 = box(23, 1.6, 0.6, at=(14, 13.8, H + 0.6), name="folding rule", color="#e8c43a")
rule2.rotate(-14, axis="z")

# ---------- the sizes to cut ----------
dim((0, 0, H), (W, 0, H), offset=(0, 0, 10))
dim((W + 1, 0, 0), (W + 1, 0, H), offset=(12, 0, 0))
dim((W + 1, 0, 0), (W + 1, D, 0), offset=(12, 0, 0))
