"""Axial leaded diode, Vishay's DO-35 (DO-204AH), DO-41 (DO-204AL), DO-15 (DO-204AC), DO-201AD and P600 packages, mounted horizontal or vertical. Lead 1, the cathode, is at the origin and lead 2, the anode, at +X by the pitch; the leads go down through the board. Horizontal: the body lies on the board along X, centred between the leads, its cathode band toward lead 1. Vertical: the body stands on the board over lead 1 with the anode up (or over lead 2 with the cathode up) and the top lead comes back down beside it. Dimensions from Vishay's data sheets, listed in the README.""" import math from steve import Model package = "DO-41" # DO-35, DO-41, DO-15, DO-201AD or P600 mounting = "horizontal" # horizontal or vertical pitch = 10.16 # mm Lead pitch on the board up = "anode" # vertical only: the end on top, anode (the body over lead 1) or cathode (the body over lead 2) tail = 3.0 # mm Leads below the board detail = "full" # full: body, cathode band and leads; simple: the body only # Each entry: (body diameter (min, max), body length (min, max), lead diameter (min, max)), mm; the model uses the middle of each range (a # single value where the sheet gives only a maximum). The sheets' "PACKAGE OUTLINE DIMENSIONS" drawings: # DO-35 (DO-204AH): Vishay Semiconductors 1N4148, document 81857, Rev. 1.6, 07-Nov-2024, page 3: Ø 1.5 to 1.75, length 3.4 max, lead 0.55 max. # DO-41 (DO-204AL): Vishay General Semiconductor 1N4001 thru 1N4007, document 88503, revision 29-Apr-2020, page 4. # DO-15 (DO-204AC): Vishay General Semiconductor P6KE6.8A thru P6KE540A, document 88369, revision 27-Sep-2021, page 5. # DO-201AD: Vishay General Semiconductor 1N5400 thru 1N5408, document 88516, revision 19-Dec-2025, page 4. # P600: Vishay General Semiconductor P600A thru P600M, document 88692, revision 19-Dec-2025, page 3. PACKAGES = { "DO-35": ((1.5, 1.75), (3.4, 3.4), (0.55, 0.55)), "DO-41": ((2.0, 2.7), (4.1, 5.2), (0.71, 0.86)), "DO-15": ((3.3, 3.5), (6.15, 6.55), (0.71, 0.86)), "DO-201AD": ((4.8, 5.3), (7.2, 9.5), (1.22, 1.32)), "P600": ((8.6, 9.1), (8.6, 9.1), (1.22, 1.32)), } if package not in PACKAGES: raise ValueError(f"no package {package!r}: {', '.join(PACKAGES)}") if mounting not in ("horizontal", "vertical") or up not in ("anode", "cathode"): raise ValueError("mounting: horizontal or vertical; up: anode or cathode") diameter, length, lead = (sum(v) / 2 for v in PACKAGES[package]) R, r = diameter / 2, lead / 2 glass = package == "DO-35" # Proportions, for looks (the sheets draw the body but dimension only its diameter and length): the body's end edges rounded by 0.25 x the # radius (DO-35 glass: 0.45 x); the cathode band 0.18 x the length wide, starting at the cathode end's rounding; the leads bent with a radius # of one lead diameter; vertical: the top lead clears the body's top end by 2 lead diameters + 1 before it turns down. EDGE = (0.45 if glass else 0.25) * R BAND = 0.18 * length BEND = lead LOOP = 2 * lead + 1.0 horizontal = mounting == "horizontal" if horizontal and pitch < length + 2 * BEND: raise ValueError(f"horizontal pitch: at least {length + 2 * BEND:.2f} mm for {package} (body {length:.2f} long, bends {BEND:.2f})") if not horizontal and pitch < max(R + r, 2 * BEND): raise ValueError(f"vertical pitch must let the top lead pass the body: at least {max(R + r, 2 * BEND):.2f} mm for {package}") def body_profile(): """The body outline as (u along the axis from the cathode end, radius) and the band segment's index.""" pts = [(0.0, 0.0), (0.0, R - EDGE)] pts += [(EDGE * (1 - math.cos(math.pi / 2 * i / 4)), R - EDGE + EDGE * math.sin(math.pi / 2 * i / 4)) for i in range(1, 5)] pts.append((EDGE + BAND, R)) band = len(pts) - 2 pts.append((length - EDGE, R)) pts += [(length - u, v) for u, v in reversed(pts[1:5])] pts.append((length, 0.0)) return pts, band model = Model() outline, band = body_profile() if horizontal: x0 = pitch / 2 - length / 2 axis_z = R # the body rests on the board points = [(x0 + u, axis_z + v) for u, v in outline] axis = ((0, 0, axis_z), (1, 0, 0)) else: base = 0.0 if up == "anode" else pitch # the lead the body stands over # Cathode at the bottom when the anode is up: u runs up from the cathode end; else down from the top. points = [(base + v, u if up == "anode" else length - u) for u, v in outline] axis = ((base, 0, 0), (0, 0, 1)) with model.sketch("body_sketch", on="XZ", name="Body") as sk: sk.polyline("body_outline", points, closed=True) model.revolve("body", "body_sketch", axis=axis, op="new", body="body_body", name="Body") bodies = ["body_body"] if detail == "full": if horizontal: legs = [(0.0, 1, x0), (pitch, -1, x0 + length)] for i, (x, side, x_end) in enumerate(legs, 1): with model.sketch(f"lead_{i}_path", on="XZ", name=f"Lead {i} path") as sk: sk.line(f"lead_{i}_up", (x, -tail), (x, axis_z - BEND), construction=True) if side > 0: sk.arc(f"lead_{i}_bend", (x + BEND, axis_z - BEND), BEND, 90, 180, construction=True) else: sk.arc(f"lead_{i}_bend", (x - BEND, axis_z - BEND), BEND, 0, 90, construction=True) sk.line(f"lead_{i}_along", (x + side * BEND, axis_z), (x_end, axis_z), construction=True) model.plane(f"lead_{i}_start", on="XY", offset=-tail, name=f"Lead {i} end") with model.sketch(f"lead_{i}_section", on=f"lead_{i}_start", name=f"Lead {i}") as sk: sk.circle(f"lead_{i}_round", (x, 0), r) model.sweep(f"lead_{i}", f"lead_{i}_section", f"lead_{i}_path", op="new", body=f"lead_{i}_body", name=f"Lead {i}") bodies.append(f"lead_{i}_body") else: far = pitch if up == "anode" else 0.0 # where the top lead comes down step = 1 if far > base else -1 model.plane("lead_low_start", on="XY", offset=-tail, name="Bottom lead end") with model.sketch("lead_low_section", on="lead_low_start", name="Bottom lead") as sk: sk.circle("lead_low_round", (base, 0), r) model.extrude("lead_low", "lead_low_section", distance=tail, op="new", body="lead_low_body", name="Bottom lead") top = length + LOOP with model.sketch("lead_top_path", on="XZ", name="Top lead path") as sk: sk.line("lead_top_up", (base, length), (base, top - BEND), construction=True) if step > 0: sk.arc("lead_top_bend_1", (base + BEND, top - BEND), BEND, 90, 180, construction=True) sk.line("lead_top_over", (base + BEND, top), (far - BEND, top), construction=True) sk.arc("lead_top_bend_2", (far - BEND, top - BEND), BEND, 0, 90, construction=True) else: sk.arc("lead_top_bend_1", (base - BEND, top - BEND), BEND, 0, 90, construction=True) sk.line("lead_top_over", (base - BEND, top), (far + BEND, top), construction=True) sk.arc("lead_top_bend_2", (far + BEND, top - BEND), BEND, 90, 180, construction=True) sk.line("lead_top_down", (far, top - BEND), (far, -tail), construction=True) model.plane("lead_top_start", on="XY", offset=length, name="Top lead start") with model.sketch("lead_top_section", on="lead_top_start", name="Top lead") as sk: sk.circle("lead_top_round", (base, 0), r) model.sweep("lead_top", "lead_top_section", "lead_top_path", op="new", body="lead_top_body", name="Top lead") bodies += ["lead_low_body", "lead_top_body"] # Materials, for looks and a rough mass: DO-35 is a glass body (the sheet's cathode band is black); the others are moulded epoxy (nylon, PA6, # the nearest in the list) with a light band ("color band denotes cathode end"); the leads tin-plated copper. if glass: model.material("glass-borosilicate", bodies=["body_body"], color="#d98a3a") else: model.material("pa6", bodies=["body_body"], color="#202022") if detail == "full": model.material("copper", bodies=bodies[1:], color="#c9ccd1") model.appearance(color="#141414" if glass else "#c8c8c8", faces=[f"body.side(body_outline.side{band})"]) result = model.result()