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