This commit is contained in:
2026-07-15 18:33:33 +09:00
parent 6b1583103f
commit f533082537
201 changed files with 19776 additions and 563 deletions
@@ -0,0 +1,43 @@
---
status: stable
page_id: B04_wf1_Surface
related_pages: ["[[B04_wf1_Surface/B04_backend]]", "[[B04_wf1_Surface/B04_frontend]]", "[[B04_wf1_Surface/B04_db]]", "[[B04_wf1_Surface/B04_dependencies]]"]
last_updated: 2026-07-12
---
# B04_wf1_Surface — API
실제 라우터 prefix: `/api/projects` (`B04_wf1_Surface_Router.py:41`). 총 12개 엔드포인트.
> ⚠️ 이전 계획서 기반 api.md에는 "추정 경로 surface/analyze·models 2개"로만 기재됐으나,
> 실 코드는 아래 12개(분석·모델·미리보기·등고선·VWorld·GeoJSON 포함). 실 코드 채택(규칙6).
## 엔드포인트
| 엔드포인트 | 위치 | 역할 |
|---|---|---|
| `POST /{project_id}/surface/analyze` | `B04_wf1_Surface_Router.py:147` | LAS 구조화+지면필터+모델생성 실행, DB 기록, WF1 stage 전이 |
| `GET /{project_id}/surface/models` | `B04_wf1_Surface_Router.py:241` | 생성된 지표면 모델 목록 |
| `GET /{project_id}/surface/input-files` | `B04_wf1_Surface_Router.py:260` | 분석 대상 LAS/LAZ 입력파일 목록 |
| `GET /{project_id}/surface/point-cloud` | `B04_wf1_Surface_Router.py:279` | 3D 미리보기용 포인트클라우드 샘플 |
| `GET /{project_id}/surface/ground-stats` | `B04_wf1_Surface_Router.py:341` | 필터별 지면 포인트 통계 |
| `GET /{project_id}/surface/status` | `B04_wf1_Surface_Router.py:372` | WF1 분석 상태 조회 (workflow_state 우선, 레거시 폴백) |
| `GET /{project_id}/surface/models/{model_id}/preview` | `B04_wf1_Surface_Router.py:484` | 모델 미리보기 |
| `GET /{project_id}/surface/models/{model_id}/contour` | `B04_wf1_Surface_Router.py:557` | 등고선 생성/조회 |
| `GET /{project_id}/vworld-meta` | `B04_wf1_Surface_Router.py:643` | VWorld 배경지도 메타 |
| `GET /{project_id}/vworld-map` | `B04_wf1_Surface_Router.py:676` | VWorld 배경지도 타일 |
| `GET /{project_id}/geojson` | `B04_wf1_Surface_Router.py:712` | GIS 벡터 GeoJSON |
## 요청/응답 스키마 (Pydantic)
| 모델 | 위치 | 역할 |
|---|---|---|
| `SurfaceAnalyzeRequest` | `B04_wf1_Surface_Schema.py:16` | input_file_id, source_filters?, methods?, force. resolved_filters/methods로 화이트리스트 검증 |
| `SurfaceAnalyzeResponse` | `B04_wf1_Surface_Schema.py:97` | ground_summary, manifest_status, surface_model_ids |
| `SurfaceModelSummary` / `SurfaceModelListResponse` | `B04_wf1_Surface_Schema.py:45,107` | 모델 요약/목록 |
| `SurfaceInputFileSummary` / `...ListResponse` | `B04_wf1_Surface_Schema.py:56,69` | 입력파일 요약/목록 |
| `SurfacePointCloudSampleResponse` | `B04_wf1_Surface_Schema.py:77` | 포인트클라우드 샘플(bounds/points/rgb) |
| `SurfaceGroundStatsResponse` | `B04_wf1_Surface_Schema.py:89` | 필터별 통계 |
- 공통 오류 포맷 `{"status":"error","message":...}` → [[schema_common]]
- 분석 파라미터 화이트리스트: `SURFACE_MODEL_SOURCE_FILTERS`+`ransac`, `SURFACE_MODEL_PRECOMPUTE` (config_system)
@@ -0,0 +1,71 @@
---
status: stable
page_id: B04_wf1_Surface
related_pages: ["[[B04_wf1_Surface/B04_frontend]]", "[[B04_wf1_Surface/B04_api]]", "[[B04_wf1_Surface/B04_db]]", "[[B04_wf1_Surface/B04_dependencies]]", "[[B03_FileInput/B03_backend]]", "[[B05_wf2_Route/B05_backend]]"]
last_updated: 2026-07-12
---
# B04_wf1_Surface — Backend
WF1 지표면 분석. LAS 구조화 → 지면 필터 → 지표면 5종 모델 생성 → 스무딩/등고선. 무거운 연산은 `asyncio.to_thread`로 실행.
## 파일 구성 (오케스트레이터/저장소/라우터)
| 파일 | 위치 | 역할 |
|---|---|---|
| `B04_wf1_Surface_Router.py` | `B04_wf1_Surface_Router.py:1-739` | `/api/projects` 12개 엔드포인트 → [[B04_wf1_Surface/B04_api]] |
| `B04_wf1_Surface_Schema.py` | `B04_wf1_Surface_Schema.py:1-113` | 요청/응답 검증 |
| `B04_wf1_Surface_Repository.py` | `B04_wf1_Surface_Repository.py:1-236` | processed_point_cloud/surface_models Raw SQL |
| `B04_wf1_Surface_Engine.py` | `B04_wf1_Surface_Engine.py:27` | `run_surface_analysis()` 오케스트레이터(구조화→필터→모델빌드) |
## 엔진 서브모듈
| 파일 | 역할 |
|---|---|
| `..._Engine_Structurize.py` | LAS/LAZ 구조화(structured.npz) |
| `..._Engine_Ground.py` | 지면 마스크 생성/요약(`build_ground_masks`, `summarize_masks`) |
| `..._Engine_Filter_Grid/CSF/PMF/RANSAC.py` | 지면 필터 4종 |
| `..._Engine_Pipeline.py` | `build_all_terrain_models()` 지표면 모델 파이프라인 + manifest |
| `..._Engine_ModelContext.py` | 모델 공통 컨텍스트/메시 유틸 |
| `..._Engine_ModelBuild.py` | TIN/DTM/NURBS/implicit/meshfree 생성 |
| `..._Engine_Smooth.py` | DTM/TIN 스무딩 |
| `..._Engine_Contour.py` | 등고선 생성 |
| `..._Engine_GisVector.py` / `..._Engine_VWorld.py` / `..._Engine_MvtHelper.py` | GIS 벡터 / VWorld 배경지도 / MVT 헬퍼 |
## 주요 함수 (Router)
| 함수 | 위치 | 역할 |
|---|---|---|
| `analyze_surface()` | `B04_wf1_Surface_Router.py:147` | 분석 실행: start_stage→to_thread(run_surface_analysis)→DB저장→complete_stage |
| `save_surface_analysis_to_db()` | `B04_wf1_Surface_Router.py:90` | processed_point_cloud + surface_models INSERT (호출자 트랜잭션) |
| `get_wf1_analysis_status()` | `B04_wf1_Surface_Router.py:372` | 상태 조회(project_workflow_stages 우선, 폴백) |
| `update_project_status()` | `B04_wf1_Surface_Router.py:76` | ⚠️ 정의만 있고 **호출처 없음**(죽은 코드, grep 확인) |
## 워크플로우 상태 전이
analyze 흐름에서 `project_workflow_stages`(stage 1) 전이:
- `start_stage(cursor, project_id, 1, params)``B04_wf1_Surface_Router.py:168`
- `complete_stage(cursor, project_id, 1)``B04_wf1_Surface_Router.py:209`
- `fail_stage(cursor, project_id, 1, err)``B04_wf1_Surface_Router.py:227,233`
→ SSOT 정의·전파 규칙 → [[workflow_state]]
## ⚠️ 레거시 폴백 (416,420줄)
`get_wf1_analysis_status()``project_workflow_stages`**우선** 조회하고,
행이 없을 때만(백필 미작동 대비) `projects.status` 문자열 비교로 폴백:
- 416줄 `project_status == "WF1_COMPLETE"`, 420줄 `"WF1_ANALYZING"` (`B04_wf1_Surface_Router.py:412-427`)
이전 wiki는 "구형 잔재, 정리 필요"로 표기했으나, 실제로는 정상 경로가 아닌 **방어적 폴백**.
SSOT가 안정화되면 제거 가능하나 현재는 백필 안전장치로 동작 중.
## 책임
LAS 구조화·지면 필터 → 변환 포인트클라우드 저장 → 지표면 5종 모델 생성 → 스무딩/등고선/미리보기 → 모델 확정 및 하위 단계(B05) stale 전파([[workflow_state]]).
## 의존성
- [[common_util]] — `common_util_workflow_state`(start/complete/fail_stage), 저장소 경로 헬퍼
- 외부 라이브러리 → [[B04_wf1_Surface/B04_dependencies]]
- DB → [[B04_wf1_Surface/B04_db]]
- config: `SURFACE_MODEL_SOURCE_FILTERS`, `SURFACE_MODEL_PRECOMPUTE`, `build_surface_model_config`
+34
View File
@@ -0,0 +1,34 @@
---
status: stable
page_id: B04_wf1_Surface
related_pages: ["[[B04_wf1_Surface/B04_backend]]", "[[B04_wf1_Surface/B04_api]]", "[[B04_wf1_Surface/B04_dependencies]]", "[[db_schema/files_surface]]"]
last_updated: 2026-07-12
---
# B04_wf1_Surface — DB
이 페이지가 쓰는 테이블 (정의는 concepts에, 여기선 용도만).
## 쓰는 테이블
| 테이블 | 이 페이지의 용도 | 정의 |
|---|---|---|
| `processed_point_cloud` | 필터/변환된 포인트클라우드 저장(input_files 참조) | [[db_schema/files_surface]] |
| `surface_models` | TIN/DTM/NURBS/implicit/meshfree 모델 메타데이터 | [[db_schema/files_surface]] |
| `terrain_layers` | 등고선 등 파생 레이어 | [[db_schema/files_surface]] |
| `project_workflow_stages` | WF1(stage 1) 상태 전이·조회 | [[workflow_state]] |
| `input_files` | 분석 대상 LAS/LAZ 조회 | [[db_schema/files_surface]] |
| `projects` | (레거시 폴백) status 조회 | [[db_schema/projects]] |
## Repository 함수
| 함수 | 위치 | 역할 |
|---|---|---|
| `create_processed_point_cloud()` | `B04_wf1_Surface_Repository.py` | processed_point_cloud INSERT |
| (surface_models INSERT) | `B04_wf1_Surface_Repository.py` | 모델별 메타데이터 저장 |
| `get_input_file()` | `B04_wf1_Surface_Repository.py` | 입력 LAS 단건 조회 |
## 참고
- `save_surface_analysis_to_db()`([[B04_wf1_Surface/B04_backend]])가 processed_point_cloud + surface_models를 한 트랜잭션으로 저장(호출자가 begin/commit)
- WF1 단계 판정 SSOT는 `project_workflow_stages`. `projects.status`는 레거시 폴백 경로에서만 참조 → [[workflow_state]]
@@ -0,0 +1,34 @@
---
status: stable
page_id: B04_wf1_Surface
related_pages: ["[[B04_wf1_Surface/B04_backend]]", "[[B04_wf1_Surface/B04_frontend]]", "[[dependencies]]"]
last_updated: 2026-07-12
---
# B04_wf1_Surface — Dependencies
이 페이지가 쓰는 외부 라이브러리 (공통 정의는 [[dependencies]]).
## 백엔드 (Python)
| 라이브러리 | 용도 |
|---|---|
| Laspy | LAS/LAZ 구조화 |
| Whitebox / Rasterio | 지면 필터·DEM 처리 |
| Trimesh | TIN/메시 모델 |
| Geopandas / Shapely | GIS 벡터(GeoJSON, 등고선) |
| NumPy | structured.npz 등 배열 연산 |
→ 공통 정의·버전 → [[dependencies]]
## 프론트엔드 (TypeScript)
| 라이브러리 | 위치 | 용도 |
|---|---|---|
| **three.js** | `B04_wf1_Surface_UI_Viewer.ts:1`, `..._TerrainViewer.ts` | WebGL 3D 뷰어(WebGLRenderer, OrbitControls, THREE.Points/Mesh) |
## ⚠️ dependencies concept 정정 필요
[[dependencies]]의 "HTML5 Canvas / WebGL — WebCAD 렌더링 (B04~B06 뷰어, **현재 미구현**)"은
실 코드와 불일치. B04는 three.js로 3D 뷰어가 **구현됨** → [[B04_wf1_Surface/B04_frontend]].
dependencies.md에 three.js 항목 추가·"미구현" 문구 정정 필요 (B05/B06 뷰어 상태는 각 페이지 인제스트 시 확인).
@@ -0,0 +1,66 @@
---
status: stable
page_id: B04_wf1_Surface
related_pages: ["[[B04_wf1_Surface/B04_backend]]", "[[B04_wf1_Surface/B04_api]]", "[[B04_wf1_Surface/B04_dependencies]]", "[[ui_templates]]"]
last_updated: 2026-07-12
---
# B04_wf1_Surface — Frontend
WF1 지표면 분석 화면. 워크플로우 레이아웃(필터/표현 폼 + 모델 목록) + **three.js 기반 3D 뷰어**(포인트클라우드/지형).
## 파일 구조
| 파일 | 위치 | 역할 |
|---|---|---|
| `B04_wf1_Surface_UI_Page.ts` | `B04_wf1_Surface_UI_Page.ts:1-377` | 페이지 조립 + 분석 실행/폴링/뷰어 렌더 |
| `B04_wf1_Surface_UI_Viewer.ts` | `B04_wf1_Surface_UI_Viewer.ts:1-567` | 포인트클라우드 3D 뷰어(three.js) |
| `B04_wf1_Surface_UI_TerrainViewer.ts` | `B04_wf1_Surface_UI_TerrainViewer.ts:1-637` | 지형 메시 3D 뷰어(three.js) |
| `B04_wf1_Surface_Api_Fetch.ts` | `B04_wf1_Surface_Api_Fetch.ts:1-174` | surface API 클라이언트 |
| `B04_wf1_Surface_UI_Style.css` | `B04_wf1_Surface_UI_Style.css` | 폼 그룹/모델 카드/뷰어 스타일 |
## ⚠️ 계획서와 실 코드 불일치 (3D 뷰어)
이전 wiki(계획서 기반)는 **"WebCAD 3D 뷰어 미구현"**으로 기재했으나,
실 코드에는 three.js(WebGL) 기반 뷰어가 **구현되어 있음**:
- `createSurfacePointCloudViewer` (`B04_wf1_Surface_UI_Viewer.ts:187` WebGLRenderer, OrbitControls, THREE.Points)
- `createSurfaceTerrainViewer` (`B04_wf1_Surface_UI_TerrainViewer.ts`)
- UI_Page에서 import·인스턴스화(`B04_wf1_Surface_UI_Page.ts:37,38,110,356`)
→ 규칙6, 실 코드 채택. dependencies도 three.js 반영 → [[B04_wf1_Surface/B04_dependencies]]
## 컴포넌트 / 함수
| 함수 | 위치 | 역할 |
|---|---|---|
| `renderB04Surface(root)` | `B04_wf1_Surface_UI_Page.ts:95` | 워크플로우 레이아웃+뷰어 조립(async) |
| `createSurfacePointCloudViewer()` | `B04_wf1_Surface_UI_Viewer.ts:187` | 포인트클라우드 뷰어 핸들 생성 |
| `createSurfaceTerrainViewer()` | `B04_wf1_Surface_UI_TerrainViewer.ts` | 지형 메시 뷰어 핸들 생성 |
## API 클라이언트 함수
| 함수 | 위치 | 대응 API |
|---|---|---|
| `analyzeSurface()` | `B04_wf1_Surface_Api_Fetch.ts:117` | `POST .../surface/analyze` |
| `listSurfaceModels()` | `B04_wf1_Surface_Api_Fetch.ts:128` | `GET .../surface/models` |
| `listSurfaceInputFiles()` | `B04_wf1_Surface_Api_Fetch.ts:134` | `GET .../surface/input-files` |
| `fetchSurfacePointCloud()` | `B04_wf1_Surface_Api_Fetch.ts:142` | `GET .../surface/point-cloud` |
| `fetchSurfaceGroundStats()` | `B04_wf1_Surface_Api_Fetch.ts:153` | `GET .../surface/ground-stats` |
| `fetchSurfaceStatus()` | `B04_wf1_Surface_Api_Fetch.ts:161` | `GET .../surface/status` |
| `getVWorldMapUrl()` / `fetchVWorldMeta()` | `B04_wf1_Surface_Api_Fetch.ts:182,186` | VWorld 배경지도 |
| `fetchGisGeoJson()` | `B04_wf1_Surface_Api_Fetch.ts:192` | `GET .../geojson` |
## 처리 흐름
1. 워크플로우 레이아웃(`createWorkflowLayout`) + 스텝(`workflowSteps`) 조립
2. 입력파일/모델 목록 로드 → 필터·표현 폼 구성
3. 분석 실행(`analyzeSurface`) → 상태 폴링(`fetchSurfaceStatus`)
4. 완료 시 포인트클라우드(`fetchSurfacePointCloud`) → `viewer.render()` (`B04_wf1_Surface_UI_Page.ts:356`)
## 의존성
- [[a00_app_shell_framework]] — `navigateTo`, `workflowSteps`(b_page_scaffold)
- `config_frontend.ts``API_BASE_URL`, `CURRENT_PROJECT_ID_KEY`, `ROUTES`, `RENDER_OPTIONS`, `API_TIMEOUT_MS`
- [[ui_templates]] — `createWorkflowLayout`(ui_template_workflow_layout) 등
- **three.js** (WebGL 3D 뷰어) → [[B04_wf1_Surface/B04_dependencies]]
- 백엔드 API → [[B04_wf1_Surface/B04_api]]