初始导入:PhoneRail 五路手机直供电源板

原理图/PCB 已在 EasyEDA 里做到 12 页跨页 0 漏接,固件刚完成骨架包 A1。
这次是把已有的一切一次性纳入版本控制,没有改动任何设计内容。

纳入:
- 设计与需求文档、PROGRESS.md、小米8 参考原理图 PDF 与追脚脚本
- .claude/ 下的 EasyEDA 桥接工具链与几何/网表缓存(eda-parts.json、
  pcb-parts.json、pcb-pads.json、p2-ch1.json 等,是重画各页的唯一事实来源)
- 117 张验证截图(本项目所有方向问题都是靠人眼看截图发现的,属于证据不是垃圾)
- firmware/ 的 A1 骨架与 site/ 文档站源码

.gitignore 排除:构建产物(firmware/build、host/build、sdkconfig)、
site/node_modules、__pycache__、桥接日志 _bridge.log、脚本自标的 *.stale。

.gitattributes 默认 `* -text`:现有 .py/.json 大多是 CRLF,原样存,
不让 git 重写行尾。唯一例外是 *.sh 强制 LF —— 带 \r 的 shell 脚本 bash 跑不了。

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01QYuExfgyYa6DzRRcUso8M8
这个提交包含在:
zhou yang
2026-09-06 18:18:14 +08:00
共同撰写人 Claude Opus 5
当前提交 2bfe308b30
共修改 526 个文件,包含 80633 行新增和 0 行删除
+70
查看文件
@@ -0,0 +1,70 @@
import fitz, math
from collections import defaultdict
TOL = 0.6
WIRE_COLORS = {(1.0,0.0,0.0), (0.5,0.0,0.25)} # red pin stubs + maroon wires
class DSU:
def __init__(s): s.p={}
def find(s,x):
s.p.setdefault(x,x)
while s.p[x]!=x:
s.p[x]=s.p[s.p[x]]; x=s.p[x]
return x
def union(s,a,b):
ra,rb=s.find(a),s.find(b)
if ra!=rb: s.p[ra]=rb
def segs_of_page(page):
out=[]
for d in page.get_drawings():
col=d.get('color')
if col is None: continue
c=tuple(round(v,3) for v in col)
if c not in WIRE_COLORS: continue
for it in d['items']:
if it[0]=='l':
p,q=it[1],it[2]
out.append(((p.x,p.y),(q.x,q.y)))
return [s for s in out if math.dist(s[0],s[1])>0.05]
def on_seg(p,a,b,tol=TOL):
(px,py),(ax,ay),(bx,by)=p,a,b
dx,dy=bx-ax,by-ay
L2=dx*dx+dy*dy
if L2==0: return False
t=((px-ax)*dx+(py-ay)*dy)/L2
if t<-1e-9 or t>1+1e-9: return False
cx,cy=ax+t*dx,ay+t*dy
return math.hypot(px-cx,py-cy)<=tol
def junction_dots(page):
out=[]
for d in page.get_drawings():
f=d.get('fill')
if d['type']=='fs' and f and abs(f[0]-1)<.01 and f[1]<.01 and abs(f[2]-1)<.01:
r=d['rect']; out.append(((r.x0+r.x1)/2,(r.y0+r.y1)/2))
return out
def nets(page):
segs=segs_of_page(page)
dsu=DSU()
key=lambda p:(round(p[0]*2)/2, round(p[1]*2)/2)
for a,b in segs: dsu.union(key(a),key(b))
for i,(a,b) in enumerate(segs):
for p in (a,b):
for j,(c,e) in enumerate(segs):
if i==j: continue
if on_seg(p,c,e):
dsu.union(key(p),key(c)); dsu.union(key(p),key(e))
for dc in junction_dots(page):
hit=[]
for a,b in segs:
if on_seg(dc,a,b,tol=1.4): hit.append((a,b))
for a,b in hit[1:]:
dsu.union(key(a),key(hit[0][0])); dsu.union(key(b),key(hit[0][0]))
comp=defaultdict(set)
for a,b in segs:
for p in (a,b): comp[dsu.find(key(p))].add(key(p))
return segs,dsu,key,comp