"""Stage 5: bridge bearings (black boxes) and sole plates (wedges) on each h2 pad. Run inside Rhino 8 on the current model. 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 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 H3 = 181 # D2 ELEVATION TABLE h3 (all 10) 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)) doc.Objects.AddBrep(brep, attr) def main(): for o in list(doc.Objects): if (o.Attributes.GetUserString("id") or "").startswith(("P1-BB", "P1-SP")): doc.Objects.Delete(o, True) sp = P["sole_plates"] steps = P["coping"]["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"] z0 = steps[b["girder_line"] - 1]["z"] + b["h1"] + b["h2"] # modelled pad top # bearing: (L-100) x (W-100), height h3 cb = corners(cx, cy, r["L"] - sp["bearing_shrink"], r["W"] - sp["bearing_shrink"], rot) add(hexa([(x, y, z0) for x, y, _ in cb], [(x, y, z0 + H3) for x, y, _ in cb]), "P1::교량받침", f"P1-BB{r['no']:02d}", tuple(sp["colours"]["bearing"]), dict(role="bridge bearing", no=r["no"], size=f"{r['L'] - 100}x{r['W'] - 100}x{H3}", el_x=b["el_x"], src="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, thick end at -along 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), "P1::솔플레이트", f"P1-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="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()