/* ============================================================================= * A00_Common/design/logic/design_calc_node_follow.ts * 계산 Node 입구(`design_calc_node.ts`)의 따라감 몫(PLAN 472-4 ①) — 측점 열쇠 · 시설 따라감 · 추가 측점 · * 꼭짓점 세움. 브라우저 묶음이 쓰는 같은 TS 를 부름 · 파이썬은 `common_util_calc_runner.run_calc` 로. * * profile.seat 입력 seat { ground_s · ground_z(저장 선형 표본) · policy(파이썬 `AlignmentPolicy.as_dict`) · * base_pvi(옮기기 전) · base(옮긴 꼭짓점) · born · held } → 꼭짓점 목록(`seatBornNodes`) * facility.follow 입력 follow { items: [{ placement · chainage_m · start_m · end_m · x · y }] · line · * max_drift_m · interval_m(site 맞춤 간격) } → [{ item · drift_m · far }](`followStructures`) * — follow.fill { previous?: { structure_id: 항목 } · only_missing } 있으면 = 저장 좌표 맞춤(같은 F1 · * 511-B B-5) → { xy: [{ x · y } | null(그대로)] · filled }(`fillStructureCoordinates` · items 에 structure_id) * facility.plus_follow 입력 plus { rows: [{ chainage_m · x · y }] · line: [[x, y]](새 노선) } → * { rows: [{ chainage_m · x · y }](`followPlusRows` · 정수 m · 같은 m 하나) · moved: 옮긴 수 } * ========================================================================== */ import { seatBornNodes } from "../../../B05_Profile/logic/B05_Profile_Grade_Seat"; import { fillStructureCoordinates, followPlusRows, followStructures, type FollowingStructure, } from "@util/common_util_route_follow"; import type { AlignmentNode, AlignmentPolicy, } from "../../../B05_Profile/logic/B05_Profile_UI_Profile_Alignment"; type Line = Array<[number, number]>; const xyOf = (line: Line) => line.map(([x, y]) => ({ x, y })); export interface FollowInputs { follow?: { items: Array; line: Line; max_drift_m?: number; interval_m?: number | null; fill?: { previous?: Record | null; only_missing?: boolean }; }; plus?: { rows: Array<{ chainage_m: number; x?: number | null; y?: number | null }>; line: Line }; seat?: { ground_s: number[]; ground_z: number[]; policy: AlignmentPolicy; base_pvi: AlignmentNode[]; base: AlignmentNode[]; born: number[]; held?: number[]; }; } /** id → 셈(입구 `RUNNERS` 에 얹음). */ export function followRunners(inputs: FollowInputs): Record unknown> { return { "profile.seat": () => { const seat = inputs.seat; if (!seat) return null; const base = { chainage: seat.ground_s, ground: seat.ground_z, policy: seat.policy, basePvi: seat.base_pvi, }; return seatBornNodes(base, seat.base, seat.born, seat.held ?? []); }, "facility.follow": () => { const follow = inputs.follow; if (!follow) return null; if (follow.fill) return fillStructureCoordinates( follow.items, xyOf(follow.line), follow.fill.previous ?? null, follow.fill.only_missing ?? false, follow.interval_m ?? null, ); return followStructures( follow.items, xyOf(follow.line), follow.max_drift_m, follow.interval_m ?? null, ); }, "facility.plus_follow": () => { const plus = inputs.plus; if (!plus) return null; const line = xyOf(plus.line); const moved = followStructures(plus.rows, line).filter( ({ item }, index) => item.chainage_m !== plus.rows[index].chainage_m, ).length; const rows = followPlusRows(plus.rows, line).map(({ chainage_m, x, y }) => ({ chainage_m, x: x ?? null, y: y ?? null, })); return { rows, moved }; }, }; }