"""6 x 3.5 mm through-hole tactile switch, APEM MJTP1243 and MJTP1250 (top-operated, two terminals). The body is centred on the origin, its underside on the board's top face (the XY plane); the body's 6.0 length and the two terminals lie along X (6.5 apart), its 3.5 depth along Y. Dimensions from APEM's MJTP series sheet, in the README.""" from steve import Model kind = "1243" # Type (MJTP1243 or MJTP1250) # Each entry: (height to the actuator's top L1, overall height to the terminals' tips L). # APEM "MJTP Series 6mm Thru-Hole Mtg. Tact Switches", catalogue section M (pages M3 to M7, PDF dated 2021-09-05/2023-04-20; the # mm.digikey.com copy), page M6, MJTP1243 & MJTP1250, table: MJTP1243 L1 .169 (4,3), L .307 (7,8); MJTP1250 L1 .197 (5,0), # L .335 (8,5). TYPES = { "1243": (4.3, 7.8), "1250": (5.0, 8.5), } # Page M6, the MJTP1243 & MJTP1250 drawing, in inches (mm); the mm values are used: BODY_L = 6.0 # .236 (6.0), the body's length (front view) BODY_W = 3.5 # .138 (3.5), its depth (side view) TOP = 3.5 # .138 (3.5), the board to the cover's top EAR_H = 0.3 # .012 (0.3), the two end bosses above the cover's top ACT_L = 3.0 # .118 (3.0), the actuator's length (front view) ACT_W = 1.5 # .059 (1.5), its depth (side view) TAIL = 3.5 # .138 (3.5), the terminals' tips below the board PITCH = 6.5 # .256 (6.5), the terminals' centres at the tips OVER = 7.9 # .311 (7.9), over the terminals' bends LEAD_W = 1.0 # .039 (1.0), the terminals' width (side view) LEAD_T = 0.3 # .012 (0.3), their thickness BEND_START = 0.7 # .028 (0.7), the board to where the terminal starts to bend out BEND_APEX = 1.8 # .071 (1.8), the board to the bend's outermost point BEND_END = 2.8 # .110 (2.8), the board to where the terminal is straight again # Proportions, for looks only (the drawing doesn't dimension them; scaled from the drawing, README): the cover's thickness, the end # bosses' size, the corner feet's recesses, and where the terminals leave the housing. COVER_T = 0.3 EAR_L = 1.0 EAR_W = 2.0 RECESS_L = 2.2 RECESS_W = 2.5 RECESS_H = 0.4 LEAD_TOP = 0.8 if kind not in TYPES: raise ValueError(f"no type {kind!r}: {', '.join(TYPES)}") height, overall = TYPES[kind] if abs(height + TAIL - overall) > 0.05: raise ValueError("L1 and L disagree with the 3.5 tail") hx, hy = BODY_L / 2, BODY_W / 2 housing_top = TOP - COVER_T # model.box takes the box's centre; the XZ plane's normal is -Y, so a sketch on it extrudes towards -Y. model = Model() model.box("housing", BODY_L, BODY_W, housing_top - RECESS_H, at=(0, 0, (housing_top + RECESS_H) / 2), op="new", body="housing_body", name="Housing") # Four corner feet: the underside is recessed RECESS_L along X and RECESS_W along Y (front and side views). foot_l = (BODY_L - RECESS_L) / 2 foot_w = (BODY_W - RECESS_W) / 2 for i, (sx, sy) in enumerate(((1, 1), (-1, 1), (-1, -1), (1, -1))): model.box(f"foot_{i + 1}", foot_l, foot_w, RECESS_H + 0.01, at=(sx * (hx - foot_l / 2), sy * (hy - foot_w / 2), (RECESS_H + 0.01) / 2), op="join", body="housing_body", name="Foot") # The two end bosses stand on the cover; they are moulded with the housing, through the cover's end notches. for i, sx in enumerate((1, -1)): model.box(f"ear_{i + 1}", EAR_L, EAR_W, COVER_T + EAR_H + 0.01, at=(sx * (hx - EAR_L / 2), 0, housing_top - 0.01 + (COVER_T + EAR_H + 0.01) / 2), op="join", body="housing_body", name="End boss") # Cover: a plate over the housing with the ends notched round the bosses and an opening for the actuator. model.box("cover", BODY_L, BODY_W, COVER_T, at=(0, 0, housing_top + COVER_T / 2), op="new", body="cover_body", name="Cover") for i, sx in enumerate((1, -1)): model.box(f"cover_notch_{i + 1}", EAR_L + 0.02, EAR_W, COVER_T + 0.2, at=(sx * (hx - EAR_L / 2 + 0.01), 0, housing_top + COVER_T / 2), op="cut", body="cover_body", name="Boss notch") model.box("cover_opening", ACT_L, ACT_W, COVER_T + 0.2, at=(0, 0, housing_top + COVER_T / 2), op="cut", body="cover_body", name="Actuator opening") # Actuator: from the housing's top, through the cover, up to L1. model.box("actuator", ACT_L, ACT_W, height - housing_top, at=(0, 0, (height + housing_top) / 2), op="new", body="actuator_body", name="Actuator") def outline(points, t): """A closed outline around a polyline of straight segments, t thick (mitred corners).""" import math def offset(sign): out = [] for i, (x, y) in enumerate(points): normals = [] segments = ([(points[i - 1], points[i])] if i else []) + ([(points[i], points[i + 1])] if i + 1 < len(points) else []) for a, b in segments: dx, dy = b[0] - a[0], b[1] - a[1] n = math.hypot(dx, dy) normals.append((-dy / n, dx / n)) if len(normals) == 1: nx, ny = normals[0] k = 1.0 else: nx, ny = normals[0][0] + normals[1][0], normals[0][1] + normals[1][1] n = math.hypot(nx, ny) nx, ny = nx / n, ny / n k = 1 / (nx * normals[0][0] + ny * normals[0][1]) out.append((x + sign * nx * k * t / 2, y + sign * ny * k * t / 2)) return out return offset(1) + offset(-1)[::-1] # Terminals 1 (-X) and 2 (+X): a strip 1.0 wide and 0.3 thick down the housing's end face from LEAD_TOP, out to the bends' 7.9 overall # at 1.8 below the board, back in to the 6.5 pitch at 2.8 and straight down to the tip; drawn as an outline in the XZ plane (the strip's # centre line offset by half the thickness) and extruded along Y. x_face = hx + LEAD_T / 2 x_pin = PITCH / 2 x_apex = OVER / 2 - LEAD_T / 2 for _ in range(4): # the mitred outer corner reaches past half the thickness: move the bend in until it sits at OVER / 2 path = [(x_face, LEAD_TOP), (x_face, -BEND_START), (x_apex, -BEND_APEX), (x_pin, -BEND_END), (x_pin, -TAIL)] x_apex -= max(x for x, z in outline(path, LEAD_T)) - OVER / 2 path = [(x_face, LEAD_TOP), (x_face, -BEND_START), (x_apex, -BEND_APEX), (x_pin, -BEND_END), (x_pin, -TAIL)] leads = [] for i, sx in enumerate((-1, 1)): pts = [(sx * x, z) for x, z in path] model.plane(f"lead_{i + 1}_plane", on="XZ", offset=-LEAD_W / 2, name=f"Terminal {i + 1}") with model.sketch(f"lead_{i + 1}_sketch", on=f"lead_{i + 1}_plane", name=f"Terminal {i + 1}") as sk: sk.polyline(f"lead_{i + 1}_outline", outline(pts, LEAD_T), closed=True) model.extrude(f"lead_{i + 1}", f"lead_{i + 1}_sketch", distance=LEAD_W, op="new", body=f"lead_{i + 1}_body", name=f"Terminal {i + 1}") leads.append(f"lead_{i + 1}_body") # Materials (page M3): the case and actuator black thermoplastic (pa6 for both, the sheet names no resin), the cover PET film # (pet; the sheet also lists tin plated brass or stainless steel for covers and brackets), the terminals silver plated brass (brass). model.material("pa6", bodies=["housing_body"], color="#26272a") model.material("pet", bodies=["cover_body"], color="#1c1d20") model.material("pa6", bodies=["actuator_body"], color="#202124") model.material("brass", bodies=leads, color="#d6d8db") result = model.result()