Files
Pier_v1/Code/교각모델링앱/tools/patches/2026-10-14_patch_ring_okseong.py
T
ahnyongjooandClaude Sonnet 5.5 964a841de1 chore(rebar): Pier_T_rebar 작업 폴더 초기 구성 및 외부 의존 파일 통합
- Code\rebar_pipeline, review_pipeline, pier-program을 정션에서 실제 폴더로 전환
- Code\rhino_mcp 및 CLAUDE_rhino배경.md 추가, .mcp.json은 PYTHONPATH로 새 위치 사용
- pier-program 내부 .git 제거(이력은 backup\pier-program_20261028.bundle에 보관)
- worktree 가이드 반영(CLAUDE.local.md, HANDOFF.md)
- D:\Rhino-MCP 경로 참조를 새 위치로 치환

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-28 11:20:18 +09:00

114 lines
6.7 KiB
Python

"""Patch (2026-10-14, Okseong P1 G2): optional inner ring / per-zone hoop radius / 90-135 ties in
engine/rhino/column_rebar_ring.py and the matching optional checks in engine/rhino/checks/g2_ring.py.
Absent options -> the Ulsan code paths are unchanged. Backups: backup/2026-10-14_okseong_g2/."""
import shutil
from pathlib import Path
APP = Path(__file__).resolve().parents[2]
BK = APP / "backup" / "2026-10-14_okseong_g2"
BK.mkdir(parents=True, exist_ok=True)
B = APP / "engine" / "rhino" / "column_rebar_ring.py"
C = APP / "engine" / "rhino" / "checks" / "g2_ring.py"
for f in (B, C):
if not (BK / f.name).exists():
shutil.copy2(f, BK / f.name)
def patch(path, reps):
s = path.read_text(encoding="utf-8")
for a, b in reps:
assert s.count(a) == 1, (path.name, a[:60])
s = s.replace(a, b)
path.write_text(s, encoding="utf-8")
patch(B, [
('''includes the coupler).
"""''',
'''includes the coupler).
Optional (Okseong P1, 2026-10-14; absent -> unchanged): main.inner {mark, radius} second ring at the same angles
with the hook bent inwards; zone.radius per hoop zone; ties.shape "90-135" {leg, tail, y_lift, design_length}:
straight on the X / Y diameters, 90-deg leg down at one end, 135-deg hook at the other, ends swapped per level,
the Y tie y_lift above the X tie.
"""'''),
(''' f"{PID}-FT,{PID}-CP", f"angle {th:.4f} deg; 배근도(1) 정면도 갈고리 R{R:.0f}·{m['hook_leg']:.0f}; 단면 DIVISION {m['count']}")
n += 1''',
''' f"{PID}-FT,{PID}-CP", f"angle {th:.4f} deg; 배근도(1) 정면도 갈고리 R{R:.0f}·{m['hook_leg']:.0f}; 단면 DIVISION {m['count']}")
n += 1
if "inner" in m: # second ring, hook bent inwards (Okseong P1)
ri = m["inner"]["radius"]
z0 = m["hook_leg_z"]
leg = rg.LineCurve(pt(ri - R - m["hook_leg"], th, z0), pt(ri - R, th, z0))
bend = rg.ArcCurve(rg.Arc(pt(ri - R, th, z0),
pt(ri - R + R * math.sin(math.radians(45)), th, z0 + R - R * math.cos(math.radians(45))),
pt(ri, th, z0 + R)))
vert = rg.LineCurve(pt(ri, th, z0 + R), pt(ri, th, top))
c = rg.Curve.JoinCurves([leg, bend, vert], TOL)[0]
add_bar(c, m["inner"]["mark"], f"{i + 1:02d}", m["straight_len"] + math.pi / 2 * R + m["hook_leg"],
f"{PID}-FT,{PID}-CP", f"angle {th:.4f} deg; inner ring r {ri:.0f}, hook inwards")
n += 1'''),
(''' mark, typ = zone["mark"], zone["type"]
for j, z in enumerate(zone["levels"]):''',
''' mark, typ = zone["mark"], zone["type"]
r = zone.get("radius", hp["radius"]) # per zone (Okseong P3 1,150 / P4 1,147)
for j, z in enumerate(zone["levels"]):'''),
(''' tie = cr["ties"]
half = tie["straight"] / 2''',
''' tie = cr["ties"]
if tie.get("shape") == "90-135": # Okseong P1 (2026-10-14), as column_rebar_straight.py
rb = min_bend_radius(MARK[tie["mark"]][0])
for q, z in enumerate(tie["levels"]):
for axis, name in ((0, "X"), (1, "Y")):
zt = z + (tie["y_lift"] if axis else 0)
u = rg.Vector3d(1, 0, 0) if axis == 0 else rg.Vector3d(0, 1, 0)
s = -1 if q % 2 else 1
a = rg.Point3d(0, 0, zt) - u * (s * tie["straight"] / 2)
b = rg.Point3d(0, 0, zt) + u * (s * tie["straight"] / 2)
d = -u * s * math.cos(math.radians(45)) + rg.Vector3d(0, 0, -1) * math.sin(math.radians(45))
pl = rg.PolylineCurve([a + rg.Vector3d(0, 0, -tie["leg"]), a, b, b + d * tie["tail"]])
c = rg.Curve.CreateFilletCornersCurve(pl, rb, TOL, math.radians(1)) or pl
add_bar(c, tie["mark"], f"L{q + 1:02d}{name}", tie["design_length"], hosts(zt),
f"EL {zt / 1000:.3f}; {name} (Y +{tie['y_lift']}, 90/135 교번 [추론])")
n += 1
doc.Views.Redraw()
print(json.dumps({"bars": n}))
return
half = tie["straight"] / 2'''),
])
patch(C, [
(''' check(f"{m} radius (mid point)", G["r_hoop"], math.hypot(p.X, p.Y), tol=0.5)''',
''' check(f"{m} radius (mid point)", G.get("r_hoop_by_mark", {}).get(m, G["r_hoop"]), math.hypot(p.X, p.Y), tol=0.5)
if "inner" in M: # Okseong P1: inner ring (2026-10-14)
im = M["inner"]
tops = [max((o.Geometry.PointAtStart, o.Geometry.PointAtEnd), key=lambda q: q.Z) for o in cl[im["mark"]]]
lows = [min((o.Geometry.PointAtStart, o.Geometry.PointAtEnd), key=lambda q: q.Z) for o in cl[im["mark"]]]
check(f"{im['mark']} inner ring radius (worst)", 0, max(abs(math.hypot(q.X, q.Y) - im["radius"]) for q in tops) if tops else 1e9, tol=0.5)
flag(f"{im['mark']} hooks bent inwards", bool(lows) and all(math.hypot(q.X, q.Y) < im["radius"] for q in lows))'''),
(''' tz = {}
for o in cl[tie_mark]:
tz.setdefault(round(o.Geometry.GetBoundingBox(True).Max.Z, 1), []).append(o)
lv = sorted(tz)
flag(f"tie levels {len(TIE_LEVELS)} x {TIE['per_level']}", len(lv) == len(TIE_LEVELS)
and all(len(v) == TIE["per_level"] for v in tz.values()), f"{len(lv)} levels")
check(f"tie levels vs chain + {TIE['offset']} (worst)", 0,
max(abs(a - (b + TIE["offset"])) for a, b in zip(lv, TIE_LEVELS)) if lv else 1e9)''',
''' if TIE.get("y_lift"): # Okseong P1: X tie at the level, Y tie lifted
occ_ = lambda o: o.Attributes.GetUserString("occurrence")
lx = sorted(round(o.Geometry.GetBoundingBox(True).Max.Z, 1) for o in cl[tie_mark] if occ_(o).endswith("X"))
ly = sorted(round(o.Geometry.GetBoundingBox(True).Max.Z, 1) for o in cl[tie_mark] if occ_(o).endswith("Y"))
flag(f"tie X / Y levels {len(TIE_LEVELS)} each", len(lx) == len(ly) == len(TIE_LEVELS), f"X {len(lx)} Y {len(ly)}")
check("tie X levels vs chain (worst)", 0, max(abs(a - b - TIE["offset"]) for a, b in zip(lx, TIE_LEVELS)) if lx else 1e9)
check(f"tie Y = X + {TIE['y_lift']} (worst)", 0, max(abs(b - a - TIE["y_lift"]) for a, b in zip(lx, ly)) if ly else 1e9)
else:
tz = {}
for o in cl[tie_mark]:
tz.setdefault(round(o.Geometry.GetBoundingBox(True).Max.Z, 1), []).append(o)
lv = sorted(tz)
flag(f"tie levels {len(TIE_LEVELS)} x {TIE['per_level']}", len(lv) == len(TIE_LEVELS)
and all(len(v) == TIE["per_level"] for v in tz.values()), f"{len(lv)} levels")
check(f"tie levels vs chain + {TIE['offset']} (worst)", 0,
max(abs(a - (b + TIE["offset"])) for a, b in zip(lv, TIE_LEVELS)) if lv else 1e9)'''),
])
print("patched")