Files
Aislo/docs/raw/plans/2026-07-18_plan_B04_old_align.md
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

8.3 KiB

이관 계획서 (Archived Plan)

  • 이관 일자: 2026-07-18
  • 대상 작업: B04 전처리를 old 버전 방식으로 정렬 (2026-07-18)
  • 상태: 완료 및 검증 완료로 활성 계획에서 이관

배경

old 버전(0_old/main.py + 0_old/utils/)은 업로드 직후 구조화→필터 4종→모델 15종→등고선 캐시→VWorld/GIS를 전부 사전 처리하고 문제없이 동작했다. 본 프로그램(B04)은 계산 코어를 그대로 포팅했으나 old의 3가지 장치가 빠졌고 등고선 캐시 간격이 어긋나 있었다:

  1. 지면 마스크 영구 저장(mask_*.npy) 없음 → 매 분석·미리보기마다 CSF/PMF 재계산
  2. structured.npz 존재 시 스킵 로직 없음 → 구조화 무조건 재실행
  3. 엔진 계층 로그 0건 + 백그라운드 트리거에 진행률 콜백 미전달 → 침묵 상태로 수 분 소요
  4. 등고선 사전 캐시 5.0m vs 프론트 요청 1.0m 불일치(작업 트리에서 1.0m로 수정됨) + on-demand 재계산이 adaptive_contour_grid_resolution(old에 없음)을 사용

방향: 최대한 old 방식을 따른다. old에 없는 신규 장치는 삭제한다. 문제가 생기면 그때 변경한다.

저장 위치 매핑 (old → 본 프로그램)

old (instance/{proj}/) 본 프로그램 ({project_root}/B04_wf1_Surface/)
structured.npz processed/structured.npz (기존 동일)
mask_{filter}.npy processed/mask_{filter}.npy (신규 저장)
terrain_models/* (모델·manifest·등고선) models/* (기존 동일)
vworld_*, GIS geojson processed/* (기존 동일)

완료 구현 체크리스트

A. 마스크 영구 저장·재사용B04_wf1_Surface_Engine.py

  • A-1. run_surface_analysis: 필터별 processed/mask_{filter}.npy 존재+길이 일치 시 np.load(mmap_mode="r") 재사용, 없으면 계산 후 np.save. force=True면 재계산
  • A-2. cache_ground_points: mask 미전달 시 build_ground_masks 대신 저장된 mask_{filter}.npy 우선 로드 (없을 때만 필터 실행 후 저장)

B. 구조화 스킵 + 입력 세대 검증B04_wf1_Surface_Engine.py

  • B-1. structured.npz 존재 && force=Falsestructurize_las 스킵 (old upload_files 스킵 로직과 동일 원리)
  • B-2. 입력 LAS 정체성(파일명+크기+mtime)을 structured.npz(또는 sidecar json)에 기록, 불일치 시 구조화·마스크·모델 캐시를 force 취급으로 무효화 — old는 업로드마다 새 프로젝트 폴더라 이 문제가 없었으나 본 프로그램은 같은 폴더를 재사용하므로 필수

C. 로깅·진행률 복원 (old의 print 진행 표시를 logger로 대체)

  • C-1. run_surface_analysis: 단계별 시작/완료 logger.info + 소요시간(구조화/필터별/모델빌드/VWorld/GIS/총계)
  • C-2. VWorld·GIS 다운로드 except: passlogger.warning으로 실패 사유 기록 (old는 print로 출력했음)
  • C-3. build_all_terrain_models 호출 시 progress reporter 연결 (_report 래핑, 70~90% 구간 배분)
  • C-4. B03 trigger_wf1_analysis_and_email: on_progress 콜백 전달 → write_surface_progress로 progress.json 갱신 (업로드 자동 전처리도 진행률 노출)

D. 등고선 old 정합B04_wf1_Surface_Engine_Contour.py, B04_wf1_Surface_Router_Contour.py, B04_wf1_Surface_Engine_Pipeline.py

  • D-1. adaptive_contour_grid_resolution 삭제, on-demand 재계산도 old처럼 config 고정 격자(SURFACE_CONTOUR_GRID_RESOLUTION_M=1.0) 사용
  • D-2. NURBS 스플라인 s=0 → old 공식 s=len(control_x)*len(control_y)*0.01 복귀 (추출 로직을 old와 동일화; CONTOUR_EXTRACTOR_VERSION=4는 유지해 기존 캐시 전면 재생성)
  • D-3. Pipeline 캐시 재사용 분기: dtm/tin은 _smooth_ 등고선 파일 존재도 검사해 누락 시 재생성 (프론트 기본값이 스무딩 ON이므로)
  • D-4. 사전 캐시 간격 1.0m 유지 (작업 트리 수정분 유지 — old config와 동일)
  • D-5. 모델 (재)빌드 직전 해당 stem의 contour_{filter}_{method}*.json 전부 삭제 + 라우터 캐시 검사에 "모델 npz mtime > 등고선 캐시 mtime → 재계산" 추가 — 같은 경로를 세대 구분 없이 재사용하므로 구세대 등고선 잔존 방지 (외부 검토 지적 채택)
  • D-6. SURFACE_MODEL_PRECOMPUTE 순서를 dtm 우선으로 변경 — TIN 등고선 사전 캐시가 dtm_{filter}.npz footprint를 참조하는데 tin이 먼저 빌드되면 footprint 미적용으로 캐시됨. old도 tin 우선이라 동일 결함이 있었으나 저비용 개선이므로 채택 (외부 검토 지적 채택)

E. 이상한 것 삭제·정리

  • E-1. run_surface_analysis의 3중 .prj glob(**/*.prj 재귀 포함) 제거 → B03 입력 폴더에서 명시적 1회 탐색
  • E-2. 재분석 시 해당 프로젝트의 surface_models 기존 행 삭제 후 INSERT — 실측 결과 한 프로젝트에 121행 누적, 전부 동일 파일 경로를 가리키며 디스크에는 일부만 존재(중단된 분석). 화면은 이 목록의 첫 매치를 선택하므로 "파일 없는 모델 선택 → 프리뷰/등고선 404"가 미반영 증상의 1차 원인 중 하나 (외부 검토 실측 채택)

F. config 파라미터 old 값 복귀config/config_system.py (변경 시 config_signature 변경 → 모델 캐시 전면 재빌드됨)

  • F-1. SURFACE_IMPLICIT_MAX_POINTS_PER_TILE 20000→10000, SURFACE_IMPLICIT_SMOOTHING 0.5→0.1
  • F-2. SURFACE_TIN_MAX_INPUT_POINTS 200000→500000, SURFACE_MAX_PREVIEW_VERTICES 120000→500000
  • F-3. SURFACE_MESHFREE_MAX_MODEL_POINTS 300000→500000, SURFACE_MESHFREE_POINT_RADIUS_M 0.5→0.15

G. 프론트 경합 보완 (소규모)B04_wf1_Surface_UI_TerrainViewer.ts

  • G-1. GLTF/PLY 로더 콜백에 요청 세대 토큰 가드 추가 — 선택 변경 후 늦게 도착한 이전 메쉬가 scene에 겹쳐 남는 문제 차단 (등고선 fetch에는 이미 가드 있음)

H. 코딩 후 실측 테스트에서 발견·해결한 추가 문제 (2026-07-18 오후)

  • H-1. TIN/meshfree 등고선 수 분 소요·행(Hang)의 진짜 원인 = scipy 버전: venv의 scipy 1.13.1에서 scipy.spatial.Delaunay.transform(무게중심 변환 지연 계산)이 97만 심플렉스 기준 114~280초 소요 (실측). old 환경은 scipy 1.18.0(0_old/requirements.txt, UTF-16 인코딩 주의)이라 빨랐음. old 데이터를 현재 venv에 넣어도 동일하게 느린 것으로 교차 검증 완료 → 데이터·코드 문제 아님. 조치: venv scipy를 1.16.3(현재 numpy 1.26.4와 호환되는 최신)으로 업그레이드, requirements.txt 핀 1.13.1→1.16.3 갱신. transform 15.8초로 단축, TIN 등고선 1개당 25~27초. 완전한 old 동등(scipy 1.18)을 위해서는 numpy 2.x 마이그레이션 필요 → Backlog 참조
  • H-2. 진단 과정에서 _grid_axes를 float64로 바꿨다가 오진으로 판명되어 old와 동일한 float32로 원복 (H-1이 진짜 원인; 최종 작업 트리에서 이 함수는 무변경)
  • H-3. 분석 중 서버 프로세스 침묵 소멸의 원인 = uvicorn 자동 리로드: .envDEBUG=Truemain.py:268reload=DEBUG 활성화 → 분석 도중 .py 파일이 저장되면 백그라운드 분석 스레드째 재시작(2회 재현 확인). 조치: .env DEBUG=False로 변경 + 사유 주석 추가
  • H-4. 전처리 전체 재개 실측 검증 완료 (프로젝트 storage/1/3/acb9…, cloud_merged.las 606만 지면점): 15개 모델 + 등고선 캐시 21개 + VWorld 3종 + GIS 벡터 6종 전부 생성, manifest completed, 실패 0, 총 433초 (구조화 스킵·마스크 3종 캐시 재사용 각 0.03초·dtm 1종 캐시 재사용 상태 기준. 전체 신규 계산 시 구조화 ~2분 추가 예상). A·B·C·D 캐시/스킵/로그/진행률 로직 동작 확인됨

완료된 백로그 (Completed Backlog)

  • TIN coverage 마스크 rasterio.features.rasterize 대체 검토 (2026-07-18): B04_wf1_Surface_Engine_Contour.py_tin_face_coverage_mask 함수 내에서 shapely union_allintersects_xy 연산의 오버헤드를 줄이기 위해 rasterio의 rasterize 방식으로 전환 완료. (Delaunay transform 병목 해소와 병행해 성능 체감 효과 확보)