/* ============================================================================= * B06_Section_UI_Cross_View_Ford.ts * 횡단 카드 ↔ **세월교 조정창** 배선 — 카드 렌더러(`_UI_Cross_View.ts`)에서 700줄 * 제한으로 분리했다(2026-08-25). 조정창이 부르는 동작을 제어기로 넘기는 얇은 층이고, * 기하나 그리기는 하지 않는다. * ========================================================================== */ import type { CrossSection } from "./B06_Section_Api_Fetch"; import type { FordPanelDeps, FordControl } from "./B06_Section_UI_Cross_Ford_Panel"; import type { FordLayout, FordWallRole } from "./B06_Section_UI_Cross_Ford"; /** 조정창 배선에 필요한 카드 상태. 계산 결과는 그릴 때마다 바뀌므로 함수로 받는다. */ export interface FordPanelContext { section: CrossSection; ford: FordControl; /** 마지막 계산의 측벽 높이(m) — 높이 조작의 시작값. */ heightFor: (role: FordWallRole) => number; /** 마지막 계산의 바닥판 길이(m). */ slabLengthM: () => number; close: () => void; } /** 화면 좌(◀) 방향을 벽 기준 바깥 부호로 환산한다. 유입 = 상단측. */ function outwardOf(section: CrossSection, role: FordWallRole): number { return ((section.uphill_side ?? "left") === "left") === (role === "inlet") ? 1 : -1; } export function fordPanelDeps(context: FordPanelContext): FordPanelDeps { const { section, ford } = context; const chainage = section.chainage_m; return { adjustFor: (role) => ford.adjustFor(chainage)[role], heightFor: context.heightFor, nudgeHeight: (role, deltaM) => ford.update(chainage, role, { heightM: context.heightFor(role) + deltaM }), nudge: (role, screenDeltaM) => ford.update(chainage, role, { lateralM: ford.adjustFor(chainage)[role].lateralM + screenDeltaM * outwardOf(section, role), }), nudgeSlope: (role, deltaM) => ford.update(chainage, role, { slopeM: ford.adjustFor(chainage)[role].slopeM + deltaM, }), reset: (role) => ford.reset(chainage, role), pipeDiameterMm: () => Math.round((section.ford?.diameter_m ?? 1) * 1000), setPipeDiameterMm: (value) => ford.setPipe(chainage, { pipe_diameter_mm: value }), pipeCount: () => section.ford?.pipe_count ?? 1, setPipeCount: (value) => ford.setPipe(chainage, { pipe_count: value }), wingFor: (role) => { const spec = section.ford; if (!spec) return null; return role === "inlet" ? spec.wing_in : spec.wing_out; }, setWing: (role, patch) => ford.setWing(chainage, role, patch), slabLengthM: context.slabLengthM, close: context.close, }; } /** 조정창이 쓸 세월교 카드 상태 — 마지막 기하 결과에서 뽑는다(카드 렌더러 700줄 분리). */ export function fordCardState(layout: FordLayout): { slabLengthM: number; heights: Map; } { return { slabLengthM: layout.slabLengthM, heights: new Map(layout.sides.map((side) => [side.role, side.heightM])), }; }