fix(B04): 프로젝트 좌표계를 지형 자료와 짝인 PRJ로 고른다
실측 사고(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) <noreply@anthropic.com>
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user