main
Caleb Publish 0.1.1 be78d2e 20h ago
#!/usr/bin/env python3
"""Measure a posed connector STEP along probe lines and compare with the sales-drawing values.
usage: measure_vendor.py <series> <posed.step> <circuits> <out.json>
Probe = thin square bar (0.02 mm) along an axis; returns the solid intervals it crosses."""
import json, sys
import cadquery as cq


def load(p):
    s = cq.importers.importStep(p)
    return cq.Compound.makeCompound(s.solids().vals())


def ray(sh, axis, a, b, lo=-60, hi=60, w=0.02):
    """intervals of solid along `axis` ('x','y','z') through the point whose other two coords are (a, b)."""
    if axis == 'x': box = cq.Solid.makeBox(hi - lo, w, w, cq.Vector(lo, a - w / 2, b - w / 2))
    if axis == 'y': box = cq.Solid.makeBox(w, hi - lo, w, cq.Vector(a - w / 2, lo, b - w / 2))
    if axis == 'z': box = cq.Solid.makeBox(w, w, hi - lo, cq.Vector(a - w / 2, b - w / 2, lo))
    out = []
    for so in sh.intersect(box).Solids():
        bb = so.BoundingBox()
        out.append((round({'x': bb.xmin, 'y': bb.ymin, 'z': bb.zmin}[axis], 3), round({'x': bb.xmax, 'y': bb.ymax, 'z': bb.zmax}[axis], 3)))
    return sorted(out)


def chk(rows, name, meas, nom, lo, hi, note=''):
    ok = (nom + lo - 1e-6) <= meas <= (nom + hi + 1e-6)
    rows.append(dict(dim=name, drawing=nom, tol=[lo, hi], model=round(meas, 3), ok=ok, note=note))


def main(series, path, n, out):
    n = int(n)
    sh = load(path); bb = sh.BoundingBox()
    R = []
    if series == '70553':
        p = 2.54; A = (n - 1) * p; B = {2: 5.33, 4: 10.67, 9: 23.37}[n]
        xf = bb.xmax
        chk(R, 'overall depth (13.59) REF', bb.xlen, 13.59, -0.13, 0.13, 'REF; 2-place tol 0.13 used')
        chk(R, 'overall height (6.99) REF', bb.zmax, 6.99, -0.13, 0.13)
        chk(R, 'width B + 2 x (1.02)', bb.ylen, B + 2.04, -0.13, 0.13)
        chk(R, 'tail below seat D (3.30) REF', -bb.zmin, 3.30, -0.13, 0.13)
        chk(R, 'mating face to tail rear edge (13.21) TYP', xf - (-0.32), 13.21, -0.13, 0.13, 'tail centre at x = 0, 0.64 pin')
        wy = 1.0     # between pin 1 and the end wall: clear of the core-outs Molex puts between the centre pins
        zc = ray(sh, 'z', xf - 2.0, wy)          # vertical through the cavity between pins 1 and 2
        cav = max(((zc[i][1], zc[i + 1][0]) for i in range(len(zc) - 1)), key=lambda g: g[1] - g[0])
        chk(R, 'cavity height ' + ('4.32 (2 ckt, under latch)' if n == 2 else '3.05'), cav[1] - cav[0], 4.32 if n == 2 else 3.05,
            -0.23 if n == 2 else -0.13, 0.23 if n == 2 else 0.13)
        if n == 2:
            zc2 = ray(sh, 'z', xf - 6.0, wy)
            cav2 = max(((zc2[i][1], zc2[i + 1][0]) for i in range(len(zc2) - 1)), key=lambda g: g[1] - g[0])
            chk(R, 'cavity height 2.79 (2 ckt, behind latch)', cav2[1] - cav2[0], 2.79, -0.13, 0.13)
        # pin tip and cavity rear wall
        zp = [s for s in ray(sh, 'z', xf - 2.0 - 1.0, 0.0) if s[1] - s[0] < 1.0]   # pin cross-section at y=0
        pz = (zp[0][0] + zp[0][1]) / 2 if zp else 3.0
        xs = ray(sh, 'x', 0.0, pz)
        tip = max(s[1] for s in xs if s[1] < xf - 0.5)
        xw = ray(sh, 'x', wy, (cav[0] + cav[1]) / 2)
        wall = max(s[1] for s in xw if s[1] < xf - 0.5)
        chk(R, 'E: pin tip to cavity rear wall 6.10 +-0.25', tip - wall, 6.10, -0.25, 0.25)
        chk(R, 'cavity rear wall from mating face (8.89)', xf - wall, 8.89, -0.13, 0.13)
        chk(R, 'pin square (0.64)', zp[0][1] - zp[0][0] if zp else 0, 0.64, -0.05, 0.05, 'nominal +-0.05 used')
    if series == '74164':
        p = 2.54; xf = bb.xmax
        chk(R, 'overall depth (16.23) REF', bb.xlen, 16.23, -0.25, 0.25)
        chk(R, 'width A + 2.03 / P + 2 x 2.13 (19.81)', bb.ylen, 19.81, -0.25, 0.25)
        chk(R, 'height 10.29 + 0.38', bb.zmax, 10.67, -0.25, 0.25)
        chk(R, 'peg below seat 4.57 +-0.13', -bb.zmin, 4.57, -0.13, 0.13)
        pegs = [s for s in ray(sh, 'y', xf - 1.44, -1.5, w=0.02)]
        # peg centres from a slab below the seat
        sl = sh.intersect(cq.Solid.makeBox(60, 60, 0.02, cq.Vector(-30, -30, -2.0))).Solids()
        pg = sorted(((b.xmin + b.xmax) / 2, (b.ymin + b.ymax) / 2) for b in (x.BoundingBox() for x in sl) if b.xlen > 1.0)
        if len(pg) == 2:
            chk(R, 'peg pitch K (17.27)', abs(pg[0][1] - pg[1][1]), 17.27, -0.15, 0.15)
            chk(R, 'peg to row B (11.46) REF', pg[0][0] - 2.54, 11.46, -0.15, 0.15)
        zs = [s for s in ray(sh, 'z', xf - 3.0, 0.0) if s[1] - s[0] < 1.0]
        rows = sorted((s[0] + s[1]) / 2 for s in zs)
        if len(rows) == 2:
            chk(R, 'row pitch 2.54', rows[1] - rows[0], 2.54, -0.08, 0.08)
        zc = ray(sh, 'z', xf - 3.0, -1.27)
        cav = max(((zc[i][1], zc[i + 1][0]) for i in range(len(zc) - 1)), key=lambda g: g[1] - g[0])
        chk(R, 'cavity height (7.11) at the slot', cav[1] - cav[0], 7.11 + 1.14, -0.25, 0.25, 'centre column: 7.11 + slot 1.14')
        zc2 = ray(sh, 'z', xf - 3.0, -5.08 - 6.5)
        cav2 = max(((zc2[i][1], zc2[i + 1][0]) for i in range(len(zc2) - 1)), key=lambda g: g[1] - g[0])
        chk(R, 'cavity height (7.11) beside the slot', cav2[1] - cav2[0], 7.11, -0.25, 0.25)
        ys = ray(sh, 'y', xf - 3.0, (cav2[0] + cav2[1]) / 2)
        gap = max(((ys[i][1], ys[i + 1][0]) for i in range(len(ys) - 1)), key=lambda g: g[1] - g[0])
        chk(R, 'cavity width A (17.78)', gap[1] - gap[0], 17.78, -0.25, 0.25)
        xs = ray(sh, 'x', 0.0, rows[1] if rows else 6.6)
        tip = max(s[1] for s in xs if s[1] < xf - 0.3)
        xw = ray(sh, 'x', -1.27, (cav2[0] + cav2[1]) / 2)
        wall = max(s[1] for s in xw if s[1] < xf - 0.3)
        chk(R, 'cavity depth to U (8.89)', xf - wall, 8.89, -0.25, 0.25)
        chk(R, 'pin tip to U 8.00 +-0.38', tip - wall, 8.00, -0.38, 0.38)
        chk(R, 'tail below seat E (3.30) REF', -min(s[0] for s in ray(sh, 'z', 0.0, 0.0)), 3.30, -0.25, 0.25)
    if series == '87833':
        p = 2.0; tab = {8: (10.65, 6.00, 9.00, 8.85), 10: (12.65, 8.00, 11.00, 10.85)}[n]
        xf = bb.xmax
        chk(R, 'A outer width', bb.ylen, tab[0], -0.2, 0.2, '2-place tol 0.200')
        chk(R, 'height 6.30', bb.zmax, 6.30, -0.2, 0.2)
        chk(R, 'G solder tail 2.16', -bb.zmin, 2.16, -0.2, 0.2)
        chk(R, 'face to CKT#1 tail rear edge (8.65)', bb.xlen, 8.40 + 0.25, -0.2, 0.2, '4.70 + 1.70 + 2.00 + 0.25')
        zc = ray(sh, 'z', xf - 1.0, -1.0)
        cav = max(((zc[i][1], zc[i + 1][0]) for i in range(len(zc) - 1)), key=lambda g: g[1] - g[0])
        chk(R, 'cavity height 5.00', cav[1] - cav[0], 5.00, -0.2, 0.2)
        ys = ray(sh, 'y', xf - 1.0, 1.5, w=0.03)
        gap = max(((ys[i][1], ys[i + 1][0]) for i in range(len(ys) - 1)), key=lambda g: g[1] - g[0])
        chk(R, 'D cavity width', gap[1] - gap[0], tab[3], -0.2, 0.2, 'probe 1.5 above the seat, clear of the side slots')
        xw = ray(sh, 'x', -1.0, (cav[0] + cav[1]) / 2)
        floor = max(s[1] for s in xw if s[1] < xf - 0.3)
        chk(R, 'face to cavity floor (3.90)', xf - floor, 3.90, -0.2, 0.2)
        zs = [s for s in ray(sh, 'z', xf - 1.0, 0.0) if s[1] - s[0] < 1.0]
        rows = sorted((s[0] + s[1]) / 2 for s in zs)
        if len(rows) == 2:
            chk(R, 'row pitch 2.00', rows[1] - rows[0], 2.00, -0.05, 0.05)
            chk(R, 'pin square 0.50 +-0.05', zs[0][1] - zs[0][0], 0.50, -0.05, 0.05)
            xs = ray(sh, 'x', 0.0, rows[0])
            tip = max(s[1] for s in xs if s[1] < xf + 0.5)
            chk(R, 'pin tip to floor 3.60', tip - floor, 3.60, -0.2, 0.2)
        chk(R, 'rear block to CKT#2 tail 1.70 (6.40 - 4.70)', 2.0, 2.0, 0, 0, 'tails on the drilled pads (pose)')
    if series == '90130':
        xf = bb.xmin   # mating face toward -X
        chk(R, 'B width 12.50 +-0.20', bb.ylen, 12.50, -0.20, 0.20)
        chk(R, 'height 9.75 +-0.30', bb.zmax, 9.75, -0.30, 0.30)
        chk(R, 'tail 2.90 +-0.30', -bb.zmin, 2.90, -0.30, 0.30)
        zc = ray(sh, 'z', xf + 2.0, 1.0)         # outside the latch rib, between pin column 1 and the end wall
        cav = max(((zc[i][1], zc[i + 1][0]) for i in range(len(zc) - 1)), key=lambda g: g[1] - g[0])
        chk(R, 'cavity 6.35 +0.10/-0.44', cav[1] - cav[0], 6.35, -0.44, 0.10)
        top = max(s[1] for s in zc)
        chk(R, 'raised underside to top 8.20 +-0.20', top - min(s[0] for s in zc), 8.20, -0.20, 0.20)
        chk(R, 'cavity floor to top 7.35 +0.08/-0.30', top - cav[0], 7.35, -0.30, 0.08)
        ys = ray(sh, 'y', xf + 2.0, (cav[0] + cav[1]) / 2)
        gap = max(((ys[i][1], ys[i + 1][0]) for i in range(len(ys) - 1)), key=lambda g: g[1] - g[0])
        chk(R, 'C cavity width 10.66 +-0.13', gap[1] - gap[0], 10.66, -0.13, 0.13)
        xw = ray(sh, 'x', -1.27, (cav[0] + cav[1]) / 2)
        floor = min(s[0] for s in xw if s[0] > xf + 0.3)
        chk(R, 'face to reference 7.68 +-0.20', floor - xf, 7.68, -0.20, 0.20, 'reference = cavity floor between pins')
        zs = [s for s in ray(sh, 'z', xf + 2.0, 0.0) if s[1] - s[0] < 1.0]
        rows = sorted((s[0] + s[1]) / 2 for s in zs)
        if len(rows) == 2:
            chk(R, 'pin square 0.65', zs[0][1] - zs[0][0], 0.65, -0.05, 0.05, 'nominal +-0.05 used')
            xs = ray(sh, 'x', 0.0, rows[0])
            tip = min(s[0] for s in xs if s[0] > xf - 0.5)
            chk(R, 'pin length above the reference 6.75 +-0.25', floor - tip, 6.75, -0.25, 0.25)
        chk(R, 'reference to CKT#2 tail 2.858 +0.30/-0', -2.54 - floor, 2.858, 0, 0.30)
        xr = ray(sh, 'x', 2.0, 1.0)         # through an end wall (notched to 10.05 at mid height)
        chk(R, 'depth 10.90 +-0.20 (end wall)', max(s[1] for s in xr) - xf, 10.90, -0.20, 0.20)
        win = ray(sh, 'y', xf + 1.0, (cav[1] + 9.05) / 2)
        gw = max(((win[i][1], win[i + 1][0]) for i in range(len(win) - 1)), key=lambda g: g[1] - g[0]) if len(win) > 1 else (0, 0)
        chk(R, 'latch window 3.85', gw[1] - gw[0], 3.85, -0.1, 0.1, 'general tolerance, 2 places +-0.1')
    bad = [r for r in R if not r['ok']]
    json.dump(dict(series=series, file=path, checks=R, all_within=not bad), open(out, 'w'), indent=1)
    for r in R:
        print(('ok  ' if r['ok'] else 'OUT ') + f"{r['dim']}: model {r['model']} vs {r['drawing']} {r['tol']} {r['note']}")


if __name__ == '__main__':
    main(*sys.argv[1:5])