153 行
5.8 KiB
Python
153 行
5.8 KiB
Python
# -*- coding: utf-8 -*-
|
||
u"""量 PCIE 插槽**顶面开口**的真实长宽 —— 判断刀片舌头 36.0 插不插得进。
|
||
|
||
为什么不能用碰撞法:插槽模型把簧片触点建成了**刚性**的,两排触点自由间隙只有
|
||
1.22 mm,而 STEP 里刀片板厚 1.67 ⇒ 干涉检查在任何位置都报"插不进",
|
||
与舌头宽度无关。所以必须**直接量开口**。
|
||
|
||
两条互相独立的口径(两个都给,不一致就说明哪条的假设不成立):
|
||
A. 顶面那个平面的**内环**(inner loop)包围盒 = 开口轮廓
|
||
B. 落在卡槽通道里(|y − 通道中心| 小)的所有面的 x 并集 = 通道长度
|
||
|
||
⛔ 全程不碰 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'
|
||
|
||
|
||
def prop(o, name):
|
||
u"""0 参成员:多数是属性,但 GetFaces / GetLoops 这类是方法(NOTES §25)。
|
||
⛔ 不能用 callable() 判断(COM 对象一律 callable,§2),只认 python 方法类型。"""
|
||
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)
|
||
print(u'零件: %s' % part.GetTitle)
|
||
|
||
# 取面数最多的那个实体 = 塑料壳
|
||
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 个面' % nmax)
|
||
faces = prop(shell, 'GetFaces')
|
||
|
||
# ── 找顶面(法线 +Z、z 最高的平面)───────────────────────────────────
|
||
top, topz = None, -1e9
|
||
info = []
|
||
for f in faces:
|
||
fc = D(f)
|
||
try:
|
||
s = prop(fc, 'GetSurface')
|
||
if not prop(s, 'IsPlane'):
|
||
continue
|
||
nz = list(prop(s, 'PlaneParams'))[2]
|
||
fb = [v * 1000 for v in prop(fc, 'GetBox')]
|
||
info.append((fc, nz, fb))
|
||
if nz > 0.99 and fb[5] > topz:
|
||
top, topz = fc, fb[5]
|
||
except Exception:
|
||
continue
|
||
print(u'顶面 z = %.3f' % topz)
|
||
|
||
# ── 口径 A:顶面的内环 ───────────────────────────────────────────────
|
||
print(u'\n=== 口径 A:顶面的环(内环 = 开口)===')
|
||
try:
|
||
loops = prop(top, 'GetLoops')
|
||
print(u' 共 %d 个环' % len(loops))
|
||
for li, lp in enumerate(loops):
|
||
L = D(lp)
|
||
try:
|
||
outer = prop(L, 'IsOuter')
|
||
except Exception:
|
||
outer = '?'
|
||
xs, ys = [], []
|
||
try:
|
||
for e in prop(L, 'GetEdges'):
|
||
E = D(e)
|
||
try:
|
||
cp = list(prop(E, 'GetCurveParams2'))
|
||
pts = [(cp[0], cp[1], cp[2]), (cp[3], cp[4], cp[5])]
|
||
except Exception:
|
||
pts = []
|
||
for p in pts:
|
||
xs.append(p[0] * 1000); ys.append(p[1] * 1000)
|
||
except Exception as ex:
|
||
print(u' 环%d 取边失败 %s' % (li, str(ex)[:50])); continue
|
||
if xs:
|
||
print(u' 环%-2d 外环=%-5s x %8.3f~%8.3f (%6.3f) y %7.3f~%7.3f (%5.3f)'
|
||
% (li, outer, min(xs), max(xs), max(xs) - min(xs),
|
||
min(ys), max(ys), max(ys) - min(ys)))
|
||
except Exception as e:
|
||
print(u' ⛔ 取环失败: %s' % str(e)[:90])
|
||
|
||
# ── 口径 B:卡槽通道里所有面的 x 并集 ────────────────────────────────
|
||
print(u'\n=== 口径 B:卡槽通道内各面的 x 并集 ===')
|
||
YC = 0.74 # 通道中心线(由两排触点 -0.56 / +2.04 推出)
|
||
for halfw in (0.7, 0.9, 1.2):
|
||
xs = []
|
||
for fc, nz, fb in info:
|
||
ymid = (fb[1] + fb[4]) / 2.0
|
||
if abs(ymid - YC) < halfw and fb[5] > 1.5 and fb[2] < topz + 0.01:
|
||
xs.append(fb[0]); xs.append(fb[3])
|
||
if xs:
|
||
print(u' |y−%.2f|<%.1f ⇒ x %8.3f ~ %8.3f,通道长 **%.2f mm**'
|
||
% (YC, halfw, min(xs), max(xs), max(xs) - min(xs)))
|
||
|
||
print(u'\n对照:刀片舌头 36.00 mm(TONGUE_X0/X1 = 27.0/63.0,板局部)')
|
||
print(u' 塑料体全长 41.00 mm,顶面平面跨度 39.00 mm')
|