/* ============================================================================= * A00_Common/design/design_pipeline_probe.ts * 계산 묶음 아무 누가거리 한 장(368-4 · 요구 240-21) — 종단 원지반 점 작은 창 = 지금 계획선(초안 포함). * * 묶음 출력(노선 · 측점 · 종단 · 횡단 입력 · 관 · 구조물)을 읽기만 하고, 같은 단계 함수(ground · cross · * `crossWithUphill` · `stationSection`)를 그 자리 측점 하나로 다시 부름 — [측점 추가] 뒤 묶음이 낼 측점과 * 같은 틀 · 반경 · 확폭(기존 측점 + 그 자리로 셈). 파생 저장 · 캐시 · 묶음 상태는 안 건드림. * 지형 격자가 없거나 분석 지형 ≠ 설계 지형이면 null(부르는 쪽이 서버 미리 뜨기로). * 단면(`section`) = 그 측점에 지금 현황 형상 · 이름을 얹은 것 — 창이 「횡단」 판과 같은 B06 카드로 그림(505-3). * ========================================================================== */ import { pagePipeline } from "./design_pipeline_page"; import type { CrossOutput, GroundOutput, StageContext, StageName, } from "./logic/design_pipeline_types"; import { probeStation } from "./logic/design_pipeline_probe_station"; import { groundStageDeps } from "../../B05_Profile/B05_Profile_Api_TerrainGrid"; import { createGroundStage } from "../../B05_Profile/logic/B05_Profile_Pipeline_RouteGround"; import { attachStatus, crossWithShapes, crossAtSeat, crossWithUphill, shapeStatus, stationSection, type CrossInput, } from "../../B05_Profile/logic/B05_Profile_Pipeline_Detail"; import { fetchStructureTypes } from "../../B05_Profile/B05_Profile_Api_Structures"; import { createCrossStage } from "../../B06_Section/logic/B06_Section_Cross_Stage"; import { pipelineCrossAt } from "../../B05_Profile/B05_Profile_UI_RouteEdit_Cross"; import type { CrossPreviewResponse } from "../../B05_Profile/B05_Profile_Api_Replan"; import type { CrossSection } from "../../B06_Section/B06_Section_Api_Fetch"; const SAME_M = 1e-6; /** * 지금 계획선(초안 포함)으로 그 누가거리 임시 횡단(선 그림 재료 · 형상 얹은 단면) — 묶음이 아직 안 셌거나 * 격자 없음 · 분석 지형 ≠ 설계 지형이면 null. */ export async function pipelineCrossAtChainage( projectId: string, chainageM: number, intervalM: number, ): Promise<{ preview: CrossPreviewResponse; section: CrossSection } | null> { const pipe = pagePipeline(projectId); const route = pipe?.output("route"); const profile = pipe?.output("profile"); const ground = pipe?.output("ground"); if (!pipe || !route || !profile || !ground) return null; const deps = groundStageDeps(projectId); const local = deps.grid(); const terrain = pipe.input("route")?.terrain ?? null; if (!local || (terrain !== null && terrain !== local.design)) return null; const inputs = { route: pipe.input("route"), alignment: pipe.input("alignment"), cross: pipe.input("cross"), pipes: pipe.input("pipes"), structures: pipe.input("structures"), }; const existing = ground.stations.find((s) => Math.abs(s.chainageM - chainageM) < SAME_M); let station = existing ?? null; if (!station) { const probe = probeStation(route.line, route.curves, ground.stations, chainageM); if (!probe) return null; // ground 단계 그대로 — 측점 하나 · 종단 지반선은 안 뜸(노선 선 빼고 넘김) const ctx = { generation: 0, range: null, signal: new AbortController().signal, inputs, out: { stations: [probe], route: { ...route, line: null } }, before: {}, prev: null, } as unknown as StageContext<"ground">; const filled = (await createGroundStage(deps)(ctx)) as GroundOutput; station = filled.stations[0] ?? null; } if (!station) return null; // 시설 맥락 = 지금 현황을 그 측점에 얹은 그림에서(묶음 cross 와 같음 · 457) const status = shapeStatus( inputs.pipes, inputs.structures, await fetchStructureTypes(true).catch(() => []), ); const shaped = crossWithShapes( crossAtSeat(inputs.cross as CrossInput | null, [station]), [station], status, ); const out = { profile, ground: { stations: [station], longitudinal: { chainageM: [], z: [] } }, } as Partial>; const cross: CrossOutput = createCrossStage({ grid: deps.grid }).stage({ generation: 0, range: null, signal: new AbortController().signal, inputs: { ...inputs, cross: crossWithUphill(shaped, [station]) }, out, before: {}, prev: null, } as unknown as StageContext<"cross">); // 평면 우측 횡단 판과 같은 꼴(그림 · 요약) — 이 측점 하나만 실은 묶음처럼 넘김 const one = { output: (name: StageName) => name === "ground" ? { stations: [station] } : name === "cross" ? cross : null, } as unknown as Parameters[0]; const preview = pipelineCrossAt(one, chainageM, intervalM, undefined); if (!preview) return null; const section = stationSection(station, cross, {}, intervalM); attachStatus([section], status); return { preview, section }; }