Files
Aislo/resources/tester/test_75_profile_strip.py
T
eomsangdonandClaude Opus 5.5 0deeb52e9a fix(B05): 노선 추천 균형 종단을 본 설계 횡단과 맞춤 — 곡선표 확폭 · 비탈 안 닫힘 넓힘 · 암반 경계 · 누가토량 ±500㎥(78)
- 확폭은 노선 곡선표로(후보 · 편집 띠 · [확인]) · 없으면 종전 실측 반경
- 반폭에서 비탈이 안 닫히면 지표면 끝까지 넓힌 샘플로 다시 셈(본 설계 extend_unclosed 와 같은 뜻)
- 암반 경계 기본 오프셋(본 설계 기본 설계와 같음)
- 균형 목표 = 누가토량 끝값(절토 다짐 − 성토) ±500㎥ · 고른 선은 보간 말고 바로 셈해 λ 를 더 좁힘
- 후보 줄 세우기는 보간값 그대로(빠름) · 화면에 낼 선만 바로 셈
- 추천 창 한 줄: 불균형 % → 누가토량 ±㎥

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019EMfGERKUg5nMMNQsyVZ2j
2026-10-07 23:08:43 +09:00

103 lines
3.9 KiB
Python

"""편집 창 종단 띠 — [확인]과 같은 노선 점으로 균형 종단을 셈한다(PLAN 75-1).
./venv/Scripts/python.exe -m pytest resources/tester/test_75_profile_strip.py -q
"""
import asyncio
from pathlib import Path
from uuid import uuid4
from B05_Profile import B05_Profile_Router_Replan as replan
from B05_Profile import B05_Profile_Router_RouteInitial as initial
from common_util.common_util_route_geometry import read_planned_route_csv
NODES = [(0.0, 0.0), (120.0, 35.0), (180.0, 140.0), (310.0, 150.5)]
RADIUS_M = 25.0
def _strip_points(monkeypatch, tmp_path: Path, criteria=None) -> tuple[list, object]:
seen: dict = {}
async def paths(_pid):
return tmp_path, "x"
async def plan_criteria(_pid):
return RADIUS_M, 0.0, 0.0
async def profile_of(_pid, _root, points, crit, curves=None):
seen["points"], seen["criteria"], seen["curves"] = points, crit, curves
return {"stations_m": [0.0, 20.0], "plan_m": [1.0, 2.0]}
monkeypatch.setattr(replan, "_project_paths", paths)
monkeypatch.setattr(replan, "_plan_criteria", plan_criteria)
monkeypatch.setattr(initial, "balanced_profile_of", profile_of)
request = initial.ProfilePreviewRequest(
vertices=[
replan.RouteVertexInput(x=x, y=y, curve=i != 2, radius_m=40.0 if i == 1 else None)
for i, (x, y) in enumerate(NODES)
],
criteria=criteria,
)
answer = asyncio.run(initial.profile_preview(uuid4(), request))
assert answer["profile"]["plan_m"] == [1.0, 2.0]
return seen["points"], seen["criteria"]
def test_띠_노선점은_확인이_읽는_CSV와_같다(monkeypatch, tmp_path: Path) -> None:
points, _ = _strip_points(monkeypatch, tmp_path)
working = tmp_path / "planned_route.csv"
replan._write_planned_polyline(
working,
NODES,
RADIUS_M,
simplify=False,
curve_flags=[True, True, False, True],
radii=[None, 40.0, None, None],
)
stored = read_planned_route_csv(working)
assert stored is not None
assert [(p["x"], p["y"]) for p in points] == [(v.x, v.y) for v in stored.vertices]
assert len(points) > len(NODES) # 원호가 펴져 있다
def test_띠는_그_노선의_곡선표로_확폭을_맨다(monkeypatch, tmp_path: Path) -> None:
seen: dict = {}
async def paths(_pid):
return tmp_path, "x"
async def plan_criteria(_pid):
return RADIUS_M, 0.0, 0.0
async def profile_of(_pid, _root, _points, _crit, curves=None):
seen["curves"] = curves
return {"stations_m": [0.0, 20.0], "plan_m": [1.0, 2.0]}
monkeypatch.setattr(replan, "_project_paths", paths)
monkeypatch.setattr(replan, "_plan_criteria", plan_criteria)
monkeypatch.setattr(initial, "balanced_profile_of", profile_of)
request = initial.ProfilePreviewRequest(
vertices=[
replan.RouteVertexInput(x=x, y=y, curve=i != 2, radius_m=40.0 if i == 1 else None)
for i, (x, y) in enumerate(NODES)
]
)
asyncio.run(initial.profile_preview(uuid4(), request))
assert seen["curves"] and 40.0 in [c["radius_m"] for c in seen["curves"]]
assert all({"start", "apex", "end", "radius_m"} <= set(c) for c in seen["curves"])
def test_띠는_지금_추천_제약을_싣는다(monkeypatch, tmp_path: Path) -> None:
criteria = replan.RouteInitialCriteria(max_grade_pct=12.0)
_, got = _strip_points(monkeypatch, tmp_path, criteria)
assert got.max_grade_pct == 12.0
def test_확인_목표는_같은_셈의_측점_계획고(monkeypatch, tmp_path: Path) -> None:
async def profile_of(*_args):
return {"stations_m": [0.0, 20.0, 31.5], "plan_m": [5.0, 6.0, 6.5], "cut_m3": 1.0}
monkeypatch.setattr(initial, "balanced_profile_of", profile_of)
target = asyncio.run(initial.balanced_target(uuid4(), tmp_path, [], None))
assert target == ([0.0, 20.0, 31.5], [5.0, 6.0, 6.5])