main
Caleb Publish 0.1.1 4e55566 1d ago
#!/usr/bin/env python3
"""Evidence overlays: the built STEP projected orthographically at the drawing's own scale, drawn in translucent red
over Samtec's print (rendered at 1200 dpi). usage: overlay.py <step> <print.pdf> <outdir>"""
import os, subprocess, sys
import numpy as np
import cadquery as cq
from PIL import Image, ImageDraw

step, pdf, out = sys.argv[1:4]
os.makedirs(out, exist_ok=True)
shape = cq.importers.importStep(step)
tris = []
for sol in shape.solids().vals():
    vs, fs = sol.tessellate(0.01, 0.2)
    V = np.array([(v.x, v.y, v.z) for v in vs])
    for f in fs:
        tris.append(V[list(f)])
tris = np.array(tris)


def crop(page, x, y, w, h, name):
    base = os.path.join(out, name)
    subprocess.run(['pdftoppm', '-r', '1200', '-f', str(page), '-l', str(page), '-x', str(x), '-y', str(y), '-W', str(w),
                    '-H', str(h), '-png', '-singlefile', pdf, base], check=True)
    return Image.open(base + '.png').convert('RGB')


def overlay(img, axes, px_mm, origin_px, flip_h, name, label):
    """axes: (i, j) model axes for image (right, up); origin_px: pixel of model (0, 0) in that plane."""
    ov = Image.new('RGBA', img.size, (0, 0, 0, 0)); d = ImageDraw.Draw(ov)
    i, j = axes
    for t in tris:
        pts = [(origin_px[0] + (-1 if flip_h else 1) * p[i] * px_mm, origin_px[1] - p[j] * px_mm) for p in t]
        d.polygon(pts, fill=(255, 0, 0, 40))
    res = Image.alpha_composite(img.convert('RGBA'), ov).convert('RGB')
    ImageDraw.Draw(res).text((10, 10), label, fill=(200, 0, 0))
    res.save(os.path.join(out, name))


# 1. Sheet 1 Fig 1 end view (5:1, 236.2 px/mm at 1200 dpi): seating plane at y=1197, body centre x=506.5 in this crop
img = crop(1, 8618, 6545, 982, 1310, 'sheet1_fig1_end')
overlay(img, (0, 2), 236.22, (506.5, 1197), False, 'overlay_fig1_end_view.png',
        'model (red) over Samtec FTSH print rev FQ sheet 1 Fig 1 end view, 236.2 px/mm')
# 2. Sheet 2 Fig 2 top view (3:1, 141.7 px/mm). The print shows an 8-position -K part; the key is centred on the
#    centreline (x=750 here), so only the key and the pitch around it are comparable. Rows run horizontally there,
#    row 02 on top: model Y (columns) -> image right is model -Y? pin 1 column is at the left end of the print, our
#    pin 1 is at +Y, so image right = -Y; image up = +X (row 02 = even contacts at +X).
img = crop(2, 1440, 780, 1920, 3180, 'sheet2_fig2_top')
ov = Image.new('RGBA', img.size, (0, 0, 0, 0)); d = ImageDraw.Draw(ov)
px = 141.73; ox, oy = 750, (381.5 + 867.5) / 2
for t in tris:
    if t[:, 2].max() < 2.9 and t[:, 2].min() > 0.5:   # skip nothing; full silhouette
        pass
    pts = [(ox - p[1] * px, oy - p[0] * px) for p in t]
    d.polygon(pts, fill=(255, 0, 0, 30))
res = Image.alpha_composite(img.convert('RGBA'), ov).convert('RGB').crop((0, 150, 1500, 1100))
ImageDraw.Draw(res).text((10, 10), 'model (red, 7 positions) over Samtec print sheet 2 Fig 2 top view (8 positions shown), 141.7 px/mm, centred on CL',
                         fill=(200, 0, 0))
res.save(os.path.join(out, 'overlay_fig2_top_view.png'))
print('ok')