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>
This commit is contained in:
commit
964a841de1
3978 files changed
+58013356
No files matched your search
@@ -0,0 +1,241 @@
|
||||
"""G4 stage: coping rebar C1-C16, S1, S2 (centreline + pipe) from params `coping_rebar`.
|
||||
|
||||
Run inside Rhino 8 via runner (globals PARAMS_PATH) after concrete.py, then rebar_colours.py.
|
||||
Ported from Code/교각모델링/build_coping_rebar_rhino.py (Ungok P1, model v0.1.09). Rules: 설계서 v0.1.07 §7. Units mm, X transverse, Y longitudinal, Z = EL x 1000.
|
||||
"""
|
||||
import json
|
||||
import math
|
||||
|
||||
import Rhino
|
||||
import Rhino.Geometry as rg
|
||||
from Rhino.DocObjects import ObjectAttributes
|
||||
from System.Drawing import Color
|
||||
|
||||
P = json.load(open(PARAMS_PATH, encoding="utf-8"))
|
||||
doc = __rhino_doc__
|
||||
TOL = 0.01
|
||||
PID = P["pier_id"]
|
||||
MARK = {m: (v["dia"], v["shape"]) for m, v in P["rebar_marks"].items() if m[0] in "CS"}
|
||||
DIA = {d: float(d[1:]) for d, _ in MARK.values()} # 'H29' -> 29.0
|
||||
CL_RGB = tuple(P["display"]["centreline_colour"])
|
||||
CP_RGB = tuple(P["display"]["coping_layer_colour"])
|
||||
ARC_C = tuple(P["coping_rebar"]["soffit_arc_centre"]) # soffit arc centre (right); left is mirrored
|
||||
# coping end faces (concrete) from the coping outline: bottom tip (+-half, zb+rise) -> top (+-(half-inset), end step z)
|
||||
_C = P["coping"]
|
||||
HALF, INSET = _C["length_bottom_tip_to_tip"] / 2, _C["end_batter_top_inset"]
|
||||
Z_TIP = _C["z_bottom_flat"] + _C["tip_bottom_rise"]
|
||||
ZL, ZR = _C["top_steps"][0]["z"], _C["top_steps"][-1]["z"]
|
||||
|
||||
|
||||
def xl(z):
|
||||
return -(HALF - INSET) - INSET * (ZL - z) / (ZL - Z_TIP)
|
||||
|
||||
|
||||
def xr(z):
|
||||
return (HALF - INSET) + INSET * (ZR - z) / (ZR - Z_TIP)
|
||||
|
||||
|
||||
def unit(dx, dz):
|
||||
n = math.hypot(dx, dz)
|
||||
return dx / n, dz / n
|
||||
|
||||
|
||||
U_LEFT_DOWN, U_RIGHT_DOWN = unit(-INSET, -(ZL - Z_TIP)), unit(INSET, -(ZR - Z_TIP))
|
||||
|
||||
|
||||
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 min_r(dia):
|
||||
d = DIA[dia]
|
||||
return ((2 * d if d <= 16 else 3.5 * d) + d) / 2 # box rule (REBAR_BENDS_20260914)
|
||||
|
||||
|
||||
def fillet(curve, dia):
|
||||
f = rg.Curve.CreateFilletCornersCurve(curve, min_r(dia), TOL, math.radians(1))
|
||||
return f or curve
|
||||
|
||||
|
||||
def add_bar(curve, mark, occ, design_len, src, extra=None):
|
||||
dia, shape = MARK[mark]
|
||||
pipes = rg.Brep.CreatePipe(curve, DIA[dia] / 2, False, rg.PipeCapMode.Flat, False, TOL, math.radians(1))
|
||||
if not pipes or not pipes[0].IsSolid:
|
||||
raise RuntimeError(f"{mark} {occ}: pipe failed")
|
||||
common = dict(mark=mark, dia=dia, shape=shape, occurrence=occ, host=f"{PID}-CP", anchor_hosts="",
|
||||
design_length=f"{design_len:.3f}", coupler_length="0.000", src=src)
|
||||
common.update(extra or {})
|
||||
for geo, lay, prefix in ((curve, layer(f"{PID}::철근::중심선", CL_RGB), f"{PID}-RC"),
|
||||
(pipes[0], layer(f"{PID}::철근::코핑::{mark}", CP_RGB), f"{PID}-R")):
|
||||
attr = ObjectAttributes()
|
||||
attr.LayerIndex = lay
|
||||
oid = f"{prefix}-{mark}-{occ}"
|
||||
attr.Name = oid
|
||||
attr.SetUserString("id", oid)
|
||||
for k, v in common.items():
|
||||
attr.SetUserString(k, v)
|
||||
(doc.Objects.AddBrep if isinstance(geo, rg.Brep) else doc.Objects.AddCurve)(geo, attr)
|
||||
|
||||
|
||||
def soffit_offset_z(x, cp):
|
||||
st = cp["stirrups"]
|
||||
if abs(x) <= cp["bottom"]["half_flat"]:
|
||||
return cp["bottom"]["z_flat"]
|
||||
cx = ARC_C[0] if x > 0 else -ARC_C[0]
|
||||
R = cp["bottom"]["R_offset"]
|
||||
return ARC_C[1] + math.sqrt(R * R - (x - cx) ** 2)
|
||||
|
||||
|
||||
def stirrup_top(x, cp):
|
||||
st = cp["stirrups"]
|
||||
bands = st["top_right"] if x >= 0 else st["top_left"]
|
||||
return [z for x0, z in bands if abs(x) >= x0][-1]
|
||||
|
||||
|
||||
def main():
|
||||
for o in list(doc.Objects):
|
||||
oid = o.Attributes.GetUserString("id") or ""
|
||||
if oid.startswith(tuple(f"{PID}-{k}-{m}" for k in ("R", "RC") for m in "CS")):
|
||||
doc.Objects.Delete(o, True)
|
||||
cp = P["coping_rebar"]
|
||||
ys = cp["y_positions"]
|
||||
n = 0
|
||||
# top bars (VIII)
|
||||
for tier, t in cp["top"]["tiers"].items():
|
||||
z, a, (bl, br) = t["z"], t["a"], t["legs"]
|
||||
d = (xr(z) - xl(z) - a) / 2
|
||||
x0, x1 = xl(z) + d, xr(z) - d
|
||||
for i, y in enumerate(ys):
|
||||
mark = t["marks"][i % 2]
|
||||
pts = [rg.Point3d(x0 + U_LEFT_DOWN[0] * bl, y, z + U_LEFT_DOWN[1] * bl), rg.Point3d(x0, y, z),
|
||||
rg.Point3d(x1, y, z), rg.Point3d(x1 + U_RIGHT_DOWN[0] * br, y, z + U_RIGHT_DOWN[1] * br)]
|
||||
add_bar(fillet(rg.PolylineCurve(pts), MARK[mark][0]), mark, f"t{tier}y{y:+.0f}", a + bl + br,
|
||||
f"tier {tier} EL {z / 1000:.3f}; end inset {d:.1f}; legs parallel to end faces",
|
||||
{"a_model": f"{x1 - x0:.3f}"})
|
||||
n += 1
|
||||
# bottom bars (VII)
|
||||
b = cp["bottom"]
|
||||
R, zf = b["R_offset"], b["z_flat"]
|
||||
hf = ARC_C[0] - math.sqrt(R * R - (zf - ARC_C[1]) ** 2) # exact flat/arc junction (params 1,073.9 is rounded)
|
||||
dth = b["arc_len"] / R
|
||||
for i, y in enumerate(ys):
|
||||
mark = b["marks"][i % 2]
|
||||
pieces = [rg.LineCurve(rg.Point3d(-hf, y, zf), rg.Point3d(hf, y, zf))]
|
||||
for side in (1, -1):
|
||||
cx = side * ARC_C[0]
|
||||
th0 = math.atan2(zf - ARC_C[1], side * hf - cx)
|
||||
th1 = th0 - side * dth
|
||||
thm = (th0 + th1) / 2
|
||||
p = lambda th: rg.Point3d(cx + R * math.cos(th), y, ARC_C[1] + R * math.sin(th))
|
||||
arc = rg.ArcCurve(rg.Arc(p(th0), p(thm), p(th1)))
|
||||
up = (-U_RIGHT_DOWN[0], -U_RIGHT_DOWN[1]) if side > 0 else (-U_LEFT_DOWN[0], -U_LEFT_DOWN[1])
|
||||
e = p(th1)
|
||||
leg = rg.LineCurve(e, rg.Point3d(e.X + up[0] * b["leg"], y, e.Z + up[1] * b["leg"]))
|
||||
pieces += [arc, leg]
|
||||
joined = rg.Curve.JoinCurves(pieces, TOL)
|
||||
if len(joined) != 1:
|
||||
raise RuntimeError(f"{mark} y{y}: bottom bar did not join ({len(joined)} pieces)")
|
||||
c = joined[0]
|
||||
add_bar(c, mark, f"y{y:+.0f}", 2 * hf + 2 * b["arc_len"] + 2 * b["leg"],
|
||||
"flat EL 40.511 +-1,073.9; arcs R 12,100 concentric with soffit, length 5,273; legs 650 // end faces")
|
||||
n += 1
|
||||
# stirrups (IV as closed rectangles, widths as drawn in section A-A)
|
||||
st = cp["stirrups"]
|
||||
for mark, xs in (("C10", st["x_c10"]), ("C11", st["x_c11"]), ("C9", st["x_c9"])):
|
||||
for x in xs:
|
||||
zb, zt = soffit_offset_z(x, cp), stirrup_top(x, cp)
|
||||
for k, (y0, y1) in enumerate(st["loops_y"]):
|
||||
ym = (y0 + y1) / 2
|
||||
pts = [rg.Point3d(x, ym, zb), rg.Point3d(x, y1, zb), rg.Point3d(x, y1, zt), rg.Point3d(x, y0, zt),
|
||||
rg.Point3d(x, y0, zb), rg.Point3d(x, ym, zb)]
|
||||
c = fillet(rg.PolylineCurve(pts), MARK[mark][0])
|
||||
w, h = y1 - y0, zt - zb
|
||||
b_s = h + st["b_offset"]
|
||||
add_bar(c, mark, f"x{x:+.0f}k{k + 1}", 2 * w + 2 * b_s + 2 * st["c_sched"],
|
||||
f"X {x}; loop {k + 1} Y {y0}..{y1}; laps 2x750 not drawn (length only)",
|
||||
{"b_sched": f"{b_s:.1f}", "w_model": f"{w:.1f}"})
|
||||
n += 1
|
||||
# horizontal closed loops C12 (lower 6 levels) / C13 (upper 3 levels), one inside each stirrup
|
||||
lp = cp.get("loops")
|
||||
if lp:
|
||||
R, inset = cp["bottom"]["R_offset"], lp["end_inset_face"]
|
||||
for z, mark in zip(lp["levels"], lp["marks_by_level"]):
|
||||
disc = R * R - (z - ARC_C[1]) ** 2
|
||||
xs = ARC_C[0] - math.sqrt(disc) if disc > 0 else 1e9 # soffit-offset limit (symmetric)
|
||||
x0, x1 = max(-xs, xl(z) + inset), min(xs, xr(z) - inset)
|
||||
for k, (y0, y1) in enumerate(lp["loops_y"]):
|
||||
xm = (x0 + x1) / 2
|
||||
pts = [rg.Point3d(xm, y0, z), rg.Point3d(x1, y0, z), rg.Point3d(x1, y1, z), rg.Point3d(x0, y1, z),
|
||||
rg.Point3d(x0, y0, z), rg.Point3d(xm, y0, z)]
|
||||
c = fillet(rg.PolylineCurve(pts), MARK[mark][0])
|
||||
a_m, w = x1 - x0, y1 - y0
|
||||
add_bar(c, mark, f"z{z}k{k + 1}", 2 * (a_m + lp["a_offset"]) + 2 * w + 4 * lp["c_sched"],
|
||||
f"EL {z / 1000:.3f}; X {x0:.1f}..{x1:.1f}; loop {k + 1} Y {y0}..{y1}; laps 4x580 length only",
|
||||
{"a_sched": f"{a_m + lp['a_offset']:.1f}", "w_model": f"{w:.1f}"})
|
||||
n += 1
|
||||
# C14 transverse (Y) bars with hooks down; C15 / C16 longitudinal (X) bars in the raised step zones
|
||||
if "c14" in cp:
|
||||
c14 = cp["c14"]
|
||||
h, hk = c14["a"] / 2, c14["hook"]
|
||||
up = [tuple(v) for v in c14.get("hooks_up", [])]
|
||||
for x, z in c14["points"]:
|
||||
s = 1 if (x, z) in up else -1 # hooks up only where a down hook would leave the soffit
|
||||
pts = [rg.Point3d(x, -h, z + s * hk), rg.Point3d(x, -h, z), rg.Point3d(x, h, z), rg.Point3d(x, h, z + s * hk)]
|
||||
add_bar(fillet(rg.PolylineCurve(pts), MARK["C14"][0]), "C14", f"x{x:+.0f}z{z:.0f}", c14["a"] + 2 * hk,
|
||||
"D1 정면도 점; hooks " + ("up (HITL fix)" if s > 0 else "down [추론]"))
|
||||
n += 1
|
||||
c15, c16 = cp["c15"], cp["c16"]
|
||||
for y in c15["y_positions"]:
|
||||
z, (h0, h1) = c15["z"], c15["hooks"]
|
||||
pts = [rg.Point3d(c15["x0"], y, z - h0), rg.Point3d(c15["x0"], y, z), rg.Point3d(c15["x1"], y, z),
|
||||
rg.Point3d(c15["x1"], y, z - h1)]
|
||||
add_bar(fillet(rg.PolylineCurve(pts), MARK["C15"][0]), "C15", f"y{y:+.0f}", c15["x1"] - c15["x0"] + h0 + h1,
|
||||
"D1 정면도 43,598.4 / 3,816~5,900")
|
||||
z = c16["z"]
|
||||
pts = [rg.Point3d(c16["x0"], y, z - c16["hook_left"]), rg.Point3d(c16["x0"], y, z),
|
||||
rg.Point3d(c16["x1"], y, z)]
|
||||
add_bar(fillet(rg.PolylineCurve(pts), MARK["C16"][0]), "C16", f"y{y:+.0f}", c16["x1"] - c16["x0"] + c16["hook_left"],
|
||||
"D1 정면도 43,454.7 / -1,195~4,066; hook at left end [추론]")
|
||||
n += 2
|
||||
# S1 / S2 bearing-seat reinforcement under each pedestal (rotated with the pedestal)
|
||||
if "s1s2" in cp and "bearing_seats" in P:
|
||||
bs, ss = P["bearing_seats"], cp["s1s2"]
|
||||
corners = bs["pedestal_girder5"]["front_half"] + bs["pedestal_girder5"]["rear_half"]
|
||||
c5 = (sum(p[0] for p in corners) / len(corners), sum(p[1] for p in corners) / len(corners))
|
||||
t = math.radians(bs["pedestal_girder5"]["rotation_deg"])
|
||||
ua, uc = (math.sin(t), math.cos(t)), (math.cos(t), -math.sin(t)) # along (2,500) / across (1,200)
|
||||
steps = P["coping"]["top_steps"]
|
||||
for g in range(1, len(steps) + 1):
|
||||
cx_, cy_ = c5[0] + (g - bs["reference_girder"]) * bs["pitch_x"], c5[1]
|
||||
top = steps[g - 1]["z"]
|
||||
pt = lambda s_al, s_ac, z: rg.Point3d(cx_ + ua[0] * s_al + uc[0] * s_ac, cy_ + ua[1] * s_al + uc[1] * s_ac, z)
|
||||
s1 = ss["s1"]
|
||||
for off in s1["offsets_across"]:
|
||||
z, h = top - s1["z_below_top"], s1["a"] / 2
|
||||
pts = [pt(-h, off, z - s1["leg"]), pt(-h, off, z), pt(h, off, z), pt(h, off, z - s1["leg"])]
|
||||
add_bar(fillet(rg.PolylineCurve(pts), MARK["S1"][0]), "S1", f"g{g}c{off:+.0f}", s1["a"] + 2 * s1["leg"],
|
||||
f"girder {g} pedestal; upper layer [추론]")
|
||||
n += 1
|
||||
s2 = ss["s2"]
|
||||
for off in s2["offsets_along"]:
|
||||
z, h = top - s2["z_below_top"], s2["a"] / 2
|
||||
pts = [pt(off, -h, z - s2["leg"]), pt(off, -h, z), pt(off, h, z), pt(off, h, z - s2["leg"])]
|
||||
add_bar(fillet(rg.PolylineCurve(pts), MARK["S2"][0]), "S2", f"g{g}a{off:+.0f}", s2["a"] + 2 * s2["leg"],
|
||||
f"girder {g} pedestal; lower layer")
|
||||
n += 1
|
||||
doc.Views.Redraw()
|
||||
print(json.dumps({"coping_bars": n}))
|
||||
|
||||
|
||||
main()
|
||||
Reference in new issue
Block a user