/* ============================================================================= * B05_Profile_Structure_Follow.ts * 노선 초안 동안 종단 알약 자리(PLAN 346-2 덧 3) — 계산 묶음 follow 가 좌표로 따라간 관 · 구조물의 새 * 누가거리를 알약 목록에 얹음. 구조물 = structure_id 로 짝 · 관 알약 id = 세션 id(`pipeIdAt`) 라 묶음 관 id * (서버 고정 id)와 다르면 누가거리 차례로 짝. * * 순수 — 화면 · fetch · 세션 없음. * ========================================================================== */ interface Placed { chainage_m?: number | null; start_m?: number | null; end_m?: number | null; } interface Mark extends Placed { structure_id?: string | null; } interface Moved extends Placed { id?: string | null; structure_id?: string | null; } const list = (value: unknown): Moved[] => (Array.isArray(value) ? (value as Moved[]) : []); const at = (item: Placed): number => item.chainage_m ?? item.start_m ?? 0; /** 알약 목록 → 따라간 자리를 얹은 사본 · 짝 없는 알약은 그대로. `structures` · `pipes` = 묶음 입력(follow 뒤). */ export function followedMarks( marks: ReadonlyArray, structures: unknown, pipes: unknown, ): T[] { const byId = new Map(); for (const item of list(structures)) if (item.structure_id) byId.set(item.structure_id, item); const movedPipes = list(pipes).filter((pipe) => typeof pipe.chainage_m === "number"); for (const pipe of movedPipes) if (pipe.id) byId.set(pipe.id, pipe); // ponytail: 차례 짝 — 노선을 고쳐 관 차례가 뒤바뀌면 틀림 · 알약이 서버 관 id 를 들면 id 짝으로 const loose = marks .filter((mark) => mark.structure_id?.startsWith("pipe-") && !byId.has(mark.structure_id)) .sort((a, b) => at(a) - at(b)); const ids = new Set(marks.map((mark) => mark.structure_id)); const free = movedPipes.filter((pipe) => !ids.has(pipe.id)).sort((a, b) => at(a) - at(b)); const paired = new Map(); if (loose.length === free.length) loose.forEach((mark, index) => paired.set(mark, free[index])); return marks.map((mark) => { const moved = (mark.structure_id ? byId.get(mark.structure_id) : undefined) ?? paired.get(mark); if (!moved) return mark; const shift = at(moved) - at(mark); const move = (value: number | null | undefined, next: number | null | undefined) => value == null ? value : (next ?? value + shift); return { ...mark, chainage_m: move(mark.chainage_m, moved.chainage_m), start_m: move(mark.start_m, moved.start_m), end_m: move(mark.end_m, moved.end_m), }; }); }