import pcbnew from shapely.geometry import MultiPolygon, Polygon # --------------------------------------------------------------------------- # KiKit postprocess hook – cleanup.py # # 1. Copy all Edge.Cuts content (substrate rings) to Eco1_User as segments, # EXCEPT the outermost panel rectangle. # --------------------------------------------------------------------------- TOLERANCE_NM = 1_000 # 1 µm def _mm(nm_val): return f"{pcbnew.ToMM(int(nm_val)):.4f} mm" def _collect_rings(geom): """Return all rings as list of (shapely_ring, coord_list).""" rings = [] if isinstance(geom, Polygon): rings.append((geom.exterior, list(geom.exterior.coords))) for interior in geom.interiors: rings.append((interior, list(interior.coords))) elif isinstance(geom, MultiPolygon): for poly in geom.geoms: rings.extend(_collect_rings(poly)) return rings def _is_outer_frame(ring_geom, x0, y0, x1, y1, tol=TOLERANCE_NM): """True if the ring's bounding box equals the panel bounding box.""" b = ring_geom.bounds return (abs(b[0] - x0) <= tol and abs(b[1] - y0) <= tol and abs(b[2] - x1) <= tol and abs(b[3] - y1) <= tol) def _shapely_to_segments(board, coords, layer, width_mm=0.05): pts = list(coords) if not pts: return 0 if pts[0] != pts[-1]: pts.append(pts[0]) count = 0 for i in range(len(pts) - 1): seg = pcbnew.PCB_SHAPE(board) seg.SetShape(pcbnew.SHAPE_T_SEGMENT) seg.SetLayer(layer) seg.SetWidth(pcbnew.FromMM(width_mm)) seg.SetStart(pcbnew.VECTOR2I(int(pts[i][0]), int(pts[i][1]))) seg.SetEnd (pcbnew.VECTOR2I(int(pts[i+1][0]), int(pts[i+1][1]))) board.Add(seg) count += 1 return count def kikitPostprocess(panel, arg): print("=" * 60) print("[cleanup] START") board = panel.board substrate = panel.boardSubstrate # outer panel bbox b = substrate.bounds() x0, y0, x1, y1 = int(b[0]), int(b[1]), int(b[2]), int(b[3]) print(f"[cleanup] Panel bbox: ({_mm(x0)},{_mm(y0)})–({_mm(x1)},{_mm(y1)})") # get substrate geometry geom = None for attr in ("substrates", "substrate", "_substrate", "geometry"): if hasattr(substrate, attr): geom = getattr(substrate, attr) break if geom is None: print("[cleanup] ERROR: cannot access substrate geometry") return rings = _collect_rings(geom) print(f"[cleanup] Total rings in substrate: {len(rings)}") total = 0 for i, (ring_geom, coords) in enumerate(rings): rb = ring_geom.bounds if _is_outer_frame(ring_geom, x0, y0, x1, y1): print(f"[cleanup] ring[{i}] pts={len(coords)-1} → OUTER FRAME, skipped") continue n = _shapely_to_segments(board, coords, pcbnew.Eco1_User) total += n print(f"[cleanup] ring[{i}] pts={len(coords)-1}" f" bbox=({_mm(rb[0])},{_mm(rb[1])})–({_mm(rb[2])},{_mm(rb[3])})" f" → {n} segments on Eco1_User") print(f"[cleanup] Total Eco1_User segments added: {total}") print("[cleanup] END") print("=" * 60)