- B05 Corridor Build · Envelope · Station · Station_Structure · Structures · _Box · _Chute · _Path → B05_Profile/logic/B05_Profile_Corridor_*.ts (본문 그대로 · import 경로만) - Structures 재수출 줄 걷음(700 줄 한도) · Envelope 는 Structures_Hash 를 바로 부름 - helper_472_3_graph = 줄 머리 import · export 만 셈(주석 속 낱말 안 셈) - test_472_3 SESSION_PULLS 헛잡음 6 줄 · GEOMETRY_PULLS B05 8 줄 걷음 (남은 ui_template_locale 10 = Route_Carry_Patch → common_util_svg 진짜 끌림) - 옮긴 파일을 읽는 시험 · 헬퍼 경로 새 자리로 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
78 lines
3.4 KiB
JavaScript
78 lines
3.4 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 { makeLoader } = require("./helper_ts_stub_loader.cjs");
|
|
|
|
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`;
|
|
const { loadTs } = makeLoader({
|
|
root: ROOT,
|
|
interop: true,
|
|
requireFor: (full) => (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)));
|
|
},
|
|
});
|
|
|
|
const { buildCorridorStructures } = loadTs(
|
|
path.join(ROOT, "B05_Profile", "logic", "B05_Profile_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));
|