- 검증_랩탑메인 No.14+12.22 관 유출 흙막이가 원지반 아래 → 91-4 벽 모서리 절토와 139-4 끝 연결선이 함께 이어져 설계선이 되접힘 - 유출 끝 연결선이 있으면 벽 모서리 절토를 잇지 않음(카드 · 서버 면적 · B07 · 3D 같은 기하) - 사본 재현 시험 test_186_1 · 픽스처 b06_186_1_pipe_292 · 91 헬퍼 시작점 맞춤 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01F3mdb91125mPoC6tpsQx4P
117 lines
4.8 KiB
JavaScript
117 lines
4.8 KiB
JavaScript
/* 186-1 묻힌 관 유출 벽 설계선 접힘 헬퍼 — 화면 TS 를 그 자리에서 트랜스파일해 Node 로 돌림.
|
|
* 입력 = 검증_랩탑메인 No.14+12.22 사본(`fixtures/b06_186_1_pipe_292.json`) · 73-4 픽스처 관 340(절토 쪽 유출).
|
|
* 결과 = 표준출력 JSON 한 벌. 짝 = `test_186_1_outlet_fold.py`.
|
|
*/
|
|
const fs = require("fs");
|
|
const path = require("path");
|
|
const ts = require(path.join(__dirname, "..", "..", "config", "node_modules", "typescript"));
|
|
|
|
const ROOT = path.join(__dirname, "..", "..");
|
|
const cache = new Map();
|
|
// 화면 전용 모듈(토스트) — 기하 계산엔 안 쓰임
|
|
const STUBS = {
|
|
"@ui/ui_template_toast": { showToast: () => undefined },
|
|
};
|
|
|
|
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);
|
|
cache.set(full, box.exports);
|
|
return box.exports;
|
|
}
|
|
const resolve = (base) =>
|
|
[base, `${base}.ts`, path.join(base, "index.ts")].find(
|
|
(p) => fs.existsSync(p) && fs.statSync(p).isFile(),
|
|
) ?? `${base}.ts`;
|
|
|
|
const B06 = (f) => path.join(ROOT, "B06_Section", f);
|
|
const { computeStoredLayouts, structureAreaRows } = loadTs(B06("B06_Section_Structure_Layouts.ts"));
|
|
const { computeCulvertLayout } = loadTs(B06("B06_Section_UI_Cross_Culvert_Geom.ts"));
|
|
const read = (name) =>
|
|
JSON.parse(fs.readFileSync(path.join(__dirname, "fixtures", name), "utf8")).cross_sections;
|
|
const clone = (v) => JSON.parse(JSON.stringify(v));
|
|
const r2 = (v) => Math.round(v * 100) / 100;
|
|
|
|
/** 유출 쪽 설계선(트림 사면) 점열 · 유출 벽 · 면적 행. */
|
|
function study(sections, target) {
|
|
const section = sections.find((s) => Math.abs(s.chainage_m - target) < 0.01);
|
|
const { culvert } = computeStoredLayouts(section, sections);
|
|
const wall = culvert.walls.find((w) => w.role === "outlet");
|
|
const trim = culvert.designTrim;
|
|
const slope = (wall.outward > 0 ? trim.maxSlope : trim.minSlope).points;
|
|
const row = structureAreaRows(sections).find((r) => Math.abs(r.chainage_m - target) < 0.01);
|
|
return {
|
|
outward: wall.outward,
|
|
wallTop: r2(wall.topJoint.elevation),
|
|
groundAtWall: r2(groundOf(section, wall.topJoint.offset)),
|
|
offsets: slope.map((p) => r2(p.offset)),
|
|
elevations: slope.map((p) => r2(p.elevation)),
|
|
cut: row ? row.cut_area_m2 : null,
|
|
fill: row ? row.fill_area_m2 : null,
|
|
};
|
|
}
|
|
function groundOf(section, offset) {
|
|
const s = section.samples;
|
|
for (let i = 1; i < s.length; i += 1)
|
|
if (s[i].offset_m >= offset) {
|
|
const t = (offset - s[i - 1].offset_m) / (s[i].offset_m - s[i - 1].offset_m);
|
|
return s[i - 1].elevation_m + (s[i].elevation_m - s[i - 1].elevation_m) * t;
|
|
}
|
|
return NaN;
|
|
}
|
|
|
|
const out = {};
|
|
// ① 저장값 그대로(유출 d 9.0) · ② 자동 자리(조작값 없음)
|
|
const stored = read("b06_186_1_pipe_292.json");
|
|
out.stored = study(stored, 292.22);
|
|
const auto = clone(stored);
|
|
auto[0].design.revet_adjust = null;
|
|
out.auto = study(auto, 292.22);
|
|
// ③ 91-4 절토 쪽 배관 유출(73-4 픽스처 관 340 · 유출 = 우측 절토)
|
|
const base = read("b06_73_4_body_guard_sections.json");
|
|
const s340 = clone(base.find((s) => Math.abs(s.chainage_m - 340) < 0.6));
|
|
s340.uphill_side = "left";
|
|
s340.culvert = {
|
|
type: "pipe",
|
|
chainage_m: 340,
|
|
pipe_kind: "흄관",
|
|
diameter_m: 1.0,
|
|
min_cover_m: 0.5,
|
|
inlet: { role: "inlet", structure: "기슭막이", revet_form: "돌쌓기(찰)" },
|
|
outlet: { role: "outlet", structure: "기슭막이", revet_form: "돌쌓기(찰)" },
|
|
};
|
|
s340.design.inlet_structure = "revet";
|
|
const layout = computeCulvertLayout(s340, s340.samples, undefined, "revet");
|
|
const wall340 = layout.walls.find((w) => w.role === "outlet");
|
|
const slope340 = (wall340.outward > 0 ? layout.designTrim.maxSlope : layout.designTrim.minSlope)
|
|
.points;
|
|
out.cut340 = {
|
|
outward: wall340.outward,
|
|
offsets: slope340.map((p) => r2(p.offset)),
|
|
elevations: slope340.map((p) => r2(p.elevation)),
|
|
};
|
|
process.stdout.write(JSON.stringify(out));
|