- 암 경계 · 암 절토 경사 저장소(`B06_Section_UI_Page_Persist`) = 세션 칸이 주인 — 읽을 때마다 측점 열쇠 칸(`readCells`) · 고칠 때 지금 칸을 읽어 그 측점만 바꿔 씀(`putCell`) · 메모리 맵 · load · 갈아끼움 다시 읽기(keyedStores · reloadKeyedStores) 걷음 · ↶ 뒤 다음 조작이 되돌림을 덮던 흠(N5) 고침 - 저장 재료 = `offsets()` · `ratios()`(새 Map) · ↶ ↷ 가 rockb · cutslope 칸을 바꾸면 조정창과 같은 onRestore 로 카드 · 면적 다시 - B05 상단측 메모리 맵(uphillOverrides · load/saveUphillOverrides) 걷음 — 읽는 곳 없이 저장 뒤 비우기만 하던 사본 · 값 주인 = 세션 칸 `uphill` · 상단측 차례 = 기본 조각 그대로 - 노선 바뀐 [저장] 성공 뒤(페이지 다시 세운 뒤) 옛 노선 번호의 노선 범위 초안(`clearRouteDrafts`) · `route-draft-hold` 비움 · 넘김 규칙 그대로 · 같은 번호면 노선 칸 안 지움 · 실패면 그대로 - 시험 test_472_5r_rock_owner 7(옛 코드 빨강 5) · 옛 단언 고침(176_3 · 271 · 443 상단측 조각 · 344_3 저장소 load) - 위키 암선 · 암 경사 · ↶ ↷ 규칙 · 노선 저장 뒤 정리 줄 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
122 lines
4.5 KiB
JavaScript
122 lines
4.5 KiB
JavaScript
/* 472-5 남음 헬퍼 — node helper_472_5r_rock.mjs <묶음.mjs> · 표준출력 JSON.
|
||
* ① 암 경계(▲▼ · 되돌림) · 암 절토 경사를 고침 → ↶ → 다른 측점을 고침 → ↶ ↷ — 세션 칸 · 카드 읽기 · 저장 재료가
|
||
* 되돌린 값을 따르는가(옛 코드 = 메모리 맵이 옛 값을 쥐고 다음 조작이 칸을 통째로 다시 씀 · N5).
|
||
* ② clearRouteDrafts — 그 노선 번호의 노선 범위 초안만 비움(다른 노선 · 프로젝트 칸 그대로). */
|
||
import { pathToFileURL } from "node:url";
|
||
|
||
const storage = () => {
|
||
const m = new Map();
|
||
return {
|
||
getItem: (k) => (m.has(k) ? m.get(k) : null),
|
||
setItem: (k, v) => m.set(k, String(v)),
|
||
removeItem: (k) => m.delete(k),
|
||
key: (i) => [...m.keys()][i] ?? null,
|
||
get length() {
|
||
return m.size;
|
||
},
|
||
clear: () => m.clear(),
|
||
};
|
||
};
|
||
const any = new Proxy(function () {}, {
|
||
get: (_t, k) => (k === Symbol.toPrimitive ? () => 0 : any),
|
||
apply: () => any,
|
||
construct: () => any,
|
||
});
|
||
globalThis.window = { sessionStorage: storage(), localStorage: storage() }; // 손길 듣기 없음 = 열 때 규칙 꺼짐
|
||
globalThis.sessionStorage = window.sessionStorage;
|
||
globalThis.localStorage = window.localStorage;
|
||
globalThis.document = any;
|
||
|
||
const m = await import(pathToFileURL(process.argv[2]).href);
|
||
const P = "p4725rock";
|
||
const R = 7;
|
||
localStorage.setItem("frd_current_project_id", P);
|
||
const SAVED_ROCK = -0.8; // 저장분 암 경계(측점 100)
|
||
const sections = [100, 120, 140].map((chainage_m) => ({
|
||
chainage_m,
|
||
station_id: `s${chainage_m}`,
|
||
design: chainage_m === 100 ? { rock_boundary_offset_m: SAVED_ROCK } : {},
|
||
}));
|
||
const detail = { cross_sections: sections };
|
||
const refreshed = [];
|
||
const rock = m.createRockBoundaryStore({
|
||
sessionKey: () => m.stateKey("rockb", P, R),
|
||
detail: () => detail,
|
||
refreshCard: (at) => refreshed.push(at),
|
||
recompute: () => undefined,
|
||
});
|
||
rock.setDefaults(-0.5, 0.1);
|
||
const cut = m.createCutSlopeStore({
|
||
sessionKey: () => m.stateKey("cutslope", P, R),
|
||
standard: () => ({ rock: { cut_slope_ratio: 0.4 }, soil: { cut_slope_ratio: 1.0 } }),
|
||
refreshCard: () => undefined,
|
||
recompute: () => undefined,
|
||
});
|
||
const cell = (name) => {
|
||
const raw = m.readState(name, P, R) ?? {};
|
||
// 측점 열쇠 칸 = 열쇠 → 값 · `@at`(쓴 때 누가거리) · `@seat` — 누가거리 → 값으로 풀어 봄
|
||
const at = raw["@at"] ?? {};
|
||
return Object.fromEntries(
|
||
Object.entries(raw)
|
||
.filter(([key]) => !key.startsWith("@"))
|
||
.map(([key, value]) => [Number(at[key] ?? key).toFixed(2), value]),
|
||
);
|
||
};
|
||
const cells = () => ({ rockb: cell("rockb"), cutslope: cell("cutslope") });
|
||
const reads = () =>
|
||
Object.fromEntries(
|
||
sections.map((s) => [
|
||
s.chainage_m,
|
||
{ rock: rock.control.offsetFor(s), cut: cut.control.ratioFor(s) },
|
||
]),
|
||
);
|
||
const out = {};
|
||
|
||
const history = m.createProfileHistory(() => undefined, 100);
|
||
// 조작 A — 100 ▼(저장분 −0.8 → −0.9) · 120 ▲(기본 −0.5 → −0.4) · 140 암 경사 0.7
|
||
rock.control.adjust(100, -0.1);
|
||
rock.control.adjust(120, 0.1);
|
||
cut.control.set(140, 0.7);
|
||
history.record();
|
||
out.afterA = cells();
|
||
out.readsA = reads();
|
||
|
||
history.undo(); // ↶ = 세션 칸을 조작 전으로 되씀(저장소를 안 거침)
|
||
out.afterUndo = cells();
|
||
out.readsUndo = reads();
|
||
|
||
// 조작 B — 다른 측점(옛 코드 = 메모리 맵이 A 값을 쥐고 통째로 다시 씀)
|
||
rock.control.adjust(140, -0.1);
|
||
cut.control.set(100, 0.5);
|
||
out.afterB = cells();
|
||
out.payloadB = {
|
||
rock: Object.fromEntries(typeof rock.offsets === "function" ? rock.offsets() : rock.offsets), // 옛 꼴 = Map
|
||
cut: Object.fromEntries(typeof cut.ratios === "function" ? cut.ratios() : cut.ratios),
|
||
};
|
||
history.record();
|
||
history.undo();
|
||
out.afterUndo2 = cells();
|
||
history.redo(); // ↷ = B 그대로
|
||
out.afterRedo = cells();
|
||
out.readsRedo = reads();
|
||
// 되돌림(↺) — 암 경계 = 기본값 · 암 경사 = 0(표준 표시)
|
||
rock.control.reset(140);
|
||
cut.control.set(100, null);
|
||
out.afterReset = cells();
|
||
out.readsReset = reads();
|
||
|
||
// ② 노선 저장 뒤 옛 노선 칸만 비움
|
||
m.writeState("rockb", { "grid:1": -0.7 }, P, 8);
|
||
m.writeState("crossw", { "100.00": 6 }, P, R);
|
||
m.writeState("uphill", { "100.000": "left" }, P);
|
||
m.writeState("rockb", { "grid:1": -0.6 }, "other", R);
|
||
const keys = () =>
|
||
Array.from({ length: sessionStorage.length }, (_, i) => sessionStorage.key(i))
|
||
.filter((key) => key.startsWith("aislo:draft:"))
|
||
.sort();
|
||
out.keysBefore = keys();
|
||
m.clearRouteDrafts(P, R);
|
||
out.keysAfter = keys();
|
||
|
||
process.stdout.write(JSON.stringify(out));
|