Files
Aislo/resources/tester/helper_234_1_structure_station.cjs
T
eomsangdonandClaude Opus 5.5 bbd6254892 feat(구조물표): 322-1 부품 상자 · 표 읽기 — 목록 · 측점 · 카드 이름 · 형상 고르기 · 3D 몸체 · 알약 띠가 종류 키 · 군 글자 · 자리꼴 · managed_by 대신 구조물 표(catalog) 한 줄을 읽음 · 코드 숨김 목록 걷음 · ★ 넷 + 관 공식 한 벌
- 부품 상자 common_util_structure_parts.json(갈래마다 부품 · 읽는 칸 · 자리꼴 · 정본 · 42종 처음값) · 표 읽기 common_util_structure_catalog.ts / .py 짝(정의 반영 ⊕ 처음값 ⊕ 부품 끔) · 거울 시험 test_322_1_catalog_mirror
- 목록: pickGroups 군 차례 = 구조물군 열쇠 · 페이지 거르기 listPick(B05 both · B06 both + b06) · HIDDEN_PICK_GROUPS · HIDDEN_PICK_TYPES · pickable 걷음(옛 대피 셋 asRoad 그대로)
- 측점: structureStationMarks · pipeStationMarks · is_station_planting_type · resolve_extra_stations = 표 횡단도(anchor · span3 · none)
- 카드 이름: cardTitle / card_title 한 공식(빈칸 = 그 종류 정의 기본값) · 표시 이름이 정의 관종도 앎
- 형상: 벽 = shape wall(형태 = 형상칸.form · 물빼기 = 형상칸.weep) · 포장 = shape pavement(「사용 중」 거르기 없앰) · 맹암거 · 사토 · 관 지점 시설 세트 = shape
- 3D 몸체 = 그림 자료 주인 종류의 표 3D 부품 · 알약 띠 = 표 자리꼴 구간(관 지점 시설은 알약만)
- ★1 노출형 · 개거 횡단도 none · ★2 쇄석 화면에서도 포장층 · ★3 기슭막이 표 자리꼴 interval(정의 파일 그대로) · ★4 코드 숨김 10종 list hidden · ★5 관 빈칸 D800 → 정의 기본 D1000
- 옛 시험: 도움 파일 로더 27개가 표 모듈 공용 한 벌(helper_322_catalog_module) 씀 · 기대값 고침(272_1 · b05_extra_stations · roundtrip · 314 · 52_7 · walls 거울 · wall_drain_pipe)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ji4nuyLVHcxrXWHTdb5nRD
2026-10-14 15:09:45 +09:00

199 lines
7.6 KiB
JavaScript

/* 234-1 · 272 구조물 기준 측점 = 정수 m · 옛 소수 자동 맞춤(단추 없음 · 167).
* 진짜 `common_util_structure_station` · `_Structures_Snap` · `_Structures_Fields` · `_Drainage_Pipes` ·
* `followedStation` 을 Node 로 돌림. 입력은 argv[2] JSON(파이썬과 같은 값) · 표준출력 JSON 한 벌.
*/
const fs = require("fs");
const path = require("path");
const ts = require(path.join(__dirname, "..", "..", "config", "node_modules", "typescript"));
const ROOT = path.join(__dirname, "..", "..");
function loadTs(file, stubs = {}) {
const js = ts.transpileModule(fs.readFileSync(path.join(ROOT, file), "utf8"), {
compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2020 },
}).outputText;
const box = { exports: {} };
const localRequire = (request) => {
if (stubs[request]) return stubs[request];
throw new Error(`stub 없음: ${request} (${file})`);
};
new Function("exports", "module", "require", js)(box.exports, box, localRequire);
return box.exports;
}
/* 가짜 DOM — 폼 칸(input · label · span)만. */
function fakeElement(tag) {
const listeners = {};
const classes = new Set();
return {
tagName: tag,
value: "",
className: "",
style: {},
children: [],
classList: {
toggle: (name, on) => (on ? classes.add(name) : classes.delete(name)),
add: (name) => classes.add(name),
remove: (name) => classes.delete(name),
contains: (name) => classes.has(name),
},
append(...nodes) {
this.children.push(...nodes);
},
addEventListener(type, fn) {
(listeners[type] ??= []).push(fn);
},
fire(type) {
(listeners[type] ?? []).forEach((fn) => fn({ type }));
},
focus() {},
};
}
global.document = { createElement: fakeElement };
const input = JSON.parse(fs.readFileSync(process.argv[2], "utf8"));
// 심는 측점 = 구조물 표(322-1) — 공용 표 모듈(실제 정의로 세움)
const catalog = require("./helper_322_catalog_module.cjs");
const station = loadTs("common_util/common_util_structure_station.ts", {
"./common_util_structure_catalog": catalog,
});
const STATIONS = input.stations;
const out = {};
// ① 맞춤 · 걸음 — 파이썬과 같은 값(거울)
out.snap = input.samples.map((value) => station.snapStructureStation(value, STATIONS));
out.step = input.steps.map(([from, dir]) => station.stepStructureStation(from, dir, STATIONS));
out.snapTwice = input.samples.every(
(value) =>
station.snapStructureStation(station.snapStructureStation(value, STATIONS), STATIONS) ===
station.snapStructureStation(value, STATIONS),
);
// 일반 측점 등록 — 구조물 측점(irregular)은 뺌 · 등록값이 기본으로 쓰임
station.setGeneralStations(
STATIONS.map((value) => ({ chainage_m: value, kind: "regular" })).concat([
{ chainage_m: 80.17, kind: "irregular" },
]),
);
out.general = [...station.generalStations()];
out.defaultSnap = station.snapStructureStation(80.4);
// ② 좌측 폼 칸 — 친 값 80.17 → 80 · 안 고친 옛 값은 그대로
const fields = loadTs("B05_Profile/B05_Profile_UI_Structures_Fields.ts", {
"./B05_Profile_Util_Station": loadTs("B05_Profile/B05_Profile_Util_Station.ts"),
"../B06_Section/B06_Section_UI_Cross_Culvert_Basin": { DEFAULT_BASIN_SHAPE: {} },
"../common_util/common_util_culvert_sets": { fillPipeHeights: () => {} },
"../common_util/common_util_structure_station": station,
});
const anchor = fields.stationFields("기준 측점", () => 20);
out.remainderStep = anchor.remainder.step;
anchor.station.value = "4";
anchor.remainder.value = "0.17";
out.typed = anchor.read(20, true);
anchor.remainder.value = "0.6";
out.typedNear = anchor.read(20, true);
anchor.remainder.value = "1";
out.typedOne = anchor.read(20, true);
anchor.write(80.17, 20);
out.untouched = anchor.read(20, true);
// ③ 구조물 옮김 · 옛 소수 자동 맞춤 셈 · 실행
const toasts = [];
let confirmText = null;
const snap = loadTs("B05_Profile/B05_Profile_UI_Structures_Snap.ts", {
"@ui/ui_template_elements": {
showToast: (message, kind) => toasts.push({ message, kind }),
showConfirmDialog: async (message) => ((confirmText = message), true),
},
"../common_util/common_util_structure_station": station,
"../A00_Common/design/design_selection": { PIPE_MATCH_M: 0.51 },
"./B05_Profile_Api_Structures": {
structureAnchorM: (entry) => entry.chainage_m ?? entry.start_m ?? 0,
},
});
out.movedPoint = snap.movedStructure({ placement: "point", chainage_m: 127.86 }, 127.86);
out.movedWall = snap.movedStructure(
{ placement: "interval", chainage_m: 80.17, start_m: 75.17, end_m: 95.67 },
80.17,
);
out.movedDrag = snap.movedStructure(
{ placement: "interval", chainage_m: 50, start_m: 50, end_m: 62 },
133.4,
);
const structures = input.structures.map((entry) => ({ ...entry }));
const pipes = input.pipes.map((chainage_m) => ({
chainage_m,
facility: "pipe",
options: { pipe_kind: "흄관" },
summary_item: null,
group_items: null,
}));
const plan = snap.snapPlan(structures, pipes);
out.plan = {
structures: plan.structures.map(({ index, next }) => ({ index, next })),
pipes: plan.pipes.map(({ from, to }) => [from, to]),
skipped: plan.skipped,
};
const moves = [];
let emits = 0;
let closed = 0;
Promise.resolve(
snap.snapOldStations({
structures,
pipes: () => pipes,
emit: () => (emits += 1),
movePipe: (from, to, attributes) => moves.push({ from, to, attributes }),
closeForm: () => (closed += 1),
}),
)
.then(async (count) => {
out.run = { count, emits, closed, moves, structures, confirmText, toasts: [...toasts] };
// 두 번째 = 옮길 것 없음(관은 위 moves 로 옮겨졌다고 보고 목록을 맞춤)
moves.forEach(({ from, to }) => {
const hit = pipes.find((pipe) => pipe.chainage_m === from);
if (hit) hit.chainage_m = to;
});
toasts.length = 0;
const again = { structures, pipes: () => pipes, emit() {}, movePipe() {}, closeForm() {} };
out.second = { count: snap.snapOldStations(again), toasts: [...toasts] };
// ④ 계획고 편집 따라감 — 한꺼번에 여럿 옮김(사라진 둘 · 새 둘)
const alignment = loadTs("B05_Profile/B05_Profile_UI_Profile_Alignment.ts");
const gone = [
{ id: "pipe-80.17", chainage_m: 80.17 },
{ id: "pipe-263.31", chainage_m: 263.31 },
];
const born = [
{ id: "pipe-80.00", chainage_m: 80 },
{ id: "pipe-263.00", chainage_m: 263 },
];
out.follow = gone.map((entry) => {
const old = alignment.followedStation(entry, gone, born);
const next = old ?? snap.followSnapped(entry, born);
return { old: old?.chainage_m ?? null, next: next?.chainage_m ?? null };
});
// ⑤ 배수유역도 관 지점 — 옮김 · 우클릭 추가 = 정수 m
const pipesEditor = loadTs("B05_Profile/B05_Profile_UI_Drainage_Pipes.ts", {
"../A00_Common/touch_bridge": { pickPx: (px) => px }, // 기기대응 4-4 — 마우스 반경 그대로
"@ui/ui_template_palette": { themeColor: () => "#000" },
"../common_util/common_util_structure_station": station,
});
const editor = pipesEditor.createPipeEditor(() => {});
editor.setContext(null, [
{ x: 0, y: 0, chainage_m: 0 },
{ x: 300, y: 0, chainage_m: 300 },
]);
editor.setPipes([{ chainage_m: 80.17, reason: "stream" }]);
editor.moveTo(0, 141.37);
editor.addAtChainage(200.6);
out.editor = editor.pipes().map((pipe) => pipe.chainage_m);
process.stdout.write(JSON.stringify(out));
})
.catch((error) => {
process.stderr.write(String(error && error.stack ? error.stack : error));
process.exit(1);
});