feat(B03): 계획노선 shapefile 의 CSV 정본화 + LAS 없는 도엽 서피스 좌표계 교정

- 자동설계 체인이 초기값 스냅샷에 `planned_route.csv` 를 함께 남김. 값은 체인이
  이미 만든 정점(사업지 좌표계·트림·조밀화 후)이라 재계산 없음.
- `load_design_route()` 는 surface_params 가 주어진 호출에 한해 그 CSV 정본을 읽음.
  트림 전 원본이 필요한 호출(도엽 범위)은 종전 경로 유지. 지표면·노선이 바뀌면
  `discard_initial_snapshot()` 이 폴더째 지워 경로가 저절로 닫힘.
- `run_sheet_surface_analysis()` 가 노선을 원본 좌표계로 읽어 도엽 서피스를 딴 자리에
  만들던 문제 교정 — `load_design_route()` 로 창구 통일, 도엽 확보 PRJ 탐색도 지형
  PRJ 폴더로 교정. shapefile 노선(5179) + 지형 PRJ(5176) 조합에서 트림이 노선을
  통째로 지우던 원인.

검증: tmp/tests 158 passed(신규 4건 포함), 공용 브라우저 실사용 경로로 용화 shapefile
한 벌 업로드 → 자동 체인 완주 → CSV 정본 643점, 원본 경로와 최대 좌표차 0.00007m.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-03 08:17:21 +09:00
co-authored by Claude Opus 5
parent e065e5701e
commit 56b9bf5280
4 changed files with 63 additions and 11 deletions
@@ -510,7 +510,8 @@ def run_sheet_surface_analysis(
반환 형식은 `run_surface_analysis()`와 같다(save_surface_analysis_to_db 호환).
"""
from common_util.common_util_route_geometry import read_planned_route
from B04_PreProcess.B04_PreProcess_Engine_Extent import project_epsg_from_prj
from common_util.common_util_route_geometry import load_design_route
def _report(percent: int, stage: str, message: str) -> None:
if on_progress is not None:
@@ -522,10 +523,14 @@ def run_sheet_surface_analysis(
processed_dir.mkdir(parents=True, exist_ok=True)
models_dir.mkdir(parents=True, exist_ok=True)
planned = read_planned_route(route_csv_path)
# 노선을 **사업지(.prj) 좌표계로 옮긴 뒤** 도엽을 뜬다. 원본 좌표 그대로 뜨면 노선이
# 5179, 지표면이 5176처럼 갈려 설계 계통(`load_design_route`)이 재투영한 노선이 지표면
# 밖으로 나가고 트림이 노선을 통째로 지운다(2026-09-03 실측: shapefile 노선 + LAS 없는
# 설계). LAS 경로·`build_sheet_surface_from_route`와 같은 창구를 쓰는 것이 요지다.
planned = load_design_route(project_root)
if planned is None or len(planned.vertices) < 2:
raise ValueError(f"계획 노선 파일을 읽지 못했습니다: {route_csv_path.name}")
epsg = planned.epsg or 5186
crs = planned.crs_input or project_epsg_from_prj(project_root)
route_xy = np.array([(v.x, v.y) for v in planned.vertices], dtype=np.float64)
bounds_dict = {
@@ -545,16 +550,15 @@ def run_sheet_surface_analysis(
project_root,
processed_dir,
bounds_dict,
route_csv_path.parent,
# 노선 세트 폴더의 PRJ는 노선 좌표계다 — 지형 PRJ를 고르게 지형 폴더를 준다.
project_root / "B03_FileInput" / "input" / "prj",
rebuild=False,
default_epsg=f"EPSG:{epsg}",
default_epsg=crs,
report=_report,
)
_report(70, "surface_model", "도엽등고선 3D 서피스 생성 중")
models = build_sheet_surface_model(
project_root, processed_dir, models_dir, route_xy, f"EPSG:{epsg}"
)
models = build_sheet_surface_model(project_root, processed_dir, models_dir, route_xy, crs)
if not models:
raise ValueError("도엽등고선으로 지표면을 만들지 못했습니다 — 도엽 확보를 확인하세요.")