- `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>
101 lines
13 KiB
Markdown
101 lines
13 KiB
Markdown
---
|
||
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 벡터 데이터들이 모두 정상적으로 다운로드됨을 확인함.
|