From 06f72393a978ccaee606e43ae58efb96e9191e8e Mon Sep 17 00:00:00 2001 From: umsangdon Date: Sun, 30 Aug 2026 18:27:07 +0900 Subject: [PATCH] =?UTF-8?q?fix(B04):=20LAS=20=EC=97=86=EB=8A=94=20?= =?UTF-8?q?=EC=84=A4=EA=B3=84=EC=97=90=EC=84=9C=EB=8F=84=20=ED=99=95?= =?UTF-8?q?=EC=A0=95=20=EC=A7=80=ED=91=9C=EB=A9=B4=20=EB=B2=94=EC=9C=84?= =?UTF-8?q?=EB=A5=BC=20=EB=8F=8C=EB=A0=A4=EC=A4=80=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit /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). --- B04_PreProcess/B04_PreProcess_Router.py | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/B04_PreProcess/B04_PreProcess_Router.py b/B04_PreProcess/B04_PreProcess_Router.py index 00977c5c..a1df3a3d 100644 --- a/B04_PreProcess/B04_PreProcess_Router.py +++ b/B04_PreProcess/B04_PreProcess_Router.py @@ -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(