main
John Lauer Add KiCad symbol and footprint, viewers, provenance, README, models.json and verification log 354b2dd 11h ago
#!/usr/bin/env python3
"""Overlay proof: the model rendered orthographically at the datasheet drawing's own scale, blended over the
Melexis MLX90614 datasheet Rev 021 p.49 Figure 45 (MLX90614xCI): side view and bottom view.
Red outline + blue fill = model silhouette; black = datasheet drawing.

usage: overlay.py model.step page49_400dpi.png out.png
Scale: 44.5 px/mm at 400 dpi, calibrated on the printed Ø9.00 (401 px) and 20.20 (899 px) dimensions.
"""
import sys
import numpy as np
import cadquery as cq
from PIL import Image, ImageDraw, ImageFilter, ImageChops, ImageFont

step, page, out = sys.argv[1:4]
K = 44.5
CX, CY, ZTOP = 2.54, 0.0, 20.58
SIDE_AXIS_X, SIDE_TOP_Y = 1616.5, 936.0          # drawing side view: can axis column, top row
BOT_C = (264 + 325 * 2944 / 2000, 654 + 413 * 2944 / 2000)  # drawing bottom view centre (page px)

shape = cq.importers.importStep(step).val()
verts, tris = shape.tessellate(0.01, 0.2)
V = np.array([[v.x, v.y, v.z] for v in verts])
T = np.array(tris)
img = Image.open(page).convert('RGB')
W, H = img.size


def silhouette(proj):
    m = Image.new('L', (W, H), 0)
    d = ImageDraw.Draw(m)
    P = proj(V)
    for t in T:
        d.polygon([tuple(P[i]) for i in t], fill=255)
    return m


def side(Vv):
    return np.stack([SIDE_AXIS_X + (Vv[:, 0] - CX) * K, SIDE_TOP_Y + (ZTOP - Vv[:, 2]) * K], 1)


def bottom(Vv):
    dx, dy = Vv[:, 0] - CX, Vv[:, 1] - CY
    u, v = dy, dx            # mirror for the bottom view, then turn so the tab sits where Melexis drew it
    return np.stack([BOT_C[0] + u * K, BOT_C[1] - v * K], 1)


def blend(mask, base):
    fill = Image.new('RGB', (W, H), (60, 110, 255))
    a = mask.point(lambda p: 70 if p else 0)
    base = Image.composite(fill, base, a)
    edge = ImageChops.subtract(mask.filter(ImageFilter.MaxFilter(5)), mask)
    red = Image.new('RGB', (W, H), (230, 30, 30))
    base = Image.composite(red, base, edge)
    # keep the drawing's black lines on top
    dark = img.convert('L').point(lambda p: 255 if p < 110 else 0)
    return Image.composite(Image.new('RGB', (W, H), (0, 0, 0)), base, dark)


# bottom view: only the part below the header (leads cut at the seating plane, header, tab)
Vb = V.copy()
base = blend(silhouette(side), img)
base = blend(silhouette(bottom), base)
crop = base.crop((240, 640, 3230, 2560))
dr = ImageDraw.Draw(crop)
try:
    f = ImageFont.truetype('DejaVuSans.ttf', 34)
except Exception:
    f = ImageFont.load_default()
dr.text((20, 1870), 'Model (blue fill, red outline) over Melexis MLX90614 datasheet Rev 021 p.49 Figure 45 (xCI), 44.5 px/mm',
        fill=(200, 20, 20), font=f)
crop.save(out)
print('OK', out, crop.size)