文件

511 行
22 KiB
Python

此文件含有模棱两可的 Unicode 字符
此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。
# -*- coding: utf-8 -*-
# v4:去北墙两个窗口;南墙 Type-C 开口 = 母座口内侧轮廓 8.34×2.60 R0.7
# v3 短机版:风扇 6010(孔距 50.2、Ø5.2 过孔)+ 分风腔 10;内腔 x −16~113.5、外 −18.4~115.9、导轨唇边 −24.8
u"""**v2 = v1 + 西端插拔式滤网导轨 + 建模内倒角**(2026-09-13)。
导轨让包围盒西界变成唇边 x −43.8,add_fillets 的「包围盒角」判据会漏掉西侧两角 ⇒ 圆角在加导轨之前做。
(以下为 v1 说明)**一体顶盖** TopShell_v1(2026-09-13 用户改方案:顶盖一体打印 + 底盖一整块 + 螺丝固定)。
= 顶板 + 南/北侧墙 + 西/东端墙 + 4 根内角立柱,底部敞开,从上往下扣在底盖上。
外形与上一版六件式完全一致(175.0 × 110.8,顶外表面 z=74.4、墙底 z=−10),
内腔也一致(x −36~134 / y −1.655~104.345 / 顶内表面 z=72)⇒ 15 mm 分风腔、0.66 顶隙原样保留。
零件本地坐标:x、y = 装配坐标;**本地 z = 装配 z − 74.4**(顶外表面在本地 z=0,全部往 −z 拉)。
装配时纯平移 dz = +74.4,不旋转。
建模顺序是刻意安排的(只用本机验证过的「基准面草图 + 拉伸,孔画进同一张草图」):
[1] 4 根角柱 10×10 + 柱内 Ø4.2 孔,前视面草图,向 −z 拉 84.4(孔此时是通的)
[2] 四面墙:外框 + 内框的环形轮廓,向 −z 拉 84.4
[3] 顶板 + 11 条泄压缝,向 −z 拉 2.4 —— **顺带把柱孔上端封死**,
柱孔变成从底面进、深 82 的盲孔(热熔螺母压在底口 6 mm 内即可),顶面看不到孔
[4] 端墙外表面:Ø60 风口 + 4 × Ø3.4 风扇孔(面上草图切)
[5] 南墙外表面:2 个 13×9 Type-C 窗口
[6] 北墙外表面:J33 窗口 + 风扇出线窗口
面上草图的 uv 映射按候选逐个试,每刀之后回读「目标孔/窗口是否出现在设计位置」;
候选都经过检查:错误映射只会把轮廓画到墙外(切不到料、返回 None)。
若出现「切出了东西但不在目标位置」立即停手、不存盘。
"""
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
DST = u'D:\\DCDC\\新建文件夹\\5blades\\TopShell_v4.SLDPRT'
EMPTY = wc.VARIANT(pythoncom.VT_DISPATCH, None)
ZOFF = 74.4 # 本地 z = 装配 z − ZOFF
X0, X1, Y0, Y1 = -18.4, 115.9, -4.055, 106.745 # 外形
IX0, IX1, IY0, IY1 = -16.0, 113.5, -1.655, 104.345 # 内腔
T = 2.4
H = 84.4 # 顶外 74.4 → 墙底 −10
SLOT_W, SLOT_L, SLOT_N, SLOT_SPAN = 1.5, 60.0, 11, 106.0
SLOT_XC, SLOT_YC = (X0 + X1) / 2.0, 51.345
POST = 10.0
POST_RECTS = [(IX0, IX0 + POST, IY0, IY0 + POST), (IX0, IX0 + POST, IY1 - POST, IY1),
(IX1 - POST, IX1, IY0, IY0 + POST), (IX1 - POST, IX1, IY1 - POST, IY1)]
POST_HOLES = [((a + b) / 2.0, (c + d) / 2.0) for a, b, c, d in POST_RECTS]
R_INS = 2.1
FAN_CY, FAN_CZ = 51.345, 37.85
R_VENT, R_FAN = 30.0, 2.6 # 风扇孔 Ø5.2:机箱自攻螺丝要穿墙拧进风扇 Ø4.4 孔
END_CIRCLES = [(FAN_CY, FAN_CZ, R_VENT)] + [(FAN_CY + dy, FAN_CZ + dz, R_FAN)
for dy in (-25.1, 25.1) for dz in (-25.1, 25.1)]
SOUTH_WINDOWS = [(6.0, 19.0, -5.7, 3.3), (77.5, 90.5, -5.7, 3.3)] # x0,x1,z0,z1(装配)
NORTH_WINDOWS = [(72.14, 87.85, -3.0, 12.0), (0.53, 19.03, -3.0, 15.0)]
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
def L(z):
return z - ZOFF
app = wc.GetActiveObject('SldWorks.Application')
for d in list(app.GetDocuments or []):
try:
t = prop(d, 'GetTitle') or ''
if 'TOPSHELL_V4' in t.upper():
app.CloseDoc(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 last_sketch():
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 bodies():
return part.GetBodies2(0, True) or []
def faces():
b = bodies()
return prop(D(b[0]), 'GetFaces') if b else []
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 cyls():
out = []
for f in faces():
fc = D(f)
s = prop(fc, 'GetSurface')
if prop(s, 'IsCylinder'):
cp = list(prop(s, 'CylinderParams'))
fb = [v * 1000 for v in prop(fc, 'GetBox')]
ax = max(range(3), key=lambda i: abs(cp[3 + i]))
out.append((round(cp[6] * 1000, 2), ax, fb))
return out
def hist():
h = {}
for r, _, _ in cyls():
h[r] = h.get(r, 0) + 1
return dict(sorted(h.items()))
def planes():
u"""[(朝外法线轴, 符号, box)] —— 朝外 = PlaneParams × (sense ? −1 : +1)(NOTES §36)"""
out = []
for f in faces():
fc = D(f)
s = prop(fc, 'GetSurface')
if not prop(s, 'IsPlane'):
continue
n = list(prop(s, 'PlaneParams'))[:3]
if prop(fc, 'FaceInSurfaceSense'):
n = [-v for v in n]
ax = max(range(3), key=lambda i: abs(n[i]))
out.append((ax, 1 if n[ax] > 0 else -1, [v * 1000 for v in prop(fc, 'GetBox')],
prop(fc, 'GetArea') * 1e6, fc))
return out
def boss(depth, rev):
if pick(last_sketch(), '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 check(tag, want, tol=0.02):
got = bbox()
ok = got is not None and all(abs(got[i] - want[i]) <= tol for i in range(6))
P(u' %s box %s %s' % (tag, got, u'✅' if ok else u'⛔ 期望 %s' % want))
if not ok:
sys.exit(2)
# ── [1] 角柱 + 柱孔 ───────────────────────────────────────────────────────
P(u'\n[1] 4 根角柱 %.0f×%.0f + Ø%.1f 孔,向 −z 拉 %.1f' % (POST, POST, 2 * R_INS, H))
pick(u'前视基准面', 'PLANE')
sm.InsertSketch(True)
sm.AddToDB = True
for a, b, c, d in POST_RECTS:
sm.CreateCornerRectangle(M(a), M(c), 0.0, M(b), M(d), 0.0)
for hx, hy in POST_HOLES:
sm.CreateCircleByRadius(M(hx), M(hy), 0.0, M(R_INS))
sm.AddToDB = False
sm.InsertSketch(True)
boss(H, True)
check(u'角柱', [IX0, IY0, -H, IX1, IY1, 0.0])
# ── [2] 四面墙(环形轮廓)────────────────────────────────────────────────
P(u'\n[2] 四面墙 环形轮廓,向 −z 拉 %.1f' % H)
pick(u'前视基准面', 'PLANE')
sm.InsertSketch(True)
sm.AddToDB = True
sm.CreateCornerRectangle(M(X0), M(Y0), 0.0, M(X1), M(Y1), 0.0)
sm.CreateCornerRectangle(M(IX0), M(IY0), 0.0, M(IX1), M(IY1), 0.0)
sm.AddToDB = False
sm.InsertSketch(True)
boss(H, True)
check(u'墙', [X0, Y0, -H, X1, Y1, 0.0])
# ── [3] 顶板 + 泄压缝(封住柱孔上端)──────────────────────────────────────
P(u'\n[3] 顶板 + %d 条泄压缝,向 −z 拉 %.1f' % (SLOT_N, T))
step = SLOT_SPAN / (SLOT_N - 1)
pick(u'前视基准面', 'PLANE')
sm.InsertSketch(True)
sm.AddToDB = True
sm.CreateCornerRectangle(M(X0), M(Y0), 0.0, M(X1), M(Y1), 0.0)
for i in range(SLOT_N):
xc = SLOT_XC - SLOT_SPAN / 2.0 + i * step
sm.CreateCornerRectangle(M(xc - SLOT_W / 2), M(SLOT_YC - SLOT_L / 2), 0.0,
M(xc + SLOT_W / 2), M(SLOT_YC + SLOT_L / 2), 0.0)
sm.AddToDB = False
sm.InsertSketch(True)
boss(T, True)
check(u'顶板', [X0, Y0, -H, X1, Y1, 0.0])
ph = [c for c in cyls() if abs(c[0] - R_INS) < 0.01 and c[1] == 2]
P(u' 柱孔 R%.1f 沿 z:%d 个(期望 4)' % (R_INS, len(ph)))
for r, ax, fb in ph:
P(u' 中心 (%.2f, %.2f) z %.2f~%.2f(期望 %.1f~%.1f,上端被顶板封住)'
% ((fb[0] + fb[3]) / 2, (fb[1] + fb[4]) / 2, fb[2], fb[5], -H, -T))
if len(ph) != 4 or any(abs(fb[5] - (-T)) > 0.05 or abs(fb[2] + H) > 0.05 for _, _, fb in ph):
P(u'⛔ 柱孔不对,停手'); sys.exit(3)
slot_faces = sum(1 for ax, sg, fb, a, _ in planes()
if ax == 0 and abs(fb[2] + T) < 0.05 and abs(fb[5]) < 0.05
and abs(fb[4] - fb[1] - SLOT_L) < 0.05)
P(u' 泄压缝侧面 %d 个(期望 %d = 每条 2)%s' % (slot_faces, 2 * SLOT_N,
u'✅' if slot_faces == 2 * SLOT_N else u'⛔'))
if slot_faces != 2 * SLOT_N:
sys.exit(3)
# ── [3b] 外轮廓 4 条竖边倒 R3(此时包围盒 = 盒体本身,导轨还没加)─────────
P(u'\n[3b] 外轮廓竖边倒 R3')
_bx = bbox()
_cand = []
for _e in prop(D(bodies()[0]), 'GetEdges'):
_E = D(_e)
try:
_p0 = [v * 1000 for v in prop(D(prop(_E, 'GetStartVertex')), 'GetPoint')]
_p1 = [v * 1000 for v in prop(D(prop(_E, 'GetEndVertex')), 'GetPoint')]
except Exception:
continue
if abs(_p0[0] - _p1[0]) > 1e-6 or abs(_p0[1] - _p1[1]) > 1e-6 or abs(_p0[2] - _p1[2]) < 1e-6:
continue
if all(min(abs(_p[i] - _bx[i]), abs(_p[i] - _bx[i + 3])) < 0.01 for _p in (_p0, _p1) for i in (0, 1)):
_cand.append(_E)
_done = 0
for _E in _cand:
for _r in (3.0, 2.0, 1.5):
part.ClearSelection2(True)
_E.Select4(False, EMPTY)
try:
_f = fm.FeatureFillet3(195, M(_r), 0, 0, 0, 0, 0, None, None, None, None, None, None, None)
except Exception:
_f = None
if _f:
_done += 1
break
P(u' 候选 %d 条,成功 %d 条;直方图 %s' % (len(_cand), _done, hist()))
if _done != 4 or hist().get(3.0, 0) != 4:
P(u'⛔ 圆角没做全,停手'); sys.exit(8)
# ── 面上草图切除(带候选映射)────────────────────────────────────────────
def pick_face(ax, sign, coord):
best, ba = None, -1.0
for a_, s_, fb, area, fc in planes():
if a_ != ax or s_ != sign:
continue
if abs(fb[ax] - coord) > 0.02 or abs(fb[ax + 3] - coord) > 0.02:
continue
if area > ba:
best, ba = fc, area
if best is None:
return False
part.ClearSelection2(True)
best.Select4(False, EMPTY)
return part.SelectionManager.GetSelectedObjectCount2(-1) == 1
def do_cut(depth):
if pick(last_sketch(), 'SKETCH') != 1:
return None
return fm.FeatureCut4(True, False, False, 0, 0, M(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)
def sketch_xform():
sk = prop(sm, 'ActiveSketch')
if not sk:
return None
arr = list(prop(D(sk), 'ModelToSketchTransform').ArrayData)
Mx = [[arr[3 * c + r] for c in range(3)] for r in range(3)] # 列主序
return Mx, arr[9:12]
def to_sketch(X, p):
u"""模型点 p(mm)→ 草图坐标(米)"""
Mx, t = X
q = [v / 1000.0 for v in p]
return [sum(Mx[r][c] * q[c] for c in range(3)) + t[r] for r in range(3)]
def open_face_sketch(face, tag):
ax, sign, coord = face
for attempt in range(1, 4):
if not pick_face(*face):
P(u' ⛔ %s 选不到面' % tag); sys.exit(4)
sm.InsertSketch(True)
X = sketch_xform()
ok, nax, sz = False, -1, 99.0
if X:
nax = max(range(3), key=lambda i: abs(X[0][2][i]))
probe = [0.0, 0.0, 0.0]
probe[ax] = coord
sz = to_sketch(X, probe)[2] * 1000.0
ok = nax == ax and abs(sz) < 0.01
P(u' %s 进草图 第 %d 次:法线轴 %s(目标 %s)、墙面点草图 z = %.4f mm %s'
% (tag, attempt, 'xyz'[nax] if nax >= 0 else '?', 'xyz'[ax], sz, u'✅' if ok else u'✗ 平面不对,退出重进'))
if ok:
return X
sm.InsertSketch(True)
P(u' ⛔ %s 三次都没进到目标面,停手' % tag); sys.exit(4)
def cut_shapes(tag, face, circles, rects, verify):
nbefore = len(faces())
X = open_face_sketch(face, tag)
sm.AddToDB = True
for p, r in circles:
q = to_sketch(X, p)
sm.CreateCircleByRadius(q[0], q[1], 0.0, M(r))
for p0, p1 in rects:
q0, q1 = to_sketch(X, p0), to_sketch(X, p1)
sm.CreateCornerRectangle(q0[0], q0[1], 0.0, q1[0], q1[1], 0.0)
sm.AddToDB = False
sm.InsertSketch(True)
c = do_cut(T + 0.2)
ok = verify()
P(u' %s 切除 → %-12r 面数 %d→%d 目标 %s'
% (tag, prop(c, 'Name') if c else c, nbefore, len(faces()), u'✅' if ok else u'⛔'))
if not ok:
P(u' ⛔⛔ 目标没出现在设计位置 —— 停手、不存盘'); sys.exit(5)
def end_verify(xwall):
def v():
cs = cyls()
for cy, cz, r in END_CIRCLES:
hit = any(abs(rr - r) < 0.01 and ax_ == 0 and
abs((fb[1] + fb[4]) / 2 - cy) < 0.05 and abs((fb[2] + fb[5]) / 2 - L(cz)) < 0.05 and
min(abs(fb[0] - xwall), abs(fb[3] - xwall)) < 0.05
for rr, ax_, fb in cs)
if not hit:
return False
return True
return v
def rect_verify(wins, ywall0, ywall1):
def v():
ps = planes()
for x0, x1, z0, z1 in wins:
for xe in (x0, x1):
hit = any(ax_ == 0 and abs(fb[0] - xe) < 0.05 and abs(fb[3] - xe) < 0.05 and
abs(fb[2] - L(z0)) < 0.05 and abs(fb[5] - L(z1)) < 0.05 and
fb[1] >= ywall0 - 0.05 and fb[4] <= ywall1 + 0.05
for ax_, sg, fb, a_, _ in ps)
if not hit:
return False
return True
return v
P(u'\n[4] 端墙:Ø60 风口 + 4 × Ø%.1f 风扇孔(孔距 %.1f)' % (2 * R_FAN, 2 * abs(END_CIRCLES[1][0] - FAN_CY)))
cut_shapes(u'西端墙', (0, -1, X0), [((X0, cy, L(cz)), r) for cy, cz, r in END_CIRCLES], [], end_verify(X0))
cut_shapes(u'东端墙', (0, +1, X1), [((X1, cy, L(cz)), r) for cy, cz, r in END_CIRCLES], [], end_verify(X1))
# ── [5] 南墙 Type-C:完全等于母座口内侧轮廓(用户拍板 2026-09-13)──────────────
# 母座 USB-C_SMD-TYPE-C-31-M-12 实测(STEP,本地→装配 x=12.5−lx / z=−lz):
# 内侧平直边 x ±4.17、z 0.35~2.95(本地)⇒ 8.34 × 2.60;四角圆柱 R0.70,圆心 (±3.47, 1.05/2.25)
# ⇒ 装配口中心 J1 (12.50, −1.65)、J23 (84.00, −1.65);口面 y=0.20,墙外表面 y=−4.055(缩进 4.26)
# 北墙原有 J33 / 风扇出线两个窗口:用户要求去掉,不再切。
USB_W, USB_H, USB_R = 8.34, 2.60, 0.70
USB_CX = (12.50, 84.00)
USB_CZ = -1.65
P(u'\n[5] 南墙 Type-C ×2:%.2f × %.2f、R%.2f,中心 z=%.2f(= 母座口内侧轮廓)' % (USB_W, USB_H, USB_R, USB_CZ))
def usb_shapes(cx):
hw, hh, r, cz = USB_W / 2, USB_H / 2, USB_R, L(USB_CZ)
lines = [((cx + hw - r, cz + hh), (cx - hw + r, cz + hh)),
((cx - hw, cz + hh - r), (cx - hw, cz - hh + r)),
((cx - hw + r, cz - hh), (cx + hw - r, cz - hh)),
((cx + hw, cz - hh + r), (cx + hw, cz + hh - r))]
arcs = [((cx + hw - r, cz + hh - r), (cx + hw, cz + hh - r), (cx + hw - r, cz + hh)),
((cx - hw + r, cz + hh - r), (cx - hw + r, cz + hh), (cx - hw, cz + hh - r)),
((cx - hw + r, cz - hh + r), (cx - hw, cz - hh + r), (cx - hw + r, cz - hh)),
((cx + hw - r, cz - hh + r), (cx + hw - r, cz - hh), (cx + hw, cz - hh + r))]
return lines, arcs
def usb_verify():
hw, hh, r, cz = USB_W / 2, USB_H / 2, USB_R, L(USB_CZ)
cs = cyls()
ps = planes()
for cx in USB_CX:
for ccx, ccz in ((cx + hw - r, cz + hh - r), (cx - hw + r, cz + hh - r),
(cx - hw + r, cz - hh + r), (cx + hw - r, cz - hh + r)):
if not any(abs(rr - r) < 0.01 and ax_ == 1 and fb[1] >= Y0 - 0.05 and fb[4] <= IY0 + 0.05 and
(abs(fb[0] - (ccx - r)) < 0.05 or abs(fb[3] - (ccx + r)) < 0.05) and
(abs(fb[2] - (ccz - r)) < 0.05 or abs(fb[5] - (ccz + r)) < 0.05)
for rr, ax_, fb in cs):
return False
for xe in (cx - hw, cx + hw):
if not any(ax_ == 0 and abs(fb[0] - xe) < 0.05 and abs(fb[3] - xe) < 0.05 and
abs(fb[2] - (cz - hh + r)) < 0.05 and abs(fb[5] - (cz + hh - r)) < 0.05
for ax_, sg, fb, a_, _ in ps):
return False
for ze in (cz - hh, cz + hh):
if not any(ax_ == 2 and abs(fb[2] - ze) < 0.05 and abs(fb[5] - ze) < 0.05 and
abs(fb[0] - (cx - hw + r)) < 0.05 and abs(fb[3] - (cx + hw - r)) < 0.05
for ax_, sg, fb, a_, _ in ps):
return False
return True
nbefore = len(faces())
X = open_face_sketch((1, -1, Y0), u'南墙')
sm.AddToDB = True
nseg = 0
for cx in USB_CX:
lines, arcs = usb_shapes(cx)
for p0, p1 in lines:
q0, q1 = to_sketch(X, (p0[0], Y0, p0[1])), to_sketch(X, (p1[0], Y0, p1[1]))
nseg += bool(sm.CreateLine(q0[0], q0[1], 0.0, q1[0], q1[1], 0.0))
for c, p1, p2 in arcs:
qc = to_sketch(X, (c[0], Y0, c[1]))
q1 = to_sketch(X, (p1[0], Y0, p1[1]))
q2 = to_sketch(X, (p2[0], Y0, p2[1]))
cross = (q1[0] - qc[0]) * (q2[1] - qc[1]) - (q1[1] - qc[1]) * (q2[0] - qc[0])
dirn = 1 if cross > 0 else -1 # 草图坐标系里取 90° 短弧:叉积正 = 逆时针
nseg += bool(sm.CreateArc(qc[0], qc[1], 0.0, q1[0], q1[1], 0.0, q2[0], q2[1], 0.0, dirn))
sm.AddToDB = False
P(u' 草图段 %d(期望 16 = 2 × (4 直线 + 4 圆弧))' % nseg)
sm.InsertSketch(True)
if nseg != 16:
P(u' ⛔ 草图段数不对,停手'); sys.exit(5)
c = do_cut(T + 0.2)
ok = usb_verify()
P(u' 南墙 切除 → %-12r 面数 %d→%d 母座口轮廓 %s'
% (prop(c, 'Name') if c else c, nbefore, len(faces()), u'✅ 4 圆角 + 4 直边 ×2 全在位' if ok else u'⛔'))
if not ok:
P(u' ⛔⛔ 开口没落在母座口轮廓上 —— 停手、不存盘'); sys.exit(5)
# ── [6b] 西端插拔式滤网导轨(前视面草图 L 形轮廓,向 −z 拉满高)───────────
FW, CLR, SLOT_T, LIP_T, SPACER, LIP = 70.0, 0.3, 4.4, 2.0, 4.0, 3.0
XO = X0 - SLOT_T - LIP_T # 唇边外表面 −43.8
YS0, YS1 = FAN_CY - FW / 2 - CLR, FAN_CY + FW / 2 + CLR # 滑槽 y 16.045 ~ 86.645
P(u'\n[6b] 滤网导轨:滑槽 x %.1f~%.1f(厚 %.1f)、y %.3f~%.3f;唇边 x %.1f~%.1f 压边 %.1f'
% (X0 - SLOT_T, X0, SLOT_T, YS0, YS1, XO, X0 - SLOT_T, LIP))
rails = [
[(X0, YS0 - SPACER), (XO, YS0 - SPACER), (XO, YS0 + LIP), (X0 - SLOT_T, YS0 + LIP),
(X0 - SLOT_T, YS0), (X0, YS0)],
[(X0, YS1 + SPACER), (XO, YS1 + SPACER), (XO, YS1 - LIP), (X0 - SLOT_T, YS1 - LIP),
(X0 - SLOT_T, YS1), (X0, YS1)],
]
pick(u'前视基准面', 'PLANE')
sm.InsertSketch(True)
sm.AddToDB = True
for poly in rails:
for i in range(len(poly)):
a, b = poly[i], poly[(i + 1) % len(poly)]
sm.CreateLine(M(a[0]), M(a[1]), 0.0, M(b[0]), M(b[1]), 0.0)
sm.AddToDB = False
sm.InsertSketch(True)
boss(H, True)
lips = [(fb[1], fb[4]) for ax, sg, fb, a, _ in planes()
if ax == 0 and sg == -1 and abs(fb[0] - XO) < 0.02 and abs(fb[3] - XO) < 0.02]
P(u' 唇边外表面 %d 个(期望 2):%s' % (len(lips), [(round(a, 3), round(b, 3)) for a, b in sorted(lips)]))
want_l = [(YS0 - SPACER, YS0 + LIP), (YS1 - LIP, YS1 + SPACER)]
if len(lips) != 2 or any(abs(a - c) > 0.02 or abs(b - d) > 0.02 for (a, b), (c, d) in zip(sorted(lips), want_l)):
P(u'⛔ 导轨不对,停手'); sys.exit(9)
# ── 验收 ──────────────────────────────────────────────────────────────────
P(u'\n[7] 验收')
check(u'最终', [XO, Y0, -H, X1, Y1, 0.0])
h = hist()
P(u' 圆柱面直方图 %s(期望 {0.7: 8, 2.1: 4, 2.6: 8, 3.0: 4, 30.0: 2})' % h)
if h.get(2.6, 0) != 8 or h.get(2.1, 0) != 4 or h.get(30.0, 0) != 2 or h.get(0.7, 0) != 8:
P(u'⛔ 孔数不对,不存盘'); sys.exit(7)
e1 = wc.VARIANT(pythoncom.VT_BYREF | pythoncom.VT_I4, 0)
w1 = wc.VARIANT(pythoncom.VT_BYREF | pythoncom.VT_I4, 0)
part.Extension.SaveAs3(DST, 0, 1, EMPTY, EMPTY, e1, w1)
P(u'\n另存 err=%s 存在=%s %.0f KB'
% (e1.value, os.path.exists(DST), os.path.getsize(DST) / 1024.0 if os.path.exists(DST) else 0))