Files
Aislo/docs/wiki/pages/B04_PreProcess/B04_backend.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

101 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
status: stable
page_id: B04_PreProcess
related_pages: ["[[B04_PreProcess/B04_frontend]]", "[[B04_PreProcess/B04_api]]", "[[B04_PreProcess/B04_db]]", "[[B04_PreProcess/B04_dependencies]]", "[[B03_FileInput/B03_backend]]", "[[B05_Profile/B05_backend]]", "[[las_free_sheet_surface]]", "[[concepts/drainage_watershed]]", "[[architecture/project_map]]", "[[architecture/workflow_data_flow]]"]
last_updated: 2026-08-30
source: ["docs/raw/plans/2026-08-17_plan_B04_등고선_추출_가속.md", "docs/raw/plans/2026-08-17_plan_B05_box_ui_recommendations.md", "docs/raw/verification/2026-08-17_verify_B04_등고선_추출_가속_교차검증.md", "docs/raw/plans/2026-08-30_plan_las_free_sheet_surface.md", "docs/raw/verification/2026-08-30_verify_las_free_sheet_surface.md"]
---
# B04_PreProcess — Backend
WF1 지표면 분석. LAS 구조화 → 지면 필터 → 지표면 5종 모델 생성 → 스무딩/등고선. 무거운 연산은 `asyncio.to_thread`로 실행. 또한 프로젝트 bounds 기준 1:5,000 수치지형도 도엽 3x3 자동 취득 및 등고선 하강 기반 배수유역 1차 해석 영구저장 캐싱을 전담. B04/B05 배수유역 설계 및 관 편집 데이터 소스(SSOT)가 B04로 단일화되어 관련 API 서빙을 전담합니다.
## 파일 구성 (오케스트레이터/저장소/라우터)
| 파일 | 위치 | 역할 |
|---|---|---|
| `B04_PreProcess_Router.py` | `B04_PreProcess_Router.py` | `/api/projects` 핵심 분석/모델/확정 엔드포인트 및 `GET /confirmed` (0.4KB 확정 지표면 요약, 0.018s 응답) (700줄 한계 규정 준수). |
| `B04_PreProcess_Router_GIS.py` | `B04_PreProcess_Router_GIS.py` | VWorld 이미지, GeoJSON, MVT 타일, 원청 계획선 좌표(`GET /planned-route`), 도엽 벡터 레이어 (raw byte direct 전송 + ETag 적용) 라우터. |
| `B04_PreProcess_Router_Contour.py` | `B04_PreProcess_Router_Contour.py` | 등고선 생성 및 캐시 다운로드 서빙 라우터 (700줄 한계 규정 준수). |
| `B04_PreProcess_Router_Watershed.py` | `B04_PreProcess_Router_Watershed.py` | `GET /{project_id}/drainage/primary-region` 배수유역 1차 해석 및 WAMIS 관측소 수급/지역 분기(본토 관측소 반경10km 최대지점, 제주 등우선) 라우터. |
| `B04_PreProcess_Router_Inflow.py` | `B04_PreProcess_Router_Inflow.py` | **[신설/2026-08-01]** `GET /{project_id}/drainage/road-inflow` 도로 유입 흐름 강도 1m 해상도 곡선, 유입 집중점 마커 및 기여 셀 외곽선 폴리곤 라우터 (700줄 한계 규정 준수). |
| `B04_PreProcess_Router_Basins.py` | `B04_PreProcess_Router_Basins.py` | **[신설/2026-08-01]** 관 매설 지점 및 세부유역 분할 연산 제어 라우터 (`GET/POST/PUT/DELETE /{project_id}/drainage/basins`). (B04/B05 배수 데이터 일원화 통합 라우터) |
| `B04_PreProcess_Schema.py` | `B04_PreProcess_Schema.py` | 요청/응답 Pydantic 검증 |
| `B04_PreProcess_Repository.py` | `B04_PreProcess_Repository.py` | processed_point_cloud/surface_models Raw SQL 및 DB 트랜잭션 헬퍼 |
| `B04_PreProcess_Engine.py` | `B04_PreProcess_Engine.py` | `run_surface_analysis()` 오케스트레이터, 노선 시/종점 기반 도엽 선정(`neighbors_for_points()`), 잔재 zip 정리(`prune_sheets()`) |
## 엔진 서브모듈
| 파일 | 역할 |
|---|---|
| `..._Engine_Structurize.py` | LAS/LAZ 구조화(structured.npz) 및 입력 정체성(파일명+크기+mtime) 캐시 가드 적용 |
| `..._Engine_Ground.py` | 지면 마스크 생성/요약(`build_ground_masks`, `summarize_masks`) |
| `..._Engine_Filter_Grid/CSF/PMF.py` | 지면 필터 3종 |
| `..._Engine_Pipeline.py` | `build_all_terrain_models()` 지표면 모델 파이프라인 + dtm 우선 빌드 + manifest |
| `..._Engine_ModelContext.py` | 모델 공통 컨텍스트/메시 유틸 |
| `..._Engine_ModelBuild.py` | TIN/DTM/NURBS/implicit/meshfree 생성 |
| `..._Engine_Smooth.py` | DTM/TIN 스무딩 |
| `..._Engine_Contour.py` | 저장 TIN faces·meshfree 단일 Delaunay를 공용 `rasterize_triangle_mesh()`로 직접 격자화. float32 UTM 축은 `searchsorted`로 처리하며 15유닛·스무딩을 유지한다. 2026-08-17 검증에서 등고선 27분 39초→77.6초, meshfree·dtm 완전 일치, TIN 정점 0.03~0.07%(화면 확인 후속). |
| `..._Engine_Watershed_Grid.py` | **[배수유역 하강]** 격자 규격, 1차 영역, 셀 마스크 |
| `..._Engine_Watershed_Stream.py` | **[배수유역 하강]** 세류망 노딩·도로 절단·상류 추출 |
| `..._Engine_Watershed_Descent.py` | **[배수유역 하강]** 등고선 하강 potential·방위(32방위) 산출 |
| `..._Engine_Watershed_Flow.py` | **[배수유역 하강]** 세류 burn, 사슬 추적 적/청 판정 |
| `..._Engine_Watershed_Analyze.py` | **[배수유역 하강]** ①~⑧ 배수유역 오케스트레이션 + 유입 집중점 `find_inflow_hotspots()` 산출 + 평균 화살표(10m ... 원형 평균) 백엔드 산출 |
## 주요 함수 (Router / Repository / Engine / Utility)
| 함수 | 위치 | 역할 |
|---|---|---|
| `get_road_inflow()` | `B04_PreProcess_Router_Inflow.py` | `GET /api/projects/{id}/drainage/road-inflow`: 도로 유입 흐름 강도 1m 해상도 노출 및 기여 셀 외곽선 폴리곤(`polygonize_labels`) 조회 |
| `find_inflow_hotspots()` | `B04_PreProcess_Engine_Watershed_Analyze.py` | 관 최소 간격(20m) 양 편측 제외 그리디 기반 유입 집중점 마커 위치 산출 |
| `get_planned_route()` | `B04_PreProcess_Router_GIS.py` | `GET /api/projects/{id}/planned-route`: 2D 배경 지도 표기용 B03 원청 계획노선 CSV 2D 좌표 추출 및 CRS 변환 API |
| `get_confirmed_surface()` | `B04_PreProcess_Router.py:372` | `GET /api/projects/{id}/surface/confirmed`: B05 수신량 절감을 위한 0.4KB 확정 지표면 요약 fast-path API |
| `get_drainage_basins()` | `B04_PreProcess_Router_Basins.py` | `GET /api/projects/{id}/drainage/basins`: 관 매설 정보(`pipe_points.json`) 및 세부유역(`04_detailed_basins.geojson`) 데이터 조회 API (B04/B05 공용) |
| `update_drainage_basins()` | `B04_PreProcess_Router_Basins.py` | `POST /api/projects/{id}/drainage/basins`: 관 매설 포인트 편집 및 임시 세부유역 분할 계산 API (`common_util_drainage_detail` 공용 엔진 연동, B04/B05 공용) |
| `confirm_drainage_basins()` | `B04_PreProcess_Router_Basins.py` | `PUT /api/projects/{id}/drainage/basins`: 세부 배수유역 구조 확정 및 `pipe_points.json`/`04_detailed_basins.geojson` 최종 영구보존 API (B04/B05 공용) |
| `delete_drainage_basins()` | `B04_PreProcess_Router_Basins.py` | **[신설/2026-08-02]** `DELETE /api/projects/{id}/drainage/basins`: 관 매설 저장분 및 세부유역 GeoJSON 물리적 디스크 삭제 및 자동배치 갱신 API (B04/B05 공용) |
| `_apply_recommendations()` | `B04_PreProcess_Router_Basins.py` | 자동 배치 관에 추천 관경·시설을 넣고 사용자 변경값·기존 옵션을 보호 |
| `analyze_surface()` | `B04_PreProcess_Router.py:88` | 분석 실행: start_stage → clear_confirmed_surface_models → to_thread(run_surface_analysis) → save_surface_analysis_to_db |
| `confirm_surface()` | `B04_PreProcess_Router.py:206` | 모델 수동 확정: 트랜잭션 내에서 기존 `CONFIRMED` 행들을 `COMPLETE`로 되돌리고, 선택된 모델을 `CONFIRMED`로 변경 후 `complete_stage` 호출 (SYSTEM_ADMIN 전용) |
| `confirm_surface_selection()` | `B04_PreProcess_Service.py:39` | 재사용 가능한 확정 서비스 헬퍼: CONFIRMED 처리, stage 1 params 스냅샷 저장 및 `complete_stage(1)` 수행 (API 및 자동 확정이 공유) |
| `get_surface_confirmation_params()` | `common_util_surface_confirmation.py:42` | 확정 params 스냅샷 조회: 스냅샷이 존재하면 이를 우선 사용하고, 없으면 config 기본값으로 폴백 조회 (B05 등 연동 경로 통합 경유) |
| `merge_surface_confirmation_params()` | `common_util_surface_confirmation.py:66` | 기존 stage 1 params에 확정 선택값 전체를 병합 저장 |
| `save_surface_analysis_to_db()` | `B04_PreProcess_Repository.py:336` | processed_point_cloud + surface_models INSERT (호출자 트랜잭션) |
| `delete_project_surface_models()` | `B04_PreProcess_Repository.py:321` | 재분석 시 이전 세대의 유령 모델 정보 누적 방지를 위해 기존 surface_models 삭제 |
| `get_wf1_analysis_status()` | `B04_PreProcess_Router.py:369` | 상태 조회(project_workflow_stages 우선, 폴백) |
| `_cache_contours_safely()` | `B04_PreProcess_Engine_Pipeline.py:111` | 등고선 캐시 오류 발생 시에도 모델 빌드 프로세스가 롤백되지 않도록 경고 로깅 처리 |
## 수치지형도 도엽 오버레이 아키텍처 (2026-07-26, 2026-08-01 S8 개편)
* **도엽 zip 영구보존 및 processed/map_sheets/**: VWorld를 통해 다운로드한 도엽 zip 원본 및 인덱스 메타(`map_sheets_index.json`)는 `{프로젝트 영구저장소}/B04_PreProcess/processed/map_sheets/` 경로에 보관하며, `prune_sheets()`를 통해 21개 비대상 잔재 zip을 자동 정리합니다.
* **노선 시/종점 기준 도엽 선정**: 기존 LAS 전체 bounds 기반 도엽 선정 대신 `neighbors_for_points()`를 구현하여 계획노선 시/종점 좌표 기반 도엽 합집합을 선정하여 불필요한 도엽 수집을 최소화합니다.
* **크롭 철회 및 raw byte 서빙**: 사용자 요청에 따라 도엽 잘라내기(크롭)를 철회하고 원본 등고선 전송을 유지하며, JSON 재직렬화 대신 raw byte direct 전송 및 ETag 304 응답 처리(`B04_PreProcess_Router_GIS.py`, 2.0s -> 0.006s)를 적용했습니다.
* **위성사진 범위 확대 (`SURFACE_MAP_MARGIN_TILES = 3`)**: 위성사진 타일 여유폭을 3타일로 확장하고 타임스탬프(`_t=`)를 제거하여 ETag/304 응답을 활성화했습니다.
* **VWorld 취득 자동화**: 검색 API(무로그인)와 다운로드 API(자격증명 `.env` `VWORLD_LOGIN_ID/PW` 활용 세션 로그인)를 파이썬 백엔드에서 오케스트레이션하여, 세션 만료 시에도 무인 구동하도록 재로그인 1회 재시도 정책을 포함합니다.
## 워크플로우 상태 전이 및 자동 확정
일반 역할(`role != "SYSTEM_ADMIN"`)인 경우 B03 분석이 끝난 시점에 백엔드에서 비동기 스레드 바깥(`B03_FileInput_Service_WF1.py`)에서 `confirm_surface_selection()`을 자동 호출하여 모델을 자동 확정하고 stage 1 `COMPLETE`를 격발합니다.
* **complete_stage(1) 호출 지점 일원화**: 기존 B03 라우터에서 분석 직후 stage 1 COMPLETE를 시키던 결함을 해결하고, 수동/자동 확정 서비스 내부로 일원화하였습니다.
* **스텝바 disabled 및 진입 가드**: 일반 사용자는 B04 페이지 진입이 차단되며(disabled 처리), URL 강제 진입 시 stage 1 완료 여부에 따라 B05 또는 B03으로 분기 리다이렉트됩니다.
* **uvicorn 로깅 부작용 완치**: status API 폴링에 따른 access_log 전면 차단 옵션(`access_log=False`)을 롤백하고, 일반 사용자 B04 진입 차단으로 인해 근본적인 로깅 비대화 문제가 해결되었습니다.
## ⚙️ 설정 및 환경 파일 정합성
* **.env**: uvicorn 자동 리로드로 인해 백그라운드 분석 스레드가 침묵 소멸하는 리스크 차단을 위해 `DEBUG=False`로 변경
* **config/config_system.py**:
* `SURFACE_CONFIRM_DEFAULT_FILTER="csf"`, `SURFACE_CONFIRM_DEFAULT_METHOD="dtm"` 등 자동 확정 기본값 설정 관리
* `SURFACE_MODEL_PRECOMPUTE` 순서에서 `dtm` 최우선 빌드되도록 조정
* 수치 정합성 기준치 old 버전 값(implicit/TIN/meshfree 등)으로 원복
* 기본 등고선 사전 캐시 간격을 1.0m로 유지하도록 `SURFACE_CONTOUR_INTERVAL_M=1.0` 설정
* **requirements.txt**: 현행 `scipy==1.18.0`. meshfree Delaunay 생성에는 사용하지만 등고선 격자 평가의 `find_simplex` 병목은 직접 삼각망 래스터화로 우회
## 📋 구현 예외 처리 검토 항목 (PLAN)
* **자동 확정 세션 분리**: 백그라운드 스레드 에러 방지를 위해 `confirm_surface` 트랜잭션을 로그인 세션 의존성 없이 DB 커넥션과 파라미터만 받는 독립 비동기 함수로 격리 설계.
* **등고선 간격 포맷 통일**: 부동소수점 오차로 인한 캐시 미인식 및 중복 연산 방지를 위해 등고선 간격은 API 및 파일 경로 조회 시 항상 소수점 1자리(예: `1.0`)로 포맷팅하여 통일.
## 2D/GIS 미표시 원인 분석 및 조치
* **PRJ 파일 부재로 인한 지도 다운로드 silent 스킵**: `B04_PreProcess_Engine_VWorld.py``download_vworld_satellite_map``.prj` 파일 부재 시 별도 예외 없이 즉시 `None`을 반환하여 위성 지도 및 메타데이터 생성이 무산됨.
* **좌표계 불일치(5186 ↔ 5187)로 인한 WFS API 빈 피처 반환**: `.prj` 파일이 없어 기본 투영을 `EPSG:5186`(중부원점)으로 가정하여 좌표 변환을 하였으나, 업로드 데이터의 실제 투영계는 `EPSG:5187`(동부원점)이었음. 이에 따라 BBOX 범위가 실제 범위에서 완전히 왜곡(바다 등)되어 브이월드 WFS API가 빈 GeoJSON 파일만 생성함.
* **검증 및 해결**: 수동 진단 스크립트(`scratch/test_vworld_download.py`)를 통해 정확한 PRJ 경로(`B03_FileInput/input/prj/result.prj`)와 정합 좌표계를 입력한 경우 위성 지도와 국가 GIS 벡터 데이터들이 모두 정상적으로 다운로드됨을 확인함.