feat(B05 종단): ▲▼ 직선 안 측점 · 꼭짓점 아닌 자리 = 그 점 새 꺾임 · 좌우 다음 R 점 축 (368-1)

- pivotAxes 직선 안쪽 null 지움 · 꼭짓점 아닌 자리는 품은 마디로 축 찾기
- 시험 helper_355_1 ③ 직선 안 80 바꿈 · ④ 꼭짓점 아닌 70 더함

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013QyNXY2TUKXCFMwAca2APG
This commit is contained in:
2026-10-17 11:46:18 +09:00
co-authored by Claude Opus 5.5
parent ea4e152d32
commit 84ead5a561
4 changed files with 59 additions and 25 deletions
+34 -11
View File
@@ -1,7 +1,8 @@
/* 355-1 종단 ▲▼ 이웃 꺾임 축 돌림 단위검증 헬퍼 — `B05_Profile_UI_Profile_Alignment.ts` ·
* `_Straighten.ts` 를 그 자리에서 트랜스파일해 세 경우를 Node 로 돌린다.
* ① 처음 계획선 ▲ = 옛 값 ② 직선화 뒤 꺾임 ▲ = 사이 측점 한 직선 · 축 표고 그대로 · +0.1
* ③ 직선 안쪽 ▲ = 옛 값. 옛 값 = 355-1 앞 adjustStation(아래 oldAdjust) 그대로.
* ③ 직선 안 측점 ▲ = 그 점 새 꺾임 · 축 = 좌우 다음 꺾임(368-1) ④ 꼭짓점 아닌 자리 ▲ = 같은 규칙.
* 옛 값 = 355-1 앞 adjustStation(아래 oldAdjust) 그대로.
*/
const fs = require("fs");
const path = require("path");
@@ -132,19 +133,41 @@ const out = {};
};
}
// ③ 직선 안쪽(80 · 40~100 직선 위) — 꺾임 아님 → 옛 값.
{
/** 직선 안 점 ▲ — 축 40 · 100 그대로 · 사이 점 새 직선 위 · 누른 점 꺾임(368-1). */
function tiltInside(pressM, innerS) {
let edits = straight.straightenBetween(base, align.emptyEdits(), 40, 100);
edits = straight.straightenBetween(base, edits, 100, 160);
const next = align.adjustStation(base, edits, 80, 0.1);
out.inside = {
same:
JSON.stringify(sorted(next.station_offsets)) ===
JSON.stringify(sorted(oldAdjust(edits, 80, 0.1).station_offsets)),
planRise:
align.planElevationAt(align.buildAlignment(base, next), 80) -
align.planElevationAt(align.buildAlignment(base, edits), 80),
const before = align.buildAlignment(base, edits);
const next = align.adjustStation(base, edits, pressM, 0.1);
const after = align.buildAlignment(base, next);
const p = pviZ(after, pressM);
const z40 = pviZ(before, 40);
const z100 = pviZ(before, 100);
const line = (s) =>
s < pressM
? z40 + ((p - z40) * (s - 40)) / (pressM - 40)
: z100 + ((p - z100) * (s - 100)) / (pressM - 100);
return {
planRise: align.planElevationAt(after, pressM) - align.planElevationAt(before, pressM),
axisMove: [pviZ(after, 40) - z40, pviZ(after, 100) - z100],
outsideMove: [20, 120, 140, 160].map((s) => pviZ(after, s) - pviZ(before, s)),
innerResidual: innerS.map((s) => pviZ(after, s) - line(s)),
innerMoved: innerS.map((s) => pviZ(after, s) - pviZ(before, s)),
curveAtPress: after.curves.some((c) => Math.abs(c.chainage_m - pressM) < 1e-6),
pressRadiusKey: Object.prototype.hasOwnProperty.call(
next.curve_radii,
align.chainageKey(pressM),
),
innerRadiusKeys: innerS.filter((s) =>
Object.prototype.hasOwnProperty.call(next.curve_radii, align.chainageKey(s)),
),
};
}
// ③ 직선 안 측점(80 · 40~100 직선 위) — 80 새 꺾임 · 축 40 · 100 · 60 새 직선 위.
out.inside = tiltInside(80, [60]);
// ④ 꼭짓점 아닌 자리(70) — 같은 규칙 · 60 · 80 새 직선 위.
out.between = tiltInside(70, [60, 80]);
process.stdout.write(JSON.stringify(out));
+11 -3
View File
@@ -55,9 +55,17 @@ def test_꺾임_누르면_사이_측점이_한_직선(out):
assert kink["oldWouldBreak"] == [0, 0]
def test_직선_안쪽은_옛_값(out):
assert out["inside"]["same"]
assert out["inside"]["planRise"] == pytest.approx(0.1, abs=1e-4)
@pytest.mark.parametrize("case", ["inside", "between"])
def test_직선_안_점은_새_꺾임_축은_좌우_다음_꺾임(out, case):
# 368-1: 직선 안 측점(80) · 꼭짓점 아닌 자리(70) 모두 그 점에 R · 축 40 · 100
got = out[case]
assert got["planRise"] == pytest.approx(0.1, abs=1e-4)
assert got["axisMove"] == [0, 0]
assert got["outsideMove"] == [0, 0, 0, 0]
assert all(abs(value) < 1e-6 for value in got["innerResidual"])
assert all(value > 0 for value in got["innerMoved"])
assert got["curveAtPress"] and not got["pressRadiusKey"]
assert got["innerRadiusKeys"] == []
def test_부르는_곳_셋이_같은_함수():