From afc404cbc5580a35b37d90114dc0d44d33fc559b Mon Sep 17 00:00:00 2001 From: umsangdon Date: Mon, 31 Aug 2026 20:10:16 +0900 Subject: [PATCH] =?UTF-8?q?fix(B04):=20=ED=94=84=EB=A1=9C=EC=A0=9D?= =?UTF-8?q?=ED=8A=B8=20=EC=A2=8C=ED=91=9C=EA=B3=84=EB=A5=BC=20=EC=A7=80?= =?UTF-8?q?=ED=98=95=20=EC=9E=90=EB=A3=8C=EC=99=80=20=EC=A7=9D=EC=9D=B8=20?= =?UTF-8?q?PRJ=EB=A1=9C=20=EA=B3=A0=EB=A5=B8=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 실측 사고(2026-08-31): 실제 업로드에서 자동 설계 체인이 B05 경로 계산 400으로 멈췄다. input/prj/ 에 옛 result.prj(KGD2002 East Belt 2010, FN 600,000)가 남아 있었고, find_project_prj 가 이름 정렬 첫 번째를 골라 새 용화.prj(Korean 1985 Modified East Belt, FN 500,000) 대신 그것을 집었다. 그 결과 노선이 Y로 100,000m 어긋나(로그의 bp y=468228.23, 옳은 값 367920.75) 지표면 밖으로 나갔다. 자료를 다시 올려도 파일명이 다르면 옛 PRJ가 그대로 남는다 - 이름 정렬은 어느 것이 지금 쓰는 것인지 알지 못한다. 그래서 지금 쓰는 지형 자료(LAS/LAZ/TIF/TFW)와 basename이 같은 PRJ를 먼저 찾고, 못 찾으면 가장 최근 것을 쓰고 경고를 남긴다. 폴백 경로에서도 노선 세트 폴더(input/shp/)의 PRJ는 제외한다 - 그건 노선 좌표계다. 검증: 실제 프로젝트 폴더로 확인 - 선택이 용화.prj로 바뀌고 노선 시점이 x=208403.20 y=367920.75 로 TFW 원점(208288.84/368092.28) 안쪽에 앉는다. tmp/tests/test_route_shapefile_input.py 10개 통과(회귀 시험 추가), 전체 302 passed. Co-Authored-By: Claude Opus 5 (1M context) --- common_util/common_util_crs.py | 39 ++++++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/common_util/common_util_crs.py b/common_util/common_util_crs.py index 35ff8b5b..fb56efbe 100644 --- a/common_util/common_util_crs.py +++ b/common_util/common_util_crs.py @@ -124,18 +124,45 @@ def identify_epsg(crs: CRS, wkt_text: str | None = None) -> int | None: return None +_TERRAIN_DATA_GLOBS = ("las/*", "laz/*", "tif/*", "tfw/*") + + def find_project_prj(project_root: Path) -> Path | None: """프로젝트 **작업 좌표계**를 정하는 PRJ를 고른다. 자료가 둘 이상의 좌표계로 들어온다(실측 2026-08-31 — 노선 shapefile은 UTM-K, - 지형은 동부원점 Bessel). 서피스 격자가 모델좌표의 주인이므로 지형 PRJ가 우선이고, - 노선 PRJ는 shapefile 세트 폴더(`input/shp/`) 안에 있어 여기서 섞이지 않는다. - 파일명 정렬 순서에 기대던 옛 `glob()[0]`을 대신한다. + 지형은 동부원점 Bessel). 서피스 격자가 모델좌표의 주인이므로 **지형 PRJ**를 쓴다. + 노선 PRJ는 shapefile 세트 폴더(`input/shp/`)에 있어 여기서 섞이지 않는다. + + `input/prj/`에도 PRJ가 여럿 쌓인다 — 자료를 다시 올려도 파일명이 다르면 옛 PRJ가 + 남기 때문이다. 이름 정렬로 고르면 잔재를 집는다(실측 2026-08-31: 옛 `result.prj` + (5187)가 새 `용화.prj`(5176)보다 앞서 뽑혀 노선이 Y로 100,000m 어긋났고 B05 + 경로 계산이 400으로 실패했다). 그래서 **지금 쓰는 지형 자료(LAS·TIF·TFW)와 + basename이 같은 PRJ**를 먼저 찾고, 못 찾으면 가장 최근 것을 쓴다. """ - terrain = sorted(project_root.glob("B03_FileInput/input/prj/*.prj")) - if terrain: - return terrain[0] + prj_dir = project_root / "B03_FileInput" / "input" / "prj" + candidates = sorted(prj_dir.glob("*.prj")) if prj_dir.is_dir() else [] + if candidates: + if len(candidates) == 1: + return candidates[0] + input_root = project_root / "B03_FileInput" / "input" + terrain_stems = { + path.stem + for pattern in _TERRAIN_DATA_GLOBS + for path in input_root.glob(pattern) + if path.is_file() + } + paired = [path for path in candidates if path.stem in terrain_stems] + pool = paired or candidates + chosen = max(pool, key=lambda path: path.stat().st_mtime) + if not paired: + logger.warning( + "지형 자료와 짝이 되는 PRJ를 찾지 못해 가장 최근 PRJ를 씁니다: %s", chosen.name + ) + return chosen remainder = sorted(project_root.glob("B03_FileInput/**/*.prj")) + # 노선 세트 폴더의 PRJ는 노선 좌표계라 프로젝트 좌표계가 될 수 없다. + remainder = [path for path in remainder if path.parent.name != "shp"] or remainder return remainder[0] if remainder else None