/* ============================================================================= * B05_Profile_UI_Structures_Pavement.ts * 포장 구간과 물넘이포장의 겹침 정리(2026-08-28 사용자 확정). * * 물넘이포장은 그 자체가 콘크리트 노면이라 포장 구간이 그 위를 덮을 수 없다. * · 포장 구간이 물넘이를 **통째로 품으면** → 알리고 앞·뒤 두 구간으로 나눈다 * (물넘이가 가운데 한 구간 — 합쳐서 3구간). * · **끝만 걸치면** → 어디까지 겹치는지 알리고 저장을 멈춘다. 사용자가 값을 고친다. * ========================================================================== */ import { FORD_PAVEMENT_DEFAULT_WIDTH_M } from "@config/config_frontend"; import { showConfirmDialog } from "@ui/ui_template_elements"; import type { PipeFacilityItem } from "./B05_Profile_UI_Structures_Panel"; /** 누가거리 비교 허용오차(m) — 정본이 0.01m로 끊어 쓴다. */ const EPS = 0.005; export interface Span { start: number; end: number; } /** 물넘이포장이 차지하는 누가거리 구간 — 기준 측점 ± 월류 폭/2. */ export function fordSpans(pipes: PipeFacilityItem[]): Span[] { return pipes .filter((pipe) => pipe.facility === "ford_pavement") .map((pipe) => { const raw = Number(pipe.options?.ford_width_m); const width = Number.isFinite(raw) && raw > 0 ? raw : FORD_PAVEMENT_DEFAULT_WIDTH_M; return { start: pipe.chainage_m - width / 2, end: pipe.chainage_m + width / 2 }; }) .sort((left, right) => left.start - right.start); } const format = (value: number): string => `${value.toFixed(2)}m`; /** * 포장 구간에서 물넘이 몫을 덜어낸다. * 반환: 저장할 구간 목록. `null`이면 저장하지 않는다(사용자가 값을 고쳐야 한다). */ export async function splitPavementRange( start: number, end: number, pipes: PipeFacilityItem[], ): Promise { const overlaps = fordSpans(pipes).filter( (ford) => ford.end > start + EPS && ford.start < end - EPS, ); if (!overlaps.length) return [{ start, end }]; // 끝만 걸친 물넘이 — 자르면 사용자가 찍은 구간이 조용히 줄어든다. 값을 고치게 안내한다. const partial = overlaps.find((ford) => ford.start <= start + EPS || ford.end >= end - EPS); if (partial) { await showConfirmDialog( `지정한 포장 구간(${format(start)}~${format(end)})이 물넘이포장` + `(${format(partial.start)}~${format(partial.end)})의 끝에 걸칩니다.\n` + "물넘이는 그 자체가 포장이라 겹칠 수 없습니다 — 기준 측점·길이·전후 값을 고쳐 주세요.", "확인", ); return null; } const segments: Span[] = []; let cursor = start; for (const ford of overlaps) { if (ford.start - cursor > EPS) segments.push({ start: cursor, end: ford.start }); cursor = ford.end; } if (end - cursor > EPS) segments.push({ start: cursor, end }); const inside = overlaps.map((ford) => `${format(ford.start)}~${format(ford.end)}`).join(", "); const proceed = await showConfirmDialog( `포장 구간 안에 물넘이포장(${inside})이 있습니다.\n` + `물넘이는 그 자체가 포장이라 그 몫을 빼고 ${segments.length}개 구간으로 나눠 저장합니다.`, "나눠 저장", ); return proceed ? segments : null; }