Commit Graph
218 Commits
Author SHA1 Message Date
eomsangdonandClaude Opus 5 269ec3e213 feat(B04,B05): 2D 지도 휠 줌 방향 반전 — 당기면 확대, 밀면 축소
B04 2D 지도와 B05 배수유역도의 휠 판정을 deltaY > 0 기준으로 바꿨다.
커서 아래 지점을 고정하는 offset 보정은 그대로다. 3D 뷰어는 손대지 않았다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-02 01:13:24 +09:00
eomsangdonandClaude Opus 5 b3ab6028cd fix(B05): 측점 하이라이트가 표 값을 가리던 문제 + 계획고 추가 강조 제거
하이라이트 열이 덮는 자리의 규칙 측점 값 셀을 통째로 숨겨(hideCoveredCells),
비정규 측점을 고를 때마다 좌우 최대 2개 열의 값이 사라졌다. 표는 그대로 두고
선택된 값만 위에 얹도록 그 함수와 .is-covered 규칙을 걷어냈다.

하이라이트 열에서 계획고만 자주색 테두리·글자색으로 따로 강조되던 것도 없앴다.
평상시에는 다른 셀과 같은 모습이고, 고칠 수 있다는 표시는 hover·focus에서만
나타난다. 직접 입력 기능은 그대로다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-02 01:07:14 +09:00
eomsangdonandClaude Opus 5 a0e6289e8f fix(B05): 관을 옮겨도 옛 자리 구조물 세로선이 남던 문제
구조물 측점이 두 곳에 있었다. 화면 정본인 사이드바 목록과, 경로 확정 때 종단
정본 파일에 병합된 kind="irregular" 측점이다. 그래프와 3D가 둘을 겹쳐 그려서
관을 옮기면 사이드바 목록만 따라가고 확정 당시 자리는 그대로 남았다.

그래프(_UI_Profile_Panel.draw)와 3D(_UI_Page.renderStationLines) 모두 종단
정본의 비정규 측점을 걷어내고 사이드바 목록만 얹는다. 저장분은 진입 시
restoreSections가 목록으로 되살리고, 관 항목은 배수유역도가 정본
(pipe_points.json)에 맞춰 갈아 끼운다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-02 00:58:55 +09:00
eomsangdonandClaude Opus 5 d9e8125e4c fix(B05): 손으로 넣은 "배관" 처리 통일 + 첫 진입 시 배수유역도 공백
1) 사이드바 폼으로 이름을 "배관"이라 적어 넣은 항목은 origin이 "user"라 [초기화]로
   지워지지 않고 배수유역도와도 어긋난 채 남았다. isPipeStation()(origin이 pipe이거나
   이름이 "배관")으로 판정을 통일해 목록 교체·이동·삭제·선택 동기화가 같은 규칙을 쓴다.

2) 대시보드에서 곧장 B05로 들어오면 배수유역도가 비어 보이고 새로고침해야 나왔다.
   패널이 배치되기 전(0×0)에 fitToRoute()가 돌아 엉뚱한 배율이 굳은 것이다. 크기가
   2px 미만이면 맞춤을 미뤘다가 첫 배치 때 다시 맞춘다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-02 00:48:05 +09:00
eomsangdonandClaude Opus 5 a58fac58d0 fix(B05): 초기화가 저장된 관 지점을 남기던 문제
[초기화]가 화면 목록만 자동 배치로 되돌리고 edits/pipe_points.json은 그대로 두어,
페이지를 다시 열면 옛 관이 살아났다. B04와 같은 파일을 보므로 B04에도 그대로 남았다.

- DELETE /{project_id}/drainage/pipe-points 신설: 저장분과 파생물
  (04_detailed_basins.geojson)까지 지우고 자동 배치 결과를 돌려준다.
- clear_pipe_points() 헬퍼 추가.
- B05 [초기화] 버튼이 이 경로를 쓴다.
- loadSaved / analyze / resetPipes가 같은 뼈대를 반복해 run() 하나로 묶었다.

검증: 초기화 전 {user:1, stream:1, spacing:2} → 초기화 후 {stream:1, spacing:3},
두 파일 삭제 확인, 재조회도 같은 자동 배치.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-02 00:38:24 +09:00
eomsangdonandClaude Opus 5 9cd70a14dc fix(B05): 배수유역 영역 클릭 선택이 안 되던 문제
pointerdown에서 유역 고르기 후보(basinClickStart)를 기억하는 코드가 실제로는 들어가
있지 않아, pointerup의 후보가 늘 null이었고 pickBasinAt()이 한 번도 불리지 않았다.
같은 편집에 묶여 있던 좌클릭 전용 제한도 함께 빠져 있어 우클릭·가운데 클릭으로도
마커가 잡히고 있었다.

- 좌클릭일 때만 pipeEditor.handleDown()을 부르고, 잡았으면 pipeClickStart로 기록
- 마커를 못 잡은 좌클릭은 basinClickStart로 남겨 뗄 때 유역을 고른다
- 700줄 유지: basinIndexOfPipe()를 _Drainage_Parts.ts로 이동

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-02 00:32:06 +09:00
eomsangdonandClaude Opus 5 0fb656ce49 fix(B04): 집중유역 오버레이를 최상단으로
집중점 마커와 유입 외곽선이 세부유역 채움·관 마커 아래에 깔려, 켜도 무엇을 고른
것인지 보이지 않았다. 강도 색칠은 그대로 두고 마커·외곽선만 떼어 맨 마지막에 그린다.

- FlowStrengthOverlay.draw(): 계획선 강도 색칠만
- FlowStrengthOverlay.drawTop(): 집중점 마커 + 선택한 지점의 유입 셀 외곽선
- MapViewer 그리기 순서: 배수유역 오버레이 → 계획선 → 강도 색칠 → 세부유역·관 마커
  → 집중유역

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-02 00:25:53 +09:00
eomsangdonandClaude Opus 5 bb0499d6d7 fix(B05): 배수유역도 패널 크기를 바꿔도 지도 배율을 그대로 둔다
하단 패널이나 우측 배수유역 패널을 늘리면 computeMapRect()가 지도를 뷰포트에 다시
맞춰(contain) 지도까지 함께 확대됐다. 배율이 바뀌니 방금 보던 자리를 다시 찾아야 했다.

화면 변환 계수(ax·bx)가 그대로가 되도록 배율·오프셋을 되계산해, 늘린 만큼은 확대가
아니라 더 넓은 범위로 채운다.

- preserveViewOnResize(): 이전 프레임의 변환 계수를 새 뷰포트에서 재현
- observeViewportSize(): 크기 변화를 지켜보며 위 보정을 걸고 다시 그린다
- 700줄 유지를 위해 fitCanvasToViewport / createProgressReporter / pipeMarkerColor도
  _Drainage_Parts.ts로 이동

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-02 00:18:55 +09:00
eomsangdonandClaude Opus 5 32fd199dbf feat(B04/B05): 흐름 강도 범례 + 배관 라벨 가독성 + 선택 3자 동기화
- 흐름 강도 색띠 범례를 지도 우측에 세로로 세운다(B04 2D 지도·B05 배수유역도 공용).
  색은 화면과 같은 색띠를, 눈금은 같은 로그 정규화를 되돌려 적는다. 제목 "흐름강도".
- 배관 누가거리 라벨에 흰 테두리를 깔았다. --map-* 토큰은 다크 테마에서 바뀌지 않아
  색만으로는 위성사진·다크 배경에서 묻힌다.
- 배수유역 영역 · 종단 그래프 세로선 · 좌측 구조물 폼 · 3D 마커의 선택이 서로를
  갱신한다. B05_wf2_Route_UI_Selection.ts로 경로를 한곳에 모으고 isSyncing 가드로
  재진입을 막았다. 유역 강조는 origin === "pipe" 항목에만 붙는다.

700줄 규칙 유지를 위한 분리
- B04_wf1_Surface_UI_MapOverlays.ts 신설(유역 채움·번호 배지·분수령·상류 세류망)
- reconcilePipes / fetchDrainageLayers / fitViewToRoute → _Drainage_Parts.ts

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-02 00:14:37 +09:00
eomsangdonandClaude Opus 5 a7f09a827e fix(B04/B05): 세부유역 서클 번호를 최상단 오버레이로
채움과 함께 그리던 번호가 등고선·흐름 화살표·관 마커에 가려 읽히지 않았다.
번호만 떼어내 프레임 맨 마지막에 얹는다.

- MapRender에 drawRingBadge()·ringCenterOnScreen()을 분리 노출.
  drawFilledRing은 라벨이 있을 때 drawRingBadge를 부르는 형태로 바뀐다.
- B04: drawBasinNumbers() 호출을 관 마커 뒤로 이동(관이 없어도 번호는 그린다).
- B05: 채움은 라벨 없이 그리고 배지 자리만 모아 두었다가 배관 마커 뒤에 그린다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-02 00:00:44 +09:00
eomsangdonandClaude Opus 5 6d13b3b781 refactor(B05): 배관 추가·삭제 우클릭 메뉴를 종단 그래프로 이동
구조물 조작이 테이블과 그래프로 나뉘어 있었다. 이동은 그래프 측점선, 추가·삭제는
테이블이라 어디서 무엇을 하는지 알기 어려웠다. 메뉴를 그래프 칸으로 옮겨 셋을 한
자리에 모은다. 테이블은 값만 보여 준다.

- mountStructureMenu의 부착 대상을 테이블 → 그래프 칸(.b05-profile__chart)으로 교체
- ProfileTableOptions.structureLines 제거
- CSS 블록명 b05-profile-table__context-menu → b05-profile-chart__context-menu

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-01 23:57:40 +09:00
eomsangdonandClaude Opus 5 c141ad4ef8 refactor(B05): 구조물 조작을 종단 그래프 측점선으로 이동
- 테이블에 얹던 구조물 세로선을 걷어냈다. 위치는 그래프 측점선이 이미 보여 주므로
  같은 것을 두 번 그리는 셈이었다. 테이블에는 우클릭 메뉴만 남는다
  (가까운 구조물이 있으면 삭제, 없으면 배관 추가).
- 드래그는 종단 그래프의 구조물 측점선에서 한다. createLongitudinalProfile에
  onDragStation을 추가하고 kind === "irregular" 측점선에만 붙였다(좌클릭 전용).
- 좌측 구조물 폼에서 "배관" 항목을 고치거나 지우면 그래프와 배수유역도가 함께
  갱신된다. DrainagePanel.setPipeChainages() 신설.
  reconcilePipes()가 목록이 같으면 null을 돌려 관↔구조물 순환을 끊는다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-01 23:52:17 +09:00
eomsangdon 6147a9a2fd auto: 2026-08-01 23:37 (ESD_LAPTOP) 2026-08-01 23:37:27 +09:00
eomsangdonandClaude Opus 5 b023698e38 refactor(B04/B05): 배수유역 저장소·API 일원화 + 종단 테이블 구조물 라인 연동
데이터 흐름 문제
- B04 해석 산출물 7개(7.2MB)가 B05로 전량 복사되고 있었고, 관 지점 정본
  (pipe_points.json)은 B05가 아예 참조하지 않았다. B04에서 확정한 관이 B05에
  보이지 않고 진입할 때마다 자동 배치로 되돌아갔다.
- 사본은 "B05 편집이 원본을 덮어쓴다"를 막으려던 것인데, 외곽선 편집을 제거한
  뒤로 B05는 아무것도 저장하지 않아 존재 이유가 사라졌다.

일원화
- B05 전용 모듈 3개 삭제: Engine_Drainage_Store / Engine_Drainage_Basin /
  Router_Drainage. 두 화면이 B04_wf1_Surface/drainage/ 한 폴더를 직접 읽는다.
- POST /drainage/basins 폐기 → GET/PUT /drainage/pipe-points ·
  POST /drainage/detail-basins 한 벌로 통합. 응답에 route_lonlat ·
  main_polygon_lonlat · flow_arrows · upstream_lonlat · inflow_hotspots를 추가해
  B05가 그리는 데 필요한 값을 같은 응답으로 받는다.
- 경로 확정 시 관 지점을 B04와 같은 저장소에 커밋한다.

B05 화면
- 유역 폴리곤을 눌러 고르기(지도에서도 선택), [집중유역] 토글, 관 개수·유역 수·
  종단 Z 출처 요약 줄 추가.
- 관 마커는 좌클릭으로만 잡는다(우클릭은 메뉴, 가운데 버튼은 팬).
- 유역 목록은 3행까지 보이고 나머지는 스크롤.

종단 테이블 구조물 라인
- 관 매설 지점을 "배관" 구조물로 실체화(origin: "pipe"). 정본은 관 지점 파일이며
  목록은 그 투영이라, 어디서 옮기든 pipeEditor 한 경로로 전파된다.
- 테이블 위 세로선을 끌어 이동(배관은 세부유역까지 재산정), 우클릭으로 배관
  추가/구조물 삭제.

정리
- B05_wf2_Route/drainage/ 사본과 debug/(삭제된 Subdivide 엔진 검증 스크립트) 삭제.
- config DRAINAGE_B05_DIRNAME 제거.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-01 23:37:17 +09:00
eomsangdonandClaude Opus 5 e994330874 refactor(B05): 유역 외곽선 편집 기능 제거
등고선을 전부 해석해 얻은 경계라 사람이 다시 그릴 이유가 없다(2026-08-01 사용자 지시).
남겨 두면 손으로 옮긴 외곽선과 1m 셀 라벨로 만든 세부유역이 어긋나 면적·관경의 근거가
깨진다. 외곽선은 이제 해석 결과를 그대로 표시만 한다.

제거 대상
- B05_wf2_Route_UI_Drainage_Boundary.ts (핸들 편집기)
- "유역선 편집" 버튼과 경로 확정 시 저장 여부 모달
- PUT /{project_id}/drainage/boundary 엔드포인트
- boundary_overrides 로드·저장·재부착 로직과 resample_boundary
- DRAINAGE_BOUNDARY_OVERRIDE_FILENAME / _HANDLE_SPACING_M / _MATCH_RADIUS_M

B05 저장소 모듈은 B04 산출물 사본 동기화만 남겨 245줄 → 55줄로 줄었다.
이미 저장돼 있던 boundary_overrides.json은 지우지 않았다(사용자 데이터라 그대로 둔다).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-01 22:46:34 +09:00
eomsangdonandClaude Opus 5 8c37f2f6f3 feat(B04/B05): 유역 선택 강조, B05 배관 상시 드래그·자동 재산정, 강도 색칠 공용화
B04
- 세부유역을 눌러 고르면 그 유역만 진하게, 나머지는 옅게 물러난다. 관 마커를
  눌러도 그 관이 받는 유역이 골라지고, 유역 밖을 누르면 강조가 풀린다.
- 고른 유역의 제원(측점·면적·표고차·유하장)을 상태 줄에 표기한다.

B05
- "배관 편집" 토글을 없애고 마커를 언제나 끌 수 있게 했다. 계획선을 그냥 누르는
  것으로는 배관이 생기지 않는다 — 유역을 고르려 할 때마다 배관이 생기기 때문이다.
  추가·삭제는 B04와 같은 우클릭 메뉴로 옮겼다.
- 배관을 옮기거나 넣거나 지우면 세부유역을 즉시 다시 나눈다(격자 해석 없음).
- "자동 제안" 버튼 이름을 "초기화"로 바꿨다.
- 노선 유입 강도 색칠을 B04 지도와 같은 색띠로 추가했다(토글 포함).

공용화
- common_util_drainage_detail: 1m 구간별 유입 면적 곡선을 응답에 포함(B04·B05 동일).
- B04_wf1_Surface_UI_FlowRamp.ts: 색띠·정규화·강도선 렌더러를 두 화면이 공유.
- ui_template_context_menu.ts: 지도 우클릭 메뉴를 공용 부품으로 분리.
- B05_wf2_Route_UI_Drainage_Parts.ts 신설로 패널을 700줄 규칙 안으로 되돌림(677줄).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-01 22:36:02 +09:00
eomsangdonandClaude Opus 5 83f23aa43f fix(B04): 우클릭 메뉴 동작 복구 + 배수유역 토글 정리, 세부유역 서클 번호
- 관 매설 추가·삭제가 안 되던 원인 수정: 메뉴 항목을 누를 때 pointerdown이
  뷰포트로 전파돼 메뉴가 먼저 닫히면서 click이 발생하지 않았다. 메뉴 안에서 난
  pointerdown/pointerup/contextmenu는 지도 조작에서 제외한다.
- 관 매설·세부유역 토글을 "세부유역" 하나로 합쳤다(따로 끄면 관을 옮겨도 유역이
  보이지 않아 판단할 수 없다).
- 유입 집중점 마커를 흐름 강도 색칠에서 떼어 "집중유역" 전용 토글로 옮기고
  기본을 꺼짐으로 두었다. 끄면 골라 둔 유입 외곽선도 함께 걷는다.
- 세부유역마다 서클 번호를 폴리곤 면적 중심에 얹었다(시점에서 종점 순).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-01 22:04:29 +09:00
eomsangdonandClaude Opus 5 07c4a7897c feat(B04): 상세 배수유역 계산 — 관 매설 지점 편집 + 세부유역 분할
관 매설 지점을 기준으로 세부 배수유역을 나누는 기능을 B04 2D 지도에 추가한다.
경계는 B04 전처리 격자(03_road_routing.npz)의 road_slot — 1m 셀마다 물이 도달하는
도로 셀 — 을 담당 관으로 라벨링해 그 경계로 잡는다. 종단 Z는 경계를 긋지 않고
"도로 셀이 어느 관으로 흐르는가"만 정한다.

공용 승격 (B04 관리자 화면과 B05 사용자 화면이 같은 결과를 내야 함)
- common_util_drainage_detail.py: 관 보충(9)·세부유역 분할(10) 알고리즘
- common_util_drainage_context.py: 노선·종단 Z·좌표계 입력 준비
- common_util_drainage_pipes.py: 관 지점 정본 저장소(edits/pipe_points.json)
- common_util_route_profile.py: 종단 Z 해석기(계획고 > 경로 정점 > 지표면 > CSV)
- common_util_surface_sampler.py: B05 종횡단 sampler 이동
- B05 _prepare()의 노선 소스를 원청 계획노선 CSV로 정정(B04 격자와 누가거리 정합)

B04 신규 API
- GET  /{project_id}/drainage/pipe-points   저장분 조회(없으면 자동 생성)
- POST /{project_id}/drainage/detail-basins 편집 중 목록으로 재분할(저장 안 함)
- PUT  /{project_id}/drainage/pipe-points   모델 확정 시 관 지점·세부유역 커밋

B04 화면
- 관 마커 기본/자동/수동 색 구분, 계획선 스냅 드래그 이동
- 계획선 우클릭 "관 매설 추가" / 마커 우클릭 "관 매설 삭제"
- 표시 토글 2그룹(관 매설 / 세부 유역)을 유입 집중점과 분리
- "상세유역 분석" 버튼을 눌렀을 때만 재계산

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-01 21:48:28 +09:00
eomsangdonandClaude Opus 5 9fb24c1ce6 fix(공통): 테마에 없던 --spacing-12를 정의 — 절대 위치 라벨이 좌상단에 겹치던 원인
간격 토큰이 4·8·16·24…만 있고 12가 없었다. CSS는 정의되지 않은 변수를 만나면 그 선언을
통째로 버리므로, `right: var(--spacing-12)` / `bottom: var(--spacing-12)`가 auto가 되어
절대 위치 요소가 offset 없이 원래 흐름 자리(좌상단)에 놓였다. B04 2D 지도의 객체 개수·
유역 결과·분석 진행 라벨 셋이 좌상단에 겹쳐 보이던 것이 이 때문이다.

- ui_template_theme.css에 --spacing-12: 12px를 정의한다(값의 유일한 정의처).
- 이 변수는 A07·B03·B04·B07·B11 등 10개 파일 31곳에서 쓰이고 있었고 그 선언이 전부
  조용히 버려지고 있었다(패딩·간격이 0). 일부 파일에 남아 있던
  `var(--spacing-12, var(--spacing-8))` 우회는 이 문제를 앞서 겪은 흔적이다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-01 17:07:11 +09:00
eomsangdonandClaude Opus 5 b3d9282869 fix(공통): 앱 종료 시 프론트엔드 개발 서버도 함께 내리고 포트를 고정
지금까지 main.py는 Vite를 띄우기만 하고 종료를 시키지 않았다. 서버를 다시 띄울 때마다
이전 Vite가 살아남고, 포트가 차 있으면 Vite가 조용히 옆 포트로 올라갔다. 그래서 오늘
5173~5190에 13개가 쌓였고, 사용자가 오전에 뜬 인스턴스를 보는 바람에 하루치 변경이
화면에 반영되지 않은 것처럼 보였다.

- 종료 시 stop_frontend_dev()로 개발 서버 계통을 통째로 끝낸다. shell=True로 띄우면
  실제 계통이 cmd.exe -> npm -> node라 부모만 죽이면 node가 남는다. Windows는
  taskkill /T /F, POSIX는 프로세스 그룹으로 처리한다.
- 개발 서버 포트를 FRONTEND_DEV_PORT(기본 5173)로 고정한다(--strictPort). 포트가 막혀
  있으면 조용히 옮겨가지 않고 그 자리에서 드러난다.
- 기동 전에 그 포트를 물고 있는 잔여 프로세스를 정리한다. 앞선 실행이 강제 종료됐을 때를
  대비한 청소이며, 이게 없으면 --strictPort 때문에 기동이 실패한다.

실기동 검증: 기동 시 5173/8000만 뜸 -> API만 강제 종료해 고아 Vite를 만든 뒤 재기동하니
"포트 5173를 물고 있던 잔여 프로세스 30736 정리" 로그와 함께 5173을 회수했다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-01 16:57:50 +09:00
eomsangdonandClaude Opus 5 2375a2f3ba feat(B04): 배수유역 진행 문구를 지도 우상단 전용 줄로 분리
한 줄을 결과와 같이 쓰다 보니 분석을 돌릴 때마다 직전 결과가 지워졌다. 진행 문구는
우상단, 결과는 좌상단에 남겨 둘 다 동시에 읽을 수 있게 했다(2026-08-01 사용자 지시).

- WatershedOverlay에 busyElement(진행 전용)를 추가하고 sayBusy()로 갱신한다.
  결과·오류는 종전대로 statusElement(좌상단)에 쓴다.
- 분석이 끝나면 진행 문구를 거둔다.
- 지도에 .b04-map__status-topright 자리를 신설했다. 객체 개수는 우하단
  (.b04-map__status-corner), 유역 결과·흐름 강도 요약은 좌상단 그대로다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-01 16:57:16 +09:00
eomsangdonandClaude Opus 5 d5d97547f5 feat(B04): 유입 집중점에 세류 교차점(기본 관) 자리 추가
세류가 도로를 가로지르는 자리가 대개 그 노선에서 가장 큰 유역을 받는데, 그 자리는
구역 경계라 구역별 선정 규칙으로는 영영 뽑히지 않았다. 실측 프로젝트에서 전체 유역의
89%(409,210㎡)를 받는 지점이 마커에서 빠져 있었다.

- 기본 관마다 관 ±최소간격 안에서 강도가 가장 큰 칸을 집중점으로 넣는다. 관 누가거리를
  그대로 쓰지 않는 이유는 도로를 폭 4m로 굽는 과정에서 실제 유입 봉우리가 관에서 두어
  걸음 옆에 놓이기 때문이다(관 149.73m, 봉우리 152m).
- 이 항목은 구역 번호 -1로 구분한다. 구역별 보충 후보 선정 규칙은 그대로 둔다.
- 관 자리와 같은 칸이 구역 쪽에서 다시 뽑혀 마커가 겹치는 것만 막았다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-01 16:27:23 +09:00
eomsangdonandClaude Opus 5 4d9f8db33d feat(B04): 도로 유입 흐름 강도 표시 + 유입 집중점 마커, 사이드 패널 컨테이너 정리
흐름 강도 계산은 이미 trace_flow()가 원본 1m 격자에서 하고 있었고 03_road_routing.npz에
저장까지 되어 있었다. 이번 작업은 그 원본값을 밖으로 꺼내 화면에 그리는 것이다.

- 강도 곡선 출력 간격을 5m -> 1m로 바꿔 계산 원본을 그대로 내보낸다(구간 합, 평균 아님).
  구간 기준을 round -> floor로 바로잡았다. 도로 셀 누가거리가 전부 0.5 배수라
  numpy의 짝수 반올림이 짝수 칸에 3배를 몰아 2m 주기 빗살을 만들고 있었다
  (도로가 격자축과 나란한 구간은 홀수 칸이 전부 0이라 색이 점선으로 나왔다).
- find_inflow_hotspots(): 도로를 시점·기본 관(세류 교차)·종점으로 잘라 구역을 만들고
  구역마다 floor(길이 / 관 최대간격) + 3개를 뽑는다. 강도 최대점부터 고르되 고른 지점
  양 편측으로 관 최소간격만큼을 후보에서 빼 한쪽 쏠림을 막는다. 관 쪽 경계에서도 같은
  거리만큼 물러난다 - 그러지 않으면 그 관이 이미 받는 물 전부가 관 옆 칸에서 다시
  최대값으로 잡혀, 정작 관이 없어 보충이 필요한 자리가 뽑히지 못한다.
- GET /api/projects/{id}/drainage/road-inflow 신설(B04_wf1_Surface_Router_Inflow.py).
  저장된 road_slot으로 그 1m 구간에 귀속된 셀 마스크를 만들어 외곽선만 돌려준다.
  새 그래프 탐색 없음. npz는 mtime 키로 프로세스 캐시에 둔다.
- 응답에 schema_version을 넣어 형식이 바뀌면 옛 저장분을 무시하고 다시 계산하게 했다.
- 프론트: B04_wf1_Surface_UI_FlowStrength.ts 신설. 계획선 위에 1m 구간 로그 레인보우와
  유입 집중점 마커(크기=강도, 번호)를 얹고, 마커를 고르면 기여 셀 외곽선을 겹쳐 그린다.
  마커 안쪽만 선택 대상이며 팬은 가운데 버튼 전용이라는 규칙은 그대로 둔다.
  좌표 변환은 MapRender에 모았다(normalizedToScreen / lonLatToScreen / metricToScreen).
- 사이드 패널: 지면 필터·서피스·스무딩을 "지표면 분석" 한 컨테이너로 모으고 스무딩을
  드롭다운(적용/미적용)으로 바꿨다. 포인트·모델 표시 옵션은 "모델 표시 옵션" 하나로
  합치고 맨 아래에 점 크기·밀도를 [값][게이지] 형태로 놓았다.
- DRAINAGE_ROAD_WIDTH_M 주석에 설계 도로폭이 아니라 D8 대각 통과를 막는 해석용 굽기
  폭임을 명시했다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-01 16:16:15 +09:00
eomsangdonandClaude Opus 5 d14222242a refactor(B04/B05/공통): 지도 색상 토큰화, 배수유역 패널 i18n, 소개 페이지 단계명 통일
- ui_template_theme.css에 2D 지도 벡터 팔레트(--map-*) 33종을 유일한 정의처로 등록하고,
  캔버스에서 CSS 변수를 읽는 공통 유틸 ui_template_palette.ts(themeColor)를 신설.
  값은 한 번만 읽어 캐시하고 data-theme 변경 시 비운다(다크 전환 대응).
- B04 지도·유역 오버레이·흐름 화살표와 B05 배수유역도·유역선 편집·배관 마커의
  하드코딩 색상을 전부 토큰 조회로 교체. 계획선 색·굵기, 후광색은 공용 함수로 일원화.
- B05 배수유역 패널의 사용자 문구를 전부 ui_locales로 이관(제목, 레이어 토글 5종,
  도구 버튼 5종, 툴팁, 상태 문구 8종, 유역 제원 표기). B04 유역 분석 오버레이의
  버튼·갈래 토글·진행/실패 안내도 함께 전환. 관리자 진단용 결과 판독문은 원문 유지.
- A02 프로그램 소개의 6단계 제목과 A01 히어로 문구의 단계 나열을 진행단계 이름
  (전처리/종단설계/횡단설계/상세설계/수량산출/설계도서)과 일치시킴.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-01 14:35:42 +09:00
eomsangdonandClaude Opus 5 9b6547a418 feat(B04/B05/공통): 7단계 명칭 통일, B05 패널 드래그 리사이즈, B04 계획선 레이어, 2D 지도 좌드래그 팬 제거
- 진행단계 오버레이 버튼과 B그룹 페이지 제목을 파일입력/전처리/종단설계/횡단설계/
  상세설계/수량산출/설계도서로 통일(ko/en). i18n 키는 유지하고 값만 교체.
  B05 페이지 제목의 하드코딩 문구를 locale 참조로 교체.
- ui_template_resizer 공통 스플리터 신설. B05 하단 종단 패널은 위쪽 경계를 끌어
  높이 조절(늘어난 만큼 그래프만 신축, 도면 테이블 높이는 고정), 안쪽 우측
  배수유역 패널은 왼쪽 경계를 끌어 폭 조절(상한 = 하단 패널 폭의 70%).
  크기는 sessionStorage에만 저장하고 CSS 변수로 적용해 접기 규칙과 충돌하지 않게 함.
- B04 2D 지도에 계획선 레이어 추가. 계획노선 좌표를 주는
  GET /api/projects/{id}/planned-route 신설(B03 업로드 CSV → 사업지 좌표계 m).
  선 색·굵기는 MapRender에 상수로 두고 B05 배수유역도와 공유.
- B04 지도 오버레이 재배치: 객체 표시 라벨은 우측 최하단, 배수유역 정보는 좌측 최상단.
- B04 지도·B05 배수유역도에서 좌버튼 드래그 팬 제거(가운데 버튼 전용).
  유역선 핸들·배관 마커 편집은 좌버튼 그대로 유지, 팬 중에만 grabbing 커서.
- B05 배수유역도에 위성사진 표시 토글 추가(등고선 앞, 기본 on).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-01 14:05:58 +09:00
eomsangdon ec873c6c0e merge: feature/B07-상세설계-기능-개발 → main (B04/B05 지도·배수유역 개선, B11 자료 준비 화면, 3D 조작감·성능 개선) 2026-08-01 13:17:47 +09:00
eomsangdonandClaude Opus 5 85eda04a8e feat(B04/B05): 지도 초기 화면을 도로 중심 + 여유 200m로 통일
B04 하단 지도와 B05 배수유역도가 같은 규칙으로 열린다 — 계획도로 중심을 화면 중앙에
두고 도로 전체 + 사방 200m가 보이는 배율(2026-08-01 사용자 지시).

- computeRouteView()를 공용 렌더 엔진(B04_wf1_Surface_UI_MapRender)에 두어 두 화면이
  같은 정의를 쓴다. 여유 거리는 ROUTE_VIEW_MARGIN_M 한 곳에서 정의.
- B04는 도로 범위를 알 방법이 없어 GET /surface/confirmed 응답에 route_bounds를 추가
  (B03 계획노선 CSV 범위를 프로젝트 좌표계로 변환). 노선이 없으면 배경 전체 보기로 폴백.
- B05는 기존 상대 배율(0.85배) 대신 같은 함수를 쓴다.
- 표본 실측: 노선 239x166m -> 여유 포함 639x566m가 화면에 들어온다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-01 13:08:11 +09:00
eomsangdonandClaude Opus 5 306268b616 feat(B04/B05): 지도 레이어 기본 표시값 정의 + 명칭 정리
2026-08-01 사용자 지정 기본값을 한곳(BACKGROUND_DEFAULT_ON / GIS_DEFAULT_ON /
CONTOUR_LABEL_DEFAULT_ON)에 모아 정의한다.

- 켜짐: 백지도, 위성, 시군구, 읍면동, 세류(전체)
- 꺼짐: 하이브리드, 연속지적도, 등고선, 도엽등고선, 표고점, 성절토, 옹벽석축, 등고라벨
- 유수방향 레이어는 화면에서 제외(목록에서 삭제)
- 명칭: 세류(하천중심선) -> 세류(전체), 배수유역 재산정 -> 유역 분석
- 유역 갈래 기본값(1차 꺼짐 / 2차 켜짐 / 유역방향 꺼짐 / 평균흐름 켜짐)은 기존과 동일
- B05 배수유역도 초기 보기는 도로 기준 줌인으로 되돌림(B04 하단 지도는 배경 전체 보기 유지)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-01 13:01:02 +09:00
eomsangdonandClaude Opus 5 5da0fb1cd6 feat(B04): 배경 지도 확보 범위를 기준 도엽 도곽과 동일하게
사용자 지시(2026-08-01): 위성사진은 수치지형도 도엽과 같은 눈금으로 확보한다.
계획노선이 걸치는 기준 도엽만 받고(1매 또는 2~3매), 주변 도엽은 받지 않는다.

- sheets_for_points(): 기준 좌표가 속한 도엽번호만 반환(주변 확장 없음)
- satellite_extent(): 기준 도엽들의 도곽 합집합을 프로젝트 좌표계로 반환.
  도엽을 못 구하면 라이다∪계획노선 범위로 폴백
- 다운로더: 주변 확장 로직 제거. 요청 범위를 덮는 타일만 받되, 한 변 타일 수가
  한도를 넘으면 zoom을 낮춘다(도엽 1매를 zoom 18로 받으면 한 변 19타일 = 4,864px)
- 국가 GIS 벡터는 종전대로 라이다∪계획노선 범위 사용
- 표본 실측: 기준 도엽 1매(37816093) -> 10x13 타일, 2438x3169m, 0.95m/px, 15.1MB,
  실패 타일 0개 (이전 731x853m)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-01 12:47:20 +09:00
eomsangdonandClaude Opus 5 a17b95f621 fix(B04/B05): 2D 지도 기준을 라이다에서 브이월드 범위로 + 배경 확보를 기준 박스 3x3으로
3D(라이다)와 2D(브이월드)는 다루는 범위가 다르다. 그런데 2D 지도가 열릴 때 라이다
범위에 맞춰 확대하고 있어서, 배경을 넓게 받아도 화면에 보이는 범위가 늘 같았다
(2026-08-01 사용자 지적).

- 확보 범위: 계획노선·기준 좌표를 덮는 기준 박스 + 주변 박스(SURFACE_MAP_NEIGHBOR_RINGS=1)
  = 3x3 배치. 미터/타일 여유폭 방식(SURFACE_MAP_MARGIN_TILES) 폐기.
  해상도(zoom 18)는 브이월드 기본 스케일 그대로 — 화소를 키우는 것이 아니다.
- 타일 상한 15는 양쪽에서 균등하게 줄여 기준 박스가 가장자리로 밀리지 않게 한다.
- B04 하단 지도·B05 배수유역도는 확보한 배경 전체가 보이도록 열린다.
- 표본 실측: 기준 박스 372x401m -> 12x15 타일 = 1463x1828m (이전 731x853m).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-01 12:35:51 +09:00
eomsangdonandClaude Opus 5 6af50811b6 fix(B04): 배경 지도 재다운로드 판정을 파일 존재에서 범위 포함 여부로 변경
기존에는 vworld_*_meta.json이 있으면 무조건 건너뛰었다. B03 업로드가 부르는 전처리
경로는 rebuild=False라, 계획노선이 바뀌거나 여유 셀 설정을 바꿔도 옛 사진을 계속 썼다
(2026-08-01 사용자 지적: 트리거 시점 문제).

map_meta_covers()로 저장된 사진이 필요한 범위(라이다 U 계획노선)를 실제로 덮는지
확인하고, 못 덮으면 다시 받는다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-01 12:18:47 +09:00
eomsangdonandClaude Opus 5 d3b443e077 feat(B04): 배경 지도 여유폭을 미터가 아닌 주변 셀 겹수로 지정
사용자 요청 방향(2026-08-01): 해상도(zoom 18)는 그대로 두고, 계획노선과 기준 좌표를
덮는 타일 바깥으로 주변 셀을 더 확보한다.

- SURFACE_MAP_MARGIN_M(300m) 제거, SURFACE_MAP_MARGIN_TILES(3겹) 신설.
  기존 하드코딩 1겹 -> 설정값. zoom 18에서 1겹 약 122m(위도 37deg).
- download_extent는 덮어야 할 범위(라이다 U 계획노선)만 돌려주고 여유는 타일 쪽에서 준다.
- 표본 실측: 덮을 범위 372x401m -> 10x11 타일 = 1220x1341m,
  계획노선 사방 여유 474~588m (이전 731x853m).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-01 12:11:39 +09:00
eomsangdonandClaude Opus 5 5073916739 fix(cache): 브라우저 보관함 버전을 올려 철회된 도엽 표시본을 비운다
도엽 표시용 사본을 철회했지만, 이미 그 사본을 받아 둔 브라우저는 계속 그것을 쓴다
(보관함 키가 주소 기준이라 서버 파일을 지워도 남는다). DB_VERSION 1 -> 2로 올리고
업그레이드 시 기존 저장소를 버리도록 해 다음 접속에서 원본을 새로 받게 한다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-01 12:06:23 +09:00
eomsangdonandClaude Opus 5 d033e58880 revert(B04): 도엽 표시용 사본 철회 — 도엽 산출물을 원본 그대로 전송
배수유역이 어디까지 뻗을지 알 수 없어 도엽 자료를 잘라 두 벌로 나누지 않는다
(2026-08-01 사용자 지시). 분석 경로는 원래부터 원본을 읽었고 사본은 전송용이었으나,
사본 자체를 없앤다.

- B04_wf1_Surface_Engine_SheetView.py 삭제, SHEET_VIEW_* 설정 제거
- /geojson의 도엽 레이어는 원본 파일 그대로 + ETag로 전송
  (재직렬화 제거만으로 요청당 2.0초 -> 0.006초, 두 번째 요청부터 304)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-01 11:57:12 +09:00
eomsangdonandClaude Opus 5 07a2cf1393 fix(B04): 배수유역 재산정 버튼이 표시 토글로 걸려 눌러도 반응 없던 문제
저장분을 자동 표시하도록 바꾼 뒤로 진입 시 shown=true가 되어, 재산정 버튼을 누르면
분석 요청 없이 오버레이만 숨겨졌다(사용자 눈에는 무응답). 버튼은 언제나 재산정을
실행하도록 하고, 보이기/숨기기는 갈래별 버튼(1차/2차/유역방향/평균흐름)이 맡는다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-01 11:54:07 +09:00
eomsangdonandClaude Opus 5 a9caf872b2 perf(B04/B05): 도엽 표시본 도입 + 배경 범위·도엽 기준을 계획노선으로 변경
- 도엽 병합본의 화면 표시용 사본 생성(B04_wf1_Surface_Engine_SheetView):
  프로젝트 + 500m로 잘라내고 좌표를 소수 7자리로 줄여 등고선 37.3MB -> 0.97MB.
  분석용 원본은 그대로 둔다(배수유역은 상류까지 넓은 범위가 필요).
- /geojson의 도엽 레이어를 파일 그대로 + ETag로 전송 — 매 요청 2.0초 재직렬화 제거(0.008초).
- /vworld-map도 ETag 전송으로 바꾸고, 프론트가 붙이던 `&_t=` 시간꼬리표 제거.
- 도엽 레이어를 브라우저 보관함 경유로 조회하고 준비화면에서 미리 담는다.
- 배경 지도 범위 = 라이다 범위 + 계획노선 범위 + 여유 300m(SURFACE_MAP_MARGIN_M).
- 도엽 기준 좌표 = 계획노선 시점·종점(없으면 라이다 중심). 같은 도엽이면 9매,
  이웃 도엽에 걸치면 12매. 표본 프로젝트는 기존 9매와 동일(회귀 없음).
- 선정에서 빠진 도엽 zip 정리(prune_sheets) — 표본에서 30매 중 21매가 다른 지역 잔재.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-01 11:47:29 +09:00
eomsangdonandClaude Opus 5 96561de120 perf(B04/B05): 확정 지표면 요약 API 신설 + 포인트클라우드 24MB 수신 제거
- GET /surface/confirmed 추가: 확정 구성(모델·필터·표현·평활·등고선간격)과
  지형 가장자리만 반환(수 KB, 0.02s). 진입 판정·준비화면·B05의 단일 출처.
- B05 진입이 받던 포인트클라우드 JSON 23.8MB 제거 — 실제로 쓰던 값은 bounds뿐.
- 준비 표식을 프로젝트 ID에서 확정 signature로 변경: B04에서 다시 확정하면
  대시보드 복귀·새 브라우저·B그룹 단계 이동 어느 경로로 들어와도 최신본을 담는다.
- preloadSurfaceAssets가 평활 여부를 추측하던 부분 제거(확정 저장값 사용) —
  추측이 어긋나면 같은 지형을 두 번 내려받았다.
- B04 진입 시 필터·표현·평활·등고선간격을 확정본 값으로 초기화(확정 없으면 기존 기본값).
- 모델 확정 직후 준비 표식과 B05 세션 캐시를 비워 옛 지형이 남지 않게 함.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-01 11:34:44 +09:00
eomsangdon 77a637d7c9 feat(B11): 자료 준비 화면 신설 — 작업 화면 진입 전 3D·등고선 선적재
- B11_Status_UI_Loading + 라우트 b11-loading: 공통 프로그레스 서클로 단계·진행률 표시,
  끝나면 원래 가려던 화면으로 자동 이동
- goToWorkflowStage: 아직 준비하지 않은 프로젝트면 준비 화면 경유, 같은 프로젝트로
  다시 들어오면 건너뜀(탭 단위 기억). 다른 프로젝트면 보관분 교체
- 선적재 범위: 확정 지표면 3D + 그 등고선만 (종단·횡단은 0.86MB·0.06초로 이미 즉시라 제외,
  배수유역·포인트클라우드도 제외)
- 실패 시 자동 이동하지 않고 담당자 연락 안내 + [그래도 이동]/[대시보드로]
- B04 등고선 간격 시작값을 B05 저장값과 공유(B04 변경은 DB에 쓰지 않음)
- 새 문구는 ui_locales에 한국어·영어 등록
2026-08-01 10:34:08 +09:00
eomsangdon c970812cf3 feat(3D): 휠 방향 반전·회전점 표시 + 3D/등고선 브라우저 보관함
- 휠 위 = 축소로 반전, 커서 지점을 축으로 한 dolly를 공용 유틸에서 직접 처리
- 회전 중심을 작은 구로 표시(돌리는 동안만, 화면상 크기 일정, 항상 위에 그림)
- 등고선 렌더 비용 감소: 폴리라인을 주곡선·보조곡선 2덩어리로 병합(드로우콜 424 → 2),
  라벨은 카메라가 움직였을 때만 재배치
- common_util_http_cache: 파일 mtime+크기 ETag, If-None-Match 일치 시 304
  (preview·contour 적용, 파일이 바뀌면 자동 무효화)
- A00_Common/b_asset_cache: IndexedDB 보관함(키 = projectId|url, 값 = 바이트+ETag).
  보관본 즉시 사용 후 백그라운드 재검증, 3D는 보관 바이트를 직접 파싱
- 프로젝트 전환 시 타 프로젝트 보관분 삭제, 대시보드→B그룹 이동 시 확정 모델의
  3D 프리뷰·등고선(1.0m) 미리 받기(포인트클라우드 제외)
2026-08-01 09:58:44 +09:00
eomsangdon 13c2522f47 feat(B04/B05): 프로그레스 서클을 3D·지도·그래프 전 영역에 공통 적용
- 공통 서클 양식을 로딩 스피너(.ui-spinner) 기준으로 통일하고 overlay 옵션 신설
  (컨테이너 정중앙 배치를 페이지별 CSS 없이 처리)
- B05 3D: 위쪽 18% → 뷰포트 정중앙 (하단 패널에 가려져도 무방)
- B04 포인트클라우드 뷰어: setLoading() 신설, render() 시 자동 해제
- B04 지형 뷰어: GLTF/PLY 로더 진행 이벤트로 실제 바이트 진행률 표시
- B04 2D 지도: 도엽 레이어 n/10 진행률
- B05 종단면 그래프: body-wrap으로 감싸 서클 유지, 자료 조회 전후로 토글
- B05 배수유역도: 배경도 → 도엽 레이어 → 세부유역 산정 단계 진행률
2026-08-01 09:29:53 +09:00
eomsangdon f6be8d7307 fix(B04/B05): 3D 조작감 보정 — 커서 표면 회전축, 상하 반전, 가운데 버튼 팬
- 회전축을 커서가 가리키는 지형 표면 지점으로. 포인트클라우드는 카메라 거리의 1%를
  클릭 허용 반경으로 주고, 못 맞히면 시선 수직 평면과 만나 커서 방향 지점을 쓴다
  (화면 중앙으로 되돌아가지 않음)
- 수직 회전 부호 반전 (마우스를 내리면 내려다보는 방향)
- controls.mouseButtons.MIDDLE = PAN (전역 공통). 브라우저 자동 스크롤 차단
- B05 뷰셋 버튼 그룹을 좌상단으로 이동 (.b05-route__view-controls top 58px → 16px)
2026-08-01 09:19:59 +09:00
eomsangdon 4501f3b19e auto: 2026-08-01 08:55 (EOMSANGDON-HOME) 2026-08-01 08:55:01 +09:00
eomsangdon 4aa211cead feat(drainage): B05 평균 흐름 화살표 표기 + 응답 캐시 저장 누락 수정 2026-07-31 21:47:17 +09:00
eomsangdonandClaude Fable 5 500a3c9047 fix(B04): 배수유역 상태 문구 전용 줄 분리 + 저장분 없을 때 안내
증상 두 가지
  1. 재산정 버튼을 눌러도 프론트에 아무 안내가 없었다.
     오버레이가 지도 자체 상태(.b04-map__status)에 문구를 썼는데,
     loadLayers 가 같은 칸에 3곳에서 덮어써 즉시 지워졌다.
  2. 페이지 접근 시 배수유역이 안 보였다.
     응답 캐시 파일(00_watershed_response.json)이 아직 없어 자동 조회가
     빈 손으로 끝나는데, 그 사실을 화면에 알리지 않아 이유를 알 수 없었다.

조치
- 배수유역 전용 상태 줄(.b04-map__watershed-status)을 컨트롤 영역에 따로 둔다.
  지도 로딩 문구와 서로 덮어쓰지 않는다.
- 컨트롤에 배수유역 그룹을 만들어 재산정 버튼 + 갈래 토글 4종 + 상태 줄을 묶었다.
- 진행 상태를 버튼 라벨에도 반영: 배수유역 재산정 -> 분석 중… / 불러오는 중…
- 결과 문구에 출처와 소요를 붙인다: [저장분] ... / [재산정 28.4초] ...
- 저장분이 없으면 오류가 아니라 안내로 표시:
  "저장된 배수유역 분석이 없습니다. [배수유역 재산정]을 누르세요."
- 실패하면 버튼 활성 상태를 되돌려 껐다 켠 것처럼 보이지 않게 했다.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-31 21:26:32 +09:00
eomsangdonandClaude Fable 5 2ddf81c86c feat(B04/B05): 저장분 자동 표시 + 평균 흐름 화살표 + 갈래별 토글
1. 재산정하지 않는 한 저장분을 그대로 쓴다
   GET /drainage/primary-region 이 기본으로 영구저장소의 응답 캐시를
   그대로 돌려준다(0.0004s). refresh=true 일 때만 다시 계산한다.
   저장 배열에서 응답을 재조립하지 않고 **응답 자체**를 남긴다 —
   재조립하면 원본과 어긋날 여지가 생긴다.
   버튼 이름 배수유역 -> 배수유역 재산정. 지도를 열면 저장분이 자동으로 뜬다.

2. B05용 평균 흐름 화살표 (build_flow_arrows)
   셀 화살표는 1m 라 도면 배율에서 경향이 안 보인다. 겹치지 않는 10m 블록으로
   나눠 방향을 원형 평균하고, 40m 간격으로 솎아낸다.
   - 세류선 셀과 도로 셀은 뺀다. 그 자리는 확정된 물길/노면을 따르는 값이라
     사면 경향을 왜곡한다.
   - 산술평균이 아니라 원형 평균(0도와 359도의 평균은 180도가 아니다).
     평균 벡터 길이가 방향 일치도이므로 0.7 미만이면 그 블록은 버린다.
   - 블록 유효 셀이 절반 미만이면 건너뛴다(가장자리 조각 방지).
   실데이터 377개, 간격 40m 균일, 블록당 평균 98셀, 적 278 / 청 99.
   config: ARROW_BLOCK_M / ARROW_SPACING_M / ARROW_MIN_COVERAGE / ARROW_MIN_AGREEMENT

3. 갈래별 하이드/쇼 버튼 4종
   1차 유역 / 2차 유역 / 유역 방향 / 평균 흐름.
   평균 화살표는 B04 에도 올려 형태를 확인할 수 있게 했다.

4. B05 는 페이지 진입 즉시 유역도를 올린다
   B04 결과를 읽기만 해 0.1초면 끝나므로 버튼을 기다릴 이유가 없다.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-31 21:20:44 +09:00
eomsangdonandClaude Fable 5 79fe2fb7c9 feat(B04): 표본 화살표 + 오버레이 갈래별 토글 버튼
화살표가 안 보이던 문제
  1m 격자를 도엽 전체 배율로 보면 셀이 1~2px 다. 줌 상한이 8배라 셀이
  화살표 최소 크기(7px)에 절대 못 미쳐 채움색만 보였다.
  -> 셀마다 그리지 않고 화면상 약 22px 간격이 되도록 건너뛰며 표본만 그린다.
     화살표 크기는 그 간격에 맞춰 커진다. 흐름장을 읽는 표준 방식이다.
  -> 채움색 위에서도 읽히도록 흰 테두리를 한 겹 깔고 그 위에 그린다.

갈래별 토글 버튼 추가 (1차 유역 / 2차 유역 / 유역 방향)
  GIS 버튼 줄에 배수유역 전체 토글 옆으로 붙는다. 전체 토글이 꺼져 있으면
  갈래 설정과 무관하게 아무것도 그리지 않는다.
  그리는 순서는 유역방향(격자/화살표) -> 1차 유역 -> 2차 유역/관.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-31 21:09:20 +09:00
eomsangdonandClaude Fable 5 395e6b4b13 fix(B04): 배수유역 오버레이가 화면에 안 그려지던 문제
분석은 돌고 상태 문구도 나오는데 지도에는 아무것도 안 보였다.

원인: 프레임 함수 이름이 draw() 가 아니라 drawVectorLayer() 라
오버레이 draw 호출을 끼워 넣는 치환이 조용히 실패했다. 호출 자체가
소스에 없었다.

- drawVectorLayer() 안, GIS 레이어와 등고 라벨 뒤에 오버레이 draw 삽입.
  격자/화살표가 등고선을 덮어야 읽히므로 맨 위에 얹는다.
- drawPrimaryRegion 이 drawGridCells 를 한 번 더 부르던 중복 제거
  (draw 체인이 이미 먼저 호출한다).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-31 21:02:52 +09:00
eomsangdonandClaude Fable 5 8a0d640e0e refactor(B04/B05): 배수유역 분석을 B04로 이관, B05는 저장분 소비만
분석이 30초 걸리는데 B05는 일반 사용자 화면이다. 관리자 확인용 B04에서
한 번 돌려 저장하고, B05는 그 결과를 읽어 관 보충과 세부유역만 처리한다
(2026-07-31 사용자 지시).

노선 원천 변경
- B05 확정 경로 -> B03 업로드 계획 노선 파일(CSV). 분석이 노선 설계보다
  먼저 끝나 있어야 하기 때문. 샘플 planned_route_sample_epsg5187.csv 로 검증.
- common_util_route_geometry.py 신설 — RouteVertex/StructureCandidate/누가거리
  보간/세류 교차점/계획 노선 CSV 리더. B04와 B05가 같은 표현을 쓰도록 공용화.
  열 이름은 대소문자·한글 표기를 함께 받는다(B03이 여러 형식 수용 예정).

B04 (관리자 확인용, 신규)
- Engine_Watershed_{Grid,Stream,Descent,Flow,Expand,Export} — B05에서 git mv
- Engine_Watershed_Analyze.py — 1~8단계 오케스트레이션
- Router_Watershed.py — GET /drainage/primary-region
- UI_Watershed.ts — 2D 지도 GIS 레이어 그룹에 "배수유역" 토글 추가.
  격자/화살표/세류망/1차영역/2차유역/기본관을 겹쳐 그린다.
- 저장 위치 B05_wf2_Route/drainage -> B04_wf1_Surface/drainage
- 03_road_routing 단계 추가: B05가 세부유역을 나눌 최소 배열(셀->도로셀 귀속,
  유하장, 강도, 도로셀 제원, 셀 표고) + 계획도로선/기본배관/2차유역 기하

B05 (일반 사용자용, 축소)
- Engine_Drainage_Basin.py — B04 산출물 로더 + 관 보충(9) + 측구 라우팅/세부유역(10,11)
- Engine_Drainage.py 는 관경 산정만 남기고 322 -> 27줄
- Router_Drainage.py 509 -> 142줄. POST /drainage/basins 만 남김
- 화살표·격자·강도 띠 렌더 제거. 계획도로선/기본배관/2차유역만 받는다

삭제
- _legacy_watershed/ 4파일 (능선 행진 방식 원본 보관본)
- Engine_Watershed_Basin.py (B04 Analyze + B05 Drainage_Basin 으로 분할)
- GET /drainage/candidates 와 propose_structure_stations (구방식 후보 제안)

E2E 검증 (실데이터)
  B04 분석 28.2s -> 저장(geojson 11KB + npz 2.6MB)
  B05 로드 + 세부 설계 0.11s   <-- 30초가 0.1초로
  면적 457,404m2 로 B04 2차 유역과 정확히 일치
  관 편집 재산정 0.12s, 관 3개 -> 세부유역 3개, 면적 보존

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-31 20:57:09 +09:00
eomsangdonandClaude Fable 5 b0747e74b6 fix(B05): 6/7/8 단계 산출물도 영구저장소에 남긴다
확인해 보니 7(2차 유역 외곽선)과 8(기본 관)은 저장되고 있었으나
6(흐름 강도 곡선)이 빠져 있었고, 관에 누가거리가 안 붙었다.

- write_stage 의 레이어 항목이 (기하, 속성dict) 짝도 받도록 확장.
  관 피처에 chainage_m / reason / stream_name 이 실린다.
- 흐름 강도 곡선은 기하가 아니라 수치 곡선이라 GeoJSON 대신
  02_flow_direction.npz 에 strength_chainage_m / strength_area_m2 로 담는다.
- manifest 에 strength_points / strength_total_m2 요약 추가.

저장 확인 (실데이터)
  01_primary_region.geojson  688KB  kind: primary_region 1 / upstream 16 /
     downstream 860 / route 1 / grid_bbox 1 / basin_boundary 1 / pipe 1
     pipe 속성 = chainage_m 149.73, reason stream
  01_primary_region.npz       11KB  셀 마스크 + 확장 회차
  02_flow_direction.npz     2353KB  direction/reaches_road/analyzed/receiver/
     burned/band_elevation + 강도 곡선 71점(합계 457,404m2, 최대 150m)
  manifest.json                     3단계 요약 전부

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-31 20:04:26 +09:00
eomsangdonandClaude Fable 5 baef88dd50 feat(B05): 단계 검증에 흐름 강도·2차 유역 외곽선·기본 관 위치 추가
본 계산(POST /basins)은 손대지 않았다. 검증 경로에만 6/7/8 단계를 얹는다.

6. 흐름 강도
   색 판정은 세류 셀에서 멈춘다(거기서 도로 도달이 확정되므로). 강도는 그 물이
   세류를 타고 최종적으로 어느 도로 셀로 들어가는지를 봐야 하므로, 도로만
   흡수점으로 두고 한 번 더 따라가 도로 셀별로 센다.
   -> 누가거리 5m 구간별 유입 면적 곡선

7. 2차 전체 배수유역 외곽선
   적색 셀 전체를 폴리곤화한 외곽 링 + 면적

8. 기본 관 매설 위치
   도로 x 세류선 교차점. 20m 이내는 하나로 병합. 300m 보충 배치는 다음 단계.

프론트는 기존 렌더 경로를 그대로 쓴다 — 2차 유역선은 갈색 파선, 강도는 계획선
위 파란 띠, 관은 번호 마커. 버튼을 끄면 이 셋도 같이 걷는다.

실데이터 검증 (27.8s)
  적색 457,404셀 = 457,404m2
  7. 폴리곤 면적 457,374m2 (셀 면적의 100.0%)
  6. 강도 합계 457,404m2 (적색 면적의 100.0% - 귀속 누락 0)
     최대 지점 150m 에 409,244m2(89.5%) 집중
  8. 기본 관 1개 chainage 149.7m
     -> 강도 최대 지점과 정확히 일치. 세류가 도로를 건너는 그 자리다.
     교차 노드는 2개였으나 13.3m 간격이라 20m 병합 규칙으로 1개가 됐다.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-31 19:58:54 +09:00