# -*- coding: utf-8 -*- """노선 추천 균형 종단 — 본 설계와 같은 횡단 · 누가토량 ±500㎥(PLAN 78). 랩탑 메인 노선 271: 추천은 곡선표 확폭 · 비탈 안 닫힘 넓힘을 빼 성토를 4,200㎥ 적게 봄. """ import numpy as np from B05_Profile.B05_Profile_Engine_RouteInitial_Profile import ( CROSS_HALF_M, _station_areas, _widenings, route_profile, route_sections, ) from B05_Profile.B05_Profile_Engine_RouteInitial_Search import Terrain from config.config_system_design import curve_widening_m def _steep() -> Terrain: # 노선(y = 200) 왼쪽(+y)으로 70 % 내리막 — 성토 비탈(1:1.5)이 ±20 m 안에서 안 닫힘 x = np.arange(0.0, 202.0, 2.0) y = np.arange(120.0, 282.0, 2.0) xx, yy = np.meshgrid(x, y) z = 100.0 - 0.7 * (yy - 200.0) + 0.02 * xx return Terrain(x, y, z, np.ones(xx.shape, dtype=bool)) def test_곡선표가_있으면_그_반경으로_확폭(): xy = np.array([(0.0, 0.0), (40.0, 0.0), (80.0, 0.0)]) chain = np.array([0.0, 40.0, 80.0]) at = np.array([0.0, 20.0, 40.0, 60.0, 80.0]) table = [{"start": [30.0, 0.0], "apex": [40.0, 1.0], "end": [50.0, 0.0], "radius_m": 12.0}] rows = _widenings(xy, chain, at, table) assert rows[2]["curve_widening_m"] == curve_widening_m(12.0) assert rows[2]["plan_radius_m"] == 12.0 # 곡선표 없으면 직선(반경 실측 없음) — 확폭 0 assert all(row["curve_widening_m"] == 0 for row in _widenings(xy, chain, at)) def test_비탈_안_닫히면_넓힌_샘플로_셈(): at, ground, sections, modes, curves = route_sections([(20.0, 200.0), (180.0, 200.0)], _steep()) i = len(at) // 2 samples = sections[i] assert max(s["offset_m"] for s in samples) > CROSS_HALF_M # 반폭 밖까지 떠 둠 narrow = [s for s in samples if abs(s["offset_m"]) <= CROSS_HALF_M] high = float(ground[i] + 3.0) # 쌓기 — 내리막 쪽 성토 비탈이 길어짐 _, _, wide_fill = _station_areas(samples, modes[i], high, curves[i]) _, _, narrow_fill = _station_areas(narrow, modes[i], high, curves[i]) assert wide_fill > narrow_fill + 1.0 def test_누가토량_끝값은_허용_안(): profile = route_profile( [(20.0, 200.0), (180.0, 200.0)], _steep(), max_grade=0.14, design_speed=20 ) assert profile["exact"] is True assert abs(profile["mass_end_m3"]) <= profile["mass_tolerance_m3"] == 500.0 assert profile["balanced"] is True