Merge remote-tracking branch 'origin/sub_laptop_3' into main_laptop_1

This commit is contained in:
2026-10-30 14:36:03 +09:00
2 changed files with 31 additions and 14 deletions
+22 -10
View File
@@ -79,12 +79,13 @@ const SITE_RADIUS_M = 1000;
/** 되돌리기 쌓는 수. */
const UNDO_MAX = 100;
/** 캐시 꼴 판 — 옛 꼴(지점 없음 · 갈래 고름)은 안 읽음. */
const DRAFT_VERSION = 3;
const DRAFT_VERSION = 4;
/** 한 걸음 = 지점 + 노선(되돌리기 · 캐시 · 고침 판정). */
/** 한 걸음 = 지점(+ 이름 · 차례 같음 · 빈 값 = 「지점 N」) + 노선(되돌리기 · 캐시 · 고침 판정). */
interface Snap {
network: PlanNetwork;
points: Vertex[];
pointNames: string[];
}
interface Draft extends Snap {
@@ -99,15 +100,17 @@ export async function renderD03PlanAnalysis(root: HTMLElement): Promise<void> {
const projectId = currentProjectId();
let editable = false;
let points: Vertex[] = []; // 지점(긋기에 붙는 점 · 591-2)
let pointNames: string[] = []; // 지점 이름(596 · 597-2)
let epsg = 0;
let yearStart = new Date().getFullYear(); // 새 선 처음 해
let network: PlanNetwork = emptyNetwork();
let savedJson = JSON.stringify({ network, points }); // 못 읽은 채 떠남 = 고침 없음
let savedJson = JSON.stringify({ network, points, pointNames }); // 못 읽은 채 떠남 = 고침 없음
let undoStack: Snap[] = [];
let redoStack: Snap[] = [];
let surface: PlanSurface | null = null;
let have: [number, number, number, number] | null = null;
let viewCore: Vertex[] = []; // 지도 보기 가운데 상자 두 귀(넓으면 빈 것)
let viewMid: Vertex | null = null; // 지도 보기 가운데(지점 [추가] 자리)
let viewTimer = 0;
let lastTried = ""; // 같은 받기를 거듭하지 않음
let ready = false; // 들어올 때 받기 판단이 끝남(그 앞 보기 바뀜은 안 받음)
@@ -150,9 +153,12 @@ export async function renderD03PlanAnalysis(root: HTMLElement): Promise<void> {
const marks = createPlanPoints({
points: () => points,
network: () => network,
names: () => pointNames,
epsg: () => epsg,
draw,
commit: (nextPoints, next) => step({ network: next, points: nextPoints }),
commit: (nextPoints, nextNames, next) =>
step({ network: next, points: nextPoints, pointNames: nextNames }),
center: () => viewMid,
show: (nextPoints, next) => {
[points, network] = [nextPoints, next];
map.redraw();
@@ -172,6 +178,7 @@ export async function renderD03PlanAnalysis(root: HTMLElement): Promise<void> {
].map(([x, y]) => screen.toMetric(...screen.unrotate(x, y)));
const xs = corners.map((c) => c[0]);
const ys = corners.map((c) => c[1]);
viewMid = w ? screen.toMetric(...screen.unrotate(w / 2, h / 2)) : null;
const box: Vertex[] = [
[Math.min(...xs), Math.min(...ys)],
[Math.max(...xs), Math.max(...ys)],
@@ -246,7 +253,7 @@ export async function renderD03PlanAnalysis(root: HTMLElement): Promise<void> {
root.querySelector(".ui-workflow-layout")?.classList.add("d03-plan-layout");
const allVertices = (): Vertex[] => network.lines.flatMap((line) => line.vertices);
const snap = (): Snap => ({ network, points });
const snap = (): Snap => ({ network, points, pointNames });
const dirty = (): boolean => JSON.stringify(snap()) !== savedJson;
const keepDraft = (): void =>
dirty()
@@ -257,21 +264,25 @@ export async function renderD03PlanAnalysis(root: HTMLElement): Promise<void> {
function step(next: Snap): void {
undoStack = [...undoStack.slice(1 - UNDO_MAX), snap()];
redoStack = [];
[network, points] = [normalizePieces(next.network, yearStart), next.points];
[network, points, pointNames] = [
normalizePieces(next.network, yearStart),
next.points,
next.pointNames,
];
keepDraft();
refresh();
void ensureCovered();
}
function commit(next: PlanNetwork): void {
step({ network: next, points });
step({ network: next, points, pointNames });
}
function undo(): void {
const last = undoStack.pop();
if (!last) return;
redoStack.push(snap());
({ network, points } = last);
({ network, points, pointNames } = last);
keepDraft();
refresh();
}
@@ -280,7 +291,7 @@ export async function renderD03PlanAnalysis(root: HTMLElement): Promise<void> {
const next = redoStack.pop();
if (!next) return;
undoStack.push(snap());
({ network, points } = next);
({ network, points, pointNames } = next);
keepDraft();
refresh();
}
@@ -422,6 +433,7 @@ export async function renderD03PlanAnalysis(root: HTMLElement): Promise<void> {
? fromServer(server.lines, server.marks, server.pieces, yearStart)
: emptyNetwork();
points = view.base.points.map((p): Vertex => [p.x, p.y]);
pointNames = view.base.points.map(() => ""); // 594-1 이름 칸이 들어오면 `p.name ?? ""`
if (view.base.epsg) epsg = view.base.epsg;
savedJson = JSON.stringify(snap());
}
@@ -553,7 +565,7 @@ export async function renderD03PlanAnalysis(root: HTMLElement): Promise<void> {
takeServer(view);
const draft = readState<Draft>("d03-plan", projectId);
if (draft?.version === DRAFT_VERSION && draft.network && Array.isArray(draft.points))
({ network, points } = draft);
({ network, points, pointNames } = draft);
const tm = tmParams(epsg);
const siteXy = site && tm ? lonLatToTm(tm, site.lon, site.lat) : null;
const around: Vertex[] = siteXy
@@ -27,11 +27,15 @@ const PIN_HEAD_PX = 18;
export interface PlanPointsParams {
points: () => Vertex[];
/** 지점 이름(차례 = `points` · 빈 값 = 「지점 N」). */
names: () => string[];
network: () => PlanNetwork;
epsg: () => number;
draw: PlanDraw;
/** 한 걸음 — 지점 · 노선 함께. */
commit: (points: Vertex[], network: PlanNetwork) => void;
/** 한 걸음 — 지점 · 이름 · 노선 함께. */
commit: (points: Vertex[], names: string[], network: PlanNetwork) => void;
/** 지도 보기 가운데(작업 좌표 · 못 잼 = null) — [추가] 자리. */
center: () => Vertex | null;
/** 끌기 중 — 화면만. */
show: (points: Vertex[], network: PlanNetwork) => void;
/** 쉴 때(긋기 · 재기 아님)만 핀을 끎. */
@@ -86,6 +90,7 @@ export function createPlanPoints(params: PlanPointsParams): PlanPoints {
function remove(i: number): void {
params.commit(
params.points().filter((_, k) => k !== i),
params.names().filter((_, k) => k !== i),
params.network(),
);
}
@@ -100,7 +105,7 @@ export function createPlanPoints(params: PlanPointsParams): PlanPoints {
.filter((item) => item.gap <= SNAP_PX)
.sort((a, b) => a.gap - b.gap)[0];
const at = node?.point ?? map.toMetric(px, py);
params.commit([...params.points(), [at[0], at[1]]], params.network());
params.commit([...params.points(), [at[0], at[1]]], [...params.names(), ""], params.network());
}
function openMenu(px: number, py: number, map: ScreenMap): boolean {
@@ -154,7 +159,7 @@ export function createPlanPoints(params: PlanPointsParams): PlanPoints {
drag = null;
if (!done?.last) return;
params.show(done.points, done.network);
params.commit(...done.last);
params.commit(done.last[0], params.names(), done.last[1]);
},
};