modified kikit script
This commit is contained in:
232
scripts/fixture_postprocess.py
Normal file
232
scripts/fixture_postprocess.py
Normal 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.")
|
||||
Reference in New Issue
Block a user