Files
Aislo/B05_Profile/B05_Profile_UI_RouteEdit_Draft.ts
T
eomsangdonandClaude Opus 5.5 aeca9616cc feat(계산묶음): 346-1 묶음을 B05 페이지 · 노선 편집에 붙임 — 노선 초안 캐시 칸 · 노선 고칠 때마다 종단 따라옴 · ▲▼ = grade · 단계 붙임
- design_pipeline_page.ts 새 — 프로젝트마다 묶음 하나(종단도 dispose 때 버림) · route · ground(sub8) · follow · planline · profile · stations · footprint(sub6) 붙임 · cross · masshaul · haul · drainage 는 붙으면 한 줄 · 첫 계산은 처음 고칠 때 · 가게 stations · profile · footprint · generation
- B05_Profile_UI_RouteEdit_Draft.ts 새 — 사진첩 감싸기(쌓기 · 되돌리기 · 다시하기 · 열 때로 = 초안 넘김 · 같으면 null) · 저장 안 한 초안 되살림 · RouteEdit.ts 는 줄 셋(700줄 안)
- logic/B05_Profile_Pipeline_Grade.ts 새 — follow(관 · 구조물 좌표 · 계획고 옮김) · planline(저장 기준 · 초안이면 바뀐 구간만 새 지반 첫 계획선) · profile(buildAlignment) · routeRange · gradeRange — sub1 짝 부르기만
- design_profile — listed 를 design_profile_base.ts 로 나눔 · rebuild = pipelineGrade · render · 구조물 측점 = 다시 셈 · adoptPipeline(초안 동안 편집은 메모리만 · [저장]이 안 보냄) · pipelineSource
- design_pipeline — input() · dispose()
- 시험 test_346_1_pipeline_page 12 건(실제 단계 · 노선 1,078 m 점 옮김 23 ms · 늦은 응답 버림 · 초안 캐시 칸 살아남음) · popout 시험 문맥에 pipelineGrade 자리

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TteK8mfYZetk5P3bEZkyVZ
2026-10-16 11:59:45 +09:00

83 lines
3.5 KiB
TypeScript

/* =============================================================================
* B05_Profile_UI_RouteEdit_Draft.ts
* 노선 편집기 ↔ 계산 묶음 다리(PLAN 346-1) — 노선을 한 번 고칠 때마다(놓기 · 더함 · 지움 · 곡선 ·
* 되돌리기 · 다시하기 · [반영 전으로] · 추천 [적용]) 노선 초안을 넘김. 끄는 동안은 넘기지 않음
* (사진첩에 쌓이는 때 = 손을 놓은 때).
*
* 편집기는 사진첩(`_History`)을 `watch` 로 감싸기만 함 — 고친 줄 하나. 저장 안 한 초안은
* 다리가 캐시 칸(`route-draft`)에 두고, 편집기가 자료를 읽은 뒤 `restore` 로 한 번 되살림
* (새로고침 · 보기 전환에도 남음). 계산 · 가게는 `A00_Common/design/design_pipeline_page.ts` 몫.
* ========================================================================== */
import type { RouteDraft } from "../A00_Common/design/design_pipeline_types";
import type { RouteEditHistory, RouteEditSnapshot } from "./B05_Profile_UI_RouteEdit_History";
/** 편집기가 넘기는 노선 — 판 번호 · 지형은 다리가 붙임. */
export type RouteDraftEdit = Omit<RouteDraft, "rev" | "terrain">;
export interface RouteDraftBridge {
/** 노선이 바뀜 — 열 때(저장분)와 같으면 null. */
edited(draft: RouteDraftEdit | null): void;
/** 저장 안 한 초안(캐시 칸) — 없으면 null. */
saved(): RouteDraft | null;
}
/** 사진 → 노선 초안(고정 · 고른 점은 노선이 아님). */
export function draftOfSnapshot(snapshot: RouteEditSnapshot, stationSnap: boolean): RouteDraftEdit {
return {
nodes: snapshot.planned.map(([x, y]): [number, number] => [x, y]),
curveOn: [...snapshot.curveOn],
curveRadius: [...snapshot.curveRadius],
curveLock: [...snapshot.curveLock],
curveArc: [...snapshot.curveArc],
stationSnap,
};
}
/** 노선 초안 → 사진 — 고정은 편집기가 좌표로 다시 짚음(`restoreSnapshot` 새 걸음). */
export function snapshotOfDraft(draft: RouteDraft): RouteEditSnapshot {
return {
planned: draft.nodes.map(([x, y]): [number, number] => [x, y]),
curveOn: [...draft.curveOn],
curveRadius: [...draft.curveRadius],
curveLock: [...draft.curveLock],
curveArc: [...draft.curveArc],
apexLock: draft.nodes.map(() => false),
picked: -1,
};
}
/** 사진첩을 감싸 노선이 바뀔 때마다 다리에 알림 — 쌓기 · 되돌리기 · 다시하기 · 열 때로. */
export function watch(
history: RouteEditHistory,
bridge: RouteDraftBridge | undefined,
stationSnap: () => boolean,
): RouteEditHistory {
if (!bridge) return history;
const tell = (snapshot: RouteEditSnapshot | null): RouteEditSnapshot | null => {
if (snapshot)
bridge.edited(history.isDirty() ? draftOfSnapshot(snapshot, stationSnap()) : null);
return snapshot;
};
return {
...history,
commit: (snapshot) => {
history.commit(snapshot);
tell(snapshot);
},
undo: () => tell(history.undo()),
redo: () => tell(history.redo()),
reset: () => tell(history.reset()),
};
}
/** 저장 안 한 초안을 편집기에 한 번 되살림 — 사진첩에 새 걸음으로(되돌리면 저장분). */
export function restore(
bridge: RouteDraftBridge | undefined,
apply: (snapshot: RouteEditSnapshot, message: string, record: boolean) => void,
): void {
const kept = bridge?.saved();
if (kept?.nodes.length)
apply(snapshotOfDraft(kept), "저장 안 한 노선 초안을 되살렸습니다.", true);
}