app
KiCad - the KiCad Bridge
Public Made by Adomby adom
Reference implementation of the KiCad bridge: multi-instance Python server, forward path via kicad-cli, reverse path via in-process plugin. Most complex of the three bundled bridges.
master
John Lauer
ESC routing round: planes fixture (GND In1, +3V3 In2), Fable's grid router, offline DRC gate, live replay
f564403
25d ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
#!/usr/bin/env python3
"""Draw a routing plan over the board's pads as a PNG (a quick look without KiCad).
python3 demo/routing/esc/render_plan.py BOARD.kicad_pcb PLAN.json OUT.png [--dpi 300] [--zoom x0,y0,x1,y1]
F.Cu copper red, B.Cu copper blue, vias black rings, pads grey (through pads darker), the outline
black. Plane nets' stubs and vias are drawn like any other copper.
"""
import argparse
import json
import os
import sys
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt # noqa: E402
from matplotlib.patches import Polygon, Circle # noqa: E402
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from escboard import Board # noqa: E402
from write_copper import plan_to_copper # noqa: E402
def main(argv=None):
ap = argparse.ArgumentParser()
ap.add_argument("board")
ap.add_argument("plan")
ap.add_argument("out")
ap.add_argument("--dpi", type=int, default=250)
ap.add_argument("--zoom", help="x0,y0,x1,y1 in mm")
ap.add_argument("--labels", action="store_true", help="print reference designators")
a = ap.parse_args(argv)
board = Board(a.board)
plan = json.load(open(a.plan, encoding="utf-8"))
entries = plan["nets"] if isinstance(plan, dict) else plan
x0, y0, x1, y1 = board.bbox
if a.zoom:
x0, y0, x1, y1 = [float(v) for v in a.zoom.split(",")]
fig, ax = plt.subplots(figsize=((x1 - x0) / 10.0 + 1, (y1 - y0) / 10.0 + 1))
ax.add_patch(Polygon(board.outline, closed=True, fill=False, lw=0.6, ec="black"))
for p in board.pads:
col = "#777777" if p.thru else "#b8b8b8"
for poly in p.polys:
ax.add_patch(Polygon(poly, closed=True, fc=col, ec="none", alpha=0.9))
if p.thru and p.drill:
ax.add_patch(Circle((p.x, p.y), p.drill / 2.0, fc="white", ec="none"))
if a.labels:
for ref, fp in board.footprints.items():
if x0 <= fp["x"] <= x1 and y0 <= fp["y"] <= y1:
ax.text(fp["x"], fp["y"], ref, fontsize=3, ha="center", va="center", color="#333333")
for e in entries:
segs, vias = plan_to_copper(board, e)
for sx, sy, ex, ey, layer, w in segs:
col = "#d0342c" if layer == "F.Cu" else "#2c6fd0"
ax.plot([sx, ex], [sy, ey], color=col, lw=w * 72.0 / 25.4 * (a.dpi / 72.0) * 0.5, solid_capstyle="round", alpha=0.85, zorder=3 if layer == "F.Cu" else 2)
for vx, vy, size, drill in vias:
ax.add_patch(Circle((vx, vy), size / 2.0, fc="#222222", ec="none", zorder=4))
ax.add_patch(Circle((vx, vy), drill / 2.0, fc="white", ec="none", zorder=5))
ax.set_xlim(x0, x1)
ax.set_ylim(y1, y0)
ax.set_aspect("equal")
ax.axis("off")
fig.tight_layout(pad=0.1)
fig.savefig(a.out, dpi=a.dpi)
print(a.out)
if __name__ == "__main__":
main()