Files
Pier_v1/Code/교각모델링앱/engine/rhino/bearings.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

111 lines
5.1 KiB
Python

"""G5 stage: bridge bearings (black boxes) and sole plates (wedges) on each h2 pad.
Run inside Rhino 8 via runner (globals PARAMS_PATH) after concrete.py.
Ported from Code/교각모델링/build_bearing_plates_rhino.py (Ungok P1, model v0.1.09). Rules: 설계서 v0.1.10 §8. Reads params.json `bearing_seats`,
`sole_plates`, `coping`. Bottom of the bearing = modelled pad top (= coping step + h1 + h2 = EL.'X' within 1 mm).
"""
import json
import math
import Rhino
import Rhino.Geometry as rg
import System
from Rhino.DocObjects import ObjectAttributes, ObjectColorSource
from System.Drawing import Color
P = json.load(open(PARAMS_PATH, encoding="utf-8"))
doc = __rhino_doc__
TOL = 0.01
PID = P["pier_id"]
H3 = P["sole_plates"].get("h3") # D2 ELEVATION TABLE h3 (common value; a table row may override)
def layer(path, color):
parent = -1
parts = path.split("::")
for i in range(1, len(parts) + 1):
idx = doc.Layers.FindByFullPath("::".join(parts[:i]), -1)
if idx < 0:
lay = Rhino.DocObjects.Layer()
lay.Name, lay.Color = parts[i - 1], Color.FromArgb(*color)
if parent >= 0:
lay.ParentLayerId = doc.Layers[parent].Id
idx = doc.Layers.Add(lay)
parent = idx
return parent
def corners(cx, cy, along, across, rot_deg):
"""Plan corners, `along` on +Y rotated clockwise by rot_deg; order: (-a,-c), (+a,-c), (+a,+c), (-a,+c)."""
t = math.radians(rot_deg)
ua, uc = (math.sin(t), math.cos(t)), (math.cos(t), -math.sin(t))
out = []
for sa, sc in ((-1, -1), (1, -1), (1, 1), (-1, 1)):
out.append((cx + sa * ua[0] * along / 2 + sc * uc[0] * across / 2,
cy + sa * ua[1] * along / 2 + sc * uc[1] * across / 2, sa * along / 2))
return out
def hexa(bottom, top):
pts = [rg.Point3d(*p) for p in bottom + top]
b = rg.Brep.CreateFromBox(pts)
if b is None or not b.IsSolid:
raise RuntimeError("hexahedron failed")
if b.SolidOrientation == rg.BrepSolidOrientation.Inward:
b.Flip()
return b
def add(brep, key, oid, color, props):
attr = ObjectAttributes()
attr.LayerIndex = layer(key, color)
attr.Name = oid
attr.ObjectColor = Color.FromArgb(*color)
attr.ColorSource = ObjectColorSource.ColorFromObject
attr.SetUserString("id", oid)
for k, v in props.items():
attr.SetUserString(k, str(v))
if doc.Objects.AddBrep(brep, attr) == System.Guid.Empty:
raise RuntimeError(f"{oid}: AddBrep failed")
def main():
for o in list(doc.Objects):
if (o.Attributes.GetUserString("id") or "").startswith((f"{PID}-BB", f"{PID}-SP")):
doc.Objects.Delete(o, True)
sp = P["sole_plates"]
if not sp["table"]: # 2026-10-13: an empty table silently produced no bearings
raise RuntimeError("sole_plates.table is empty")
steps = P["coping"].get("top_steps")
bear = {b["no"]: b for b in P["bearing_seats"]["bearings"]}
for r in sp["table"]:
b = bear[r["no"]]
cx, cy = b["centre"]
rot = b["rotation_deg"]
seat = b["seat_z"] if "seat_z" in b else steps[b["girder_line"] - 1]["z"] # seat_z: tapered form (Ulsan)
z0 = seat + b["h1"] + b["h2"] # modelled pad top
h3 = r.get("h3", H3) # per bearing when tabled
if sp.get("bearing_size") == "AB": # bearing body A (along) x B (across) (Ulsan detail drawing)
along, across, rule = b["A"], b["B"], "A x B (교량받침 상세)"
else: # (L-100) x (W-100) per user 2026-10-08 (Ungok)
along, across, rule = r["L"] - sp["bearing_shrink"], r["W"] - sp["bearing_shrink"], None
cb = corners(cx, cy, along, across, rot)
add(hexa([(x, y, z0) for x, y, _ in cb], [(x, y, z0 + h3) for x, y, _ in cb]),
f"{PID}::교량받침", f"{PID}-BB{r['no']:02d}", tuple(sp["colours"]["bearing"]),
dict(role="bridge bearing", no=r["no"], size=f"{along}x{across}x{h3}", el_x=b["el_x"],
src=f"ELEVATION TABLE h3, {rule}" if rule else "D2 ELEVATION TABLE h3, (L-100)x(W-100) per user 2026-10-08"))
# sole plate: bottom flat, top sloped S% along the pad long axis, centre thickness T (sign of S sets thick end)
zb = z0 + h3
cs = corners(cx, cy, r["L"], r["W"], rot)
top = [(x, y, zb + r["T"] + r["S"] / 100 * s) for x, y, s in cs]
add(hexa([(x, y, zb) for x, y, _ in cs], top), f"{PID}::솔플레이트", f"{PID}-SP{r['no']:02d}",
tuple(sp["colours"]["sole_plate"]),
dict(role="sole plate", no=r["no"], S=r["S"], L=r["L"], W=r["W"], T=r["T"],
end_thick=f"{r['T'] - r['S'] / 100 * r['L'] / 2:.2f}/{r['T'] + r['S'] / 100 * r['L'] / 2:.2f}",
src=sp.get("sole_plate_src", "D2 솔플레이트 상세 TABLE; slope along pad axis, thick end -Y [HITL]")))
doc.Views.Redraw()
print(json.dumps({"bearings": len(sp["table"]), "sole_plates": len(sp["table"])}))
main()