/* 467 헬퍼 — 소단 원천 한 벌: 구조물 → 소단 구간(TS) · 저장분 소단 제원(TS) · 시설 줄이 세션 사본을 씀 · * 다시 셈 = 사본 없으면 저장분 `design.berm`. * node helper_272_berm_source.mjs <묶음.mjs> * job = { standard, rockDefault, structureCases, storedCases, ground } · 짝 = `test_272_berm_source.py`. */ import { readFileSync } from "node:fs"; import { pathToFileURL } from "node:url"; const writes = []; const memory = () => { const m = new Map(); return { getItem: (k) => (m.has(k) ? m.get(k) : null), setItem: (k, v) => { writes.push(k); 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 = memory(); globalThis.localStorage = memory(); 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); globalThis.fetch = async () => new Response("{}", { status: 404 }); const m = await import(pathToFileURL(process.argv[2]).href); const job = JSON.parse(readFileSync(process.argv[3], "utf8")); const P = "p272berm"; const R = 5; const out = {}; /* 1. 거울 — 구조물 → 소단 구간 · 저장분 제원 */ out.spans = job.structureCases.map((list) => m.bermSpansFromStructures(list)); out.stored = job.storedCases.map((spec) => m.storedBermSpec(spec)); /* 2. 시설 줄이 사본을 씀 — 구조물 받기 전 안 씀 · 같으면 안 씀 · 바뀌면 한 번 */ { m.setPageRouteId(P, R); const key = m.stateKey("berm", P, R); const count = () => writes.filter((k) => k === key).length; const copy = () => m.readState("berm", P, R); const lane = m.createFacilityLane(P, () => null); const steps = {}; lane.setTypes([]); lane.follow(); // 저장분 · 가게 구조물 없음 = 아직 모름 steps.beforeKnown = { copy: copy(), writes: count() }; const saved = job.structureCases[0]; lane.setStored(saved); lane.set({ structures: saved }, false); steps.loaded = { copy: copy(), writes: count() }; lane.set({ structures: saved.map((item) => ({ ...item })) }); lane.set({ pipes: [] }); steps.same = { writes: count() }; const moved = saved.map((item) => item.type_id === "berm" ? { ...item, start_m: item.start_m + 5, end_m: item.end_m + 5 } : item, ); lane.set({ structures: moved }); steps.moved = { copy: copy(), writes: count() }; lane.set({ structures: [] }); steps.removed = { copy: copy(), writes: count() }; lane.dispose(); out.lane = steps; } /* 2-2. 시설 줄 칠함 — 종류 표 받기 전 측점(빈 목록)을 종단도에 안 씀 · 받은 뒤 한 번 */ { const P2 = "p272paint"; const wrote = []; const fake = { setStructureTypes: () => undefined, setStructures: () => undefined, setIrregularStations: (list) => wrote.push(list.length), setMinCoverPipes: () => undefined, resetStationEdit: () => undefined, }; const lane = m.createFacilityLane(P2, () => fake); lane.set({ pipes: [] }); lane.set({ structures: [] }, false); lane.paint(); const before = wrote.length; lane.setTypes([{ type_id: "berm", name: "소단", placement: "interval" }]); out.paint = { before, after: wrote.length }; lane.dispose(); } /* 3. 다시 셈 소단 원천 — 사본 없음(저장분 design.berm) · 사본 = 같은 구간 · 사본 = 빈 목록 */ { m.writeState("std-cross", job.standard, P); m.rememberRockBoundaryDefault(P, job.rockDefault); const detailOf = () => ({ longitudinal: { length_m: 200, stations: [], profile_alignment: { policy: {} } }, cross_sections: [ { station_id: "station_000000040000", chainage_m: 40, label: "", kind: "regular", center_z: 96, azimuth_deg: 90, center_x: 40, center_y: 0, frame: { left_xy: [0, 1] }, uphill_side: "left", samples: job.ground, design: { design_elevation_m: 100, ground_type: "soil", section_mode: "both_fill", ditch_type: "standard", berm: job.storedBerm, }, }, ], }); const alignment = { stations: [{ chainage_m: 40, plan_elevation_m: 100 }], samples: [ { chainage_m: 0, elevation_m: 100 }, { chainage_m: 100000, elevation_m: 100 }, ], balance: { cut_area_m2: 0, fill_area_m2: 0, net_area_m2: 0 }, }; const run = async (copy) => { if (copy === undefined) sessionStorage.removeItem(m.stateKey("berm", P, R)); else m.writeState("berm", copy, P, R); const detail = detailOf(); await m.refreshCrossDesigns({ projectId: P, routeId: R, detail, edits: { station_offsets: {}, curve_radii: {} }, alignment, }); const design = detail.cross_sections[0].design; return { fill: design.fill_area_m2 ?? null, cut: design.cut_area_m2 ?? null }; }; out.refresh = { noCopy: await run(undefined), copySame: await run(m.bermSpansFromStructures(job.structureCases[0])), copyEmpty: await run([]), }; } process.stdout.write(JSON.stringify(out));