- 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>
111 lines
5.1 KiB
Python
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()
|