Files
Aislo/resources/tester/test_edge_trim_3m_yonghwa.py
T
eomsangdonandClaude Opus 5 d7cb14f416 test(B08): tmp/tests 중 tester 에 없던 47 개를 resources/tester 로 옮김
tmp/ 가 창끼리 안 건너가는 것이 확정돼(랩탑이 시간 두고 두 번 확인) 시험·예외가
저절로 건너가도록 git 안으로 옮김. 사용자 확정.

- 내용은 하나도 안 고침 — 자리만 옮김. tmp/tests 는 남겨 둠.
- 같은 이름이 이미 있던 64 개는 랩탑 것을 그대로 두고 건너뜀.
- helper_b05_*.js 둘은 랩탑이 .cjs 로 이미 올린 것과 **줄바꿈만 다른 같은 내용**이라
  복사본을 도로 뺌(시험이 .cjs 를 부름).
- resources/tester/ 에서 전체 1176 통과 · 29 건너뜀 · 실패 0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-09 17:15:57 +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