Files
Pier_v1/Code/교각모델링/extract_column_rebar.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
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()