文件
phonerail/.claude/r2/shell/patch_v3_cut.py
T

125 行
5.1 KiB
Python
原始文件 Blame 文件历史

此文件含有模棱两可的 Unicode 字符
此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。
# -*- coding: utf-8 -*-
u"""把 topshell_v3.py 里「候选映射逐个试」的切除换成「读草图变换 + 先验平面再下刀」。
起因(2026-09-13 实测):东端墙那一刀 Select4 返回 True、选中数 1、选中面 box 也对,
但 InsertSketch 之后草图却建在了**顶板**上(风口从顶上切穿),靠「切出了东西但不在目标位置」才拦下。
⇒ 选中数不能证明草图建在哪;**进草图后读 ActiveSketch.ModelToSketchTransform**:
列主序 M[r][c] = a[3c+r],s = M·p + t(米);第 3 行 = 草图法线。
法线轴 ≠ 目标轴 或 墙面上一点的草图 z ≠ 0 ⇒ 退出重进,三次不成就停手。
同一个变换顺带给出精确的 uv 映射,不再需要候选法。
"""
import io
import sys
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', write_through=True)
P_ = u'C:\\Users\\35138\\.claude\\jobs\\11836093\\tmp\\topshell_v3.py'
s = open(P_, encoding='utf-8').read()
a = s.index(u'def try_cut(')
b = s.index(u'\n# ── [6b]')
NEW = u'''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))
P(u'\\n[5] 南墙:2 个 13×9 Type-C 窗口')
cut_shapes(u'南墙', (1, -1, Y0), [],
[((x0, Y0, L(z0)), (x1, Y0, L(z1))) for x0, x1, z0, z1 in SOUTH_WINDOWS],
rect_verify(SOUTH_WINDOWS, Y0, IY0))
P(u'\\n[6] 北墙:J33 窗口 + 风扇出线窗口')
cut_shapes(u'北墙', (1, +1, Y1), [],
[((x0, Y1, L(z0)), (x1, Y1, L(z1))) for x0, x1, z0, z1 in NORTH_WINDOWS],
rect_verify(NORTH_WINDOWS, IY1, Y1))
'''
s = s[:a] + NEW + s[b:]
if s.count(u'try_cut(') or s.count(u'X_CANDS'):
raise SystemExit(u'⛔ 旧的候选法残留')
open(P_, 'w', encoding='utf-8').write(s)
print(u'topshell_v3.py 已换成「读草图变换 + 先验平面」版')