main
Caleb Publish 0.1.1 231a1c6 1d ago
#!/usr/bin/env python3
"""Adom-built 3D model of the G-Switch GT-USB-7090C (vertical 14-pin USB Type-C receptacle, H 10.50 mm).

Source: G-Switch drawing GT-USB-7090C, REV. X1, design date 2022.08.12, 1 page
        https://www.dg-switch.com/uploads/soft/230131/GT-USB-7090C.pdf (sha256 e9c0f0b1ed179af5...).
Licence of this script and its output: CC-BY-SA-4.0 (Adom). No vendor CAD used (G-Switch publishes none).

Frame = the page footprint frame, per the Adom standard: Z-up, seating plane (PCB top) on z = 0, origin at the
footprint origin (pad-pattern centre), STEP y = -KiCad y (pin A1 at KiCad (0.95, -2.84) -> STEP (0.95, 2.84)).

Printed dimensions used (as printed):
  shell outer 8.94 (front view; product page 8.94 x 3.16) x 3.16 (section 1-1); opening 8.34 +0.06/-0.02 x 2.56 +-0.04
  height above seat 10.50 +-0.15 (front view); shell legs to 11.80 overall -> 1.30 below seat
  posts dia 0.55 at 8.00 +-0.15, to 11.50 +-0.15 -> 1.00 below seat; base 9.00 +-0.15 x 4.30 +-0.15
  shell legs 0.80 +-0.05 wide, 4.74 +-0.10/0.15 apart (long axis); 4.96 +-0.15 over the legs (section 1-1)
  shell sheet thickness 0.30 (= (8.94 - 8.34) / 2 = (3.16 - 2.56) / 2)
  contact tails on the recommended layout pads: rows x = +-0.95, 1.00 pitch, B row 0.32 above A row
Measured off the drawing at 51 px/mm (calibrated on 9.00 = 462 px and 4.96 = 253 px at 300 dpi), not printed:
  base height 1.25 (front view), insert top 5.3 above seat, tongue 6.7 x 0.70, tongue top 0.9 below the shell top,
  leg strap height 0.30. These are simplifications; the model is not a manufacturer model.
usage: gt_usb_7090c_build.py <out.step>
"""
import sys
import cadquery as cq

OUT = sys.argv[1]
H = 10.50            # shell top above seat
SH_L, SH_W, T = 8.94, 3.16, 0.30
BASE_L, BASE_W, BASE_H = 9.00, 4.30, 1.25
LEG_W, LEG_X, LEG_Y, LEG_LOW = 0.80, 2.33, 2.37, -1.30
POST_D, POST_Y, POST_LOW = 0.55, 4.00, -1.00
INSERT_TOP, TONGUE_L, TONGUE_T, TONGUE_TOP = 5.3, 6.7, 0.70, H - 0.9


def stadium(length_y, width_x, h, z0):
    """Stadium (slot) prism: long axis along y, semicircular ends, from z0 up h."""
    return cq.Workplane('XY').workplane(offset=z0).slot2D(length_y, width_x, angle=90).extrude(h)


shell = stadium(SH_L, SH_W, H - BASE_H, BASE_H).cut(stadium(SH_L - 2 * T, SH_W - 2 * T, H - BASE_H + 1, BASE_H - 0.5))
for sx in (-1, 1):
    for sy in (-1, 1):
        leg = (cq.Workplane('XY').box(T, LEG_W, BASE_H + 0.3 - LEG_LOW, centered=(True, True, False))
               .translate((sx * (LEG_X + 0.0), sy * LEG_Y, LEG_LOW)).edges('|Y and <Z').chamfer(0.12))
        x0, x1 = SH_W / 2 - T, LEG_X + T / 2                      # strap from the shell wall out to the leg
        strap = (cq.Workplane('XY').box(x1 - x0, LEG_W, 0.30, centered=(True, True, False))
                 .translate((sx * (x0 + x1) / 2, sy * LEG_Y, BASE_H)))
        shell = shell.union(leg).union(strap)

base = cq.Workplane('XY').box(BASE_W, BASE_L, BASE_H, centered=(True, True, False))
for sy in (-1, 1):
    post = (cq.Workplane('XY').circle(POST_D / 2).extrude(-POST_LOW).translate((0, sy * POST_Y, POST_LOW))
            .faces('<Z').chamfer(0.1))
    base = base.union(post)
insert = stadium(SH_L - 2 * T, SH_W - 2 * T, INSERT_TOP - BASE_H, BASE_H)
tongue = stadium(TONGUE_L, TONGUE_T, TONGUE_TOP - INSERT_TOP, INSERT_TOP)
housing = base.union(insert).union(tongue)

# SMD contact tails, one per recommended-layout pad (KiCad y -> STEP -y)
pads = {'A1': (0.95, -2.84), 'A4': (0.95, -1.84), 'A5': (0.95, -0.84), 'A6': (0.95, 0.16), 'A7': (0.95, 1.16),
        'A9': (0.95, 2.16), 'A12': (0.95, 3.16), 'B1': (-0.95, 2.84), 'B4': (-0.95, 1.84), 'B5': (-0.95, 0.84),
        'B6': (-0.95, -0.16), 'B7': (-0.95, -1.16), 'B9': (-0.95, -2.16), 'B12': (-0.95, -3.16)}
tails = None
for name, (x, y) in pads.items():
    t = cq.Workplane('XY').box(0.80, 0.25, 0.12, centered=(True, True, False)).translate((x, -y, 0))
    tails = t if tails is None else tails.union(t)

asm = cq.Assembly(name='GT-USB-7090C')
asm.add(housing, name='housing', color=cq.Color(0.06, 0.06, 0.07))      # black LCP base/insert (product photo)
asm.add(shell, name='shell', color=cq.Color(0.78, 0.78, 0.80))         # stainless shell
asm.add(tails, name='contacts', color=cq.Color(0.83, 0.69, 0.22))      # plated contact tails
asm.save(OUT, exportType='STEP')
bb = cq.Compound.makeCompound([housing.val(), shell.val(), tails.val()]).BoundingBox()
print(f'bbox x {bb.xmin:.3f}..{bb.xmax:.3f}  y {bb.ymin:.3f}..{bb.ymax:.3f}  z {bb.zmin:.3f}..{bb.zmax:.3f}')