# Spur gear stage: a 16-tooth pinion driving a 32-tooth gear (module 4, 20° involute teeth from
# gear(), the gear set to mesh with the pinion), on shafts in bearings between two side plates; a
# V-belt pulley on the input, a keyed output shaft.
from math import *
units("mm")

M, Z1, Z2 = 4, 16, 32               # module, teeth
A = M * (Z1 + Z2) / 2               # centre distance: 96
X1, X2 = -A / 3, 2 * A / 3          # the shafts' x
H = 15 + M * Z2 / 2 + M + 22        # the shafts' height
steel, brass, chrome, plate_c, base_c = "steel", "#c9a54a", "#dfe2e6", "#5b6068", "#3a3f47"

# the pinion: solid, on the input shaft (24 bore), a keyway along the top of its bore
pinion = gear(Z1, M, 34, at=(X1, -17, H), axis="y", bore=24, name="pinion", color=steel)
pinion = pinion - box(6, 34, 3.5, at=(X1 - 3, -17, H + 11))
pinion.chamfer(0.8, edges=pinion.face("y"))
pinion.paint(steel)

# the gear: a rim, a thinner web with six holes, a hub standing proud of it
wheel = gear(Z2, M, 30, mesh=pinion, bore=40, name="gear", color=brass)    # beside the pinion, its teeth in the pinion's gaps
wheel.move(0, 2, 0)                                                              # centred on y = 0
wheel = wheel - box(10, 30, 3.5, at=(X2 - 5, -15, H + 19))
rim_in = M * Z2 / 2 - 1.25 * M - 7
for y0 in (-15, 7):
    wheel = wheel - (cylinder(rim_in, 8, at=(X2, y0, H), axis="y", sides=96) - cylinder(34, 8, at=(X2, y0, H), axis="y", sides=64))
for k in range(6):
    a = radians(30 + 60 * k)
    wheel = wheel - cylinder(7, 30, at=(X2 + 43.5 * cos(a), -15, H + 43.5 * sin(a)), axis="y", sides=32)
wheel.paint(brass)

# the shafts, a keyway cut where each key sits; their front ends held by a washer and a nut
s1 = cylinder(12, 142, at=(X1, -20, H), axis="y", name="input shaft", color=chrome, sides=48)
s2 = cylinder(20, 154, at=(X2, -20, H), axis="y", name="output shaft", color=chrome, sides=64)
keys, cuts = [], {1: [], 2: []}
for n, x, r, w, y0, l in [(1, X1, 12, 6, -15, 30), (1, X1, 12, 6, 78, 26), (2, X2, 20, 10, -14, 28), (2, X2, 20, 10, 100, 30)]:
    cuts[n].append(box(w, l, 3.5, at=(x - w / 2, y0, H + r - 3.5)))
    k = box(w, l, 6, at=(x - w / 2, y0, H + r - 3.5), name="key", color=steel)
    k.fillet(1.2, edges="y")
    keys.append(k)
s1 = subtract(s1, *cuts[1])
s2 = subtract(s2, *cuts[2])
for sh in (s1, s2):
    sh.chamfer(1)
    sh.paint(chrome)
ends = {12: [], 20: []}
for x, r in [(X1, 12), (X2, 20)]:
    # an end cap on each shaft's front end, held by three socket screws
    cap = cylinder(r + 8, 6, at=(x, -26, H), axis="y", name="end cap", color="#9a9da3", sides=64)
    cap.chamfer(1.2, edges="front")
    cap.paint("#9a9da3")
    ends[r].append(cap)
    for k in range(3):
        a = radians(90 + 120 * k)
        sx, sz = x + (r - 4) * cos(a), H + (r - 4) * sin(a)
        rs = 3.2 if r > 15 else 2.4
        screw = cylinder(rs, 3, at=(sx, -27, sz), axis="y", name="screw", color="#2f3033", sides=20)
        screw = screw - ngon(sx, sz, rs * 0.5, sides=6, plane="xz", offset=-27).pull(1.6)
        screw.paint("#2f3033")
        ends[r].append(screw)
# the V-belt pulley on the input, behind the plate: two grooves, turned
grooves = []
for g0 in (0, 17):
    grooves += [(64 + g0, H + 48), (68 + g0, H + 37), (73 + g0, H + 37), (77 + g0, H + 48)]
pulley = polygon([(62, H + 12), (62, H + 48)] + grooves + [(98, H + 48), (98, H + 22), (106, H + 22), (106, H + 12)], plane="yz", offset=X1).revolve(axis="y", about=(X1, 0, H), name="pulley", color="#c9ccd2", sides=96)
pulley = pulley - box(6, 44, 3.5, at=(X1 - 3, 62, H + 12 - 1))
pulley.paint("#c9ccd2")

# the plate the shafts turn in, with a bearing for each, standing on a base
outline = [(-160, 15), (160, 15), (160, H + 40)]
outline += [(130 + 30 * cos(radians(a)), H + 40 + 30 * sin(radians(a))) for a in range(0, 91, 15)]
outline += [(-130 + 30 * cos(radians(a)), H + 40 + 30 * sin(radians(a))) for a in range(90, 181, 15)]
plate = polygon(outline, plane="xz", offset=36).pull(14, name="plate", color=plate_c)
for x, r in [(X1, 24), (X2, 34)]:
    plate = plate - cylinder(r, 14, at=(x, 36, H), axis="y", sides=64)
plate.paint(plate_c)
bearings = []
for x, r_in, r_out in [(X1, 12, 24), (X2, 20, 34)]:
    for y0 in (32, 50):
        b = cylinder(r_out + 9, 4, at=(x, y0, H), axis="y", name="bearing", color="#cfd2d6", sides=64)
        if y0 == 32:
            b = b + cylinder(r_out, 18, at=(x, 32, H), axis="y", sides=64)
        b = b - cylinder(r_in, 22, at=(x, 32, H), axis="y", sides=48)
        b.paint("#cfd2d6")
        bearings.append(b)
        for k in range(4):
            a = radians(45 + 90 * k)
            bearings.append(cylinder(3.2, 3, at=(x + (r_out + 4.5) * cos(a), y0 - 3 if y0 == 32 else y0 + 4, H + (r_out + 4.5) * sin(a)), axis="y", name="screw", color="#2f3033", sides=16))
base = box(360, 210, 15, at=(-180, -70, 0), name="base", color=base_c)
base.fillet(10, edges="vertical")
base.fillet(2, edges="top")
for x in (-150, 150):
    for y in (-45, 115):
        base.top.circle(x + 180, y + 70, 6).push(15)
# two gussets behind the plate
gussets = [prism([(36 + 14, 15), (36 + 14 + 50, 15), (36 + 14, 15 + 80)], 10, plane="yz", offset=x, name="gusset", color=plate_c) for x in (-150, 140)]

group([pinion, s1, keys[0], keys[1], pulley] + ends[12], name="input")
group([wheel, s2, keys[2], keys[3]] + ends[20], name="output")
group([plate] + bearings + gussets, name="plate")
group([base], name="base")

dim((X1, -40, H + 80), (X2, -40, H + 80), offset=(0, 0, 30))
label("module 4 · 16 and 32 teeth · 2 : 1", at=(-60, -80, H + 140), to=(X1 + M * Z1 / 2 + 2, -17, H))
