- 노선 꼭짓점 z: 한 칸 값 · 빈칸 0.0 대신 build_surface_sampler · 빈칸 · 밖은 이웃 정점 누가거리 보간 · 모두 밖이면 멈춤 - 종단 미리보기 · [확인] 균형 목표: 2 m 비용면 대신 1 m 표본기(추천 점수 비용면은 그대로) - 시험 test_342_4_ground_unify.py Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013QyNXY2TUKXCFMwAca2APG
67 lines
3.2 KiB
Python
67 lines
3.2 KiB
Python
"""342-4 지반고 값 갈림 맞춤 — 노선 꼭짓점 z · 종단 미리보기가 공용 1 m 표본기와 같은 값.
|
|
|
|
./venv/Scripts/python.exe -m pytest resources/tester/test_342_4_ground_unify.py -q
|
|
"""
|
|
|
|
from pathlib import Path
|
|
|
|
import numpy as np
|
|
import pytest
|
|
|
|
from B05_Profile.B05_Profile_Engine_AsPlanned import solve_as_planned
|
|
from B05_Profile.B05_Profile_Engine_RouteInitial_Profile import route_sections
|
|
from common_util.common_util_surface_sampler import DtmGridSampler, build_surface_sampler
|
|
|
|
|
|
def _grid(tmp_path: Path) -> Path:
|
|
"""1 m 남짓 고르지 않은 축 · 기울어진 면 · 가운데 빈칸 한 덩이."""
|
|
x = np.cumsum(np.r_[0.0, np.full(120, 1.0) + 0.03 * np.sin(np.arange(120))])
|
|
y = np.cumsum(np.r_[0.0, np.full(80, 1.0) + 0.02 * np.cos(np.arange(80))])
|
|
xx, yy = np.meshgrid(x, y)
|
|
z = 100.0 + 0.1 * xx + 0.05 * yy + np.sin(xx / 7.0)
|
|
valid = np.ones(z.shape, dtype=bool)
|
|
valid[38:42, 58:62] = False
|
|
models = tmp_path / "B04_PreProcess" / "models"
|
|
models.mkdir(parents=True)
|
|
np.savez(models / "dtm_classification.npz", x=x, y=y, z=z, valid_mask=valid)
|
|
return models
|
|
|
|
|
|
def test_꼭짓점_z_는_공용_표본기_값(tmp_path: Path) -> None:
|
|
models = _grid(tmp_path)
|
|
vertices = [(5.3, 10.7), (40.2, 30.9), (60.0, 40.0), (100.4, 60.2)] # 셋째 = 빈칸
|
|
result = solve_as_planned(tmp_path, "classification", False, vertices, {})
|
|
z = [p[2] for p in result["polyline"]]
|
|
expect, valid = build_surface_sampler(models, "classification", "dtm", False).sample_xy(
|
|
np.asarray(vertices)
|
|
)
|
|
assert valid.tolist() == [True, True, False, True]
|
|
assert np.allclose([z[0], z[1], z[3]], expect[[0, 1, 3]], atol=1e-9)
|
|
# 빈칸은 0.0 이 아니라 이웃 정점 사이 누가거리 보간
|
|
chain = np.concatenate([[0.0], np.cumsum(np.hypot(*np.diff(vertices, axis=0).T))])
|
|
assert z[2] == pytest.approx(np.interp(chain[2], chain[[1, 3]], expect[[1, 3]]))
|
|
assert min(z) > 50.0
|
|
|
|
|
|
def test_꼭짓점_모두_밖이면_멈춤(tmp_path: Path) -> None:
|
|
_grid(tmp_path)
|
|
with pytest.raises(ValueError):
|
|
solve_as_planned(tmp_path, "classification", False, [(-50.0, -50.0), (-20.0, -40.0)], {})
|
|
|
|
|
|
def test_종단_미리보기_지반은_1m_쌍선형(tmp_path: Path) -> None:
|
|
models = _grid(tmp_path)
|
|
sampler = DtmGridSampler.from_npz(models / "dtm_classification.npz")
|
|
vertices = [(10.0, 40.0), (110.0, 40.0)] # 가운데 빈칸을 지남
|
|
at, ground, sections, _modes, _curves = route_sections(vertices, sampler)
|
|
for chain, row in zip(at, sections):
|
|
cx = 10.0 + chain
|
|
offsets = np.array([s["offset_m"] for s in row])
|
|
z, valid = sampler.sample_xy(np.column_stack([np.full(offsets.size, cx), 40.0 + offsets]))
|
|
assert [s["valid"] for s in row] == valid.tolist()
|
|
got = np.array([np.nan if s["elevation_m"] is None else s["elevation_m"] for s in row])
|
|
assert np.allclose(got[valid], z[valid], atol=1e-9)
|
|
assert all(s["elevation_m"] is None for s, ok in zip(row, valid) if not ok)
|
|
# 중심 빈칸 측점의 지반고는 이웃 측점 보간 — 0.0 · 평균 표고로 안 메움
|
|
assert np.isfinite(ground).all() and ground.min() > 50.0
|