- 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
6.0 KiB
Python
111 lines
6.0 KiB
Python
"""Read column rebar (marks P1-P6) and append `column_rebar` to params.json.
|
|
|
|
Sources (read only): 판독/3_survey.json (D3 rebar schedule rows), D1 DXF (section C-C bar dots and
|
|
tie lines, front-view hoop/tie levels via dimension chain texts). Existing params.json keys unchanged.
|
|
Items marked `hitl` are interpretations pending user approval (설계서 v0.1.03).
|
|
"""
|
|
import json
|
|
import math
|
|
from collections import defaultdict
|
|
from pathlib import Path
|
|
|
|
import ezdxf
|
|
|
|
HERE = Path(__file__).resolve().parent
|
|
SCHED_COLS = {"mark": 2100, "shape": 3000, "dia": 3951, "n": 4800, "A": 5846, "B": 7449, "C": 9000,
|
|
"R": 13449, "L": 19541}
|
|
SECTION_CC = (23572.5, 26567.1) # D1 단면 C-C concrete ARC 1C77F centre
|
|
|
|
|
|
def schedule():
|
|
texts = json.loads((HERE / "판독" / "3_survey.json").read_text(encoding="utf-8"))["texts"]
|
|
rows = defaultdict(dict)
|
|
for t in texts:
|
|
if t["x"] > 21000 or t["y"] < 15000:
|
|
continue # SD400 table occupies x<21000; SD500 table (P1, P2) is handled below
|
|
col = min(SCHED_COLS, key=lambda c: abs(SCHED_COLS[c] - t["x"]))
|
|
if abs(SCHED_COLS[col] - t["x"]) < 260:
|
|
rows[round(t["y"])][col] = t["text"]
|
|
out = {r["mark"]: r for r in rows.values() if r.get("mark") in ("P3", "P4", "P5", "P6")}
|
|
# SD500 table: P1/P2 rows (same column pitch, offset by the table origin)
|
|
off = None
|
|
for t in texts:
|
|
if t["text"] == "P1" and t["x"] > 21000 and t["y"] > 15000:
|
|
off = t["x"] - SCHED_COLS["mark"]
|
|
rows = defaultdict(dict)
|
|
for t in texts:
|
|
if t["x"] > 21000 and t["y"] > 15000:
|
|
col = min(SCHED_COLS, key=lambda c: abs(SCHED_COLS[c] + off - t["x"]))
|
|
if abs(SCHED_COLS[col] + off - t["x"]) < 260:
|
|
rows[round(t["y"])][col] = t["text"]
|
|
out.update({r["mark"]: r for r in rows.values() if r.get("mark") in ("P1", "P2")})
|
|
return out
|
|
|
|
|
|
def section_bars():
|
|
msp = ezdxf.readfile(sorted((HERE / "입력DXF").glob("*.dxf"))[0]).modelspace()
|
|
cx, cy = SECTION_CC
|
|
dots = []
|
|
for e in msp.query("LWPOLYLINE"):
|
|
if e.dxf.layer != "CS-RBAR-MAJR":
|
|
continue
|
|
pts = [(p[0], p[1]) for p in e.get_points()]
|
|
mx, my = sum(p[0] for p in pts) / len(pts), sum(p[1] for p in pts) / len(pts)
|
|
r = math.hypot(mx - cx, my - cy)
|
|
if 700 < r < 900:
|
|
dots.append((math.degrees(math.atan2(my - cy, mx - cx)) % 360, r))
|
|
outer = sorted(a for a, r in dots if r > 850)
|
|
inner = sorted(a for a, r in dots if r < 850)
|
|
steps = [b - a for a, b in zip(outer, outer[1:])]
|
|
return dict(count_outer=len(outer), count_inner=len(inner), start_deg=round(outer[0], 3),
|
|
pitch_deg_mean=round(sum(steps) / len(steps), 4),
|
|
r_outer_cad=round(sum(r for a, r in dots if r > 850) / len(outer), 1),
|
|
r_inner_cad=round(sum(r for a, r in dots if r < 850) / len(inner), 1))
|
|
|
|
|
|
def main():
|
|
s = schedule()
|
|
sec = section_bars()
|
|
footing_bottom = 26208
|
|
hoop_levels = [footing_bottom + 150 + 1030 + 120 * i for i in range(9)] # P4: 8@120
|
|
hoop_levels += [hoop_levels[-1] + 120 * (i + 1) for i in range(22)] # P5: 22@120
|
|
hoop_levels += [hoop_levels[-1] + 300 * (i + 1) for i in range(36)] # P3: 36@300
|
|
tie_levels = [footing_bottom + 150 + 1030 + 1800 * k for k in range(9)] # P6: 8@1.800
|
|
rebar = dict(
|
|
_note="Column rebar P1-P6. Z = EL x 1000. Angles from +X counter-clockwise (plan).",
|
|
schedule={m: s[m] for m in sorted(s)},
|
|
main_bars=dict(
|
|
divisions=46, start_deg=sec["start_deg"], pitch_deg=360 / 46,
|
|
section_cad=sec,
|
|
r_outer_dim=875, r_outer=870.5, r_inner=825.5, # HITL H2 2026-10-07: section CAD radii
|
|
p1=dict(role="outer, hooked into footing (XIV)", hook_leg_z=footing_bottom + 300,
|
|
bend_r=340, hook_leg=500, hook_dir="outward (radial +)",
|
|
straight_from=footing_bottom + 300 + 340, straight_len=16213),
|
|
p2=dict(role="inner, straight (XVI)", z0=footing_bottom + 300, length=16553),
|
|
src={"radii": "D1 단면 C-C dim '125'/'875' (outer); D1 정면도 lines 1C4DB x=875, 1C4DA x=830 "
|
|
"(inner); section CAD dots 870.5/825.5",
|
|
"bottom": "D1 정면도 1C4D7 bottom y -> EL 26.508 (= footing bottom + 300); 1C4DB starts 26.848 "
|
|
"(= 26.508 + R340); P1 bend b=534 = pi/2 x 340",
|
|
"top": "schedule: P1 26.848+16.213 = 43.061, P2 26.508+16.553 = 43.061 (drawn lines stop at "
|
|
"43.011 / 40.411 -> schedule adopted; HITL H1 2026-10-07)"}),
|
|
hoops=dict(radius=897, levels=hoop_levels,
|
|
marks=["P4"] * 9 + ["P5"] * 22 + ["P3"] * 36,
|
|
src={"levels": "D1 정면도 dim chain '150','1.030','8@120=960','22@120=2.640','36@300=10.800' "
|
|
"(user: @120 adopted over label @100); drawn hoop dots y match",
|
|
"radius": "D3 R 897 (2*pi*897 = 5636 = L of P4/P5); section ARC r=898; front dots 902 (HITL H2: R897)"}),
|
|
ties=dict(levels=tie_levels, angles_deg=[0, 45, 90, 135], straight=1836, hook=150,
|
|
src={"levels": "D1 정면도 dim chain '150','1.030','8@1.800=14.400'",
|
|
"angles": "D1 단면 C-C tie lines along 0/45/90/135 deg, ends at +-897/898"}),
|
|
)
|
|
params_path = HERE / "params.json"
|
|
params = json.loads(params_path.read_text(encoding="utf-8"))
|
|
params["column_rebar"] = rebar
|
|
params_path.write_text(json.dumps(params, ensure_ascii=False, indent=2), encoding="utf-8")
|
|
print(json.dumps(dict(schedule=rebar["schedule"], section=sec, hoops=len(hoop_levels),
|
|
hoop_top=hoop_levels[-1], ties=len(tie_levels) * 4, tie_top=tie_levels[-1]),
|
|
ensure_ascii=False, indent=1))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|