Files
Pier_v1/Code/새재1교P1판독/extract_g4.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

176 lines
10 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""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))