"""Add the column rebar (G2: P1~P5) to the app pier '새재1교P1' (ring builder column_rebar_ring.py, Okseong options). params = 판독/g2_values.json (front chains / section reading) + schedule; expected = schedule L / N / r (구조도(4)) and the front dimension chains, typed in by hand. Backs up params.json / expected.json to data/새재1교P1/backup/2026-10-15_g2/ first. Refuses if G2 is in scope. """ import json import shutil import sys from pathlib import Path HERE = Path(__file__).resolve().parent D = HERE.parents[1] / "Code" / "교각모델링앱" / "data" / "새재1교P1" V = json.loads((HERE / "판독" / "g2_values.json").read_text(encoding="utf-8")) P = json.loads((D / "params.json").read_text(encoding="utf-8")) X = json.loads((D / "expected.json").read_text(encoding="utf-8")) if "G2" in P["scope"]: sys.exit("G2 already in scope") bk = D / "backup" / "2026-10-15_g2" bk.mkdir(parents=True, exist_ok=True) for f in ("params.json", "expected.json"): shutil.copy2(D / f, bk / f) h, z = V["hoops_chain"], V["hoop_zones"] cut, zones = 0, [] spec = {"P3": ("coupler_half", 3073.0, 80.0, 1003.5), "P4": ("coupler_half", 3078.0, 65.0, 1000.5)} # r = ring 975 + P1 r 16 + hoop r 12.5 / 9.5 (table r 1.004 / 1.001 rounded) for mark, n in z: t, a, gap, r = spec[mark] zones.append({"mark": mark, "type": t, "levels": h[cut:cut + n], "a": a, "gap": gap, "radius": r}) cut += n assert cut == len(h) P["scope"] = ["G1", "G2", "G5"] P["builders"]["G2"] = "column_rebar_ring.py" P["rebar_marks"] = {"P1": {"dia": "H32", "shape": "VI"}, "P2": {"dia": "H32", "shape": "VI"}, "P3": {"dia": "H25", "shape": "coupler_half"}, "P4": {"dia": "H19", "shape": "coupler_half"}, "P5": {"dia": "H19", "shape": "tie-90/135"}} P["rebar_marks_src"] = "구조도(4) 철근 재료표·상세 (기둥 P1~P5)" P["column_rebar"] = { "form": "ring", "main": {"mark": "P1", "count": 49, "start_deg": 0.0, "radius": 975.0, "hook_leg_z": 10182.0, "bend_r": 340.0, "hook_leg": 500.0, "straight_from": 10522.0, "straight_len": 21835.0, "inner": {"mark": "P2", "radius": 930.0}, "src": "단면 r 975 / 930 × 49 (7.347° 간격); 상세 a 21,835 r 340 c 500; 다리 EL 10.182 = 정면 작도 (기초 하면 + 150)"}, "hoops": {"radius": 1003.5, "zones": zones, "src": "사슬 '띠철근외측' 72단(100 | 1.300 | 4@300 | 18@150 | 36@300 | 9@300 | 4@300); 구간 P3 5 / P4 18 / P3 36 / P4 9 / P3 4 " "(수량 45·27 일치, 표지선 교번 [추론]); 상세 r 1.004 / 1.001 = 1,003.5 / 1,000.5(주철근 바깥 접함), a, b(커플러); 커플러 90°/270° [추론]"}, "ties": {"mark": "P5", "shape": "90-135", "levels": V["ties_chain"], "straight": 2050.0, "leg": 200.0, "tail": 165.0, "y_lift": 19.0, "design_length": 2515.0, "src": "사슬 '크로스타이' 40단; 상세 a 200, b 2,050, c 165, d 100; Y +19 [추론], 90°/135° 교번 [추론], 꼬리 = c [추론]"}, } X["checkers"]["G2"] = "g2_ring.py" X["negative"]["G2"] = [{"mark": "P1", "d": [5, 0, 0]}, {"mark": "P3", "d": [0, 0, 5]}] X["G2"] = {"schedule_L": {"P1": 22869, "P2": 22869, "P3": 6306, "P4": 6286, "P5": 2515}, "schedule_n": {"P1": 49, "P2": 49, "P3": 45, "P4": 27, "P5": 80}, "dia": {"P1": 32, "P2": 32, "P3": 25, "P4": 19, "P5": 19}, "main": {"mark": "P1", "radius": 975, "divisions": 49, "start_deg": 0.0, "bottom_above_footing": 150, "top_parts": [150, 340, 21835], "inner": {"mark": "P2", "radius": 930}}, "hoop_chain": {"start": [100, 1300], "groups": [[4, 300], [18, 150], [36, 300], [9, 300], [4, 300]]}, "hoop_zones": [["P3", 5], ["P4", 18], ["P3", 36], ["P4", 9], ["P3", 4]], "r_hoop": 1004, "r_hoop_by_mark": {"P3": 1004, "P4": 1001}, "tie": {"mark": "P5", "chain": {"start": [100, 950], "groups": [[1, 600], [7, 300], [15, 600], [14, 300], [2, 600]]}, "per_level": 2, "offset": 0, "y_lift": 19}, "no_fillet_marks": ["P1", "P2", "P3", "P4"], "src": "재료표 L·N·r; 단면 r 975 / 930 DIVISION 49; 사슬 '띠철근외측'·'크로스타이' (기초 하면 EL 10.032 기준)"} (D / "params.json").write_text(json.dumps(P, ensure_ascii=False, indent=1), encoding="utf-8") (D / "expected.json").write_text(json.dumps(X, ensure_ascii=False, indent=1), encoding="utf-8") print("G2 added; backup", bk)