- common_util_structure_station `followMovedNodes` = 옮김 · 지움 · 세울 측점(`seat`)만 돌려줌 - 새 B05_Profile/logic/B05_Profile_Grade_Seat.ts `seatBornNodes` = 파이썬 `_seat_born_nodes` 짝 - design_profile_base 가 둘을 차례로 부름 · 272-1 · 427-1 도우미 맞춤 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014utrjfoW831Vc5wJUd13kL
60 lines
2.3 KiB
TypeScript
60 lines
2.3 KiB
TypeScript
/* =============================================================================
|
|
* B05_Profile/logic/B05_Profile_Grade_Seat.ts
|
|
* 옮긴 관 · 구조물의 새 측점에 계획선 꼭짓점 세움(427) — 원지반 지남(`passThrough` 규칙) · 다른 꼭짓점 그대로.
|
|
*
|
|
* 짝 = 파이썬 `B05_Profile_Router_Confirm._seat_born_nodes` · 세울 측점은 공용 `followMovedNodes`
|
|
* (common_util_structure_station.ts)가 고름 · 거울 시험 = resources/tester/test_427_1_follow_seat.py.
|
|
* ========================================================================== */
|
|
|
|
import {
|
|
buildCurves,
|
|
evaluateAt,
|
|
type AlignmentBase,
|
|
type AlignmentNode,
|
|
} from "./B05_Profile_UI_Profile_Alignment";
|
|
|
|
/** 새 측점(`born`)에 원지반을 지나는 꼭짓점 — 양 끝 밖 · 이미 꼭짓점 있는(0.006m 안) 자리는 건너뜀. */
|
|
export function seatBornNodes(
|
|
base: Pick<AlignmentBase, "chainage" | "ground" | "policy">,
|
|
nodes: AlignmentNode[],
|
|
born: ReadonlyArray<number>,
|
|
): AlignmentNode[] {
|
|
if (!nodes.length || base.chainage.length < 2) return nodes;
|
|
const first = nodes[0].chainage_m;
|
|
const last = nodes[nodes.length - 1].chainage_m;
|
|
const fresh = born.filter(
|
|
(value) =>
|
|
first < value &&
|
|
value < last &&
|
|
nodes.every((node) => Math.abs(value - node.chainage_m) >= 0.006),
|
|
);
|
|
if (!fresh.length) return nodes;
|
|
const rows = [
|
|
...nodes.map((node) => ({
|
|
s: node.chainage_m,
|
|
z: node.elevation_m,
|
|
node: node as AlignmentNode | null,
|
|
})),
|
|
...fresh.map((s) => ({ s, z: evaluateAt(base.chainage, base.ground, [], s), node: null })),
|
|
].sort((a, b) => a.s - b.s);
|
|
const baseS = rows.map((row) => row.s);
|
|
const target = rows.map((row) => row.z);
|
|
let baseZ = [...target];
|
|
for (let round = 0; round < 20; round += 1) {
|
|
const pvi = baseS.map((s, index) => ({ chainage_m: s, elevation_m: baseZ[index] }));
|
|
const curves = buildCurves(pvi, base.policy, {}, []);
|
|
const error = rows.map((row, index) =>
|
|
row.node ? 0 : target[index] - evaluateAt(baseS, baseZ, curves, baseS[index]),
|
|
);
|
|
if (Math.max(...error.map(Math.abs)) < 1e-6) break;
|
|
baseZ = baseZ.map((z, index) => z + error[index]);
|
|
}
|
|
return rows.map(
|
|
(row, index) =>
|
|
row.node ?? {
|
|
chainage_m: Number(row.s.toFixed(6)),
|
|
elevation_m: Number(baseZ[index].toFixed(6)),
|
|
},
|
|
);
|
|
}
|