- `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>
90 lines
10 KiB
Markdown
90 lines
10 KiB
Markdown
# PLAN: B04 결함 수정 6건 + 확정 흐름 주의점 보완 (2026-07-17)
|
|
|
|
## 활성 작업: B04 결함 수정 6건 + 확정 흐름 주의점 보완 (2026-07-17)
|
|
|
|
### A. 지면 필터 미리보기가 원본 데이터를 표시 (핵심 결함)
|
|
- **현상**: 지면 필터를 선택해도 필터링 후 데이터가 아닌 원본에서 50만 개를 샘플해 표시
|
|
- **원인 (확인됨)**:
|
|
- `GET .../surface/point-cloud`가 `structured.npz`(지면 필터 **이전** 구조화 원본)를 고정 조회 — `B04_wf1_Surface_Router.py:332`. 필터 파라미터 자체가 없음
|
|
- 지면 필터 마스크는 분석 중 메모리에서만 생성·사용되고 **영구저장되지 않음** — `B04_wf1_Surface_Engine.py:77-85` (`build_ground_masks` → 모델 빌드에 전달 후 소멸)
|
|
- **0_old 검증 프로그램의 방식 (준용)**: `create_ground_filter_cache`(`0_old/backend/app/analyzer.py:622-739`)가 분석 시 **필터링된 지면 포인트 자체를 브라우저 상한(0_old는 500만)으로 샘플해 `processed/ground-points.json`으로 영구저장**하고, `GET .../ground-points`(`0_old/backend/app/main.py:166-170`)가 캐시 파일을 그대로 서빙. 요청 시 재계산 없음
|
|
- **수정 방향 (0_old 패턴 준용)**:
|
|
1. Engine: 분석 시 필터별 지면 포인트 캐시를 `processed/ground_points_{filter}.npz`로 영구저장 — 50만 규칙(초과 시 랜덤 50만, 이하 전체) 적용된 미리보기 서빙용. 메타(원본 지면 포인트 수, 샘플 수, bounds) 포함
|
|
2. Router: point-cloud 엔드포인트에 `filter` 쿼리 파라미터 추가 — 지정 시 해당 캐시 파일 서빙, 미지정 시 기존 원본(structured) 동작 유지
|
|
3. Api_Fetch / UI_Page: 지면 필터 선택 변경 시 `filter` 파라미터로 재조회 → 뷰어 렌더
|
|
4. **기존 프로젝트**에는 캐시 파일이 없음 → filter 요청 시 파일 부재면 `structured.npz`로 해당 필터만 온디맨드 재계산 후 캐시 저장(백필)
|
|
5. 경로(B05)·등고선 등 백엔드 분석은 종전대로 전체 필터링 데이터 기준(미리보기 캐시와 무관) 유지
|
|
|
|
### B. 등고선 간격 옵션 미작동
|
|
- **원인 (확인됨)**: 등고선은 분석 시 config 기본 간격(`contour_interval_meters`=5.0m) 파일만 사전 생성 — `B04_wf1_Surface_Engine_Pipeline.py:57-104`. contour 엔드포인트는 **파일 조회 전용**이라 다른 간격 요청 시 파일이 없고, 폴백 glob이 기존 5.0m 파일을 반환 — `B04_wf1_Surface_Router.py:655-662` → **간격 변경이 조용히 무시됨**. 프론트 전달(`interval` 파라미터)은 정상 — `B04_wf1_Surface_UI_TerrainViewer.ts:383-385`
|
|
- **수정 방향**: 요청 간격의 파일이 없으면 저장된 모델 npz로 **온디맨드 등고선 생성 후 파일 캐시 저장**(기존 `Engine_Contour` 함수 재사용, `asyncio.to_thread`). 폴백 glob은 생성 실패 시에만 사용하거나 제거
|
|
|
|
### C. 스무딩 옵션 동작 불명확
|
|
- **확인된 사실**: 프론트 연결은 정상(`smooth` 파라미터 전달 및 토글 시 재로드 — `UI_TerrainViewer.ts:326-329,568-570`). 스무딩은 **tin/dtm 전용**이며 `{stem}_smooth_preview.glb` 사전 생성 파일을 조회(`Router.py:567-570`). nurbs/implicit/meshfree는 토글해도 무동작이 현재 설계
|
|
- **수정 방향**:
|
|
1. 실행 검증: tin/dtm에서 `_smooth_preview.glb`·`contour_*_smooth_*.json` 파일 실존 및 토글 시 메시 교체 여부 확인, 파일 누락 시 Pipeline 생성 경로 수정
|
|
2. UX: 스무딩 미지원 기법(nurbs/implicit/meshfree) 선택 시 토글 비활성화(회색)로 "안 되는 게 아니라 해당 없음"을 명시
|
|
3. 등고선도 스무딩 상태와 간격을 함께 반영(B와 연동)
|
|
|
|
### D. 2D 지도 이미지 왜곡 (그룹 컨테이너에 맞춰 늘어남)
|
|
- **원인 (확인됨)**: `.b04-map__image { object-fit: fill; width/height:100% }` — `B04_wf1_Surface_UI_Style.css:468-478`. VWorld 배경 이미지가 뷰포트(가변 폭 × 고정 560px)에 종횡비 무시로 강제 인장됨. 이전에 보고된 "살짝 대각선" 현상도 이 왜곡이 원인일 가능성 높음
|
|
- **수정 방향**: VWorld 요청 해상도를 뷰포트 실제 크기(종횡비)에 맞춰 요청하거나 `object-fit` 정합 처리 + canvas GeoJSON 오버레이 좌표 변환 동기화. 수정 후에도 대각선 느낌이 남으면 투영 좌표 변환 재점검
|
|
|
|
### F. 두 3D 뷰어 카메라 동기화의 스케일 불일치
|
|
- **현상**: 포인트클라우드 미리보기 ↔ 지표면 표현 뷰어가 함께 움직이긴 하나 배율(스케일)이 서로 다름
|
|
- **원인 (확인됨)**: 카메라 상태를 비율로 주고받는데 **정규화 기준이 서로 다름**
|
|
- Viewer: 데이터를 최대 span=180 고정 공간으로 스케일링(`UI_Viewer.ts:202`)하고 `distanceRatio = distance/180` 고정 기준(`UI_Viewer.ts:165-187`)
|
|
- TerrainViewer: 실좌표 메시의 바운딩박스 span 기준 `distance/sceneSpan`(`UI_TerrainViewer.ts:270-296`)
|
|
- 포인트클라우드 범위(현재는 원본이라 식생 포함 z-range 큼)와 지표면 메시 범위가 달라 같은 비율이 다른 배율로 나타남. A 수정 후에도 기준 데이터 범위가 완전히 같지 않으므로 잔존
|
|
- **수정 방향**: 카메라 상태를 **실세계 좌표(m) 기준 공통 프레임**으로 교환 — 각 뷰어가 자기 월드→씬 변환(Viewer: 180/span 배율+중심점, Terrain: sceneCenter)을 알고 있으므로, emit/apply 시 실좌표(중심 기준 오프셋 m, 거리 m)로 변환해 동기화. 축 방향 컨벤션(Viewer의 x/z/-y 스왑)도 함께 정합
|
|
|
|
### G. 지표면 표현 뷰어가 컨테이너 전체를 사용하지 못함
|
|
- **원인 (확인됨)**: TerrainViewer 렌더 영역에 인라인 `height: 520px` 고정(`UI_TerrainViewer.ts:106`) — 포인트클라우드 뷰어(`.three-viewer` 560px, `UI_Style.css:355-360`)와 불일치하고, 2열 컨테이너 높이와 무관하게 고정됨
|
|
- **수정 방향**: 인라인 높이 제거, 두 뷰어 동일한 CSS 규칙(컨테이너 기준 100% 또는 공통 고정값)으로 통일. ResizeObserver 기반 리사이즈는 이미 구현되어 있어(`UI_TerrainViewer.ts:587-596`) CSS만 정리하면 추종함
|
|
|
|
### E. 확정 흐름 주의점 보완 (2026-07-17 검증에서 발견)
|
|
1. `enableRouteStep`이 진행단계 버튼을 DOM 인덱스 `[2]` 하드코딩으로 탐색(`UI_Page.ts:186-188`) → 스텝 식별자/route 기반 탐색으로 변경 (스텝 순서 변경 시 무음 파손 방지)
|
|
2. 확정 토스트의 `{smoothing}` 값이 `"-"` 고정(`UI_Page.ts:304`) → 실제 스무딩 토글 상태 연결
|
|
3. B04 재진입 시(이미 확정 상태) WF2 스텝 활성화가 서버 workflowState 렌더에 의존 → 확정 → 새로고침 → 스텝 클릭 가능 여부 실행 검증, 불가하면 수정
|
|
4. 잔여 확인: 지면 필터 드롭다운의 `ransac` 제거(`UI_Page.ts:54` `SOURCE_FILTERS`) — 이전 계획 항목이나 현재 코드에 잔존
|
|
5. **확정 성공 시 B05로 자동 이동** (사용자 확정, 2026-07-17): 확정 토스트 표시 후 `goToWorkflowStage`로 WF2(B05) 페이지 자동 전환. 스텝 수동 클릭 대기 방식 폐기 — 단, `enableRouteStep`의 스텝 활성화 처리는 뒤로가기/재진입 대비 유지
|
|
|
|
### 대상 파일
|
|
| 파일 | 작업 |
|
|
|---|---|
|
|
| `B04_wf1_Surface/B04_wf1_Surface_Engine.py` | 필터별 지면 포인트 캐시 영구저장 (A) |
|
|
| `B04_wf1_Surface/B04_wf1_Surface_Router.py` | point-cloud `filter` 파라미터+캐시 서빙 (A), 등고선 온디맨드 생성 (B) |
|
|
| `B04_wf1_Surface/B04_wf1_Surface_Api_Fetch.ts` | point-cloud filter 파라미터 전달 (A) |
|
|
| `B04_wf1_Surface/B04_wf1_Surface_UI_Page.ts` | 필터 선택 → 재조회 연결 (A), E-1·2·4 |
|
|
| `B04_wf1_Surface/B04_wf1_Surface_UI_Viewer.ts` | 카메라 상태 실좌표 변환 (F) |
|
|
| `B04_wf1_Surface/B04_wf1_Surface_UI_TerrainViewer.ts` | 스무딩 토글 UX (C), 카메라 상태 실좌표 변환 (F), 인라인 높이 제거 (G) |
|
|
| `B04_wf1_Surface/B04_wf1_Surface_UI_MapViewer.ts` | 이미지 종횡비 정합 (D) |
|
|
| `B04_wf1_Surface/B04_wf1_Surface_UI_Style.css` | `object-fit` 수정 (D), 뷰어 높이 통일 (G) |
|
|
| `B04_wf1_Surface/B04_wf1_Surface_Engine_Pipeline.py` | (조건부) 스무딩 프리뷰 생성 누락 시 수정 (C) |
|
|
|
|
### 구현 체크리스트
|
|
- [x] A-1. Engine: 분석 시 필터별 `processed/ground_points_{filter}.npz` 캐시 저장 (50만 규칙 + 메타)
|
|
- [x] A-2. Router: point-cloud `filter` 파라미터 + 캐시 파일 서빙
|
|
- [x] A-3. Router: 캐시 파일 부재 시 온디맨드 재계산·백필
|
|
- [x] A-4. Api_Fetch/UI_Page: 필터 선택 → filter 파라미터 재조회·렌더
|
|
- [x] B-1. Router: 요청 간격 등고선 파일 부재 시 온디맨드 생성 + 캐시 저장
|
|
- [x] B-2. 폴백 glob 정리 (간격 무시 무음 동작 제거)
|
|
- [x] C-1. tin/dtm 스무딩 프리뷰·등고선 파일 생성 여부 검증, 누락 시 Pipeline 수정
|
|
- [x] C-2. 스무딩 미지원 기법에서 토글 비활성화
|
|
- [x] D-1. VWorld 이미지 종횡비 정합 + canvas 오버레이 좌표 동기화
|
|
- [x] F-1. Viewer/TerrainViewer: 카메라 상태를 실세계 좌표(m) 공통 프레임으로 emit/apply 변환 (축 컨벤션 정합 포함)
|
|
- [x] F-2. 동기화 배율 일치 실행 검증 (양쪽 축척바 값 비교)
|
|
- [x] G-1. TerrainViewer 인라인 높이 제거, 두 뷰어 높이 통일
|
|
- [x] E-1. enableRouteStep 스텝 탐색 방식 개선
|
|
- [x] E-2. 확정 토스트 스무딩 값 연결
|
|
- [x] E-3. 확정 후 새로고침 시 WF2 스텝 활성화 실행 검증
|
|
- [x] E-4. `SOURCE_FILTERS`에서 `ransac` 제거 확인
|
|
- [x] E-5. 확정 성공 시 B05 자동 이동 (`goToWorkflowStage`)
|
|
- [x] 700줄 제한 및 라우터 분리: `B04_wf1_Surface_Router.py`(643줄), `B04_wf1_Surface_Router_GIS.py`(175줄)로 분할하여 700줄 한계 준수
|
|
- [x] GIS/VWorld 라우터 복원: `B04_wf1_Surface_Router_GIS.py` 유실 복구 및 `main.py` 기동 실패(ImportError) 해결
|
|
|
|
### 협의 완료 (2026-07-17 사용자 확정)
|
|
- **확정 후 자동 이동**: 확정 성공 시 B05 자동 전환으로 확정 → E-5 반영
|
|
- **A-3 백필 방식**: 온디맨드 재계산 채택 — 기존 프로젝트(캐시 파일 없음)에서 필터 첫 선택 시 서버가 `structured.npz`로 해당 필터만 재계산해 캐시 생성 후 응답. 첫 선택에만 수 초 대기 발생, 이후 즉시 표시
|
|
|