Files
Pier_v1/Code/rebar_pipeline/rhino/06_flip_hooks.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

96 lines
4.0 KiB
Python

# -*- coding: utf-8 -*-
# 06_flip_hooks.py (대호지교 P1, 2026-10-06 검증)
# 목적: 수평전단철근(VIII: 직선 + 양끝 135° 수평 갈고리) 중 폭방향 특정 위치(|t|≈TARGET_T)의 철근만
# 자기 축을 기준으로 거울 반전해서 갈고리 방향을 반대로 뒤집는다 (길이 불변).
# 실행: execute_rhino_code, MARKS 한 번에 돌려도 되지만 개수가 EXPECTED와 다르면 수정하지 않고 보고만 한다.
# 구조 가정: 마크 idef(C20/C22/C24)의 리프 Brep = 철근 1본, 인스턴스 변환은 보통 단위행렬(리프가 월드 좌표).
import Rhino, json, io, os, math
import scriptcontext as sc
doc = sc.doc
OX, OY = 480714926.0, 153833329.5
ANG = math.atan2(4255.0, 12284.0)
TARGET_T = 650.0 # 대상 철근의 |t| (centroid 기준, 갈고리 때문에 축에서 ~2mm 벗어남)
T_BAND = 40.0
EXPECTED = {"C20": 8, "C22": 10, "C24": 12} # 위치 2곳 x 단 수 x 구역 수 (불일치 시 중단)
ca = math.cos(ANG)
sa = math.sin(ANG)
folder = os.path.dirname(doc.Path)
res = {}
plan = {}
es = Rhino.DocObjects.ObjectEnumeratorSettings()
es.HiddenObjects = True # 꺼진 레이어 객체도 열거 (기본값은 제외함!)
es.NormalObjects = True
es.LockedObjects = True
for mk in EXPECTED:
inst = None
for o in doc.Objects.GetObjectList(es):
g = o.Geometry
if isinstance(g, Rhino.Geometry.InstanceReferenceGeometry):
if doc.Layers[o.Attributes.LayerIndex].FullPath.endswith(mk + "_H16"):
inst = g
T = inst.Xform
ok, inv = T.TryGetInverse()
idf = doc.InstanceDefinitions.FindId(inst.ParentIdefId)
objs = idf.GetObjects()
sel = []
for idx in range(len(objs)):
w = objs[idx].Geometry.Duplicate()
w.Transform(T)
c = Rhino.Geometry.AreaMassProperties.Compute(w).Centroid
t = -(c.X - OX) * sa + (c.Y - OY) * ca
if abs(abs(t) - TARGET_T) < T_BAND:
sel.append(idx)
plan[mk] = [T, inv, idf, objs, sel]
res[mk] = {"selected": len(sel), "expected": EXPECTED[mk]}
good = True
for mk in EXPECTED:
if res[mk]["selected"] != EXPECTED[mk]:
good = False
res["all_counts_match"] = good
if good:
for mk in EXPECTED:
T = plan[mk][0]
inv = plan[mk][1]
idf = plan[mk][2]
objs = plan[mk][3]
sel = plan[mk][4]
bk = mk + "_bk1006c"
if doc.InstanceDefinitions.Find(bk) is None:
bl = []
al = []
for ob in objs:
bl.append(ob.Geometry.Duplicate())
al.append(ob.Attributes.Duplicate())
doc.InstanceDefinitions.Add(bk, "backup before hook flip", Rhino.Geometry.Point3d.Origin, bl, al)
newg = []
attrs = []
for idx in range(len(objs)):
attrs.append(objs[idx].Attributes.Duplicate())
bg = objs[idx].Geometry
if idx not in sel:
newg.append(bg.Duplicate())
continue
w = bg.Duplicate()
w.Transform(T)
cen = w.GetBoundingBox(True).Center
# 철근 중간 s에서 s-수직 평면으로 자르면 직선부 단면 원 -> 그 중심이 철근 축 위의 점
plane = Rhino.Geometry.Plane(cen, Rhino.Geometry.Vector3d(ca, sa, 0.0))
curves = Rhino.Geometry.Intersect.Intersection.BrepPlane(w, plane, 0.01)[1]
axis_pt = Rhino.Geometry.AreaMassProperties.Compute(curves[0]).Centroid
nrm = Rhino.Geometry.Vector3d(-sa, ca, 0.0) # 폭방향 t
w.Transform(Rhino.Geometry.Transform.Mirror(axis_pt, nrm))
w.Flip() # 거울 반전 뒤 법선 복구
w.Transform(inv)
newg.append(w)
doc.InstanceDefinitions.ModifyGeometry(idf.Index, newg, attrs)
doc.Views.Redraw()
f = io.open(os.path.join(folder, "flip_result.json"), "w", encoding="utf-8")
txt = json.dumps(res)
try:
f.write(txt)
except TypeError:
f.write(txt.decode("utf-8"))
f.close()