# -*- 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