chore(계획): 요구 440 요구서 · 분석 셋 · PLAN 579~582 승인 대기 — 예정노선 설계 · GIS 겹 · 등고선 성능

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-29 13:41:16 +09:00
co-authored by Claude Opus 5.5
parent addce07aa5
commit efb449a94e
4 changed files with 600 additions and 0 deletions
@@ -0,0 +1,160 @@
# 분석 440-A — 기준지정 복수 시점 · 종점 · 「다음」 GIS 받기 (요구 440 1 · 2)
읽기 전용 · 코드 읽기만(서버 · 브라우저 안 씀) · 줄 = main_laptop_1 `0c415aca6`.
## ① 결론 다섯 줄
1. 지금 D02 = 시점 하나 · 종점 하나 고정(`[null, null]` 두 칸) · 정본 = `projects.plan_base_json` `{epsg, start:{x,y}, end:{x,y}}` · 붉은 선 = 두 점을 잇는 카카오 기본 선색(`#E60046`) 한 줄.
2. 서버 뒷단은 이미 「점 목록」 꼴 — 지형 받기 범위(`plan_extent` · `ensure_plan_terrain`)는 점 몇 개든 감싸는 상자 + 여유로 셈 · 노선 정본(`derive`)은 시점 · 종점을 안 봄 · 갈래 없는 선 여럿도 받음 → 고칠 곳은 「두 점」을 넘기는 입구뿐.
3. 바꿀 자리 = D02 서버 꼴 · 화면 + D03 이 `start` · `end` 를 집는 여덟 곳(지형 입구 · 정본 굳힘 · 화면 변수 · 빈 선 · 종점 붙기 · 점 그림 · 맞춤 · 등고선 범위).
4. 「다음」 GIS = 지금은 D03 에 와도 자동 받기 없음([지형 범위 보기] → [이 범위 받기] 두 번 누름) · 범위 = 점 상자 + 350 m · 바뀔 점 = 들어올 때 덮지 못하면 받기를 바로 시작 + 새로 더한 시점 · 종점이 받은 범위 밖이어도 지금 화면은 「받은 지형 안」이라 보이는 흠.
5. 업체 조각(563-2)은 선 × 마크 구간 단위라 시점 · 종점 수와 무관 — 표 · API 고침 없음 · 선 이름(「본선 · 갈래 N」)만 갈래 없는 선이 여럿일 때 어긋남.
---
## 1. 지금 기준지정(D02) 동작
| 항목 | 지금 | 자리 |
| --- | --- | --- |
| 점 수 | 시점 1 · 종점 1 고정 · 화면 상태 `points = [null, null]` | `D02_PlanBase_UI_Page.ts:102` · 이름 `:106` · 빈 칸 찾기 `:107-110` |
| 놓기 | 📍 로 고른 칸(`active`) → 지도 누름 · 표지 끌기 · 경위도 칸 | `:103` · `:116-125` · `place` `:143-148` · 칸 `:168-214` |
| 붉은 잇는 선 | 두 점 다 있으면 `[[a],[b]]` 한 줄 → 카카오 `Polyline` 기본색 | `D02_PlanBase_UI_Page.ts:155-165` → `ui_template/ui_template_kakao_map.ts:20`(`LINE_COLOR #E60046`) · `:170-178` |
| 캐시 | 등록표 `d02-points` `{base, points}` · 서버 값과 같을 때만 씀 · 길이 2 검사 | `:113-114` · `:265-270` · `A00_Common/b_page_state.ts:204` |
| 저장 | [저장] · [>] · 떠남 = `PUT …/plan/points` 몸 `{start, end}` | `:233-254`(몸 `:236`) · 떠남 `mountGroupStep` `:93-99` |
| 정보 줄 | 저장 좌표계 + 시점 X · Y | `:216-220` |
| DB | `projects.plan_base_json` JSON 칸 하나 | `db_management/021_plan_base_json.sql:7` |
| 서버 꼴 | 요청 `BaseRequest {start, end}`(각 `LonLat \| null`) → TM 셈 · 좌표계 = 두 점 평균 경도 띠 | `D02_PlanBase_Router.py:42-44` · `stored_base` `:189-200`(평균 `:192`) · 쓰기 `:203-208` |
| 읽기 | `base_view` — 칸 있으면 그대로 · 비면 옛 연도 행 첫 시점 + 끝 종점으로 접음 | `:162-180` · `load_base` `:183-186` |
| API | `GET/PUT /api/projects/{id}/plan/points` → `{epsg, start, end}`(점 `{lon, lat, x, y}` · 빈 = null) · 고침 = 산림청만 | `:211-226`(권한 `:222-223`) |
| 죽은 코드 | `YearPoints` · `chain_years` · `with_tm` · `changed` · `_store` · `SAME_M` — 머리 주석은 「D03 [저장]이 씀」이나 지금 부르는 곳 없음(시험 하나만) | `:28` · `:36-152` · 시험 `test_529_3_plan_points.py:129-137` |
D02 정본을 읽는 곳(모두 `load_base` 하나 거침)
| 읽는 곳 | 쓰임 | 자리 |
| --- | --- | --- |
| D03 지형 입구 | `[start, end]` 두 점 → 범위 · 둘 중 하나 비면 400 | `D03_PlanAnalysis_Router.py:49-61`(거절 `:52-55` · 두 점 `:60`) · 범위 `:123-132` · 받기 `:135-149` · 겹 입구 `:161-167` |
| D03 노선 정본 GET | 응답 `base` 칸 그대로 | `D03_PlanAnalysis_Network.py:272-282` · `:285-298` |
| D03 노선 정본 PUT | 좌표계 같은지 · 칸 비면 접은 두 점 굳힘(`start` · `end` 열쇠) | `:413-415` · `:429-430` · `_freeze_base` `:390-400` |
| D03 화면 | `start` · `end` 변수 · 빈 선 = `emptyNetwork(start)` · 그리기 `base` · 등고선 점 · 맞춤 | `D03_PlanAnalysis_UI_Page.ts:86-89` · `:102` · `:121` · `:428` · `:500` · `:541-552` |
| D03 그리기 | 본선만 종점 둘레 12 px 붙기 · 본선 끝 = 종점 닿음 · 시점 초록 · 종점 빨강 점 | `D03_PlanAnalysis_UI_Draw.ts:75` · `:197` · `:233-240` · `:317` · `:348` · `:388-402` |
| D03 꼴 | `emptyNetwork(start)` · `reachedEnd(network, end)` · 선 이름 | `logic/D03_PlanAnalysis_Plan.ts:45-47` · `:227-231` · `:234-236` |
| 프로젝트 복제 | 칸 통째 복사(꼴 무관) | `common_util/common_util_project_copy.py:39` · 시험 `test_573_1_clone_de.py:170` |
D04 · B01 · B03 은 D02 정본을 안 읽음(조각 행 `plan_route_pieces` · 연도 행만).
---
## 2. 복수 시점 · 종점으로 바꿀 자리
### 2-1 저장 꼴 · 옛 꼴
- 새 꼴(권함) — 같은 칸 `plan_base_json` = `{"epsg", "starts": [{x, y}…], "ends": [{x, y}…]}` · 짝 없이 따로 목록(요구 「복수개의 시작과 복수개의 종료」).
- 옛 꼴 읽기 = `base_view` 한 곳에서 `start` → `[start]` · `end` → `[end]` 로 감쌈 · 옛 연도 행 접기는 그대로(첫 시점 1 · 끝 종점 1).
- 옮김 = 읽을 때만 바꿈 · 쓰기는 늘 새 꼴 · 마이그레이션 · SQL 없음(JSON 칸).
- 점 id 는 안 둠 — D03 선은 시점 · 종점을 id 가 아니라 좌표(1 mm)로 만남(`reachedEnd` · 갈래 첫 점 검사 `Network.py:101-104`).
- 좌표계 — 지금은 저장마다 평균 경도로 다시 고름(`:192`) · 점을 더하면 평균이 띠 경계(128° 등)를 넘어 EPSG 가 바뀔 수 있음 → D03 저장 노선 · 받은 지형과 어긋남(PUT 400 `Network.py:414-415`). 지금도 숨은 흠 · 점이 늘면 잦아짐 → 「저장된 epsg 가 있으면 그대로 씀」 한 줄 권함.
### 2-2 API
- `GET/PUT …/plan/points` 꼴만 바꿈 — 응답 `{epsg, starts: [{lon, lat, x, y}], ends: [...]}` · 몸 `{starts: [{lon, lat}], ends: [{lon, lat}]}`.
- 옛 `start` · `end` 칸은 안 남김 — 읽는 곳이 위 표 넷뿐이라 한 번에 바꿈.
- 검사 — 경위도 범위(지금 `LonLat`) 그대로 · 같은 자리 두 점(1 mm) 거절 여부 · 수 상한(예 20)은 물음 없이 기본값으로 둠.
- D03 이 받는 꼴 — `load_base` 응답이 새 꼴 · `PlanBaseView`(`D03_PlanAnalysis_Api.ts:23-27`) 같이 바꿈.
### 2-3 D02 화면
- 상태 `points[2]` → `starts[]` · `ends[]` · 표 = 「시점」 묶음 · 「종점」 묶음 · 줄마다 [📍][경도][위도][🗑] · 묶음 끝 [+ 시점] · [+ 종점](부품 `createIconButton` · 아이콘 `plus` · `trash` 있음 `ui_template_icons.ts:104` · `:120`).
- [+] = 빈 줄 하나 더하고 `active` 를 그 줄로 → 지도 누름이 거기 놓음(지금 흐름 그대로).
- 표지 이름 = 「시점 1」 「종점 2」(카카오 표지 색은 하나 — 이름 글로 가름 · 색 가름은 부품 상자 `MapPin` 에 칸을 더해야 함 → 뒤로).
- 붉은 선 지움 = `drawMap` 의 `lines` 를 늘 `[]`(`D02_PlanBase_UI_Page.ts:155-165` 삭제 · 공용 부품 손 안 댐).
- 캐시 꼴 `{base, starts, ends}` · 옛 캐시(`points`)는 꼴이 달라 무시(`:270` 길이 2 검사 대신 꼴 검사).
- 정보 줄 = 「시점 n · 종점 m · EPSG」(`:216-220`).
- 말 사전 — `D02_Points_Title` 「전체 시점 · 종점」 → 「시점 · 종점」 · 새 열쇠 [+ 시점] [+ 종점] [지움](`ui_template_locale_de.ts:121-142`).
- 줄 수 276 → 약 320 예상(700 안).
### 2-4 D03 이 시점 · 종점을 쓰는 곳(최소 맞춤)
| 자리 | 지금 | 바꿈 |
| --- | --- | --- |
| `Router._plan_ends` `:49-61` | `[start, end]` · 하나라도 비면 400 | 시점 · 종점 모두를 점 목록으로 · 시점 1 이상 · 종점 1 이상 아니면 400 |
| `Network._freeze_base` `:390-400` | `start` · `end` 열쇠 | 새 꼴 `starts` · `ends` |
| `UI_Page.ts:86-89 · 546-548` | `start` · `end` 한 점씩 | `starts` · `ends` 배열 |
| 빈 선 `UI_Page.ts:89 · 428` · `Plan.ts:45-47` | 본선 = 시점에서 한 줄 | 440-3(끝에서도 긋기) 몫과 묶임 — 최소안 = 시점마다 빈 선 한 줄 |
| 종점 붙기 `UI_Draw.ts:233-240` | 본선(`active === 0`)만 · 종점 하나 | 모든 선 · 가장 가까운 종점 |
| 끝남 판정 `UI_Draw.ts:197 · 317` · `Plan.ts:227-231` | 본선 끝 = 종점 | 선 끝이 종점 중 하나 |
| 점 그림 `UI_Draw.ts:348 · 388-402` | 초록 하나 · 빨강 하나 | 배열 돌림 |
| 맞춤 · 등고선 점 `UI_Page.ts:121 · 552` | `[start, end, …]` | `[...starts, ...ends, …]` |
- 서버 `derive`(`Network.py:83-165`)는 시점 · 종점을 안 봄 · 갈래 없는 선 여럿 받음(`:96-105` — `branch` 없으면 검사 없음) → 고침 없음.
- 440-3(시작에서도 · 종료에서도 긋기 · 부분 수정)이 같은 줄(`UI_Draw.ts` · `Plan.ts`)을 크게 고침 → 위 표 아래 넷은 440-3 일감과 한 창에서 하는 쪽 권함 · 440-A 단독이면 「시점마다 빈 선」 최소안만.
### 2-5 지형 받기 영역
- 셈은 이미 점 목록 — `wanted_box(points, margin, have)` = 모든 점 축 상자 ± 여유 ∪ 받은 범위(`D03_PlanAnalysis_Terrain.py:85-91`) · `plan_extent` `:125-154` · `ensure_plan_terrain` `:223-301`.
- 바꿀 곳 = 입구 `_plan_ends` 하나(점 수만 늘림) → 도엽 · 위성 · 지적도 · DEM 모두 따라옴.
- 한계 — 범위 = 상자 하나(받은 범위도 상자 하나 `plan_terrain.json` `:75-82`) · 시점 · 종점이 멀리 흩어지면(예 두 공사 터 10 km) 그 사이 빈 땅까지 받음 → 미리보기 창 「지형 칸 약 N 백만」(`UI_Page.ts:318-321`)으로 보임. 상자 여럿은 DEM 한 벌 구조를 바꿔야 해 뒤로.
### 2-6 업체 조각(563-2)과의 관계
- 조각 = 선 × 마크 구간(`plan_route_pieces` · `Network.py:128-157`) · 업체 = `plan_route_assignees.piece_id` → 시점 · 종점 수와 무관 · 표 · API · D04 · B01 · B03 고침 없음.
- 어긋남 하나 — 선 이름 = 「차례 0 = 본선 · 그 밖 = 갈래 N」(`D04_PlanConfirm_Repository.py:68-70` · `logic/D03_PlanAnalysis_Plan.ts:234-236`) → 시점이 둘이라 갈래 없는 선이 둘이면 둘째도 「갈래 1」로 보임 · 조각 이름 「갈래 1 0+0~…」 · 내보내기 폴더 이름까지(`D04_PlanConfirm_Router.py:382-384`). 갈래 없는 선 = 「본선 N」 꼴로 두 곳 같이 고침(440-3 몫과 묶임).
---
## 3. 「다음」으로 넘어갈 때 GIS 받기
### 지금
- D02 [>] = 저장 뒤 D03 이동(560-4) · D03 열 때 = 지형면 읽기 → 없으면 「받은 지형 없음」 + [지형 범위 보기](`UI_Page.ts:132-137` · `:233-246`) → 창에서 범위 · 도엽 미리보기 → [이 범위 받기](`:291-363`) → 진행 막대(`:365-410`). 자동 받기 = 일이 이미 돌 때 지켜보기만(`:557`).
- 받는 것 한 번에 = 도엽(등고선 · 하천 · 도로 …) · 위성(VWorld) · 지적도 · DEM 2 m(`Terrain.py:247-288`) · 겹 단추는 받기 뒤에만 켜짐(`UI_Layers.ts:141-152`) · 처음 켬 = 위성 · 등고선 · 세류.
- 범위 = 시점 · 종점(+ 그은 점) 축 상자 + 여유 350 m(`Terrain.py:51` · 300~5000 `:68-72` · 창에서 고침 `UI_Page.ts:323-337`) ∪ 받은 범위 · 등고선 겹은 점 둘레 600 m 만 그림(`UI_Layers.ts:62` · `:200-213`).
- 「자동 다시 받기 없음」은 요구 389 정함 7(`요구서_389_예정노선_수동노선.md:31`) — 옛 흠(열 때마다 다시 받아 같은 실패 반복 · `_분석_389-B` B 절) 때문.
### 바뀔 점
1. 기준 = D02 시점 · 종점 모두(2-5 · 입구 한 곳).
2. 들어올 때 받기 — 산림청 · 일 안 돎 · 직전 받기 실패 아님 · 서버 `covered = false`(받은 범위가 지금 시점 · 종점 상자를 못 덮음)일 때만 `startTerrain(기본 여유)` 바로 · 아니면 지금 그대로. 같은 실패 반복 막음 = 진행 `error` 있으면 자동 안 함(그땐 [다시 받기]). 자리 = `UI_Page.ts:554-557` 몇 줄 · 서버 고침 없음.
3. 흠 고침 — 「범위 밖」 판정 `outside()`(`UI_Page.ts:219-221`)가 그은 꺾임점만 봄 → D02 에서 받은 범위 밖에 새 종점을 더해도 「받은 지형 안」 · [범위 밖 더 받기] 안 보임. 시점 · 종점도 넣음(한 줄) — 2번 자동 받기가 서버 `covered` 로 같은 일을 하므로 둘 중 하나로 충분.
4. 여유 폭 — 350 m 그대로 권함(점 상자 기준 · 선이 상자 밖으로 휘면 [범위 밖 더 받기]) · 흩어진 점은 2-5 한계.
5. 받기 시간 — 도엽 6매 약 143 s(561-3 기록) → 들어오자마자 진행 막대 · 그동안 긋기는 되나 길이 · 기울기 미리보기는 지형 뒤(지금 안내 글 그대로).
---
## 4. 갈래 · 기존 노선 잇기와 시점 · 종점
- 갈래(562-3) = 그은 선 꺾임점에서 새 선(`branch {line, vertex}` · `Plan.ts:186-199` · 서버 첫 점 1 mm 검사 `Network.py:96-105`) — D02 시점 · 종점과 따로임. 「같은 연도 갈래」 = 조각마다 연도를 고르므로 갈래 조각도 본선과 같은 해 · 다른 해 다 됨.
- 연도 마크 = 선 위 누가 `at_m` · 조각 경계(`Plan.ts:79-112` · `Network.py:108-123`) — 시점 · 종점에 연도를 달 일 없음. 다년간 = 한 선을 마크로 나눠 조각마다 연도 · 단독 = 마크 없이 한 조각.
- 여러 시점 = 갈래 없는 선 여럿(서버가 이미 받음) · 여러 종점 = 선 끝이 어느 종점에든 닿으면 끝 · 갈래 끝이 종점에 닿아도 같음.
- 「기존 노선과 잇기」 — 지금 D02 · D03 어디에도 기존 노선(옛 B 임도 · 다른 D 사업 · 도엽 도로)에 붙는 기능 없음 · D03 겹 「기존 도로(도엽 도로중심선)」는 그림만(`UI_Layers.ts:57` · `:231-232`). 시점을 기존 길 위에 놓는 것은 사용자가 카카오 지도(위성)를 보고 놓는 것으로 충분하다고 봄 → 붙기 기능은 물음 2.
- 시점이 이미 그은 선 위에 있으면 갈래로 볼지 — 지금 규칙(좌표 1 mm)으로는 따로 선 · 묻지 않고 따로 선으로 둠.
---
## 5. 고칠 파일 · 갈래(작은 것 먼저)
| 차례 | 일 | 파일 | 시험 |
| --- | --- | --- | --- |
| W1 | 서버 꼴 — 새 꼴 읽기 · 쓰기 · 옛 꼴 감쌈 · epsg 그대로 · 죽은 연도 잇기 코드 지움 | `D02_PlanBase/D02_PlanBase_Router.py` | `test_529_3_plan_points.py`(두 점 → 목록 · 옛 꼴 · 접기 · chain 시험 지움) |
| W1 | 입구 둘 — 점 목록 · 굳힘 꼴 | `D03_PlanAnalysis/D03_PlanAnalysis_Router.py:49-61` · `D03_PlanAnalysis_Network.py:390-400` | `test_530_2_plan_router.py:30-66`(가짜 `plan` 꼴) · `test_530_2_plan_analyze.py:177-246` |
| W2 | D02 화면 — 시점 · 종점 목록 · [+] · [🗑] · 붉은 선 지움 · 캐시 꼴 | `D02_PlanBase/D02_PlanBase_UI_Page.ts` · `_UI_Style.css`(줄 칸 넷) · `ui_template/ui_template_locale_de.ts:121-142` | `test_553_4_de_parts.py:19-27` · `test_560_4_leave_save.py:22-29`(꼬리 정규식 `active = firstEmpty(); paint();` — 이름 바꾸면 같이) |
| W3 | D03 받는 꼴 — 배열 · 점 그림 · 맞춤 · 등고선 점 · `outside` 에 시종점 | `D03_PlanAnalysis_Api.ts:23-27` · `_UI_Page.ts` · `_UI_Draw.ts`(점 그림) | `test_530_3_plan_logic.py`(빈 선 · 끝남) · typecheck |
| W4 | 들어올 때 자동 받기(요구 2) | `D03_PlanAnalysis_UI_Page.ts:554-557` | ORCA 한 바퀴 |
| (440-3 과 묶음) | 시점마다 빈 선 · 아무 종점 붙기 · 끝남 판정 · 선 이름 「본선 N」 | `logic/D03_PlanAnalysis_Plan.ts` · `_UI_Draw.ts` · `D04_PlanConfirm_Repository.py:68-70` | `test_530_3` · `test_563_2` |
- 가이드 `A05_EduDetail/guide/D02`(장면 `_scenes.json` 이 `.d02-points__row:nth-child(2)` 를 잡음)는 사용자 지시 때 몰아서.
- 계산 자리 = ③ 서버 단독(TM 셈 · 범위) 그대로 — 새 짝 없음.
---
## 6. 사용자 물음
1. 「다음」 GIS — 들어오자마자 바로 받기(약 2~3 분 진행 막대 · 389 「자동 받기 없음」을 바꿈) vs 지금처럼 범위 미리보기 창을 저절로 띄워 [이 범위 받기] 한 번 누름 — 어느 쪽인지.
2. 시점 · 종점 = 짝 없이 따로 목록 · 최소 시점 1 · 종점 1 · 점에 연도 · 종류(「기존 노선 잇기」 표시 · 기존 길 붙기)는 안 둠 — 맞는지.
---
## 7. 확인 못 함
- 흩어진 시점 · 종점(수 km)에서 상자 하나 받기 시간 · 메모리 — 실측 안 함(어림 = 칸 수 비례 · 6매 143 s).
- 카카오 지도에 표지 열 개 넘게 놓았을 때 이름 글 겹침 — 화면 안 봄.
- 띠 경계(127° · 128° · 129°)에 걸친 사업이 실제 있는지 — DB 안 봄(2-1 epsg 흠은 코드상 가능성).
@@ -0,0 +1,209 @@
# 분석 440-B — 노선 긋기(시점 · 종점 양쪽 · 부분 수정) · 미리보기 각도 · 각도 고정 · 연도 지정 · 연도 마커 (요구 440 3~7)
읽기 전용 · 코드 읽기만(서버 · 브라우저 안 씀) · 줄 = main_laptop_1 `7d0353022`(D03 · D02 · D04 파일은 `d8b93a4ea` 와 같음) · 440-A(`_분석_440-A_기준지정_복수시종점.md`)와 맞춤.
## ① 결론
1. 지금 = 시점에서만 긋기 · 본선은 끝에서 이어 긋기 됨 · 갈래 이어 긋기 · 종점에서 긋기 · 꺾임점 끌기 · 가운데 점 더하기 · 지우기 · 선 고르기 · 선 하나 지우기 · 각도 글 · 각도 고정 모두 없음 · 연도 = 조각(선 × 마크 사이)마다 왼쪽 판에서 고름 · 연도 마커 = 지금 [구역 마크](562-3) 그대로 있음.
2. 저장 꼴 바뀜 없음 — 종점에서 그은 선을 끝낼 때 한 번 뒤집으면 지금 꼴(선 · 갈래 · 마크 · 조각)에 그대로 들어감 · 서버 `derive` 고침 없음.
3. 각도 = 수평 방향 각으로 읽음(「기울기 고정」이 이미 「기울기 고정 · 길이 자유」라서) · 갈래 = 방위각(도북) · 꺾인 각(교각) · 둘 다 → 미리보기엔 둘 다 · 고정은 하나 고름(물음 1).
4. 각도 고정 = 길이 고정의 짝(길이 고정 = 원 위 · 각도 고정 = 반직선 위) · 제약 고름 넷에 「각도 고정」 하나 더함 · 섞음은 안 만듦.
5. 연도 꼴 = 조각(마커로 나눈 구간) 단위 그대로 · 노선 단위 = 「그 선 조각 모두 같은 해」 지름길(저장 칸 덧 없음) · 연도 마커 = 구역 마크와 같은 것.
6. 고칠 곳 = `logic/Plan.ts`(꼴 함수 일곱) · `logic/Draw.ts` ↔ `Draw.py` 짝(각도 셋) · `UI_Map.ts`(끌기 놓음 창구) · `UI_Draw.ts` · 새 `UI_Edit.ts`(고르기 · 고치기) · `UI_Page.ts`(선 해 고름 · 긋는 해) — 440-A 의 D03 몫(시점 · 종점 배열 · 아무 종점 붙기 · 「본선 N」)과 한 창에서.
---
## 1. 지금 D03 그리기 도구 — 하는 것 · 못 하는 것
파일 = `D03_PlanAnalysis/` 아래(`UI_Draw` = `D03_PlanAnalysis_UI_Draw.ts` · `Plan` = `logic/D03_PlanAnalysis_Plan.ts` · `Draw` = `logic/D03_PlanAnalysis_Draw.ts` · `Page` = `D03_PlanAnalysis_UI_Page.ts` · `Map` = `D03_PlanAnalysis_UI_Map.ts`).
| 항목 | 됨? | 지금 하는 것 | 자리 |
| --- | --- | --- | --- |
| 시점 쪽에서 긋기 | 됨 | [본선 긋기] = D02 시점에서 점 찍기 · 빈 선 = 시점 한 점 | `UI_Draw:117-122` · `setMode :312-327`(늘 `active = 0` `:321`) · `Plan:45-47` |
| 종점 쪽에서 긋기 | 안 됨 | 종점은 붙는 자리일 뿐(본선만 · 12 px) · 종점에서 시작할 길 없음 · 본선이 종점에 닿으면 [본선 긋기] 꺼짐 | `previewAt :238-239` · `panelState :197-200` · `:317-319` · `Plan reachedEnd :227-231` |
| 이어 긋기 — 본선 | 됨(종점 닿기 전) | Enter 로 끝낸 뒤 [본선 긋기] 다시 = 본선 마지막 점에서 | `:321-322` · `lastOf :221-224` |
| 이어 긋기 — 갈래 | 안 됨 | [갈래]는 늘 새 갈래 · 끝낸 갈래를 다시 잡을 길 없음 | `press :409-425` |
| 갈래 | 됨 | 선 위 · 꺾임점 누름 → 거기서 새 선(선 위면 꺾임점 끼움) | `:409-425` · `Plan insertVertex :124-145` · `addBranch :186-199` |
| 끝 붙기 | 본선만 | 본선 → D02 종점 하나(12 px) · 갈래 끝은 선 · 꺾임점 · 종점 어디에도 안 붙음 | `:238` · `SNAP_PX :52` |
| 꺾임점 끌기 | 안 됨 | 겹 창구 = 누름 · 곁 · 나감뿐 · 지도에 `pointerup` 없음 | `Map:68-73` · `:269-292` |
| 꺾임점 더하기 | 따로 없음 | 갈래 시작 때 곁따라 끼울 뿐 | `UI_Draw:414-417` |
| 꺾임점 지우기 | 끝 점만 | 긋는 중 Backspace = 마지막 점 빼기(선 첫 점 · 갈래 붙은 점은 못 뺌) · 가운데 점 지우기 없음 | `key :586-596` · `Plan dropLastVertex :158-172` |
| 되돌림 | 됨 | Esc = 이번 긋기 통째 · Ctrl+Z · Y = `commit` 한 걸음(100) | `:579-585` · `Page:183-207` · `UNDO_MAX :66` |
| 미리보기 글 | 길이 · 기울기만 | 「35.2 m · +6.1 %」(+ 오르막) · 붙음 · 자리 없음 안내 · **각도 없음** | `DrawPreview :64-72` · `previewAt :250-258` · 글 `:527-538` |
| 그은 구간 글 | 길이 · 기울기만 | 도구줄 「구간 길이 · 기울기」 켤 때 · 화면 70 px 넘는 구간 | `segmentLabels :448-461` · `LABEL_MIN_PX :56` |
| 제약 | 넷 | 자유 · 길이 고정(마우스 방향 · 길이 L) · 기울기 고정(마우스 방향 반직선 위 \|기울기\| 자리 중 마우스 거리에 가장 가까운 것 · **길이 자유**) · 둘 다(반지름 L 원 위 후보 중 마우스 가까운 것) | 고름 `:138-153` · 분기 `:240-248` · 셈 `Draw:38-45` · `:50-106` · `:110-179` |
| 제약 처음 값 | — | 길이 20 m(측점 간격) · 기울기 9 %(± 같음 · 간선 20 km/h 상한) | `:58-59` · 칸 `:154-180` |
| 각도 고정 | 없음 | — | — |
| 노선 고르기 | 없음 | 쉴 때 누름 = 아무 일 없음 · 선 집기 `lineAt` 은 갈래 · 마크 몫만 · 3D 창 「선 고름」은 보기만 | `press :403-439` · `lineAt :262-298` · `UI_3D.ts:3-4` |
| 노선 지우기 | 없음 | 점 하나뿐인 갈래 버림 · 긋는 중 Backspace 로 갈래 첫 점까지 가면 그 갈래 지움 · 전체는 [초기화] | `stop :301-310` · `Plan dropLastLine :175-183` · `Page reset :460-483` |
| 연도 지정 | 조각마다 | 왼쪽 「구역 · 연도」 = 선 머리 줄(이름 · 길이) + 조각 줄마다 고름 · 선 통째 해 없음 · 새 선 = 사업연도 시작 해 · 고름 = 시작 해부터 10 해 | `Page renderPieces :251-288` · 새 조각 해 `commit :186` · `YEAR_SPAN :68` · `Plan setPieceYear :115-120` |
| 긋는 중 연도 | 왼쪽 판만 | 왼쪽 고름은 긋는 중에도 됨(모드 안 끊음 · 키는 고름 안이면 안 받음) · 지도 위 고름 · 「긋는 해」 없음 | `Page:273-281` · `:517-518` |
| 연도 구분 마커 | 됨(562-3 구역 마크) | [구역 마크] 모드 선 위 누름 = 조각 둘(같은 해) · 오른쪽 누름 = 지움(앞 조각 해로 합침) · 마름모 + 조각 가운데 「2027년」 · 꺾임점 12 px 안이면 꺾임점에 붙음 · 끌어 옮기기 · 측점 붙기 없음 · 끝 · 다른 마크 1 m 안 못 놓음 | `press :426-437` · `drawPieces :463-489` · `Plan splitPiece :79-94` · `removeMark :97-112` · `MARK_GAP_M :34` |
| 단축키 표 | — | Enter · Esc · Backspace · Ctrl+Z/Y(설정 창 D03 줄 · 지도 [?] 안내 여덟 줄) | `ui_template/ui_template_locale_common.ts:163-165` · `Map:154-163` |
옛 고침 기능(543 · 꺾임점 끌기 · 넣기 · 지우기 · R 손잡이)은 엔진 노선용이라 562-3 에서 걷음(`cdcdd5f59` — `UI_Edit.ts` · `logic/Edit.ts`). 끌기 꼴(grab · move · release)만 참고 감(`git show cdcdd5f59^:D03_PlanAnalysis/D03_PlanAnalysis_UI_Edit.ts`).
---
## 2. 항목별 고칠 자리 · 가장 작은 고침 · 저장 꼴 영향
### 2-3 시점 · 종점 양쪽에서 긋기 · 부분 수정
시작 자리 하나로
- [본선 긋기] · [갈래] 두 단추 → [긋기] 하나 · 첫 누름 자리 = 시점 표지 · 종점 표지 · 선 끝(이어 긋기) · 선 위 점(갈래). 440-A 복수 시점 · 종점(`starts[]` · `ends[]`)과 같은 길 — 점 수와 무관.
- 집기 = 지금 `lineAt :262-298`(꺾임점 12 px · 선 8 px) + 표지 · 선 끝 집기 몇 줄.
종점에서 그은 선
- 긋는 동안 = 그린 차례 그대로(첫 점 = 종점 · 꼬리에 더함 = 지금 `appendVertex`).
- 끝낼 때(Enter · 붙음 · 모드 바꿈 · [저장] 앞 `stop`) 한 번 뒤집음 → 종점이 선 끝 · 측점 No.0 = 반대쪽(물음 2).
- 끝 자리에 따라
- 다른 선 꼬리(예 본선 끝)에 붙음 → 그 선에 이어 붙여 한 선(측점 한 줄 · 「시점 → 종점」 본선 완성)
- 다른 선 꺾임점 · 선 위에 붙음 → 갈래(뒤집으면 첫 점 = 부모 점 → 지금 갈래 꼴 그대로 · 서버 1 mm 검사 `Network.py:96-104` 통과)
- 안 붙음 → 갈래 없는 선(서버가 이미 받음 · 440-A 2-4)
- 끝 붙기 넓힘 — 긋는 선 끝이 종점(들) · 다른 선 끝 · 꺾임점 12 px 안이면 붙음(지금 `:238` 본선 → 종점 하나만).
이어 긋기
- 선 끝 누름 → 그 선이 `active`. 갈래 없는 선의 머리(첫 점)에서 잇기 = 뒤집기 → 꼬리에 더함 → 끝낼 때 다시 뒤집기(머리 끼우기 · 마크 밀기를 따로 만들지 않음).
- 잠금 — 본선 · 시점에서 시작한 선의 머리 · 갈래 머리(부모에 붙음) · 종점에 닿은 꼬리.
부분 수정 = [고치기](또는 쉴 때 누름)
- 꺾임점 끌기 · 선 위 누름 = 꺾임점 더함 · 꺾임점 오른쪽 누름 = 지움.
- 잠금 = 시점 · 종점에 놓인 점 · 갈래 첫 점(부모 점을 끌면 같이 감) — 시점 · 종점 자리는 D02 몫.
- 가운데 점 지움 = 갈래 붙은 점은 막음(지금 말 「갈래를 먼저 지우세요」 `Plan:165` 그대로) · 뒤쪽 갈래 차례 −1.
- 끌기 중엔 `commit` 안 함 · 놓을 때 한 번(되돌리기 한 걸음 · 캐시 한 번).
- 마크 따라가기 — 길이가 바뀌면 `at_m` 이 어긋남(줄면 끝 밖 마크는 `normalizePieces :59-61` 이 말없이 버림 → 업체 지정 조각이면 [저장] 409 `Network.py:320-326`) → 끌기 = 그 구간 안 비율 그대로 · 지움 = 합친 구간 안 비율 · 선 위 더함 = 그대로(`Plan:122-123`).
가장 작은 고침
- `Plan.ts` 순수 함수 — `reverseLine`(꼭짓점 · 그 선 조각 `from/to = L − …` · 붙은 갈래 차례 `n−1−v`) · `joinLines`(꼬리 + 뒤집은 선 · 조각 · 갈래 옮김 · 조각 id 그대로) · `moveVertex`(붙은 갈래 첫 점 같이 · 마크 비율) · `removeVertex` · 끝남 판정 = 종점 중 하나(440-A).
- `UI_Map.ts` — `PlanMapLayer` 에 `release?()` · `pointerup` 한 줄 · 끌기 중 `hover` 그대로 받음(`:275-281`).
- `UI_Draw.ts` — `active` 에 「종점에서 왔나」 · `stop` 에서 뒤집기 · 합치기 · `previewAt` 붙기 넓힘 · [긋기] 하나.
- 새 `UI_Edit.ts` — 고치기 · 고르기 겹(`UI_Draw` 616 줄 · 700 넘음).
저장 꼴 — 바뀜 없음(`plan_networks.network_json` 꼴 그대로). 영향 = 합치기 때 종점 쪽 선 id 사라짐 · 그 조각은 본선으로 옮겨 id 그대로(업체 지정 유지) · 꺾임점을 끌면 그 조각 지문이 바뀌어 그 해 확정 풀림(`Network.py:360` · 지금 규칙 그대로).
### 2-4 미리보기 거리 · 각도
- 자리 — `DrawPreview :64-72` 에 각도 칸 · `previewAt :250-258` · 글 `:527-538` · 검증 창구 `Page:502` 저절로 따라옴.
- 셈 — `Draw.ts` 짝에 `azimuthDeg(a, b)` · `deflectionDeg(prev, a, b)` → `Draw.py` 같은 이름(snake) + 거울 시험 `test_562_1_plan_draw.py` 경우 덧(짝 규칙 `Draw.ts:7-8`). 서버는 각도를 안 씀 — 그래도 그리기 셈은 모두 짝에 있는 지금 결 따름.
- 꺾인 각의 앞 구간 = 긋는 선 마지막 구간 · 갈래 첫 구간 = 부모 선의 그 점 앞 구간 · 없으면 방위만.
- 글(안) — 「35.2 m · +6.1 % · 방위 123.4° · 우 25.0°」 · 돌린 지도에서도 방위는 좌표 북 기준(돌림은 글 세우기만 `:550`).
- 그은 구간 글(`:458`)에 각도 — 요구는 미리보기만 → 안 더함.
- 저장 꼴 — 없음.
### 2-5 각도 고정 · 길이 자유
- 자리 — `DrawConstraint :61` 에 `"angle"` · 고름 `:139-144` 에 「각도 고정」 · 칸 「각도 °」(`createInputField` · 길이 칸 꼴 `:154-166`) · `fieldsState :190-193` · `previewAt :240-248` 분기 하나.
- 셈 — `fixedAnglePoint(from, cursor, angleDeg)` = 반직선 방향 u · 점 = `from + max(0, (cursor − from)·u)·u`(마우스를 반직선에 내린 발) · 뒤쪽이면 길이 0 → 지금 `blocked` 규칙(`:256`). 짝 + 거울 시험.
- 그림 — 고정 방향 반직선 점선 하나(「둘 다」 원 그림 `:501-515` 옆).
- 칸 처음 값 — 「각도 고정」을 고르는 순간의 미리보기 방위(방향 잠금 꼴) · 값을 넣어 바꿈도 됨.
- 꺾인 각으로 고정이면 첫 구간에 앞 구간 없음 → 방위로 대신(물음 1).
- 저장 꼴 — 없음(찍은 점만 저장).
### 2-6 연도 지정 · 노선 고르기 · 지우기
- 고르기 — 쉴 때 선 누름 = 그 선 · 누른 조각 고름(굵게 · `--draw-primary`) · 왼쪽 「구역 · 연도」 그 줄 밝힘 · `lineAt` 그대로.
- 선 통째 해 — 왼쪽 선 머리 줄(`Page:259-264`)에 고름 하나 → 그 선 조각 모두 그 해(`setLineYear` · `Plan` 한 줄) · 조각마다 해가 다르면 「여러 해」.
- 긋는 해 — 그리기 칸에 「긋는 해」 고름 · 새 선 · 새 조각 처음 해 = 그 해(`commit` 의 `normalizePieces(next, yearStart)` `Page:186` → 긋는 해).
- 긋는 도중 해 바꿈 — 지금 끝 점 자리에 마커 저절로 · 뒤 조각 = 새 해(끝 자리에선 `splitPiece` 못 나눔 `Plan:84` → 다음 점을 찍는 `commit` 에 나눔까지 한 걸음).
- 지우기 — 고른 선 + Delete 키 · [선 지움] → `removeLine`(그 선 · 조각 지움 · 그 선에 붙은 갈래가 있으면 막음 · 본선 = 시점만 남김) · Delete 를 단축키 표(`locale_common.ts:163-165`) · 지도 [?](`Map:154-163`)에.
- 지도 위 떠 있는 해 고름(`ui_template_float_panel`)은 뒤로 — 왼쪽 판 + 지도 밝힘으로 먼저.
- 저장 꼴 — 없음. 영향 = 업체 지정 조각이 든 선을 지우면 [저장] 409(지금 보호 그대로) · 선 이름 「갈래 N」 = 차례라 가운데 선을 지우면 뒤 이름이 당겨짐(`D04_PlanConfirm_Repository.py:70` · `Plan:234-236` · 내보내기 폴더 이름) → 440-A 「본선 N」 고침과 같이.
### 2-7 연도 구분 마커
- 지금 [구역 마크](562-3)가 곧 이것 — 새로 만들 것 없음 · 단추 이름만 「연도 구분」으로 바꿀지는 글 한 줄.
- 모자란 것
- 놓은 뒤 뒤 조각이 바로 고름 상태 · 왼쪽 그 줄 밝힘(2-6 고르기 다시 씀).
- 마커 끌어 옮기기 — `moveMark`(앞 · 뒤 조각 경계 함께 · `MARK_GAP_M` 지킴 · 조각 id 그대로).
- 측점(20 m 배수) 붙기 — 뒤로.
- 6 과 잇기 = 고르기 하나 — 선 누름 = 선 · 조각 · 마커 누름 = 마커(끌기 · 오른쪽 지움).
- 저장 꼴 — 없음(`marks [{line, at_m}]` + `pieces [{id, line, from_m, to_m, year}]` `Network.py:54-71`).
### 저장 꼴 영향 한눈
| 저장 | 3~7 영향 |
| --- | --- |
| `plan_networks.network_json` | 꼴 그대로 — 선(꼭짓점 · 갈래) · 마크 · 조각 · 서버 `derive`(`Network.py:83-165`) 고침 없음 |
| `plan_route_pieces` | [저장] 때 통째 다시 씀(`:332-351`) · 열쇠 = 조각 id → 뒤집기 · 합치기 · 끌기 · 지우기 함수가 조각 id 를 넘겨 줘야 함(업체 `plan_route_assignees.piece_id`) |
| `plan_route_years` | 해마다 그 조각 모음 · 지문 바뀐 해만 확정 풀림(`:352-371`) — 그대로 |
| 연도 열쇠 `route_<연도>_<지점 열쇠>` | 지금 없음 — 543-4 파생 파일(`4753d8898` · 옛 `Analyze.py`) · 562-2 에서 엔진과 함께 걷음(`ba255f285`) · 지금 D03 파생 저장본 = 급경사 겹만(`Layers.py:244` · `:258`) → 영향 없음 |
| 캐시 `d03-plan {version: 2, network}` | 꼴 같으니 판 안 올림 · 긋는 해 · 고름 · 「종점에서 왔나」 = 화면 기억(캐시 밖) |
---
## 3. 「각도」 정의 · 각도 고정과 길이 고정
| 갈래 | 뜻 | 좋은 점 | 걸림 |
| --- | --- | --- | --- |
| (가) 방위각 | 좌표 북(TM 도북)에서 시계 방향 0~360° | 첫 구간 · 갈래 첫 구간에도 뜻 · 도면 방위와 같음 | 꺾임 크기는 머리로 셈 |
| (나) 꺾인 각(교각) | 앞 구간 방향에서 좌 · 우로 꺾인 각 0~180° | 임도 곡선(교각 · R)과 바로 이어짐 · 「30° 꺾어 긋기」 | 첫 구간에 앞 구간 없음 |
| (다) 둘 다 | 미리보기에 둘 다 · 고정은 하나 고름 | 보기는 다 됨 | 고름 칸 하나 더 |
- 권함 = 보기 (다) · 고정 기본 (가) — 물음 1.
- 진북 대 도북 — 좌표 북 = 도북 · 진북과 차 = 자오선 수렴각 ≈ Δ경도 × sin 위도 · D02 가 두 점 평균 경도로 TM 띠를 고름(`D02_PlanBase_Router.py:192`)이라 Δ경도 ±1° 안 · 위도 37.5° 면 최대 약 0.6°. 권함 = 도북(지도 위쪽 = 0° · 글에 「도북」) · 진북이면 수렴각 셈 하나 더.
- 경사각(°)으로 읽는 갈래는 뺌 — 「기울기 고정」이 이미 「기울기 고정 · 길이 자유」라 5번이 그 뜻이면 이미 됨(물음 1 끝 줄).
각도 고정 ↔ 길이 고정
- 길이 고정 = 길이 L 묶음 · 방향 자유(마우스 방향) → 점이 출발점 둘레 원 위.
- 각도 고정 = 방향 θ 묶음 · 길이 자유(마우스를 반직선에 내린 발) → 점이 반직선 위.
- 둘은 극좌표 두 축의 짝 — 둘 다 묶으면 점 하나로 정해짐(마우스 뜻 없음 = 값 넣고 찍기 꼴).
- 기울기 고정도 「길이 자유」 꼴이나 방향은 마우스 · 각도 + 기울기 = 고정 반직선 위 기울기 자리(`fixedSlopePoint` 에 반직선 위 가짜 커서를 넘기면 그대로).
- 「길이 고정 20 · 기울기 9 %」(562-1 덧) = 칸 처음 값(`UI_Draw:58-59`)일 뿐 · 각도 칸도 처음 값 하나(2-5 = 고르는 순간 방위).
- 고침 = 고름 넷 → 다섯(「각도 고정」 덧) · 각도 + 길이 · 각도 + 기울기 섞음은 안 만듦(요구 5 = 각도만).
---
## 4. 연도 지정 꼴
| 꼴 | 뜻 | 판정 |
| --- | --- | --- |
| 노선 단위 | 선마다 해 하나 · 마커 없음 | 한 선을 해마다 못 나눔 → 요구 7 과 어긋남 |
| 구간 단위(마커로 나눈 조각) | 지금 꼴(562-3) · 업체 지정 단위(요구 391) | 노선 단위는 「그 선 조각 모두 같은 해」인 특별한 경우 |
- 권함 = 조각 단위 그대로 · 노선 단위 = 화면 지름길(선 머리 줄 고름 · 지도에서 선 고름 → 그 선 조각 모두) · `line.year` 칸 안 둠(조각 해와 어긋날 자리 생김).
- 지금 구역 마크와 합침 = 같은 것 — 연도 구분 마커 = 구역 마크 = 조각 경계 · 해는 조각에 · 마커 양쪽 같은 해도 됨(업체만 나눌 때 · 요구 391).
- 긋는 중 = 「긋는 해」(새 조각 처음 값) · 도중 바꿈 = 그 자리 마커 저절로.
- 새 마커 뒤 조각 처음 해 = 지금 같은 해(`Plan:91`) — 다음 해로 할지 물음 3.
---
## 5. 고칠 파일 · 차례
| 차례 | 일 | 파일 | 시험 |
| --- | --- | --- | --- |
| W1 | 꼴 함수 — `reverseLine` · `joinLines` · `moveVertex` · `removeVertex` · `removeLine` · `setLineYear` · `moveMark` · 끝남 = 종점 중 하나 | `logic/D03_PlanAnalysis_Plan.ts`(236 → 약 380) | `test_530_3_plan_logic.py`(+ 서버 `derive` 가 받는지 대조) |
| W1 | 셈 짝 — `azimuthDeg` · `deflectionDeg` · `fixedAnglePoint` | `logic/D03_PlanAnalysis_Draw.ts` ↔ `D03_PlanAnalysis_Draw.py` | `test_562_1_plan_draw.py` 거울 경우 덧 |
| W2 | 지도 놓음 창구 — `release` · `pointerup` | `D03_PlanAnalysis_UI_Map.ts` | typecheck |
| W2 | 긋기 — [긋기] 하나 · 종점에서 긋기 · 뒤집기 · 합치기 · 끝 붙기 넓힘 · 미리보기 각도 글 · 각도 고정 칸 · 긋는 해 | `D03_PlanAnalysis_UI_Draw.ts`(616 — 고르기 · 고치기를 빼도 700 근처 → 미리보기 그림을 따로 뺄 수도) | typecheck |
| W2 | 고르기 · 고치기 겹 — 선 · 조각 · 마커 고름 · 꺾임점 끌기 · 더함 · 지움 · Delete | 새 `D03_PlanAnalysis_UI_Edit.ts` | typecheck |
| W3 | 페이지 — 선 머리 줄 해 고름 · 고른 줄 밝힘 · 긋는 해를 `commit` 에 · Delete 키 · 검증 창구(고름 · 각도) | `D03_PlanAnalysis_UI_Page.ts`(561 → 약 620) · `_UI_Style.css`(고른 줄) | ORCA 한 바퀴 |
| W3 | 단축키 표 · [?] 안내 | `ui_template/ui_template_locale_common.ts:163-165` · `UI_Map.ts:154-163` | — |
| W3 | 부품 단언(새 단추 · 칸 = 부품 상자) | — | `test_553_4_de_parts.py` |
| 묶음 | 440-A D03 몫 — 시점 · 종점 배열 · 아무 종점 붙기 · 「본선 N」 | `Plan.ts` · `UI_Draw.ts` · `D04_PlanConfirm_Repository.py:68-70` | `test_530_3` · `test_563_2` |
- 계산 자리 = ① 짝(각도 셋) · 꼴 다루기는 TS 만(서버는 [저장] 때 선 · 마크 · 조각으로 다시 셈 — 지금 결 그대로).
- 가이드(`A05_EduDetail/guide/D03`)는 사용자 지시 때 몰아서.
---
## 6. 사용자 물음
1. 「각도」 = 수평 방향 각 — 방위각(도북 0°) · 앞 구간에서 꺾인 각 · 둘 다 보이고 고정은 방위각 기본(권함) 중 어느 것 · 기울기를 ° 로 보이라는 뜻이면 5번은 지금 「기울기 고정」으로 이미 됨.
2. 종점에서 그은 선의 측점 방향 — 종점이 선 끝(No.0 = 반대쪽 · 권함) vs 그은 차례대로(No.0 = 종점).
3. 연도 구분 마커를 놓으면 뒤 구간 처음 해 — 같은 해(지금) vs 다음 해.
---
## 7. 확인 못 함
- 화면 실제 동작(긋는 중 왼쪽 해 고름이 모드를 안 끊는지 등) — 코드로만 봄 · ORCA 안 씀.
- 지도 위쪽 = TM 좌표 북인지 — 바탕 정렬(B04 `createMetricProjector`)로 미뤄 봄 · 실측 안 함.
- B03 가져오기 · D04 내보내기가 뒤집힌 선 · 합친 선을 받는 꼴 — 조각 `planned` 를 그대로 쓴다는 563-2 기록만 봄 · 코드 안 따라감.
- 옛 storage 에 `route_<연도>_<지점 열쇠>` 파일이 남았는지 — storage 안 봄(읽는 코드 없음만 확인).
- 고친 뒤 `UI_Draw.ts` 가 700 줄 안인지 — 어림만.
@@ -0,0 +1,183 @@
# 분석 440-C — 예정노선 GIS 겹 더하기 · 수치지형 등고선 줌아웃 끊김 (요구 440 8 · 9)
읽기 전용 · 코드 · 지식DB · 옛 기록 읽기 + storage 등고선 파일 세기(읽기만) · 서버 · 브라우저 안 씀 · 줄 = main_laptop_1 `addce07aa`.
## ① 결론
1. 「더 있었던 GIS 정보」 = 395-B 분석이 「다음 · 나중」으로 미룬 겹(음영기복 · 지명 · 0차곡 · 산림 주제도(산사태 · 보호구역 · 입지) · 계류 100 m · 도로 300 m 띠 — `docs/raw/요구_1025/_분석_395-B_노선분석_겹.md:155-160` · `docs/raw/plans/2026-10-28_plan_568-569.md:18`) + 지식DB 가 노선 계획 자료로 꼽은 것(교본 = 지형도 · 지적도 · 항공사진 · 지질도 · 임상도 · 산림입지토양도 · 임도망도 · 타당성평가 = 산사태위험지도 · 산사태취약지역 · 산불취약지도 · 하류 민가 · 상수원 · 보호종 서식지).
2. 바로 받을 수 있는 것 = 브이월드 WFS 보호 · 규제 구역 여덟 종(산림보호구역 · 백두대간 · 상수원보호 · 자연공원 · 국가유산 · 습지 · 야생동식물 · 개발제한) · 도엽 안 건물 · 이미 받은 세류 · 도로로 만드는 계류 100 m · 도로 300 m 띠 · DEM 음영기복 — 모두 있는 받기 코드 재사용(작음). 행안부 산사태위험지도 WMS(이용허락 제한 없음)는 중간. 임상도 · 임도망도 · 지질 암상 · 산사태취약지역은 공개 길 · 조건 확인 못 함.
3. 등고선 끊김 까닭(추정 · 순위) = ① D03 은 마우스가 움직일 때마다 바탕(위성 · 등고선 두 번 · 글 · 하천 · 도로)까지 통째로 다시 그림 ② 공용 그리기가 줌아웃해도 꼭짓점을 **전부 훑음**(그리는 점은 줄이나 훑는 점은 그대로 — 다 줌아웃에서 11 % 만 그리는데 100 % 훑음) ③ D03 굵은 계곡선은 가닥 한도 밖이라 줌아웃해도 25 m 선 전부 ④ 가닥마다 따로 긋는 명령 수천 번.
4. 권함 = 화면이 지금과 **같은 그림**으로 남는 다섯 가지 묶음 — 줌 단계 색인 · 한 판 한 번 긋기(등고선) · 글 폭 기억(공용 두 파일) + 한 화면 한 번 그리기 · 바탕 / 위 겹 두 장(D03). 끌기 중 비트맵은 07-28 사용자 롤백이라 뺌.
5. 공용 자리 = `B04_PreProcess/B04_PreProcess_UI_MapRender.ts` · `B04_PreProcess/logic/B04_PreProcess_UI_MapRender_Prepare.ts` — B04 지도 · B05 평면 노선 편집 · B05 배수유역 · D03 네 화면이 같은 함수를 부름 → 부르는 쪽 고침 없이 함께 빨라짐.
---
## 1. (요구 8) 노선 긋기 GIS 자료 대 지금 D03 겹
### 1-1. 지금 D03 겹 여섯
| 겹 | 출처 | 자리 |
| --- | --- | --- |
| 위성 | 브이월드 WMTS 이어 붙인 그림 한 장 | `D03_PlanAnalysis/D03_PlanAnalysis_UI_Layers.ts:53` · `:196-199` |
| 도엽 등고선(계곡선 굵게 · 25 m 수치) | 수치지형도 도엽 | `:54` · `:200-216` · 그리기 `:280-301` |
| 세류 · 하천 | 도엽 하천중심선 | `:55` · `:217-228` |
| 지적도 | 브이월드 WFS LX맵 1 km 조각 | `:56` · 서버 `D03_PlanAnalysis/D03_PlanAnalysis_Layers.py:166-191` |
| 기존 도로 | 도엽 도로중심선 | `:57` · 서버 `D03_PlanAnalysis_Layers.py:72-86` |
| 급경사 색(15 · 35 · 40°) | 2 m DEM · E07 경사 | `:58` · 서버 `D03_PlanAnalysis_Layers.py:54-58` · `:233` |
### 1-2. 지식DB · 옛 요구가 꼽은 자료(근거)
| 자료 | 근거 |
| --- | --- |
| 지형도 · 경사구분도 · 지질도 · 항공사진 | `resources/knowledge/original/임도기술교본/2. 임도망 편성/3. 임도망의 배치 절차.md:85` |
| 지형도 · 지적도 · 항공사진 · 지질도 · 임상도 · 산림입지토양도 · 임도망도 | 같은 파일 `:234-256` |
| 기존 임도망 판독 | 같은 파일 `:346` · `technical_info/01_임도/01_계획노선/노선_배치.md:20` · `:63` |
| 피할 곳(40° 연속 · 암반 · 0차곡 · 붕괴지 · 산사태지역 × · 화강풍화 · 인가 · 상수원) | `노선_배치.md:29-41` · 자동 필터 다섯 `:55` |
| 설치 불가(35° 10 % · 도로 300 m 10 % · 화강암풍화토 20 % · 암반 30 % · 확정 도로 중복) | `타당성평가.md:18-22` |
| 환경성(멸종위기 · 특별산림보호대상종 서식지 · 상수원) | `타당성평가.md:51-53` |
| GIS 규칙(산사태취약지역 · 계류 100 m · 산사태위험지도 · 산불취약지도) | `타당성평가.md:59-64` · `original/예정노선/01_산림청_타당성평가_재해안전성_기준_및_GIS규칙.md:46-50` |
| 하류 민가 = 수치지형도 건물 겹 | `original/예정노선/01_…GIS규칙.md:47` |
| GIS 분석(지황 = 경사 · 방향 · 수계 · 임황 = 임상 · 영급 · 경급 · 산사태위험도) | `임도계획_기본설계.md:29` · 원문 `original/임도기술교본/3. 임도 계획과 설계/2. 기본설계.md:59-63` |
| 사전조사 = GIS 분석자료 · 경사 · 사면향 · 수계 · 진입로 | 원문 `3. 실시설계.md:157-159` |
| 광역 산사태(SINMAP · 무한사면) = 우리 스택으로 자체 셈 | `original/예정노선/02_광역_산사태_토석류_공간평가_메소드_및_SW.md:35` · `:58-60` |
| 사용자 395-2 「도엽등고선 · 위성 · 세류선 · 지적도 등」 | `docs/raw/요구_1025/사용자요구_1025.md:381` |
| 미룬 겹 | `_분석_395-B_노선분석_겹.md:155-160` · `2026-10-28_plan_568-569.md:18` |
### 1-3. 빠진 겹 표
| # | 겹 | 출처 · 지금 받을 수 있나 | 이용 조건 | 손 | 노선 긋기 쓸모 |
| --- | --- | --- | --- | --- | --- |
| 1 | 보호 · 규제 구역 묶음 — 산림보호구역 `lt_c_uf151` · 백두대간보호지역 `lt_c_uf901` · 상수원보호 `lt_c_um710` · 자연공원 `lt_c_wgisnpgug` · `lt_c_wgisnpdo` · `lt_c_wgisnpgun` · 국가유산 지정/보호구역 `lt_c_uo301` · 습지보호 `lt_c_um901` · 야생동식물보호 `lt_c_um221` · 개발제한구역 `lt_c_ud801` | 브이월드 WFS(같은 키) · **있음** — 지적도 조각 받기 `fetch_tile` 그대로 · 지금 이름이 고정(`D03_PlanAnalysis_Layers.py:43` · `:121-122`)이라 이름만 인자로 | 겹별 공공누리 유형 확인 못 함 | 작음~중간(서버 이름 목록 + 화면 겹 하나 · 종류별 색) | 높음 — 환경성 「불가」 · 관계기관 협의 대상을 긋기 전에 피함 |
| 2 | 계류 100 m · 도로 300 m 띠 | 이미 받은 세류 · 하천 · 도로에서 만듦 · 그림만이면 선을 띠 폭(m × 화면 배율)으로 반투명하게 덧그림(셈 없음) · 비율 셈은 서버 ③ | 원자료와 같음(수치지형도 공공누리 1유형 `_분석_395-B:40`) | 작음(그림) · 중간(비율) | 높음 — 설치 불가 · 점수 항목(`타당성평가.md:19` · `:46-47`) |
| 3 | 건물(하류 민가 · 인가) + 실폭하천 · 저수지 | 도엽 zip `N3A_B0010000` · `N3A_E0010001`(이미 받은 도엽 안 · `_분석_395-B:37`) · **있음** — 파서 목록 한 줄씩(`B04_PreProcess/B04_PreProcess_Engine_SheetParser.py:27-37`) → `ensure_sheet_layer` 그대로 | 공공누리 1유형 | 작음 | 중간 — 하류 민가 점수 · 상수원 · 양어장 회피 |
| 4 | 음영기복 | 2 m DEM · B07 `hillshade_png`(`B07_DesignDetail/B07_DesignDetail_Engine_Cad_Lidar.py:59`) · 급경사 PNG 와 같은 길 | 없음(자체) | 작음 | 중간 — 위성 끈 채 산줄기 · 골 읽기 |
| 5 | 지명(계곡 · 령 · 부락) | 도엽 지명 이미 파싱(`SheetParser.py:35`) | 공공누리 1유형 | 작음 | 낮음~중간 |
| 6 | 기존 임도(짐작) | 도엽 도로중심선 `도로구분` 「소로 · 미분류」를 색으로 나눔(이미 받음) · 정식 산림청 임도망도는 확인 못 함 | — | 작음 | 높음 — 기존 임도 접속 · 갈래(`노선_배치.md:63`) |
| 7 | 산사태위험지도(1~5 등급) | 행안부 생활안전지도 WMS(data.go.kr 15149602 · 그림만) · 받기 코드 없음 — 서버 대리 받기 + 그림 한 장(위성 이어 붙이기 꼴 `B04_PreProcess_Engine_VWorld.py:72-197`) | 이용허락 제한 없음 · 무료 · 운영 = 심의승인 · 축척 · 좌표계 확인 못 함 | 중간 | 높음 — 산사태지역 × 회피(`노선_배치.md:33`) · 점수(`타당성평가.md:63`) · 그림이라 등급 비율 셈은 못 함 |
| 8 | 자체 산사태 위험(SINMAP 안정지수 6 등급) | 우리 DEM · E07 `analyze_grid`(`E07_StabArea/E07_StabArea_Engine.py:283` · 머리 `:1-4` 「D 예정노선도 같은 엔진」) · 급경사 PNG 꼴 | 없음(자체 · 법정 지도 아님) | 중간 | 중간~높음 — 법정 지도가 없는 곳도 보임 · 흙 값 기본 = E 기본값(협의) |
| 9 | 산림입지도(산림입지토양도) `lt_c_fsdifrsts` | 브이월드 WFS · 1 과 같은 길 | 확인 못 함 | 중간(폴리곤 많음 · 속성 뜻 표) | 중간 — 토양 · 모암 → 화강암풍화토 판단 보조(`타당성평가.md:20`) |
| 10 | 지질 — 단층 `lt_l_gimsfault` · 지질구조선 `lt_l_gimslinea` | 브이월드 WFS(선) · 1 과 같은 길 · 암상(화강암 구분) 지질도는 브이월드 목록에 없음 → KIGAM 1:50,000 수치지질도(교본 `:254`) | 단층 = 확인 못 함 · KIGAM = 확인 못 함 | 단층 작음 · 암상 큼 | 중간 — 단층 안장부 · 화강풍화 · 사문암(`노선_배치.md:35` · `:38-39`) |
| 11 | 임상도(임종 · 수종 · 경급 · 영급) | 산림청(FGIS) · 브이월드 목록에 없음 · 공개 API 확인 못 함 | 확인 못 함 | 큼 | 중간 — 임황 분석 · 벌채 최소화 |
| 12 | 0차곡(지형 추정 골짜기) | DEM · B05 whitebox 흐름누적(`_분석_395-B:49`) | 없음 | 중간 · 임계값 협의 | 중간(`노선_배치.md:31` · `:51`) |
| 13 | 사면향(방위) | DEM · E07 Horn 기울기에서 방향 | 없음 | 작음 | 낮음 |
| 14 | 산사태취약지역 · 산불취약지도 | 공개 여부 확인 못 함 · 브이월드 `lt_c_kfdrssigugrade` 는 날마다 산불 「예측」(취약지도 아님) | — | — | 점수 항목이나 지금 못 넣음 |
- 브이월드 겹 이름 = 브이월드 WMS/WFS 목록 쪽 그대로(아래 출처). 임상도 · 보전산지 · 산사태 · 생태자연도는 그 목록에 없음.
- 브이월드 키가 코드 안 기본값 · 요청 `domain=localhost`(`_분석_389-C:26` · `_분석_395-B:73`) — 겹이 늘면 상용 전 정리 일이 커짐.
### 1-4. 권하는 차례
| 차례 | 겹 | 처음 값 |
| --- | --- | --- |
| 지금(작음) | 1 보호 · 규제 구역 · 2 계류 · 도로 띠(그림) · 3 건물 · 실폭하천 · 4 음영기복 · 6 기존 임도 짐작(도로 색 나눔) · 5 지명 | 끔 |
| 다음(중간) | 7 산사태위험지도(WMS) 또는 8 자체 SINMAP · 9 산림입지도 · 10 단층 | 끔 |
| 나중(출처 확인 뒤) | 11 임상도 · 정식 임도망도 · 10 암상 · 12 0차곡 · 14 | — |
- 단추 = 지금 여섯 + 「지금」 여섯 = 열둘 → 한 줄은 너무 김. 395-B 가 「일곱 넘으면 펼침 판」으로 정해 둠(`_분석_395-B:167`). 부품 상자에 펼침 판이 없음(`ui_template/` = toolbar · toggle 칩 · map_tools 안내 판뿐) → 「겹 판」 부품을 부품 상자에 더해야 함.
---
## 2. (요구 9) 수치지형 등고선 줌아웃 끊김
### 2-1. 지금 그리는 길
| 화면 | 그리기 | 등고선 판 | 다시 그리는 때 | 자리 |
| --- | --- | --- | --- | --- |
| D03 노선분석 | canvas 2D 한 장 · 위성 그림 → 바탕 겹 → 그은 선 · 재기 | 가는 판(가닥 한도 350 으로 간격 고름) + **굵은 계곡선 판(25 m 전부 · 한도 밖)** + 25 m 높이 글 | 휠 · 가운데 끌기 · **마우스 움직임마다(긋지 않아도)** 바로 · 한 화면 묶음 없음 | `D03_PlanAnalysis_UI_Map.ts:234-253` · `:275-281` · `:293-301` · `D03_PlanAnalysis_UI_Layers.ts:280-301` · 미리보기만 바꾸는 hover `D03_PlanAnalysis_UI_Draw.ts:440-442` |
| B05 평면 노선 편집 | canvas 2D 한 장 · 노선 둘레 300 m 만(받을 때 잘라 받음 · 그릴 때 clip) | 가닥 한도 1,200 으로 간격 고름 + 글 | 휠 · 끌기마다 바로 · 묶음 없음 | `B05_Profile/B05_Profile_UI_RouteEdit.ts:86` · `:313-317` · `B05_Profile_UI_RouteEdit_Render.ts:186-194` · `:224` · `B05_Profile_UI_RouteEdit_Input.ts:82` · `:117` |
| B04 하단 지도 | canvas 2D | **간격 고르기 없음 = 5 m 전부** + 글 | 한 화면 한 번(rAF) | `B04_PreProcess/B04_PreProcess_UI_MapViewer.ts:393-410` · `:439-441` |
| B05 배수유역 | canvas 2D | 5 m 전부 | 한 화면 한 번(rAF) | `B05_Profile/B05_Profile_UI_Drainage_Render.ts:111-119` · `B05_Profile_UI_Drainage_Panel.ts:269-272` |
공용 그리기(네 화면 같음):
- 준비 1 회 = 경위도 → 0~1 좌표 · 가닥 상자 · 꼭짓점마다 DP 무게(`logic/B04_PreProcess_UI_MapRender_Prepare.ts:84-121` · `:146-212`).
- 그릴 때 = 화면 밖 가닥 거름(`B04_PreProcess_UI_MapRender.ts:469-481`) · 화면 밖 구간 끊음(`:366-373`) · 화면 오차 0.75 px 미만 꼭짓점 생략(`:355` · `:391-392`) · 가닥(조각)마다 `beginPath` · `stroke`(`:380` · `:426`) · 글 = 프레임마다 글 폭 재기 + 찍은 글 전부와 겹침 훑기(`:603-607`) · 간격 고르기 = 가닥 × 배수 최대 7 번(`:523-545`).
- 이미 해 둔 것: 07-28 B04 성능 계획(사전 투영 · rAF · 컬링 · DP LOD — `docs/raw/plans/2026-07-28_plan_B04_Map_Performance.md:25-43`) · 509-3 화면 밖 구간 · 508 노선 띠 잘라 받기.
### 2-2. 줌아웃 때 일 양(storage 등고선 파일 셈 · 읽기만)
| 항목 | 값 |
| --- | --- |
| 큰 D 프로젝트(`4250c7bc…`) 도엽 등고선 | 7,039 가닥(계곡선 1,413 · 주곡선 5,626) · 꼭짓점 169만 · 약 11 × 11 km · 75.5 MB(표시본 42.3 MB) |
| 보통 D 프로젝트(`1b628fec…` 등 열 벌) | 593 가닥 · 꼭짓점 12.6만 · 5.6 MB |
| 큰 D 계곡선만 | 꼭짓점 35.5만 |
| DP 규칙(0.75 px)으로 남는 꼭짓점 — 화면 1 px 당 m(어림 · 계곡선 전부 · 주곡선 15 % 표본) | 7.9 m/px(11 km 를 1,400 px · 다 줌아웃) 11 % · 2.7 m/px 21 % · 1.3 m/px 31 % · 0.7 m/px 44 % · 0.3 m/px 67 % |
- 다 줌아웃이면 화면 밖 거르기가 아무것도 못 거름 → 훑는 꼭짓점 = 받은 전부 · 그리는 꼭짓점 = 그중 11 % → **훑기의 89 % 가 헛일**.
- D03 은 등고선을 「그은 선 + 600 m」로 잘라 받음(`D03_PlanAnalysis_UI_Layers.ts:62` · `:200-216`) — 요구 440 의 복수 시종점 · 다년 노선이면 이 범위가 커져 큰 D 프로젝트 쪽으로 다가감.
### 2-3. 끊기는 까닭(추정 · 순위)
| 순위 | 까닭 | 자리 |
| --- | --- | --- |
| 1 | D03 = 마우스 움직임마다 바탕까지 통째로 다시 그림 — 긋기 미리보기 · 재기 · 그냥 지나감 모두. 요구 440-4(미리보기 선 거리 · 각도)로 더 잦아짐 | `D03_PlanAnalysis_UI_Map.ts:275-281` |
| 2 | 꼭짓점 생략이 「그리기」만 줄이고 「훑기」는 그대로 — 줌아웃할수록 헛훑기 비율이 커짐(위 표 89 %) | `B04_PreProcess_UI_MapRender.ts:391-392` |
| 3 | D03 굵은 계곡선 판 = 가닥 한도 밖 — 줌아웃해도 25 m 선 전부(큰 D 1,413 가닥 · 35.5만 꼭짓점 훑기) · 25 m 가닥은 가는 판 · 굵은 판 두 번 | `D03_PlanAnalysis_UI_Layers.ts:286-287` |
| 4 | 가닥마다 따로 긋기 = 그리기 명령 수천 번 | `B04_PreProcess_UI_MapRender.ts:380` · `:426` |
| 5 | 높이 글 = 프레임마다 글 폭 다시 잼 + 겹침 훑기 | `:603-607` |
| 6 | D03 · B05 노선 편집 = 휠 · 끌기마다 바로 그림(한 화면 묶음 없음) | `B05_Profile_UI_RouteEdit_Input.ts:82` · `:117` |
| — | B04 지도 · B05 배수유역 = 5 m 전부라 줌아웃 때 훑기 · 그리기 둘 다 최대(그래도 rAF) | `B04_PreProcess_UI_MapViewer.ts:399` · `B05_Profile_UI_Drainage_Render.ts:118` |
- 확인 못 함: 줌아웃 프레임에서 JS 몫 대 GPU(선 칠하기) 몫. 316 실측(B05 노선 편집 · 줌아웃 아님)에선 GPU 가 프레임당 약 15~16 ms 로 JS 보다 컸음(`docs/raw/조사/2026-10-21_요구316_수치지형도_느림.md:41`). GPU 가 주범이면 아래 c · d 만으로 모자랄 수 있음 → 첫 단계에서 잼.
### 2-4. 품질 유지 방법 갈래
| 갈래 | 하는 일 | 효과 | 화면 변화 | 위험 · 크기 |
| --- | --- | --- | --- | --- |
| a. 바탕 / 위 겹 두 장(D03) | 위성 · GIS 겹은 아래 캔버스 · 그은 선 · 미리보기 · 재기 · 마우스 표시는 위 캔버스 · 마우스 움직임엔 위만 다시 그림 | 긋기 · 재기 중 등고선 다시 그리기 0 회 | 없음 | 작음~중간 · 화면이 바뀌면(이동 · 확대 · 돌림 · 겹 켬끔 · 테마) 아래도 바로 다시 그림 → 07-28 롤백한 「묵은 그림 늘리기」와 다름 |
| b. 한 화면 한 번 그리기 | 휠 · 끌기 · 움직임을 rAF 하나로 모음(D03 · B05 노선 편집) | 한 화면에 알림이 몰려도 한 번 | 없음 | 아주 작음 · B04 · B05 배수가 이미 씀 |
| c. 줌 단계 색인(LOD 색인) | 준비 때 조각마다 DP 무게 몇 단(예 = 0.25 · 0.5 · 1 · 2 · 4 · 8 m 상당)의 「남는 꼭짓점 번호」 목록을 미리 만듦 · 그릴 때 지금 줌보다 한 단 촘촘한 목록만 훑고 지금 규칙(0.75 px) 그대로 거름 | 다 줌아웃 훑기 100 % → 약 11~21 %(5~9 배 덜) · 중간 줌 3~4 배 · 확대 땐 변화 작음(이미 화면 밖 거름) | 없음 — 그리는 꼭짓점 · 차례가 지금과 같음 | 작음 · 메모리 = 꼭짓점 × 4 B × 단 합(큰 D 어림 7~15 MB) · 준비 시간 조금 |
| d. 한 판 한 번 긋기 | 같은 색 · 굵기 한 판의 가닥을 한 길로 모아 `stroke` 한 번 | 그리기 명령 수천 → 판마다 1 · GPU 넘김 횟수도 줄어듦 | 등고선 = 없음(서로 안 겹침) · 반투명 선이 겹치는 자리(도로 갈림목)는 한 겹 색이 됨 → 등고선 판만 | 작음 |
| e. 글 폭 기억 · 겹침 칸 나눔 | 글 폭을 준비 때 한 번 · 겹침 확인을 화면 칸 나눔으로 | 글 비용 작게 | 없음(같은 차례 · 같은 규칙) | 작음 |
| f. 화면 밖 자르기 · 가닥 수 한도 | 이미 있음(`:366-373` · `:469-481` · `:523-545`) | 줌아웃 땐 다 화면 안이라 효과 없음 | — | — |
| g. 끌기 중 비트맵 · 다시 그림 늦춤 | 움직이는 동안 찍어 둔 그림을 옮기고 멈추면 다시 그림 | 큼 | 움직이는 동안 흐림 · 끝날 때 다시 그려짐 | **07-28 B04 에서 사용자 롤백**(끝날 때 체감 · 가장자리 빈칸 `2026-07-28_plan_B04_Map_Performance.md:35-37`) → 뺌 |
| h. 일꾼 스레드(Worker + OffscreenCanvas) | 바탕을 다른 스레드가 그림 | 주 스레드 비움 · 그림 같음 | 바탕이 한두 화면 늦게 따라옴(그은 선과 등고선이 잠깐 어긋남) | 중간 · g 와 비슷한 체감 위험 → 나중 |
| i. 서버 벡터 타일(MVT 길 있음 `B04_PreProcess_Engine_MvtHelper.py`) | 보이는 칸 · 그 줌 자세함만 받음 | 아주 넓은 범위(수십 km)에 맞음 | 타일 좌표 양자화 · 줌마다 받기 기다림 | 큼 |
| j. WebGL(MapLibre 설치만 됨 · `_분석_389-C:19` · `:69`) | GPU 가 선을 그림 | 가장 빠름 | 선 굵기 · 매끈함이 지금과 달라짐 | 큼 · D03 조작 부품 옮김 |
### 2-5. 권함
- **a + b + c + d(등고선 판) + e** — 화면은 지금과 같은 그림(그리는 꼭짓점 · 차례 · 색 · 굵기 같음) · 사용자 조건 「해상도 저하 절대 불가」(`2026-07-28_plan_B04_Map_Performance.md:13`)와 맞음.
- 차례: 0) 큰 D 프로젝트로 줌아웃 프레임 시간 잼(JS · GPU 나눠 · tmp 벤치 · 316 방식) → 1) c · d · e 공용 두 파일 → 2) a · b D03 → 3) b B05 노선 편집 → 다시 잼. 그래도 GPU 가 16.7 ms 를 넘기면 j 를 따로 계획.
- D03 굵은 계곡선을 가는 판과 같은 한도로 성글게 하면 줌아웃이 더 가벼워지나 화면 모양이 바뀜 → 사용자 물음.
### 2-6. 공용 한 벌로 적용할 자리
| 자리 | 파일 · 함수 | 덕 보는 화면 |
| --- | --- | --- |
| 줌 단계 색인 · 글 폭(c · e) | `B04_PreProcess/logic/B04_PreProcess_UI_MapRender_Prepare.ts` `prepareLayer`(`:146-212`) | B04 지도 · B05 노선 편집 · B05 배수유역 · D03 |
| 훑기 · 한 판 긋기 · 글(c · d · e) | `B04_PreProcess/B04_PreProcess_UI_MapRender.ts` `drawLineParts`(`:357-428`) · `drawPreparedLayer`(`:555-571`) · `drawPreparedLabels`(`:577-626`) | 같은 넷 · 부르는 쪽 고침 없음 |
| 한 화면 한 번(b) | `D03_PlanAnalysis_UI_Map.ts` `draw` · `B05_Profile_UI_RouteEdit.ts` `draw`(`:317`) | D03 · B05 노선 편집 |
| 두 장 캔버스(a) | `D03_PlanAnalysis_UI_Map.ts`(338 줄) | D03 · B05 노선 편집은 실측 뒤 |
| 밖 | B07 CAD(openwebcad · 따로 공간 색인 · PLAN 227) · B04 3D 지형(three) | — |
- `B04_PreProcess_UI_MapRender.ts` = 628 줄(700 한도 가까움) → 색인은 Prepare 쪽 · 훑기 조각은 `logic/` 새 파일로.
- B04 CLAUDE.md = 이 두 파일은 남의 페이지가 부름 → 고치면 B05 · D03 시험도.
- 지킴 시험 하나 = 색인으로 고른 꼭짓점 = 지금 규칙으로 고른 꼭짓점(여러 줌 · 닫힌 링 · 짧은 조각) — logic 순수 함수.
---
## 3. 사용자 물음
1. 겹 단추가 열둘로 늘어남 — 지금처럼 한 줄(가로로 김) 또는 「겹」 단추 하나 → 펼침 판(바탕 · 물 · 길 · 구역 · 재해 묶음) 중 어느 쪽?
2. 등고선 「품질」 = 지금 화면과 같은 그림(권함)으로 충분한지 · 줌아웃 때 굵은 계곡선(25 m)도 성글게 해도 되는지(화면 모양 바뀜)?
협의 항목(계획서 단계):
- 산사태 겹 = 법정 지도(행안부 WMS 그림) · 자체 셈(SINMAP) · 둘 다 중.
- 계류 100 m 띠의 「주요 수계」(원문 1/25,000) = 도엽 1/5,000 하천중심선의 어느 구분까지(세류 포함 여부).
## 4. 확인 못 함
- 임상도 · 산림청 임도망도 · 산사태취약지역 · 산불취약지도 — 공개 API · 이용 조건.
- 브이월드 보호 · 규제 겹별 이용허락(공공누리 유형) · 하루 한도.
- 행안부 산사태위험지도 WMS — 겹 이름 · 좌표계 · 축척(1:5,000 여부) · 운영 심의 조건.
- KIGAM 수치지질도(암상) 이용 조건 · API 유무.
- D03 줌아웃 실제 프레임 시간 · JS 대 GPU 몫(서버 · 브라우저 안 씀 조건) · 크롬이 휠 알림을 한 화면 한 번으로 묶는지.
## 출처(바깥)
- 브이월드 WMS/WFS 겹 목록(산림보호구역 `lt_c_uf151` · 백두대간 `lt_c_uf901` · 상수원보호 `lt_c_um710` · 국가유산 `lt_c_uo301` · 산림입지도 `lt_c_fsdifrsts` · 단층 `lt_l_gimsfault` 등): https://www.vworld.kr/dev/v4dv_wmsguide2_s001.do
- 행정안전부 생활안전지도 산사태위험지도(WMS · 1~5 등급 · 이용허락 제한 없음 · 무료): https://www.data.go.kr/data/15149602/openapi.do
- 산림청 과거산사태 정보(API): https://www.data.go.kr/data/15074816/openapi.do
- 그 밖 출처는 `_분석_395-B_노선분석_겹.md` 출처 절 그대로.
@@ -0,0 +1,48 @@
# 요구서 440 — 예정노선 설계 (D02 기준지정 · D03 노선분석 · GIS 겹 · 등고선 성능)
원문 = `사용자요구_1025.md` 요구 440 · 근거 분석 = `_분석_440-A_기준지정_복수시종점.md` · `_분석_440-B_노선그리기_연도.md` · `_분석_440-C_GIS겹_등고선성능.md`.
## 1. 요구 (원문 요약)
| # | 요구 | 페이지 |
| --- | --- | --- |
| 1 | 시작 · 종료 지점 여러 개(기존 노선 잇기 · 갈래) · 더하고 지우는 UI · 점 잇는 붉은 선 지움 | D02 기준지정 |
| 2 | 다음 페이지로 넘어가면 지점들을 보고 GIS 자료를 받아 보여 줌 | D02 → D03 |
| 3 | 시작에서도 종료에서도 긋기 · 부분 수정 | D03 |
| 4 | 미리보기 선에 거리 · 각도 | D03 |
| 5 | 각도 지정 미리보기 = 각도 고정 · 길이 자유 | D03 |
| 6 | 그리는 중 여러 연도 · 만든 노선 골라 연도 지정 · 고르기 · 지우기 | D03 |
| 7 | 노선 위 마커 = 연도 구분 지점(6 과 이어짐) | D03 |
| 8 | 노선 긋기에 필요한 GIS 자료 더 찾아 겹 단추에 더함 | D03 지도 |
| 9 | 수치지형 등고선 줌아웃 끊김 — 품질 유지 · Aislo 전체 공용 · 제안 | 공용 지도 그리기 |
## 2. 지금 (조사)
- 기준지정 = 시점 하나 · 종점 하나 고정 · 저장 = 프로젝트 칸 `plan_base_json` 하나 · 붉은 선 = `D02_PlanBase_UI_Page.ts:155-165` 몇 줄 · GIS 받을 범위 셈은 이미 점 몇 개든 감싸는 상자 + 여유 350 m · 다음 페이지 와도 자동 받기 없음 · 받은 범위 밖에 점을 더해도 「받은 지형 안」으로 보이는 흠.
- D03 = 시점에서만 긋기 · 본선만 이어 긋기 · 종점에서 · 갈래 이어 긋기 · 꺾임점 끌기 · 가운데 점 더하기/지우기 · 선 고르기 · 지우기 · 각도 글 · 각도 고정 없음 · 연도 = 왼쪽 판 구간마다 · 연도 구분 마커 = [구역 마크]로 이미 있음 · 저장 꼴(노선 정본 · 조각 · 연도) 바꿈 없이 화면 고침으로 가능.
- 겹 여섯(위성 · 등고선 · 세류 · 지적 · 도로 · 급경사) · 빠진 것 = 보호 · 규제 구역(브이월드 여덟 종) · 계류 100 m · 도로 300 m 띠 · 건물 · 실폭하천 · 음영기복 · 지명 · 기존 임도(짐작) · 산사태위험지도 · 자체 SINMAP · 산림입지도 · 단층 · 임상도(출처 확인 못 함) 등 — 근거 지식DB `노선_배치.md` · `타당성평가.md` · `임도계획_기본설계.md`.
- 등고선 끊김(추정) = D03 은 마우스가 움직일 때마다 위성 · 등고선까지 통째로 다시 그림 · 공용 그리기는 줌아웃 때 그리는 점 11 % 인데 점은 100 % 훑음 · 굵은 계곡선은 줌아웃해도 전부 · 실제 프레임 시간 안 잼.
## 3. 고칠 것
- 579 기준지정 = 시점 목록 · 종점 목록(옛 값은 읽을 때 목록으로 감쌈 · 옮김 없음) · 줄마다 지움 · [+ 시점] · [+ 종점] · 붉은 선 지움 · D03 이 시종점을 집는 여덟 곳 맞춤 · 받은 범위가 지점을 못 덮으면 D03 들어올 때 받기 · 범위 밖 점 표시 흠 고침.
- 580 D03 그리기 = [긋기] 하나로(시점 · 종점 · 선 끝 · 선 위 어디서든) · 종점에서 그은 선은 끝낼 때 뒤집어 저장 꼴에 맞춤 · 꺾임점 끌기 · 더하기 · 지우기 · 미리보기 글에 각도 · 「각도 고정」(길이 고정의 짝) · 지도에서 선 고르기 · Delete 지우기 · 선 통째 연도 · 「긋는 해」 · 마커 놓은 뒤 연도 바로 고름 · 마커 끌어 옮김 · 그리기 화면 616 줄 → 고르기 · 고치기 새 파일.
- 581 GIS 겹 = 「지금(작음)」 여섯 먼저(보호 · 규제 구역 · 계류 · 도로 띠 · 건물 · 실폭하천 · 음영기복 · 기존 임도 짐작) · 「다음(중간)」(산사태위험지도 또는 자체 SINMAP · 산림입지도 · 단층) · 「나중」 = 출처 · 이용 조건 확인 뒤 · 단추 열둘 → 펼침 판.
- 582 등고선 성능 = 그림 그대로(꼭짓점 · 차례 · 색 · 굵기 같음) · 0) 줌아웃 프레임 시간 잼 1) 공용 두 파일(`B04_PreProcess_UI_MapRender_Prepare.ts` · `B04_PreProcess_UI_MapRender.ts`)에 줌 단계 색인 · 한 판 한 번 긋기 · 글 폭 기억 2) D03 바탕 / 위 두 장 · 한 화면 한 번 그리기 3) B05 노선 편집 한 화면 한 번 · 덕 보는 화면 = B04 지도 · B05 노선 편집 · 배수유역 · D03 · 끌기 중 비트맵(07-28 되돌린 방식)은 안 씀.
## 4. 사용자 결정
1. D03 들어올 때 GIS 받기 — (가) 받은 범위가 지점을 못 덮으면 바로 받기(2~3 분 진행 막대 · 권함 · 요구 2 그대로) (나) 범위 미리보기 창만 띄우기.
2. 시점 · 종점 = 짝 없이 따로 목록(최소 1 개씩) · 점에 연도 · 「기존 노선 잇기」 표시 안 둠 — 맞는지(권함 = 예).
3. 「각도」 — 미리보기에 방위각(도북 기준)과 앞 선과 꺾인 각 둘 다 · 「각도 고정」은 방위각 기준(권함).
4. 종점에서 그은 선의 측점 No.0 — 반대쪽(시점 쪽) 끝(권함) · 종점 쪽.
5. 새 연도 구분 마커 뒤 구간의 처음 해 — 같은 해(권함 · 바로 고름) · 다음 해.
6. 겹 단추 열둘 — 「겹」 단추 하나 → 펼침 판(권함 · 395-B 「일곱 넘으면 펼침」) · 한 줄 그대로.
7. 등고선 「품질」 — 지금과 같은 그림(권함) · 줌아웃 때 굵은 계곡선도 성글게 해도 됨(더 가벼움 · 모양 바뀜).
## 5. 배정안 (승인 뒤)
- 579 + 580 = 한 창(D03 시종점 맞춤 · 긋기가 같은 파일) Opus high — 579 서버 꼴 → 화면 → 580 차례.
- 581-1 「지금」 겹 = 한 창 Opus high(서버 받기 · 겹 판).
- 582 = 한 창 Opus high(0 잼 먼저 · 공용 두 파일은 B04 · B05 · D03 시험도).
- 581-2 「다음」 겹 · 「나중」 출처 확인 = 581-1 뒤.