Files
Pier_v1/Code/교각모델링/extract_bearing_seats.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

122 lines
5.9 KiB
Python

"""Read bearing pedestal (h1) and pad (h2) geometry and append `bearing_seats` to params.json.
Sources (read only): 판독/plan.json (D1 평면도 entities), 판독/2_survey.json (D2 ELEVATION TABLE).
Base pattern = girder line 5 as drawn in D1 평면도. Girder lines 1..4 = base shifted in X by
(k-5) * 7516/3 (D1 평면도 dim '3@2.505=7.516'); lines 3·4 are checked against drawn vertices,
lines 1·2 are not drawn ([추론], approved by user 2026-10-07).
Existing params.json keys are left unchanged; only `bearing_seats` is (re)written.
"""
import json
import math
from pathlib import Path
from calc_bearing_seat import table_rows
HERE = Path(__file__).resolve().parent
DATUM = (12162.4, 26412.3) # D1 평면도 pier centre (CS-CNTL 1BFBF x 1C113)
PITCH = 7516 / 3
def entities():
return {r["h"]: r for r in json.loads((HERE / "판독" / "plan.json").read_text(encoding="utf-8"))}
def rel(p):
return [round(p[0] - DATUM[0], 1), round(p[1] - DATUM[1], 1)]
def centre(q):
return [sum(p[0] for p in q) / 4, sum(p[1] for p in q) / 4]
def angle_deg(a, b):
"""Rotation of edge a->b from the +Y axis, clockwise positive (plan view)."""
return math.degrees(math.atan2(b[0] - a[0], b[1] - a[1]))
def main():
E = entities()
pt = lambda h, i: E[h]["pts"][i]
# Pedestal outline girder 5: 1C0D1 start (front-left), 1C0CE end (rear-left), 1C0CF end, 1C0D0 end
ped = [pt("1C0D1", 1), pt("1C0CE", 1), pt("1C0CF", 1), pt("1C0D0", 1)]
split = [pt("1CAD4", 0), pt("1CAD4", 1)] # left / right point of the front|rear split line
front_half = [ped[0], split[0], split[1], ped[3]]
rear_half = [split[0], ped[1], ped[2], split[1]]
pads = {"front": dict(bottom="1C124", top="1C125"), "rear": dict(bottom="1C11B", top="1C11C")}
rows = {r["no"]: r for r in table_rows()}
checks = []
# Parallel-translation check on drawn girder lines 4 (full) and 3 (half, x >= datum)
g4 = [pt("1C0D9", 1), pt("1C0D6", 1), pt("1C0D7", 1), pt("1C0D8", 1)]
for a, b in zip(ped, g4):
checks.append(dict(item="girder4 pedestal vertex", dx=round(b[0] - (a[0] - PITCH), 2),
dy=round(b[1] - a[1], 2)))
g3 = [pt("1C0DC", 1), pt("1C0DD", 1)] # rear-right, front-right corners of girder 3
for a, b in zip([ped[2], ped[3]], g3):
checks.append(dict(item="girder3 pedestal vertex", dx=round(b[0] - (a[0] - 2 * PITCH), 2),
dy=round(b[1] - a[1], 2)))
for row, hs in (("front", ("1C124", "1C127")), ("rear", ("1C11B", "1C11E"))):
c5, c4 = centre(E[hs[0]]["pts"]), centre(E[hs[1]]["pts"])
checks.append(dict(item=f"girder4 {row} pad centre", dx=round(c4[0] - (c5[0] - PITCH), 2),
dy=round(c4[1] - c5[1], 2)))
pad_rows = {}
for row, h in pads.items():
q, qt = E[h["bottom"]]["pts"], E[h["top"]]["pts"]
pad_rows[row] = dict(
centre_rel_girder5=rel(centre(q)),
rotation_deg=round(angle_deg(q[0], q[1]), 3),
drawn_bottom_along=round(math.dist(q[0], q[1]), 1),
drawn_bottom_across=round(math.dist(q[1], q[2]), 1),
drawn_top_along=round(math.dist(qt[0], qt[1]), 1),
drawn_top_across=round(math.dist(qt[1], qt[2]), 1),
src=f"D1 평면도 {h['bottom']} (bottom), {h['top']} (top)")
bearings = []
for no in range(1, 11):
r = rows[no]
girder = (no - 1) % 5 + 1
row = "front" if no <= 5 else "rear"
p = pad_rows[row]
bearings.append(dict(
no=no, type=r["type"], girder_line=girder, row=row,
centre=[round(p["centre_rel_girder5"][0] + (girder - 5) * PITCH, 1), p["centre_rel_girder5"][1]],
rotation_deg=p["rotation_deg"],
el_x=round(r["el_x"] * 1000), h1=r["h1"], h2=r["h2"], A=None, B=None,
inferred=girder <= 2))
# A and B per bearing from D2 TABLE (columns A, B)
texts = json.loads((HERE / "판독" / "2_survey.json").read_text(encoding="utf-8"))["texts"]
ys = {r["no"]: r["src_y"] for r in rows.values()}
for b in bearings:
for t in texts:
if abs(round(t["y"]) - ys[b["no"]]) <= 1 and 21000 < t["x"] < 37500:
if abs(t["x"] - 29742) < 200:
b["A"] = int(t["text"])
elif abs(t["x"] - 30642) < 200:
b["B"] = int(t["text"])
seats = dict(
_note="pedestal (h1) per girder line, split into front/rear halves; pad (h2) = frustum "
"bottom (A+200)x(B+200) -> top (A+100)x(B+100), height h2, rotated per row",
plan_datum=list(DATUM), pitch_x=PITCH,
pedestal_girder5=dict(front_half=[rel(p) for p in front_half], rear_half=[rel(p) for p in rear_half],
rotation_deg=round(angle_deg(ped[0], ped[1]), 3),
src="D1 평면도 1C0CE~1C0D1 (outline 2500x1200), 1CAD4 (front/rear split)"),
pad_rows=pad_rows, bearings=bearings, translation_checks=checks,
src={"h1_h2_A_B_ELX": "D2 교량받침 ELEVATION TABLE", "row_mapping":
"front(전열)=3500kN NO.1-5 (S1 852), rear(후열)=2800kN NO.6-10 (S1 950); 852+1298+950=3100",
"girder_mapping": "NO.k / NO.k+5 -> girder line k, left->right (EL.'X' rises with coping steps)",
"pad_size_rule": "D1 평면도 front pad 900x840 / 800x740 = (A+200)x(B+200) / (A+100)x(B+100) for "
"A=700,B=640; side view 900->800 over 50"})
params_path = HERE / "params.json"
params = json.loads(params_path.read_text(encoding="utf-8"))
params["bearing_seats"] = seats
params_path.write_text(json.dumps(params, ensure_ascii=False, indent=2), encoding="utf-8")
print(json.dumps(dict(pedestal_rotation=seats["pedestal_girder5"]["rotation_deg"], pad_rows=pad_rows,
checks=checks, AB=[(b["no"], b["A"], b["B"]) for b in bearings]),
ensure_ascii=False, indent=1))
if __name__ == "__main__":
main()