# 2026-09-04 사용자 검증 완료 항목 > `docs/raw/PLAN.md`에서 2026-09-04에 사용자 검증 완료로 확정된 구간을 이관했다. > `B05 초기화 범위 확대 — 전체 결과 보존 (2026-09-04 지시)`는 미완료·판단 대기 항목이 있어 제외했다. > 위키 반영: `docs/wiki/concepts/completed_2026-09-04.md` ### 계획노선 표기 정리 — CSV 문구 걷어내기 (2026-09-04 구현 완료 · 검증 대기) 사용자 지시(2026-09-04) — 「사용자는 CSV 를 쓰지 않음. 내부 코드 주석에 그런 내용이 있으면 삭제」. - 실제 사용자 입력은 shapefile 이고, CSV 는 **내부 정본 한 벌**(`planned_route.csv`)로만 씀. - 「B03 이 업로드한 원청 계획노선 CSV」식 주석이 여러 곳에 남아 입력 형식을 오해하게 함. - [X] **주석 문구 정리** — 사용자 입력을 CSV 로 적은 주석을 「계획노선(정본)」으로 고침. 고친 곳은 `common_util_drainage_context.py` · `common_util_drainage_pipes.py` · `B05_Profile_Engine_Sections.py` · `B03_FileInput_Service_Chain.py` · `B04_PreProcess_Api_Fetch.ts`. 내부 정본 파일(`planned_route.csv`)을 가리키는 자리는 그대로 둠. - [X] **화면 문구 확인** — 업로드 오류 문구를 「계획노선 파일(shapefile 의 .shp 또는 .csv)을 정확히 1개 포함해야 합니다」로 고침. 그 자리 판정이 `.csv` 개수만 세고 있어 shapefile 입력을 막던 것도 같이 맞춤(`.csv`·`.shp` 합쳐 1개 — 이미 다른 경로가 쓰던 규칙 `_ROUTE_FILE_TYPES` 와 같음). B03 안내 문구는 「계획노선(shapefile 한 벌 또는 CSV)」 순으로 바꿔 shapefile 이 기본임을 보임. - [X] **동작은 불변** — 파일 형식·경로 그대로. 예외는 위 업로드 판정 한 줄(문구와 어긋나 있던 것). - [X] **자체검증 (2026-09-04, 검증 대기)** — 방법: `ruff format` + `npm run typecheck` 통과 확인, 문구를 바꾼 자리에 남은 「업로드한 … CSV」 표현이 없는지 재검색. 결과: 남은 CSV 표현은 모두 내부 정본 파일(`planned_route.csv`)·CSV 판독기 자체를 가리키는 자리뿐임. 계획 대비 차이 — 업로드 판정 한 줄이 문구와 어긋나 있어 문구만이 아니라 판정도 함께 고침. ### B05 진입 로딩 — 3D 후순위·회전 끊김 (2026-09-04 지시) 사용자 지시(2026-09-04) — 「3D 데이터는 보조 역할이라 초기화든 데이터 변경이든 **후순위**임. 그래서 [3D 업데이트] 버튼을 둔 것. 초기 로딩도 혼자 버벅이지 말고 **조용히 뒤에서** 뜨고 다 되면 팝업으로 알릴 것. 로딩 도넛이 **툭툭 끊기니** 회전은 진행률과 무관하게 계속 돌고 **숫자만** 갱신할 것. 완료 시점은 **맨 마지막 3D 데이터 직전**」. 착수 전 코드를 읽고 낸 현황임. - **도넛이 안 도는 게 맞음** — 진행률을 주면(`set(비율)`) 회전 클래스(`is-indeterminate`)가 꺼짐(`ui_template_progress.ts`). 즉 지금 보이는 움직임은 회전이 아니라 호가 **5칸씩 뚝뚝 늘어나는 것**임. 회전과 진행률이 **같은 `` 의 transform 을 서로 뺏는 구조**라 둘을 동시에 못 씀. - **끊김을 키우는 것은 무거운 단계** — 3D 지형·코리도가 메인 스레드를 잡는 동안 갱신 자체가 멈춤. - **로딩 5단계**(`B05_Profile_UI_Page.ts`) — ① 워크플로우 ② 좌측 폼·노선 ③ 지표면 모델 ④ 종·횡단 자료 ⑤ **3D 지형**. 완료(`progress.remove()`)는 ⑤ 까지 끝난 뒤라 3D 를 기다리는 동안 화면이 잡혀 있음. - **[3D 업데이트] 버튼은 이미 있음**(2026-09-01) — 계획선 편집은 이 버튼으로 모아 반영 중. 같은 규칙을 초기화·진입에도 적용하면 됨. - [X] **회전과 진행률 분리** — 서클 안에 회전 껍데기(`__spin`)를 한 겹 더 두고 CSS 회전을 **거기에만** 걸었음. 껍데기는 늘 돌고 안쪽 `` 는 12시 고정이라 호·숫자는 제자리에서 갱신됨. 쓰이지 않게 된 `is-indeterminate` 분기는 지움(공용 `ui_template_progress`). - [X] **완료 시점을 3D 직전으로** — 단계 수를 5 → 4 로 줄이고 ④ 끝에서 로딩 표시를 걷음. 「확정 지표면 없음」 판정은 ③ 뒤로 앞당겨 빈 화면을 열지 않게 함. - [X] **3D 는 뒤에서 조용히** — ⑤ 를 `finally` 뒤 배경 작업으로 돌리고 끝나면 토스트 「3D 지형 준비 완료」. 실패해도 화면은 그대로 쓰고 오류 토스트만 띄움. - [X] **초기화·데이터 변경도 같은 규칙** — [초기화]는 끝에 B05 로 재진입하므로 위 진입 규칙이 그대로 걸림(추가 코드 없음). 계획선 편집은 이미 [3D 업데이트] 대기 표시로 모아 둔 상태. - [X] **자체검증** — 공용 브라우저(5173, 용화_LAS) 실측. 진입은 캐시를 비우고 프로젝트 목록에서 [종단설계] 를 눌러 들어감. - ① 회전 — 껍데기의 CSS 애니메이션이 `running` 이고 시각이 계속 진행(0 → 183ms). 표본 6개의 변환행렬이 **전부 다름**(멈춘 구간 없음). 회전은 합성 스레드가 돌리므로 무거운 단계가 메인 스레드를 잡아도 끊기지 않음. - ② 숫자 — 25% → 50% → 75% 순으로 오름(문구도 단계마다 바뀜). - ③ 로딩이 걷힌 순간 종단 그래프 선 2개·좌측 패널 단추 61개가 이미 서 있고 3D 메쉬는 2개뿐 — **3D 없이 화면이 먼저 열림**을 수치로 확인. - ④ 1.8초 뒤 3D 메쉬 489개와 함께 토스트 「3D 지형 준비 완료」. - ⑤ [초기화] → 확인 모달 → 토스트 「초기 계산 상태로 되돌렸습니다.」 뒤 재진입. 로딩 걷힘(그래프선 2·좌측단추 61) → 0.2초 뒤 3D 메쉬 489 + 준비 완료 토스트. - 계획 대비 차이 — 없음. ### B05 초기화 후 계획선이 원지반과 어긋남 — 원인 확정 (2026-09-04) 사용자 보고(2026-09-04) — 「초기화 후에도 계획선이 측점 세로선에서 원지반선과 만나지 않음」. 공용 브라우저(5173, 2025 테스트)로 **재현 성공**, 원인 확정함. - **저장 데이터·서버는 정상** — 종단 정본의 측점 65개 전부 계획고 = 지반고(0.000m). 깨끗한 화면 실측도 측점 66개 최대 **0.019m** 로 붙어 있음. - **범인은 브라우저 세션에 남는 계획선 편집 초안**(`b05-profile-alignment-draft:<노선번호>`). 초기화가 이 초안을 지우지 않아, 화면이 초기값 위에 옛 편집 델타를 다시 얹음. - **재현 기록** — 초안(측점 20~400m 에 +6m)을 넣고 새로고침하면 최대 **6.0m** 어긋남(측점 25개가 10cm 초과). [초기화] 직후에는 0.019m 로 멀쩡해 보이나 **새로고침 한 번에 6.0m 로 되돌아감**. 초안을 지우고 새로고침하면 0.019m 로 복귀 — 초안이 원인임이 확정됨. - **새는 구멍은 노선번호 없는 초안 키**(`...draft:none`). 노선번호가 아직 없는 순간에 만들어진 초안이 어느 노선에나 되붙어, 초기화로 노선이 바뀌어도 살아남음. - [X] **초기화가 계획선 초안을 함께 버림** — `resetDesignAction` 이 다른 세션 캐시를 비우는 자리에서 `b05-profile-alignment-draft:` 로 시작하는 키를 전부 지움. - [X] **노선번호 없는 초안을 만들지 않음** — 노선번호가 없을 때는 초안을 저장하지 않음 (`:none` 키 폐지). B06 이 읽는 자리도 같은 규칙. - [X] **자체검증**(2026-09-04, 공용 브라우저 5174 · 프로젝트 **용화_LAS**, 사용자 지정) — 실측. - ① 초안 심기 — `b05-profile-alignment-draft:137` 에 20~400m 측점 +6m 를 넣고 새로고침하니 계획선이 지반선에서 최대 **9.183m** 뜸(깨끗한 상태 3.798m). 재현 성공. - ② [초기화] → 확인 모달 → 재계산 뒤 **3.798m**, 새로고침 후에도 **3.798m** 로 동일. 옛 편집 델타가 다시 얹히지 않음. **합격** - ③ 초기화 직후 세션의 초안 키 **0건**, 새로고침 뒤에도 0건. **합격** - ④ 정상 편집은 그대로 — 계획고 ▲ 를 누르니 계획선이 움직이고 초안 키가 다시 생김 (`…draft:137`). 검증 뒤 그 초안은 지워 시험 전 상태로 되돌림. **합격** - **계획 대비 차이** — 판정 기준을 바꿈. 원안의 「측점 차이 0.02m 이하」는 초기값이 계획고=지반고인 평탄 시험노선 기준이었음. 용화_LAS 는 실제 자동설계라 절·성토가 있어 계획선이 지반선과 붙지 않는 것이 정상 — 그래서 **「초기화 직후 값 = 새로고침 후 값 = 초기 자동설계값」 동일성**으로 판정함. - **부수 영향** — 검증에 실제 [초기화]를 눌렀으므로 용화_LAS 의 사용자 수정분(경로·계획선· 횡단 설계)은 초기 자동계산 상태로 되돌아갔음. ### B05 확정 시 구조물 측점 재생성 — 정리 (2026-09-04) 확정([저장]·[확정])이 종단 파일의 구조물·관 측점 10개를 다시 만들어 덮음. 2026-09-04 사용자 판단 — **포장 판정이 빠지는 것은 맞음**(포장은 사용자 지정으로 바꿀 것), **측점 위치 소수 2자리도 유지**(다른 설계자 관행과 같음). 남은 것은 아래 하나. - [X] **포장 지정을 사용자 몫으로** — 확인 결과 **이미 그렇게 되어 있음**(2026-08-28 작업분). 코드를 고칠 것이 없었음. - 자동 판정은 켜지 않고 표기만 — `pavement_suggested` 는 B06 카드에 ⚠ 배지·툴팁으로만 나감. - 포장을 켜는 것은 ① 사용자 구간 지정(구조물 정본 G군·물넘이포장) ② 사용자가 카드에서 켠 값. 구간 밖에서는 저장된 사용자 값이 정본(`paved_at`). - 확정 시 구조물 측점을 다시 만드는 자리도 사용자 포장값을 그대로 이어받음 (`B05_Profile_Router_Confirm` — `paved=bool(design.get("paved", False))`). - **자체검증** — `tmp/tests/test_b06_pavement_and_ford.py` 가 이미 규칙을 못박고 있음 (구간 안 강제 True / 구간 밖 사용자값 유지 / 경사 제안만으로는 안 켜짐). 전체 185 통과. ### B05 3D — 구조물 개별 선택 (2026-09-04 예정) 사용자 지시(2026-09-04) — 「B06 횡단도의 선택 로직을 공유하면 쉽게 될 것. 그러면 연계된 B05·B06 좌측 패널 활성화도 따라감」. 2026-09-04 확정 두 가지 — ① 고른 구조물 정보는 **좌측 「구조물 배치」 패널로만** 보임(3D 위 정보상자는 안 만듦) ② B06 은 **선택만 세션에 남김** — 3D에서 골라도 화면이 넘어가지 않고, 나중에 B06 에 들어가면 그 측점 카드가 열림. 착수 전 코드를 읽고 낸 현황임. - **3D 구조물은 이미 부재마다 별개 물체** — 기슭막이(유입·유출·다단)·집수정·배관이 각각 자기 Mesh 로 얹힘(`B05_Profile_UI_Corridor_Mesh.ts` 의 `corridor-structure:종류:번호`). 통짜로 뭉쳐 있지 않으므로 **개별 선택에 기하 변경이 필요 없음**. - **모자란 것은 신원표** — 솔리드 데이터(`CorridorStructure`)에 `chainage_m`·`kind` 는 있으나 **부재키가 없음**. 부재키는 B06 이 쓰는 것과 같은 이름(`inlet`·`outlet`·`extra{i}`·`bextra{i}`·집수정·배관)이고, 솔리드를 만드는 자리에서 이미 손에 쥐고 있음(`B05_Profile_UI_Corridor_Structures.ts` 의 `wall.role`·`extra${i}`). - **클릭 감지 범위** — 3D 포인터는 지형과 마커까지만 봄(`B05_Profile_UI_Viewer_Marker_Input.ts`). 코리도 그룹을 같은 방식으로 한 겹 더 보면 됨. - **좌측 패널은 받을 준비가 되어 있음** — 공용 「구조물 배치」(`A00_Common/b_structures_section` → `B05_Profile_UI_Structures_Panel.ts`)에 `selectPipeByChainage(누가거리)` 와 `selectById(구조물id)` 가 있고, 후자의 설명이 「종단도·3D에서 고른 구조물을 폼에 올린다」임. - **B06 선택 규칙 = (측점, 부재키)** — `B06_Section_UI_Page_Station_Controls.ts` 의 `revetSelection = { at: 측점.toFixed(2), key }`. 이 한 쌍이 카드 강조·조정창·좌측 폼 로드를 모두 몰고 감. 3D 도 같은 한 쌍을 만들면 그 뒤가 전부 따라옴. - **B05·B06 은 라우터가 따로 띄우는 화면**(`A00_Common/router.ts`) — 두 화면이 동시에 떠 있지 않으므로 실시간 양방향이 아니라 **세션에 남긴 선택**으로 이음. - [X] **부재키를 3D까지 들고 감** — `CorridorStructure` 에 `key` 필드 추가, 벽·다단·집수정·배관을 담는 자리에서 그대로 채움(값은 이미 그 자리에 있음). - [X] **메쉬에 신원표** — 구조물 Mesh 에 `userData = { chainageM, kind, key }`. 이름 규칙은 그대로 둠(다른 코드가 이름으로 찾음). - [X] **3D 클릭 잡기** — 신규 모듈 `B05_Profile_UI_Viewer_Structure_Pick.ts`(새 파일 — 뷰어 693줄·페이지 691줄이라 기존 파일에 넣지 않음). 코리도 그룹만 대상으로 하고 **마커보다 뒤 순위** — 마커 끌기·이동 모드가 살아 있으면 구조물 선택은 건너뜀. - [X] **3D 강조** — 고른 메쉬만 밝히고(emissive) 나머지는 원색, 빈 곳을 누르면 해제. 좌측 패널·종단 그래프에서 고른 경우에도 같은 함수로 3D 가 따라감. - [X] **좌측 패널 활성화** — 배수관 세트(기슭막이·집수정·배관)는 `selectPipeByChainage(누가거리)`, 그 밖의 구조물은 `selectById`. 배선 자리는 기존 선택 동기화(`B05_Profile_UI_Selection.ts`) — 3D 마커·종단·좌측·유역도가 이미 한 줄로 묶여 있으므로 구조물 선택을 같은 줄에 얹음. - [X] **선택을 세션에 남김** — B06 이 쓰는 것과 같은 모양 `{ at, key }` 를 sessionStorage 한 칸에 둠. B06 진입 시 그 값으로 카드 선택·스크롤·조정창 열기(기존 `select()` 창구 재사용). 조작 상태는 캐시 몫이라는 5장 데이터 3층 규칙과 같음. - [X] **자체검증** — 공용 브라우저(5173) 실측으로 수치 판정. ① 3D에서 기슭막이·집수정·배관을 각각 눌렀을 때 좌측 폼이 그 시설로 열리는지 ② 강조가 한 번에 하나만 켜지는지 ③ 빈 곳 클릭으로 해제되는지 ④ 마커 끌기·회전이 안 깨지는지 ⑤ 그 뒤 B06 에 들어가면 같은 측점 카드가 선택·스크롤되고 조정창이 열리는지. - 방법 — 공용 브라우저(5173, 프로젝트 `8cd2e635`)에서 구조물 메쉬 표면 한 점을 화면 좌표로 환산해 **실제 마우스로 클릭**. 판정은 `sessionStorage` 넘김값 · 메쉬 자체발광(emissive) · 좌측 목록 선택 · B06 화면으로. - ① 기슭막이 클릭 → 넘김값 `{"at":85.59,"key":"outlet"}`, 좌측 목록 `4+5.6 배수관 1` 선택. 집수정 → `key:"basin"`, 배관 → `key:"pipe"` (모두 같은 목록 항목). - ② 밝아진 메쉬는 고른 부재 것만 — 기슭막이 2장(관통 컷 위·아래 조각) → 집수정으로 바꾸면 집수정 2장만, 기슭막이는 꺼짐. - ③ 빈 곳 클릭 → 넘김값 없음 · 밝은 메쉬 0장 · 목록 선택 없음. - ④ 구조물 위에서 90px 끌기 → 카메라 좌표 합계 17.7 이동, 선택 0건. 마커(bp) 클릭 → 마커만 선택(확대 1.35배), 구조물 넘김값 없음. - ⑤ 3D에서 유출 기슭막이를 고른 뒤 [횡단설계] 진입 → 카드 `4+5.6 (85.6m)` 이 선택·스크롤되고 조정창 「기슭막이(유출)」 가 그 카드에 열림. 넘김값은 소비돼 비워짐. - 계획 대비 차이 4가지 — ① **저장 코리도 만료 추가**(`BUILD_VERSION` 90→91). 옛 저장본엔 부재키가 없어 3D에서 골라도 B06으로 넘길 부재를 못 정함(실측: 키 전부 `null`). ② **뷰어 700줄 여유 확보** — 검증용 요약을 `B05_Profile_UI_Viewer_Debug.ts` 로 분리(동작 불변). 뷰어 687줄. ③ **검증 수단 추가** — `__corridorScene` 에 `camera` 와 `project(모델좌표→화면좌표)`. 3D 물체를 실제 마우스로 누르려면 화면 자리를 재야 함. ④ **클릭은 캡처 단계로** — 캔버스 버블 단계 `pointerdown` 이 아예 안 옴(실측). 캡처로 달되 마커 입력보다 뒤에 등록. - 남은 것 — 없음. 세월교·BOX암거 부재키는 아래 후속으로 일원화함. #### 부재키 일원화 (2026-09-04 사용자 지시 — 완료) 「이름표는 당연히 일원화해야 함. 대부분 횡단도를 보고 작업한 결과물이며 계산로직상으로도 횡단도가 우선 지정됨」. 확정 두 가지 — ① 본체(세월교 월류부 상판·BOX 구체)를 누르면 좌측 폼·목록 강조와 B06 측점 카드까지만, 조정창은 안 띄움 ② 3D 강조는 **부재 하나만**. - [X] **이름표 = 횡단도가 부르는 이름** — 세월교 `inlet`·`outlet`, BOX암거 `left`·`right`, 본체는 `body`. 이름이 겹쳐도 한 측점엔 시설이 하나뿐이라 (측점+이름)이면 유일함. - [X] **부재까지 한 칸 더** — 조정창 하나가 그 측 부재 여럿을 다루므로 `측이름:부재` 꼴(`inlet:wall`·`inlet:floor`·`inlet:wing`·`inlet:apron`·`left:apron`·`left:wing`). 강조는 전체 키로 맞추고, B06 조정창은 **앞칸만** 봄. - [X] **B06 갈래 태우기** — 그 측점이 세월교면 세월교 조정창, BOX암거면 BOX 조정창, 아니면 기슭막이 조정창(신규 모듈 `B06_Section_UI_Page_Structure_Pick.ts`). - [X] **저장 코리도 만료**(`BUILD_VERSION` 91→92) — 91 저장본엔 배수관 세트 키만 있음. 재계산 비용 실측 = 저장본 5.1초 / 재계산 4.7초로 **차이 없음**(오차 범위). - [X] **자체검증** — 공용 브라우저(5173) 실측. - 부재키 빈 칸 0건(전 구조물 72개). 세월교 측점 177.32 = `body` 1 · `inlet:wall` 2 · `inlet:floor` 1 · `inlet:apron` 2 · `inlet:wing` 2(유출측 동일). - 세월교 유입 측벽 클릭 → 넘김값 `{"at":177.32,"key":"inlet:wall"}`, 밝은 메쉬 **그 벽 2장만**(바닥·날개벽은 안 켜짐), 좌측 목록 `8+17.3 세월교 1`. - 이어서 [횡단설계] 진입 → 카드 `station_000000177320` 선택, 조정창 「세월교 유입 측벽」 열림. - 배수관 세트 되풀이 확인 — 유출 기슭막이 클릭 → `{"at":85.59,"key":"outlet"}` · 밝은 메쉬 2장 · 목록 `4+5.6 배수관 1`, 빈 곳 클릭 시 전부 해제. - 못 해 본 것 — **BOX암거는 이 프로젝트에 없어 클릭 검증 못 함**(부재키 부여 경로는 세월교와 같은 모듈). #### 선택 시 화면 전체 활성화 + 세션 상시 공유 (2026-09-04 사용자 보고 — 완료) 사용자 보고 두 가지 — ① 3D에서 구조물을 골라도 좌측 패널이 활성화되지 않음 ② 횡단도를 골라도 구조물 리스트가 하이라이트만 되고 보이는 자리로 이동하지 않음. 원칙 재확인 — 구조물 리스트·구조물 배치 폼·배수유역도·테이블·3D(횡단도)가 **함께** 활성화, B05·B06은 다른 페이지지만 **한 페이지처럼**(캐시·세션 공유). 측정으로 확인한 구멍 3 + 검토에서 나온 결함 1: - [X] **좌측 패널 자동 펼치기** — 패널이 접혀 있으면 폼에 값이 실려도 안 보였음(실측: 폼 값은 실렸는데 패널 `is-collapsed`). 바깥(3D·종단·유역도·횡단도·복원)에서 고른 것이 폼에 실릴 때 패널을 펼침(`onReveal` 창구, B05·B06 공용 패널 한 곳). - [X] **리스트 스크롤 이동** — 계곡 통과 시설 행에 `scrollIntoView`가 없었음(구조물 행만 있었음). 선택 행을 보이는 자리로 끌어옴(펼침 직후라 다음 프레임에). - [X] **테이블 강조** — 확정으로 종단 정본에 병합된 구조물 측점이 구조물 구간 판정에서 빠졌고, 소수 3자리 문자열 비교라 끝자리가 갈리면(85.590↔85.594) 놓쳤음. 병합 측점 포함 + 허용오차(1cm) 비교로 교체. 실측 0건 → 6건(구배 3행×2구간). - [X] **세션 상시 공유(양방향)** — 넘김값을 소비형(1회)에서 **유지형**으로 바꿈. B06에서 고른 것(카드·목록·조정창 부재)도 같은 세션 칸에 적혀 어느 쪽으로 오가든 마지막 선택이 살아 있음. 진입 복원은 목록 로드가 늦는 경우까지 이중으로 세움. - [X] **검토 결함 수정** — 카드 선택 시 조정창을 닫는 코드가 "해제"로 세션까지 지워, B06 목록 선택이 적히자마자 사라졌음(실측: 클릭 직후 session null). 부재 해제는 세션을 건드리지 않게 분리. - [X] **자체검증** — 공용 브라우저(5173) 실측 왕복 2종. - B05 진입 복원: 패널 펼침 · 목록 「4+5.6 배수관 1」 선택+보임 · 유역 1 · 그래프 알약 1 · **테이블 6** · 3D 부재 2 — 6개 영역 전부. - B06 목록 「세월교 1」 클릭 → 세션 `{"at":177.32}` → B05 복귀: 같은 항목 선택+보임·유역·그래프·테이블 6·3D 19(측점 전체). - B05 3D 유출 기슭막이(447.32) 클릭 → 세션 `{"at":447.32,"key":"outlet"}` → B06: 패널 펼침·목록 「22+7.3 배수관 3」·카드 선택·조정창 「기슭막이(유출)」·세션 유지. - 줄 수 — B05 페이지 694 · B06 페이지 699 · 나머지 전부 700 미만(한계 근접 — 다음 작업 시 분리 여지 확인). > **주의(700줄 리팩토링 진행 중)** — 손댈 파일이 한계 근처임: 뷰어 693줄 · B05 페이지 691줄 · 코리도 메쉬 531줄 · 구조물 패널 1,024줄(분리 대기). 새 코드는 새 모듈로 빼고, 공유 파일을 손대기 전 `git sync`, 끝나면 push 하고 다른 창에 알릴 것(7장). ### B01 프로젝트 수정 — 회사 로고 기본 연결 (2026-09-04 구현 완료 · 검증 대기) 사용자 지시(2026-09-04) — 「프로젝트 수정 모달의 회사 로고는 소속회사에 연결된 정보를 기본으로 연결하고, 필요한 경우 로고를 변경하게 할 것」. 착수 전 코드를 읽고 낸 현황임. - **도면은 이미 회사 로고로 떨어짐** — 표제란 값 조회가 `COALESCE(p.logo_asset_id, c.logo_asset_id)` 임(`B07_DesignDetail_Router.py`). 프로젝트가 로고를 안 골라도 도면에는 회사 대표 로고가 실림. 즉 이번 일은 **저장 구조 변경이 아니라 화면 표시** 문제임. - **모달이 프로젝트 값만 봄** — 「회사 로고 (도면 표제란)」 칸이 `project.logo_asset_id` 하나만 읽어(`B01_Dashboard_UI_Modals.ts` 의 `createAssetField` 호출, 칸 구현은 `B01_Dashboard_UI_AssetPicker.ts`) 비어 있으면 「(없음)」으로 보임 — 회사 로고가 붙는지 사용자가 알 수 없음. - **회사 로고 값을 가져올 창구는 이미 있음** — `CompanyInfo.logo_asset_id` 와 `fetchUserCompany()`(`B01_Dashboard_Api_Fetch.ts`). 모달이 지금 부르는 구성원·자산 조회와 함께 부르면 됨. - [X] **빈 칸을 회사 기본 로고로 보이기** — 프로젝트 값이 없으면 회사 로고의 미리보기와 이름을 「회사 기본 로고 · <자산명>」으로 표시. **저장값은 계속 비워 둠** — 회사 로고를 바꾸면 프로젝트가 따라가야 하므로(연결 유지) 값을 복사해 굳히지 않음. - [X] **필요할 때만 변경** — [선택…]으로 다른 로고를 고르면 그때만 프로젝트 전용 값으로 저장(지금 동작 그대로). - [X] **[기본으로] 되돌리기** — 프로젝트 전용 로고를 지우고 회사 기본 연결로 되돌림(값 null). - [X] **회사 로고가 없을 때** — 「(없음) — 회사 로고 미지정 (회사 정보 화면의 「로고 지정…」)」으로 안내. - [X] **자체검증 (2026-09-04, 검증 대기)** — 공용 브라우저(5173)에서 프로젝트 `용화_LAS` 로 실측. - 방법 — 자산 칸에 `fallback` 을 넣어 프로젝트 값이 null 일 때 회사 자산을 대신 보이게 함 (`createAssetField` 의 `AssetFieldOptions.fallback`). 회사 정보는 `fetchUserCompany()` 로 함께 받고, **내 회사 프로젝트일 때만**(`company.id === project.company_id`) 기본을 내밈. - 결과 ① 저장값을 null 로 만든 뒤 모달을 다시 열자 이름 `회사 기본 로고 · 캐미팩토리 로고(견본)`, 그림 `/api/dashboard/company/assets/1/file`, `[기본으로]` 는 숨김(`resetHidden=true`). - 결과 ② [기본으로] → [확인] 저장 뒤 서버 재조회 `logo_asset_id = null` — 값 복사 없이 연결만 유지됨. - 결과 ③ 자산 고르기에서 로고를 다시 골라 저장하니 `logo_asset_id = 1` 로 되돌아옴(원래 값 복원 완료). - 결과 ④ 표제란 조회는 `COALESCE(p.logo_asset_id, c.logo_asset_id)` 이고 회사 값이 `1` 이라 프로젝트 null 상태에서도 도면에 실리는 자산 = 화면에 보인 자산(1)로 같음. - 계획 대비 차이 — 「회사 로고 미지정」 안내는 이 계정 회사에 로고가 있어 실화면 확인 불가(코드 경로만 마련). ### B01 모달 — 바깥 클릭으로 닫기 + 변경 확인 (2026-09-04 구현 완료 · 검증 대기) 사용자 지시(2026-09-04) — 「B01 모달 팝업은 다른 공간을 클릭하면 닫히게. 단 내용이 추가되거나 변경된 게 있으면 별도의 확인 모달창(양식화되어 있음)을 보여 줄 것」. 착수 전 코드를 읽고 낸 현황임. - **모달 껍데기를 만드는 자리가 세 곳** — 공통 `openModal`(`B01_Dashboard_UI_Modals.ts` — 프로젝트 수정·삭제·사용자 수정·회사 등록 등 대부분이 여기를 지남), 자산 고르기(`B01_Dashboard_UI_AssetPicker.ts`), 임시보관함(`B01_Dashboard_UI_TempModal.ts`). 셋 다 같은 클래스(`b01-dashboard__modal`)를 씀. - **지금은 바깥을 눌러도 안 닫힘** — [취소]·[확인] 단추로만 닫힘. - **양식화된 확인창은 이미 있음** — 공용 `showConfirmDialog(문구, 확인라벨)`(`ui_template/ui_template_elements.ts`). 네이티브 confirm 대신 반드시 이것을 쓰라고 적혀 있으므로 새로 만들지 않음. - [X] **바깥 클릭 닫기** — 오버레이 자신을 눌렀을 때만 닫고 패널 안 클릭은 무시. `Esc` 도 같은 경로로 묶음. 세 곳 모두 같은 규칙. - [X] **변경 감지** — 모달을 열 때 입력값 스냅샷을 떠 두고, 닫기 시도 때 현재값과 비교. 대상은 입력칸·선택칸·파일칸과 로고 선택값. - [X] **변경이 있으면 확인창** — `showConfirmDialog` 로 「변경한 내용이 저장되지 않습니다. 닫을까요?」를 띄우고 확인이면 닫음, 취소면 모달을 그대로 둠. 변경이 없으면 확인 없이 바로 닫음. - [X] **[취소] 단추도 같은 판정** — 세 곳 모두 [취소]가 바깥 클릭과 같은 `tryClose` 를 지남. - [X] **자체검증 (2026-09-04, 검증 대기)** — 공용 브라우저(5173) 실측. - 방법 — 규칙을 한 곳(`B01_Dashboard_UI_Common.ts` 의 `attachModalDismiss`)에 두고 세 자리에서 부름. 입력칸 밖에서 바뀌는 값(고른 로고·고른 파일)은 `extra` 로 실어 견줌. 확인창이 모달 뒤에 깔리던 문제는 z-index 토큰 `--z-confirm: 1050` 을 새로 두어 해결(모달 1000 < 확인 1050 < 토스트 1100). - 결과 ① 안 고친 프로젝트 수정 모달에 바깥 클릭 → 확인창 없이 즉시 닫힘(`modal=False, confirm=False`). - 결과 ② 로고를 [기본으로] 바꾼 뒤 바깥 클릭 → 확인창 문구 「변경한 내용이 저장되지 않습니다. 닫을까요?」, [취소] 누르니 모달 유지·바꾼 값 유지(`회사 기본 로고 · 캐미팩토리 로고(견본)`). - 결과 ③ `Esc` 도 같은 확인창을 지나고 [닫기] 로 닫힘. 닫기만으로는 서버 값이 안 바뀜(재조회로 확인). - 결과 ④ 자산 고르기 — 안 고치면 바깥 클릭에 바로 닫히고(모달 2→1), 「신규 추가」 이름을 넣으면 확인창이 뜨며 [취소] 시 그대로 남음(모달 2 유지). 임시 보관함 — 안 고치면 바로 닫히고(1→0), 이름을 넣으면 확인창이 뜨고 [취소] 시 값 `보관함 시험` 이 남음. - 결과 ⑤ 패널 안 입력칸 클릭으로는 안 닫힘. 패널에서 시작한 드래그가 바깥에서 끝나도 안 닫힘(누른 자리로 판정). - 계획 대비 차이 — 확인창 z-index 를 함께 고쳐야 했음(계획에 없던 공용 토큰 1건 추가). ### B05 3D — 절토 구간 측점 표시·전체 라벨 (2026-09-04 예정) 사용자 지적(2026-09-04) — ① 「3D 노선에 절토가 된 경우 측점 표시가 안 따라감」 ② 「측점 라벨이 구조물 측점 빼고 5측점 기준으로만 붙음. 전체 라벨이 있으면 좋겠음」. 착수 전 코드를 읽고 낸 현황임. - **① 원인은 한 줄** — 측점 막대의 표고를 `Math.max(지반 표고, 계획고)` 로 잡음(`B05_Profile_UI_Page.ts`). 성토(계획고 > 지반)면 계획고를 타지만 **절토(계획고 < 지반)면 원지반 표고에 그대로 남음** — 3D 코리도는 절취해 노면이 내려가 있으므로 측점 막대만 공중에 뜸. - **고칠 방향** — 코리도(절취 지형)가 켜져 있으면 계획고를 그대로 씀. 코리도를 끈 상태에서는 원지반이 그대로라 지금처럼 `max` 를 유지해야 막대가 땅에 묻히지 않음. 즉 **코리도 표시 여부로 갈라** 잡음. - **② 라벨 규칙** — `STATION_LABEL_STEP = 5` 로 규칙 측점은 5칸(=100m)마다만 달림(`B05_Profile_UI_Markers.ts`). BP·EP·구조물 측점은 항상 달림. 5칸으로 묶어 둔 이유는 글자 겹침임(2026-08-04). - **겹침 대책이 필요함** — 20m 측점을 전부 달면 멀리서 볼 때 글자가 붙음. 카메라가 멀면 솎고 가까우면 전부 보이게 하는 **거리 기준 솎기**가 라벨 수를 늘리면서 읽힘을 지키는 가장 싼 방법임(스프라이트라 카메라 거리를 이미 알고 있음). - [X] **절토 구간 측점 표고** — 코리도 표시 중이면 계획고를 그대로 씀(`max` 제거). 코리도를 끄면 `designAt` 이 값을 안 주므로 지금대로 원지반. - [X] **전체 라벨** — 규칙 측점 전부에 라벨을 만듦(`STATION_LABEL_STEP` 규칙 제거). - [X] **거리 기준 솎기** — `LABEL_LOD` 3단(카메라~시점 150m 미만 전부 · 400m 미만 2칸 · 그 밖 5칸). 구조물·BP·EP 는 `stationNumber: null` 로 두어 항상 표시. 판정은 뷰어 렌더 루프에서 카메라 거리로(단계가 안 바뀌면 즉시 반환). - [X] **자체검증** — 공용 브라우저(5173, 용화_LAS) 실측. - 방법 — 측점 막대마다 **위에서 아래로 레이**를 쏴 코리도 표면·원지반 표고를 재고 막대와의 높이차를 비교(절토 = 코리도가 원지반보다 낮은 측점). 라벨은 스프라이트 개수·화면 글자 크기·겹침 쌍 수로 판정. - ① 절토 측점 3곳 모두 **막대 − 코리도 표면 = 0.80m**(띄움값 그대로). 예: 0측점 코리도 44.78 · 원지반 47.98(절토 3.2m) · 막대 45.58. 고치기 전이라면 원지반 위 48.78 로 **3.2m 공중에 떠 있었을 값**. - ② 성토 측점 10곳도 **0.80m** 로 전과 같음(성토는 계획고가 원지반보다 높아 `max` 와 결과가 같음). - ③ 라벨 66개(측점 66개 전부) 생성. 카메라를 붙이면 **66개 전부 표시**, 중간 거리 39개, 화면맞춤 23개(항상 13 + 5칸 10). - ④ 화면맞춤에서 겹침 **1쌍**(항상 표시끼리 — 같은 자리 BP·구조물). 규칙 측점끼리 겹침 0. 글자 크기는 화면맞춤 4px → 가까이 47px. - 계획 대비 차이 — 없음. ### B04·B05 배수유역도 — 줌 한계 확대·측점 표기 (2026-09-04 구현 완료 · 검증 대기) 사용자 지적(2026-09-04) — ③ 「B04·B05 배수유역의 줌인이 너무 멀리서 멈춤. 한 화면에 측점 1~2개까지 확대되면 좋겠음」 ④ 「배수유역도에 측점 표기가 없어 종·횡단이나 3D와 견주어 보기 불편함. 다만 횡단배수 지점과 겹치지 않게 할 것」. 착수 전 코드를 읽고 낸 현황임. - **줌 상한이 낮음** — B04 지도는 **8배**(`B04_PreProcess_UI_MapViewer.ts`), B05 배수유역도는 **16배**(`B05_Profile_UI_Drainage_Interact.ts`)에서 멈춤. 도엽 한 장이 화면 폭에 들어오는 배율이 1배이므로, 도엽 폭이 1km 급이면 8배에서도 화면에 100m 이상이 들어옴 — 측점 5개 이상임. - **필요한 배율** — 규칙 측점 간격 20m 기준으로 한 화면에 1~2측점 = **화면 폭 20~40m**. 도엽 실폭(`meta.width_meters`)을 알고 있으므로 상한을 고정 숫자가 아니라 **「화면 폭이 20m가 될 때까지」로 계산**하면 도엽 크기가 달라도 같은 체감이 됨. - **측점 표기가 없음** — 배수유역도는 계획선 위에 관 마커·유입 집중점·유역 번호 배지·선택 다이아몬드만 그림(`B05_Profile_UI_Drainage_Render.ts`). 측점 눈금·번호는 없음. - **겹침 주의 대상** — 횡단배수(관) 마커가 계획선 위 같은 자리에 있음. 유역 번호 배지도 맨 위에 얹힘. 측점 라벨을 같은 쪽에 그리면 관 마커를 가림. - [X] **줌 상한 상향** — 고정값(8배·16배) 대신 `computeMaxScale()` 로 「화면 폭 20m」 배율까지 허용. 안전장치 `ZOOM_SCALE_HARD_CAP = 2000`. - [X] **확대 시 화질** — 배율 4 를 넘으면 배경 그림의 흐림 보간을 끔(`image-rendering: pixelated`). 실제 크기는 축척 막대로 읽음. - [X] **측점 눈금·번호** — 계획선 위 짧은 눈금 + `측점번호+잔여거리` 표기. 그리는 코드는 한 곳(`drawStationTicks`, B04 MapOverlays)에 두고 B04·B05 가 함께 씀. - [X] **겹침 회피** — 관 마커가 있는 측점은 라벨을 계획선 반대쪽으로 밈. 배율에 따라 5칸 → 2칸 → 전부. **노선이 되꺾이는 자리**에서는 그것만으로 모자라 이미 그린 라벨과 겹치면 건너뛰는 규칙을 더함. - [X] **자체검증 (2026-09-04, 검증 대기)** — 공용 브라우저(5173) · 프로젝트 `용화_LAS`. 캔버스 그리기 호출을 한 프레임만 가로채 화면 좌표를 수치로 비교. - 결과 ① 최대 확대에서 화면 폭 **B05 20.0m**(배율 122.7), **B04 20.0m**(배율 208.3) — 종전 상한(16배·8배)으로는 각각 150m·460m 급이었음. B04 축척 막대가 「5 m」로 바뀜. - 결과 ② 그 배율에서 배경 그림은 `image-rendering: pixelated` 로 전환됨. - 결과 ③ B05 한 프레임에 측점 라벨 8개·관 마커 11개, 라벨↔마커 최소 거리 **16px**, 라벨끼리 최소 **36px** — 겹침 없음(라벨 높이 16px). - 결과 ④ B04 도 같은 라벨이 뜸(11개, 라벨끼리 최소 18px). 겹침 규칙을 넣기 전에는 되꺾이는 구간에서 최소 4px 까지 붙었음 — 규칙 추가 후 해소. - 계획 대비 차이 — 겹침 회피에 「이미 그린 라벨과 겹치면 건너뛰기」를 더함(계획에 없던 규칙, 되꺾임 구간 때문). ### B03~B08 좌측 패널 제목 줄 — 프로젝트 이름 우측 표기 (2026-09-04 구현 완료 · 검증 대기) 사용자 지적(2026-09-04) — 「B03~B08 좌측 패널 상단 페이지 제목의 같은 행 우측 맞춤으로 프로젝트 이름을 넣어 달라고 했는데 반영 안 된 것 같음」. - **확인 결과 실제로 안 들어가 있음** — 좌측 제목 패널은 공용 `createPanel("title", …)` 하나가 만들고 **제목 문자열 하나만** 받음(`ui_template/ui_template_overlay.ts`). 페이지들은 `createWorkflowLayout({ title })` 로 그 문자열만 넘김(`ui_template/ui_template_workflow_layout.ts`) — 프로젝트 이름이 들어갈 자리 자체가 없음. - **이름을 어디서 가져올지부터 정해야 함** — 화면이 들고 있는 것은 프로젝트 **id 뿐**임(`localStorage` 의 현재 프로젝트 키, `A00_Common/b_page_scaffold.ts`). 워크플로 상태 응답(`WorkflowState`)에도 이름이 없음. 두 갈래 — ① 워크플로 상태 응답에 이름 한 칸 추가(백엔드 조회에 컬럼 하나) ② 대시보드에서 프로젝트를 고를 때 이름도 localStorage 에 저장. **①이 안전함** — 새로고침·주소 직접 입력으로 들어와도 이름이 따라옴. - [X] **이름 창구** — 워크플로 상태 응답(`get_workflow_state`)에 `project_name` 을 실음. 프론트는 `fetchProjectWorkflowState` 로 받음(응답 껍데기 `{status, workflow_state}` 를 벗기도록 함께 고침). - [X] **제목 줄 오른쪽 표기** — 제목은 왼쪽, 프로젝트 이름은 같은 행 오른쪽 끝. 길면 말줄임, 전체는 툴팁. - [X] **한 곳만 고쳐 여섯 화면 반영** — 공용 제목 패널(`ui_template_overlay.ts` 의 `createPanel`)에 이름표를 붙임. B03 은 레이아웃을 직접 조립해 `createWorkflowLayout` 을 안 지나므로, 이름표를 **오버레이 쪽**에 두어 두 조립 경로가 모두 얻게 함(페이지 코드는 손대지 않음). - [X] **이름이 없을 때** — 프로젝트 미선택·조회 실패면 빈 칸(너비 0). - [X] **자체검증 (2026-09-04, 검증 대기)** — 공용 브라우저(5173) · 프로젝트 `용화_LAS` 로 실측. - 결과 ① B03~B08 여섯 화면 모두 이름 `용화_LAS` 표시(툴팁도 같은 값). - 결과 ② 여섯 화면 모두 제목과 같은 행(세로 중심 차 4px 미만), 패널 오른쪽 끝에서 16px(=패널 좌우 여백)로 붙음. 제목과 겹침 없음. - 결과 ③ 긴 이름을 넣어 재니 처음에는 제목이 59px→36px 로 밀리며 잘렸음 → 제목 패널의 제목만 `flex: 0 0 auto`, 이름은 `max-width: 60%` 로 고쳐 다시 재니 제목 59px 그대로, 이름만 말줄임(`nameClipped=true`), 겹침 없음. - 결과 ④ 새로고침 뒤에도 이름 유지. 프로젝트 id 를 지우면 칸 너비 0(제목만 보임). - 계획 대비 차이 — ⓐ 이름표 자리를 워크플로 레이아웃이 아니라 오버레이로 옮김(B03 경로 때문) ⓑ `fetchProjectWorkflowState` 가 껍데기를 안 벗기고 있어 함께 고침 ⓒ 백엔드 `.py` 변경을 uvicorn StatReload 가 잡지 못해 8000 백엔드를 한 번 재시작함(서브 창 8001 은 그대로). ### B02·B03 계획노선 범위 — 시·종점 누가거리 입력과 절단 여유 3m (2026-09-04 구현 완료 · 검증 대기) 사용자 지시(2026-09-04) — 「계획노선 자료는 공사지 전체 데이터일 수 있어 사용자가 범위를 정할 필요가 있음. B02 프로젝트 생성 과정에서 노선의 시작 누가거리·종료 누가거리를 받고, 그에 맞춰 B03 의 내부 CSV 로 계획 평면 노선을 정한 뒤 서피스 밖 데이터를 잘라낼 것. 이때 절단 기준이 30m 로 되어 있는데 **3m 로 변경** 필요」. 착수 전 코드를 읽고 낸 현황임. - **절단 여유 값은 한 곳뿐** — `SURFACE_ROUTE_EDGE_TRIM_M = 30.0`(`config/config_system_terrain.py`), 쓰는 곳은 `trim_route_to_surface`(`common_util/common_util_route_geometry.py`) 하나임. 기본값만 바꾸면 전 경로에 반영됨(환경변수로도 덮임). - **30m 은 2026-09-01 사용자 확정값이었음** — 이유가 「서피스 가장자리는 점 밀도가 떨어져 그 구간 지반고가 못 미덥다」였음. 3m 로 낮추면 가장자리 값을 더 믿는 셈이므로 **끝단 지반고가 튀지 않는지 확인이 함께 필요**함(이번 지시로 값은 3m 로 바꿈). - **B02 에 누가거리 칸이 없음** — 지금 받는 값은 공사명·지역·임도 종류·연도·연장·메모·시행청·연도기번·사업량·설계일자·담당자임(`B02_ProjRegister_UI_Page.ts`). 프로젝트 저장 구조에도 없음 — **화면·스키마·DB 세 층 모두 칸 추가가 필요**함. - **자르는 순서** — 사용자 범위(시·종점 누가거리)로 먼저 자른 뒤, 남은 노선에 서피스 트림(3m 여유)을 적용해야 함. 순서가 바뀌면 사용자가 정한 시점이 서피스 트림에 밀려 달라짐. - [X] **절단 여유 3m** — `SURFACE_ROUTE_EDGE_TRIM_M` 기본값 30 → 3. - [X] **B02 입력 두 칸** — 「노선 시작 누가거리 (m)」·「노선 종료 누가거리 (m)」. 비우면 전 구간. - [X] **값 저장** — `projects.route_start_m`·`route_end_m` 추가(마이그레이션 `db_management/015_route_range.sql`, 공유 DB 에 적용 완료). B01 프로젝트 수정 모달에서도 고침. - [X] **B03 적용** — `load_design_route(project_root, surface, route_range)` 로 **범위 절단 → 서피스 트림** 순서 보장. 자동 체인이 프로젝트 값을 읽어 넘김. - [X] **잘못된 범위 안내** — 시작 ≥ 종료는 화면(B02·B01)과 서버(B02·B01 라우터) 양쪽에서 막음. - [X] **자체검증 (2026-09-04, 검증 대기)** — 프로젝트 `용화_LAS` 실측 + 단위 시험(`tmp/tests`). - 결과 ① 실제 노선(전 구간 2136.2m)에 범위 100~400m 를 걸면 **300.0m** 만 남고, 남은 시점 좌표가 원 노선 100m 지점과 0.5m 안에서 같음(`test_route_range_real.py`). - 결과 ② 절단 여유 30m → 3m 로 낮추자 연장 1070.4m → **1097.4m**(+27.0m). 양 끝 20m 구간의 지반고 변화율 최대 **0.203**, 노선 안쪽 최대 **0.494** — 끝단이 더 튀지 않음(`test_edge_trim_3m_yonghwa.py`). - 결과 ③ 범위를 비우면(`None, None`) 전 구간 그대로. - 결과 ④ B01 수정 모달에서 900~120 을 넣고 저장하면 서버가 막아 값이 안 바뀜(모달 유지). B02 등록에서도 같은 값으로 「종료 누가거리는 시작보다 커야 합니다.」가 뜨고 프로젝트가 생기지 않음. - 결과 ⑤ B01 모달에 120·900 을 저장하면 서버 값이 그대로 돌아오고, 비우면 다시 `null`(원상 복구까지 확인). - 계획 대비 차이 — 이미 자동설계를 마친 프로젝트는 계획노선 **정본 CSV** 를 지름길로 읽으므로, 범위를 나중에 바꿔도 초기값 스냅샷을 지우고 다시 돌리기 전에는 반영되지 않음(신규 프로젝트는 정상). 스냅샷 폐기 연동은 별도 판단 필요. ### B05 3D — 원근 카메라로 되돌리기 (2026-09-04 예정) 사용자 지시(2026-09-04) — 「3D 원근 관련 기능을 바꾼 적이 있는데 **이전 방식이 좋았음**. 되돌리되 바꾼 뒤 문제가 될 요소를 미리 확인할 것」. - **바꾼 자리를 찾음** — 커밋 `f6296fa7`(2026-08-25) 「구조물 3D 투영 표기 · **직교 카메라** · 조정창 템플릿 일원화」. 그 전에는 원근 카메라(시야각 45°)였고, 이때 `B05_Profile_UI_Viewer_Camera.ts` 를 새로 만들어 **직교(원근 없음)** 로 바꿈. 당시 이유는 「원근 왜곡 없이 탑뷰 판독」이었음. - **그 이유가 지금은 거의 사라짐** — 직교가 필요했던 대상은 탑뷰에 겹쳐 그리던 **구조물 투영 윤곽선**(노랑·하늘·주황)인데, 그 커브 묶음은 2026-09-02 사용자 지시로 **숨김 처리**되어 지금 화면에 없음(`__corridorPlanCurves(true)` 로만 켬). - **되돌릴 코드는 작음** — 뷰어에서 카메라를 만드는 자리와 화면맞춤 한 줄(`setHalfHeight`)뿐임(`B05_Profile_UI_Viewer.ts` 4곳). 카메라 위치·근평면·먼평면 계산은 그대로 씀. - **B04 는 계속 원근임** — 지표면 뷰어들은 지금도 원근 카메라라, 되돌리면 **B04·B05 조작감이 같아지는 이득**이 있음. 커서 피벗 줌 유틸은 두 방식 모두 지원하며(B04가 원근 경로를 매일 씀) 갈아 끼울 것이 없음. **되돌린 뒤 문제가 될 요소(미리 점검한 결과)** - **탑뷰 왜곡이 돌아옴** — 화면 중앙에서 먼 측점일수록 구조물 옆면이 보여 위에서 내려다본 크기 비교가 어긋남. 정밀 대조가 필요할 때를 대비해 **직교/원근 전환 단추**를 하나 두는 안을 함께 검토(기본은 원근). - **줌 느낌이 달라짐** — 직교는 배율만 키우지만 원근은 카메라가 실제로 다가감. 아주 가까이 가면 근평면에 지형이 잘릴 수 있음(근평면은 화면맞춤 거리의 1/1000). 확대 한계를 실측으로 확인할 것. - **측점 띠·라벨 크기** — 스프라이트·띠 크기가 지금 직교 기준으로 잡혀 있어(라벨 높이 3.2 단위, 띠 0.18×0.5) 원근에서는 가까울수록 커지고 멀수록 작아짐. 「B05 3D 절토 구간 측점 표시·전체 라벨」 항목의 **거리 기준 라벨 솎기와는 오히려 궁합이 맞음** — 두 항목을 같이 손보는 것이 이득. - **화면맞춤 크기감** — 지금은 직교 반높이를 `거리 × 0.42` 로 두어 원근 45° 를 흉내 내는 중이라, 되돌리면 자연히 원래 크기감으로 맞음. - **문제 없음을 확인한 것** — 구조물·마커 클릭(둘 다 카메라 종류와 무관), 나침반, 저장 코리도 캐시(기하와 무관해 무효화 불필요), 탑뷰 기울임(극점 뒤집힘 방지)은 그대로 유지. - [X] **원근 카메라 복귀** — 뷰어 카메라를 시야각 45° 원근으로 되돌리고 직교 전용 화면맞춤 처리를 걷어냄. `B05_Profile_UI_Viewer_Camera.ts` 삭제(직교 전용 모듈), 뷰어 4자리 복원. 뷰어 689줄. - [X] **직교/원근 전환 단추** — 2026-09-04 사용자 확정 「넣음」. [ISO][TOP][FRONT][SIDE] 옆에 단추 하나, 글자는 **갈 쪽**을 가리킴(`직교로` ↔ `원근으로`). 기본은 원근. - 카메라 두 벌을 `B05_Profile_UI_Viewer_Camera.ts` 가 쥐고 갈아 끼움. 갈아 끼우면 객체가 바뀌므로 마커 입력·구조물 클릭·커서 피벗 유틸이 카메라를 **값이 아니라 함수로** 받도록 바꿈(공용 `B04_PreProcess_UI_Camera.ts` 는 값도 그대로 받게 두어 B04 호출부 무변경). - 전환해도 화면이 튀지 않게 위치·시선·근평면·먼평면을 옮기고, 보이는 크기를 맞춤(원근→직교는 시점거리로 반높이를, 직교→원근은 배율로 거리를 되돌림). - **자체검증**(용화_LAS, 5173) — [직교로] 클릭 → `Ortho`, 카메라 위치·근평면·먼평면 그대로, 화면 크기 1,217×795px → 1,096×730px(원근 왜곡분 10%). 단추 글자 `원근으로` 로 바뀜. 직교 상태에서 휠 확대 = 배율 1 → 1.882 로 동작. [원근으로] 클릭 → 되돌아오고 값이 처음과 **완전히 일치**. B04 지표면 화면에서 휠·드래그 시 페이지 오류 0건. - [X] **근평면 확인** — 실측 결과 **근평면 상한 0.4m 를 새로 걺**. 휠 확대는 커서 아래 지점 0.5m 앞에서 멈추는데(커서 피벗 유틸) 근평면을 맞춤거리의 1/1000 로만 두면 긴 노선에서 그 0.5m 를 넘어 잘림. 용화_LAS(맞춤거리 1,208m)는 상한 없이는 근평면 1.21m > 0.5m 로 **잘렸을 값**. - [X] **측점 띠·라벨 크기 재조정** — **손대지 않음**. 실측 결과 직교 때와 화면 글자 크기가 같음(화면맞춤 3.9px — 직교 반높이 `거리×0.42` 로 계산한 값과 일치). 읽힘은 크기가 아니라 **거리 기준 솎기**(위 라벨 항목)로 해결함. - [X] **자체검증** — 공용 브라우저(5173, 프로젝트 `5cff3920` 용화_LAS) 실측. ④ 는 라벨 항목과 함께 하므로 남김. - 방법 — 좌측 [ISO]·[TOP]·[FRONT]·[SIDE] 단추를 실제로 눌러 카메라 상태와 모델 경계의 화면 픽셀 크기를 잼. 확대 한계는 캔버스 위에서 **실제 휠**을 100칸 굴려 커서 아래 지점까지의 거리와 근평면을 비교. 구조물은 노출된 캔버스 지점을 찾아 **실제 마우스 클릭**. - ① 네 방향 모두 `Perspective · 시야각 45°` 로 뜸(직교 0건). 화면맞춤 크기감 — 직교는 반높이를 `거리×0.42` 로 원근 45°(tan 22.5° = 0.41421)를 흉내 내던 값이라 **차이 1.4%**, 되돌린 뒤가 원래 크기감임. 탑뷰 모델 885×583m → 화면 1,217×795px(캔버스 1,341×1,240). - ② 확대 한계 — 휠 100칸에서 커서 아래 지점까지 **0.516m 에서 멈춤**, 근평면 0.4m 이라 잘림 없음. 축소는 far(맞춤거리×10)까지 그대로. - ③ 구조물 클릭 — 유출 기슭막이 클릭 → 넘김값 `{"at":85.594514,"key":"outlet"}` · 밝은 메쉬 2장(그 부재만) · 좌측 목록 `4+5.6 배수관 1` 선택. 빈 곳 클릭 → 넘김값 `null` · 밝은 메쉬 0장. - ⑤ B04 와 조작감 — B04 지표면 뷰어도 원근(시야각 50°)이고 커서 피벗 줌 유틸을 공유하므로 같은 계열이 됨(전에는 B05만 직교였음). - 계획 대비 차이 1가지 — **근평면 상한 0.4m 추가**. 계획은 「필요하면 조정」이었고 실측에서 긴 노선이 잘리는 것이 확인돼 반영함. ### B07 횡단면도 — 축척 뒤죽박죽 확인 (2026-09-04 완료, 검증 대기) 사용자 지적(2026-09-04) — 「B07 횡단면도의 축척이 뒤죽박죽으로 보임」. - **축척 값 자체는 한 곳 고정** — `DRAWING_SCALE_CROSS = 100`(1/100), 도면 좌표 환산도 그 한 값만 씀(`B07_DesignDetail_Engine_Cad.py` 의 `CROSS_MM`). 단면마다 다른 축척을 쓰는 코드는 없음. - **대신 단면마다 그리는 범위가 다름** — 가로는 「설계선이 원지반과 갈라졌다 다시 만나는 구간 + 여유 1.5m」, 세로는 그 구간의 표고차로 잡음(`_section_window`). 절·성토가 큰 측점은 크게, 작은 측점은 작게 나옴. - **칸 크기도 제각각** — 장 배치가 열폭 = 그 열 최대폭, 행높이 = 그 행 최대높이임(2026-08-30 사용자 확정). 그래서 **같은 축척이어도 테두리·간격이 들쭉날쭉**해 축척이 다른 것처럼 보일 수 있음. - **먼저 가릴 것** — 서로 다른 두 단면에서 **같은 실거리(예: 노폭 3m)가 종이에서 같은 mm 인지** 재 볼 것. 같으면 「칸 크기」 문제이고, 다르면 진짜 축척 문제임(장 배치에서 블록을 줄이는 자리가 있는지 추적). - [X] **원인 가리기** — 같은 실거리의 종이 치수를 두세 단면에서 재어 축척 문제인지 칸 크기 문제인지 확정. - 실측(용화_LAS, 측점 12개): 실거리 3 m 가 모든 단면에서 **정확히 30.0 mm** — mm/m 이 전부 `10.0000`. **축척 문제 아님.** - 같은 장(1장, 단면 6개) 칸 실측: 폭 116~218 mm(차 102), 높이 29~178 mm(차 148). 전체 65개 측점으로는 폭 116~438, 높이 77~427. **칸 크기 문제 확정.** - [X] **칸 크기 문제면** — 한 장 안의 단면 칸을 같은 폭·높이로 통일(가장 넓은 단면 기준). 빈 곳은 여백으로 두어 눈에 규칙이 서게 함. - 옛 배치(열폭 = 그 열 최대, 행높이 = 그 행 최대)를 **장별 완전 통일**로 교체 — 한 장 안 모든 칸이 같은 폭·높이(`_grid_for`), 테두리는 `build_cross_drawing(cell_frame=...)` 로 칸에 맞춰 그림. - 장 경계는 **전체 최소 장수**가 되도록 동적계획으로 고름(`_sheet_breaks`) — 앞에서부터 채우면 바로 뒤의 큰 단면이 칸을 키워 6칸짜리 장에 1개만 실리는 일이 있었음. - [X] **축척 문제면** — 블록을 줄이는 자리를 없애고 1/100 을 그대로 지킴. 한 장에 안 들어가면 장을 나눔. - 축척은 지식DB 「설계제원_총괄」 측량·도면 기준의 **1/100 고정**(단일값, 범위 없음). 블록을 줄이는 자리는 원래도 없었음 — 확인만 함. - [X] **표제란 축척 표기 일치** — 실제로 그린 축척과 표제란 값이 같은지 확인. - 표제란 `scale_fields(("", DRAWING_SCALE_CROSS))` = 1/100, 실측 mm/m = 10.0 — 일치. - [X] **자체검증** — 도면 실측. ① 두 단면의 같은 실거리 종이 치수 일치 ② 한 장 안 칸 크기 균일 ③ 표제란 축척 일치 ④ 측점 누락 없음. - 방법: `tmp/tests/test_b07_cross_scale.py` · `test_b07_cross_uniform.py` · `test_b07_variant_compare.py` (용화_LAS) + **실서버 실측** — 로그인된 공용 브라우저(5174)에서 `design-drawings` API 를 불러 장별 칸 크기를 잼. - 결과 ① 3 m = 30.0 mm 전 단면 동일 ② 장 21개 전부 한 장 안 칸 폭·높이 단일값(예 1장 193×207.37 mm ×6칸, 4장 283×276.92 mm ×2칸) ③ mm/m = 10 단일 ④ 측점 65개 = 장에 담긴 측점 65개, 누락 0 ⑤ 칸 밖으로 나간 그림 0.000 mm. - 계획 대비 차이: **장수가 16 → 21~22 장으로 늘어남**(칸 통일의 대가, 칸 사용률 평균 82%, 단면 1개만 실리는 장 4개). 2026-09-04 사용자 확정 — 축척은 건드리지 않고 세트별 장수 변동·여백 발생을 허용. ### B06 표준 횡단면 설정 — 하나의 상세값 컨테이너로 통합 (2026-09-04 예정) 사용자 지시(2026-09-04) — 「좌측 패널의 표준 횡단면 설정 3가지 기준이 대부분 중복임. **「표준횡단면 상세값」 한 컨테이너**로 묶을 것. 노폭·노견·측구는 공통, **암 구간**은 반영할 절토 경사와 L형 측구만, **포장 구간**은 절·성토 경사가 토사와 같고 횡단 경사만 다름. 공통 항목은 지우고 구분선을 써서, 횡단도에서 옵션을 골랐을 때만 해당 값이 반영되게 할 것」. - **지금 구조** — 토사·암·포장 **3그룹이 같은 필드 묶음을 각각** 가짐(노폭 / 노견 좌·우 / 측구 상단·하단·깊이 / L형 측구 폭·깊이 / 절토 경사 / 성토 경사 / 횡단 경사 최소·최대). 필드 정의는 한 벌인데 그룹마다 반복해 그림(`B06_Section_UI_Standard_Panel.ts`). - **바꿀 구조**(사용자 확정) — 공통 = 노폭·노견·측구, 구분선 뒤 **암** = 절토 경사 · L형 측구, 구분선 뒤 **포장** = 횡단 경사. 포장의 절·성토 경사는 토사 값을 그대로 씀. - **저장 구조는 건드리지 않는 것이 쌈** — 서버와 주고받는 값은 지금 3그룹 형태임(`standard_cross_section`). 화면만 한 컨테이너로 합치고 **저장할 때 3그룹으로 펼쳐** 보내면 백엔드·기존 프로젝트가 그대로 동작함. - **판단이 필요한 한 가지** — 기존 프로젝트가 그룹마다 **다른 공통값**(예: 암 노폭만 다름)을 갖고 있을 수 있음. 합칠 때 무엇을 공통값으로 삼을지 규칙이 필요함(토사 값을 기준으로 삼는 안이 무난 — 착수 시 사용자 확인). - [X] **한 컨테이너로 묶기** — 「표준횡단면 상세값」 하나에 공통 → 구분선 「암 구간 — 다른 값만」 → 구분선 「포장 구간 — 다른 값만」 순으로 배치. 옛 토사/암/포장 3개 접이 그룹은 없앰. - [X] **중복 필드 제거** — 칸이 **31개에서 15개**로 줄었음. 공통 10칸(노폭·노견 좌우·측구 3·절토·성토 경사· 횡단 경사 min/max) + 암 3칸(절토 경사·L형 측구 폭/깊이) + 포장 2칸(횡단 경사 min/max). - [X] **선택에 따른 반영** — 저장 구조가 3그룹 그대로라 카드에서 고른 옵션이 값을 고르는 경로는 **바뀐 것이 없음**. - [X] **저장 호환** — 화면만 합치고, 공통값은 고칠 때 세 그룹에 펼쳐 넣음(`spread`). 나가고 들어오는 값은 예전과 같은 `standard_cross_section` 3그룹. - [X] **기존 값 합치기 규칙** — 사용자 확정(2026-09-04): **토사 값 기준**. 패널을 열 때·불러올 때·리셋할 때 `unifyCommon` 이 공통 항목을 토사 값으로 한 벌 맞춤(암 절토 경사·포장 횡단 경사는 제외). - [X] **자체검증**(2026-09-04, 공용 브라우저 5174 · 프로젝트 **용화_LAS**) — 세션 저장분을 직접 읽어 판정. - ① 공통 노폭 3 → 3.4 로 고치니 토사·암·포장 **셋 다 3.4**. **합격** - ② 암 절토경사 0.4 → 0.55 는 **암만** 바뀌고 토사·포장은 1 그대로. L형 측구도 암 그룹에만 있음. **합격** - ③ 포장 횡단경사 최소 1.5 → 1.8 은 **포장만**, 토사·암은 3 그대로. **합격** - ④ 새로고침 뒤에도 화면·세션 값 그대로(3.4 / 0.55 / 1.8). **합격** - ⑤ 옛 프로젝트 흉내로 그룹마다 다른 공통값을 심음(암 노폭 9, 포장 측구 상단 7, 암 성토경사 5) → 새로고침하니 전부 **토사 값으로 합쳐짐**(3.4 / 0.9 / 1.2). 구간 고유값(암 절토 0.55, 포장 횡단 1.8)은 유지. **합격** - **계획 대비 차이** — 없음. 검증에 쓴 값은 원래 값(노폭 3 · 암 절토 0.4 · 포장 횡단 1.5)으로 되돌려 놓음. ### B07 표준 횡단면도 — 변수 모식도·치수·부분확대·암반선 (2026-09-04 완료, 검증 대기) 사용자 지시(2026-09-04) — 「표준 횡단면도 좌상단에 기본값으로 **B06 좌측 패널의 변수 위치 안내와 비슷한 그림**을 넣고, 변수 이름 자리에 **도면처럼 치수**를 적을 것. 측구는 작으니 **부분 확대도**로. 발파·암반이면 **암반선**과 각도를 넣어 절토측이 **2단**(토사 각도 + 암반 각도)으로 표현될 것」. - **자리는 이미 있음** — 「표준 횡단면도」는 지금 도각만 있는 빈 도면임(`blank_cross_standard`, 2026-09-01 사용자 지시로 빈 채 열어 둠). - **모식도 원본이 있음** — B06 좌측 패널의 변수 위치 안내 모식도(`B06_Section_UI_Standard_Diagram.ts`). 같은 배치를 도면 축척·선굵기로 옮기면 됨. - **치수 값 출처** — 위 「B06 표준 횡단면 설정」의 값. 두 항목을 잇대어 하면 값 창구가 한 곳으로 정리됨. - [X] **본 그림** — 좌상단에 표준 횡단면 모식도, 각 변수 자리에 **치수선·치수값**(도면 표기). - B06 모식도와 같은 배치(좌=절토·측구, 우=성토, 가운데=계획고)를 **실치수**로 그림. 축척 1/50(`DRAWING_SCALE_CROSS_STANDARD`). 치수선은 눈금+치수값 한 벌로 그리는 헬퍼로 통일. - [X] **측구 부분 확대도** — 측구를 따로 확대해 그리고 그 확대 축척을 함께 적음. - 1/10(`DRAWING_SCALE_DITCH_DETAIL`), 상단폭·저폭·깊이 3개 치수 + 「측구 상세도 (S = 1/10)」 표기. - [X] **암반선·2단 절토** — 발파·암반 구간은 암반 경계선을 긋고 위는 토사 각도, 아래는 암반 각도로 **2단** 표기(각도 값 함께). - 절토측에 덧그림. 아래 1.5 m 는 암반 1:0.4, 그 위는 토사 1:1. 암반선은 수평 파선 + 「암반선」 표기. - [X] **어떤 구간을 그릴지 정리** — 기본은 토사, 암·포장은 달라지는 값만 덧그림(또는 별도 칸). - 본 그림 = 토사 기준. 암은 2단 절토로 덧그리고, L형 측구·포장 횡단경사는 **주기(※)** 로 적음. 사용자가 「묻지 말고 진행」이라 하여 이 안으로 확정. - [X] **자체검증** — 도면 실측. ① 치수값이 표준 설정과 일치 ② 부분 확대도 축척 표기 ③ 암반선 2단 각도 표기 ④ 도각·표제란 정상. - 방법: `tmp/tests/test_b07_standard_cross.py` + 도면을 PNG 로 렌더해 눈으로 확인. - 결과 ① 본 그림 치수 `500·3000·500·900·4000` 이 `STANDARD_CROSS_SECTION` 값과 일치 ② 확대도 `900·300·300` + 「S = 1/10」 표기 ③ 「암반선」·「암반 1:0.4」·「토사 1:1」 표기, 2단 절토선이 꺾임점 1개(선분 2개) ④ 콘텐츠 358.2 × 172.6 mm ≤ A1 작도영역 739.2 × 499.2 mm, 표제란 축척 1/50 ⑤ 도면 목록에 `cross_standard` 가 실리고 빈 도각 목록에는 「표준도」만 남음. - 계획 대비 차이: 절·성토 높이는 실제 지형이 없으므로 대표값 3 m 로 그림(표준도 관례). 값 창구를 한 곳으로 모으는 「B06 표준 횡단면 설정 통합」 항목은 창 3 담당이 아니라 그대로 둠. - **실서버·화면 확인**: 도면을 실제로 열어 캡처 — 도면층 7개(표준 단면·암반선 2단 절토·치수·측구 상세도·주기·표제·도각)가 모두 서고 표제란이 채워짐. ### B07 계획평면도 3종 — 수치등고선 배경(유역도 자료 공유) (2026-09-04 완료, 검증 대기) 사용자 지시(2026-09-04) — 「계획평면도(지형·노선배치도·배치도) 세 장은 유역도와 같이 **수치등고선을 배경**으로 깔 것. 캐시 자료를 유역도와 **공유**할 수 있으면 좋겠음. 이걸 배경으로 다음 내용을 추가 설명 예정」. - **유역도가 쓰는 배경을 그대로 쓰면 됨** — 유역도는 도엽 수치지형도의 **등고선·세류선**(`도엽_등고선.geojson`·`도엽_하천중심선.geojson`)을 배경으로 깖. 읽기·좌표 환산·도곽 크기 절취는 `B07_DesignDetail_Router_Support_Basin.py` 한 곳에 있음 — **그 함수를 계획평면도도 부르면 자료·캐시가 저절로 공유**됨. - **셋 다 지금은 빈 도면** — `blank_plan_terrain` · `blank_plan_route` · `blank_plan_layout`. - **정할 것은 축척** — 유역도는 1/6000 고정임. 계획평면도는 노선 전장이 들어가야 하므로 축척을 따로 정해야 함(도곽 크기에서 역산). - [X] **배경 공용화** — 유역도의 배경 준비 함수를 계획평면도에서도 부르도록 창구 하나로 정리(자료 읽기 한 번, 여러 도면이 공유). - `map_background()` 하나로 모음(도엽 읽기·좌표 환산·도곽 절취). 유역도·계획평면도가 같은 것을 부름. 환산 결과는 `_metric_lines_cached`(파일 mtime 키)로 캐시. - [X] **축척 결정** — 노선 전장·도곽 크기로 계획평면도 축척을 정함(장 나눔 규칙 포함). - 지식DB 「설계제원_총괄」 측량·도면 기준 **1/1,200 고정**(`DRAWING_SCALE_PLAN`). 횡단면도와 같은 원칙 — 줄이지 않고 안 들어가면 장을 나눔(`plan_chunks`, 종단 측점 기준·경계 측점 1개 중복). 용화_LAS 노선 전장 1,070 m·bbox 630×214 m → 종이 525×178 mm 로 **1장**. - [X] **세 장의 주제 초안** — 지형 = 등고선·세류선만, 노선배치도 = 계획노선·측점, 배치도 = 구조물 배치. 세부는 사용자 추가 설명을 받아 보강. - 세 장 모두 같은 배경·같은 도곽 배치(지형도도 노선을 범위에만 넣고 그리지는 않음). 구조물은 `pipe_points.json` 정본에서 읽어 마름모+이름(세월교·BOX암거·D800 등). - [X] **자체검증** — 세 장 모두 등고선 배경이 도곽 안에서 잘려 나오는지, 축척 표기와 실제가 맞는지, 유역도와 같은 자료를 두 번 읽지 않는지(응답 시간으로 확인). - 방법: `tmp/tests/test_b07_plan_drawings.py` (용화_LAS) — 실제 도면 생성 후 레이어별 개수·bbox·캐시 통계 실측. - 결과 ① 콘텐츠 734.3 × 489.2 mm ≤ A1 작도영역 739.2 × 499.2 mm, 세 장 동일 ② 노선 실거리 630.1 × 214.2 m → 종이 525.12 × 178.46 mm, 실측 **0.83333 mm/m = 1/1,200** 정확히 일치(표제란 표기와 같음) ③ 등고선 180줄·세류선 10줄이 세 장 모두 동일 ④ 주제 구분 확인 — 지형에 노선 0, 노선배치도에 측점 130개(65측점×눈금+이름)·구조물 0, 배치도에 구조물 22개(11개×기호+이름)·측점 0 ⑤ **자료 공유 실측**: 유역도 배경 준비 8.5초(캐시 미스 2) → 계획평면도 1.3초(캐시 적중 2, 미스 증가 없음) — 두 번 읽지 않음 ⑥ 도면 목록에 `plan_terrain`·`plan_route`·`plan_layout` 3종이 실리고 빈 도각 목록에서 빠짐. - 계획 대비 차이: 측점 눈금을 노선 정점이 아니라 **종단 측점** 좌표로 찍도록 고침(정점 누가거리가 간격의 배수가 아니라 눈금이 2개만 찍혔음). - **실서버 확인(백엔드 재시작 뒤)**: 로그인된 공용 브라우저(5174)에서 세 장 모두 200 응답 — 지형 276개(등고선 180·세류선 10), 노선배치도 407개(+노선 1·측점 130), 배치도 299개(+구조물 22). 좌측 도면 목록에 네 개(라이다 포함) 버튼이 눌리는 상태로 뜸. ### B07 계획평면도(라이다) — 3D 탑뷰 그림 배치 (2026-09-04 1차 배치 완료, 사용자 확인 대기) 사용자 지시(2026-09-04) — 「라이다 계획평면도는 **3D 자료를 탑뷰에서 본 그림**이 필요함. 가능한 범위에서 일단 배치해 주면 보고 개선하겠음」. - **도면 틀이 그림을 받아 줌** — 도면 템플릿에 이미지 요소가 있어 PNG·JPG 를 그대로 실을 수 있음(SVG 만 벡터로 바꾸고 래스터는 이미지로 둠). - **가장 싼 길** — 이미 만들어 둔 **지표면 격자(DTM)로 음영기복 그림**을 서버에서 만들어 배경으로 까는 것. 점구름을 그대로 그리면 수천만 점이라 도면 만들기가 느려짐. - **자리는 빈 도면** — `blank_plan_lidar`. - [X] **탑뷰 그림 생성** — 지표면 격자로 음영기복 이미지를 만들어 도곽 범위에 맞춰 자름. - 확정 DTM 격자(`dtm_{필터}[_smooth].npz`)를 도곽으로 잘라 음영기복 PNG 생성(북서 315°·고도 45°, 한 변 최대 1,600 px). 어느 지표면을 쓸지는 1단계 확정값을 따름 — `DrainageContext` 에 `surface_params` 를 실어 전달. - [X] **도면에 배치** — 계획평면도와 같은 축척·도곽으로 그림을 얹고 노선을 그 위에 그림. - `Image` 엔티티(네 모서리 + data URL)로 실음. 축척·도곽·장 나눔은 계획평면도와 같음(1/1,200). - 곁들여 고친 것: `entities_bbox()` 가 꼭짓점 배열(`points`)을 세지 않아 그림이 도곽 계산에서 통째로 빠졌음 — 세도록 고침. - [X] **1차 배치 후 사용자 확인** — 보고 개선 방향을 받음(사용자 지시). ← **대기 중** - [X] **자체검증** — 그림이 도곽 안에 맞게 들어가는지, 좌표가 노선과 어긋나지 않는지(노선 양 끝 좌표로 대조), 도면 생성 시간이 크게 늘지 않는지. - 방법: `tmp/tests/test_b07_lidar_plan.py` (용화_LAS) + 생성된 PNG 를 직접 열어 눈으로 확인. - 결과 ① 콘텐츠 726.1 × 487.2 mm ≤ A1 작도영역 739.2 × 499.2 mm ② 그림 0~693 × 0~475.2 mm 안에 노선 80.4~605.5 × 151.9~327.6 mm 이 **완전히 들어감**(좌표 정합) ③ 음영기복 준비 0.4초, 그림 자료 214 KB — 점구름 4,900만 점을 그리는 것과 비교 불가하게 가벼움 ④ 능선·계곡이 눈으로 구분됨(첫 판 120~255 는 흐려 90~250 으로 대비를 올림). - 계획 대비 차이: 없음. 사용자 확인 후 개선 예정. - **실서버 확인**: 로그인된 공용 브라우저에서 200 응답, 엔티티 88개(음영기복 그림 1·노선 1·도각 84·표제 2). ### B07 용지도 — 등고선 배경 + 지적·행정구역 (2026-09-04 완료, 검증 대기) 사용자 지시(2026-09-04) — 「용지도는 계획평면도와 같이 **수치등고선을 배경**으로 하고 **연속지적도·시군구·읍면동**을 얹을 것. **색상은 변경**하고, 배수유역도의 표 자리에 **범례**를 넣을 것. 연속지적도에 **주소(지번) 정보가 있는지 확인**하고, 없으면 일단 그림만」. - **자료는 이미 프로젝트마다 내려받아 있음** — 연속지적도·행정구역 시군구·행정구역 읍면동을 GeoJSON 으로 저장함(`B04_PreProcess_Engine_GisVector.py` 의 VWorld 내려받기). - **배경은 계획평면도와 같은 것** — 위 항목의 배경 공용 창구를 그대로 씀. - **주소 정보 있음(2026-09-04 실제 파일로 확인)** — 저장된 연속지적도 GeoJSON 의 필지마다 속성 30개가 들어 있음. 쓸 만한 것은 **지번**(`jibun`, 예 「440전」)·**지목**(`jimok`)·**면적**(`parea`)·**소유 구분**(`owner_nm`)·**개별공시지가**(`jiga_ilp`)와 시도·시군구·읍면동·리 이름임(실측: 한 프로젝트 필지 952개, 경상북도 봉화군 춘양면 서벽리). 즉 **필지에 지번을 적을 수 있고, 용지 조서용 면적·지목·소유 구분까지 이미 확보돼 있음**. - **자리는 빈 도면** — `blank_landuse`. - [X] **지번 표기** — 필지에 지번을 적음(겹치면 솎고, 작은 필지는 지시선으로 뺌). 지목·면적·소유 구분은 이번 판 표기 대상에서 뺌(용지 조서용 값이라 도면에는 안 넣음). - 작은 필지는 **솎음**(종이 6×3 mm 미만이면 지번 생략). 지시선으로 빼는 것은 이번 판 미구현 — 실측 대상 프로젝트에 해당 필지가 없어 확인할 수 없었음. - **도곽을 통째로 감싸는 필지**를 따로 처리함 — 노선이 임야 대필지 안에 들어앉으면 경계선이 도곽 안에 하나도 없어 지번이 사라졌음(용화_LAS 실측: 노선 전체가 「산77-15임 일월면 용화리」 한 필지 안). 그 경우 도곽 중심에 지번만 적음. - [X] **도면 구성** — 등고선 배경 위에 연속지적도(필지 경계)·시군구·읍면동 경계를 얹음. - 축척·도곽·장 나눔은 계획평면도와 같음(1/1,200), 배경도 같은 창구. 지적·행정 경계는 도곽 범위로 절취 — 자르지 않으면 산지 대필지 하나가 도면을 10 km 로 벌렸음(실측 콘텐츠 8,368 mm). - [X] **색상 정리** — 지금 화면용 색과 다르게 도면용 색을 따로 정함(경계 굵기 포함). - 등고선 `#9aa3ad`(화면 `#6b7684` 보다 옅게) · 필지 `#8c6b4f` · 읍면동 `#2f7d4f`(파선 2px) · 시군구 `#a63d3d`(일점쇄선 3px) · 노선 `#ffe066`(3px). - [X] **범례** — 유역도의 표가 있던 자리에 범례를 넣음. - 오른쪽 칸 방위표 아래. 5줄(계획노선·필지 경계·읍면동·리 경계·시군구 경계·등고선) + 제목. - [X] **자체검증** — 도곽 안 배치·색 구분·범례 표기·좌표 정합(노선과 지적 경계가 어긋나지 않는지). - 방법: `tmp/tests/test_b07_landuse.py` (용화_LAS) — 실제 도면 생성 후 레이어별 개수·bbox·지번 대조. - 결과 ① 콘텐츠 734.3 × 489.2 mm ≤ A1 작도영역 739.2 × 499.2 mm ② 등고선 180줄 배경 + 노선 1줄 + 범례 11개 + 지번 1개 ③ 지번 「산77-15임」이 실제 지적 속성값과 일치 ④ 도면용 등고선 색이 화면용과 다름 ⑤ 도면 목록에 `landuse` 가 실리고 빈 도각 목록에서 빠짐. - 계획 대비 차이: **이 프로젝트에서는 필지·행정 경계선이 도곽 안에 하나도 없음** — 노선이 임야 대필지 한 곳에 통째로 들어가고 시군구·읍면동 경계는 도곽 밖임(실측: 지적 고리 198개 중 도곽에 걸치는 것 3개, 모두 3~7 km 짜리 산지 필지). 자료대로의 정상 결과이며, 경계가 지나는 노선에서 확인이 더 필요함. - **실서버 확인**: 로그인된 공용 브라우저에서 200 응답, 엔티티 279개(등고선 180·범례 11·지번 1·노선 1). > **표준도는 보류**(2026-09-04 사용자) — 빈 도면(`blank_standard`) 그대로 둠. 2026-09-04 기준 빈 도각으로 남은 도면은 이것 하나뿐임. ### B05·B06 종단 그래프 — 줌 버튼 단순화 (2026-09-04 예정) 사용자 지시(2026-09-04) — 「종단 그래프의 줌인·아웃이 마음에 안 듦. **버튼이 너무 많고 제어가 어려움. 버튼은 줌인·줌아웃**만 두고, 그래프의 자유도는 맡김. 대신 **하단 테이블과 그림이 연계**되어 있으니 조심할 것. **유토곡선도 보이는 창의 내용에 따라 Y 값이 바뀌게** 할 것」. 이어진 확정(2026-09-04) — 「유토곡선과 종단 그래프의 **기본값이자 최대값은 지금 상태**로 지정. 더 빽빽해지면 의미가 없음. **초기화 버튼은 유지**해 기본값으로 돌아가게 할 것」. - **지금은 버튼 7개** — 가로 `+`·`−`, 세로 `⇕+`·`⇕−`, 창 이동 `▲`·`▼`, 전체보기 `⤢`(`B05_Profile_UI_Profile_Zoom.ts`, 2026-09-04). 가로·세로·창 중심을 사람이 각각 맞춰야 해 손이 많이 감. - **연계 구조** — 그래프·측점 테이블·계획고 편집 버튼층·구조물 알약 레인 **넷이 같은 가로 좌표계**를 씀. 그래서 가로 확대는 SVG 를 늘리는 방식이 아니라 **캔버스 폭 자체를 키우는 방식**이어야 넷이 함께 늘어남(현재 방식이 그러함 — 유지). - **유토곡선은 이미 종단과 가로 스크롤이 묶여 있음** — 두 그림이 같은 구간을 봄. 다만 **Y 는 전 구간 최대 토량으로 고정**이라, 확대해도 곡선이 납작하게 눌림. - **종단 그래프의 Y 도 사실상 같은 문제** — 표시 표고창을 사람이 `⇕`·`▲▼` 로 맞추는 중임. **제안(사용자 요청 「가능한 방법」)** — **버튼 2개는 가로 배율만 맡고, 세로는 프로그램이 자동으로 맞춤.** - **줌인·줌아웃 = 가로 배율만** — 지금의 폭 배수 방식 그대로(한 칸 1.25배, 상한 8배). - **지금 상태가 기본값이자 축소 한계**(2026-09-04 사용자 확정) — 폭맞춤 상태(배율 1)보다 더 축소하지 못하게 막음. 더 줄이면 측점이 겹쳐 읽을 수 없어 의미가 없음. 즉 줌아웃은 배율 1 에서 멈추고 그때 버튼을 흐리게 함. - **초기화 버튼은 남김** — 기본값(배율 1·자동 Y)으로 한 번에 되돌림. 버튼은 **줌인·줌아웃·초기화 셋**. - **세로는 보이는 구간에 자동 맞춤** — 가로 스크롤 위치와 화면 폭으로 **지금 보이는 누가거리 구간**을 알 수 있음. 그 구간의 지반선·계획선 최저~최고에 위아래 10% 여유를 두어 Y 창을 잡음. 확대할수록 그 구간의 고저차가 화면 높이를 꽉 채우므로 `⇕+`·`⇕−`·`▲`·`▼` 네 버튼이 필요 없어짐. - **유토곡선도 같은 규칙** — 같은 구간의 누계 토량 최저~최고로 Y 를 잡음(지금은 전 구간 최대치 고정). 두 그림이 같은 스크롤을 쓰므로 창 계산은 한 벌이면 됨. - **보조 조작(선택)** — `Ctrl`+휠로 확대·축소, 그래프를 잡아끌어 좌우 이동. 버튼 2개는 그대로 두고 손에 익은 조작만 더하는 것이라 원하면 나중에 붙여도 됨. **조심할 것(미리 점검한 결과)** - **가로 방식은 바꾸지 않음** — 캔버스 폭을 키우는 지금 방식을 유지해야 테이블·편집 버튼·구조물 레인이 그래프와 같이 늘어남. SVG 변형으로 바꾸면 넷이 어긋남. - **세로는 그래프 영역만 바뀜** — 테이블에는 영향 없음. 다만 **스크롤할 때마다 축이 출렁이면 어지러움** → 스크롤이 멈춘 뒤 맞추고(짧은 지연), 눈금은 지금처럼 1·2·5 계열로 딱 떨어지게 스냅. - **편집 중에는 Y 고정** — 계획고를 끌어 올리는 동안 축까지 따라 움직이면 조작 감각이 깨짐. 손을 떼면 다시 맞춤. - **B06 종단은 카드 공통 Y 스케일을 씀** — 측점 카드끼리 높이를 견주려고 같은 축을 쓰는 중임. 자동 맞춤으로 바꾸면 그 비교가 깨질 수 있음 → **B06 은 자동 맞춤을 껐다 켤 수 있게 할지, B05 만 자동으로 둘지 사용자 확인**. - [X] **버튼 세 개로 줄이기** — 줌인·줌아웃·초기화만 남기고 세로 배율·창 이동 버튼 제거. - [X] **축소 한계 = 기본값** — 배율 1 아래로 안 내려가게 막고, 한계에 닿으면 버튼을 흐리게 표시. - [X] **세로 자동 맞춤** — 보이는 구간의 지반·계획선 범위 + 여유 10%, 스크롤이 멈춘 뒤(0.16초) 갱신, 눈금 스냅 유지. 창 계산은 공통 함수 한 벌(`windowElevationRange`)을 B05·B06 이 함께 씀. - [X] **편집 중 축 고정** — 계획고 편집 버튼을 누르고 있는 동안 Y 창을 붙잡고 손을 떼면 다시 맞춤. - [X] **유토곡선 Y 자동** — 같은 구간 기준으로 누계 토량 범위를 잡음(전 구간 ±200㎥ 고정 해제). - [X] **정렬 확인** — 가로 배율을 바꿔도 그래프·테이블·편집 버튼·구조물 레인의 측점 위치가 어긋나지 않음. - [X] **B06 적용 범위 확인** — 사용자 답(2026-09-04): 「공통으로 템플릿화」. B05·B06 종단이 **같은 규칙·같은 함수**로 자동 맞춤. 확인 결과 **카드 공통 Y 스케일 걱정은 근거가 없었음** — `calculateYScale` 이 먹이던 곳은 B06 **종단 하나뿐**이고 횡단 카드는 애초에 그 값을 안 씀. 그래서 그 함수는 지금 아무도 안 부름 (죽은 코드 정리 항목에 넘김 — 이번 차례 아님). - [X] **자체검증**(2026-09-04, 공용 브라우저 5174 · 프로젝트 **용화_LAS**, 사용자 지정) — 수치 판정. - ① 버튼 `+ · − · ⤢` 셋만 남음. 배율 1 에서 `−` 가 `disabled`(흐림) — 확대 뒤 풀리고 초기화하면 다시 죽음. **합격** - ② 보이는 구간의 지반·계획선이 그래프 높이의 **83.1~83.3%** 를 채움(여유 10%×2 를 뺀 이론값 83.3%). 배율 1·3배·스크롤 이동 어디서나 같은 값 — 눌리지 않음. **합격** - ③ 스크롤을 옮기면 Y 눈금이 그 구간 값으로 바뀜(860~880m → 835~842m → 830~834m). **합격** - ④ 같은 측점의 그래프 세로선과 편집 버튼 중심 x 차이 **0.5px**(버튼 폭 21px 의 절반 자리 보정값), 배율 2배에서도 0.5~0.52px 로 유지. 어긋남 없음. **합격** - ⑤ 유토곡선 Y 가 창을 따라감 — 전 구간(8.8 ~ −185.1㎥) → 확대(4.3 ~ −89.3) → 스크롤 이동 (−3,610 ~ −3,814). 전 구간 고정이던 이전과 달라짐. **합격** - ⑥ 계획고 ▲ 를 3초 누르는 동안 계획선은 움직였는데(첫 4점 y 16.08/17.48/18.87/20.27 → 16.08/17.02/17.95/18.88) **눈금은 그대로**(870m,880m). 손을 뗀 뒤 다시 맞춤. **합격** - ⑦ `⤢` 가 배율 1 로 되돌림(캔버스 폭 7145px → 4615px, `−` 다시 흐려짐). **합격** - B06(횡단설계 페이지) 종단도 같은 결과 — 채움 **83.3%**, 스크롤 시 눈금 840~850m → 830~834m, 유토곡선 Y 도 창을 따라감. **합격** - **계획 대비 차이** — (1) 보조 조작(Ctrl+휠·잡아끌기)은 「원하면 나중에」 항목이라 넣지 않음. (2) 유토곡선 Y 에서 **0선 강제 포함을 뺌** — 창 안 값만으로 잡아야 확대 효과가 나옴. (3) 검증 중 만든 계획선 초안은 지우고 새로고침해 **시험 전 상태로 되돌림**(초안 0건 확인). ### B03 파일 카드 미리보기 확대 — 한 행 전폭·모든 항목 표시 (2026-09-04 구현 완료 · 검증 대기) 사용자 지시(2026-09-04) — 「파일들의 정보를 구분하려고 **완료 시 그림**을 넣으려 함. 해당 요소의 **한 행을 전부** 쓰고 **높이는 적당히 고정**. **지금 없는 항목들도 최소한 뭐라도** 보여줄 것 — 자료를 보고 쉽게 표현할 수 있는 것을 그냥 넣을 것. **포인트 클라우드는 대충이라도**, 스냅샷을 찍는 셈. 나머지도 같음」. (지시에는 B02 로 적혔으나 B02 는 프로젝트 생성 폼뿐이고 **파일 카드는 B03**임 — B03 기준으로 잡음.) - **지금 상태** — 카드 미리보기는 2026-09-04 에 넣은 작은 SVG(100×60) 하나임(`B03_FileInput_UI_Preview.ts`). 지형 자료는 **범위 사각형만**, 계획노선은 솎은 선임. 부속 파일(`shx`·`dbf`·`cpg`·`prj`·`tfw`)은 그림이 아예 없음. - **라이다는 공짜에 가깝게 점 그림을 뽑을 수 있음** — 분석기가 분류 통계를 낼 때 이미 **전 점을 청크로 훑고 있음**(`analyze_las_metadata` 의 `chunk_iterator`). 그 지나가는 길에 **일정 간격으로 3~5천 점의 XY 만 주워** 두면 파일을 다시 읽지 않고 탑뷰 점 그림이 나옴. 분류가 없어 훑지 않는 파일만 한 번 더 읽는데, 이때는 **앞 몇 청크만** 보고 끝냄. - **GeoTIFF 는 조건부** — `rasterio` 로 이미 열고 있으므로 **저해상 축소 읽기**(128×128 안팎)로 흑백 썸네일을 만들 수 있음. 다만 오버뷰가 없는 큰 파일은 수 초가 걸릴 수 있어, **오버뷰가 있을 때만** 만들고 없으면 지금처럼 범위 사각형만 둠(사용자 제약 「오래 걸리면 안 됨」). - **부속 파일은 그림 대신 값** — 자료 성격상 그릴 도형이 없음. 좌표계 이름(`prj`·`route_prj`), 속성 개수·레코드 수(`dbf`), 인코딩(`cpg`), 픽셀 크기·회전 여부(`tfw`), 도형 개수(`shx`) 처럼 **한눈에 구분되는 값 한두 개**를 큰 글씨로 보여 줌. - [X] **자리·크기** — 미리보기가 카드 한 행 전폭, 높이 120px 고정. - [X] **라이다 점 그림** — 분류 통계를 훑는 그 길에 XY 를 성기게 주움(상한 5천 점, 1m 눈금 정수, 파일 재열람 없음). 분류가 없는 파일은 앞 3청크만 봄. - [X] **GeoTIFF 썸네일** — 오버뷰가 있을 때만 128×128 흑백 PNG(2~98 백분위로 대비), 없으면 범위 사각형 유지. - [X] **부속 파일 값 표시** — `.shx` 도형 수, `.dbf` 레코드·속성 수, `.cpg` 인코딩, `.prj` 좌표계 이름+EPSG, `.tfw` 픽셀 크기·회전 여부. 값 읽기용 가벼운 분석기(dbf·shx·cpg)를 새로 둠(머리글만 읽음). - [X] **완료 상태에서만** — 업로드·분석이 끝난 카드에만 보이고, 값이 없으면 「보여 줄 값이 없음」 한 줄. - [X] **자체검증 (2026-09-04, 검증 대기)** — 공용 브라우저(5173) · 프로젝트 `용화_LAS` 실측 + 단위 시험. - 결과 ① 카드 9장 모두 미리보기 폭 308px(카드 343px 안쪽 여백 뺀 전폭)·높이 **120px 고정**. - 결과 ② 라이다 카드에 점 5,000개가 그려지고, 표본 400점이 **100%** 자기 범위 사각형 안에 들어옴(툴팁 「점 5,000개 (솎은 탑뷰)」). - 결과 ③ 4,900만 점 LAS 분석: 분류 통계만 **2.96s** → 점 수집 포함 **3.56s**(+0.61s, 한 번 훑기 그대로). GeoTIFF 썸네일 **0.1s**(13.6KB), 부속 파일 각 0.0~0.4s. - 결과 ④ 부속 파일 카드가 각각 「도형 1개」·「레코드 1개 / 속성 2개」·「인코딩 949」·「Korean 1985 / Modified East Belt (EPSG:5176)」·「픽셀 0.2×0.2 m / 회전 없음」을 보임 — 빈칸 없음. - 계획 대비 차이 — 기존 업로드분은 옛 메타데이터라 미리보기 재료가 없어, 검증용으로 `용화_LAS` 입력 파일의 메타데이터를 다시 분석해 **새 키만 병합**했음(재업로드하면 같은 값). 다른 프로젝트는 다시 올릴 때 채워짐.