文件
phonerail/.claude/r2/synth_pads.py
T

78 行
3.4 KiB
Python
原始文件 Blame 文件历史

此文件含有模棱两可的 Unicode 字符
此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。
# -*- coding: utf-8 -*-
u"""按 `pcb_place.plan()` 的新摆位,把**改摆位之前**板上抓的焊盘表刚体变换成新焊盘表(离线,不连 EDA)。
/c/Python314/python .claude/r2/synth_pads.py # 两趟收敛,写 _blade_pads.json + _blade_pad_offsets.json
为什么要有:2026-09-11 晚主板转 180°(方案 §35)要先在服务器上试布线、比完再下发;
而 `net_peers()` / 布线器吃的都是焊盘表。改摆位前的表 + 当时的摆位在
`archive_blade_prerot_0911/`(`_blade_pads.json` / `old_pos.json`)。
变换:新焊盘 = 新原点 + R(Δrot)·(旧焊盘 − 旧原点)。Δrot 只允许 0 / 180(180 的时候顺/逆时针没区别,
底层「先镜像再转」也不影响);出现 90 / 270 直接报错 —— 那种情况底层的旋转方向要实测,不许猜。
⚠ **合成的表只用于离线试布线**。摆位真下发之后必须 `pcb_route.py --dump` 重抓,并和这份逐脚对账
(对不上 = 旋转语义推错了,不许拿合成表下发铜)。
"""
import io
import json
import math
import os
import sys
sys.stdout.reconfigure(encoding='utf-8')
HERE = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, os.path.dirname(HERE))
sys.path.insert(0, HERE)
ARC = os.path.join(HERE, 'archive_blade_prerot_0911')
OLD_PADS = os.path.join(ARC, '_blade_pads.json')
OLD_POS = os.path.join(ARC, 'old_pos.json')
OUT = os.path.join(HERE, '_blade_pads.json')
OFFS = os.path.join(HERE, '_blade_pad_offsets.json')
def synth(new_pos):
old = json.load(io.open(OLD_PADS, encoding='utf-8'))
op = json.load(io.open(OLD_POS, encoding='utf-8'))
out, bad = [], []
for row in old:
ref = row[0]
if ref not in new_pos or ref not in op:
bad.append(ref)
continue
ox, oy, orot = op[ref]
nx, ny, nrot = new_pos[ref]
d = (nrot - orot) % 360
if d % 90:
raise SystemExit(u'%s 旋转变了 %d°,不是 90 的倍数' % (ref, d))
dx, dy = row[2] - ox, row[3] - oy
# 方案 §25.3 实测:底层先 y 镜像、再 rot=θ 按 R(+θ)(**逆时针**)转;顶层同为逆时针。
# 镜像在旋转之前 ⇒ 改 rot 只是在已有图案上再左乘 R(+Δ),两面同一个式子。
for _k in range(d // 90):
dx, dy = -dy, dx
r = list(row)
r[2], r[3] = round(nx + dx, 3), round(ny + dy, 3)
out.append(r)
return out, sorted(set(bad))
def offsets(pads, pos):
o = {}
for r in pads:
if r[0] in pos:
o.setdefault(r[0], []).append([round(r[2] - pos[r[0]][0], 4), round(r[3] - pos[r[0]][1], 4)])
return o
if __name__ == '__main__':
import importlib
import pcb_place as PL
for k in range(2):
importlib.reload(PL)
pos, _r, un, _sz = PL.plan()
pads, bad = synth(pos)
io.open(OUT, 'w', encoding='utf-8').write(json.dumps(pads, ensure_ascii=False))
io.open(OFFS, 'w', encoding='utf-8').write(json.dumps(offsets(pads, pos)))
# ⚠ 每一趟都写:pcb_place.flip_2pin 要知道焊盘表是按哪一版 rot 做的(只在最后写的话第二趟会翻回去)
json.dump({r: list(v) for r, v in pos.items()},
io.open(os.path.join(HERE, '_blade_place_synth.json'), 'w', encoding='utf-8'), indent=0)
print(u'第 %d 趟:%d 焊盘 / %d 件;缺: %s;排不下: %s' % (k + 1, len(pads), len(pos), bad or u'无', un or u'无'))