Files
Aislo/A00_Common/design/logic/design_planted_base.ts
T

109 lines
5.6 KiB
TypeScript

/* =============================================================================
* A00_Common/design/logic/design_planted_base.ts
* 묶음 planline 의 저장 노선 종단 기준(PLAN 386-3) 셈 몫 — 화면 · 가게 · 세션 없는 순수(511-B B-3 · 서버 Node
* 묶음 `design_calc_node_stages.ts` 도 같은 셈). 페이지 겉 = `design_pipeline_base.ts`(관 id = 세션 장부) ·
* `design_profile_base.ts` · `design_structure_status.ts` 가 다시 내보냄.
*
* 종단도 `listed()`(design_profile)와 같은 셈 — 저장 상세 측점 + 구조물 · 관이 심는 측점(`listedBase`).
* 심는 측점 = 종단 보기 구조물 칸(`syncCrossDrainStations`) · 횡단 보기(`planMarkStations`)와 같은
* `planStations` → `plannedIrregular` — 보기가 종단도에 늦게 심어도 묶음은 다시 안 돎.
* ========================================================================== */
import type { SectionDetailResponse } from "../../../B06_Section/B06_Section_Api_Fetch";
import type { AlignmentBase } from "../../../B05_Profile/logic/B05_Profile_UI_Profile_Alignment";
import { toAlignmentBase } from "../../../B05_Profile/logic/B05_Profile_UI_Profile_Alignment";
import type { IrregularStation } from "../../../B05_Profile/B05_Profile_UI_IrregularStations";
import {
irregularGraphStations,
maxChainageOf,
} from "../../../B05_Profile/logic/B05_Profile_Profile_Planted";
import {
followMovedNodes,
oneStationList,
planStations,
type PlannedStation,
type PlanType,
} from "../../../common_util/common_util_structure_station";
import { readAlignment } from "../../../B05_Profile/logic/B05_Profile_UI_Profile_Data";
import { seatBornNodes } from "../../../B05_Profile/logic/B05_Profile_Grade_Seat";
import type { PipelineInputs } from "./design_pipeline_types";
/**
* 측점 계획 → 종단 측점(측점번호 · 잔여거리 = 간격 기준) — 기준 측점 id = 첫 주인 id(관 = `pipe-…` ·
* 구조물 = structure_id) · 시작 · 끝 = `{id}:{역할}`(옮겨도 계획고 편집이 따라감 · 272) · 관 기준 측점 =
* 「배관」 꼴(관 끌기 · 지우기 길).
*/
export function plannedIrregular(
planned: ReadonlyArray<PlannedStation>,
intervalM: number,
): IrregularStation[] {
const interval = intervalM > 0 ? intervalM : 20;
return planned.map((station) => {
const owner = station.owners[0];
const pipe = owner.startsWith("pipe-") && station.role === "anchor";
const number = Math.floor(station.chainage_m / interval);
return {
id: station.role === "anchor" ? owner : `${owner}:${station.role}`,
station: number,
remainder: station.chainage_m - number * interval,
chainage_m: station.chainage_m,
structure: station.title,
...(pipe ? { structureType: "배관" as const, origin: "pipe" as const } : {}),
};
});
}
/** 계획선 측점 줄 = 측점 한 벌(서버 일반 + 지금 구조물 측점 · 272) — 표 · ▲▼ · 그래프 · 3D · 횡단 다시 셈(342-1)이
* 같은 목록 · 사라진 구조물 측점의 꼭짓점은 서버와 같게 옮기거나 지우고 새 측점엔 세움(`followMovedNodes` · `seatBornNodes` · 427) ·
* 늘 저장분에서 셈. 심은 측점이 아직 없으면(null · 시설 줄 입력 전) 저장분 그대로(473). */
export function listedBase(
storedBase: AlignmentBase | null,
detail: SectionDetailResponse | null,
irregularStations: IrregularStation[] | null,
): AlignmentBase | null {
if (!storedBase || !detail || !irregularStations) return storedBase;
const server = detail.longitudinal.stations;
const planted = irregularGraphStations(irregularStations, maxChainageOf(detail.longitudinal));
const list = oneStationList(server, planted);
const after = new Set(list.map((station) => station.chainage_m.toFixed(3)));
const before = new Set(server.map((station) => station.chainage_m.toFixed(3)));
const gone = server
.filter((station) => station.kind === "irregular" && !station.grid)
.map((station) => station.chainage_m)
.filter((chainage) => !after.has(chainage.toFixed(3)));
const born = list
.map((station) => station.chainage_m)
.filter((chainage) => !before.has(chainage.toFixed(3)));
const moved = followMovedNodes(
storedBase.basePvi,
gone,
born,
Object.keys(readAlignment(detail.longitudinal)?.edits.station_offsets ?? {}),
);
return {
...storedBase,
basePvi: seatBornNodes(storedBase, moved.nodes, moved.seat, moved.held),
stations: list.map((station) => ({
station_id: station.station_id,
chainage_m: station.chainage_m,
})),
};
}
/** 저장 상세(종단도가 그리는 것) + 지금 입력이 심는 측점 = 저장 노선 종단 기준. 상세가 없으면 종단도 기준.
* `ids` = 관에 관 id 붙임(페이지 = 세션 장부 · 서버 Node = 장부 사본 · 511-B). */
export function plantedBase(
source: { base: AlignmentBase | null; detail?: SectionDetailResponse | null },
inputs: Pick<PipelineInputs, "pipes" | "structures">,
types: ReadonlyArray<PlanType>,
ids: (pipes: Array<{ chainage_m: number }>) => Array<{ chainage_m: number; id: string }>,
): AlignmentBase | null {
const detail = source.detail ?? null;
const stored = detail && readAlignment(detail.longitudinal);
if (!detail || !stored) return source.base;
const pipes = ids((inputs.pipes ?? []) as Array<{ chainage_m: number }>);
const structures = (inputs.structures ?? []) as Parameters<typeof planStations>[1];
const planted = plannedIrregular(planStations(pipes, structures, types), 20); // 간격 = 이름 몫 · 기준 무관
return listedBase(toAlignmentBase(stored), detail, planted);
}