knowledge(요구): 요구서 530 — 예정노선 · B05 평면도 지도 일원화 · 노선 긋기 · 노선추천 미리보기 · 620 고침 + 조사 셋

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015uTVHHDv583hbLQAFeBmd9
This commit is contained in:
2026-10-31 19:14:39 +09:00
co-authored by Claude Opus 5.5
parent 1ba5d49043
commit d6def61f48
4 changed files with 549 additions and 0 deletions
@@ -0,0 +1,172 @@
# 조사 530-A — 예정노선(D03) 지도 · B05 평면도 지도 일원화
근거 = 요구 530(`docs/raw/요구_1025/사용자요구_1025.md:1089-1112`) · 코드 읽기만(화면 실측 없음 — 코드로 충분).
## 0. 한눈에
- 이미 같이 쓰는 것 = GL 지도 틀 `ui_template_gl_map.createGlMap` · 도구줄 틀 `ui_template_map_tools` · 화면 틀 `ViewState`(B04 MapRender) · 휠 · 가운데 끌기(`B05_RouteEdit_Input.bindRouteEditNavigation:58`) · 돌림(`B05_RouteEdit_Rotate.createMapRotation:52`). D03 이 B05 부품을 import 함(`D03_UI_Map.ts:32-34`).
- 따로 짠 것 = **카메라 맞춤 방식** · **겹 목록**(D03 스물 · B05 셋) · **도구줄 차례 · 단추** · GL 켬끔 취향 열쇠 · 지형 원천.
- 겹 자료는 모두 경위도(GeoJSON · 조각 · 네 귀퉁이 그림) → 어느 카메라 방식에서도 GL 이 그대로 그림. 증거 = B05 배수유역 칸이 TM 방식으로 위성 조각을 이미 그림(`B05_UI_Drainage_Gl.ts:69-90`).
- 결론 = 「공용 껍데기(도구줄 표 · 겹 목록 · 범례 · 지형 칩) + 페이지별 카메라 어댑터」 갈래 권함 · 바탕 코드 = D03 겹 쪽.
## 1. 지금 구조
| 칸 | D03 예정노선 | B05 평면도(노선 편집) | 공용 |
|---|---|---|---|
| 지도 뼈대 | `D03_UI_Map.createPlanMap:181`(캔버스 두 장 · 겹 = `PlanMapLayer`) | `B05_UI_RouteEdit_Chrome.createRouteEditChrome:86` + `B05_UI_RouteEdit.ts:118`(캔버스 한 장) | — |
| GL 바탕 | `D03_UI_MapGl.createGlBase:352` → `createGlMap` | `B05_UI_RouteEdit_Gl.createRouteEditGl:50` → `B04_UI_MapGl.createTmGl:56` → `createGlMap` | `ui_template_gl_map.ts:90-220` |
| 카메라 맞춤 | 경위도 정규화(`createNormalizer`) · GL 카메라 = `UI_Map.glCamera:309-320` · TM 그림 = GL 투영에 맞춤(`logic/D03_Tm` `localTmFrame` · `UI_Map.metricFrame:323-340`) | TM 정규화(`createTmNormalizer`) · GL 이 캔버스를 따라감 = 닮음꼴 카메라 + 칸 CSS 행렬(`B04_UI_MapGl.follow:95-116` · `logic/B04_MapGl_Frame.glCameraOf`) | 둘 다 「카메라 주인 = 캔버스 view」 |
| 줌 한도 | 화면 폭 600 km(`UI_Map.ts:65 · 507-513`) | 0.5 배(기본) | `bindRouteEditNavigation` |
| 겹 | 스물(`D03_UI_LayerDefs.GROUPS:59-132`) · 받기 · 차례(`D03_UI_Layers.fetchLayer:424-`) · 범례 · 급경사 범위 · 위성 밝기 · 도엽 조각(`UI_SheetTiles`) · 옛 캔버스 대체(`UI_LayerPaint`) | 셋 = 도엽 하천 · 1 m 선 · 등고선(LAS 5 m 또는 도엽)(`RouteEdit_Gl.ts:73-85`) · 노선 둘레 300 m 띠로 GL 칸 통째 자름(`RouteEdit_Gl.ts:177-197`) | 겹 꼴 일부(`B04_UI_MapGl.lineSpecs · rasterSpec`) |
| 도구줄 | 두 줄 — 겹 줄(왼쪽 위 · `UI_Layers.ts:168-206`) + 평면 도구(오른쪽 · `UI_Map.ts:188-234`) | 한 줄(왼쪽 위 · `RouteEdit_Chrome.ts:130-171`) | `createMapTools` |
| GL 켬끔 취향 | `aislo:pref:d03.canvas`(`UI_Layers.ts:96`) | `aislo:pref:map.canvas`(B04 · 배수 같이 · `B04_UI_MapGl.ts:27`) | — |
| 위 그림 · 누름 | 긋기 · 고르기 · 지점 · 조각 · 속성 · 재기(`UI_Draw` · `UI_Edit` · `UI_Select` · `UI_Points` · `UI_Measure`) | 노드 끌기 · 곡선 · 측점 · 구조물 표 · 절/성토선 · 등고선 고름 · 자물쇠 · 횡단 미리보기(`RouteEdit_Pointer` · `_Render` · `_StructureMarks` · `_Footprint` · `_ContourLock` · `_Cross`) | — |
## 2. 기능 대조
### 2-1 도구줄 단추
| 단추 | 하는 일 | D03 | B05 | 일원화 뒤 |
|---|---|---|---|---|
| [?] | 조작 안내 | 있음(17 줄 · `UI_Map.ts:206-226`) | 있음(9 줄 · `Chrome.ts:72-82`) | 둘 다 · 글은 페이지 몫 |
| 되돌리기 · 다시하기 | 걸음 스택 | 있음(`UI_Map.ts:200-201`) | 있음(`Chrome.ts:135-136`) | 둘 다 |
| 3D | 큰 창 | 있음(`D03_UI_3D`) | 있음(부른 쪽 · `design_view_profile_3d_modal.ts:77`) | 둘 다 · 동작 페이지 몫 |
| 돌리기 좌 · 우 | 단추 · Ctrl+휠 | 있음 | 있음 | 둘 다(이미 같은 코드) |
| 1 m 등고선 | LAS 1 m 선 | 없음 | 있음 · LAS 일 때만 열림(`RouteEdit.ts:660-664`) | 라이다 원천일 때만 보임 |
| 측점 | 눈금 · 번호 | 있음 | 있음 | 둘 다 |
| 기울기 | 구간 기울기 글 | 있음(구간 길이 · 기울기) | 있음 | 둘 다 |
| 절/성토선 | 도로 끝 · 비탈 끝 | 없음 | 있음 | B05 만 |
| 거리 재기 | 두 점 | 있음(곧은 · 노선 따라 · 브라우저 격자 높이 `UI_Measure`) | 있음(노선 위 · 서버 `/route/elevations` · `RouteEdit_Measure`) | 단추 같은 자리 · 동작 페이지 몫 |
| 측점 스냅 + 간격 | MC 맞춤 | 없음 | 있음(`Chrome.ts:160-165`) | B05 만 |
| 지형 이름 칩 | 설계 지형 표시 | 없음 | 있음 · 둘 다 있을 때만(`RouteEdit.ts:642-643`) | **지형 원천 고르기**로 바꿈(둘 다) |
| GPU 켬끔 | 옛 캔버스 | 있음(겹 줄 끝) | 있음(1 m 선 뒤 · `RouteEdit_Gl.ts:63-70`) | 둘 다 · 취향 열쇠 하나 |
| 겹 스물 | 아래 2-2 | 있음 | 없음 | 둘 다 · 페이지별 보임 표 |
| 추천 미리보기(새) | 4 갈래 선 고름(요구 530 2) | 없음 | 새로 | B05 만(530 추천 쪽 몫) |
### 2-2 겹
| 겹 | D03 | B05 평면 | 원천 · 서버 길 | 임도(ROAD) 프로젝트에서 |
|---|---|---|---|---|
| 위성 | 있음 | 없음(배수유역 칸만) | `/plan/tile`(프로젝트 안 가림 · `Router.py:611`) | 바로 됨 |
| 음영기복 · 급경사 | 있음 | 없음 | `/plan/layers/raster` → `models_plan/dtm_sheet_*.npz`(`Layers.py:255-282`) | PLAN 전용(막힘) |
| 등고선 | 615 전국 조각(`contourTileSource` · 그림만) | LAS 5 m 또는 도엽 · **집기 자료**(고름 · 자물쇠 · 글 = 캔버스 · `RouteEdit_Contour.ts:191-212`) | `/plan/contour`(프로젝트 안 가림) | 조각 = 됨 · B05 집기는 지금 자료 그대로 |
| 세류 · 물 면 · 도로 · 임도 짐작 · 건물 · 지명 | 있음(도엽 조각 606) | 하천만 | `/plan/sheet-tiles`(프로젝트 안 가림 · `Router.py:350 · 363`) | 됨 |
| 올린 임도망도 | 있음 | 없음 | `/plan/layers/forest-roads`(D 자료) | PLAN 전용 |
| 지적 · 보호구역 · 산림입지 · 산사태 둘 · 단층 · 지질구조선 · 띠 | 있음 | 없음 | `/plan/layers/*` → `_layer_root:285` → `Store._project:76`(「예정노선 프로젝트가 아닙니다」) | PLAN 전용 |
| 0차곡 | 있음 | 없음 | `/plan/layers/zero-order` → `dtm_sheet` + 창고 누적(`ZeroOrder.py:262-300`) | PLAN 전용 |
| 622 새 겹 다섯(진행 중) | 붙는 중 | 없음 | `/plan/vt` · `/plan/wmt`(공용 창고 · 프로젝트 안 가림 꼴) | 됨(예정) |
### 2-3 지형 원천
| 칸 | D03 | B05 |
|---|---|---|
| 지금 원천 | 수치지형도 하나 — 공용 창고 도엽을 이어 붙인 `models_plan/dtm_sheet_<방법>.npz`(`Terrain.py:1-20`) | 라이다 확정 지표면 기본 · 수치지형도 서피스도 WF1 때 같이 지음(`B04_Engine.py:362-376`) |
| 바꾸기 로직 | 없음 | **있음** — `common_util_surface_confirmation.py:82-117`(`design_terrain` · `analysis_terrain_params` · `analysis_terrain_sources`) · `B04_Service.switch_design_terrain:63-87`(확정 모델 · stage 1 params · 라이다 값 적어 둠) · `Router_Terrain.read_terrain_sources:118-138` · `choosable_terrains:141-155` · 바꾸는 때 = 추천 [적용](`Router_Replan.py:252-266 · 358` · `RouteEdit_Apply.ts:202`) |
| 브라우저 높이 | `Api.fetchPlanSurface:172-181`(`models_plan` 모델만 고름) → `heightAt`(긋기 · 재기 · 3D) | `Api_TerrainGrid.designTerrainGridNow:75` |
| 라이다 길 | 없음 — D = `project_kind PLAN` · LAS 입력 없음 · D04 연결은 D → B 한 방향(「지형은 업체가 올림」 `D04_Link.py:1-12`) · LAS 올리기 = 임도 B03 만(`B03_Router.py:141-173`) | 있음 |
## 3. 일원화 갈래
| 갈래 | 뜻 | 좋음 | 나쁨 | 판정 |
|---|---|---|---|---|
| A 공용 껍데기 + 카메라 어댑터 둘 | 도구줄 표 · 겹 목록 · 받기 · 범례 · 지형 칩 = 공용 · 카메라 = D03 경위도 방식 / B05 TM 방식 그대로 | B05 캔버스 그림 · 집기 · 노선 자료 손 안 댐 · 겹은 경위도라 양쪽 GL 에 그대로 | 카메라 두 벌 남음(같은 점 몇 px 차 가능) | **권함** |
| B D03 지도로 B05 교체 | `createPlanMap` 하나 | 코드 한 벌 | B05 그림이 TM 정규화(`createTmNormalizer`) 위에 섬 → `_Render` 640 · `_StructureMarks` · `_Label` · `_Pointer` 집기 모두 다시 맞춤 · B06 연동 흔들림 | 안 권함 |
| C B05 방식으로 D03 교체 | `createTmGl` 하나 | B04 · 배수와 같은 길 | D03 600 km 줌아웃 · TM 띠 넘음에서 1차 맞춤 오차 커짐 | 안 권함 |
### 3-1 바탕 코드 · 자리
- 겹 쪽 바탕 = D03(`UI_LayerDefs` · `UI_MapGl.layerSpecs:127-324` · `UI_Layers` · `UI_LayerLegend` · `UI_SlopeBands` · `UI_SatLight` · `UI_SheetTiles`) — B05 는 셋뿐.
- 자리 = 공용 폴더 새로(가칭 `A00_Common/map/`) — fetch 가 섞여 `ui_template` 엔 못 둠 · B05 가 D03 파일을 직접 부르면 페이지끼리 서로 부름.
- 페이지 설정 꼴 = 보일 단추 목록 · 보일 겹 목록 · 겹 처음 켬 · 지형 원천 기본값(D03 수치지형도 · B05 라이다) · 취향 열쇠.
- 도구줄 단추 = `ui_template_map_tools.MAP_TOOLS:22-34` 에 새 이름(지형 · 추천 미리보기 · GPU)만 더함.
### 3-2 B05 를 깨지 않는 경계
| 공용 부품이 만짐 | 안 만짐(B05 그대로) |
|---|---|
| GL 바탕 겹(꼴 · 자료 · 켬끔) · 도구줄 단추 꼴 · 보임 · 겹 범례 · 지형 칩 | 캔버스 위 그림(`_Render` · `_StructureMarks` · `_Label` · `_Footprint` · `_Curve_Pick` · `_Hover`) · 누름(`_Pointer` · `_Input` · `_Keys` · `_ContourLock`) · 노선 자료(planned · curves · node_edits) · B05 · B06 공유 캐시 · [저장](`Route_Save` · `Router_Confirm`) · 관 지점 · 구조물 정본(`pipe_points.json` · `structures.json`) · B05 등고선 집기 자료 |
- 지형 원천 바꾸기만 B05 정본에 닿음(설계 지형 = 뒤 단계 모두) — 4장.
### 3-3 700 줄 한도(지금)
| 파일 | 줄 | 일원화 때 |
|---|---|---|
| `B05_UI_RouteEdit.ts` | 694 | 손대지 않게(배선은 새 파일) |
| `B05_UI_RouteEdit_Recommend.ts` | 690 | 530 추천 쪽 몫 |
| `D03_UI_Layers.ts` | 688 | 공용으로 옮기며 쪼갬 |
| `D03_UI_Page.ts` | 667 | 지형 원천 배선은 새 파일 |
| `D03_PlanAnalysis_Router.py` | 651 | 임도 갈래 · 원천 인자 = 새 파일 |
| `B05_UI_RouteEdit_Render.ts` · `_Initial_Model.ts` | 640 · 640 | 안 건드림 |
| `D03_PlanAnalysis_Layers.py` | 616 | 원천 인자만 |
| `B05_Router_Replan.py` | 615 | 지형 바꿈 때만 |
| `D03_UI_Map.ts` | 568 | 도구줄 표로 바꿈 |
### 3-4 단계(같은 파일 겹침 없게)
| 단계 | 창 | 파일 | 앞 단계 |
|---|---|---|---|
| 1 서버 — 겹 라우터가 임도 프로젝트도 받음(범위 = B 메타 상자 · DEM = 설계 지형 npz) · 급경사 · 음영 · 0차곡에 원천 인자 · 지적 등 받은 파일은 B04 파일과 다른 이름 | 창 1 | D03 `Router` 새 조각 · `Layers.py` · `ZeroOrder.py` · `Store.py` · 새 시험 | 없음 |
| 2 화면 공용 — 겹 목록 · 겹 줄 · 범례 · 조각 · 도구줄 표 → 공용 폴더 · D03 은 부르기만(겉모습 · 수치 그대로) | 창 2 | D03 `UI_Layers` · `UI_LayerDefs` · `UI_MapGl` · `UI_LayerLegend` · `UI_LayerPaint` · `UI_SheetTiles` · `UI_SlopeBands` · `UI_SatLight` · `ui_template_map_tools` · 새 공용 폴더 | 1 과 나란히 |
| 3 B05 평면에 붙임 — 공용 겹 꼴을 `createTmGl` specs 에 더함 · 도구줄을 표로 · GPU 취향 하나 | 창 3 | B05 `RouteEdit_Chrome` · `RouteEdit_Gl` · `B04_UI_MapGl`(취향 열쇠) · 새 배선 파일 | 1 · 2 뒤 |
| 4 지형 원천 바꾸기 — D03 라이다(5장 결정 뒤) · B05 칩 → 설계 지형 바꿈 | D03 = 창 1 이어서 · B05 = 530 추천 미리보기 창과 한 창 | D03 `Api.ts` · 새 배선 · B05 `RouteEdit.ts` · `_Apply` · `Router_Replan` · `Router_Terrain` | 3 뒤 |
- 겹침 주의 — 530 D03 긋기 일(Tab · 길이+기울기 기본)이 `D03_UI_Map.ts` 안내 글 · `UI_DrawPanel` · `UI_Draw` 를 만짐 → 2 단계는 `UI_Map.ts` 안 만지고 도구줄 표 바꿈은 3 단계 또는 긋기 일 뒤.
## 4. 지형 원천 바꾸기
### 4-1 D03 에서 라이다 쓰는 조건
| 길 | 뜻 | 됨 · 안 됨 |
|---|---|---|
| a D 프로젝트에 LAS 올리기 | D 화면에 올리기 + B04 지면 필터 · DTM 짓기 그대로(D storage 도 `B04_PreProcess/` 배치 · `Terrain.py:3-4`) | 새 올리기 길 · 무거운 전처리 · 가장 곧음 |
| b 이어진 임도 프로젝트 LAS 빌림 | `projects.source_project_id = D` 인 B 의 확정 DTM | D04 연결 뒤에만 · D03 은 연결 전 단계라 대개 없음 |
| c 공용 라이다 창고 | 전국 등고선 창고처럼 | 없음 |
### 4-2 바꿀 때 다시 셀 것
| 대상 | D03 | B05 |
|---|---|---|
| 급경사 · 음영 | 서버 `slope_layer` npz 자리만 바꿈 · 파생 열쇠에 npz 이름이 들어가 저장본이 저절로 갈림(`Layers.py:268`) | 새 겹(지금 없음) |
| 0차곡 | 수치지형도 = 창고 누적 빠른 길 · 라이다 = 통째 첫 셈 느림(616 근거 3.5~11.9 s) | 새 겹 |
| 등고선 그림 | 615 조각 = 수치지형도만 · 라이다 = LAS 등고선 따로 지어야 함 | 지금 로직(LAS ↔ 도엽 · `RouteEdit.ts:644-664`) |
| 브라우저 높이(긋기 길이+기울기 · 양각기 · 재기 · 3D) | `fetchPlanSurface` 고르는 모델만 바꿈(`Api.ts:174`) | `designTerrainGridNow` |
| 서버 [저장] | 높이 안 씀(`Network.py:9`) → 다시 셀 것 없음 | 설계 지형 = 종단 · 횡단 · 배수 · 토공 · 3D 모두(`switch_design_terrain` → `run_route_save_chain`) |
| 노선 추적(추천) | 없음 | 530 = 추천 다시 셈 없음 · 미리 셈 값만 |
### 4-3 B05 로직 다시 씀
- 그대로 씀 = `analysis_terrain_*` · `switch_design_terrain` · `/route/terrain-sources`.
- 바꿀 것 = 바꾸는 때 — 지금 추천 [적용] 안(509-5) → 530 으로 추천이 미리보기만 되므로 **도구줄 지형 칩**으로 옮김 · 고르면 `/route/replan`(같은 노선 + `terrain`) 길.
- D03 에는 `analysis_terrain_*` 그대로 못 씀(stage 1 params · 확정 모델 = 임도 WF1 꼴) — D 는 원천 이름(`sheet` · `las`)만 같게 하고 npz 고르기는 D 쪽 작은 함수.
## 5. 위험 · 사용자 결정
### 5-1 위험
| 위험 | 자리 | 막는 길 |
|---|---|---|
| 노선 띠 300 m 자르기가 GL 칸 통째(clip-path) → 위성 · 지적도 띠 안만 보임 | `RouteEdit_Gl.ts:177-197` | 등고선 · 하천 겹만 거름(MapLibre 겹 거름) · 칸 자르기 걷음 |
| 임도 프로젝트에서 지적도를 받으면 B04 `연속지적도_bounds.geojson` 을 덮어씀(열쇠 파일 없음 → 다시 받기) | `Layers.py:57 · 181-189` · `B04_GisVector.py:165` | 임도 프로젝트는 파생 저장 자리로 |
| 카메라 두 벌 — 같은 경위도 점 px 차 | `UI_Map.glCamera` 대 `glCameraOf` | 검증 창구로 대조(`screenOfLonLat` · `glCheck`) |
| GPU 취향 두 열쇠 → 하나로 하면 B04 하단 지도 · 배수 칸도 같이 바뀜 | `B04_UI_MapGl.ts:27` · `UI_Layers.ts:96` | 열쇠 하나로 · B04 · 배수 시험 같이 |
| B05 지형 바꿈 = 설계 지형 → B06 횡단 · 배수 · 토공 다시 셈 · 관 지점 · 구조물 따라감 | `Router_Replan.py:252-266` | 지금 [적용] 길 그대로 · 확인창 하나 |
| 파일 한도 — `RouteEdit.ts` 694 · `UI_Layers.ts` 688 · `Router.py` 651 | 3-3 표 | 새 파일로 |
| 530 다른 일(D03 긋기 · B05 추천 미리보기)과 같은 파일 | `D03_UI_Map.ts` · `RouteEdit.ts` · `_Recommend*` | 3-4 차례대로 |
### 5-2 사용자 결정 거리
| 물음 | 갈래 | 권함 |
|---|---|---|
| ① 카메라 | A 두 벌 유지 · B 하나로 | **A** |
| ② B05 평면 처음 겹 | 지금 그대로(어두운 바탕 · 등고선 · 하천) · 위성 켬 | **지금 그대로** · 나머지 겹 끔 · 겹 줄에서 켬 |
| ③ 노선 띠 300 m 자르기 | 모든 겹 · 등고선 · 하천만 | **등고선 · 하천만** |
| ④ B05 지형 바꿈의 뜻 | 설계 지형(뒤 단계 모두) · 보기만 | **설계 지형**(지금 로직 · 확인창) |
| ⑤ D03 라이다 원천 | a D 에 LAS 올리기 · b 이어진 임도 빌림 · c 뒤로 | **a**(B04 엔진 그대로 · 연결 전에도 됨) |
| ⑥ 라이다 범위 밖(D 노선이 LAS 보다 넓을 때) | 수치지형도로 채움 · 빈칸(모름) | **빈칸** — 임의로 메우지 않는 지금 규칙(`Router_Terrain` 머리글) |
| ⑦ 새 겹의 GPU 끔(옛 캔버스) 대체 | 지음 · GL 만 | **GL 만** — 옛 캔버스는 지금 겹만 |
| ⑧ 공용 코드 자리 | 새 공용 폴더 · B04 에 둠 | **새 공용 폴더**(`A00_Common/map/` 가칭) |
| ⑨ B05 에 보일 겹 | 스물 모두 · 고른 것만 | **모두**(처음 끔) · 띠(타당성) · 올린 임도망도는 숨김 |
| ⑩ 거리 재기 동작 | 하나로 · 페이지 몫 | **페이지 몫**(단추 자리만 같게) |
- 범위 밖으로 둔 것 = B05 배수유역도 칸 지도(`_Drainage_Gl` · 따로 칩 줄) · B04 하단 지도 · 추천 창 지도(`_Recommend_Map` · 530 추천 미리보기 일이 걷을 후보).
@@ -0,0 +1,151 @@
# 530-B 조사 — D03 노선 긋기(길이+기울기 기본 · Tab · 숨김 · 부채꼴 · Shift)
원문 = `docs/raw/요구_1025/사용자요구_1025.md:1098-1102`. 코드 · DB · storage 손대지 않음 · 화면 실측 대신 storage DEM 읽기 실측(로그인 POST 피함 · 탭 열었다 닫음).
## 0. 결론
- 네 방식 · 점선 원 · 후보 점 · 기울기 셈은 **있음**. 기본값 · 차례 · Tab · 숨김 = 작은 고침(한 창 반나절 꼴).
- 부채꼴 · +/− 색 · 정방향 채움 · Shift 사이 기울기 = **없음** — 새 순수 셈 하나(`compassArcs`) + 미리보기 그림 + Shift 상태 전달.
- 실측(검증 D 수치지형도 DEM · 반지름 20 m · 9 % · 점 2000): **후보 4 개 = 97.2 %** · 그중 거의 전부 「허용 호 2 개 · 각 호 끝 = + 하나 − 하나」 → 요구의 「방향 1 · 2 × 노드 2」 그대로 맞음. 나머지 2.8 % = 후보 2 · 6 · 8 개(골 · 능선 둘레).
- B05 복사(530-2) = 방식 칸 · 순수 셈 · 미리보기 그림은 떼어 씀 · `createPlanDraw`(여러 선 `PlanNetwork` · 갈래 · 연도 · 지점)는 그대로 못 옮김.
## 1. 지금 코드 자리
| 항목 | 자리(파일:줄) | 지금 |
|---|---|---|
| 그리기 칸 몸 | `D03_PlanAnalysis_UI_DrawPanel.ts:154-190` | [긋기] · [연도 구역 마커](끌기) + 방식 칸 |
| 방식 칸 | `UI_DrawPanel.ts:47-145` | `createSegment` 2 × 2(`:56-70` · `columns: 2` `:63`) + 길이 · 기울기 칸(`:72-104`) · 기울기 아래 ≈ °(`:105-109`) · 노드 판(598-4 `UI_Props.ts:143-170`)도 같은 함수 |
| 방식 종류 · 차례 | `UI_DrawPanel.ts:23` · `:31-36` | `free · length · slope · both` — 차례 = 자유 · 길이 고정 / 기울기 고정 · 길이·기울기 고정 |
| 기본값 | `D03_PlanAnalysis_UI_Draw.ts:123` · 값 `UI_DrawPanel.ts:20-21` | 방식 `"free"` · 길이 20 m · 기울기 9 % (페이지 열 때마다 처음값 · 저장 안 함) |
| 옵션 칸 막힘 | `UI_DrawPanel.ts:119-123` `fieldsState` | 자유 = 둘 다 `disabled` · 길이 고정 = 기울기 막힘 · 기울기 고정 = 길이 막힘 |
| 미리보기 셈 | `UI_Draw.ts:190-231` `previewAt` | 붙기 먼저 → 방식별(`:211-219`) · `both` = 후보 전부(`:199`) 중 마우스에 가까운 것 |
| 점선 원 · 후보 점 | `D03_PlanAnalysis_UI_DrawPaint.ts:288-298` `paintPreview` | 반지름 원(점선 [3,4]) + 후보 점 모두 노랑(`--draw-map-sketch`) · 부호 색 없음 |
| 미리보기 글 | `UI_DrawPaint.ts:65-68` · `:307-318` | 길이 · 부호 붙은 % · ° (이미 +/− 글은 있음) |
| 양각기 후보 셈 | `logic/D03_PlanAnalysis_Draw.ts:110-159` `compassCandidates` | 원 360 표본 + 이분 · `|Δz| − rise` 근 → **부호 버림**(`:126`) · 동쪽부터 반시계 차례 |
| 가까운 후보 | `logic/D03_PlanAnalysis_Draw.ts:162-179` `compassPoint` | 마우스에 가장 가까운 후보 · 없으면 null(=찍기 막힘) |
| 기울기 셈 | `logic/D03_PlanAnalysis_Draw.ts:28-35` `groundSlopePct` | (z끝 − z시작) / 수평 길이 × 100 · + 오르막 |
| 지형 원천 | `UI_Page.ts:128` → `D03_PlanAnalysis_Api.ts:172-181` | `models_plan/` smooth 격자 = 수치지형도 도엽 DEM(`D03_PlanAnalysis_Terrain.py:13-15`) · 라이다 갈래 없음(530-A 몫) |
| 파이썬 짝 | `D03_PlanAnalysis_Draw.py` · 거울 시험 `test_562_1_plan_draw.py` | 서버는 [저장] 때 꼭짓점을 받은 그대로 · 양각기 셈 안 부름 |
| 노드 기록 | `logic/D03_PlanAnalysis_Span.ts:16-22` · 어긋남 `:25-33` | `{kind, length_m, slope_pct}` · 기울기는 크기만 비교(`|기울기|`) |
| 노드 다시 놓기 | `logic/D03_PlanAnalysis_Select.ts:254-287` `placeNode` | `both` = `compassPoint`(`:273`) |
| 놓인 노드 점 | `UI_DrawPaint.ts:164-179` | 흰 점 3 px + 어긋남 경고 고리 · 부호 색 없음 |
| 키 받기 | `UI_Page.ts:611-628` · `UI_Draw.ts:503-536` | window keydown · 입력 칸 초점이면 안 받음(`:613`) · Enter · Esc · Backspace |
| 키 등록부 | `A00_Common/key_registry.ts:139-142` | `plan.drawFinish` · `plan.drawBack` · Tab 줄 없음 · Shift 단독은 `chordOf` 가 빈 글(`:259`) |
| 마우스 곁 | `D03_PlanAnalysis_UI_Map.ts:104` · `:456-464` | `hover(px, py, map)` — **Shift 안 넘김**(누름만 `:445` 넘김) |
| 지도 안내 글 | `UI_Map.ts:206-225` | Tab · Shift(긋기 중) 줄 없음 · 「Shift+누름 = 선 더함」은 쉴 때 고르기 |
## 2. 요구 대조
| 요구 | 지금 | 고칠 자리 | 크기 |
|---|---|---|---|
| 기본값 = 길이+기울기 고정 | 없음(자유) | `UI_Draw.ts:123` `"free"` → `"both"` | 한 줄 |
| 버튼 = 자유지정 오른쪽 | 없음(오른쪽 = 길이 고정) | `UI_DrawPanel.ts:31-36` 열쇠 차례 → `free · both · length · slope`(2 × 2 = [자유][길이·기울기] / [길이][기울기]) · 노드 판도 같이 바뀜 | 넉 줄 |
| 이름 「자유지정」 | 「자유」 | `UI_DrawPanel.ts:32` (선택) | 한 줄 |
| Tab = 자유 ↔ 길이+기울기 · 단독 고정이면 길이+기울기로 | 없음 | `UI_Draw.ts` `key()` 에 `kind === "both" ? "free" : "both"` + `kindFields.set` + 마지막 마우스 자리로 미리보기 다시 · 등록부 줄 `plan.drawKind ["Tab"]`(바꿀 수 있는 줄 → 시험 588 배선 판정 통과) · 안내 글 한 줄 | 20 줄 |
| 필요 없는 칸 = 숨김 | 일부(막힘) | `UI_DrawPanel.ts:119-123` — 방식 따라 칸 `root.hidden` · 권한 없음(`setDisabled`)만 막힘 유지 · 자유 = 칸 줄 통째 숨김 · `display:grid` 가 `[hidden]` 을 덮는지 확인 | 10 줄 |
| 점선 서클 + 노드 4 개 | 있음 | 그대로 | — |
| 방향 1 · 2(노드 2 개씩 짝) | 없음 | 새 순수 셈 `compassArcs` — 후보를 각도 차례로 · 이웃 두 후보 사이 가운데 각에서 `|Δz| < rise` 면 허용 호(=부채꼴) · 후보마다 부호 `sign(z − z0)` | 40 줄 |
| 진행 · 역방향 부채꼴 · 정방향 색 채움 | 없음 | 정방향 = 앞 구간 방향(앞앞 점 → 시작점)과 호 가운데 방향 cos 가 큰 호 · `paintPreview` 에 부채꼴(중심 → 호 → 닫음) · 정방향만 반투명 채움 | 50 줄 |
| 꼭지점 +/− 색(고르기 전 · 고른 뒤 같은 색) | 없음(모두 노랑) | 후보 점 색 = 부호 · 마우스가 고른 후보도 같은 색 · 놓인 노드도 들어온 구간 기울기 부호로 색(`UI_DrawPaint.ts:164-179` · 저장 없이 셈) · 새 지도 색 두 개 `--draw-map-slope-up/down` | 30 줄 + 시험 551-2 |
| Shift 누른 채 = 부채꼴 사이 기울기 지점(길이 유지) | 없음 | Shift 상태 = `hover` 에 shift 인자(`UI_Map.ts:104 · :461`) + keydown/keyup Shift · 창 blur 때 풂 → `previewAt` 에 「원 위 마우스 방위 · 허용 호 안으로 묶음」 · 기록 = `length`(아래 3 장) | 40 줄 |
| 완만한 땅(후보 0 · 원 전체 허용) | 막힘(`compassPoint` null → 찍기 막힘) | 원 전체가 허용이면 길이 고정처럼 어느 방향이나 | 5 줄 |
파일 크기 — `UI_Draw.ts` 560 → 약 610 · `UI_DrawPaint.ts` 340 → 약 400 · 새 셈 파일 약 80 · 700 줄 안.
## 3. 부채꼴 · +/− 규칙
### 3-1 지금 수식
- 후보 = 반지름 L 원 위 `|z(θ) − z0| = |s|·L` 인 방위(`logic/D03_PlanAnalysis_Draw.ts:118-127`) — +(오르막) · −(내리막) 섞여 나옴 · 부호는 버림.
- 고르기 = 마우스에 가장 가까운 후보(`:162-179`) · 방향 · 정방향 개념 없음.
### 3-2 요구대로 셈(평면 경사면 기준 · 실측과 맞음)
| 말 | 정의 |
|---|---|
| 최대 경사 G · 오르막 방위 θu | 시작점 둘레 땅 |
| 노드 4 개 | +쪽 θu ± α · −쪽 θu + π ± α (α = arccos(s / G)) |
| 방향 1 · 2 | 등고선 방향 θu ± 90° — 각 방향 = (+ 하나, − 하나) 짝 |
| 부채꼴 | 짝 두 노드 사이 호 = `|기울기| ≤ s` 인 방위 모두(가운데 = 0 %) |
| 정방향 | 앞 구간 방향과 가까운 쪽 호 · 반대 = 역방향 |
| 꼭지점 부호 | `sign(z(노드) − z0)` — 진행 방향 기준 + 오르막 |
- 실측 — 이 땅 경사 중앙 65 % → 부채꼴 폭 ≈ 2·arcsin(9/65) ≈ 16° · 20 m 원에서 호 길이 약 5.6 m(가파를수록 좁음).
- 거친 땅(2.8 %) — 허용 호가 1 · 3 · 4 개 · 끝이 (+,+) · (−,−) 인 호도 나옴 → 「이웃 후보 사이 허용 호」 규칙 하나로 모두 그림 · 꼭지점 색은 각자 부호.
### 3-3 Shift 사이 기울기 갈래
| 갈래 | 내용 | 판단 |
|---|---|---|
| A 원 위 마우스 방위 · 호 안으로 묶음 · 기울기 = 실제 지형 Δz / L | 길이 = L 그대로 · 보이는 % = 그 자리 땅 | **권함** — 짝 셈 · [저장] 재셈과 같은 값 |
| B 호 안 각도 비례로 −s ~ +s 나눔 | 보이는 % 가 땅과 다름 → 노드 어긋남 경고(`Span.ts:25-33`) | 안 권함 |
| C A + 값 눈금(1 % · 0.5 %)에 붙음 | 호 위 이분으로 그 % 자리 | 선택(정수 % 원하면) |
- 노드 기록 — Shift 로 찍은 점 = `length`(길이만) **권함** · `both` + 실제 % 로 적으면 `placeNode`(`Select.ts:273`)가 크기만 보고 맞은편 후보로 튈 수 있음 · 서버 꼴(`D03_PlanAnalysis_Network.py` `NodeRecord`) 안 바뀜.
- 호 밖(가파른 쪽)에 마우스 — 가까운 호 끝(= ±s 노드)에 붙음.
### 3-4 셈 자리
- 부채꼴 · 정방향 · Shift 묶음 = 화면 고르기만(서버는 꼭짓점 그대로 받고 길이 · 기울기 다시 셈) → 짝 파일(`Draw.ts` · `Draw.py`)에 안 넣고 **TS 전용 `logic/` 새 파일 + 작은 시험** 권함. 짝에 넣으면 파이썬 쪽도 같이 · 거울 시험 늘림.
- 화면 각도 — 작업 좌표(y 위) ↔ 그림 px(y 아래) · 돌린 지도 → 부채꼴 `arc` 방향 깃발을 끝점 · 가운데 점 화면 좌표로 정함(뒤집힘 흠 조심).
## 4. Tab · 부품 상자 · B05 복사
### 4-1 Tab · Shift 충돌
| 거리 | 지금 | 처리 |
|---|---|---|
| 브라우저 초점 이동 | 긋기 중 초점 = [긋기] 단추 등 → keydown 이 window 에 옴 | 받으면 `preventDefault`(`UI_Page.ts:623-626`) → 초점 안 옮김 · 긋기 아닐 때 Tab = 그대로 초점 이동(접근성 유지) |
| 길이 · 기울기 칸에 초점 | 입력 중이면 페이지가 키를 안 받음(`UI_Page.ts:613`) | Tab = 칸 넘김(그대로) · 숨김으로 초점 칸이 사라지면 body 로 |
| 등록부 겹침 | plan 자리 Tab 없음 · 브라우저 몫(`key_registry.ts:233-242`)에도 없음 · CAD · B09 Tab 은 다른 화면 | 겹침 없음 |
| Shift+Tab | `chordOf` = "Shift+Tab" → 안 맞음 | Shift(사이 기울기) 누른 채 Tab 은 안 먹음 — 그대로 둠 |
| Shift 누른 채 누름(D03) | 긋기 중 고르기 겹은 꺼짐(`UI_Page.ts:154`) | 충돌 없음 |
| Shift 단독 키 | `keyIs` 로 못 셈 | `event.shiftKey` 직접 · 등록부엔 고정 줄(`fixed`) 「Shift 누른 채」로 표에만 |
| Shift 붙음 | 창 바꾸면 keyup 못 받음 | window blur 에서 풂 |
### 4-2 부품 상자
- 방식 칸 = `createSegment` · `createInputField` · `createText` 만 · 날 `<button>` · `<input>` 없음 → 규칙 맞음. 숨김 = `hidden` 속성(새 선택자 아님).
- 부채꼴 · 꼭지점 = 캔버스 그림 → 색만 `--draw-map-*` 새 토큰 두 개(테마 안 따름 · 시험 `test_551_2_draw_tokens.py:172-186` 정규식 · 개수 8 → 10 고침).
### 4-3 B05 평면도 복사(530-2) 경계
| 덩이 | 자리 | 기댐 | B05 에서 |
|---|---|---|---|
| 방식 칸 | `UI_DrawPanel.ts:47-145` | 부품 상자 · `fmt` · `slopeDeg` | 그대로 씀 |
| [긋기] · 연도 마커 줄 | `UI_DrawPanel.ts:154-190` | `YEAR_MARK_DRAG`(D 사업 연도) | 연도 마커 빼고 씀 |
| 순수 셈 | `logic/D03_PlanAnalysis_Draw.ts` + 새 부채꼴 셈 | 없음(높이 함수만) | 그대로 씀 |
| 미리보기 그림 | `UI_DrawPaint.ts:278-319` + 부채꼴 | `ScreenMap` 일부(`toScreen` · `pxPerMeter` · `upright`) · `planColors` | B05 화면 좌표를 `ScreenMap` 꼴로 맞춰 주면 씀 |
| 긋기 상태 기계 | `UI_Draw.ts:115-560` `createPlanDraw` | `PlanNetwork`(여러 선 · 갈래 · 조각 연도 · 노드 기록) · 지점 붙기 · 다시 긋기 · `PlanMapLayer` | **못 옮김** — 선 하나 예정노선이면 「한 선 긋기 핵」을 따로 뽑거나 갈래 · 연도 끈 채 한 선 network 로 감쌈 |
- 뽑을 경계 권함 — ① 방식 칸 ② 순수 셈(부채꼴 포함) ③ 미리보기 그림 세 덩이를 공용 자리로(530-A 지도 일원화 공용 폴더와 같은 곳) · 상태 기계는 530-2 설계 때.
- B05 충돌 — 평면 Shift+누름 = 재기(`B05_Profile_UI_RouteEdit_Pointer.ts:243`) · Shift+방향키 = 1 m 옮김(`RouteEdit_Keys.ts:128`) → B05 긋기 중엔 재기 끔 필요.
- 겹침 — 530-A 2 단계와 `UI_Map.ts` 안내 글이 같은 파일(530-A `3-4` 주의) → 이 일을 먼저 또는 안내 글만 나중.
## 5. 위험 · 사용자 결정
### 5-1 위험
| 위험 | 대처 |
|---|---|
| 거친 땅에서 노드 4 개가 아님(2.8 %) | 「이웃 후보 사이 허용 호」 일반 규칙 · 개수 가정 안 함 |
| 완만한 땅 = 후보 0 → 지금은 찍기 막힘 | 원 전체 허용이면 길이 고정처럼 |
| 앞 구간 방향이 오르막 · 내리막과 거의 같음 → 정방향이 흔들림 | 같으면 마우스 쪽 호 |
| 첫 구간(앞 구간 없음) · 갈래 첫 구간 | 정방향 없음(채움 없음) 또는 갈래 = 붙은 선 방향 — 결정 |
| Tab · Shift 뒤 미리보기가 마우스 움직일 때까지 옛 그림 | 마지막 마우스 자리 기억 → 키에서 다시 셈 |
| 숨김이 노드 판(598-4)에도 번짐 | 같은 부품이라 같이 바뀜 — 의도로 봄 |
| 시험 | `test_588_key_registry.py`(새 줄 배선) · `test_551_2_draw_tokens.py`(토큰 수) · `test_553_4_de_parts.py:89-93`(칸 두 개 · columns 2 — 그대로 통과) · 새 부채꼴 셈 시험 |
### 5-2 사용자 결정 거리
| # | 물음 | 권함 |
|---|---|---|
| B1 | Shift 사이 기울기 값 = 실제 지형 / 각도 비례 / 눈금 붙음 | **실제 지형(A)** · 눈금은 원하면 |
| B2 | Shift 로 찍은 노드 기록 | **길이 고정(`length`)** |
| B3 | + · − 색 | 따뜻한 색(+ 오르막) · 찬 색(− 내리막) · 경고 빨강 · 노선 차례 색과 다르게 |
| B4 | 놓인 노드도 +/− 색 | **모든 노드 = 들어온 구간 기울기 부호**(저장 없이 셈 · 지형 바꾸면 따라 바뀜) |
| B5 | 첫 구간 · 갈래 첫 구간 정방향 | 첫 구간 = 채움 없음 · 갈래 = 붙은 선 방향 |
| B6 | 역방향 부채꼴 | 테두리만(채움 없음) · 고를 수는 있음 |
| B7 | 완만한 땅(원 전체 허용) | **길이 고정처럼 어느 방향이나** |
| B8 | 버튼 이름 「자유」 → 「자유지정」 | 원문대로 바꿈 |
| B9 | 기본값을 사용자마다 기억 | 안 함(늘 길이+기울기로 시작) |
@@ -0,0 +1,126 @@
# 530-C 조사 — 노선 추천 미리보기 · 예정노선으로 평면노선 바꾸기
읽기 전용 조사 · 코드 · DB · storage 손 안 댐 · 실측은 `검증_랩탑메인`(B) 파일 읽기만.
## 0. 결론
| # | 결론 |
| --- | --- |
| 1 | 「예정노선 추적」 = 지금도 자동설계 체인 초기 폴리라인(`planned_route_initial.csv`)과 같은 규칙 · 같은 선. 초기값을 바꾸는 길은 추천 [적용](`as_initial`) 하나뿐 → **[적용]을 걷으면 「초기값 = 예정노선 추적」이 저절로 맞음** |
| 2 | 넷 제안값(영선 `gradeline` · 토공 `earthwork` · 기울기 `gentle` · 비중 `weighted`)은 이미 체인 끝에서 미리 셈 · `B05_Profile/route_recommend/` 저장본 → 드롭다운은 **서버 고침 없이** 저장본 `planned` 선만 그리면 됨 |
| 3 | 예정노선을 고쳐 평면을 바꾸는 새 길 = 「새 노드 → 편집기 `restoreSnapshot(record)` → 페이지 [저장](`/design/save` · 손 고침 길)」이면 손 편집과 **같은 저장 · 재계산 길** → 평면노선 값만 바뀜 |
| 4 | 다시 추적 계산(`snapped_initial`)은 지형 안 씀 · 순수 기하 · 실측 0.32 s(331점 → 노드 28) · TS 짝 없음 → 서버 단독(③) 요청 한 번(긋기 끝낼 때) |
| 5 | ⚠ [적용]이 **지형 바꿈(라이다 ↔ 수치지형도)의 유일한 길** · ⚠ 고친 예정노선을 `expected_route.csv` 에 쓰면 초기값 · 추천 저장본이 함께 깨짐 → 새 파일 필요 |
## 1. 지금 노선 추천
| 칸 | 내용 | 근거 |
| --- | --- | --- |
| 화면 입구 | 좌측 「노선 추천」 칸 [노선 추천] 단추 · 「현재 추천: ○○」 | `B05_Profile_UI_Panel_Recommend.ts:21-22` · `_Panel_Sections.ts:32` |
| 모달 | 알약 다섯(follow · gradeline · earthwork · gentle · weighted) · 옵션 겹창(제약 넷 · 목표 기울기 · 비중) · 지형 고르기 · 「종단 반영」 · [재계산] · [적용] · 균형 종단 그림 | `_RouteEdit_Recommend.ts:83` · `:217` · `:230` · `:240` |
| 갈래 실제 이름 | follow 예상노선 추적 · gradeline 영선 · earthwork 토공 최소 · gentle 기울기 순한 · weighted 비중 (엔진엔 safe · crossings · cost 도 있으나 화면 밖) | `Engine_RouteInitial.py:10-24` |
| 서버 | `POST /route/initial` → `compute_initial` · 화면 요청은 저장본만(없으면 409 `NOT_PREPARED`) · 바꾼 값 · [재계산]만 그 자리 셈 | `Router_RouteInitial.py:33` · `:45` · `:138-174` |
| 언제 셈 | 자동설계 체인 끝 · B04 재확정 체인 끝 · B01 사용 범위 바꿈 → `schedule_precompute` · 기본 다섯 × (설계 지형 + 고를 수 있는 지형) · 셈 23~26 s / 꺼내기 2 s(sub1 로그) | `B03_FileInput_Service_Chain.py:352-354` · `:672-674` · `Router_RouteInitial.py:264-319` · `:383-425` |
| 저장 자리 | 파생 층 `B05_Profile/route_recommend/<지문>.json`(`request` · `result.planned` · `nodes` · `metrics`) · 초기 종단 `route_recommend/initial/` · 종류마다 2벌 | `Engine_RouteInitial_Store.py:52-58` · `Engine_InitialProfile.py:10` |
| [적용] 길 | `saveRecommendedRoute` → `POST /route/replan` `as_initial: true` | `_RouteEdit_Initial.ts:173-195` · `_RouteEdit_Apply.ts:190-211` |
| [적용]이 덮는 것 | 수정본 `planned_route.csv` · 사용자 구조물 · 추가 측점 · 관 버림 · 균형 종단을 1차 종단으로 · 설계 지형 바꿈 · `initial_choice.json` · **초기값 스냅샷 다시 뜸** | `Router_Replan.py:452-490` · `:564` · `:585-604` · `Route_Save.py:518-523` · `Router_RouteInitial.py:459` · `:573-596` |
## 2. 초기값 흐름
| 차례 | 하는 일 | 근거 |
| --- | --- | --- |
| ① | B03 예정노선(shp · csv · D04 연결) → `expected_route.csv`(원본 점 묶음 · 불변) | `B03_FileInput_Service_Chain.py:239-241` |
| ② | 초기 폴리라인 `planned_route_initial.csv` = `snapped_initial`(= 예정노선 추적 규칙) | `:247` · `Router_Replan.py:198-227` |
| ③ | 그 선으로 as_planned 풀기 → 확정 → 배수 · 관 정착 1차 계획선 → B06 확정 | `:254-303` |
| ④ | `initial_snapshot/` 뜸(`B05_Profile/route` 등 네 폴더 + DB 덤프) | `:339-343` · `common_util_initial_snapshot.py:37-42` · `:183` |
| [초기화] | `/route/reset` → 덤프 · 폴더 통째 되돌림(폴더 지우고 복사 = 스냅샷에 없던 파일 사라짐) | `Router_Lifecycle.py:234` · `common_util_initial_snapshot.py:154-159` |
- 읽기 차례 = 수정본 → 초기 폴리라인 → 예정노선 → 스냅샷 (`common_util_route_geometry.py:303-312`).
- 지금 초기값 = 추천 [적용]을 한 번이라도 했으면 **그 추천 노선**. 실측: `검증_랩탑메인` `initial_choice.json` = earthwork · 스냅샷 안 `planned_route.csv` 있음.
- 요구대로 바꿀 때 바뀌는 자리 = 화면에서 `as_initial` 부름 걷기뿐. 체인 · 스냅샷 · [초기화] 코드는 그대로.
- 다름 하나: 체인 초기 종단 = 관 정착 1차 계획선 · 추적 [적용] + 「종단 반영」 = 균형 종단 → [적용]을 걷으면 균형 종단 초기값은 사라짐(결정 D6).
## 3. 평면노선 변경이 B05 · B06 에 번지는 길
브라우저(즉시): `applyEdit` → `watch` → `bridge.edited` → `design_pipeline` 단계 route → follow → stations → ground → planline → profile → cross → footprint · 배수 · 3D 는 낡음 표시만.
근거 `B05_Profile_UI_RouteEdit.ts:431-450` · `_RouteEdit_Draft.ts:63-92` · `design_pipeline_page.ts:635-657` · `design_pipeline.ts:33-60`.
서버([저장] `POST /design/save`):
| 단계 | 하는 일 | 근거 |
| --- | --- | --- |
| a | `_save_route` → `planned_route.csv` · `_nodes` · `_curves` (실패면 되돌림) | `Router_Replan.py:493-582` |
| b | stage 2 제어점 다시 씀(사용 범위 트림) | `Router_Replan.py:287-327` |
| c | 구조물 · 추가 측점 좌표 따라감 → 새 `routes` 행 → 관 재투영 + 새 교차 관 → 종횡단 다시 → 계획고 옮김(`_carry_profile`) → 횡단 이월(측점 열쇠) → B06 확정 · 3D | `Route_Save.py:435-636` · `:211-382` |
| d~f | 세션 초안 새 노선에 다시 얹음 · 손 고친 종단만 위에 · 세션 횡단 `stations.carry` | `B06_Section_Router_DesignSave.py:186-245` · `DesignSave_Route.py:83-176` |
| 안 함 | 배수유역 다시 셈(낡음만) · 초기값 · 파생 저장본 | `Route_Save.py:619` · `Router_Replan.py:601` |
측점에 묶인 값: 구조물 · 관 · 추가 측점 = 좌표 따라감 · `grid:k` 열쇠 = 위쪽 연장이 바뀌면 같은 열쇠가 다른 자리 · 횡단 비좌석 칸(지반 · 측구 종류 등)은 자리가 옮겨도 열쇠로 이월 · 곡선 측점 = 가까운 새 곡선 · 종단 꼭짓점 = 1 m 안 같은 자리만 (`common_util_station_key.py:1-12` · `B06_Section_Route_Carry.ts:39-69` · `Route_Save_Parts.py:210-250`).
「평면노선 값만 바뀜」 경계:
| 지킬 것 | 까닭 |
| --- | --- |
| 새 노드를 편집기 `restoreSnapshot(…, record=true)` 로 싣기 | [저장]이 편집기 `nodes()` · `changed()` 를 읽음 — 가게 `routeDraft` 만 바꾸면 덮임 (`_RouteEdit.ts:483` · `_RouteEdit_Apply.ts:97-124`) |
| 입력은 노드(꺾임점) · `curveOn` · `curveRadius` · `stationSnap: true` | 서버가 노드로 다시 짬 · 촘촘한 선은 꺾임점이 지워짐 (`design_pipeline_types.ts:63-79` · `Router_Replan.py:514-542`) |
| 저장은 페이지 [저장]만 · `/route/replan` 직접 부름 · `as_initial` 금지 | 직접 부름 = 잠금 · 떠 두기 · 세션 이월 없음 · `as_initial` = 시설 버림 + 초기값 바뀜 |
| `expected_route.csv` · `initial_snapshot/` · `route_recommend/` · `initial_choice.json` 안 씀 | 예정노선 원본 mtime 이 바뀌면 초기 폴리라인을 다시 지음(`Router_Replan.py:205-209`) · 추천 지문이 바뀌어 넷 제안 저장본을 못 찾음 |
| `design_pipeline_page.ts`(699줄) 손대지 않는 길 | 편집기 길이면 필요 없음 |
## 4. 예정노선 추적 로직
| 칸 | 내용 | 근거 |
| --- | --- | --- |
| 자리 | 파이썬 단독 `snapped_initial`(R · 곡선 MC = 일반측점) · 추천 follow 도 같은 규칙 | `Engine_RouteInitial_Station.py:559` · `Engine_RouteInitial.py:362-367` |
| TS 짝 | 없음 — `logic/B05_Profile_RouteEdit_StationFit.ts` 는 줄인 꼴(짝 아님) | 그 파일 머리 |
| 입력 | 예정노선 정점 · 최소 R(`_plan_criteria`) — **지형 안 씀** | `Router_Replan.py:131` · `:214` |
| 비용 | 0.32 s (`검증_랩탑메인` 331점 → 노드 28 · 로컬 실측) | — |
| 넷 제안값 | 체인 끝 미리 셈 · 저장본 있음 · 화면 요청은 저장본만 | 1장 |
| 고친 예정노선 다시 추적 | 새 끝점 필요 — 지금 `/route/initial` 은 서버 파일 `expected_route.csv` 만 읽음 | `Router_RouteInitial.py:97` |
## 5. 단계 나누기
| 물결 | 창 | 일 | 파일(겹침 없음) |
| --- | --- | --- | --- |
| 1 | A 화면 | 평면 도구줄 아이콘 하나 + 드롭다운(끔 · 영선 · 토공 · 기울기 · 비중) · 고른 하나만 선 · 데이터 = 기존 `fetchRouteInitial` 저장본(기본 요청 · 설계 지형) · 없으면 「준비 중」 · 좌측 칸 · 모달 · [적용] 걷음 | `_RouteEdit_Chrome.ts` · 새 `_RouteEdit_Guide.ts` · `_RouteEdit_Render.ts` 또는 `_Gl.ts` · `_Panel_Sections.ts` · `_Panel_Recommend.ts` · `_Panel.ts` · `_RouteEdit_Initial*.ts` · `_RouteEdit_Recommend*.ts` · `_RouteEdit.ts`(initial 이음 다섯 줄) · `_RouteEdit_Apply.ts`(initial 칸) |
| 1 | B 서버 | `POST /route/follow`(선 → 노드 · 쓰기 없음) · 고친 예정노선 저장 칸(`RouteDraftInput.expected` → `expected_route_edit.csv`) · `GET /route/plan` 에 `expected_edited` · 지킴 시험 | 새 `Router_RouteFollow.py` · `common_util_route_geometry.py`(경로 하나 · 648줄) · `Route_Save.py`(636줄) · `Router_Replan.py`(615줄) |
| 2 | C 화면 | `_RouteEdit.ts` 먼저 나눔(694줄) · 예정노선 그리기 칸(긋기 · 다시 긋기 · 지움) · 긋는 동안 그 선 맨 위 · 노드 · 구조물 · 관 고르기 막음 · 끝내면 `/route/follow` → `restoreSnapshot` · `RouteDraft.expected` 캐시 → [저장] | `_RouteEdit.ts` · 새 `_RouteEdit_ExpectedDraw.ts` · `design_pipeline_types.ts` · `_RouteEdit_Apply.ts`(`routeDraftOf`) · `_Api_Replan.ts` |
- C 는 A · B 합친 뒤. D03 그리기 부품(`D03_PlanAnalysis_UI_DrawPanel.ts:47` `createDrawKindFields` · `logic/D03_PlanAnalysis_Draw.ts`)은 그대로 떼어 쓸 수 있으나 B05 → D03 거꾸로 부름이 됨 · `createPlanDraw`(여러 선 `PlanNetwork`)는 못 옮김 → 지도 일원화 일감이 공용 자리로 옮긴 뒤 씀.
- 지도 일원화(530 다른 조사)가 `_RouteEdit_Chrome.ts` · `_RouteEdit.ts` 를 고치면 A · C 와 겹침 → 차례 = 일원화 도구줄 → A → C.
### 위험
| 위험 | 대처 |
| --- | --- |
| [적용] 걷으면 지형 바꿈 길 없음(`_RouteEdit_Apply.ts:98` · `Router_Replan.py:564` · `_RouteEdit_Chrome.ts:128`) | 새 자리 먼저 정함(D2) · 서버 `as_initial` 은 남김 |
| B 그룹 완료 · 요구 491 | 도엽 등고 치환(SheetSurface · SheetParser · SheetStore · Watershed) · `switch_design_terrain` 안 고침 · 부르기만 |
| 예정노선은 점 묶음(331점 · 3.3 m) — 노드 끌기 꼴이 안 맞음 | D03 [다시 긋기] · 새로 긋기 · 지움 중심(D10) |
| 다시 추적 = 시점부터 MC 맞춤 → 한 곳 고쳐도 뒤쪽 연장 · `grid:k` 가 밀림 | 손 편집과 같은 이월 길 · 확인 창에 「평면선 통째 다시」 |
| 사용 범위 트림은 원본에만 · 고친 선엔 안 걸림 | 그리기 칸이 시 · 종점 범위 안만 받음 |
| `_RouteEdit.ts` 694 · `design_pipeline_page.ts` 699 · `_Initial_Model.ts` 640 줄 | C 는 먼저 나눔 · `design_pipeline_page.ts` 는 안 씀 |
| 옛 프로젝트 초기값 = 추천 노선 | D5 |
### 지킴 시험 후보
| 시험 | 내용 |
| --- | --- |
| 새 `test_530_c_follow_route.py` | `/route/follow` 몸통 = `_ensure_planned_initial` 노드와 같음(같은 입력 같은 선) · 프로젝트 폴더 쓰기 없음 |
| 새 `test_530_c_expected_edit.py` | 고친 예정노선 [저장] 뒤 `expected_route.csv` · `planned_route_initial*` 그대로 · `expected_route_edit.csv` 생김 · `restore_snapshot_files` 뒤 사라짐 · `/route/plan` `expected` 원본 + `expected_edited` |
| 새 규칙 시험 | B05 TS 에 `as_initial: true` 보내는 곳 없음 |
| 돌릴 기존 | `test_346_3_route_save` · `test_472_6_route_save` · `test_472_6_design_save` · `test_383_1_route_station_default` · `test_initial_snapshot` · `test_418_reset_cleanup` · `test_283_route_change_reset` · `test_476_1_apply_initial`(서버 남기면 그대로) · `test_b05_routeedit_initial_roundtrip`(서버 필요 · 고치거나 지움) |
### 사용자 결정 거리
| # | 물음 | 권함 |
| --- | --- | --- |
| D1 | 추천 모달 · 좌측 칸 | 통째 걷고 아이콘 드롭다운만(비교값 · 균형 종단 그림 사라짐) |
| D2 | 지형 바꿈(라이다 ↔ 수치지형도) 새 자리 | 평면 도구줄 지형 칸 → 손 [저장] 길로 지형만 · 초기값 안 바뀜 (지도 일원화와 함께 정함) |
| D3 | 예정노선 고치면 평면선 | 통째 다시 추적 · 직접 고친 것 버림 · 확인 창 |
| D4 | 고친 예정노선 저장 자리 | 새 `B05_Profile/route/expected_route_edit.csv`([저장] 때 · [초기화]면 사라짐) |
| D5 | 옛 프로젝트(추천으로 뜬 초기값) | 그대로 둠 · 새 프로젝트부터 |
| D6 | 초기 종단 | 지금 체인(관 정착 1차 계획선) 그대로 |
| D7 | 드롭다운 지형 | 지금 설계 지형 저장본만 |
| D8 | 서버 `as_initial` 길 | 화면 부름만 끊고 서버 · 시험은 D2 정할 때까지 남김 |
| D9 | 「선 긋기 때 맨 위로 올릴 계획선」 | B05 에서 고치는 예정노선으로 읽음 — 확인 |
| D10 | 예정노선 고치는 꼴 | 새로 긋기 · 구간 다시 긋기 · 지움(노드 끌기 없음) |
@@ -0,0 +1,100 @@
# 요구서 530 — 예정노선 · B05 평면도 지도 일원화 · 노선 긋기 · 노선추천 미리보기 (+ 620)
원문 = `사용자요구_1025.md` 요구 530(전문) · 620 = sub8 알림(B06 관 옵션 칸).
근거 조사:
- `_조사_530-A_지도일원화.md` · `_조사_530-B_노선긋기.md` · `_조사_530-C_노선추천_평면변경.md` · `_분석_620_B06_저장_옵션지워짐.md`.
## 1. 요구 요지
| # | 페이지 | 요구 |
|---|---|---|
| 1 | 공통 | 예정노선 지도 · B05 평면도 지도 기능 대부분 일원화 · 상단 아이콘 셋 같게 · 필요 없는 것 숨김 |
| 2 | 예정노선 | 기본 수치지형도 · 필요하면 라이다로 바꿔 계산 |
| 3 | 예정노선 | 긋기 기본값 = 길이 + 기울기 고정 · 버튼 = 자유지정 오른쪽 |
| 4 | 예정노선 | Tab = 자유지정 ↔ 길이 + 기울기(기울기만 · 길이만이면 길이 + 기울기로) |
| 5 | 예정노선 | 선택지에 따른 아래 칸 = 필요 없으면 숨김(비활성 아님) |
| 6 | 예정노선 | 점선 서클 · 노드 4(방향 1 · 2) · 부채꼴(진행 · 역) · 정방향 색 채움 · 꼭지점 +/− 색(고르기 전 · 뒤 같게) |
| 7 | 예정노선 | Shift = 부채꼴 사이 기울기 지점(길이 유지) |
| 8 | B05 평면 | 기본 라이다 · 수치지형도로 바꿀 수 있음(로직 있음) |
| 9 | B05 평면 | 노선추천 = 미리보기 · 초기값 = 예정노선 추적 선 · 추천 다시 셈 없음 |
| 10 | B05 평면 | 아이콘 하나 + 하위 넷(영선 · 토공 · 기울기 · 비중) · 선만 · 가이드 · 하나만 · 끔 가능 |
| 11 | B05 평면 | 평면노선 변경 = 계획선 직접 + 예정노선 고쳐서(예정노선 선 그리기 컨테이너 복사 · 선 긋기 때 계획선 맨 위 · 나머지 고르기 막음) |
| 12 | B05 평면 | 노선 바뀐 뒤 예정노선 추적 다시 셈 · 초기화값 안 바뀜(파일입력 예정노선 = 초기화 기준) |
| 13 | B05 평면 | ⚠ B05/B06 연계 — 평면노선 값만 바뀌게 |
| 14 | B06 | 620 — 관 옵션 칸 지워짐 까닭 · 고칠 길 |
## 2. 조사 결과 요지
- 지도: 지도 틀 · 도구줄 틀 · 휠 · 끌기 · 돌림은 이미 공용 · 카메라(D03 경위도 · B05 TM) · 겹 목록(D03 20 · B05 3) · 도구줄 차례 · 지형 원천이 따로.
- 막힘: D03 겹 서버 길 대부분이 예정노선 프로젝트 전용(`D03_PlanAnalysis_Store.py:76`).
- 지형: B05 전환 로직 있음(`common_util_surface_confirmation.py:82-117` · `B04_PreProcess_Service.py:63-87`) — 지금은 추천 [적용] 때만 · D03 라이다 길 없음.
- 긋기: 네 방식 · 점선 원 · 후보 점 · 기울기 셈 있음 · 기본값 = 자유 · 부채꼴 · +/− 색 · 정방향 채움 · Shift 없음 · 실측 97 % = 노드 4 · 호 2 · 호마다 + 하나 − 하나 · 완만한 땅 = 노드 0 이면 찍기 막힘(흠).
- 노선추천: 예정노선 추적 = 자동설계 체인 초기 평면선과 같은 선 · 초기값 바꾸는 길 = 추천 [적용] 하나 · 제안 넷 = `route_recommend/` 에 이미 저장 · 다시 추적 = 순수 기하 0.32 s.
- 평면 변경 새 길: 새 꺾임점 → 편집기 한 걸음 → 페이지 [저장](손 편집과 같은 저장 · 재계산 길) · `/route/replan` · `as_initial` · `expected_route.csv` 쓰기 금지.
- 620: 데이터 손실 아님 — 집수정이면 `inlet_revet_*` 아무도 안 읽음 · 까닭 = 79ca22082(서버가 모든 갈래 기본값 채움) + d5d9c5f66(유입 기본 집수정) · 고칠 자리 = `B04_PreProcess_Router_Basins.py` `_apply_new_defaults`.
## 3. 정함(브레인 권함 · 4장 결정 확인 뒤 확정)
- 지도 일원화 = 갈래 A: 도구줄 표 · 겹 목록 · 범례 · 지형 칩만 공용 부품(새 공용 폴더) · 카메라는 페이지별 그대로.
- 지형 바꿈 = 도구줄 지형 칩 하나(두 페이지 같은 꼴) — B05 = 지금 전환 로직(설계 지형 · 확인창) · D03 = D 프로젝트에 LAS 올리기 → B04 엔진 그대로.
- 노선추천 = [적용] 걷음 · 아이콘 하나 + 드롭다운(저장본 선만) · 초기값 = 예정노선 추적(체인 · [초기화] 코드 그대로).
- 예정노선 고쳐 평면 바꾸기 = 새 `expected_route_edit.csv` · 다시 추적 = 새 `POST /route/follow` · 결과는 편집기 한 걸음 → [저장].
- 620 = 새 관 기본값에서 집수정이면 `inlet_revet_*` 안 채움 · 옛 프로젝트 이주 없음.
## 4. 결정 거리(권함)
| 묶음 | # | 물음 | 권함 |
|---|---|---|---|
| 지도 | A① | 카메라 | 두 벌 유지 |
| 지도 | A② | B05 평면 처음 겹 | 지금 그대로 · 나머지 끔 |
| 지도 | A③ | 노선 띠 300 m 자르기 | 등고선 · 하천만 |
| 지도 | A④ | B05 지형 바꿈 뜻 | 설계 지형(뒤 단계 모두 다시 셈 · 확인창) |
| 지도 | A⑤ | D03 라이다 원천 | D 프로젝트에 LAS 올리기 |
| 지도 | A⑥ | 라이다 범위 밖 | 빈칸(임의로 메우지 않음) |
| 지도 | A⑦ | GPU 끔(옛 캔버스) 새 겹 | GL 만 |
| 지도 | A⑧ | 공용 코드 자리 | 새 공용 폴더 |
| 지도 | A⑨ | B05 에 보일 겹 | 모두(처음 끔) · 타당성 띠 · 올린 임도망도 숨김 |
| 지도 | A⑩ | 거리 재기 | 페이지 몫(단추 자리만 같게) |
| 긋기 | B1 | Shift 사이 기울기 값 | 실제 지형 |
| 긋기 | B2 | Shift 로 찍은 노드 기록 | 길이 고정 |
| 긋기 | B3 | +/− 색 | + 따뜻한 색 · − 찬 색 · 경고 빨강 · 노선 차례 색과 다르게 |
| 긋기 | B4 | 놓인 노드 색 | 들어온 구간 기울기 부호(저장 없이 셈) |
| 긋기 | B5 | 첫 구간 · 갈래 첫 구간 정방향 | 첫 구간 채움 없음 · 갈래 = 붙은 선 방향 |
| 긋기 | B6 | 역방향 부채꼴 | 테두리만 · 고를 수 있음 |
| 긋기 | B7 | 완만한 땅(노드 0) | 어느 방향이나(길이 고정처럼) |
| 긋기 | B8 | 「자유」 → 「자유지정」 | 원문대로 |
| 긋기 | B9 | 기본값 사용자마다 기억 | 안 함 |
| 추천 | D1 | 추천 모달 · 좌측 칸 | 통째 걷고 아이콘 드롭다운만 |
| 추천 | D2 | 지형 바꿈 새 자리 | 도구줄 지형 칩(A④와 같음) |
| 추천 | D3 | 예정노선 고치면 평면선 | 통째 다시 추적 · 직접 고친 것 버림 · 확인창 |
| 추천 | D4 | 고친 예정노선 저장 | 새 `expected_route_edit.csv`([초기화]면 사라짐) |
| 추천 | D5 | 옛 프로젝트 초기값 | 그대로 · 새 프로젝트부터 |
| 추천 | D6 | 초기 종단 | 지금 체인 그대로 |
| 추천 | D7 | 드롭다운 지형 | 지금 설계 지형 저장본만 |
| 추천 | D8 | 서버 `as_initial` 길 | 화면 부름만 끊고 서버 · 시험은 남김 |
| 추천 | D9 | 선 긋기 때 맨 위로 올릴 선 | B05 에서 고치는 예정노선 |
| 추천 | D10 | 예정노선 고치는 꼴 | 새로 긋기 · 구간 다시 긋기 · 지움(노드 끌기 없음) |
| 620 | E1 | 새 관 기본값 정책 | 집수정이면 기슭막이 칸 안 채움 · 동물이동형만 |
## 5. 단계 · 창
| 단계 | PLAN | 일 | 창 | 앞 일 |
|---|---|---|---|---|
| 0 | 623 | 620 고침(서버 기본값 한 자리 · 시험 기대값) | sub4 | 없음 |
| 1 | 625-1 | 예정노선 긋기 작은 고침(기본값 · 버튼 자리 · Tab · 숨김 · 이름) | sub4 | 623 |
| 1 | 624-1 | 서버 — D03 겹 길을 임도 프로젝트도 · 지형 원천 인자 · 지적도 파일 덮어씀 막기 | 622-1 끝난 창 | 622-1 |
| 2 | 625-2 | 부채꼴 · +/− 색 · 정방향 채움 · Shift 사이 기울기(새 TS 셈 파일) | sub4 | 625-1 |
| 2 | 624-2 | 공용 지도 부품(도구줄 표 · 겹 목록 · 범례 · 지형 칩) | 622-2 끝난 창 | 622-2 · 625-1(같은 파일 `D03_PlanAnalysis_UI_Map.ts`) |
| 3 | 624-3 | B05 평면에 공용 부품 붙이기(띠 = 등고선 · 하천만) | 624-2 창 | 624-1 · 624-2 |
| 3 | 626-1 | 노선추천 → 아이콘 드롭다운(저장본 선만) · [적용] 걷음 · 지형 칩으로 지형 바꿈 옮김 | 616 끝난 창 | 624-2 |
| 4 | 626-2 | 서버 `POST /route/follow` · `expected_route_edit.csv` | 624-1 창 | 624-1 |
| 4 | 626-3 | B05 예정노선 그리기(`B05_Profile_UI_RouteEdit.ts` 694 줄 먼저 나눔 · 625 컨테이너 복사) → 편집기 한 걸음 → [저장] | 626-1 창 | 625-2 · 626-1 · 626-2 |
| 5 | 624-4 | D03 라이다(D 프로젝트 LAS 올리기 · 지형 칩) | 624-1 창 | 626-2 |
## 6. 지킴(⚠ B 그룹 · 요구 491)
- 평면노선 값만 바뀜 — 예정노선 고쳐 평면 바꾸기 전후 B05/B06 저장본 대조(종단 · 횡단 · 배수 · 관 지점 · 구조물 · 측점 열쇠) = 평면 · 다시 셈 말고 차 0.
- 초기값 안 바뀜 — `initial_snapshot/` 지문 전후 같음 · [초기화] = 파일입력 예정노선 기준.
- 추천 다시 셈 없음 · `/route/replan` · `as_initial` · `expected_route.csv` 쓰기 0.
- 파일 700 줄 한도 · 고친 대상 시험 · 화면 = ORCA 수치.