Files
Aislo/resources/tester/test_426_profile_straight.py
T
eomsangdonandClaude Opus 5.5 309415a481 fix(B05 종단): 직선 판정 한 벌(꼭짓점 높이 1e-5 m) · 끝점 꼭짓점 · 기울이기 누름 쌓임 · 편집 측점 수 (426)
- TS `logic/B05_Profile_Profile_Straight.ts` ↔ 파이썬 `is_straight_bend` 짝 · 곡선 넣기 · ▲▼ 축 · 직선 찾기
- 적용 한 곳 `tidyEdits` — 직선 위 기억 R · 0 오프셋 지움(모양 그대로)
- 직선화 · 자유지정 끝이 꼭짓점 아니면 지금 높이로 세움 · 고른 직선 기울이기 = 지금 경첩 높이 + 걸음
- 「편집 측점 N개」 = 꺾인 편집 꼭짓점 수 · 시험 test_426 + 헬퍼 스텁 넷

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XWh5wNNycMkbwMpACz1rte
2026-10-18 15:51:08 +09:00

133 lines
4.9 KiB
Python

# -*- coding: utf-8 -*-
"""426 B05 종단 직선 판정 한 벌 — 높이 기준(1e-5 m) · 끝점 꼭짓점 · 누름 쌓임 · 편집 측점 수.
요구 259.
계산(`logic/B05_Profile_Profile_Straight.ts` · `_Alignment.ts` buildCurves · `_Pivot.ts` ·
`_Straighten.ts` · `design_profile_free.ts`)은 Node 헬퍼(`helper_426_profile_straight.cjs`)가
트랜스파일해 돌리고, 파이썬 짝(`B05_Profile_Engine_Grade_Alignment.py` `is_straight_bend`)은
같은 base · 편집으로 곡선 자리 · R 이 같은지 거울로 본다.
./venv/Scripts/python.exe -m pytest resources/tester/test_426_profile_straight.py -q
"""
import json
import os
import subprocess
import sys
from pathlib import Path
import numpy as np
import pytest
HERE = Path(__file__).resolve().parent
ROOT = HERE.parent.parent
sys.path.insert(0, str(ROOT))
from B05_Profile.B05_Profile_Engine_Grade_Alignment import ( # noqa: E402
STRAIGHT_HEIGHT_M,
AlignmentPolicy,
build_alignment,
is_straight_bend,
)
def _read(relative: str) -> str:
return (ROOT / relative).read_text(encoding="utf-8")
@pytest.fixture(scope="module")
def out():
proc = subprocess.run(
["node", os.path.join(HERE, "helper_426_profile_straight.cjs")],
capture_output=True,
text=True,
encoding="utf-8",
timeout=60,
)
assert proc.returncode == 0, proc.stderr
return json.loads(proc.stdout)
def test_붙은_측점_직선화_뒤_R_없음_한_직선(out):
got = out["straightened"]
# 옛 판정(대수차 1e-9)이면 꺾임으로 읽혔을 반올림 흠이 실제로 있음 — 시험이 그 길을 거침
assert got["noiseBends"] > 0
assert got["curvesInside"] == [] and got["radiiKeys"] == []
assert got["run"] == [40, 140]
assert got["axes"] == [40, 140]
def test_직선_안_누름_톱니_없음(out):
got = out["straightened"]
assert got["pressRise"] == pytest.approx(0.1, abs=1e-4)
assert got["curvesAfterPress"] == [80] # 누른 점 하나만 꺾임
left, right = got["gradesUp"][:2], got["gradesUp"][2:]
assert max(left) - min(left) < 1e-3 and max(right) - min(right) < 1e-3 # 0.4 m 조각 톱니 없음
def test_편집_측점_수는_꺾인_꼭짓점(out):
assert out["straightened"]["offsetCount"] > 0
assert out["straightened"]["editedCount"] == 0
assert out["tilt"]["editedAfterOne"] == 1
def test_끝점_꼭짓점_아니면_지금_높이로_세움(out):
got = out["endpoint"]
assert got["endHeld"] == pytest.approx(0, abs=1e-6)
assert got["endIsVertex"]
assert got["curvesInside"] == []
assert all(abs(value) < 1e-5 for value in got["innerResidual"])
def test_자유지정_R_뒤_직선되면_R_지움(out):
got = out["freeCase"]
assert got["endHeld"] == pytest.approx(0, abs=1e-6)
assert got["radiusAt140"] and got["curveAt140"] and got["curvesInsideF"] == [140]
assert got["radiusKeptRaw"] # ▼ 만으로는 기억 R 이 남음 → 적용 한 곳의 정리가 지움
assert got["radiusAfterTidy"] is None and got["curvesAfterTidy"] == []
assert got["sameShape"] == pytest.approx(0, abs=1e-9)
def test_고른_직선_기울이기_누름_쌓임(out):
got = out["tilt"]
assert got["rises"] == pytest.approx([0.1, 0.2, 0.1, 0.0], abs=1e-6)
assert got["finalRadii"] == [] and got["finalCurves"] == []
def test_0_오프셋_정리(out):
assert out["tidyZero"] == ["80.000"]
def test_파이썬_짝_같은_기준():
assert STRAIGHT_HEIGHT_M == 1e-5
assert is_straight_bend(2.5e-6, 0.4, 20.0) # 반올림 흠(0.4 m 조각) = 직선
assert not is_straight_bend(1e-3, 20.0, 20.0) # 0.1 % 꺾임 = 꺾임
assert "STRAIGHT_HEIGHT_M = 1e-5" in _read("B05_Profile/logic/B05_Profile_Profile_Straight.ts")
def test_파이썬_거울_곡선_자리_R(out):
base = out["mirror"]["base"]
policy = AlignmentPolicy.from_dict(base["policy"])
for case in out["mirror"]["cases"]:
got = build_alignment(
base_s=np.array([n["chainage_m"] for n in base["basePvi"]]),
base_z=np.array([n["elevation_m"] for n in base["basePvi"]]),
chainage=np.array(base["chainage"]),
ground=np.array(base["ground"]),
stations=base["stations"],
policy=policy,
edits=case["edits"],
)
py = [[c["chainage_m"], c["r_m"]] for c in got["curves"]]
assert [c[0] for c in py] == pytest.approx([c[0] for c in case["curves"]], abs=1e-6)
assert [c[1] for c in py] == pytest.approx([c[1] for c in case["curves"]], rel=1e-6)
def test_부르는_곳():
assert "tidyEdits(base, next)" in _read("A00_Common/design/design_profile.ts")
assert "bentEditCount(alignment)" in _read("B05_Profile/B05_Profile_UI_Profile_Balance.ts")
assert "isStraightBend(delta, spanLeft, spanRight)" in _read(
"B05_Profile/logic/B05_Profile_UI_Profile_Alignment.ts"
)
assert "is_straight_bend(delta," in _read("B05_Profile/B05_Profile_Engine_Grade_Alignment.py")