fix(B04): LAS 없는 설계에서도 확정 지표면 범위를 돌려준다

/surface/confirmed가 지형 가장자리를 structured.npz 또는
ground_points_{filter}.npz에서만 읽었다. 둘 다 LAS 산출물이라 LAS 없이
설계한 프로젝트에는 없고, bounds가 null로 나가 B05가
"지표면 범위 정보를 찾을 수 없습니다"로 막혀 3D 지형을 못 띄웠다.

두 파일이 없으면 확정 모델 격자(npz)의 bounds를 그대로 쓴다. 도엽 서피스
npz는 이미 같은 형식의 bounds(3×2)를 담고 있다.

검증: 프로젝트 5d18ebe3(LAS 0개) B05 재진입 — /surface/confirmed 200,
preview·contour 요청이 뒤따라 나가고 안내문이 사라짐. 지형·등고선·코리도·
구조물 라벨까지 화면에 뜬 것 확인(152_b05.png).
This commit is contained in:
2026-08-30 18:27:07 +09:00
parent 1d1b1c8c0b
commit 06f72393a9
+19 -1
View File
@@ -432,8 +432,26 @@ async def get_confirmed_surface(project_id: UUID) -> SurfaceConfirmedResponse |
"z_max": float(bounds[2, 1]),
}
# 지도(2D) 초기 화면을 도로 기준으로 맞추기 위한 계획노선 범위(없으면 None).
# LAS 없이 설계한 프로젝트는 위 두 파일이 아예 없다(도엽등고선으로 만든
# 서피스가 정본). 그때는 확정 모델 격자의 bounds를 그대로 쓴다 — 없으면
# B05가 "지표면 범위 정보를 찾을 수 없습니다"로 3D를 못 띄운다(2026-08-30).
project_root = processed_dir.parent.parent
if bounds_payload is None and confirmed and confirmed.get("model_file_path"):
model_path = project_root / str(confirmed["model_file_path"])
if model_path.is_file():
with np.load(model_path) as stored:
if "bounds" in stored:
bounds = np.asarray(stored["bounds"], dtype=np.float64)
bounds_payload = {
"x_min": float(bounds[0, 0]),
"x_max": float(bounds[0, 1]),
"y_min": float(bounds[1, 0]),
"y_max": float(bounds[1, 1]),
"z_min": float(bounds[2, 0]),
"z_max": float(bounds[2, 1]),
}
# 지도(2D) 초기 화면을 도로 기준으로 맞추기 위한 계획노선 범위(없으면 None).
route_bounds = planned_route_bounds(project_root, project_epsg_from_prj(project_root))
signature = "|".join(