# -*- coding: utf-8 -*- u"""离线画底板摆位(背面 L4,从上往下看):两种 Hub 走廊并排,给用户对比。 /c/Python314/python .claude/r2/plot_base.py # 定稿(走廊 2)vs 草图原样(走廊 3) /c/Python314/python .claude/r2/plot_base.py --one # 只画定稿(走廊 2) 不碰 EasyEDA:直接调 `place_base.plan()`。背面件是**镜像后的真实本体框**(`body_rect` 已含翻面)。 """ import importlib import os import sys HERE = os.path.dirname(os.path.abspath(__file__)) sys.path.insert(0, os.path.dirname(HERE)) sys.path.insert(0, HERE) import matplotlib # noqa: E402 matplotlib.use('Agg') import matplotlib.pyplot as plt # noqa: E402 from matplotlib.patches import Rectangle, Polygon, Circle # noqa: E402 import pcb_base as B # noqa: E402 plt.rcParams['font.sans-serif'] = ['Microsoft YaHei', 'SimHei', 'DejaVu Sans'] plt.rcParams['axes.unicode_minus'] = False ZCOL = {'A1': '#f4b6a0', 'A2': '#fcdcc8', 'A3': '#c9c3e0', 'A5': '#a8d1e6', 'A6': '#cfe3ef', 'A4H': '#8fc3dd', 'A4M': '#bdb3db'} def plan_for(hub3): argv = sys.argv[:] sys.argv = [a for a in argv if a != '--hub3'] + (['--hub3'] if hub3 else []) import place_base as P P = importlib.reload(P) sys.argv = argv pos, unplaced, sz, _aim = P.plan() bad = P.selfcheck(pos, unplaced, sz) return P, pos, sz, bad def draw(ax, P, pos, sz, bad): nat = P.native() pg = P.page_of() ax.add_patch(Polygon(B.outline_pts(), closed=True, fill=False, lw=1.2, ec='black')) for i in range(1, B.SLOT_N + 1): b = B.slot_body(i) ax.add_patch(Rectangle((b[0], b[1]), b[2] - b[0], b[3] - b[1], fill=True, fc='#eeeeee', ec='#888888', ls='--', lw=0.6, hatch='////', alpha=0.6)) ref = B.USB_SLOT_REF[B.SLOT_N + 1 - i] ax.text(b[2] + 0.4, (b[1] + b[3]) / 2, u'%s\n(L1)' % ref, fontsize=5, color='#666666', va='center') # D± 脚(南排 x 47.5/48.5) for u in (-1.5, -0.5): ax.add_patch(Rectangle((B.pin_x(u) - 0.35, B.slot_y(i) - B.PAD_ROW_DY - 1.0), 0.7, 2.0, fc='#7b3fa0', ec='none')) for name, r in P.LANES.items(): col = '#b58ad6' if name.startswith('DP') else ('#7cc47c' if name.startswith('I2C') else '#f0a040') ax.add_patch(Rectangle((r[0], r[1]), r[2] - r[0], r[3] - r[1], fc=col, ec='none', alpha=0.35)) for k, z in P.ZONES.items(): ax.add_patch(Rectangle((z[0], z[1]), z[2] - z[0], z[3] - z[1], fill=False, ec='#555555', ls=':', lw=0.6)) ax.text(z[0] + 0.3, z[3] - 0.3, k, fontsize=6, va='top', color='#333333', weight='bold') n = B.notch_rect() ax.add_patch(Rectangle((n[0], n[1]), n[2] - n[0], n[3] - n[1], fc='white', ec='black', hatch='xx')) a = P.antenna_keepout(sz, pos) ax.add_patch(Rectangle((a[0], a[1]), a[2] - a[0], a[3] - a[1], fill=False, ec='red', ls='--', lw=0.6)) for _n, (hx, hy) in B.MOUNT_HOLES.items(): ax.add_patch(Circle((hx, hy), B.HOLE_D / 2, fc='white', ec='black')) for ref, (x, y, rot) in pos.items(): if P.layer_of(ref) != B.BOTTOM: continue r = P.body_rect(ref, x, y, rot, sz) z = P.zone_of_ref(ref, pg) if ref in pg else None ax.add_patch(Rectangle((r[0], r[1]), r[2] - r[0], r[3] - r[1], fc=ZCOL.get(z, '#dddddd'), ec='#333333', lw=0.4)) big = (r[2] - r[0]) * (r[3] - r[1]) > 9 ax.text((r[0] + r[2]) / 2, (r[1] + r[3]) / 2, ref, fontsize=5.5 if big else 3.2, ha='center', va='center', weight='bold' if big else 'normal') # U32 下行口(USB1..5 的 DP 脚) ux, uy, ur = pos['U32'] for pn, _nn, px, py in P.pads_at(nat, 'U32', ux, uy, ur): if pn in ('2', '4', '7', '9', '12'): ax.plot(px, py, 'o', ms=2.2, color='#7b3fa0') ax.text(px, py + 0.5, 'USB%d' % {'2': 1, '4': 2, '7': 3, '9': 4, '12': 5}[pn], fontsize=3.5, color='#7b3fa0', ha='center', rotation=90, va='bottom') L = P.dp_lengths(pos, nat) txt = u' '.join(u'USB%d %.0f' % (i, v) for i, _r, v in L) ax.set_title(u'Hub 在走廊 %d(y %.1f~%.1f) D± 最远 ≈ %.0f mm\n%s 自检 %s' % (P.HUB_K, P._CH[1], P._CH[3], max(v for _i, _r, v in L), txt, u'全过' if not bad else u'%d 条不过' % len(bad)), fontsize=8) ax.set_xlim(-1, B.BW + 1) ax.set_ylim(-1, B.BH + 1) ax.set_aspect('equal') ax.grid(True, lw=0.2, alpha=0.4) ax.tick_params(labelsize=6) if __name__ == '__main__': out = sys.argv[1] variants = [False] if '--one' in sys.argv else [False, True] fig, axes = plt.subplots(1, len(variants), figsize=(8.5 * len(variants), 9.2), dpi=170) if len(variants) == 1: axes = [axes] for ax, v in zip(axes, variants): P, pos, sz, bad = plan_for(v) draw(ax, P, pos, sz, bad) fig.suptitle(u'底板背面 L4 摆位(从上往下看,背面件已镜像) 紫 = D± 车道 / 绿 = I²C 车道 / 橙 = 上行·USB6 上 L1 过孔带' u' / 斜线 = 槽体过孔带 / 红虚线 = 天线净空', fontsize=9) fig.tight_layout() fig.savefig(out) print('->', out)