R2:底板 / 刀片布局布线脚本、快照、截图与规划文档更新(含外壳、打印件、布线归档)

Co-Authored-By: Claude Opus 5.5 <[email protected]>
这个提交包含在:
zhou yang
2026-10-04 19:24:45 +08:00
共同撰写人 Claude Opus 5.5
父节点 cd01640c40
当前提交 cf7cc9cf90
共修改 759 个文件,包含 76962 行新增和 5299 行删除
+284
查看文件
@@ -0,0 +1,284 @@
# -*- coding: utf-8 -*-
u"""外观美化(2026-09-13 用户选 A+D、B+C、E+F):派生 topshell_v5 / filterframe_v3 / place_v5,新写 bottomplate_v4。
A 顶面外轮廓 R1.5 圆角;底盖四边内缩 0.5(阴影缝,圆角 R2.5 与顶盖 R3 同心)
D 滤网框高 90 → 84.4(与顶面齐平)+ 顶边指甲槽
B 东风口 Ø60 圆孔 → 11 条竖向圆头槽格栅(外包 R32、槽宽 4.5、筋 1.2;开孔 = 原 Ø60 的 81.2%)
C 顶面 11 条 1.5×60 直角缝 → 圆头槽 1.5×60.32(开孔面积不变 = 90 mm²/条)
E 底盖加厚 2.4 → 3.6(向下,内部尺寸不变)+ 四角沉头 Ø6.5 深 2.0 + 4 个 Ø10 深 1.0 脚垫窝
F 南墙 Type-C 右侧 9 mm 凹刻 0.6:J1「PWR 20V」= 闪电;J23「USB」= 箭头 + 圆点
"""
import io
import sys
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', write_through=True)
T = u'C:\\Users\\35138\\.claude\\jobs\\11836093\\tmp\\'
def patch_text(s, pairs, src):
for old, new, n in pairs:
c = s.count(old)
if c != n:
raise SystemExit(u'%s:锚点 %r 出现 %d 次(期望 %d)' % (src, old[:70], c, n))
s = s.replace(old, new)
return s
# ═══════════════════════════ topshell_v5 ═══════════════════════════════════
s = open(T + 'topshell_v4.py', encoding='utf-8').read()
SLOTS_OLD = u'''for i in range(SLOT_N):
xc = SLOT_XC - SLOT_SPAN / 2.0 + i * step
sm.CreateCornerRectangle(M(xc - SLOT_W / 2), M(SLOT_YC - SLOT_L / 2), 0.0,
M(xc + SLOT_W / 2), M(SLOT_YC + SLOT_L / 2), 0.0)
'''
SLOTS_NEW = u'''for i in range(SLOT_N):
xc = SLOT_XC - SLOT_SPAN / 2.0 + i * step
stadium_front(xc, SLOT_YC, SLOT_W, SLOT_L) # C:圆头槽,开孔面积与原 1.5×60 相同
'''
HELPERS = u'''
def arc_dir(qc, q1, qm):
u"""草图坐标里:从 q1 出发、逆时针先经过弧中点 qm ⇒ 1,否则 −1(半圆也适用)"""
return 1 if (q1[0] - qc[0]) * (qm[1] - qc[1]) - (q1[1] - qc[1]) * (qm[0] - qc[0]) > 0 else -1
def stadium_front(xc, yc, w, L):
u"""前视基准面(草图坐标 = 模型 x, y)画长沿 y 的圆头槽"""
r, a = w / 2.0, L / 2.0 - w / 2.0
sm.CreateLine(M(xc + r), M(yc - a), 0.0, M(xc + r), M(yc + a), 0.0)
sm.CreateLine(M(xc - r), M(yc + a), 0.0, M(xc - r), M(yc - a), 0.0)
for cy, sg in ((yc + a, 1), (yc - a, -1)):
qc, q1, q2, qm = (xc, cy), (xc + r, cy), (xc - r, cy), (xc, cy + sg * r)
sm.CreateArc(M(qc[0]), M(qc[1]), 0.0, M(q1[0]), M(q1[1]), 0.0, M(q2[0]), M(q2[1]), 0.0,
arc_dir(qc, q1, qm))
'''
TOPFILLET = u'''
# ── [3c] A:顶面外轮廓倒 R1.5(此时外轮廓 = 4 直边 + 4 段 R3 弧,导轨未加)──────────
TOP_R = 1.5
P(u'\\n[3c] 顶面外轮廓倒 R%.1f' % TOP_R)
_bx = bbox()
_sel = []
def _onb(p):
return (min(abs(p[0] - _bx[0]), abs(p[0] - _bx[3])) < 0.01 or
min(abs(p[1] - _bx[1]), abs(p[1] - _bx[4])) < 0.01)
for _e in prop(D(bodies()[0]), 'GetEdges'):
_E = D(_e)
try:
_p0 = [v * 1000 for v in prop(D(prop(_E, 'GetStartVertex')), 'GetPoint')]
_p1 = [v * 1000 for v in prop(D(prop(_E, 'GetEndVertex')), 'GetPoint')]
except Exception:
continue
if abs(_p0[2]) > 0.01 or abs(_p1[2]) > 0.01:
continue
if _onb(_p0) and _onb(_p1):
_sel.append(_E)
P(u' 顶面外轮廓边 %d 条(期望 8 = 4 直边 + 4 段 R3 弧)' % len(_sel))
if len(_sel) != 8:
P(u'⛔ 外轮廓边数不对,停手'); sys.exit(8)
part.ClearSelection2(True)
for _i, _E in enumerate(_sel):
_E.Select4(_i > 0, EMPTY)
P(u' 选中 %d 条' % part.SelectionManager.GetSelectedObjectCount2(-1))
try:
_f = fm.FeatureFillet3(195, M(TOP_R), 0, 0, 0, 0, 0, None, None, None, None, None, None, None)
except Exception as _ex:
_f = None
P(u' 异常 %s' % str(_ex)[:80])
_h = hist()
P(u' FeatureFillet3 → %r;直方图 %s(R1.5 圆柱面应 4 = 4 条直边)' % (prop(_f, 'Name') if _f else _f, _h))
if _h.get(TOP_R, 0) != 4:
P(u'⛔ 顶面圆角没成,停手'); sys.exit(8)
'''
EAST_OLD = u"cut_shapes(u'东端墙', (0, +1, X1), [((X1, cy, L(cz)), r) for cy, cz, r in END_CIRCLES], [], end_verify(X1))"
EAST_NEW = u'''# ── B:东端墙 Ø60 圆孔 → 竖向圆头槽格栅(西端被滤网盖住,保持圆孔)─────────────────
GR_R, GR_W, GR_RIB = 32.0, 4.5, 1.2
def grille_slots():
p, out = GR_W + GR_RIB, []
n = int((GR_R - GR_W / 2) // p)
for k in range(-n, n + 1):
y = k * p
e = abs(y) + GR_W / 2
if e >= GR_R:
continue
L_ = 2 * math.sqrt(GR_R * GR_R - e * e)
if L_ <= GR_W + 1:
continue
out.append((FAN_CY + y, L_))
return out
def east_face_area():
return sum(a_ for ax_, sg, fb, a_, _ in planes()
if ax_ == 0 and sg == 1 and abs(fb[0] - X1) < 0.02 and abs(fb[3] - X1) < 0.02)
GRS = grille_slots()
A_SLOTS = sum(GR_W * (L_ - GR_W) + math.pi * (GR_W / 2) ** 2 for _, L_ in GRS)
A_HOLES = 4 * math.pi * R_FAN ** 2
P(u' 东端格栅:%d 条槽 宽 %.1f 筋 %.1f 外包 R%.0f,槽面积 %.1f(原 Ø60 = %.1f,%.1f%%)'
% (len(GRS), GR_W, GR_RIB, GR_R, A_SLOTS, math.pi * 900, A_SLOTS / (math.pi * 900) * 100))
a_before = east_face_area()
nbefore = len(faces())
X = open_face_sketch((0, +1, X1), u'东端墙')
sm.AddToDB = True
for cy, cz, r in END_CIRCLES[1:]:
q = to_sketch(X, (X1, cy, L(cz)))
sm.CreateCircleByRadius(q[0], q[1], 0.0, M(r))
zc = L(FAN_CZ)
for ys, L_ in GRS:
r, a = GR_W / 2, L_ / 2 - GR_W / 2
for p0, p1 in (((ys + r, zc - a), (ys + r, zc + a)), ((ys - r, zc + a), (ys - r, zc - a))):
q0, q1 = to_sketch(X, (X1, p0[0], p0[1])), to_sketch(X, (X1, p1[0], p1[1]))
sm.CreateLine(q0[0], q0[1], 0.0, q1[0], q1[1], 0.0)
for cz_, sg in ((zc + a, 1), (zc - a, -1)):
qc = to_sketch(X, (X1, ys, cz_))
q1 = to_sketch(X, (X1, ys + r, cz_))
q2 = to_sketch(X, (X1, ys - r, cz_))
qm = to_sketch(X, (X1, ys, cz_ + sg * r))
sm.CreateArc(qc[0], qc[1], 0.0, q1[0], q1[1], 0.0, q2[0], q2[1], 0.0, arc_dir(qc, q1, qm))
sm.AddToDB = False
sm.InsertSketch(True)
c = do_cut(T + 0.2)
a_after = east_face_area()
d_area = a_before - a_after
ok_area = abs(d_area - (A_SLOTS + A_HOLES)) < 0.5
ends = sum(1 for rr, ax_, fb in cyls() if abs(rr - GR_W / 2) < 0.01 and ax_ == 0)
fan_ok = all(any(abs(rr - R_FAN) < 0.01 and ax_ == 0 and abs((fb[1] + fb[4]) / 2 - cy) < 0.05 and
abs((fb[2] + fb[5]) / 2 - L(cz)) < 0.05 and min(abs(fb[0] - X1), abs(fb[3] - X1)) < 0.05
for rr, ax_, fb in cyls()) for cy, cz, _ in END_CIRCLES[1:])
P(u' 东端墙 切除 → %-12r 面数 %d→%d' % (prop(c, 'Name') if c else c, nbefore, len(faces())))
P(u' 外表面面积减少 %.2f(理论 槽 %.2f + 螺丝孔 %.2f = %.2f)%s'
% (d_area, A_SLOTS, A_HOLES, A_SLOTS + A_HOLES, u'✅' if ok_area else u'⛔'))
P(u' 槽端半圆柱 R%.2f = %d(期望 %d)%s;风扇孔 4 个在位 %s'
% (GR_W / 2, ends, 2 * len(GRS), u'✅' if ends == 2 * len(GRS) else u'⛔', u'✅' if fan_ok else u'⛔'))
if not (ok_area and ends == 2 * len(GRS) and fan_ok):
P(u' ⛔⛔ 格栅不对,停手、不存盘'); sys.exit(5)'''
SYM_ANCHOR = u" P(u' ⛔⛔ 开口没落在母座口轮廓上 —— 停手、不存盘'); sys.exit(5)\n"
SYMBOLS = SYM_ANCHOR + u'''
# ── [5b] F:Type-C 右侧 9 mm 凹刻 0.6 —— J1「PWR 20V」闪电、J23「USB」箭头 + 圆点 ─────
SYM_DEPTH, SYM_DX = 0.6, 9.0
BOLT = [(0.8, 3.5), (-1.8, -0.3), (-0.1, -0.3), (-0.8, -3.5), (1.8, 0.5), (0.1, 0.5)]
ARROW = [(0.0, 3.5), (2.2, 0.9), (0.7, 0.9), (0.7, -1.2), (-0.7, -1.2), (-0.7, 0.9), (-2.2, 0.9)]
DOT_C, DOT_R = (0.0, -2.8), 0.8
def shoelace(pts):
return abs(sum(pts[i][0] * pts[(i + 1) % len(pts)][1] - pts[(i + 1) % len(pts)][0] * pts[i][1]
for i in range(len(pts)))) / 2.0
A_SYM = shoelace(BOLT) + shoelace(ARROW) + math.pi * DOT_R ** 2
P(u'\\n[5b] Type-C 标识凹刻 %.1f:闪电 %.2f + 箭头 %.2f + 圆点 %.2f = %.2f mm²'
% (SYM_DEPTH, shoelace(BOLT), shoelace(ARROW), math.pi * DOT_R ** 2, A_SYM))
nbefore = len(faces())
X = open_face_sketch((1, -1, Y0), u'南墙标识')
sm.AddToDB = True
for (cx, poly) in ((USB_CX[0] + SYM_DX, BOLT), (USB_CX[1] + SYM_DX, ARROW)):
qs = [to_sketch(X, (cx + du, Y0, L(USB_CZ + dv))) for du, dv in poly]
for i in range(len(qs)):
a_, b_ = qs[i], qs[(i + 1) % len(qs)]
sm.CreateLine(a_[0], a_[1], 0.0, b_[0], b_[1], 0.0)
qd = to_sketch(X, (USB_CX[1] + SYM_DX + DOT_C[0], Y0, L(USB_CZ + DOT_C[1])))
sm.CreateCircleByRadius(qd[0], qd[1], 0.0, M(DOT_R))
sm.AddToDB = False
sm.InsertSketch(True)
if pick(last_sketch(), 'SKETCH') != 1:
P(u' ⛔ 标识草图没选中'); sys.exit(5)
c = fm.FeatureCut4(True, False, False, 0, 0, M(SYM_DEPTH), 0.0,
False, False, False, False, 0.0, 0.0,
False, False, False, False, False,
True, True, False, False, False, 0, 0.0, False, False)
floor = sum(a_ for ax_, sg, fb, a_, _ in planes()
if ax_ == 1 and sg == -1 and abs(fb[1] - (Y0 + SYM_DEPTH)) < 0.02 and abs(fb[4] - (Y0 + SYM_DEPTH)) < 0.02)
ok = abs(floor - A_SYM) < 0.05
P(u' 标识 切除 → %-12r 面数 %d→%d 凹槽底面积 %.3f(理论 %.3f)%s'
% (prop(c, 'Name') if c else c, nbefore, len(faces()), floor, A_SYM, u'✅' if ok else u'⛔'))
if not ok:
P(u' ⛔⛔ 标识没刻对,停手、不存盘'); sys.exit(5)
'''
HIST_OLD = u'''P(u' 圆柱面直方图 %s(期望 {0.7: 8, 2.1: 4, 2.6: 8, 3.0: 4, 30.0: 2})' % h)
if h.get(2.6, 0) != 8 or h.get(2.1, 0) != 4 or h.get(30.0, 0) != 2 or h.get(0.7, 0) != 8:'''
HIST_NEW = u'''WANT_H = {0.7: 8, 0.75: 2 * SLOT_N, 0.8: 1, 1.5: 4, 2.1: 4, round(GR_W / 2, 2): 2 * len(GRS), 2.6: 8, 3.0: 4, 30.0: 1}
P(u' 圆柱面直方图 %s(期望 %s)' % (h, dict(sorted(WANT_H.items()))))
if any(h.get(k, 0) != v for k, v in WANT_H.items()):'''
s = patch_text(s, [
(u"TopShell_v4.SLDPRT'", u"TopShell_v5.SLDPRT'", 1),
(u"'TOPSHELL_V4'", u"'TOPSHELL_V5'", 1),
(u"import os\n", u"import math\nimport os\n", 1),
(u"SLOT_W, SLOT_L, SLOT_N, SLOT_SPAN = 1.5, 60.0, 11, 106.0",
u"SLOT_W, SLOT_L, SLOT_N, SLOT_SPAN = 1.5, 60.32, 11, 106.0 # C:圆头槽,长 60.32 使面积仍 = 90", 1),
(u"\n# ── [3] 顶板 + 泄压缝", HELPERS + u"\n# ── [3] 顶板 + 泄压缝", 1),
(SLOTS_OLD, SLOTS_NEW, 1),
(u"and abs(fb[4] - fb[1] - SLOT_L) < 0.05)", u"and abs(fb[4] - fb[1] - (SLOT_L - SLOT_W)) < 0.05)", 1),
(u"\n# ── 面上草图切除(带候选映射)", TOPFILLET + u"\n# ── 面上草图切除(带候选映射)", 1),
(EAST_OLD, EAST_NEW, 1),
(SYM_ANCHOR, SYMBOLS, 1),
(HIST_OLD, HIST_NEW, 1),
], 'topshell_v4.py')
s = s.replace(u'# -*- coding: utf-8 -*-\n',
u'# -*- coding: utf-8 -*-\n# v5 外观:顶面 R1.5 圆角、圆头泄压槽、东风口竖槽格栅、Type-C 凹刻标识(其余同 v4)\n', 1)
open(T + 'topshell_v5.py', 'w', encoding='utf-8').write(s)
print(u'写出 topshell_v5.py')
# ═══════════════════════════ filterframe_v3 ════════════════════════════════
f = open(T + 'filterframe_v2.py', encoding='utf-8').read()
OUTLINE = u'''SCOOP_R, SCOOP_D = 8.0, 4.0 # D:顶边指甲槽,圆心在顶边上方 4、切进框体 4(弦长 13.9)
def outline():
cx, cy = W / 2.0, HH + SCOOP_R - SCOOP_D
half = math.sqrt(SCOOP_R ** 2 - (SCOOP_R - SCOOP_D) ** 2)
for a_, b_ in (((0, 0), (W, 0)), ((W, 0), (W, HH)), ((W, HH), (cx + half, HH)),
((cx - half, HH), (0, HH)), ((0, HH), (0, 0))):
sm.CreateLine(M(a_[0]), M(a_[1]), 0.0, M(b_[0]), M(b_[1]), 0.0)
q1, q2, qm = (cx + half, HH), (cx - half, HH), (cx, cy - SCOOP_R)
d = 1 if (q1[0] - cx) * (qm[1] - cy) - (q1[1] - cy) * (qm[0] - cx) > 0 else -1
sm.CreateArc(M(cx), M(cy), 0.0, M(q1[0]), M(q1[1]), 0.0, M(q2[0]), M(q2[1]), 0.0, d)
A_SCOOP = SCOOP_R ** 2 * math.acos((SCOOP_R - SCOOP_D) / SCOOP_R) - (SCOOP_R - SCOOP_D) * math.sqrt(SCOOP_R ** 2 - (SCOOP_R - SCOOP_D) ** 2)
'''
f = patch_text(f, [
(u"FilterFrame_v2.SLDPRT'", u"FilterFrame_v3.SLDPRT'", 1),
(u"'FILTERFRAME_V2'", u"'FILTERFRAME_V3'", 1),
(u"import os\n", u"import math\nimport os\n", 1),
(u"W, HH = 70.0, 90.0", u"W, HH = 70.0, 84.4 # D:顶边与顶盖顶面齐平(z −10 ~ 74.4)", 1),
(u"sm.CreateCornerRectangle(0.0, 0.0, 0.0, M(W), M(HH), 0.0)", u"outline()", 2),
(u"want_a = W * HH - WIN * WIN", u"want_a = W * HH - WIN * WIN - A_SCOOP", 1),
(u"want_b = W * HH - NCELL * NCELL * CELL * CELL", u"want_b = W * HH - NCELL * NCELL * CELL * CELL - A_SCOOP", 1),
], 'filterframe_v2.py')
i = f.index(u"P(u'\\n[A] ")
f = f[:i] + OUTLINE + f[i:]
f = f.replace(u'# -*- coding: utf-8 -*-\n', u'# -*- coding: utf-8 -*-\n# v3 外观:高 84.4 与顶面齐平 + 顶边 R8 指甲槽(深 4)\n', 1)
open(T + 'filterframe_v3.py', 'w', encoding='utf-8').write(f)
print(u'写出 filterframe_v3.py')
# ═══════════════════════════ place_v5 ══════════════════════════════════════
p = open(T + 'place_v4.py', encoding='utf-8').read()
p = patch_text(p, [
(u"(u'TopShell_v4.SLDPRT',", u"(u'TopShell_v5.SLDPRT',", 1),
(u"(u'BottomPlate_v3.SLDPRT', (0, 0, -10.0), [-24.8, -4.055, -12.4, 115.9, 106.745, 0.0])",
u"(u'BottomPlate_v4.SLDPRT', (0, 0, -10.0), [-24.3, -3.555, -13.6, 115.4, 106.245, 0.0])", 1),
(u"u'FilterFrame_v2.SLDPRT'", u"u'FilterFrame_v3.SLDPRT'", 1),
(u"_w = [-22.4, 16.345, -10.0, -18.4, 86.345, 80.0]", u"_w = [-22.4, 16.345, -10.0, -18.4, 86.345, 74.4]", 1),
(u"((u'v4_iso', 7), (u'v4_south', 6), (u'v4_north', 5))",
u"((u'v5_iso', 7), (u'v5_east', 0), (u'v5_south', 6), (u'v5_bottom', 2), (u'v5_top', 1))", 1),
], 'place_v4.py')
open(T + 'place_v5.py', 'w', encoding='utf-8').write(p)
print(u'写出 place_v5.py')