Files
Aislo/D03_PlanAnalysis/logic/D03_PlanAnalysis_PointEdit.ts
T

77 lines
3.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* =============================================================================
* D03_PlanAnalysis_PointEdit.ts
* D03 지점 칸 손 고침 계산(PLAN 597-2 · 요구 463 7 · 8) — 화면 · fetch 없음(logic/).
* 이름 = 20 자 안 · 파일 이름에 못 쓰는 글자(`/ \ : * ? " < > |`) 막음 · 빈 값 = 「지점 N」 보임.
* 좌표 = 경위도 손 고침 → 작업 좌표(TM) · 그 자리 노선 노드도 같이(`moveNodesAt`).
* ⚠ 이름 한도 · 글자 = `Plan.ts` 의 `NAME_MAX` · `nameError`(594-1)와 같은 규칙 — 그쪽이 들어오면 거기서 가져옴.
* ========================================================================== */
import { moveNodesAt, type PlanNetwork, type Vertex } from "./D03_PlanAnalysis_Plan";
import { lonLatToTm, type TmParams } from "./D03_PlanAnalysis_Tm";
/** 지점 상한 — 서버 `MAX_POINTS` 와 같음. */
export const MAX_POINTS = 40;
export const POINT_NAME_MAX = 20;
const BAD_CHARS = /[\\/:*?"<>|]/;
/** 이름 까닭 글 — 쓸 수 있으면 null. */
export function pointNameError(name: string): string | null {
if (name.length > POINT_NAME_MAX) return `이름은 ${POINT_NAME_MAX} 자까지`;
if (BAD_CHARS.test(name)) return '이름에 / \\ : * ? " < > | 는 못 씁니다';
return null;
}
/** 보이는 이름 — 빈 값 = 「지점 N」. */
export function pointLabel(names: string[], index: number): string {
return names[index]?.trim() || `지점 ${index + 1}`;
}
/** 경위도 글 → 값 · 못 읽거나 범위 밖이면 까닭 글. */
export function parseLonLat(lonText: string, latText: string): [number, number] | string {
const lon = Number(lonText.trim());
const lat = Number(latText.trim());
if (!lonText.trim() || !Number.isFinite(lon) || Math.abs(lon) > 180) return "경도는 −180 ~ 180";
if (!latText.trim() || !Number.isFinite(lat) || Math.abs(lat) > 90) return "위도는 −90 ~ 90";
return [lon, lat];
}
export interface PointsState {
points: Vertex[];
names: string[];
network: PlanNetwork;
}
/** 지점 더함 — 이름 비움. 상한이면 그대로. */
export function addPoint(state: PointsState, at: Vertex): PointsState {
if (state.points.length >= MAX_POINTS) return state;
return {
...state,
points: [...state.points, [at[0], at[1]]],
names: [...state.names, ""],
};
}
/** 이름 바꿈 — 빈 값 허용. */
export function renamePoint(state: PointsState, index: number, name: string): PointsState {
const names = state.points.map((_, k) => state.names[k] ?? "");
names[index] = name.trim();
return { ...state, names };
}
/** 경위도로 옮김 — 그 자리 노선 노드도 같이. */
export function movePointTo(
state: PointsState,
index: number,
tm: TmParams,
lon: number,
lat: number,
): PointsState {
const to = lonLatToTm(tm, lon, lat);
const from = state.points[index];
return {
...state,
points: state.points.map((p, k): Vertex => (k === index ? to : p)),
network: moveNodesAt(state.network, from, to),
};
}