R 하한만 막고 L 하한은 칸 입력에서만 막던 것을 고침. L = R·Δ 라 한 자리의 하한을 반지름 하나로 모아 봄(`radiusFloorM` = max(R 하한, L 하한/Δ)) — 값 끌어올리기· 모자란 양 판정·칸 막기가 모두 이 값을 씀. 내각 155° 이상은 별표2 Ⅰ.2.다.(1) 상 곡선을 안 둬도 되는 자리라 L 하한을 안 걺 — 걸면 교각이 0 에 가까워 R 이 수십 배로 부풀어 안 고친 구간이 휨. 그 자리는 곡선 패널에 「155° 이상 — 곡선 생략 가능」으로 적어 냄. `deflectionRad` 를 화면 파일(`_Label`)에서 셈 파일(`_Edits`)로 옮김 — 순수 함수가 DOM 파일에 얹혀 있어 시험이 화면째 들여와야 했음(부르던 자리는 재수출로 지킴). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DJffo4VwgTumVUM3kdbJzd
77 lines
3.2 KiB
Python
77 lines
3.2 KiB
Python
# -*- coding: utf-8 -*-
|
||
"""계획노선 편집의 **곡선 하한(R·L)** 회귀검증 — 2026-09-12.
|
||
|
||
사용자 확정: 「반경과 길이가 트레이드오프기는 하지만 **둘 다 지켜야** 한다」.
|
||
L = R·Δ 라 한 자리의 하한은 반지름 하나로 모이고, 그 값을 `radiusFloorM` 이 낸다.
|
||
|
||
⚠ 예외 하나 — **내각 155° 이상은 곡선을 설치하지 않을 수 있다**(별표2 Ⅰ.2.다.(1)).
|
||
거기서 L 을 채우라고 하면 교각이 0 에 가까워 R 이 수십 배로 부풀고, 아무것도 안 고쳤는데
|
||
노선이 휜다(실측: 내각 174.8° 자리가 R 12m → 55m). 그래서 그 자리는 R 하한만 본다.
|
||
|
||
Node 헬퍼(`helper_b05_curve_radius_floor.cjs`)가 TS 를 그 자리에서 트랜스파일해 돌리고,
|
||
여기서 값을 판정한다.
|
||
"""
|
||
|
||
import json
|
||
import os
|
||
import subprocess
|
||
|
||
import pytest
|
||
|
||
HERE = os.path.dirname(os.path.abspath(__file__))
|
||
|
||
|
||
@pytest.fixture(scope="module")
|
||
def results():
|
||
proc = subprocess.run(
|
||
["node", os.path.join(HERE, "helper_b05_curve_radius_floor.cjs")],
|
||
capture_output=True,
|
||
text=True,
|
||
timeout=60,
|
||
)
|
||
assert proc.returncode == 0, proc.stderr
|
||
return json.loads(proc.stdout)
|
||
|
||
|
||
def test_R_하한이_이기는_자리는_R_하한_그대로(results):
|
||
"""내각 140° 면 R 12m 만 지켜도 L 이 8.4m 라 L 하한(5m)이 안 건다."""
|
||
assert results["floors"]["bend140"] == pytest.approx(12.0)
|
||
|
||
|
||
def test_L_하한이_이기면_R_을_끌어올린다(results):
|
||
"""내각 150°(교각 30°)에 L 하한 20m 면 R 은 38.2m 이어야 한다 — 여기가 「둘 다」의 핵심."""
|
||
assert results["floors"]["bend150LongArc"] == pytest.approx(20 / (30 * 3.141592653589793 / 180))
|
||
assert results["floors"]["bend150LongArc"] > 12.0
|
||
|
||
|
||
def test_내각_155도_이상은_L_하한을_안_건다(results):
|
||
"""곡선 생략이 되는 자리다 — 걸었다면 R 이 28.6m 로 부풀어 노선이 조용히 휜다."""
|
||
assert results["floors"]["bend170"] == pytest.approx(12.0)
|
||
assert results["floors"]["bend170NoExempt"] > 28.0 # 예외가 없을 때의 값(참고)
|
||
assert results["floors"]["bend155"] == pytest.approx(12.0)
|
||
|
||
|
||
def test_155도_바로_아래는_L_하한을_건다(results):
|
||
"""경계는 「155° 이상」이라 154° 는 지켜야 하는 쪽이다."""
|
||
assert results["floors"]["bend154"] > 12.0
|
||
|
||
|
||
def test_내각을_모르면_R_하한만_본다(results):
|
||
assert results["floors"]["unknown"] == pytest.approx(12.0)
|
||
|
||
|
||
def test_지정한_반지름만_끌어올린다(results):
|
||
"""비워 둔(자동) 자리는 안 건드린다 — 건드리면 안 고쳤는데 「R 지정」이 늘어난다."""
|
||
applied = results["applied"]
|
||
assert applied["specified"] == pytest.approx(20 / (30 * 3.141592653589793 / 180))
|
||
assert applied["auto"] is None
|
||
assert applied["curveOff"] == 12 # 곡선을 지운 자리는 그대로
|
||
|
||
|
||
def test_모자란_양도_R과_L을_함께_잰다(results):
|
||
"""내각 150°(하한 38.2m)에서 R 12m 는 26.2m 모자라고, 170° 는 곡선 생략 자리라 0 이다."""
|
||
short = results["shortfalls"]
|
||
assert short[0] == pytest.approx(20 / (30 * 3.141592653589793 / 180) - 12)
|
||
assert short[1] == 0
|
||
assert short[2] == 0 # R 40m 는 하한을 넘겼다
|