fix(764-1): 추천 측점 맞춤 덜 나쁜 자리에 원지반 기울기 늘어남 · 옮긴 거리 따짐
- 요구 606-2 · 분석 761-6 — 설계 지형에서 측점 맞춤이 후보 7/8 을 비탈로 옮겨 추천 셋이 같은 선 - 덜 나쁜 자리 순위 = 계류 나란히 → 기울기 늘어남 → 옮긴 거리 · 꼴(합친 꼴)을 가로질러 견줌 - 크게 망침(기울기 넘친 만큼 +5 %p 초과 · 원래 선에서 10 m 초과)은 그것 없이 다 놓는 길이 없을 때만 · 그때 가장 덜 망치는 자리(곡선 가운데 = 측점 유지) - 놓을 자리 풀이 기억(층 · 다시 셈 공통) · ALGO_VERSION 9(옛 저장본 안 꺼냄) - 지킴 시험 test_764_1_snap_grade.py Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
"""764-1 추천 측점 맞춤 — 덜 나쁜 자리 고를 때 원지반 기울기 늘어남 · 옮긴 거리를 따짐(요구 606-2).
|
||||
|
||||
./venv/Scripts/python.exe -m pytest resources/tester/test_764_1_snap_grade.py -q
|
||||
|
||||
· 가까운 측점 자리가 비탈(기울기 늘어남)이면 다음 측점 자리로 — 옛 순위는 가까운 측점 · 토공을
|
||||
앞세워 비탈 자리를 골랐음.
|
||||
· 모든 자리가 크게 망치면 그중 가장 덜 망치는 자리(곡선 가운데 = 측점은 지킴).
|
||||
· 판(`ALGO_VERSION`)이 다른 저장본은 꺼내지 않음.
|
||||
"""
|
||||
|
||||
import json
|
||||
import math
|
||||
|
||||
import pytest
|
||||
|
||||
from B05_Profile.B05_Profile_Engine_RouteInitial_Station import (
|
||||
STATION_M,
|
||||
curve_mc_chainages,
|
||||
off_station_count,
|
||||
snap_curves_to_stations,
|
||||
)
|
||||
from B05_Profile.B05_Profile_Engine_RouteInitial_Store import (
|
||||
ALGO_VERSION,
|
||||
read_stored_any,
|
||||
store_dir,
|
||||
)
|
||||
from common_util.common_util_route_polyline import build_planned_polyline
|
||||
|
||||
RADIUS = 12.0
|
||||
# MC ≈ 109.5 m — 가까운 측점 100 · 다음 120
|
||||
POINTS = [(0.0, 0.0), (110.0, 0.0), (230.0, 90.0)]
|
||||
|
||||
|
||||
class _Slope:
|
||||
"""직접 잼 흉내 — 늘 못 지남(덜 나쁜 자리만 남음) · 곡선 가운데가 x < 112 면 비탈 쪽.
|
||||
|
||||
토공은 비탈 쪽이 더 작게(옛 순위가 비탈을 고르도록 유혹)."""
|
||||
|
||||
def __init__(self, steep: float, flat: float) -> None:
|
||||
self.steep, self.flat = steep, flat
|
||||
|
||||
def rise(self, local, reference) -> float:
|
||||
arc = local[1:-1]
|
||||
return self.steep if sum(x for x, _ in arc) / len(arc) < 112.0 else self.flat
|
||||
|
||||
def judge(self, local, reference):
|
||||
return False, (False, 0.0, -1000.0 * self.rise(local, reference))
|
||||
|
||||
def ok(self, local, reference) -> bool:
|
||||
return False
|
||||
|
||||
|
||||
def _snap(guard) -> float:
|
||||
outline = build_planned_polyline(
|
||||
POINTS,
|
||||
min_radius_m=RADIUS,
|
||||
simplify=False,
|
||||
curve_flags=[True] * 3,
|
||||
radii=[None, 40.0, None],
|
||||
)
|
||||
(mc,) = curve_mc_chainages(outline)
|
||||
assert abs(mc - 100.0) < abs(mc - 120.0) # 가까운 측점 = 비탈 쪽
|
||||
snapped = snap_curves_to_stations(outline, RADIUS, guard=guard)
|
||||
assert snapped is not None and off_station_count(snapped) == 0
|
||||
(placed,) = curve_mc_chainages(snapped)
|
||||
return round(placed / STATION_M) * STATION_M
|
||||
|
||||
|
||||
def test_less_bad_spot_avoids_slope() -> None:
|
||||
"""가까운 측점 자리가 기울기를 크게 늘리면 다음 측점 자리."""
|
||||
assert _snap(_Slope(steep=0.30, flat=0.0)) == 120.0
|
||||
|
||||
|
||||
def test_all_ruined_takes_least_ruin() -> None:
|
||||
"""모든 자리가 크게 망치면 그중 가장 덜 망치는 자리 · MC 는 측점에."""
|
||||
assert _snap(_Slope(steep=0.20, flat=0.40)) == 100.0
|
||||
assert _snap(_Slope(steep=0.40, flat=0.20)) == 120.0
|
||||
|
||||
|
||||
@pytest.mark.parametrize("version, found", [(ALGO_VERSION - 1, False), (ALGO_VERSION, True)])
|
||||
def test_other_version_not_read(tmp_path, version: int, found: bool) -> None:
|
||||
folder = store_dir(tmp_path)
|
||||
folder.mkdir(parents=True)
|
||||
data = {"version": version, "source": "s", "pool": "p", "request": {}, "result": {}}
|
||||
(folder / "k.json").write_text(json.dumps(data), encoding="utf-8")
|
||||
got = read_stored_any(tmp_path, "p", lambda source: "k")
|
||||
assert (got is not None) is found
|
||||
|
||||
|
||||
def test_ruin_threshold_constants() -> None:
|
||||
from B05_Profile.B05_Profile_Engine_RouteInitial_Station import RUIN_GAP_M, RUIN_RISE
|
||||
|
||||
assert RUIN_RISE == pytest.approx(0.05) and math.isclose(RUIN_GAP_M, STATION_M / 2)
|
||||
Reference in New Issue
Block a user