文件
phonerail/.claude/r2/shell/add_endplates.py
T

199 行
8.6 KiB
Python
原始文件 Blame 文件历史

此文件含有模棱两可的 Unicode 字符
此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。
# -*- coding: utf-8 -*-
u"""把已确认可用的端板 `EndPlate_v2` 插进总装(两块:西端 + 东端)。
端板现状(圆柱面直方图实测 `{1.7: 4, 30.0: 1}`,都是真的):
· 本体 x 0~2.4、y −4~102、z −10~72
· Ø60 风口中心 (y,z) = (51.345, 37.85)
· 4× Ø3.4 风扇螺孔(50×50)
· L 脚 沿 +x 伸到 x=30.4、占 z −10~−7.6
⚠ 脚锁孔 2× Ø3.4 **尚未成形**(`FeatureCut4` 在本机不可靠,见 NOTES),留待 GUI 补。
摆位:
西端板:本体外表面贴到 x=−27.4 ⇒ 整体平移 x −27.4,其余不动(单位阵旋转)。
东端板:绕 z 轴转 180°,使板面朝向相反、L 脚伸向 −x;
转 180° 后本地 (x,y) → (−x, −y),再平移到本体占 x 123~125.4、y 与西端一致。
列主序旋转 = [−1,0,0, 0,−1,0, 0,0,1];
平移由「目标 box 最小值 − 旋转后 box 最小值」现算(不写死,NOTES 的固定动作)。
"""
import io
import os
import sys
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', write_through=True)
import pythoncom
import win32com.client as wc
OUT = r'C:\Users\35138\.claude\jobs\11836093\tmp'
# v5:y 对称版(−1.655~104.345,以风口中心 51.345 居中),
# 修掉东端板绕 z 翻转后偏 4.69、撞穿北板 616 mm³ 的问题。
PLATE = u'D:\\DCDC\\新建文件夹\\5blades\\EndPlate_v9.SLDPRT'
ASM = 'PhoneRail_5blades'
EMPTY = wc.VARIANT(pythoncom.VT_DISPATCH, None)
ROT_W = [1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0] # 西端:不转
# ⛔⛔ 绕 **y 轴** 180°([−1,0,0, 0,1,0, 0,0,−1])是错的:它**把 z 也翻了** ——
# L 脚本来在底部 z 0~2.4,翻完再按"z 最小端对齐 −10"平移 dz=+62,
# 脚就跑到 **z 59.6~62**,正好扎进风扇(z 6.37~69.33)的腰部 ⇒ 实测 483.9 mm³。
# (西端不撞纯粹因为它没旋转,脚老实待在风扇底面 6.37 以下。)
# ✅ 用**绕 z 轴 180°**:z 不翻、脚留在底部 z 0~2.4,从风扇正下方掠过;
# x 翻使脚朝 −x 伸向机内。附带好处:锁孔本地 y 21.345/81.345 翻转后互换成
# 81.345/21.345,**与托盘现有孔位完全重合,托盘不用改**。
ROT_E = [-1.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0, 1.0] # 东端:绕 z 180°
# 绕 z 翻转后 y 也镜像了:风口中心从 +FAN_CY 跑到 −FAN_CY,
# 要平移 2×FAN_CY 才能对回风扇中心(风扇/刀片堆叠中心 y=51.345)。
FAN_CY = 51.345
WEST_X, EAST_X = -27.4, 123.0 # 两块板本体外表面的 x(东端板本体占 123~125.4)
PLATE_T = 2.4
def prop(o, n):
v = getattr(o, n)
return v() if type(v).__name__ in ('method', 'function', 'builtin_function_or_method') else v
def P(*a):
print(*a)
def M(v):
return v / 1000.0
app = wc.GetActiveObject('SldWorks.Application')
if not os.path.exists(PLATE):
P(u'⛔ 端板文件不存在 %s' % PLATE); sys.exit(2)
doc = None
for d in app.GetDocuments:
if ASM in (prop(d, 'GetTitle') or ''):
doc = d
break
if doc is None:
P(u'⛔ 没找到总装'); sys.exit(3)
e0 = wc.VARIANT(pythoncom.VT_BYREF | pythoncom.VT_I4, 0)
app.ActivateDoc3(prop(doc, 'GetTitle'), False, 0, e0)
doc = app.ActiveDoc
P(u'总装 %s 顶层件 %d' % (prop(doc, 'GetTitle'), len(doc.GetComponents(True))))
# 幂等:先删掉已有的端板
for c in list(doc.GetComponents(True)):
nm = prop(c, 'Name2')
if 'ENDPLATE' in nm.upper():
doc.ClearSelection2(True)
doc.Extension.SelectByID2(nm, 'COMPONENT', 0, 0, 0, False, 0, EMPTY, 0)
doc.Extension.DeleteSelection2(0)
P(u' 删掉旧端板 %s' % nm)
doc.EditRebuild3
did = app._oleobj_.GetIDsOfNames('GetMathUtility')
mu = wc.Dispatch(app._oleobj_.Invoke(did, 0, pythoncom.DISPATCH_METHOD, 1))
d2 = mu._oleobj_.GetIDsOfNames('CreateTransform')
def mk(a16):
v = wc.VARIANT(pythoncom.VT_ARRAY | pythoncom.VT_R8, list(a16))
xf = wc.Dispatch(mu._oleobj_.Invoke(d2, 0, pythoncom.DISPATCH_METHOD, 1, v))
if max(abs(a - b) for a, b in zip(list(xf.ArrayData), a16)) > 1e-9:
raise RuntimeError(u'CreateTransform 回读不符')
return xf
def setx(c, rot9, t3):
xf = mk(list(rot9) + [t3[0] / 1000.0, t3[1] / 1000.0, t3[2] / 1000.0, 1.0, 0.0, 0.0, 0.0])
try:
c.SetTransformAndSolve2(xf)
except Exception:
c.Transform2 = xf
doc.EditRebuild3
return [round(v * 1000.0, 3) for v in c.GetBox(False, False)]
P(u'\n插入两块端板:')
for tag, rot, want_x0 in ((u'西端', ROT_W, WEST_X), (u'东端', ROT_E, EAST_X)):
c = doc.AddComponent4(PLATE, '', 0.0, 0.0, 0.0)
if c is None:
P(u' ⛔ %s AddComponent4 返回 None(零件没开着?)' % tag); sys.exit(4)
b0 = setx(c, rot, (0.0, 0.0, 0.0)) # 先只转不移,回读
P(u' %s 只旋转 box %s' % (tag, b0))
# ⛔ 不能一律拿 box 的**最小端**去对齐:西端板未旋转,本体(板厚那 2.4)在 box 最小端;
# 而东端板绕 y 转 180° 之后,**本体跑到了 box 的最大端**、L 脚朝最小端伸。
# 第一版统一用最小端对齐 ⇒ 东端板 box 落在 x 123.00~153.40,脚朝 +x 伸出机外。
# ✅ 按「本体外表面」这个语义对齐:西端板对齐 box 最小端,东端板对齐 box 最大端。
if tag == u'西端':
# 未旋转:本体在 box 最小端
dx = want_x0 - b0[0]
# ⛔ 原来写 `dy = −4.0 − b0[1]`(把 box 硬对到 y=−4):零件改成 y 对称之后,
# 这条旧逻辑把西端板拽偏了 2.345,与按风口对齐的东端板**不一致**
# (实测西 −4.00~102.00 / 东 −1.66~104.34),东端仍撞北板 589 mm³。
# ✅ 零件已以风口中心 51.345 对称 ⇒ **dy = 0** 时风口天然落位,两块板 y 完全一致。
dy = 0.0
dz = -10.0 - b0[2]
else:
# 绕 z 180°:本体跑到 box 最大端 ⇒ 按最大端对齐(123+2.4=125.4)
dx = (want_x0 + PLATE_T) - b0[3]
# ⛔ y 不能再按 box 最小端对齐:绕 z 翻转把风口中心镜像到了 −FAN_CY,
# 必须平移 2×FAN_CY 才能对回风扇/刀片堆叠中心(y=51.345)。
# 附带结果:锁孔 y 21.345/81.345 互换位置,与托盘孔位仍然重合。
dy = 2.0 * FAN_CY
# ⛔ z **不要**再补偿:绕 z 不翻 z,脚仍在底部 z 0~2.4(风扇底面 6.37 以下)。
dz = 0.0
t = (dx, dy, dz)
b = setx(c, rot, t)
P(u' %s 摆位后 box x %.2f~%.2f y %.2f~%.2f z %.2f~%.2f'
% (tag, b[0], b[3], b[1], b[4], b[2], b[5]))
# 截图
for nm2, vid in ((u'full_iso', 7), (u'full_front', 1), (u'full_top', 5)):
try:
doc.ShowNamedView2('', vid)
doc.ViewZoomtofit2
doc.SaveBMP(os.path.join(OUT, '%s.bmp' % nm2), 1600, 1100)
except Exception as ex:
P(u'截图 %s 失败 %s' % (nm2, str(ex)[:40]))
P(u'\n截图完成')
e3 = wc.VARIANT(pythoncom.VT_BYREF | pythoncom.VT_I4, 0)
w3 = wc.VARIANT(pythoncom.VT_BYREF | pythoncom.VT_I4, 0)
doc.Extension.SaveAs3(prop(doc, 'GetPathName'), 0, 1, EMPTY, EMPTY, e3, w3)
P(u'存盘 err=%s' % e3.value)
P(u'\n干涉(fast):')
try:
idm = doc.InterferenceDetectionManager
idm.TreatCoincidenceAsInterference = False
idm.IncludeMultibodyPartInterferences = False
idm.TreatSubAssembliesAsComponents = True
idm.IgnoreHiddenBodies = True
idm.UseTransform = False
try:
n = idm.GetInterferenceCount
except AttributeError:
dd = idm._oleobj_.GetIDsOfNames('GetInterferenceCount')
n = idm._oleobj_.Invoke(dd, 0, pythoncom.DISPATCH_PROPERTYGET, 1)
P(u' 干涉 %s 处(基线 360)' % n)
hits = []
if n:
try:
items = idm.GetInterferences
except AttributeError:
dd = idm._oleobj_.GetIDsOfNames('GetInterferences')
items = idm._oleobj_.Invoke(dd, 0, pythoncom.DISPATCH_PROPERTYGET, 1)
for it in items:
o = it if hasattr(it, 'Volume') else wc.Dispatch(it)
nms = [wc.Dispatch(x).Name2.split('/')[0] for x in o.Components]
if any('ENDPLATE' in y.upper() for y in nms):
hits.append((o.Volume * 1e9, nms))
if hits:
P(u' ⚠ 端板相关 %d 处:' % len(hits))
for vv, nms in sorted(hits, reverse=True)[:6]:
P(u' %.3f mm³ %s ↔ %s' % (vv, nms[0][:24], nms[1][:24]))
else:
P(u' ✅ 端板与风扇/刀片/底板/托盘零干涉')
idm.Done()
except Exception as ex:
P(u' 干涉失败 %s' % str(ex)[:80])
try:
doc.InterferenceDetectionManager.Done()
except Exception:
pass