/* 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.startsWith("@")) // 「@at」 · 「@seat」 = 쓴 때 자리 칸(475-3) .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));