R2 焊接:丝印临时换成器件值 + 摆放优化 + 1:1 器件值打印稿

2026-09-25 为焊接底板与旧版刀片(BLADE-PCB 3b9c4e39c8d164db):

- silk_value.py:隐藏位号、在原位建自由丝印写器件值(Value,没有就用型号),
  --restore 按 _silk_value_restore.json 删字并恢复位号。⚠ 再出 Gerber / 下单前必须先 --restore。
- silk_value_plan.py:器件值摆放优化(不压焊盘 / 不重叠 / 不出框 / 避开开槽与金手指区;
  软代价:压过孔、压他件本体、离本件远、缩字号)。EDA 默认字体实测字宽 ≈0.78×字高。
- print_value.py:两块板背面镜像 1:1 画在同一张 A4,红框标 1 脚;
  print/print_1to1.ps1 按 210×297 mm 直送打印机(不经 PDF 阅读器缩放)。
- 数据:_silk_value_geom/_extra(板上读回几何)、_dump/_plan(排位结果)。

Co-Authored-By: Claude Opus 5.5 <[email protected]>
这个提交包含在:
zhou yang
2026-09-27 10:27:20 +08:00
共同撰写人 Claude Opus 5.5
父节点 dc0395fde0
当前提交 cae567dfd8
共修改 10 个文件,包含 1840 行新增和 0 行删除
+142
查看文件
@@ -0,0 +1,142 @@
# -*- coding: utf-8 -*-
u"""焊接用**器件值打印稿**:底板 + 旧版刀片,1:1,同一张 A4 竖版(PDF + 600 dpi PNG)。
/c/Python314/python .claude/r2/print_value.py # 出 .claude/r2/print/value_1to1.pdf / .png
powershell -ExecutionPolicy Bypass -File .claude/r2/print/print_1to1.ps1 -Image .claude/r2/print/value_1to1.png -Printer "EPSON3F4E59 (L4260 Series)"
- 两块板都画**背面(器件面)、左右镜像**:和把板子翻过来拿在手里看到的一致,字照常可读。
- 器件值文字的位置 = `silk_value_plan.py` 排好并下发到 EDA 的位置(`_silk_value_plan.json`)。
- 焊盘 / 器件 = `_silk_value_geom.json`(板上读回);红框 = 1 脚(二极管 / 有极性电容 / IC 的方向)。
- 正面只有大件(插槽、插座、电解、侧键焊盘),列在页脚,不单独画。
"""
import io
import json
import os
import sys
sys.stdout.reconfigure(encoding='utf-8')
HERE = os.path.dirname(os.path.abspath(__file__))
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 # noqa: E402
from silk_value_plan import pad_box, nums, M # noqa: E402
plt.rcParams['font.sans-serif'] = ['Microsoft YaHei', 'DejaVu Sans']
plt.rcParams['axes.unicode_minus'] = False
A4 = (210.0, 297.0)
MM = 1 / 25.4
OUT = os.path.join(HERE, 'print')
geom = json.load(io.open(os.path.join(HERE, '_silk_value_geom.json'), encoding='utf-8'))
extra = json.load(io.open(os.path.join(HERE, '_silk_value_extra.json'), encoding='utf-8'))
plan = json.load(io.open(os.path.join(HERE, '_silk_value_plan.json'), encoding='utf-8'))
restore = json.load(io.open(os.path.join(HERE, '_silk_value_restore.json'), encoding='utf-8'))
dump = json.load(io.open(os.path.join(HERE, '_silk_value_dump.json'), encoding='utf-8'))
NARROW = matplotlib.font_manager.FontProperties(fname=r'C:\Windows\Fonts\ARIALN.TTF')
CAP = 0.716 # Arial 大写字高 / em
def polar(c):
r = c['ref']
if r[0] in 'UQDY' or r.startswith('DZ') or r.startswith('J'):
return True
fp = c.get('fp') or ''
return r.startswith('C') and ('CAP-' in fp or 'CASE' in fp)
def draw(fig, name, uuid, x0, y0):
g = geom[uuid]
outline = [(x * M, y * M) for x, y in nums(g['polys'][0])]
BW = max(p[0] for p in outline)
BH = max(p[1] for p in outline)
ax = fig.add_axes([x0 / A4[0], y0 / A4[1], (BW + 2) / A4[0], (BH + 2) / A4[1]])
ax.set_xlim(BW + 1, -1) # 背面看:左右镜像
ax.set_ylim(-1, BH + 1)
ax.set_aspect('equal')
ax.axis('off')
ax.add_patch(Polygon(outline, closed=True, fill=False, ec='k', lw=0.6))
for f in [f for f in extra[uuid]['F'] if f['layer'] == 12]:
pl = json.loads(f['poly'])['polygon']
q = [(x * M, y * M) for x, y in nums(pl)]
if len(q) > 2:
ax.add_patch(Polygon(q, closed=True, fc='0.8', ec='k', lw=0.3, hatch='///'))
for p in g['pads']: # 安装孔等自由焊盘
b = pad_box([p['x'], p['y'], p['rot'], p['layer'], p['pad']])
ax.add_patch(Rectangle(b[:2], b[2] - b[0], b[3] - b[1], fc='0.35', ec='none'))
for c in g['comps']:
bot = c['layer'] == 2
bs = []
for p in c['pads']:
if p['layer'] not in (2, 12):
continue
b = pad_box([p['x'], p['y'], p['rot'], p['layer'], p['pad']])
bs.append(b)
col = '#d9b64a' if bot else '#e6e6e6'
ax.add_patch(Rectangle(b[:2], b[2] - b[0], b[3] - b[1], fc=col, ec='none'))
if bot and p['n'] == '1' and polar(c) and len(c['pads']) >= 2:
ax.add_patch(Rectangle(b[:2], b[2] - b[0], b[3] - b[1], fill=False, ec='#d00000', lw=0.45))
if bot and bs:
x1, y1 = min(b[0] for b in bs) - 0.15, min(b[1] for b in bs) - 0.15
x2, y2 = max(b[2] for b in bs) + 0.15, max(b[3] for b in bs) + 0.15
ax.add_patch(Rectangle((x1, y1), x2 - x1, y2 - y1, fill=False, ec='#1a3fa0', lw=0.25))
texts = {s['id']: s['text'] for s in dump[name]['strings']}
layer = {s['id']: s['layer'] for s in dump[name]['strings']}
for sid, x, y, rot, fs in plan[name]['rows']:
if layer[sid] != 4:
continue # 正面的写在页脚
fsm = fs * M
ax.text(x * M, y * M, texts[sid], fontproperties=NARROW, fontsize=fsm / CAP * 72 / 25.4 * 0.98,
ha='center', va='center', rotation=rot, color='k')
return BW, BH
def ruler(fig, x0, y0, length):
ax = fig.add_axes([0, 0, 1, 1], facecolor='none')
ax.set_xlim(0, A4[0])
ax.set_ylim(0, A4[1])
ax.axis('off')
ax.plot([x0, x0 + length], [y0, y0], 'k', lw=0.6)
for k in range(0, int(length) + 1):
t = 2.0 if k % 10 == 0 else (1.2 if k % 5 == 0 else 0.6)
ax.plot([x0 + k, x0 + k], [y0, y0 + t], 'k', lw=0.25)
ax.text(x0 + length + 2, y0, u'%d mm(打出来量,应为 %.1f)' % (length, length), fontsize=6, va='center')
def main():
os.makedirs(OUT, exist_ok=True)
fig = plt.figure(figsize=(A4[0] * MM, A4[1] * MM))
txt = fig.add_axes([0, 0, 1, 1], facecolor='none')
txt.set_xlim(0, A4[0])
txt.set_ylim(0, A4[1])
txt.axis('off')
base, blade = restore['BASE']['pcb'], restore['BLADE']['pcb']
txt.text(A4[0] / 2, 289, u'PhoneRail R2 焊接图 · 器件值 · 1:1(底板 BASE-PCB + 刀片 BLADE-PCB 旧版)',
fontsize=9, ha='center', weight='bold')
txt.text(A4[0] / 2, 284.5, u'两块都是【背面 / 器件面,左右镜像】= 把板子翻过来看到的样子。红框 = 封装 1 脚(IC 定位;二极管多为负极、电解/钽电容为正极)。打印「实际大小 100%」。',
fontsize=6, ha='center')
ya = 180.0
txt.text(56, ya + 100.5, u'底板 98 × 98(背面)', fontsize=7, weight='bold')
draw(fig, 'BASE', base, 55.0, ya - 1)
yb = 97.0
txt.text(60, yb + 69.5, u'刀片 89.5 × 67(背面,金手指朝下)', fontsize=7, weight='bold')
draw(fig, 'BLADE', blade, 59.25, yb - 1)
ruler(fig, 20, 86, 80)
lines = [
u'正面器件(不在图上):',
u' 底板:C2 / C3 = 470uF 25V 电解(注意极性) J26 / J27 = 2510-4A 风扇座 J33 = 1×5P 2.54 排针 J34~J38 = PCIE-64P11L 插槽',
u' 刀片:J1 = 金手指(不焊) K1~K4 = 侧键焊盘(不焊)',
u'字号:大多 1.0 mm,挤的地方 0.85 / 0.7 mm。只写了器件值;看位号请开 EDA。',
u'文件:.claude/r2/print/value_1to1.pdf(print_value.py 生成)',
]
for i, s in enumerate(lines):
txt.text(20, 74 - i * 5, s, fontsize=6.2)
pdf = os.path.join(OUT, 'value_1to1.pdf')
png = os.path.join(OUT, 'value_1to1.png')
fig.savefig(pdf)
fig.savefig(png, dpi=600)
print(u'已出 %s / %s' % (pdf, png))
if __name__ == '__main__':
main()