Files
Aislo/resources/tester/helper_417_route_carry.mjs
T
eomsangdonandClaude Opus 5.5 041a22b4b3 fix(B05·B06 한 페이지): 노선 바뀐 저장 때 옛 저장 관 자리 조절 = 같은 관 id 의 새 자리로 (417-1 M2)
- 노선 저장 직전 저장 관(id · 옛 누가거리)을 떠 두고 저장 뒤 같은 id 새 자리로 — 초안으로 안 따라간 관 조절(첫 초안 측점 짝 · 관 id 규칙 갈림)
- carryChainageStates 시설 풀이 = 옛 자리 → 새 자리 · 관 열쇠 → 새 자리
- 시험 test_417 옛 자리 짝 · 346-3 저장 차례(관 받기)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Se7ytqbohmBQnfYpwYFnYf
2026-10-18 13:04:33 +09:00

156 lines
5.5 KiB
JavaScript

/* 417 헬퍼 — vite ssr 로 묶은 진짜 모듈(helper_417_entry.ts)을 부르고 결과를 JSON 한 벌로.
* node helper_417_route_carry.mjs <묶음.mjs> <입력.json>
* 입력 = { standard: 파이썬 config 표준단면 }.
*/
import { readFileSync } from "node:fs";
import { pathToFileURL } from "node:url";
const store = () => {
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(),
};
};
globalThis.window = globalThis;
globalThis.sessionStorage = store();
globalThis.localStorage = store();
const any = new Proxy(function () {}, {
get: (_t, k) => (k === Symbol.toPrimitive ? () => 0 : any),
apply: () => any,
construct: () => any,
});
globalThis.document = any;
globalThis.requestAnimationFrame = (run) => setTimeout(run, 0);
const [bundlePath, inputPath] = process.argv.slice(2);
const m = await import(pathToFileURL(bundlePath).href);
const input = JSON.parse(readFileSync(inputPath, "utf8"));
const P = "p417";
const R = 7;
const R2 = 8;
const raw = (name, route) => m.readState(name, P, route) ?? {};
const keysOf = (name, route) =>
Object.keys(raw(name, route))
.filter((k) => k !== "@at")
.sort();
const section = (chainage_m, kind, extra = {}) => ({
station_id: `s${chainage_m}`,
chainage_m,
kind,
label: String(chainage_m),
samples: [],
design: {},
...extra,
});
const detailOf = (sections) => ({
longitudinal: {
stations: sections,
profile_alignment: { policy: { station_interval_m: 20 } },
},
cross_sections: sections,
});
const out = {};
/* 1. 옛 노선(관 45 m) — B06 조절 · 사면 쉬프트 · 소단 깊이 · 측점 폭 · 상세 표 · 연동을 세션에 */
m.writeState("pipe-ids", { next: 2, ids: [{ id: "pipe-s1", at: 45 }] }, P);
const pipe = { structure: "파형강관 D800", culvert: {} };
m.useStationKeys(
P,
R,
detailOf([
section(0, "bp"),
section(20, "regular"),
section(40, "regular"),
section(45, "irregular", pipe),
section(60, "ep"),
]),
);
m.writeShoulderExtend(P, R, 40, "left", 0.5);
m.writeBermDepth(P, R, 40, "right", 1.2);
const wall = { x: 0.3, d: null, h: 1.5, m: null };
m.writeState("revetx", { "45.00:outlet": wall, "40.00:inlet": wall }, P, R);
m.writeState("boxadjust", { "45.00": { left: { x: 0.2 } } }, P, R);
m.writeState("crossw", { "40.00": 6 }, P, R);
m.writeState("detail-table", { "45.00": { rows: 2 } }, P, R);
m.writeState("revetlink", { detached: { "45.00": true }, grade: {} }, P, R);
/* 2. 노선 바뀐 [저장] — 새 노선(관 47 m 로 따라감 · 끝 58 m) 측점 열쇠로 옮김 */
m.writeState("pipe-ids", { next: 2, ids: [{ id: "pipe-s1", at: 47 }] }, P);
const next = detailOf([
section(0, "bp"),
section(20, "regular", { design: { shoulder_extend_right_m: 0.7, berm_depth_left_m: 0.4 } }),
section(40, "regular"),
section(47, "irregular", pipe),
section(58, "ep"),
]);
m.useStationKeys(P, R2, next);
out.keyedOutside = m.carryStationDrafts(P, R, R2, { quiet: true });
out.chainageOutside = m.carryChainageStates(P, R, R2);
out.shoulderKeys = keysOf("shoulderext", R2);
out.bermKeys = keysOf("bermdepth", R2);
out.revet = raw("revetx", R2);
out.box = raw("boxadjust", R2);
out.width = raw("crossw", R2);
out.table = raw("detail-table", R2);
out.link = raw("revetlink", R2);
/* 3. 새 상세 설계 칸에 얹음 — 같은 [저장]의 횡단 패치가 실을 값 */
m.withDraftAdjusts(next, P, R2);
m.withCarriedEdits(next, P, R2);
const at = (c) => next.cross_sections.find((s) => s.chainage_m === c).design;
out.design40 = at(40);
out.design47 = at(47);
/* 4. 평면 초안 횡단 입력 — 세션 사면 쉬프트 · 소단 깊이 + 저장분(세션 없음)도 */
m.writeState("std-cross", input.standard, P);
const stations = next.cross_sections.map((s, i) => ({
key: ["end:BP", "grid:1", "grid:2", "pipe:pipe-s1", "end:EP"][i],
chainageM: s.chainage_m,
kind: i === 3 ? "pipe" : "grid",
}));
const source = m.pipelineCrossSource(P, next, stations, R2);
const pick = (entry) =>
Object.fromEntries(
Object.entries(entry ?? {}).filter(([k]) => /^(shoulderExtend|bermDepth)/.test(k)),
);
out.input40 = pick(source?.input.byKey["grid:2"]);
out.input20 = pick(source?.input.byKey["grid:1"]);
/* 5. 관 id 규칙이 갈림(옛 목록 세션 id · 새 목록 저장 관 id) — 시설 자리 풀이로 옮김 · 없으면 버림 */
const R3 = 9;
const R4 = 10;
const list = [
{ key: "end:BP", chainageM: 0 },
{ key: "grid:1", chainageM: 20 },
{ key: "grid:2", chainageM: 40 },
{ key: "pipe:p9", chainageM: 52 },
{ key: "end:EP", chainageM: 60 },
];
m.useStationKeyList(P, R3, list);
m.useStationKeyList(P, R4, list);
m.writeState("pipe-ids", { next: 2, ids: [{ id: "pipe-s1", at: 45 }] }, P);
m.useStationKeys(
P,
R,
detailOf([section(0, "bp"), section(45, "irregular", pipe), section(60, "ep")]),
);
m.writeState("revetx", { "45.00:outlet": wall }, P, R);
m.carryChainageStates(P, R, R3, { keyAt: (key) => (key === "pipe:pipe-s1" ? 52 : null) });
m.carryChainageStates(P, R, R4);
out.splitResolved = raw("revetx", R3);
out.splitDropped = raw("revetx", R4);
// 옛 저장 시설 측점(초안으로 안 따라간 고침) — 좌표 짝으로 새 시설 측점에
const R5 = 11;
m.useStationKeyList(P, R5, list);
m.carryChainageStates(P, R, R5, { movedAt: (c) => (c === 45 ? 52 : null) });
out.movedByPlace = raw("revetx", R5);
process.stdout.write(JSON.stringify(out));