- 브라우저 — 노선 바뀐 [저장]의 계획고 본문 = 묶음 계획고 대 저장분 옮김(같은 carryEdits · 이 초안 첫 기준)의 다른 열쇠 · 지운 열쇠만(`gradeTouch` · `routeGradeTouch`) · 못 가르면 옛 길(노선 0 칸 통째) - 서버 — `alignment_cleared` 가 오면 관 · 구조물 · 추가 측점 차례 뒤 새 종단 편집(서버 옮김) 위에 손댐만 얹어 한 번 저장(`touched_alignment` · 얹기 실패도 되돌림 안) - follow 옮김 측점 = stations 단계와 같은 추가 측점(`plus` 넘김) - 재현: 꼬리 추가 측점 ▲ 뒤 앞 교점 끌기 [저장] = 990 m 편집 버림 · ▲ 잃음 · 최대 −0.50 m → 고친 뒤 버림 0 · 끌 때 = 저장 뒤 - 시험: test_498_2_grade_touch 새로 · helper_design_store_save 에 묶음 창구 가짜 하나(옛 길) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
145 lines
4.8 KiB
JavaScript
145 lines
4.8 KiB
JavaScript
/* 498-2 노선 바뀐 [저장] 계획고 손댐 — 진짜 TS(`logic/B05_Profile_Pipeline_Grade` follow · `gradeTouch`)를
|
|
* Node 로 돌림. 표준출력 JSON 한 벌.
|
|
*/
|
|
const path = require("path");
|
|
const { makeLoader } = require("./helper_ts_stub_loader.cjs");
|
|
|
|
const ROOT = path.join(__dirname, "..", "..");
|
|
|
|
function loadTs(file, stubs = {}) {
|
|
return makeLoader({
|
|
root: ROOT,
|
|
cache: false,
|
|
requireFor: (full) => (request) => {
|
|
if (stubs[request]) return stubs[request];
|
|
throw new Error(`stub 없음: ${request} (${file})`);
|
|
},
|
|
}).loadTs(path.join(ROOT, file));
|
|
}
|
|
|
|
const straightJudge = loadTs("B05_Profile/logic/B05_Profile_Profile_Straight.ts");
|
|
const curveLaw = loadTs("B05_Profile/logic/B05_Profile_Profile_CurveLaw.ts");
|
|
const pivot = loadTs("B05_Profile/logic/B05_Profile_UI_Profile_Pivot.ts", {
|
|
"./B05_Profile_Profile_Straight": straightJudge,
|
|
});
|
|
const alignment = loadTs("B05_Profile/logic/B05_Profile_UI_Profile_Alignment.ts", {
|
|
"./B05_Profile_UI_Profile_Pivot": pivot,
|
|
"./B05_Profile_Profile_Straight": straightJudge,
|
|
"./B05_Profile_Profile_CurveLaw": curveLaw,
|
|
});
|
|
const carry = loadTs("B05_Profile/logic/B05_Profile_Grade_Carry.ts", {
|
|
"./B05_Profile_UI_Profile_Alignment": alignment,
|
|
});
|
|
const grade = loadTs("B05_Profile/logic/B05_Profile_Pipeline_Grade.ts", {
|
|
"./B05_Profile_Profile_CurveLaw": curveLaw,
|
|
"../../common_util/common_util_route_follow": {},
|
|
"../../common_util/common_util_structure_station": {
|
|
PLUS_OWNER_PREFIX: "plus-",
|
|
SAME_STATION_M: 0.005,
|
|
},
|
|
"./B05_Profile_Grade_Seat": loadTs("B05_Profile/logic/B05_Profile_Grade_Seat.ts", {
|
|
"./B05_Profile_UI_Profile_Alignment": alignment,
|
|
}),
|
|
"./B05_Profile_UI_Profile_Alignment": alignment,
|
|
"./B05_Profile_Grade_Carry": carry,
|
|
"./B05_Profile_Sections_Stations": { SECTION_STATION_INTERVAL_M: 20 },
|
|
"./B05_Profile_Grade_Ground": loadTs("B05_Profile/logic/B05_Profile_Grade_Ground.ts", {
|
|
"./B05_Profile_Profile_CurveLaw": curveLaw,
|
|
"./B05_Profile_UI_Profile_Alignment": alignment,
|
|
}),
|
|
});
|
|
|
|
const routeOf = (line) => {
|
|
const chainage = [0];
|
|
for (let i = 1; i < line.length; i += 1)
|
|
chainage.push(
|
|
chainage[i - 1] + Math.hypot(line[i][0] - line[i - 1][0], line[i][1] - line[i - 1][1]),
|
|
);
|
|
return { line, curves: [], chainage, lengthM: chainage[chainage.length - 1] };
|
|
};
|
|
/** 10 m 격자 + 끝 — 묶음 stations 단계 자리. */
|
|
const gridOf = (route) => {
|
|
const out = [];
|
|
for (let s = 0; s < route.lengthM - 1e-6; s += 10) out.push(Math.round(s * 1000) / 1000);
|
|
return [...out, Math.round(route.lengthM * 1000) / 1000];
|
|
};
|
|
|
|
const SAVED_LINE = [
|
|
[0, 0],
|
|
[100, 0],
|
|
[100, 100],
|
|
[100, 200],
|
|
];
|
|
const STEPS = [
|
|
[
|
|
[0, 0],
|
|
[95, 0],
|
|
[100, 100],
|
|
[100, 200],
|
|
],
|
|
[
|
|
[0, 0],
|
|
[90, 0],
|
|
[100, 100],
|
|
[100, 200],
|
|
],
|
|
];
|
|
const BASE = [0, 100, 200, 300].map((chainage_m) => ({ chainage_m, elevation_m: 500 }));
|
|
const SAVED = { station_offsets: { "250.000": 0.5 }, curve_radii: {} };
|
|
|
|
/** 저장 노선에서 노선 걸음 둘 — 걸음 사이 `between` 이 사용자 계획고 조작(묶음 입력 고침). */
|
|
function run(between, after) {
|
|
const stage = grade.createFollowStage({
|
|
savedLine: () => null,
|
|
stationsAt: (route) => gridOf(route),
|
|
});
|
|
const planline = { policy: { station_interval_m: 20 }, basePvi: BASE };
|
|
let now = SAVED;
|
|
let before = routeOf(SAVED_LINE);
|
|
let route = before;
|
|
STEPS.forEach((line, index) => {
|
|
route = routeOf(line);
|
|
const patch = stage({
|
|
inputs: { route: { nodes: [] }, pipes: null, structures: null, alignment: now },
|
|
out: { route },
|
|
before: { route: before, planline },
|
|
});
|
|
if (patch.alignment) now = patch.alignment;
|
|
if (index === 0 && between) now = between(now);
|
|
before = route;
|
|
});
|
|
if (after) now = after(now);
|
|
const reader = {
|
|
input: (key) => ({ route: { nodes: [] }, alignment: now })[key] ?? null,
|
|
output: (key) => (key === "route" ? route : null),
|
|
};
|
|
return { now, touch: stage.touch(SAVED, reader) };
|
|
}
|
|
|
|
const bump = (key, by) => (edits) => ({
|
|
...edits,
|
|
station_offsets: { ...edits.station_offsets, [key]: (edits.station_offsets[key] ?? 0) + by },
|
|
});
|
|
const drop = (edits) => {
|
|
const offsets = { ...edits.station_offsets };
|
|
delete offsets[Object.keys(offsets).sort()[0]];
|
|
return { ...edits, station_offsets: offsets };
|
|
};
|
|
|
|
process.stdout.write(
|
|
JSON.stringify({
|
|
plain: run(null, null),
|
|
lateBump: run(null, bump("60.000", 0.3)),
|
|
midBump: run(bump("40.000", 0.2), null),
|
|
removed: run(null, drop),
|
|
noFirst: grade.createFollowStage({ savedLine: () => null }).touch(SAVED, {
|
|
input: () => null,
|
|
output: () => null,
|
|
}),
|
|
pure: grade.gradeTouch(
|
|
{ station_offsets: { "10.000": 1, "20.000": 2.5 }, curve_radii: { "30.000": 80 } },
|
|
{ station_offsets: { "10.000": 1, "20.000": 2, "40.000": 3 }, curve_radii: {} },
|
|
),
|
|
}),
|
|
);
|