Files
Aislo/resources/tester/test_edge_trim_3m_yonghwa.py
T
eomsangdonandClaude Opus 5 1a82df951f revert(tester): 서식만 바뀐 남의 시험 파일 25개 되돌림
ruff 글로브를 `resources/tester/*.py` 로 넓게 잡아 내 작업과 무관한 시험 파일까지
서식이 바뀌었음. 다른 창이 그 파일을 만지면 충돌만 남으므로 되돌림.
내가 실제로 고친 다섯(열쇠 장부·Z01 둘·표 읽기·못 읽은 표)만 남김.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QsGw1Dz9HmhuAxGisxmDPF
2026-09-17 19:42:32 +09:00

133 lines
4.8 KiB
Python

"""절단 여유 30m → 3m 로 낮췄을 때 끝단 지반고가 튀지 않는지 (2026-09-04 사용자 지시).
용화_LAS 프로젝트의 확정 지표면으로 실측한다. 판정은 「3m 로 남긴 양 끝 20m 구간의
지반고 변화율이 노선 안쪽 구간과 같은 수준인가」 — 가장자리 점 밀도가 떨어져 값이
못 미더우면 여기서 눈에 띄게 튄다.
"""
import asyncio
import math
import sys
from pathlib import Path
import pytest
ROOT = Path(__file__).resolve().parents[2]
sys.path.append(str(ROOT))
PROJECT_ID = "5cff3920-a181-4a3d-bec0-e0ac4082b75d" # 용화_LAS
def _project_root_and_surface():
import aiomysql
from config.config_db import DB_HOST, DB_NAME, DB_PASSWORD, DB_PORT, DB_USER
from common_util.common_util_storage import resolve_stored_project_path
async def run():
conn = await aiomysql.connect(
host=DB_HOST, port=DB_PORT, user=DB_USER, password=DB_PASSWORD,
db=DB_NAME, charset="utf8mb4",
)
try:
async with conn.cursor(aiomysql.DictCursor) as cursor:
await cursor.execute(
"SELECT storage_path FROM projects WHERE id = %s", (PROJECT_ID,)
)
row = await cursor.fetchone()
from common_util.common_util_surface_confirmation import get_surface_confirmation_params
params = await get_surface_confirmation_params(conn, PROJECT_ID)
return row, params
finally:
conn.close()
row, params = asyncio.run(run())
if not row:
pytest.skip("용화_LAS 프로젝트가 없습니다.")
return Path(resolve_stored_project_path(row["storage_path"])), params
def _sample_z(sampler, points):
import numpy as np
z, valid = sampler.sample_xy(np.asarray(points, dtype=np.float64))
return np.asarray(z, dtype=float), np.asarray(valid, dtype=bool)
def _slopes(sampler, points):
"""이웃 정점 사이 지반고 변화율(m/m) 목록."""
z, valid = _sample_z(sampler, points)
out = []
for i in range(1, len(points)):
if not (valid[i] and valid[i - 1]):
continue
d = math.dist(points[i - 1], points[i])
if d > 0.5:
out.append(abs(z[i] - z[i - 1]) / d)
return out
def _head_tail_within(points, metres):
"""양 끝에서 `metres` 안에 드는 정점만."""
acc = [0.0]
for i in range(1, len(points)):
acc.append(acc[-1] + math.dist(points[i - 1], points[i]))
total = acc[-1]
head = [p for p, a in zip(points, acc) if a <= metres]
tail = [p for p, a in zip(points, acc) if total - a <= metres]
return head, tail, total
def test_edge_trim_3m_ends_are_not_spiky():
from common_util.common_util_route_geometry import (
find_planned_route_file,
read_planned_route,
trim_route_to_surface,
)
from common_util.common_util_surface_sampler import build_surface_sampler
from B04_PreProcess.B04_PreProcess_Engine_Extent import project_epsg_from_prj
project_root, params = _project_root_and_surface()
route_file = find_planned_route_file(project_root / "B03_FileInput" / "input")
if route_file is None:
pytest.skip("계획노선 파일이 없습니다.")
planned = read_planned_route(route_file)
points = [(float(v.x), float(v.y)) for v in planned.vertices]
target_crs = project_epsg_from_prj(project_root)
source_crs = planned.crs_input or target_crs
if source_crs.upper() != target_crs.upper():
from pyproj import Transformer
transformer = Transformer.from_crs(source_crs, target_crs, always_xy=True)
points = [transformer.transform(x, y) for x, y in points]
sampler = build_surface_sampler(
project_root / "B04_PreProcess" / "models",
str(params["source_filter"]),
str(params["method"]),
bool(params["smooth"]),
)
trimmed_30 = trim_route_to_surface(points, sampler, 30.0)
trimmed_3 = trim_route_to_surface(points, sampler, 3.0)
assert len(trimmed_3) >= 2
head, tail, total_3 = _head_tail_within(trimmed_3, 20.0)
_, _, total_30 = _head_tail_within(trimmed_30, 20.0)
print(f"\n연장: 30m 트림 {total_30:.1f}m / 3m 트림 {total_3:.1f}m (차이 {total_3 - total_30:.1f}m)")
inner = _slopes(sampler, trimmed_3[len(trimmed_3) // 4 : 3 * len(trimmed_3) // 4])
ends = _slopes(sampler, head) + _slopes(sampler, tail)
assert inner and ends
inner_max = max(inner)
ends_max = max(ends)
print(f"지반고 변화율 최대: 안쪽 {inner_max:.3f} / 양 끝 20m {ends_max:.3f}")
# 끝단이 안쪽보다 크게 튀지 않아야 한다(가장자리 밀도 저하 확인).
assert ends_max <= max(inner_max * 1.5, inner_max + 0.05)
def test_config_default_is_3m():
from config.config_system_terrain import SURFACE_ROUTE_EDGE_TRIM_M
assert SURFACE_ROUTE_EDGE_TRIM_M == 3.0