R2:底板 / 刀片布局布线脚本、快照、截图与规划文档更新(含外壳、打印件、布线归档)
Co-Authored-By: Claude Opus 5.5 <[email protected]>
这个提交包含在:
@@ -0,0 +1,199 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
u"""派生 topshell_v8 / place_v8 / render_v8(2026-09-13 用户:格栅无法打印 → 方案 A「竖槽 + 3 条横撑」)。
|
||||
|
||||
问题:倒扣打印时端墙竖着长高,竖槽之间的筋 1.2 宽 × 2.4 厚 × 最长 64 高(长细比 > 50),
|
||||
只有下端连着墙往上悬空长 ⇒ 晃动、拉丝、打断。
|
||||
改法:在风扇中心 z −16 / 0 / +16 加 3 条 1.2 宽的水平横撑,每条竖槽被切成若干段,
|
||||
最长悬空筋段 64 → 16;开孔 2295 → 2138 mm²(原 Ø60 的 81.2% → 75.6%)。
|
||||
每段轮廓:挨着槽头的一端保持半圆,挨着横撑的一端是平边;横撑必须整条落在槽的直边段里或完全不碰槽(断言)。
|
||||
纯文本补丁,锚点断言次数。"""
|
||||
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\\'
|
||||
s = open(T + 'topshell_v7.py', encoding='utf-8').read()
|
||||
|
||||
|
||||
def rep(old, new, n=1):
|
||||
global s
|
||||
c = s.count(old)
|
||||
if c != n:
|
||||
raise SystemExit(u'锚点 %r 出现 %d 次(期望 %d)' % (old[:70], c, n))
|
||||
s = s.replace(old, new)
|
||||
|
||||
|
||||
rep(u"TopShell_v7.SLDPRT'", u"TopShell_v9.SLDPRT'")
|
||||
rep(u"'TOPSHELL_V7'", u"'TOPSHELL_V9'")
|
||||
|
||||
a = s.index(u'# ── B:两端墙 Ø60 圆孔 → 竖向圆头槽格栅')
|
||||
end_marker = u"grille_cut(u'东端墙', X1, +1)"
|
||||
b = s.index(end_marker) + len(end_marker)
|
||||
|
||||
NEW = u'''# ── B:两端墙竖槽格栅 + 3 条横撑(v8:解决「长细筋打不出来」)─────────────────────
|
||||
GR_R, GR_W, GR_RIB = 32.0, 6.0, 2.0 # v9:槽宽 6、竖筋 2.0(用户选 ③)
|
||||
XB_W, XB_SEG = 2.0, 10.0 # 横筋宽 2.0,最长槽段 10 ⇒ 横筋中心距 12
|
||||
XB_P = XB_SEG + XB_W
|
||||
XB_Z = tuple(k * XB_P for k in range(-int(GR_R // XB_P) - 1, int(GR_R // XB_P) + 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 slot_segments(L_):
|
||||
u"""一条槽被横筋切成的段:[(z0, z1, round0, round1)],z 相对风扇中心;round = 该端是真正的槽头(半圆)。
|
||||
v9 通用规则:横筋可以切到槽头附近;短到放不下「端头 + 0.8 直边」的碎段做成实心(不画)。"""
|
||||
r = GR_W / 2
|
||||
h = L_ / 2
|
||||
cuts = sorted((c - XB_W / 2, c + XB_W / 2) for c in XB_Z if c + XB_W / 2 > -h and c - XB_W / 2 < h)
|
||||
ivs, z = [], -h
|
||||
for lo, hi in cuts:
|
||||
ivs.append((z, lo))
|
||||
z = hi
|
||||
ivs.append((z, h))
|
||||
segs = []
|
||||
for z0, z1 in ivs:
|
||||
r0, r1 = abs(z0 + h) < 1e-9, abs(z1 - h) < 1e-9
|
||||
need = (r if r0 else 0.0) + (r if r1 else 0.0) + 0.8
|
||||
if z1 - z0 < need:
|
||||
continue
|
||||
segs.append((z0, z1, r0, r1))
|
||||
return segs, 0
|
||||
|
||||
|
||||
def seg_area(z0, z1, r0, r1):
|
||||
r = GR_W / 2
|
||||
a_ = (z1 - z0) - (r if r0 else 0) - (r if r1 else 0)
|
||||
return GR_W * a_ + (math.pi * r * r / 2) * (int(r0) + int(r1))
|
||||
|
||||
|
||||
GRS = grille_slots()
|
||||
A_SLOTS = 0.0
|
||||
N_FLAT = 0
|
||||
LONGEST = 0.0
|
||||
N_ROUND = 0
|
||||
N_SEG = 0
|
||||
for _ys, _L in GRS:
|
||||
_segs, _ = slot_segments(_L)
|
||||
A_SLOTS += sum(seg_area(*sg) for sg in _segs)
|
||||
N_FLAT += sum(int(not sg[2]) + int(not sg[3]) for sg in _segs)
|
||||
N_ROUND += sum(int(sg[2]) + int(sg[3]) for sg in _segs)
|
||||
N_SEG += len(_segs)
|
||||
LONGEST = max([LONGEST] + [sg[1] - sg[0] for sg in _segs])
|
||||
A_HOLES = 4 * math.pi * R_FAN ** 2
|
||||
P(u' 格栅:%d 条竖槽(宽 %.1f 竖筋 %.1f 外包 R%.0f)+ 横筋 %.1f(中心距 %.0f),共 %d 段;开孔 %.1f mm²(原 Ø60 的 %.1f%%),最长槽段 %.1f;半圆端 %d、平端 %d'
|
||||
% (len(GRS), GR_W, GR_RIB, GR_R, XB_W, XB_P, N_SEG, A_SLOTS, A_SLOTS / (math.pi * 900) * 100, LONGEST, N_ROUND, N_FLAT))
|
||||
|
||||
|
||||
def grille_cut(tag, xw, sg):
|
||||
xi = xw - sg * 2.4 # 墙内表面
|
||||
|
||||
def face_area():
|
||||
return sum(a_ for ax_, sgn, fb, a_, _ in planes()
|
||||
if ax_ == 0 and sgn == sg and abs(fb[0] - xw) < 0.02 and abs(fb[3] - xw) < 0.02)
|
||||
|
||||
def flat_ends():
|
||||
lo, hi = min(xw, xi), max(xw, xi)
|
||||
return sum(1 for ax_, sgn, fb, a_, _ in planes()
|
||||
if ax_ == 2 and abs(fb[0] - lo) < 0.05 and abs(fb[3] - hi) < 0.05 and abs((fb[4] - fb[1]) - GR_W) < 0.05)
|
||||
|
||||
caps0 = sum(1 for rr, ax_, fb in cyls() if abs(rr - GR_W / 2) < 0.01 and ax_ == 0)
|
||||
flat0 = flat_ends()
|
||||
a_before = face_area()
|
||||
nbefore = len(faces())
|
||||
X = open_face_sketch((0, sg, xw), tag)
|
||||
sm.AddToDB = True
|
||||
for cy, cz, r in END_CIRCLES[1:]:
|
||||
q = to_sketch(X, (xw, cy, L(cz)))
|
||||
sm.CreateCircleByRadius(q[0], q[1], 0.0, M(r))
|
||||
zc = L(FAN_CZ)
|
||||
r = GR_W / 2
|
||||
|
||||
def S(y, z):
|
||||
return to_sketch(X, (xw, y, zc + z))
|
||||
|
||||
def line(y0, z0, y1, z1):
|
||||
q0, q1 = S(y0, z0), S(y1, z1)
|
||||
sm.CreateLine(q0[0], q0[1], 0.0, q1[0], q1[1], 0.0)
|
||||
|
||||
for ys, L_ in GRS:
|
||||
segs, _ = slot_segments(L_)
|
||||
for z0, z1, r0, r1 in segs:
|
||||
b0 = z0 + (r if r0 else 0) # 直边起止
|
||||
b1 = z1 - (r if r1 else 0)
|
||||
line(ys + r, b0, ys + r, b1)
|
||||
line(ys - r, b1, ys - r, b0)
|
||||
for zz, rounded, s_ in ((b1, r1, 1), (b0, r0, -1)):
|
||||
if rounded:
|
||||
qc, q1, q2, qm = S(ys, zz), S(ys + r, zz), S(ys - r, zz), S(ys, zz + s_ * 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))
|
||||
else:
|
||||
line(ys + r, zz, ys - r, zz)
|
||||
sm.AddToDB = False
|
||||
sm.InsertSketch(True)
|
||||
c = do_cut(T + 0.2)
|
||||
d_area = a_before - face_area()
|
||||
ok_area = abs(d_area - (A_SLOTS + A_HOLES)) < 0.5
|
||||
caps = sum(1 for rr, ax_, fb in cyls() if abs(rr - GR_W / 2) < 0.01 and ax_ == 0) - caps0
|
||||
flats = flat_ends() - flat0
|
||||
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] - xw), abs(fb[3] - xw)) < 0.05
|
||||
for rr, ax_, fb in cyls()) for cy, cz, _ in END_CIRCLES[1:])
|
||||
P(u' %s 切除 → %-12r 面数 %d→%d' % (tag, 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' 槽头半圆柱 +%d(期望 %d)%s;横筋平端面 +%d(期望 %d)%s;风扇孔在位 %s'
|
||||
% (caps, N_ROUND, u'✅' if caps == N_ROUND else u'⛔',
|
||||
flats, N_FLAT, u'✅' if flats == N_FLAT else u'⛔', u'✅' if fan_ok else u'⛔'))
|
||||
if not (ok_area and caps == N_ROUND and flats == N_FLAT and fan_ok):
|
||||
P(u' ⛔⛔ %s 格栅不对,停手、不存盘' % tag); sys.exit(5)
|
||||
|
||||
|
||||
grille_cut(u'西端墙', X0, -1)
|
||||
grille_cut(u'东端墙', X1, +1)'''
|
||||
s = s[:a] + NEW + s[b:]
|
||||
_old_h = 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): 4 * len(GRS), 2.6: 8, 3.0: 4, 30.0: 0}"
|
||||
if s.count(_old_h) != 1:
|
||||
raise SystemExit(u'直方图锚点')
|
||||
# ⚠ 槽宽 6 ⇒ 槽头半径 3.0,与顶盖竖边圆角 R3 同半径:必须累加,不能在字典字面量里重复键(后者会覆盖前者)
|
||||
s = s.replace(_old_h, u"WANT_H = {0.7: 8, 0.75: 2 * SLOT_N, 0.8: 1, 1.5: 4, 2.1: 4, 2.6: 8, 3.0: 4, 30.0: 0}\n"
|
||||
u"WANT_H[round(GR_W / 2, 2)] = WANT_H.get(round(GR_W / 2, 2), 0) + 2 * N_ROUND")
|
||||
s = s.replace(u'# -*- coding: utf-8 -*-\n', u'# -*- coding: utf-8 -*-\n# v9:格栅 槽宽 6 / 竖筋 2.0 / 横筋 2.0 中心距 12(最长槽段 10),其余同 v7\n', 1)
|
||||
open(T + 'topshell_v9.py', 'w', encoding='utf-8').write(s)
|
||||
print(u'写出 topshell_v9.py')
|
||||
|
||||
p = open(T + 'place_v7.py', encoding='utf-8').read()
|
||||
for old, new in ((u"(u'TopShell_v7.SLDPRT',", u"(u'TopShell_v9.SLDPRT',"), (u"((u'v7_iso', 7),)", u"((u'v9_iso', 7),)")):
|
||||
if p.count(old) != 1:
|
||||
raise SystemExit(u'place 锚点 %r ×%d' % (old, p.count(old)))
|
||||
p = p.replace(old, new)
|
||||
open(T + 'place_v9.py', 'w', encoding='utf-8').write(p)
|
||||
print(u'写出 place_v9.py')
|
||||
|
||||
rsrc = open(T + 'render_v7.py', encoding='utf-8').read()
|
||||
rsrc = rsrc.replace(u"v7_", u"v9_")
|
||||
ZOOM_OLD = u" doc.ViewZoomTo2(0.000, -0.005, -0.012, 0.100, -0.005, 0.008)"
|
||||
if rsrc.count(ZOOM_OLD) != 1:
|
||||
raise SystemExit(u'render 锚点')
|
||||
rsrc += u'''
|
||||
vid = find((1.0, 0.0, 0.0))
|
||||
if vid is not None:
|
||||
doc.ShowNamedView2('', vid)
|
||||
doc.ViewZoomTo2(-0.0184, 0.015, 0.002, -0.0184, 0.088, 0.074) # 拉近西端格栅
|
||||
doc.SaveBMP(os.path.join(OUT, 'v9_west_zoom.bmp'), 1600, 1100)
|
||||
print(u' v9_west_zoom ← vid %d + ViewZoomTo2' % vid)
|
||||
'''
|
||||
open(T + 'render_v9.py', 'w', encoding='utf-8').write(rsrc)
|
||||
print(u'写出 render_v9.py')
|
||||
在新工单中引用
屏蔽一个用户