"""R2 (column rebar) reading of the Ulsan P2 drawing (배근도(4)) -> data/산외교울산P2 params.column_rebar / rebar_marks / display palette, expected.G2; adds G2 to the pier scope. Same form as P1 (script copied 2026-10-15); P2 differences read from the sheet: main P1 A 32.110 (P1 27.510), hoops P3 12 / P4 31 / P2 82 (chains 625, 11@150=1.650, 31@150=4.650, 82@300=24.600), ties P5 19 levels x 4 = 76 (chain 150, 625, 3@1.800 + 13@1.800 = 16 x 1.800, 1.200, 900; ends at the hoop chain top FB + 31.675 m like P1). Original P1 docstring follows. 배근도(1) (sheet x 0..46000): front view footing bottom y -40253.3, column CL x 10473.9; sections C-C / D-D / E-E. - main P1: 68 bars (CSBSEC1 inserts) on r 1125, pitch 360/68, start 0 deg; drawn 0/180-deg bars: vertical from FB+540, R340 bend (B041/B042), leg at FB+200 outwards; schedule A 27.510, B 534 (= pi/2 x 340), C 500 - hoops R 1.149 (schedule; drawn arc 1147.5): chain '150','625','11@150=1.650','25@150=3.750','70@300=21.000' -> P3 (V, coupler 55) 12 levels in the footing, P4 (X, coupler 55) 25, P2 (VI, laps 380, hooks 200) 70 - ties P5 (I, 2.295 + 2 x 150): chain '150','625','3@1.800','11@1.800','1.200' -> 16 levels x 4 (64); section lines at 0 / 42.4 / 90 / 132.4 deg (bar positions 0, 8, 17, 25) """ import json import shutil import sys import time from pathlib import Path HERE = Path(__file__).resolve().parent APP = HERE.parent / "교각모델링앱" PIER = APP / "data" / "산외교울산P2" FB = 38916 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"]} def L(m): """Schedule length (first value right of J/R columns) in mm.""" return round(float(ROWS[m]["_right"][-2][1]) * 1000) def chain(start, groups, base): z = base + sum(start) out = [z] for n, p in groups: for _ in range(n): z += p out.append(z) return out 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") (PIER / "backup").mkdir(exist_ok=True) for f in ("params.json", "expected.json"): shutil.copy2(PIER / f, PIER / "backup" / f"{Path(f).stem}_before_R2_{stamp}.json") hoop_chain = {"start": [150, 625], "groups": [[11, 150], [31, 150], [82, 300]]} levels = chain(hoop_chain["start"], hoop_chain["groups"], FB) zones = [("P3", 12), ("P4", 31), ("P2", 82)] cut = [0, 12, 43, 125] tie_chain = {"start": [150, 625], "groups": [[16, 1800], [1, 1200], [1, 900]]} a = lambda m: round(float(ROWS[m]["A"]) * 1000) if "." in ROWS[m]["A"] else int(ROWS[m]["A"]) P["column_rebar"] = { "form": "ring", "schedule": {m: {k: v for k, v in ROWS[m].items() if k not in ("y", "_right")} | {"L": ROWS[m]["_right"][-2][1]} for m in ("P1", "P2", "P3", "P4", "P5")}, "main": {"mark": "P1", "count": 68, "start_deg": 0.0, "radius": 1125.0, "hook_leg_z": FB + 200, "bend_r": 340, "hook_leg": 500, "straight_from": FB + 540, "straight_len": a("P1"), "src": "배근도(1) 단면 C-C/D-D/E-E CSBSEC1 68개 r 1,125 (start 0 deg); 정면 B041/B042 R340, A91D/A920 시작 FB+540; 재료표 P1"}, "hoops": {"radius": 1149, "zones": [ {"mark": "P3", "type": "coupler_half", "levels": levels[cut[0]:cut[1]], "a": a("P3"), "gap": int(ROWS["P3"]["B"])}, {"mark": "P4", "type": "coupler_ring", "levels": levels[cut[1]:cut[2]], "a": a("P4"), "gap": int(ROWS["P4"]["B"])}, {"mark": "P2", "type": "lap_half", "levels": levels[cut[2]:cut[3]], "a": a("P2"), "lap": int(ROWS["P2"]["J"]), "hook": int(ROWS["P2"]["B"])}], "src": "재료표 R 1.149 (단면 원호 작도 1,147.5); 정면 사슬 '150','625','11@150','25@150','70@300'; 이음 위치 [추론]"}, "ties": {"mark": "P5", "levels": chain(tie_chain["start"], tie_chain["groups"], FB), "angles_deg": [0.0, 8 * 360 / 68, 90.0, 25 * 360 / 68], "straight": a("P5"), "hook": int(ROWS["P5"]["B"]), "z_offset": 16 / 2 + 19 / 2, "src": "정면 사슬 '3@1.800','11@1.800','1.200' (+ 첫 단 775) = 16단 x 4 = 64; 단면 선 0/42.4/90/132.4 deg; 갈고리 아래 [추론]"}, } P["rebar_marks"] = {m: {"dia": r["dia"], "shape": r["shape"]} for m, r in ROWS.items()} P["rebar_marks_src"] = "배근도(3) 철근재료표 SD400·SD500 (34 마크)" pal = P["display"]["rebar_palette"] pal.setdefault("22", [23, 190, 207]) pal.setdefault("13", [140, 86, 75]) P["display"]["column_mark_colours"] = {"P1": [200, 40, 40], "P2": [40, 120, 200], "P3": [40, 170, 170], "P4": [90, 90, 220], "P5": [140, 60, 160]} P["display"]["src"] = "R8 팔레트(2026-10-07) + 울산 확장 H22 (23,190,207), H13 (140,86,75) [2026-10-13]; 숨김 없음" P["scope"] = sorted(set(P["scope"]) | {"G2"}) P["builders"]["G2"] = "column_rebar_ring.py" E["rebar_palette"] = dict(E["rebar_palette"], **{"22": [23, 190, 207], "13": [140, 86, 75]}) E["checkers"]["G2"] = "g2_ring.py" E["negative"]["G2"] = [{"mark": "P1", "d": [5, 0, 0]}, {"mark": "P2", "d": [0, 0, 5]}] E["G2"] = { "schedule_L": {m: L(m) for m in ("P1", "P2", "P3", "P4", "P5")}, "schedule_n": {m: int(ROWS[m]["n"]) for m in ("P1", "P2", "P3", "P4", "P5")}, "dia": {m: int(ROWS[m]["dia"][1:]) for m in ("P1", "P2", "P3", "P4", "P5")}, "main": {"mark": "P1", "radius": 1125, "divisions": 68, "start_deg": 0.0, "bottom_above_footing": 200, "top_parts": [540, a("P1")]}, "hoop_chain": hoop_chain, "hoop_zones": zones, "r_hoop": 1149, "tie": {"mark": "P5", "chain": tie_chain, "per_level": 4, "offset": 17.5}, "no_fillet_marks": ["P1", "P3", "P4"], "src": "재료표 L·수량·R; 단면 '125','1.125','1.125','125', DIVISION 68; 정면 사슬(띠철근 외측·크로스타이); P1 갈고리 작도 높이 200/540", } (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("hoop levels", len(levels), levels[0], levels[-1], "ties", len(P["column_rebar"]["ties"]["levels"]), P["column_rebar"]["ties"]["levels"][-1]) print("schedule L", E["G2"]["schedule_L"], "scope", P["scope"]) if __name__ == "__main__": main()