modified kikit script

This commit is contained in:
cpu
2026-05-20 18:03:49 +02:00
parent 7c739130d2
commit b14223904c
33 changed files with 46630 additions and 24262 deletions

View File

@@ -0,0 +1,232 @@
import math
import pcbnew
from shapely.affinity import translate
# ============================================================
# Fixture geometry
# ============================================================
OUTER_W_MM = 200.0
OUTER_H_MM = 130.0
INNER_W_MM = 153.4
INNER_H_MM = 87.0
INNER_X_MM = (OUTER_W_MM - INNER_W_MM) / 2 # 23.3
INNER_Y_MM = (OUTER_H_MM - INNER_H_MM) / 2 # 21.5
# ============================================================
# Alignment pins
# Absolute fixture-space coordinates in millimetres
# ============================================================
PIN_DIAMETER_MM = 3.172
# Suggested defaults:
# top = centered in top rail
# right = centered in right rail
# bottom = centered in bottom rail
# left = centered in left rail
PIN1_X_MM = 100.0
PIN1_Y_MM = 10.75
PIN2_X_MM = 188.35
PIN2_Y_MM = 65.0
PIN3_X_MM = 100.0
PIN3_Y_MM = 119.25
PIN4_X_MM = 11.65
PIN4_Y_MM = 65.0
# KiCad internal unit: 1 mm = 1 000 000 nm
MM = 1_000_000
def mm(v: float) -> int:
"""Convert mm float to KiCad internal units (nm)."""
return int(round(v * MM))
def _move_all(panel, dx_nm: int, dy_nm: int) -> None:
"""Translate every object on the board by (dx_nm, dy_nm)."""
vec = pcbnew.VECTOR2I(dx_nm, dy_nm)
for fp in panel.board.GetFootprints():
fp.Move(vec)
for track in panel.board.GetTracks():
track.Move(vec)
for drawing in panel.board.GetDrawings():
drawing.Move(vec)
for zone in panel.board.Zones():
zone.Move(vec)
# Keep the Shapely substrate in sync
panel.boardSubstrate.substrates = translate(
panel.boardSubstrate.substrates,
xoff=dx_nm,
yoff=dy_nm,
)
def _edge_cuts_bbox(panel):
"""Return (minx, miny, maxx, maxy) in nm from the Shapely substrate."""
return panel.boardSubstrate.substrates.bounds # already in nm
def _draw_rect(board, layer, x0_nm, y0_nm, x1_nm, y1_nm, width_nm=None):
"""Draw an axis-aligned rectangle on *layer* using four PCB_SHAPE lines."""
if width_nm is None:
width_nm = mm(0.1) # 0.1 mm line width thin reference line
corners = [
(x0_nm, y0_nm), (x1_nm, y0_nm),
(x1_nm, y1_nm), (x0_nm, y1_nm),
]
for i in range(4):
seg = pcbnew.PCB_SHAPE(board)
seg.SetShape(pcbnew.SHAPE_T_SEGMENT)
seg.SetLayer(layer)
seg.SetWidth(width_nm)
x_a, y_a = corners[i]
x_b, y_b = corners[(i + 1) % 4]
seg.SetStart(pcbnew.VECTOR2I(x_a, y_a))
seg.SetEnd(pcbnew.VECTOR2I(x_b, y_b))
board.Add(seg)
def _draw_circle(board, layer, cx_nm, cy_nm, r_nm, width_nm=None):
"""Draw a circle on *layer*."""
if width_nm is None:
width_nm = mm(0.1)
circ = pcbnew.PCB_SHAPE(board)
circ.SetShape(pcbnew.SHAPE_T_CIRCLE)
circ.SetLayer(layer)
circ.SetWidth(width_nm)
circ.SetCenter(pcbnew.VECTOR2I(cx_nm, cy_nm))
circ.SetEnd(pcbnew.VECTOR2I(cx_nm + r_nm, cy_nm))
board.Add(circ)
def _add_pin_footprint(board, x_nm, y_nm, diameter_mm, index):
"""
Add a non-plated through-hole (NPTH) mounting hole footprint at (x_nm, y_nm).
We create a minimal footprint with a single NPTH pad so that:
• The drill appears in the Excellon output → used for physical alignment pins.
• No copper ring is added.
"""
fp = pcbnew.FOOTPRINT(board)
fp.SetReference(f"PIN{index}")
fp.Reference().SetVisible(False)
fp.SetValue(f"Ø{diameter_mm:.3f}mm NPTH")
fp.Value().SetVisible(False)
fp.SetPosition(pcbnew.VECTOR2I(x_nm, y_nm))
pad = pcbnew.PAD(fp)
pad.SetAttribute(pcbnew.PAD_ATTRIB_NPTH)
pad.SetShape(pcbnew.PAD_SHAPE_CIRCLE)
pad.SetDrillShape(pcbnew.PAD_DRILL_SHAPE_CIRCLE)
d_nm = mm(diameter_mm)
pad.SetSize(pcbnew.VECTOR2I(d_nm, d_nm))
pad.SetDrillSize(pcbnew.VECTOR2I(d_nm, d_nm))
pad.SetLayerSet(pcbnew.LSET.AllCuMask()) # NPTH pads span all Cu layers
pad.SetNumber("")
fp.Add(pad)
board.Add(fp)
# Also draw a circle on Dwgs_User so the pin is visible even without
# the fab/courtyard layers being turned on.
_draw_circle(
board,
pcbnew.Dwgs_User,
x_nm, y_nm,
mm(diameter_mm / 2),
mm(0.1),
)
return fp
# ──────────────────────────────────────────────────────────────
# MAIN ENTRY POINT
# ──────────────────────────────────────────────────────────────
def kikitPostprocess(panel, args):
board = panel.board
# ── Step 1: get current Edge.Cuts bounding box ────────────────────────────
bounds = _edge_cuts_bbox(panel) # (minx, miny, maxx, maxy) in nm
panel_w_nm = bounds[2] - bounds[0]
panel_h_nm = bounds[3] - bounds[1]
panel_w_mm = panel_w_nm / MM
panel_h_mm = panel_h_nm / MM
print(f"[fixture] Panel size: {panel_w_mm:.3f} x {panel_h_mm:.3f} mm")
# ── Step 2: compute where panel top-left should land ─────────────────────
# We want the panel centred inside the inner opening of the fixture.
# Inner opening: top-left is at (INNER_X_MM, INNER_Y_MM) relative to
# the fixture outer top-left.
panel_target_x_mm = INNER_X_MM + (INNER_W_MM - panel_w_mm) / 2
panel_target_y_mm = INNER_Y_MM + (INNER_H_MM - panel_h_mm) / 2
print(f"[fixture] Panel will be placed at ({panel_target_x_mm:.3f}, {panel_target_y_mm:.3f}) mm")
# Warn if the panel is larger than the inner opening (it will still be
# centred but will overlap the frame rails).
if panel_w_mm > INNER_W_MM or panel_h_mm > INNER_H_MM:
print(
f"[fixture] WARNING: panel ({panel_w_mm:.1f}×{panel_h_mm:.1f} mm) "
f"is larger than the inner opening ({INNER_W_MM}×{INNER_H_MM} mm)!"
)
# ── Step 3: move everything so that the panel lands at the target ─────────
# Current panel TL is at (bounds[0], bounds[1]).
# We need to shift by (target - current).
dx_nm = mm(panel_target_x_mm) - bounds[0]
dy_nm = mm(panel_target_y_mm) - bounds[1]
_move_all(panel, int(dx_nm), int(dy_nm))
# ── Step 4: verify final position ────────────────────────────────────────
new_bounds = _edge_cuts_bbox(panel)
print(
f"[fixture] Panel TL after move: "
f"({new_bounds[0]/MM:.3f}, {new_bounds[1]/MM:.3f}) mm"
)
# ── Step 5: draw fixture frame on Dwgs_User ───────────────────────────
# Outer rectangle: (0,0) → (200, 130) mm
_draw_rect(
board, pcbnew.Dwgs_User,
mm(0), mm(0),
mm(OUTER_W_MM), mm(OUTER_H_MM),
mm(0.15),
)
# Inner rectangle: (23.3, 21.5) → (176.7, 108.5) mm
_draw_rect(
board, pcbnew.Dwgs_User,
mm(INNER_X_MM), mm(INNER_Y_MM),
mm(INNER_X_MM + INNER_W_MM), mm(INNER_Y_MM + INNER_H_MM),
mm(0.15),
)
print("[fixture] Fixture frame drawn on Dwgs_User layer.")
# ── Step 6: add alignment pin footprints ──────────────────────────────────
# Place pins at the absolute coordinates defined in the configuration block above
pin_positions_mm = [
(PIN1_X_MM, PIN1_Y_MM, "PIN1 (Top)"),
(PIN2_X_MM, PIN2_Y_MM, "PIN2 (Right)"),
(PIN3_X_MM, PIN3_Y_MM, "PIN3 (Bottom)"),
(PIN4_X_MM, PIN4_Y_MM, "PIN4 (Left)"),
]
for idx, (px_mm, py_mm, label) in enumerate(pin_positions_mm, start=1):
_add_pin_footprint(board, mm(px_mm), mm(py_mm), PIN_DIAMETER_MM, idx)
print(
f"[fixture] {label} placed at "
f"({px_mm:.3f}, {py_mm:.3f}) mm"
)
print("[fixture] Post-processing complete.")