Files
Aislo/docs/raw/plans/2026-08-31_plan_planned_route_shapefile_prj.md
T
eomsangdonandClaude Opus 5 eb30b774f8 chore(docs): docs 폴더 git 추적 전환 · PLAN·OWNERS 최상위 이관
- `docs/` 를 .gitignore 에서 빼 git 추적 대상으로 전환 (위키·완료 이력·검증 기록)
- `docs/raw/PLAN.md` · `docs/raw/OWNERS.md` 를 저장소 최상위로 이동 후 .gitignore 에 등록
  — 창끼리 공유하되 저장소에는 안 올리는 장부
- 살아 있는 경로 참조 7개 파일 정정 (아카이브 107건은 그때 사실이라 그대로 둠)
- graphify 날짜별 산출물(`docs/wiki/graphify-out/20*/`) 제외 — `graphify update` 가 다시 만듦

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-09 18:19:07 +09:00

6.6 KiB

계획노선 shapefile 입력 + PRJ 2개 분리

원본: docs/raw/PLAN.md의 「계획노선 shapefile 입력 + PRJ 2개 분리」. 검증 대기 상태로 이관했다. 남은 좌표계 기본값 일원화는 PLAN.md 「프로젝트 작업 좌표계 일원화」에 있다.

배경: 원청 정식 계획노선이 shapefile(UTM-K)로, 지형 자료가 별도 PRJ(동부원점 Bessel)로 들어왔다. 실측 — 노선 bbox를 지형 계로 옮기면 TFW 원점(208,288.84 / 368,092.28) 안쪽에 정확히 앉는다(노선 1,241m × 454m). 기존 입력 경로는 ① shapefile 확장자를 아예 막고 ② PRJ를 프로젝트당 1개로 전제했다.

설계 원칙 (2026-08-31 사용자 확정):

  • EPSG 코드로 구분하지 않는다. 모르는 좌표계가 들어와도 돌아야 한다 — 판별은 라벨일 뿐이고 변환은 crs_input_from_prj()가 주는 값(EPSG 확정 시 "EPSG:n", 아니면 원문 WKT)으로 한다. 실측: 이번 PRJ 2종 모두 to_epsg()가 None인데 WKT↔WKT 변환은 정확했다.
  • PRJ 짝은 폴더로 가른다. shapefile은 규격상 형제 파일이 같은 basename·같은 폴더에 있어야 GDAL이 연다. 세트를 input/shp/에 두면 노선 PRJ가 그 안에, 지형 PRJ는 input/prj/에 남아 파일명 정렬 운에 기대지 않고 갈린다.
  • 노선은 2D로 받는다. 업로드 shp는 PolyLine(type 3), Z 없음, 121정점. 지반고는 이미 build_surface_sampler()+sample_xy()가 확정 서피스에서 뽑는다 (B05_Profile_Engine_Sections_Core.py:135). CSV의 z는 참조값이라 z=0으로 채운다.
  • 파일 하나에 카드 한 장. 노선 파일이 5개면 카드도 5개다(2026-08-31 사용자 지시).

구현 (커밋 fe72ea04 · 36e4decf + 2열 개편, 브랜치 feat/b03-route-shapefile):

  • A. 업로드 허용에 .shp .shx .dbf .cpg 추가(py·ts). 한 번에 보낼 파일 수 5 → 10 (화면의 카드 수 한도도 10으로).
  • B. B03_FileInput_Engine_Shapefile.py 신설 — ESRI 규격 직접 파싱(GDAL 미사용). 형제 파일이 아직 안 와도 .shp 하나로 기하를 읽는다. .cpg 내용이 949뿐인 실물을 CP949로 정규화. analyze_input_metadata()에 .shp 분기.
  • C. read_planned_route()로 CSV·shapefile 일원화, find_planned_route_file()은 shapefile 우선. PlannedRoute.crs_input 추가(변환 입력), epsg는 라벨로 유지.
  • D. shapefile 세트를 input/shp/에 모으고(resolve_upload_destination + reconcile_shapefile_members), find_project_prj()가 지형 PRJ를 프로젝트 좌표계로 고른다. project_epsg_from_prj()·B04_PreProcess_Engine.py의 glob()[0] 제거.
  • E. 필수 세트를 "노선 1종(csv|shp) + prj + tfw"로 완화, shp면 shx·dbf· 노선 PRJ 동반 필수. 재접속 현황에 relative_path를 실어 노선 PRJ를 route_prj로 따로 세게 했다 — 지형 PRJ 없이 통과하던 구멍을 막았다.
  • F. UI — 컨테이너 2개 · 파일마다 카드 한 장
    • 왼쪽 「계획노선 자료」: csv(.csv·.shp) · shx · dbf · cpg · route_prj
    • 오른쪽 「지형 자료 (LAS)」: las_laz · prj(지형 좌표계) · tfw · tif
      • LAS 없는 설계 토글
    • .prj만 확장자로 안 갈린다 — 노선 도형과 basename이 같으면 노선 좌표계 카드, 아니면 지형 카드(planSlotAssignments). 재접속 현황은 저장 경로로 가린다.
    • 형제 카드는 노선 도형이 shapefile일 때만 필수 — "· 선택" 꼬리표가 실시간으로 붙고 떨어진다.
    • 처음엔 슬롯 하나에 세트를 담았으나(companions) 사용자 지시로 갈아엎었고, 슬롯=파일 하나인 기존 구조가 그대로 살아 업로드 루프도 원래대로 돌아왔다.

자체검증 — tmp/tests/test_route_shapefile_input.py 9개 전부 통과 (./venv/Scripts/python.exe -m pytest tmp/tests/ -q, 2026-08-31):

  • 실물 파서: PolyLine 1파트·121정점·전 정점 z=0 ✓
  • .cpg가 949뿐인 실물 → CP949 정규화, 속성 대상지=일월.용화.2.2·길이=2.200 ✓
  • 노선 PRJ는 to_epsg()가 None → crs_input이 원문 WKT, 라벨만 5179 ✓
  • 노선(UTM-K) → 지형 PRJ 변환이 TFW 원점 안쪽, 연장 2,000~2,300m(속성 2.2km와 일치) ✓
  • CSV·shapefile 공존 시 shapefile 우선, 노선명은 dbf 속성에서 ✓
  • 노선 PRJ 파일명이 정렬상 앞서도(a_route.prj < z_terrain.prj) 지형 PRJ 선택 ✓
  • PRJ가 SHP보다 먼저 도착한 순서도 세트 폴더로 끌어오고 지형 PRJ는 그대로 ✓
  • 필수 세트: shp면 shx·dbf·route_prj 요구, 지형 PRJ 없으면 차단, CSV 기존 흐름은 그대로 통과(회귀) ✓
  • npx tsc --noEmit 통과, ruff check·ruff format 통과
  • 전체 스위트 잔여 실패 11건은 기존 실패 — git archive HEAD 사본에서 같은 11건이 동일하게 실패한다(B05 구조물·B06 포장·B07 토적도·PRJ 실물경로). 실패 테스트 중 이번에 고친 모듈을 import하는 것은 없다.
  • 화면 검증(공용 브라우저, 백엔드 재시작 + 캐시 비우기 + reload): 실물 7파일 (노선 5 + 지형 prj·tfw)을 한 번에 떨어뜨려 배정 실측 — route.prj는 노선 좌표계 카드, terrain.prj는 지형 카드로 정확히 갈렸다. shx·dbf·route_prj의 "· 선택"이 사라지고 cpg만 남았다. 업로드 버튼은 LAS 미선택이라 비활성(정상). 조작한 화면은 새로고침으로 되돌렸다 — 업로드 버튼은 누르지 않았다.
  • 카드 제목이 한글 글자 단위로 3줄까지 접히던 것을 word-break: keep-all + 헤더 flex-wrap으로 고쳤다 — 카드 9개 전부 1줄로 실측.

계획 대비 차이·남긴 것:

  • 임시 보관함(is_batch_required_complete)은 확장자만 알아 노선/지형 PRJ를 못 가린다 — 묶음 완료 판정은 shx·dbf까지만 본다. 프로젝트 업로드 경로는 경로로 갈라 정확.
  • B04_PreProcess_Engine_SheetSurface.py의 planned.epsg or 5186은 그대로 뒀다 — 좌표계 기본값 산재는 아래 「프로젝트 작업 좌표계 일원화」 몫이다.
  • 미실행: 실제 프로젝트에 자료를 올려 끝까지 도는 종단 확인은 사용자 프로젝트 데이터를 건드려서 하지 않았다 — 지시가 있으면 시험 프로젝트로 수행한다.
  • 미실행: prettier는 돌리지 않았다. 대상 파일이 원래 prettier 형식이 아니라 파일 전체가 재포맷돼(로케일 200줄 이상) 변경분이 묻힌다. 새 코드는 주변 서식에 맞췄다.