168 行
6.7 KiB
Python
168 行
6.7 KiB
Python
# -*- coding: utf-8 -*-
|
||
u"""把三块新板(南板 / 北板 / 顶盖)插进总装,封成盒子。
|
||
|
||
三块都**只平移不旋转**(旋转是本会话的重灾区,能不转就不转):
|
||
· 南板 `SouthPanel`:本地 y 0~2.4 ⇒ 平移 **dy = −6.4**,贴到托盘南边缘 y=−4 的外侧
|
||
· 北板 `NorthPanel`:本地 y 0~2.4 ⇒ 平移 **dy = +102**,贴到北边缘外侧
|
||
· 顶盖 `TopPanel` :本地 z 0~2.4 ⇒ 平移 **dz = +72**,内表面落在 z=72
|
||
(刀片顶 71.34 ⇒ 间隙 0.66,兼做上端导轨,咬边 ≤1 ✅)
|
||
|
||
⛔ `AddComponent4` 要求被插入的文档**处于打开状态**(NOTES §15)——
|
||
三个零件脚本收尾时都保持打开了,这里直接引用。
|
||
⛔ 判据:插完回读每块板的装配 box 与期望比对;再跑 fast 干涉,
|
||
基线是 360(5 刀片 × 72 簧片蹭),多出来的才是新板撞了。
|
||
"""
|
||
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'
|
||
DIR = u'D:\\DCDC\\新建文件夹\\5blades\\'
|
||
ASM = 'PhoneRail_5blades'
|
||
EMPTY = wc.VARIANT(pythoncom.VT_DISPATCH, None)
|
||
IDENT = [1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0]
|
||
|
||
# (文件, 标识, 平移, 期望装配 box)
|
||
# ⛔ 南北板原来贴在 y=−4 / 102(托盘边缘)。端板改成 y 对称后占 **−1.655~104.345**,
|
||
# 北板 102~104.4 与端板重叠 2.345 ⇒ 实测干涉 589 mm³。
|
||
# ✅ 南北板改为贴在**端板外侧**:北板内表面 104.345、南板外表面 −1.655。
|
||
# 这样三块板与端板共面收口,也不再和托盘(−4~102)冲突(托盘比它们窄,缩在里面)。
|
||
EP_Y0, EP_Y1 = -1.655, 104.345 # 端板 y 对称范围
|
||
PANELS = [
|
||
# v2:Type-C 开孔由 11.94×6.0 放大到 13×9(原高度 6.0 带护套的线插不进去)
|
||
(u'SouthPanel_v2.SLDPRT', u'南板', (0.0, EP_Y0 - 2.4, 0.0),
|
||
[-27.4, EP_Y0 - 2.4, -10.0, 125.4, EP_Y0, 72.0]),
|
||
(u'NorthPanel_v2.SLDPRT', u'北板', (0.0, EP_Y1, 0.0),
|
||
[-27.4, EP_Y1, -10.0, 125.4, EP_Y1 + 2.4, 72.0]),
|
||
# v2:泄压缝改 11 条、按盒子中心 49 对称(原 8 条按底板坐标定,偏在东半侧)
|
||
(u'TopPanel_v2.SLDPRT', u'顶盖', (0.0, 0.0, 72.0),
|
||
[-27.4, -4.0, 72.0, 125.4, 102.0, 74.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)
|
||
|
||
|
||
app = wc.GetActiveObject('SldWorks.Application')
|
||
doc = None
|
||
for d in app.GetDocuments or []:
|
||
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').upper()
|
||
if any(k in nm for k in ('SOUTHPANEL', 'NORTHPANEL', 'TOPPANEL')):
|
||
doc.ClearSelection2(True)
|
||
doc.Extension.SelectByID2(prop(c, 'Name2'), 'COMPONENT', 0, 0, 0, False, 0, EMPTY, 0)
|
||
doc.Extension.DeleteSelection2(0)
|
||
P(u' 删掉旧的 %s' % prop(c, 'Name2'))
|
||
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
|
||
|
||
|
||
P(u'\n插入三块板:')
|
||
allok = True
|
||
for fn, tag, t, want in PANELS:
|
||
path = DIR + fn
|
||
if not os.path.exists(path):
|
||
P(u' ⛔ %s 文件不存在' % tag); allok = False; continue
|
||
c = doc.AddComponent4(path, '', 0.0, 0.0, 0.0)
|
||
if c is None:
|
||
P(u' ⛔ %s AddComponent4 返回 None(零件没开着?)' % tag); allok = False; continue
|
||
xf = mk(IDENT + [t[0] / 1000.0, t[1] / 1000.0, t[2] / 1000.0, 1.0, 0.0, 0.0, 0.0])
|
||
try:
|
||
c.SetTransformAndSolve2(xf)
|
||
except Exception:
|
||
c.Transform2 = xf
|
||
doc.EditRebuild3
|
||
b = [round(v * 1000, 2) for v in c.GetBox(False, False)]
|
||
ok = all(abs(b[i] - want[i]) < 0.05 for i in range(6))
|
||
if not ok:
|
||
allok = False
|
||
P(u' %s %-18s box x %8.2f~%8.2f y %8.2f~%8.2f z %7.2f~%7.2f %s'
|
||
% (tag, prop(c, 'Name2')[:18], b[0], b[3], b[1], b[4], b[2], b[5],
|
||
u'✅' if ok else (u'⛔ 期望 %s' % want)))
|
||
|
||
for nm2, vid in ((u'box_iso', 7), (u'box_front', 1), (u'box_right', 4)):
|
||
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,基线 360):')
|
||
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 处' % 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(k in y.upper() for y in nms for k in ('PANEL',)):
|
||
hits.append((o.Volume * 1e9, nms))
|
||
if hits:
|
||
P(u' ⚠ 新板相关 %d 处:' % len(hits))
|
||
for vv, nms in sorted(hits, reverse=True)[:8]:
|
||
P(u' %.3f mm³ %s ↔ %s' % (vv, nms[0][:26], nms[1][:26]))
|
||
else:
|
||
P(u' ✅ 三块新板与所有件零干涉')
|
||
idm.Done()
|
||
except Exception as ex:
|
||
P(u' 干涉失败 %s' % str(ex)[:80])
|
||
try:
|
||
doc.InterferenceDetectionManager.Done()
|
||
except Exception:
|
||
pass
|