182 行
6.0 KiB
Python
182 行
6.0 KiB
Python
# -*- coding: utf-8 -*-
|
||
u"""在已开着的 EndPlate_v11 上补南侧面 A 组 2 个孔,另存为 v12。
|
||
|
||
v11 实测:C 组 2 孔 + 北侧面 A 组 2 孔全部**位置正确**(回读轴线核过),
|
||
只有南侧面(朝外法线 −y)那一刀 `FeatureCut4 → None`。
|
||
北侧面(朝外 +y)用的映射 u→x、v→−z 是对的;
|
||
假设:**朝外 −y 的面上草图 u 轴是镜像的**(u→−x),圆画到了 x=−7.4、落在材料外,
|
||
没东西可切所以返回 None。
|
||
|
||
做法:按候选映射依次试,每刀之后回读「南侧应有的孔」是否出现在
|
||
x 7.4 / y −1.655~4.345 / z 10、60;对了就停。
|
||
候选里错误的映射都会把圆画到材料外(x −7.4 或 z −10/−60 处没有料)⇒ 只会返回 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\\EndPlate_v12.SLDPRT'
|
||
EMPTY = wc.VARIANT(pythoncom.VT_DISPATCH, None)
|
||
Y0 = -1.655
|
||
POST_CX = 7.4
|
||
A_Z = (10.0, 60.0)
|
||
R_INS = 2.1
|
||
|
||
|
||
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
|
||
|
||
|
||
app = wc.GetActiveObject('SldWorks.Application')
|
||
part = None
|
||
for d in app.GetDocuments or []:
|
||
if 'ENDPLATE_V11' in (prop(d, 'GetTitle') or '').upper():
|
||
part = d
|
||
break
|
||
if part is None:
|
||
P(u'⛔ EndPlate_v11 没开着'); sys.exit(2)
|
||
e0 = wc.VARIANT(pythoncom.VT_BYREF | pythoncom.VT_I4, 0)
|
||
app.ActivateDoc3(prop(part, 'GetTitle'), False, 0, e0)
|
||
part = app.ActiveDoc
|
||
sm, fm = part.SketchManager, part.FeatureManager
|
||
P(u'零件 %s' % prop(part, 'GetTitle'))
|
||
|
||
|
||
def faces():
|
||
b = part.GetBodies2(0, True) or []
|
||
return prop(D(b[0]), 'GetFaces') if b else []
|
||
|
||
|
||
def holes():
|
||
u"""返回 [(r, 轴, box)]:所有圆柱面"""
|
||
out = []
|
||
for f in faces():
|
||
fc = D(f)
|
||
s = prop(fc, 'GetSurface')
|
||
if not prop(s, 'IsCylinder'):
|
||
continue
|
||
cp = list(prop(s, 'CylinderParams'))
|
||
fb = [round(v * 1000, 2) for v in prop(fc, 'GetBox')]
|
||
out.append((round(cp[6] * 1000, 2), (round(cp[3]), round(cp[4]), round(cp[5])), fb))
|
||
return out
|
||
|
||
|
||
def hist():
|
||
h = {}
|
||
for r, _, _ in holes():
|
||
h[r] = h.get(r, 0) + 1
|
||
return dict(sorted(h.items()))
|
||
|
||
|
||
def south_ok():
|
||
u"""南侧 2 孔是否都在正确位置"""
|
||
got = 0
|
||
for r, ax, fb in holes():
|
||
if abs(r - R_INS) > 0.01 or abs(ax[1]) != 1:
|
||
continue
|
||
cx, cz = (fb[0] + fb[3]) / 2, (fb[2] + fb[5]) / 2
|
||
if abs(cx - POST_CX) < 0.05 and fb[1] < 0 and any(abs(cz - z) < 0.05 for z in A_Z):
|
||
got += 1
|
||
return got
|
||
|
||
|
||
def pick_sketch():
|
||
nm, f = None, prop(part, 'FirstFeature')
|
||
while f:
|
||
if prop(f, 'GetTypeName2') == 'ProfileFeature':
|
||
nm = prop(f, 'Name')
|
||
f = prop(f, 'GetNextFeature')
|
||
part.ClearSelection2(True)
|
||
part.Extension.SelectByID2(nm, 'SKETCH', 0, 0, 0, False, 0, EMPTY, 0)
|
||
return part.SelectionManager.GetSelectedObjectCount2(-1)
|
||
|
||
|
||
def pick_south_face():
|
||
best, ba = None, -1.0
|
||
for f in faces():
|
||
fc = D(f)
|
||
s = prop(fc, 'GetSurface')
|
||
if not prop(s, 'IsPlane'):
|
||
continue
|
||
n = list(prop(s, 'PlaneParams'))[1]
|
||
if prop(fc, 'FaceInSurfaceSense'): # 朝外 = −曲面法线
|
||
n = -n
|
||
if n > -0.99:
|
||
continue
|
||
fb = [v * 1000 for v in prop(fc, 'GetBox')]
|
||
if abs(fb[1] - Y0) > 0.02 or abs(fb[4] - Y0) > 0.02:
|
||
continue
|
||
a = prop(fc, 'GetArea') * 1e6
|
||
if a > ba:
|
||
best, ba = fc, a
|
||
if best is None:
|
||
return False
|
||
part.ClearSelection2(True)
|
||
best.Select4(False, EMPTY)
|
||
return part.SelectionManager.GetSelectedObjectCount2(-1) == 1
|
||
|
||
|
||
before = hist()
|
||
P(u'开始 直方图 %s 南侧已有正确孔 %d' % (before, south_ok()))
|
||
if before.get(1.7, 0) != 4 or before.get(30.0, 0) != 1 or before.get(R_INS, 0) != 4:
|
||
P(u'⛔ 起点不是预期的 v11,停手'); sys.exit(3)
|
||
|
||
CANDIDATES = [(u'u→−x, v→−z', -1, -1), (u'u→+x, v→+z', +1, +1), (u'u→−x, v→+z', -1, +1)]
|
||
done = False
|
||
for tag, su, sv in CANDIDATES:
|
||
if not pick_south_face():
|
||
P(u' ⛔ 选不到南侧面'); break
|
||
sm.InsertSketch(True)
|
||
sm.AddToDB = True
|
||
for z in A_Z:
|
||
sm.CreateCircleByRadius(M(su * POST_CX), M(sv * z), 0.0, M(R_INS))
|
||
sm.AddToDB = False
|
||
sm.InsertSketch(True)
|
||
if pick_sketch() != 1:
|
||
P(u' ⛔ 草图没选中'); break
|
||
c = fm.FeatureCut4(True, False, False, 0, 0, M(6.0), 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)
|
||
n_ok = south_ok()
|
||
P(u' 试 %-14s → %-12r 直方图 %s 南侧正确孔 %d/2'
|
||
% (tag, prop(c, 'Name') if c else c, hist(), n_ok))
|
||
if n_ok == 2:
|
||
done = True
|
||
break
|
||
if c:
|
||
P(u' ⛔ 切出了东西但位置不对 —— 停手、不存盘'); sys.exit(4)
|
||
|
||
h = hist()
|
||
P(u'\n验收 直方图 %s' % h)
|
||
if not done or h.get(R_INS, 0) != 6 or h.get(1.7, 0) != 4 or h.get(30.0, 0) != 1:
|
||
P(u'⛔ 没达标,不存盘(v11 仍可用:C 组 + 北侧 A 组已成形)'); sys.exit(5)
|
||
P(u'全部孔位:')
|
||
for r, ax, fb in holes():
|
||
if abs(r - R_INS) < 0.01:
|
||
P(u' R%.2f 轴%s x %.2f~%.2f y %.2f~%.2f z %.2f~%.2f' % (r, ax, fb[0], fb[3], fb[1], fb[4], fb[2], fb[5]))
|
||
|
||
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))
|