"""Straight miter gear (ratio 1:1), KHK SM series. The outline is the published one: hub of diameter B and width H on the XY plane, the back cone out to the outside diameter D at G above the back (the crown), a 45 degree tip cone up to the total length F, and the bore A through. detail = "full" cuts the teeth into it: each gap runs along the pitch cone to the apex, its section computed with Tredgold's approximation (the involute of the equivalent spur gear of z / cos 45 degrees teeth, ISO 53 proportions). This is close for looks and fits, not a tooth-contact model. detail = "simple" keeps the teeth filled in. Axis along Z; the back is on the XY plane.""" import math from steve import Model designation = "SM1-20" # Catalogue number detail = "full" # full: real teeth; simple: the outline with the teeth filled in # number: (module, teeth, bore A, hub diameter B, outside diameter D, total length F, crown to back G, hub width H). # KHK Gears catalogue 2025, Miter Gears, SM table, PDF p. 26, https://khkgears.us/media/lblpmezm/catalog-2025-miter-gears.pdf GEARS = { "SM1-20": (1, 20, 6, 16, 21.41, 13.94, 10.71, 8), "SM1-25": (1, 25, 6, 20, 26.41, 15.16, 11.21, 8), "SM1-30": (1, 30, 8, 24, 31.41, 17.71, 13.71, 10), "SM1.25-20": (1.25, 20, 8, 22, 26.77, 15.27, 11.38, 9), "SM1.25-25": (1.25, 25, 8, 25, 33.02, 17.88, 13.26, 9.25), "SM1.25-30": (1.25, 30, 10, 30, 39.27, 23.47, 18.13, 13.5), "SM1.5-20": (1.5, 20, 8, 26, 32.12, 21.24, 16.06, 13), "SM1.5-25": (1.5, 25, 10, 30, 39.62, 22.25, 16.31, 11.5), "SM1.5-30": (1.5, 30, 10, 36, 47.12, 28.24, 21.56, 16), "SM2-16": (2, 16, 10, 27, 34.83, 19, 15.41, 11.5), "SM2-20": (2, 20, 12, 34, 42.83, 24.89, 18.41, 14), "SM2-25": (2, 25, 12, 40, 52.83, 24.33, 16.41, 10), "SM2-30": (2, 30, 12, 45, 62.83, 29.42, 21.41, 12.5), "SM2.5-16": (2.5, 16, 12, 34, 43.53, 21, 16.77, 12), "SM2.5-20": (2.5, 20, 14, 42, 53.54, 32.54, 24.77, 19), "SM2.5-25": (2.5, 25, 16, 50, 66.04, 30.41, 20.52, 12.5), "SM2.5-30": (2.5, 30, 16, 60, 78.54, 36.28, 26.27, 17), "SM3-16": (3, 16, 14, 42, 52.24, 23, 18.12, 13), "SM3-20": (3, 20, 16, 50, 64.24, 39.84, 30.12, 23), "SM3-25": (3, 25, 20, 60, 79.24, 37.81, 24.62, 15), "SM3-30": (3, 30, 20, 70, 94.24, 45.47, 32.12, 20), } module, teeth, A, B, D, F, G, H = GEARS[designation] tip_radius = D / 2 - (F - G) model = Model() with model.sketch("outline", on="XZ", name="Outline") as sk: sk.polyline("profile", [(A / 2, 0), (B / 2, 0), (B / 2, H), (D / 2, G), (tip_radius, F), (A / 2, F)], closed=True) model.revolve("gear", "outline", axis="Z", name="Gear") if detail == "full": pressure = math.radians(20) cone = math.radians(45) pitch_r = module * teeth / 2 equivalent = pitch_r / math.cos(cone) base = equivalent * math.cos(pressure) root_r = pitch_r - 1.25 * module * math.cos(cone) apex = G + D / 2 def involute(angle): return math.tan(angle) - angle def half_gap(r): rho = equivalent + (r - pitch_r) / math.cos(cone) angle = math.acos(base / rho) if rho > base else 0 half_tooth = (math.pi / (2 * teeth / math.cos(cone)) + involute(pressure) - involute(angle)) * rho / r return math.pi / teeth - half_tooth top_r = D / 2 radii = [root_r + (top_r - root_r) * i / 4 for i in range(5)] section = [(r, half_gap(r)) for r in radii] section.append((top_r * 1.3, half_gap(top_r))) planes = (("gap_low", H), ("gap_high", F + 0.5)) for name, z in planes: scale = (apex - z) / (apex - G) model.plane(f"{name}_plane", on="XY", offset=z, name="Gap section") points = [(r * scale * math.sin(-g), r * scale * math.cos(g)) for r, g in section] points += [(r * scale * math.sin(g), r * scale * math.cos(g)) for r, g in reversed(section)] with model.sketch(f"{name}_sketch", on=f"{name}_plane", name="Gap section") as sk: sk.polyline(f"{name}_outline", points, closed=True) model.loft("gap", ["gap_low_sketch", "gap_high_sketch"], ruled=True, op="cut", name="Tooth gap") model.circular_pattern("gaps", axis="Z", count=teeth, features=["gap"], name="Tooth gaps") model.material("steel-generic", color="#b4b8bd") result = model.result()