- 옮김: B04 2 · B05 23 · B06 11 · A00_Common/design 13 (9,299 줄) · 이미 logic/ 에 있던 16 파일 그대로 - 안 옮김: 묶음 입구(package.json build:*) · 파이썬 · 순수지만 계산 아닌 8 (보기 결선 · 콜백 · API 타입 · 갈아끼움 알림판) - import 266 줄(142 파일) · 시험 · 주석 · 짝 표시 문자열 경로 고침 · B05 · B06 CLAUDE.md 짝 줄 logic/ - 시험 도우미 새 경로: 가짜 require 열쇠 · B05()/B06() 부름 · 형제 import 자리 · tsc 묶어 돌리는 시험 · 정규식 · rglob - design_view_cross 줄 한도 시험 685 → 688 (긴 import 경로 줄바꿈 3줄) - 확인: typecheck 0 · 서버 묶음 넷(corridor · server-calc · b07-extent · b07-note) 다시 지어 코드 같음(//#region 경로 주석만 다름) · 관련 시험 270 파일 — 남은 실패 19 는 옮기기 전과 같음 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014utrjfoW831Vc5wJUd13kL
95 lines
4.0 KiB
JavaScript
95 lines
4.0 KiB
JavaScript
/* PLAN 323-9 ④-② — 같은 시설을 그리는 카드 둘(같은 m · 노선 끝 EP 꼴 소수 차 0.01 m)이면 3D 관 · 세월교 · BOX 몸체는 한 번.
|
|
* 화면 TS(`buildCorridorStructures`)를 그 자리에서 트랜스파일해 Node 로 돌림(로더 = helper_135_3 과 같음).
|
|
* 입력 = 73-4 픽스처(세월교 173.087 · BOX 352.14) · 결과 = 표준출력 JSON. 짝 = test_323_9_twin_cards_3d.py.
|
|
*/
|
|
const fs = require("fs");
|
|
const path = require("path");
|
|
const ROOT = path.join(__dirname, "..", "..");
|
|
const ts = require(path.join(ROOT, "config", "node_modules", "typescript"));
|
|
|
|
const cache = new Map();
|
|
const STUBS = {
|
|
"@ui/ui_template_toast": { showToast: () => undefined },
|
|
three: require(path.join(ROOT, "config", "node_modules", "three")),
|
|
};
|
|
const resolve = (base) =>
|
|
[base, `${base}.ts`, path.join(base, "index.ts")].find(
|
|
(p) => fs.existsSync(p) && fs.statSync(p).isFile(),
|
|
) ?? `${base}.ts`;
|
|
function loadTs(file) {
|
|
const full = path.resolve(file);
|
|
if (cache.has(full)) return cache.get(full);
|
|
if (full.endsWith(".json")) {
|
|
const data = JSON.parse(fs.readFileSync(full, "utf8"));
|
|
cache.set(full, data);
|
|
return data;
|
|
}
|
|
const js = ts.transpileModule(fs.readFileSync(full, "utf8"), {
|
|
compilerOptions: {
|
|
module: ts.ModuleKind.CommonJS,
|
|
target: ts.ScriptTarget.ES2020,
|
|
esModuleInterop: true,
|
|
},
|
|
}).outputText;
|
|
const box = { exports: {} };
|
|
cache.set(full, box.exports);
|
|
const localRequire = (request) => {
|
|
if (STUBS[request]) return STUBS[request];
|
|
const alias = { "@util/": "common_util", "@ui/": "ui_template", "@config/": "config" };
|
|
for (const [prefix, dir] of Object.entries(alias))
|
|
if (request.startsWith(prefix))
|
|
return loadTs(resolve(path.join(ROOT, dir, request.slice(prefix.length))));
|
|
return loadTs(resolve(path.join(path.dirname(full), request)));
|
|
};
|
|
new Function("exports", "module", "require", js)(box.exports, box, localRequire);
|
|
return box.exports;
|
|
}
|
|
|
|
const { buildCorridorStructures } = loadTs(
|
|
path.join(ROOT, "B05_Profile", "B05_Profile_UI_Corridor_Structures.ts"),
|
|
);
|
|
const fixture = JSON.parse(
|
|
fs.readFileSync(path.join(__dirname, "fixtures", "b06_73_4_body_guard_sections.json"), "utf8"),
|
|
);
|
|
const clone = (v) => JSON.parse(JSON.stringify(v));
|
|
const at = (c) => clone(fixture.cross_sections.find((s) => Math.abs(s.chainage_m - c) < 0.6));
|
|
/** 직선 노선 — 가장 가까운 측점 프레임에서 앞쪽으로 편다. */
|
|
const frameAtOf = (sections) => (atM) => {
|
|
const s = sections.reduce((b, x) =>
|
|
Math.abs(x.chainage_m - atM) < Math.abs(b.chainage_m - atM) ? x : b,
|
|
);
|
|
const [lx, ly] = s.frame.left_xy;
|
|
const along = atM - s.chainage_m;
|
|
return {
|
|
cx: s.center_x - ly * along,
|
|
cy: s.center_y + lx * along,
|
|
leftX: lx,
|
|
leftY: ly,
|
|
designZ: s.design?.design_elevation_m ?? null,
|
|
};
|
|
};
|
|
/** 부재 차림표 — 종류 · 열쇠 · 측점(같은 몸체를 두 번 세우면 같은 줄이 둘). */
|
|
const kinds = (sections) =>
|
|
buildCorridorStructures(sections, frameAtOf(sections))
|
|
.map((s) => `${s.kind}:${s.key ?? ""}:${s.chainage_m.toFixed(2)}`)
|
|
.sort();
|
|
const pick = loadTs(
|
|
path.join(ROOT, "B05_Profile", "logic", "B05_Profile_UI_Corridor_Structures_Pick.ts"),
|
|
);
|
|
const own = pick.ownsBody;
|
|
/** 노선 끝 꼴 — 같은 시설을 그리는 카드가 소수 차(EP 1078 · 1078.010813)로 하나 더. */
|
|
const ep = (one) => Object.assign(clone(one), { chainage_m: one.chainage_m + 0.010813 });
|
|
const out = {};
|
|
for (const c of [173.087, 352.14]) {
|
|
const one = at(c);
|
|
const twin = kinds([one, clone(one)]);
|
|
const epTwin = kinds([one, ep(one)]);
|
|
const epFirst = kinds([ep(one), one]); // 차례가 바뀌어도 시설 자리에 가까운 카드 하나
|
|
pick.ownsBody = () => true; // 고치기 전(카드마다 몸체) — 기준이 변경을 재는지
|
|
const before = kinds([one, clone(one)]);
|
|
const epBefore = kinds([one, ep(one)]);
|
|
pick.ownsBody = own;
|
|
out[c] = { one: kinds([one]), twin, before, epTwin, epFirst, epBefore };
|
|
}
|
|
process.stdout.write(JSON.stringify(out));
|