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

424 行
21 KiB
Python
原始文件 Blame 文件历史

此文件含有模棱两可的 Unicode 字符
此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。
# -*- coding: utf-8 -*-
u"""托盘 v2:重建 + 装进总装。
⛔ 为什么不用 heredoc 跑:**bash heredoc 会打碎脚本里的中文路径**。
上一轮实测报错里路径变成了 `D:\\DCDC\\u65b0建文件夹\x05blades\\...`,
随后 `SaveAs3` 返回 err=1、文件没落盘。⇒ 含中文路径的脚本一律用 Write 落成 .py 再跑。
⛔ 旧的 `Tray_base.SLDPRT` 是**第一版躺错轴**的错版(box `x −4~102 / y 0~2.4 / z −102~4`),
已弃用;本脚本换名 `Tray_v2.SLDPRT`,并在开头关掉所有旧的 Tray 文档。
零件本地坐标(与底板局部坐标同向,装配时整体平移 z −POST_H 即可对上):
z = 0 托盘顶面(支柱根部)
z = −2.4 托盘底面
z = +15.0 支柱顶面(= 装配后 PCB 底面)
"""
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'
# v7:南边加两个 USB-C 缺口。实测托盘面板 z −2.40~0 与 USB-C 插入通道 z −3.25~0.85
# **重叠 2.40 mm**(两段 x 内各有 5 / 3 个面的板材)⇒ J1 与 J23 现在插不进去。
# v8:y 外扩到 −4.055~106.745,给南北板落脚(v7 时两板悬空、螺丝无处可打)。
# ⛔ 换名不覆盖:v7 正开在 SolidWorks 里(`~$Tray_v7` 锁文件),同名 SaveAs3 会 err=1。
# v9:托盘 y 改成与侧板**内表面**齐平(−1.655~104.345),让侧板从外侧包住托盘端面、
# 形成真正的面接触(v8 与外表面齐平 ⇒ 只是擦过,贴合面分析里一处接触都没有)。
# ⛔ 必须换名:v8 正开在 SolidWorks 里(锁文件在),同名 SaveAs3 已实测 err=1 且不写盘。
# v10:加 B 组螺丝凸台(每侧 3 个 Ø8×6,内嵌 Ø4.2 热熔螺母),
# 供南北板水平锁进托盘侧端面(贴合带 z −10~0,孔心取中线 z=−5.0)。
# v11:B 组凸台改用「遍历选端面 + 面上建草图」(v10 画在 y=0 平面,凸台位置全错,
# 只成了 3 个且悬在板外);B 组孔位同步挪到 x 30/49/68 避开 USB-C 开口。
DST = u'D:\\DCDC\\新建文件夹\\5blades\\Tray_v11.SLDPRT'
ASM = 'PhoneRail_5blades'
EMPTY = wc.VARIANT(pythoncom.VT_DISPATCH, None)
BW = BH = 98.0
# ⛔ 托盘原来 y −4~102(按 PCB + 4 外扩)。端板改 y 对称(−1.655~104.345)、南北板跟着
# 贴到端板外侧之后,南板落在 y −4.055~−1.66、北板 104.345~106.745 —— **全在托盘之外**,
# 贴合面分析里 Tray↔SouthPanel / Tray↔NorthPanel **一处接触都没有** ⇒ 两块板悬空、
# 螺丝无处可打。⚠ 干涉检查当时是 360 基线"零冲突",因为不接触本来就不干涉 ——
# **干涉为零不等于装配成立**。
# ✅ 托盘 y 外扩到与南北板外表面齐平:−4.055 ~ 106.745。
# ⛔ v8 把托盘 y 外扩到 −4.055~106.745(与侧板**外表面**齐平)——**没解决问题**:
# 贴合面分析里 Tray↔South/North 依旧一处接触都没有。因为侧板内表面在
# y=−1.655 / 104.345,托盘边缘却跑到了它们**外面**,两者只是侧面擦过、并不面接触。
# ✅ v9 改成与侧板**内表面**齐平:托盘 y = −1.655 ~ 104.345。
# 这样侧板从外侧正好包住托盘端面,形成真正的面接触,螺丝可从侧板水平拧进托盘侧棱。
TRAY_Y0, TRAY_Y1 = -1.655, 104.345
# ⛔ POST_H 由 15.0 降到 10.0(2026-09-13 用户要求「降低底部立柱高度」)。
# 15 的来历是 R2 决策 D15 那句「背面最高 12 mm(C2/C3 直立电解),底板下要 ≥15 mm 铜柱」——
# **这个前提已经失效**:C2/C3 早已挪到顶面(`pcb_base.TOP_EXTRA` = C2/C3/J26/J27/J33),
# 3D 实测底板背面最低只到 **−6.30**(SRP1265A 电感)。
# ⇒ 10.0 对背面件余量 **3.70**,同时给底板下的风扇线 / USB 线留走线空间。
# 改这一个常数即可(装配平移与断言都从它算,不许再写死)。
MARGIN, FLOOR_T, POST_H, POST_D = 4.0, 2.4, 10.0, 8.0
INSERT_D, INSERT_DEPTH = 4.2, 6.0
HOLES = [(4.0, 4.0), (94.0, 4.0), (4.0, 94.0), (94.0, 94.0)]
# ── 端板锁孔(2026-09-13 用户选 B:端板独立、螺丝锁到托盘)──────────────
# 端板在风扇外侧(西 x −27.4~−25 / 东 x 123~125.4),底部带 25 长的 L 脚伸回来,
# 在 x −4~0(西)与 98~102(东)这两段压在托盘面板上 ⇒ 锁孔打在这两段里。
# y 取 51.345 ± 30 = 21.345 / 81.345(风扇螺孔投影在 26.345/76.345,错开 5)。
# ⛔ 第一版孔心放在 x=−2.0 / 100.0:孔半径 2.1 ⇒ 圆占 x −4.1~0.1,**越过面板边界 −4**,
# 轮廓自相交 ⇒ `FeatureExtrusion3` 返回 None、整个零件建不出来(回读 box 为 None)。
# ⇒ 内移到 x=1.0 / 97.0:离边 5.0,孔外侧还剩 2.9 壁厚。端板 L 脚相应加长到 28。
# ⛔⛔ x=1.0 / 97.0 也是错的:实测底板 PCB 占 x **0.01~97.99**,这两排孔正好**落在 PCB 底下**,
# 螺丝拧不进去。托盘露在 PCB 之外的环只有 **4.01 mm**(西 −4.00~0.01 / 东 97.99~102.00)。
# ⇒ 锁孔退到环中线 **x = −2.0 / 100.0**。
# (最早那版也用过 −2.0 并"破边"失败,但那是草图自动捕捉把 r=2.1 吸成 3.1 所致;
# 现在 `AddToDB=True` 已根治,−2.0 离边 2.0、孔半径 2.1 —— 仍会破边!
# ⇒ 取环中线偏内一点:**x = −1.9 / 99.9**,离托盘边 2.1 正好等于孔半径,
# 再往内就压到 PCB。孔壁与托盘边**相切**,所以把孔径改小到 Ø3.4(M3 过孔,
# 螺母改用底面沉入的 M3 螺母或自攻螺丝),孔半径 1.7 ⇒ 离边 2.3、离 PCB 1.7,两侧都有料。
END_HOLES = [(-1.9, 21.345), (-1.9, 81.345), (99.9, 21.345), (99.9, 81.345)]
# ⛔ 由 Ø4.2 热熔螺母孔改成 **Ø3.4 过孔**:环只有 4.01 宽,Ø4.2 的孔(半径 2.1)
# 放在环中线上会与托盘外边相切/破边。Ø3.4 的孔离边 2.3、离 PCB 1.7,两侧都有料。
# ⇒ 端板用 M3 螺丝穿过托盘,从**底面**上螺母(或用自攻螺丝)。
END_INSERT_D = 3.4
END_INSERT_DEPTH = 2.4 # 打穿 2.4 厚的面板
# ⛔ y 不再用 ±MARGIN:端板改 y 对称后南北板贴到端板外侧(−4.055 / 106.745),
# 托盘若仍是 −4~102,两块板整个落在托盘之外 ⇒ 悬空、螺丝无处可打
# (贴合面分析里 Tray↔South/North 一处接触都没有,而干涉却是"零冲突")。
# ✅ y 外扩到与南北板外表面齐平。x 方向不动(端板 L 脚已在 x 上锁住托盘)。
X0, X1, Y0, Y1 = -MARGIN, BW + MARGIN, TRAY_Y0, TRAY_Y1
def prop(o, n):
v = getattr(o, n)
return v() if type(v).__name__ in ('method', 'function', 'builtin_function_or_method') else v
def D(x):
return x if hasattr(x, '_oleobj_') else wc.Dispatch(x)
def P(*a):
print(*a)
def M(v):
return v / 1000.0
app = wc.GetActiveObject('SldWorks.Application')
P(u'目标目录存在=%s' % os.path.isdir(os.path.dirname(DST)))
for d in list(app.GetDocuments):
try:
t = prop(d, 'GetTitle') or ''
if 'TRAY' in t.upper():
app.CloseDoc(t)
P(u'关掉旧文档 %s' % t)
except Exception:
pass
tmpl = app.GetUserPreferenceStringValue(8)
app.NewDocument(tmpl, 0, 0.0, 0.0)
part = app.ActiveDoc
P(u'新建零件 %s' % prop(part, 'GetTitle'))
sm, fm = part.SketchManager, part.FeatureManager
def sk_name():
nm, f = None, prop(part, 'FirstFeature')
while f:
if prop(f, 'GetTypeName2') == 'ProfileFeature':
nm = prop(f, 'Name')
f = prop(f, 'GetNextFeature')
return nm
def pick(name, typ):
part.ClearSelection2(True)
part.Extension.SelectByID2(name, typ, 0, 0, 0, False, 0, EMPTY, 0)
return part.SelectionManager.GetSelectedObjectCount2(-1)
def extrude(depth, rev=False):
if pick(sk_name(), 'SKETCH') != 1:
raise RuntimeError(u'草图没选中')
return fm.FeatureExtrusion3(True, False, rev, 0, 0, M(depth), 0.0,
False, False, False, False, 0.0, 0.0,
False, False, False, False, True, True, True, 0, 0.0, False)
def bodies():
return part.GetBodies2(0, True) or []
def bbox():
b = bodies()
if not b:
return None
xs = [[round(v * 1000, 3) for v in prop(D(x), 'GetBodyBox')] for x in b]
return [min(v[0] for v in xs), min(v[1] for v in xs), min(v[2] for v in xs),
max(v[3] for v in xs), max(v[4] for v in xs), max(v[5] for v in xs)]
def check(tag, want, tol=0.02):
got = bbox()
ok = got and all(abs(got[i] - want[i]) <= tol for i in range(6))
P(u' %s box %s 期望 %s %s' % (tag, got, want, u'✅' if ok else u'⛔'))
return ok
P(u'\n[1] 托盘底板 %.0f×%.0f×%.1f + 4 个端板锁孔(同一张草图,一次拉伸成形)'
% (X1 - X0, Y1 - Y0, FLOOR_T))
# ⛔ 端板锁孔不再用 FeatureCut4:托盘面板 z=0 那一面的法线是 (0,0,−1)(建模时从 z=0 往 −z 拉),
# z=0 处没有朝上的自由面,按坐标选面 / 前视基准面草图、rev 两个方向**全部返回 None**
# (用「Ø4.2 圆柱面计数」这个有分辨力的判据复验过:始终只有 4 个 = 只有柱顶孔)。
# ✅ 改成把 4 个圆和外框矩形放进**同一张草图**,拉伸时圆自然成为通孔,不需要切除特征。
pick(u'前视基准面', 'PLANE')
sm.InsertSketch(True)
# ⛔⛔ 必须开 AddToDB:否则 SolidWorks 的草图**自动捕捉会静默改掉几何** ——
# 实测 (1.0, 21.345) r=2.1 被吸成 **(0.0, 21.345) r=3.1**(圆心挪到原点纵轴、半径 +1.0),
# 于是锁孔要么尺寸不对、要么越界让整个轮廓失效。AddToDB=True 时几何按精确坐标写库、
# 不做任何推理,四个圆回读全部精确。
sm.AddToDB = True
# 外框改成带两个南侧缺口的折线(缺口从南边 Y0 往里挖到 y=0.20,正好让开 USB-C 插入通道)
# 缺口 x 区间实测:J1 6.53~18.47、J23 78.03~89.97(各含每侧 1.5 装配余量)
NOTCH_Y = 0.20
_pts = [(X0, Y0), (6.53, Y0), (6.53, NOTCH_Y), (18.47, NOTCH_Y), (18.47, Y0),
(78.03, Y0), (78.03, NOTCH_Y), (89.97, NOTCH_Y), (89.97, Y0),
(X1, Y0), (X1, Y1), (X0, Y1), (X0, Y0)]
for _i in range(len(_pts) - 1):
_a, _b = _pts[_i], _pts[_i + 1]
sm.CreateLine(M(_a[0]), M(_a[1]), 0.0, M(_b[0]), M(_b[1]), 0.0)
for hx, hy in END_HOLES:
sm.CreateCircleByRadius(M(hx), M(hy), 0.0, M(END_INSERT_D / 2))
sm.AddToDB = False
_sk = prop(sm, 'ActiveSketch')
_segs = prop(D(_sk), 'GetSketchSegments') if _sk else None
P(u' 草图 segment = %d(期望 4 线 + 4 圆 = 8)' % (len(_segs) if _segs else 0))
sm.InsertSketch(True)
extrude(FLOOR_T, rev=True)
if not check(u'底板', [X0, Y0, -FLOOR_T, X1, Y1, 0.0]):
sys.exit(2)
P(u'\n[2] 四支柱 Ø%.0f 高 %.0f' % (POST_D, POST_H))
pick(u'前视基准面', 'PLANE')
sm.InsertSketch(True)
for hx, hy in HOLES:
sm.CreateCircleByRadius(M(hx), M(hy), 0.0, M(POST_D / 2))
sm.InsertSketch(True)
extrude(POST_H, rev=False)
if not check(u'底板+支柱', [X0, Y0, -FLOOR_T, X1, Y1, POST_H]):
sys.exit(3)
P(u'\n[3] 柱顶热熔螺母孔 Ø%.1f 深 %.1f(FeatureCut4 = 27 参)' % (INSERT_D, INSERT_DEPTH))
part.ClearSelection2(True)
ok = part.Extension.SelectByID2('', 'FACE', M(HOLES[0][0]), M(HOLES[0][1]), M(POST_H),
False, 0, EMPTY, 0)
n = part.SelectionManager.GetSelectedObjectCount2(-1)
P(u' 按坐标选柱顶面 返回=%s 选中数=%s' % (ok, n))
if n == 1:
sm.InsertSketch(True)
for hx, hy in HOLES:
sm.CreateCircleByRadius(M(hx), M(hy), M(POST_H), M(INSERT_D / 2))
sm.InsertSketch(True)
pick(sk_name(), 'SKETCH')
try:
cut = fm.FeatureCut4(True, False, False, 0, 0, M(INSERT_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)
P(u' FeatureCut4 → %r' % (prop(cut, 'Name') if cut else cut))
except Exception as ex:
P(u' ⛔ FeatureCut4 失败: %s' % str(ex)[:110])
check(u'切孔后', [X0, Y0, -FLOOR_T, X1, Y1, POST_H])
else:
P(u' ⚠ 选不到柱顶面,跳过孔')
# ── [4] 已作废:端板锁孔改在第 1 步的草图里一次成形(见那里的说明)────────
# 这里原本用 FeatureCut4 切孔,两个方向都恒返回 None,已删除,免得重复打孔或污染日志。
# ── [3b] B 组螺丝凸台:托盘两侧端面各 3 个 Ø8×6,供南北板水平锁进来 ──────
# 2.4 的面板边攻不住 M3 ⇒ 加凸台内嵌 Ø4.2 热熔螺母。孔心在贴合带中线 z=−5.0。
BOSS_D, BOSS_H = 8.0, 6.0
# ⛔ B 组孔位与南板同步改成两个 USB-C 开口之间的实心区(原 11/49/87 会撞开口)
B_X = (30.0, 49.0, 68.0)
B_Z = -5.0
P(u'\n[3b] B 组凸台:两侧端面各 3 个 Ø%.0f×%.0f(孔心 z=%.1f)' % (BOSS_D, BOSS_H, B_Z))
# ⛔ 上一版画在**上视基准面**:草图在 y=0 平面,拉伸从 y=0 起算而不是从端面起算 ⇒
# 南侧凸台长到 y −6~0(悬在板外)、北侧 3 个整个埋进板体,只成了 3 个(R4.0 从 4→7)。
# `T0/StartOffset` 本会话已实测静默失效,不能用。
# ✅ 改走「遍历选端面 → 面上建草图 → 拉伸」——托盘柱顶孔已验证这条路可行,
# 面上草图接受**模型坐标**(那次传的就是 (x, y, z=柱顶高))。
for tag, ynom, rev in ((u'南侧', Y0, True), (u'北侧', Y1, False)):
# 遍历找法线沿 ±y、且位置等于该端面的平面
tgt, tarea = None, -1.0
for _f in prop(D(bodies()[0]), 'GetFaces'):
_fc = D(_f)
_s = prop(_fc, 'GetSurface')
if not prop(_s, 'IsPlane'):
continue
_n = list(prop(_s, 'PlaneParams'))
if abs(abs(_n[1]) - 1.0) > 0.01: # 法线必须沿 y
continue
_fb = [round(v * 1000, 3) for v in prop(_fc, 'GetBox')]
if abs(_fb[1] - ynom) > 0.01 or abs(_fb[4] - ynom) > 0.01:
continue
_a = prop(_fc, 'GetArea') * 1e6
if _a > tarea:
tgt, tarea = _fc, _a
if tgt is None:
P(u' ⛔ %s 没找到 y=%.3f 的端面' % (tag, ynom))
continue
part.ClearSelection2(True)
tgt.Select4(False, EMPTY)
if part.SelectionManager.GetSelectedObjectCount2(-1) != 1:
P(u' ⛔ %s 端面没选中' % tag)
continue
sm.InsertSketch(True)
sm.AddToDB = True
# ⛔ 面上草图**不接受模型坐标**(我误以为接受,托盘柱顶孔那次是巧合:
# 那是 z 常量面,草图 xy 恰好与模型 xy 一致)。
# y 端面实测映射:草图 u → 模型 x、草图 v → 模型 **−z**、法线 → +y。
# 传 (bx, ynom, B_Z) 会把 ynom 当成 v ⇒ 凸台被甩到 z=−104,还吞掉已有特征。
# ✅ 正确写法:第三参恒 0,v 传 −z。
for bx in B_X:
sm.CreateCircleByRadius(M(bx), M(-B_Z), 0.0, M(BOSS_D / 2))
sm.AddToDB = False
sm.InsertSketch(True)
if pick(sk_name(), 'SKETCH') != 1:
P(u' ⛔ %s 草图没选中' % tag)
continue
f = fm.FeatureExtrusion3(True, False, rev, 0, 0, M(BOSS_H), 0.0,
False, False, False, False, 0.0, 0.0,
False, False, False, False, True, True, True,
0, 0.0, False)
P(u' %s 端面(面积 %.0f mm²) 凸台 → %r' % (tag, tarea, prop(f, 'Name') if f else f))
P(u' 加凸台后 box %s' % bbox())
P(u' 圆柱面直方图 %s(R4.0 应为 4 支柱 + 6 凸台 = 10)'
% {r: n for r, n in sorted({}.items())} if False else u'')
P(u'\n[4] 复验孔(两种孔径分开数 —— 上一版把两者混成一个 8 的期望值,误报了)')
# ⛔ 柱顶热熔螺母孔是 **Ø4.2**,端板锁孔是 **Ø3.4**,半径不同不能合并计数。
# 上一版写「Ø3.4 应有 8 个 = 4 柱顶 + 4 端板」⇒ 柱顶那 4 个根本不是 3.4,
# 于是永远只数到 4,把已经成形的锁孔误判成"没成形"并提前退出。
_bd = D(bodies()[0])
_hist = {}
for _f in prop(_bd, 'GetFaces'):
_s = prop(D(_f), 'GetSurface')
if prop(_s, 'IsCylinder'):
_r = round(list(prop(_s, 'CylinderParams'))[6] * 1000, 2)
_hist[_r] = _hist.get(_r, 0) + 1
P(u' 圆柱面直方图 = %s' % dict(sorted(_hist.items())))
_n_end = _hist.get(round(END_INSERT_D / 2, 2), 0) # Ø3.4 ⇒ R1.7:端板锁孔
_n_post = _hist.get(round(INSERT_D / 2, 2), 0) # Ø4.2 ⇒ R2.1:柱顶螺母孔
P(u' 端板锁孔 Ø%.1f = %d 个(期望 4)%s' % (END_INSERT_D, _n_end, u'✅' if _n_end >= 4 else u'⛔'))
P(u' 柱顶孔 Ø%.1f = %d 个(期望 4)%s' % (INSERT_D, _n_post, u'✅' if _n_post >= 4 else u'⛔'))
if _n_end < 4 or _n_post < 4:
P(u'⛔ 停手:包围盒断言对通孔没有分辨力,必须靠这个计数判'); sys.exit(4)
e1 = wc.VARIANT(pythoncom.VT_BYREF | pythoncom.VT_I4, 0)
w1 = wc.VARIANT(pythoncom.VT_BYREF | pythoncom.VT_I4, 0)
r = part.Extension.SaveAs3(DST, 0, 1, EMPTY, EMPTY, e1, w1)
# ⚠ NOTES §11 的固定动作:不信返回值,看文件真的在不在
P(u'\n另存 返回=%s err=%s 存在=%s %.0f KB'
% (r, e1.value, os.path.exists(DST), os.path.getsize(DST) / 1024.0 if os.path.exists(DST) else 0))
if not os.path.exists(DST):
P(u'⛔ 文件没落盘,停手(零件留着便于排查)')
sys.exit(5)
# ⛔ 不要在插入前 CloseDoc:本会话三次成功的 AddComponent4(风扇占位体 / OD6025 / STEP 临时件)
# 共同点都是**被插入的文档当时还开着**;唯一一次关掉零件再插,就恒返回 None
# (文件明明存在、86 KB)。⇒ 保持零件打开。
P(u'零件保持打开(AddComponent4 疑似要求目标文档在打开状态)')
# ── 4) 插进总装 ───────────────────────────────────────────────────────
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(6)
e2 = wc.VARIANT(pythoncom.VT_BYREF | pythoncom.VT_I4, 0)
app.ActivateDoc3(prop(doc, 'GetTitle'), False, 0, e2)
doc = app.ActiveDoc
for c in list(doc.GetComponents(True)):
if 'TRAY' in prop(c, 'Name2').upper():
doc.ClearSelection2(True)
doc.Extension.SelectByID2(prop(c, 'Name2'), 'COMPONENT', 0, 0, 0, False, 0, EMPTY, 0)
doc.Extension.DeleteSelection2(0)
P(u'删掉旧托盘零部件')
doc.EditRebuild3
c = doc.AddComponent4(DST, '', 0.0, 0.0, 0.0)
P(u'AddComponent4 → %s' % (prop(c, 'Name2') if c else u'⛔ None'))
if c is None:
sys.exit(7)
did = app._oleobj_.GetIDsOfNames('GetMathUtility')
mu = wc.Dispatch(app._oleobj_.Invoke(did, 0, pythoncom.DISPATCH_METHOD, 1))
d2 = mu._oleobj_.GetIDsOfNames('CreateTransform')
xf = wc.Dispatch(mu._oleobj_.Invoke(d2, 0, pythoncom.DISPATCH_METHOD, 1,
wc.VARIANT(pythoncom.VT_ARRAY | pythoncom.VT_R8,
[1.0, 0, 0, 0, 1.0, 0, 0, 0, 1.0,
0.0, 0.0, -M(POST_H), 1.0, 0.0, 0.0, 0.0])))
try:
c.SetTransformAndSolve2(xf)
except Exception:
c.Transform2 = xf
doc.EditRebuild3
b = [round(x * 1000, 3) for x in c.GetBox(False, False)]
want = [X0, Y0, -(POST_H + FLOOR_T), X1, Y1, 0.0]
P(u'托盘装配 box %s 期望 %s %s'
% (b, want, u'✅' if all(abs(b[i] - want[i]) < 0.05 for i in range(6)) else u'⛔'))
for nm2, vid in ((u'tray_iso', 7), (u'tray_front', 1), (u'tray_right', 4)):
try:
doc.ShowNamedView2('', vid)
doc.ViewZoomtofit2
doc.SaveBMP(os.path.join(OUT, '%s.bmp' % nm2), 1600, 1100)
except Exception:
pass
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:
nn = idm.GetInterferenceCount
except AttributeError:
dd = idm._oleobj_.GetIDsOfNames('GetInterferenceCount')
nn = idm._oleobj_.Invoke(dd, 0, pythoncom.DISPATCH_PROPERTYGET, 1)
P(u' 干涉 %s 处(基线 360)' % nn)
hits = []
if nn:
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('TRAY' 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)[:5]:
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