diff --git a/A00_Common/design/design_pipe_ids.ts b/A00_Common/design/design_pipe_ids.ts index d5c9ef567..02c93b7b6 100644 --- a/A00_Common/design/design_pipe_ids.ts +++ b/A00_Common/design/design_pipe_ids.ts @@ -46,6 +46,20 @@ export function pipeIdAt(chainageM: number, projectId: string | null = active): return id; } +/** 그 자리 관의 id — 장부에 있을 때만(안 지음 · 411-E). */ +export function pipeIdNear(chainageM: number, projectId: string | null = active): string | null { + if (!projectId) return null; + return nearestWithin(bookOf(projectId).ids, chainageM, (entry) => entry.at)?.id ?? null; +} + +/** 지금 관 자리(`keep`) 근처에 없는 기록을 뺌 — 옮긴 사이 옛 측점이 지은 헛 id 정리(411-E). */ +export function prunePipeIds(keep: ReadonlyArray, projectId: string | null = active): void { + if (!projectId || !keep.length) return; // 빈 목록 = 아직 못 받음 · 다 지움 — 장부 그대로 + const book = bookOf(projectId); + const ids = book.ids.filter((entry) => keep.some((at) => isNear(entry.at, at))); + if (ids.length !== book.ids.length) writeState("pipe-ids", { next: book.next, ids }, projectId); +} + /** id 의 관 자리 — 장부 · 옛 자리 이름 순 · 관 id 가 아니면 null. */ export function pipeChainageOf(id: string, projectId: string | null = active): number | null { if (!id.startsWith("pipe-")) return null; diff --git a/A00_Common/design/design_view_profile.ts b/A00_Common/design/design_view_profile.ts index 2ee2a5f5f..9799e068c 100644 --- a/A00_Common/design/design_view_profile.ts +++ b/A00_Common/design/design_view_profile.ts @@ -66,7 +66,7 @@ import "../../B05_Profile/B05_Profile_UI_Style.css"; import "../../B05_Profile/B05_Profile_UI_Style_Table.css"; import "../../B05_Profile/B05_Profile_UI_Style_Drainage.css"; import "../../B05_Profile/B05_Profile_UI_Style_Structures.css"; -import { pipeIdAt, placePipeIds } from "./design_pipe_ids"; +import { pipeIdAt, placePipeIds, prunePipeIds } from "./design_pipe_ids"; import { useDesignStore } from "./design_store"; import { setPlusStations } from "../../common_util/common_util_structure_station"; import { @@ -132,6 +132,10 @@ export async function mountProfileView( pipe.id ? [[pipe.id, pipeIdAt(pipe.chainage_m, activeProjectId)] as const] : [], ), ); + prunePipeIds( + shown.map((pipe) => pipe.chainage_m), + activeProjectId, + ); // 헛 id 정리(411-E) return shown; }; const applyPipes = (reported: PipeReport, carryEdits = true): void => { diff --git a/B06_Section/B06_Section_Station_Keys.ts b/B06_Section/B06_Section_Station_Keys.ts index f28f8f3e3..3677b57e7 100644 --- a/B06_Section/B06_Section_Station_Keys.ts +++ b/B06_Section/B06_Section_Station_Keys.ts @@ -16,7 +16,7 @@ * ========================================================================== */ import { readState, writeState } from "../A00_Common/b_page_state"; -import { pipeIdAt } from "../A00_Common/design/design_pipe_ids"; +import { pipeIdAt, pipeIdNear } from "../A00_Common/design/design_pipe_ids"; import { showToast } from "@ui/ui_template_elements"; import { chainageKey, @@ -116,15 +116,18 @@ export function stationKeysOf( intervalM: number | null, ): Keyed[] { const known = projectId ? (owners.get(projectId) ?? []) : []; + const planned = known.some((owner) => owner.kind === "pipe"); const keys = sections.map((section) => { const at = section.chainage_m; let key: string; if (section.kind === "irregular") { const owner = known.find((entry) => Math.abs(entry.at - at) < NEAR_M); if (owner) key = stationKey("irregular", at, intervalM, owner.id, owner.kind, owner.role); - else if (looksLikePipe(section)) - key = stationKey("pipe", at, intervalM, pipeIdAt(at, projectId)); - else + else if (looksLikePipe(section)) { + // 관 계획을 아는 동안(초안) 계획에 없는 관 측점 = 옮겨 간 옛 자리 — 세션 id 를 새로 안 지음(411-E) + const id = planned ? pipeIdNear(at, projectId) : pipeIdAt(at, projectId); + key = id ? stationKey("pipe", at, intervalM, id) : stationKey("irregular", at, intervalM); + } else key = section.grid ? stationKey("regular", at, intervalM) : stationKey("irregular", at, intervalM); diff --git a/resources/tester/helper_411_b_entry.ts b/resources/tester/helper_411_b_entry.ts index 4023287b6..0e45be03d 100644 --- a/resources/tester/helper_411_b_entry.ts +++ b/resources/tester/helper_411_b_entry.ts @@ -5,7 +5,9 @@ export { followPipeReports } from "../../B05_Profile/logic/B05_Profile_Pipeline_ export { followedMarks } from "../../B05_Profile/logic/B05_Profile_Structure_Follow"; export { movePipeId, + pipeIdNear, placePipeIds, + prunePipeIds, pipeChainageOf, pipeIdAt, usePipeIds, diff --git a/resources/tester/helper_411_b_pipe_id_pairing.mjs b/resources/tester/helper_411_b_pipe_id_pairing.mjs index 0af5598f8..c41f8f15d 100644 --- a/resources/tester/helper_411_b_pipe_id_pairing.mjs +++ b/resources/tester/helper_411_b_pipe_id_pairing.mjs @@ -161,4 +161,23 @@ m.useStationOwners(P, planned); out.keysNoPipes = m.stationKeysOf(P, sections, 20).map((k) => k.key); out.pipelineKey = m.pipelineStationKey("pipe", "p8017"); +/* 7. 411-E — 관 계획을 아는 동안 옛 자리 관 측점(옮겨 간 자리)은 세션 id 를 안 지음 · 헛 id 정리 */ +const E = "e411"; +m.usePipeIds(E); +const e1 = m.pipeIdAt(80, E); // 옮긴 관(새 자리) +const bookSize = () => JSON.parse(sessionStorage.getItem(`aislo:draft:pipe-ids:${E}`)).ids.length; +m.useStationOwners(E, [{ chainage_m: 80, owners: ["p15000"], role: "anchor" }], [{ id: "p15000" }]); +const staleSections = [ + { chainage_m: 80, kind: "irregular", structure: "파형강관 D800", culvert: {} }, + { chainage_m: 150, kind: "irregular", structure: "파형강관 D800", culvert: {} }, // 옛 자리 +]; +out.staleKeys = m.stationKeysOf(E, staleSections, 20).map((k) => k.key); +out.staleBook = bookSize(); +m.useStationOwners(E, []); // 관 계획 모름(초안 없음) = 옛 갈래 그대로 지음 +out.legacyKey = m.stationKeysOf(E, [staleSections[1]], 20)[0].key; +out.legacyBook = bookSize(); +m.prunePipeIds([80], E); // 지금 관 자리만 남김 +out.pruned = { size: bookSize(), at80: m.pipeIdAt(80, E), e1 }; +m.usePipeIds(P); + process.stdout.write(JSON.stringify(out)); diff --git a/resources/tester/test_411_b_pipe_id_pairing.py b/resources/tester/test_411_b_pipe_id_pairing.py index 2e0a47b5e..f469b95a2 100644 --- a/resources/tester/test_411_b_pipe_id_pairing.py +++ b/resources/tester/test_411_b_pipe_id_pairing.py @@ -113,3 +113,13 @@ def test_B06_열쇠는_서버_관_id_도_pipe(out): assert out["keys"] == ["structure:st-1", "pipe:p8017"] assert out["keys"][1] == out["pipelineKey"] # 계산 묶음 측점 열쇠와 같음 assert out["keysNoPipes"][1] == "structure:p8017" # 관 목록을 안 주면 옛 갈래(대조) + + +def test_411_E_옛_자리_관_측점은_헛_id_안_지음(out): + assert out["staleKeys"] == ["pipe:p15000", "at:150.00"] + assert out["staleBook"] == 1 # 세션 id 표에 헛 id 0 + assert out["legacyKey"] == "pipe:pipe-s2" and out["legacyBook"] == 2 # 초안 없음 = 옛 갈래 + + +def test_411_E_헛_id_정리(out): + assert out["pruned"] == {"size": 1, "at80": out["pruned"]["e1"], "e1": "pipe-s1"}