# -*- coding: utf-8 -*- u"""量 PCIE 插槽的**可插入深度** —— 卡降到哪里会被挡住。 限制插入深度的有两个独立约束,必须分开算(很容易只算一个就下结论): 1. **槽底**:开口区域内最高的朝上平面。 2. **防呆键筋**:键筋从顶面往下伸多深。刀片缺口只有 NOTCH_D=7.45 深 —— 若键筋比缺口深,卡会被**键筋顶住**,先于槽底停下。 开口尺寸由 slot_opening_measure.py 量得(顶面 z=10.000,x ±17.540,y −0.160~1.640, 键筋 x −5.390~−4.610)。 ⛔ 全程不碰 IInterferenceDetectionMgr(NOTES §24)。 """ import io, re, subprocess, sys, time sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8') import pythoncom import win32com.client as wc BASE_STEP = r'D:\DCDC\新建文件夹\3D_BASE-PCB_2026-09-12.step' TOP_Z = 10.000 # 塑料体顶面(零件本地) OPEN_X0, OPEN_X1 = -17.540, 17.540 # 开口 x OPEN_Y0, OPEN_Y1 = -0.160, 1.640 # 开口 y KEY_X0, KEY_X1 = -5.390, -4.610 # 防呆键筋 x BLADE_T = 1.67 # STEP 刀片板厚 NOTCH_D = 7.45 # 刀片缺口深度(fp_edge.NOTCH_D) # 装配坐标换算(由槽3 反推):assembly_z = part_z + 2.33;底板板面 assembly z = 1.67 Z_OFF, BOARD_TOP = 2.33, 1.67 def prop(o, name): v = getattr(o, name) if type(v).__name__ in ('method', 'function', 'builtin_function_or_method'): return v() return v def D(x): return x if hasattr(x, '_oleobj_') else wc.Dispatch(x) def sw_pids(): out = subprocess.run(['tasklist', '/FI', 'IMAGENAME eq SLDWORKS.EXE', '/FO', 'CSV', '/NH'], capture_output=True, text=True, encoding='gbk', errors='ignore').stdout return sorted(re.findall(r'"SLDWORKS\.exe","(\d+)"', out, re.I)) app = None try: app = wc.GetActiveObject('SldWorks.Application') print(u'✅ 复用现有实例(文档数 %s)' % app.GetDocumentCount) except Exception as e: print(u'✗ 连不上 (%s) → 自愈' % str(e)[:50]) if sw_pids(): subprocess.run(['taskkill', '/F', '/IM', 'SLDWORKS.exe'], capture_output=True) time.sleep(4) for k in range(20): try: app = wc.Dispatch('SldWorks.Application'); app.Visible = True _ = app.RevisionNumber; break except Exception: if k == 19: raise time.sleep(5) if app.GetDocumentCount == 0: print(u'导入底板 STEP…') data = app.GetImportFileData(BASE_STEP) err = wc.VARIANT(pythoncom.VT_BYREF | pythoncom.VT_I4, 0) t0 = time.time(); app.LoadFile4(BASE_STEP, 'r', data, err) print(u' err=%s %.1fs' % (err.value, time.time() - t0)) part = None for d in app.GetDocuments: try: if d.GetType == 1 and 'PCIE' in d.GetTitle.upper() and '64P11L' in d.GetTitle.upper(): part = d; break except Exception: pass if part is None: print(u'⛔ 没找到插槽零件'); sys.exit(1) shell, nmax = None, -1 for bd in part.GetBodies2(0, True): b = D(bd) try: n = len(prop(b, 'GetFaces')) except Exception: continue if n > nmax: shell, nmax = b, n print(u'塑料壳:%d 个面\n' % nmax) # 刀片板料在通道里实际占据的 y 带(按开口中心对中) yc = (OPEN_Y0 + OPEN_Y1) / 2.0 BY0, BY1 = yc - BLADE_T / 2.0, yc + BLADE_T / 2.0 print(u'开口 y %.3f~%.3f(宽 %.2f);刀片料占 y %.3f~%.3f(厚 %.2f)' % (OPEN_Y0, OPEN_Y1, OPEN_Y1 - OPEN_Y0, BY0, BY1, BLADE_T)) def ovl(a0, a1, b0, b1): return min(a1, b1) - max(a0, b0) up_in_slot, key_faces, all_in = [], [], [] for f in prop(shell, 'GetFaces'): fc = D(f) try: fb = [v * 1000 for v in prop(fc, 'GetBox')] except Exception: continue if fb[2] > TOP_Z - 1e-6: # 完全在顶面及以上,跳过 continue # 与刀片料所占空间在 x/y 上有重叠的面 if ovl(fb[0], fb[3], OPEN_X0, OPEN_X1) <= 1e-6: continue if ovl(fb[1], fb[4], BY0, BY1) <= 1e-6: continue nz = None try: s = prop(fc, 'GetSurface') if prop(s, 'IsPlane'): nz = list(prop(s, 'PlaneParams'))[2] except Exception: pass is_key = ovl(fb[0], fb[3], KEY_X0, KEY_X1) > 1e-6 and (fb[3] - fb[0]) < 2.0 all_in.append((fb[5], fb, nz, is_key)) if is_key: key_faces.append((fb[5], fb)) elif nz is not None and nz > 0.99: up_in_slot.append((fb[5], fb)) print(u'\n=== 通道内(与刀片料重叠)的面:按 z 顶端排序,前 14 ===') all_in.sort(reverse=True) for z, fb, nz, is_key in all_in[:14]: print(u' z顶 %7.3f z底 %7.3f x %8.3f~%8.3f y %7.3f~%7.3f 法线z=%s %s' % (fb[5], fb[2], fb[0], fb[3], fb[1], fb[4], ('%+.2f' % nz) if nz is not None else ' 曲面', u'← 键筋' if is_key else u'')) print(u'\n=== 约束 1:槽底(通道内最高的朝上平面,已排除键筋)===') if up_in_slot: up_in_slot.sort(reverse=True) z, fb = up_in_slot[0] d1 = TOP_Z - z print(u' 槽底 z = %.3f x %.3f~%.3f y %.3f~%.3f' % (z, fb[0], fb[3], fb[1], fb[4])) print(u' ⇒ 槽深(顶面到槽底)= %.2f − %.2f = **%.2f mm**' % (TOP_Z, z, d1)) else: d1 = None print(u' ⛔ 通道内没有朝上平面') print(u'\n=== 约束 2:防呆键筋 ===') if key_faces: kz_top = max(k[0] for k in key_faces) kz_bot = min(k[1][2] for k in key_faces) kh = kz_top - kz_bot print(u' 键筋 z %.3f ~ %.3f,高 **%.2f mm**' % (kz_bot, kz_top, kh)) print(u' 刀片缺口深 %.2f ⇒ %s' % (NOTCH_D, u'缺口比键筋深 %.2f,键筋不限制插入' % (NOTCH_D - kh) if NOTCH_D >= kh else u'**键筋比缺口深 %.2f,卡会被键筋顶住**' % (kh - NOTCH_D))) d2 = NOTCH_D if kh > NOTCH_D else None else: kh, d2 = None, None print(u' ⛔ 没识别出键筋面') print(u'\n=== 结论 ===') cands = [(u'槽底', d1), (u'防呆键筋', d2)] cands = [(n, v) for n, v in cands if v is not None] if cands: name, d = min(cands, key=lambda t: t[1]) print(u' 实际可插入深度 d = **%.2f mm**(受「%s」限制)' % (d, name)) print(u' ⇒ 刀片底边在底板局部 z = %.2f − %.2f = %.2f' % (TOP_Z + Z_OFF, d, TOP_Z + Z_OFF - d)) print(u' ⇒ **刀片底边离底板板面 = %.2f mm**(板面 z=%.2f)' % (TOP_Z + Z_OFF - d - BOARD_TOP, BOARD_TOP)) print(u' ⇒ 对照设计文档写的「抬高约 11 mm」:上限 10.66(完全不插),实际 %.2f' % (TOP_Z + Z_OFF - d - BOARD_TOP))