"""Saejae-1 P1 coping + bearing-seat rebar (G4: C1~C20, S1~S2) -> centreline polylines for the generic builder rebar_polylines.py. Inputs: the drawing (DXF 구조도(1) front: stirrup stations, side-loop lines, C18 / C19 / C20 / C7 lines and points; 구조도(2) sections A-A / B-B: stirrup polygons, loop / tie y), the schedule, params.json (pedestals), the Okseong rules (H1-H6 style) applied again 2026-10-15. Output: 판독/g4_bars.json {"bars": [...], "summary": {...}} used by add_g4.py. Model axes: X along the coping, Y across, Z = EL x 1000, pier centre at the origin; the plan is rectangular (no shear). Front datum: z = drawing y - 1,429.7 (coping part), centre x 225,817.5. """ import json import math from collections import defaultdict from pathlib import Path from dxftools import entities HERE = Path(__file__).resolve().parent APP = HERE.parents[1] / "Code" / "교각모델링앱" P = json.loads((APP / "data" / "새재1교P1" / "params.json").read_text(encoding="utf-8")) SCH = {m: float(v) for m, v in json.loads((HERE / "판독" / "g4_schedule.json").read_text(encoding="utf-8")).items()} if (HERE / "판독" / "g4_schedule.json").exists() else {} FX, ZO = 225817.5, -1429.7 bars = [] STEP_B = [-3722.6, -1215.6, 1291.3, 3798.2] STEP_Z = [32531.5, 32632.5, 32733.5, 32834.5, 32936.0] TAN_S = 1700.0 / 4800.0 # soffit slope COS_S = 4800.0 / math.hypot(4800.0, 1700.0) KF = 400.0 / 1700.0 # side taper (half width 1,100 -> 1,500) Y23 = [-1375.0 + 125 * k for k in range(23)] def rb(dia): return ((2 * dia if dia <= 16 else 3.5 * dia) + dia) / 2 DIA = {"C1": 29, "C2": 29, "C3": 29, "C4": 29, "C5": 29, "C6": 29, "C7": 29, "C8": 25, "C9": 25, "C10": 25, "C11": 25, "C12": 25, "C13": 25, "C14": 22, "C15": 22, "C16": 22, "C17": 22, "C18": 19, "C19": 19, "C20": 19, "S1": 13, "S2": 13} def add(mark, occ, pts, src, r=None): length = sum(math.dist(a, b) for a, b in zip(pts, pts[1:])) bars.append({"mark": mark, "occ": occ, "pts": [[round(v, 2) for v in p] for p in pts], "r": rb(DIA[mark]) if r is None else r, "design_length": round(length, 1), "src": src}) def step_z(x): return STEP_Z[sum(1 for b in STEP_B if x >= b)] TIER_B = [-3600.5, -1100.5, 1399.5, 3899.5] # drawn stirrup top tiers (stations; between 2 stations, not at the step edges) def tier_z(x): return STEP_Z[sum(1 for b in TIER_B if x >= b)] def soffit(x): return 29532.0 if abs(x) <= 1200 else 29532.0 + TAN_S * (abs(x) - 1200) def y_out(z): # stirrup / loop outer line: 128.4 inside the side taper face return min(1375.0, 971.6 + 0.235294 * (z - 29532.0)) # ---- C1~C6 top bars: 3 layers, 23 rows, marks alternate, x +-5,875 ------------------------------------------------------------- for z, legs, (ma, mb) in ((32407.0, 1087.0, ("C1", "C4")), (32332.0, 100.0, ("C2", "C5")), (32232.0, 100.0, ("C3", "C6"))): for i, y in enumerate(Y23): add((ma, mb)[i % 2], f"y{y:+.0f}", [(-5875, y, z - legs), (-5875, y, z), (5875, y, z), (5875, y, z - legs)], f"정면 선 EL {z / 1000:.3f}, x ±5,875, 다리 {legs:.0f}; 단면 사슬 23줄 @125, 교번 [추론 F3형], 겹이음 j 미모델") # ---- C19 / C20: stepped top pieces, 23 rows ----------------------------------------------------------------------------------- PIECES = [("C20", 32508.0, -3597.6, -845.6, "left"), ("C20", 32609.0, -1090.6, 1661.3, "left"), ("C20", 32710.1, 1416.3, 4168.2, "left"), ("C19", 32811.1, 3923.2, 5875.0, "both")] for mark, z, xa, xb, leg in PIECES: for y in Y23: if leg == "both": p = [(xa, y, z - 370), (xa, y, z), (xb, y, z), (xb, y, z - 370)] else: p = [(xa, y, z - 370), (xa, y, z), (xb, y, z)] add(mark, f"x{xa:+.0f}y{y:+.0f}", p, f"정면 선 EL {z / 1000:.4f}, x {xa} ~ {xb}, 다리 370 (단 상면 − 125)") # ---- C7: soffit bar ('a' 525 up, slope, flat); 8 bars flat, 2 + 2 raised along the side face (as Okseong H3) --------------------- SLOPE = (31320.3 - 29657.0) / (5875.0 - 1178.5) CAP = 32400.0 for y in [-1375.0 + 250 * k for k in range(12)]: dz = 0.0 if abs(y) <= 875 else (30184.0 - 29657.0 if abs(y) <= 1125 else 31246.5 - 29657.0) zr, top = 31320.3 + dz, 31320.3 + 525 + dz if top > CAP: xe = 1178.5 + (CAP - (29657.0 + dz)) / SLOPE pts = [(-xe, y, CAP), (-1178.5, y, 29657.0 + dz), (1178.5, y, 29657.0 + dz), (xe, y, CAP)] else: pts = [(-5875, y, top), (-5875, y, zr), (-1178.5, y, 29657.0 + dz), (1178.5, y, 29657.0 + dz), (5875, y, zr), (5875, y, top)] add("C7", f"y{y:+.0f}", pts, "정면 하면 경사선(±1,178.5 평평 EL 29.657, ±5,875 EL 31.3203, 위 끝 연직 525), 단면 B-B 점 EL 29.657 / 30.184 / 31.2465") # ---- stirrups C8~C13: 94 stations x = -5788 + 125 k; per station 2 rectangles (C8/C10/C12) + 2 pentagons (C9/C11/C13) ------------- ST = [-5788.0 + 125 * k for k in range(94)] OFF = {"PL": -37.5, "R1": -12.5, "R2": 12.5, "PR": 37.5} def zone(x): return 0 if x < -1200 else (1 if x <= 1200 else 2) for x in ST: zt = tier_z(x) - 102.0 # drawn line = pad - 124.5, 22.5 drawn offset -> centre pad - 102 def zb_at(xb): return soffit(xb) + 102.5 / (1.0 if abs(xb) <= 1200 else COS_S) rect, pent = (("C8", "C9"), ("C10", "C11"), ("C12", "C13"))[zone(x)] for tag, (y0, y1) in (("R1", (-875.0, 625.0)), ("R2", (-625.0, 875.0))): xx = x + OFF[tag] zb = zb_at(xx) add(rect, f"x{x:+.0f}{tag}", [(xx, (y0 + y1) / 2, zt), (xx, y1, zt), (xx, y1, zb), (xx, y0, zb), (xx, y0, zt), (xx, (y0 + y1) / 2, zt)], f"정면 연직선 x {x}, 단면 A-A/B-B 직사각 y {y0:.0f} ~ {y1:.0f}, 위 = 단 상면 − 102, 아래 = 하면 + 102.5 [x 어긋남 {OFF[tag]:+.1f}, 추론]") for tag, s in (("PL", -1), ("PR", 1)): xx = x + OFF[tag] zb = zb_at(xx) yb = y_out(zb) zc = 29532.0 + (1375.0 - 971.6) / 0.235294 yin = -s * 375.0 p = [(xx, s * 500.0, zt), (xx, s * 1375.0, zt)] if zb < zc - 20: p += [(xx, s * 1375.0, zc)] p += [(xx, s * yb, zb)] else: p += [(xx, s * 1375.0, zb)] p += [(xx, yin, zb), (xx, yin, zt), (xx, s * 500.0, zt)] add(pent, f"x{x:+.0f}{tag}", p, f"단면 B-B 5각형: 안쪽 y {yin:+.0f}, 바깥 ±1,375 → 측면 테이퍼 따라 모따기, [x 어긋남 {OFF[tag]:+.1f}, 추론]") # ---- side loops C16 (upper 4) / C14 (lower 7) and ties C17 / C15 (6 rows: y +-352.5, +-602.5, +-852.5) ------------------------------- D_H = {} for e in entities("D1", FX - 6600, 30800, FX + 6600, 34300, "CS-RBAR"): if e.dxftype() == "LINE" and abs(e.dxf.start.y - e.dxf.end.y) < 0.5: z = round(e.dxf.start.y + ZO, 1) D_H[z] = max(D_H.get(z, 0), round(max(abs(e.dxf.start.x - FX), abs(e.dxf.end.x - FX)), 1)) UP = [32182.0, 31932.0, 31682.0, 31432.0] LOW = [31182.0, 30932.0, 30682.0, 30432.0, 30182.0, 29932.0, 29682.0] for levels, loop, tie in ((UP, "C16", "C17"), (LOW, "C14", "C15")): for z in levels: xe = D_H[z] yo = 1352.5 if z >= 31400 else y_out(z) - 0.0 if z < 31400: yo = round(1337.3 - (31182.0 - z) * 0.2354, 1) # drawn dots ±1337.3 ... ±984.3 (taper) add(loop, f"z{z:.0f}", [(0, yo, z), (xe, yo, z), (xe, -yo, z), (-xe, -yo, z), (-xe, yo, z), (0, yo, z)], f"정면 선 EL {z / 1000:.3f} x ±{xe}, 단면 B-B 점 y ±{yo}") for y in (-852.5, -602.5, -352.5, 352.5, 602.5, 852.5): add(tie, f"z{z:.0f}y{y:+.1f}", [(-xe, y, z), (xe, y, z)], f"정면 선 EL {z / 1000:.3f}, 단면 점 y {y} (135° 갈고리 미모델)") # ---- C18: Y-direction U at every drawn front point (7 levels, 92) ------------------------------------------------------------------ dots = defaultdict(list) for e in entities("D1", FX - 6600, 30800, FX + 6600, 34300, "CS-RBAR"): if e.dxftype() == "INSERT": dots[round(e.dxf.insert.y + ZO, 1)].append(round(e.dxf.insert.x - FX, 1)) C18_Z = [32457.0, 32432.0, 32309.5, 32209.5, 31682.0, 30682.0, 29682.0] for z in C18_Z: hl = y_out(z) for x in sorted(dots[z]): if z >= 32000: p = [(x, -hl, z - 370), (x, -hl, z), (x, hl, z), (x, hl, z - 370)] else: yl = y_out(z + 370) p = [(x, -yl, z + 370), (x, -hl, z), (x, hl, z), (x, yl, z + 370)] add("C18", f"x{x:+.0f}z{z:.0f}", p, f"정면 점 EL {z / 1000:.4f}, 측면 폭 ±{hl:.1f}, 다리 370 (낮은 단은 위로, 옥성교 H3 규칙)") # ---- seat bars per pedestal: S1 (11, a 2,297 along Y), S2 (20, a 1,200 along X), legs 700 down ------------------------------------- for k, ped in enumerate(P["bearing_seats"]["pedestals"]): xs = [c[0] for c in ped["corners"]] ys = [c[1] for c in ped["corners"]] cx, cy = (min(xs) + max(xs)) / 2, (min(ys) + max(ys)) / 2 zp = (ped["top"]["z0"] + ped["top"]["z1"]) / 2 z1, z2 = zp - 50, zp - 50 - 13 for j, dx in enumerate([-600.0] + [-500.0 + 125 * i for i in range(9)] + [600.0]): add("S1", f"P{k + 1}-{j:02d}", [(cx + dx, cy - 1148.5, z1 - 700), (cx + dx, cy - 1148.5, z1), (cx + dx, cy + 1148.5, z1), (cx + dx, cy + 1148.5, z1 - 700)], f"교좌면 보강 상세, 대좌 {k + 1}, S1 11 × 대좌 [추론 방향]", r=rb(13)) for j, dy in enumerate([-1148.5] + [-1062.5 + 125 * i for i in range(18)] + [1148.5]): add("S2", f"P{k + 1}-{j:02d}", [(cx - 600, cy + dy, z2 - 700), (cx - 600, cy + dy, z2), (cx + 600, cy + dy, z2), (cx + 600, cy + dy, z2 - 700)], f"교좌면 보강 상세, 대좌 {k + 1}, S2 20 × 대좌 [추론 방향]", r=rb(13)) count = {} for b in bars: count[b["mark"]] = count.get(b["mark"], 0) + 1 out = {"bars": bars, "summary": {"bars": len(bars), "per_mark": count}} (HERE / "판독" / "g4_bars.json").write_text(json.dumps(out, ensure_ascii=False), encoding="utf-8") print(json.dumps(out["summary"], ensure_ascii=False))