"""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()