Files
Pier_v1/Code/울산P1판독/extract_r3.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

112 lines
6.9 KiB
Python

"""R3 (footing rebar) reading of the Ulsan P1 drawing -> data/산외교울산P1 params.footing_rebar, expected.G3;
adds G3 to the pier scope (builder footing_rebar_mats.py, checker g3_mats.py).
배근도(1) front view (CX 10473.9, FB y -40253.3) and side view (CX 24604.3); footing 7,500 x 7,500 x 2,500.
- position chains: top '100','150','28@250=7.000','50','100(상면)'; bottom '100','150','56@125=7.000','50','100(하면)';
middle '100','400','13@500=6.500','400','100(중앙)'. The side-view top chain ends with '150','100' -> B4 last
bar at 3,650 (front view: 3,600) - drawing inconsistency, modelled as drawn.
- Y-direction (front): bottom z 127.5 = B2 (U, legs up 2,250, on the top-row positions, 31) + B3 (other 28);
top z 2,422.5 = B1 (31). X-direction (side): bottom z 172.5 = B5 (U) + B6; top z 2,377.5 = B4.
The B5 positions follow the front top row (bottom chain has no 3,650) [추론].
- B8 perimeter hoops centreline ±3,672.5, z 375..2,175 @300 (7); B9 (X) / B10 (Y) mid layer z 1,275 at the
drawn positions, legs 100 down; both at the same z (drawn) -> cross at the intersections (recorded).
- B7 verticals on the 14 x 14 grid -3,250..3,250 @500, checkerboard (i+j even) = 98 [추론]; drawn z 150..2,400,
A 2,218 centred -> z0 166 [추론]; legs 100 along +Y (avoids the X-direction bottom bars) [추론].
"""
import json
import shutil
import time
from pathlib import Path
HERE = Path(__file__).resolve().parent
APP = HERE.parent / "교각모델링앱"
PIER = APP / "data" / "산외교울산P1"
S = json.loads((HERE / "판독" / "schedule.json").read_text(encoding="utf-8"))
ROWS = {r["mark"]: r for t in S.values() for r in t["rows"]}
MARKS = [f"B{i}" for i in range(1, 11)]
ROW_DEF = {
"bottom": {"first": [-3650], "start": -3500, "pitch": 125, "n": 57, "last": [3600]},
"top_front": {"first": [-3650], "start": -3500, "pitch": 250, "n": 29, "last": [3600]},
"top_side": {"first": [-3650], "start": -3500, "pitch": 250, "n": 29, "last": [3650]},
"grid": {"start": -3250, "pitch": 500, "n": 14},
}
MID = [-3250, -2250, -1250, -250, 750, 1750, 2750]
def row(spec):
return sorted(spec.get("first", []) + [spec["start"] + spec["pitch"] * i for i in range(spec["n"])] + spec.get("last", []))
def mm(v):
return round(float(v) * 1000) if "." in v else int(v)
def L(m):
return round(float(ROWS[m]["_right"][0][1]) * 1000) # first value right of the J column = L
def main():
P = json.loads((PIER / "params.json").read_text(encoding="utf-8"))
E = json.loads((PIER / "expected.json").read_text(encoding="utf-8"))
stamp = time.strftime("%Y%m%d_%H%M%S")
for f in ("params.json", "expected.json"):
shutil.copy2(PIER / f, PIER / "backup" / f"{Path(f).stem}_before_R3_{stamp}.json")
bottom, tf, ts = row(ROW_DEF["bottom"]), row(ROW_DEF["top_front"]), row(ROW_DEF["top_side"])
on = [v for v in bottom if v in tf]
off = [v for v in bottom if v not in tf]
a = mm(ROWS["B1"]["A"])
leg_u = mm(ROWS["B2"]["B"])
lap = mm(ROWS["B2"]["J"])
hook = mm(ROWS["B9"]["B"])
src_f, src_s = "배근도(1) 정면도 기초", "배근도(1) 측면도 기초"
groups = [
dict(mark="B1", axis="Y", z=2422.5, pos=tf, a=a, leg=0, src=f"{src_f} 상면 사슬 '28@250' (끝 3,600)"),
dict(mark="B2", axis="Y", z=127.5, pos=on, a=a, leg=leg_u, lap=lap, src=f"{src_f} 하면 U형 (상면 위치), 이음 J {lap} 길이만"),
dict(mark="B3", axis="Y", z=127.5, pos=off, a=a, leg=0, src=f"{src_f} 하면 '56@125' 중 B2 외"),
dict(mark="B4", axis="X", z=2377.5, pos=ts, a=a, leg=0, src=f"{src_s} 상면 사슬 (끝 '150','100' -> 3,650, 정면과 불일치)"),
dict(mark="B5", axis="X", z=172.5, pos=on, a=a, leg=leg_u, lap=lap, src=f"{src_s} 하면 U형 (정면 상면 위치) [추론]"),
dict(mark="B6", axis="X", z=172.5, pos=off, a=a, leg=0, src=f"{src_s} 하면 B5 외"),
dict(mark="B9", axis="X", z=1275, pos=MID, a=a, leg=-hook, src=f"{src_s} 중앙 (작도 위치, 비대칭)"),
dict(mark="B10", axis="Y", z=1275, pos=MID, a=a, leg=-hook, src=f"{src_f} 중앙 (작도 위치, 비대칭; B9와 같은 높이)"),
]
hoop = dict(mark="B8", half=3672.5, levels=[375 + 300 * i for i in range(7)],
design_length=2 * mm(ROWS["B8"]["A"]) + 2 * mm(ROWS["B8"]["B"]) + 4 * mm(ROWS["B8"]["J"]),
src="정면·측면 둘레 띠 ±3,672.5, z 375~2,175 @300; 길이 2A+2B+4J")
grid = row(ROW_DEF["grid"])
vert = dict(mark="B7", grid_x=grid, grid_y=grid, parity=0, z0=150 + (2250 - mm(ROWS["B7"]["A"])) / 2,
a=mm(ROWS["B7"]["A"]), leg=mm(ROWS["B7"]["B"]), leg_axis="Y",
src="14x14 격자 @500 중 체크무늬 98 [추론]; 작도 z 150~2,400, A 중앙 배치 [추론]; 갈고리 +Y [추론]")
P["footing_rebar"] = {"form": "mats", "groups": groups, "hoops": hoop, "verticals": vert,
"src": "배근도(1) 정면·측면 기초 배근 + 배근도(3) 재료표 B1~B10"}
P["scope"] = [g for g in ("G1", "G2", "G3", "G4", "G5") if g in set(P["scope"]) | {"G3"}]
P["builders"]["G3"] = "footing_rebar_mats.py"
E["checkers"]["G3"] = "g3_mats.py"
E["negative"]["G3"] = [{"mark": "B3", "d": [5, 0, 0]}, {"mark": "B7", "d": [0, 0, 5]}]
E["G3"] = {
"schedule": {m: [L(m), int(ROWS[m]["n"])] for m in MARKS},
"dia": {m: int(ROWS[m]["dia"][1:]) for m in MARKS},
"rows": ROW_DEF,
"layers": {
"B1": {"axis": "Y", "z": 2422.5, "row": "top_front"},
"B2": {"axis": "Y", "z": 127.5, "row": "bottom", "subset": "on", "of": "top_front"},
"B3": {"axis": "Y", "z": 127.5, "row": "bottom", "subset": "off", "of": "top_front"},
"B4": {"axis": "X", "z": 2377.5, "row": "top_side"},
"B5": {"axis": "X", "z": 172.5, "row": "bottom", "subset": "on", "of": "top_front"},
"B6": {"axis": "X", "z": 172.5, "row": "bottom", "subset": "off", "of": "top_front"},
"B9": {"axis": "X", "z": 1275, "pos": MID, "leg": -hook},
"B10": {"axis": "Y", "z": 1275, "pos": MID, "leg": -hook},
},
"hoops": {"mark": "B8", "half": 3672.5, "chain": {"start": [375], "groups": [[6, 300]]}},
"verticals": {"mark": "B7", "grid_x": "grid", "grid_y": "grid", "parity": 0, "z0": 166, "a": 2218},
"src": "재료표 L·수량; 정면·측면 위치 사슬(상면·하면·중앙); 층 높이는 작도값 [derived]",
}
(PIER / "params.json").write_text(json.dumps(P, ensure_ascii=False, indent=1), encoding="utf-8")
(PIER / "expected.json").write_text(json.dumps(E, ensure_ascii=False, indent=1), encoding="utf-8")
print("counts", {g["mark"]: len(g["pos"]) for g in groups}, "B7", sum(1 for i in range(14) for j in range(14) if (i + j) % 2 == 0))
print("scope", P["scope"], "B8 len", hoop["design_length"], "B7 z0", vert["z0"], "palette", sorted(P["display"]["rebar_palette"]))
if __name__ == "__main__":
main()