PLAN 2026-08-17 「B05 구조물 컨테이너 병합」 프론트엔드.
- B05_Profile_Util_Station.ts 신설: 측점번호+잔여거리("3+18.0") ↔ 누가거리
변환·서식·해석. 누가거리 직접 입력도 허용, 부동소수 올림 보정.
- 구조물 패널: 위치 입력을 측점 표기 텍스트로 재편. 점형 = 기준 측점 1칸,
구간형 = 기준점(비우면 시작)+시작+종료 3칸, 시작≤기준≤종료 검증과 잘못된
입력 붉힘. 목록 표기도 측점식. 구간형 마크 드래그는 기준점 기준으로 시작·
종료가 따라온다. 상세(detail) 옵션은 폼에서 숨긴다 — B05는 유무·종류·위치
단계(2026-08-17 사용자 확정).
- 우클릭 메뉴 필터 완화: managed_by와 b05 phase 필수만 제외 — 상세 필수였던
타입(옹벽·돌쌓기 등)도 우클릭 한 번으로 추가된다.
- B05_Profile_UI_Drainage_Facility.ts 신설(패널 700줄 제한 대응 분리): 관 마커
선택 시 시설 종류(배관/BOX암거/물넘이/세월교)·구간·세월교 관 종류/크기/수량
폼. FacilityStore가 시설 확장 정보를 보관하고 세부유역 재계산·저장 요청에
되붙인다(관 이동 후에도 최근접 승계 — 백엔드 carry와 같은 기준). 응답이
정본이라 apply()에서 전량 재구성.
- B04_PreProcess_Api_Fetch.ts: PipeFacility·DetailPipeInput 타입, 요청·응답에
시설 필드 반영.
npm run typecheck·npm run build 통과. 통합 서클마크 표시와 구 비정규 측점
이관·폐기(3단계)는 배관 측점선 체계 이전과 묶어 다음 작업 — PLAN.md 체크리스트
에 미완 사유 기록.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
csf-nurbs 등고선 캐시가 Maximum allowed size exceeded로 실패하던 문제.
평활계수 s가 제어점당 잔차제곱 0.01(RMS 0.1m)로 너무 빡빡해 FITPACK이
제어점 수(122x113)보다 많은 knot(126x117)을 밀어넣고 계수가 발산했다.
실측 표고: csf 1e105, grid_min_z 1e10. grid_min_z는 footprint 안쪽만
보고 z 범위를 잡아 조용히 통과하고 있었다.
- ModelContext에 fit_nurbs_spline/evaluate_nurbs_spline 신설. 모델 빌더와
등고선 엔진이 같은 곡면을 각각 만들면서 s 식이 두 곳에 중복돼 있었다.
- NURBS_RESIDUAL_PER_CONTROL_POINT = 1.0 (RMS 1m). knot이 17~35로 떨어지고
세 지면 필터 모두 데이터 표고 범위 안에 머문다. NURBS는 평활 곡면
표현이라 이 정도 완화가 맞다.
- 평가 결과가 제어 표고 범위(±50% 여유)를 벗어나면 잘라내고 경고를 남긴다.
방치하면 float32 캐스팅에서 inf가 되어 프리뷰 색상(nan)과 등고선까지 번진다.
- extract_contours_from_grid: 레벨 수 상한 검사를 np.arange 앞으로 옮겼다.
뒤에 있어서 상한이 무용지물이었다 — 배열이 만들어지기 전에 터진다.
확인: 3필터 모두 곡면이 제어 표고 범위 내(grid_min_z 503.6~573.1,
csf 504.7~552.3, pmf 504.6~551.8), 등고선 0.55~1.64초에 정상 산출.
표고 범위 1e12 격자도 예외 없이 처리. tmp/tests 59건 통과.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사용자 결정(2026-08-08): 새 자료를 올리면 재계산해 덮어쓰고, 화면은 불러올 자료가 없으면
대시보드로 보낸다. 그러려면 자료가 갈리는 순간 옛 계산 결과가 남아 있으면 안 된다.
- common_util_project_reset 신설: 단계별 산출물 폴더(B04~B09)와 산출물 DB 레코드
(surface_models·routes·route_points·route_statistics·longitudinal_sections·
cross_sections·structures·quantity_items·outputs·processed_point_cloud)를 함께 지운다.
**B03_FileInput(업로드 원본)은 지우지 않는다** — 같은 파일인지 가리는 중복 검사가 쓴다.
- 직접 업로드 완료·보관함 연결 양쪽에서 정리를 호출하고, 진행 단계도 1단계 이후를
NOT_STARTED로 되돌린다(reset_stages_after_input_change).
- is_analysis_running(): 전처리가 도는 중이면 업로드 세션 생성과 보관함 연결을 409로
막는다. 화면 버튼 잠금은 새로고침·다른 탭으로 우회되므로 서버에도 문을 단다.
- fail_stage 아래 있던 리비전(번호표) 안은 폐기 — 사용자가 "산출물이 없으면 대시보드"
방식으로 정리했다.
곁들여: os.replace 공유 위반 재시도(replace_with_retry)
진행률 파일은 서버가 쓰는 동안 화면이 계속 읽어 WinError 5가 났고, 전처리
structured.npz 교체에서는 같은 이유로 분석이 통째로 죽었다(결함 3의 사망 원인).
짧게 여러 번 다시 시도하도록 바꿨다.
검증(실서버 f45243b3, 계획노선 CSV 재업로드로 자료 교체):
전처리 결과 112개 -> 재분석분만, 노선 2->0, 횡단 20->0,
DB 지표면 15->0 / 노선 1->0 / 횡단 19->0, 업로드 원본 6개는 그대로.
진행 단계가 초기로 돌아가고 재분석이 자동 시작됨.
교체 재시도는 읽는 쪽이 파일을 잡고 있는 상황을 만들어 성공 확인.
ruff format·check 통과.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
앞선 두 커밋(c3f643b, 7d50ded)으로도 증상이 남아 헤드리스 크롬으로 실제 앱에 로그인해
B05 3D를 끌어 보며 측정했다. 원인은 회전 계산이 아니라 **탑뷰 카메라 자리**였다.
카메라를 정확히 수직으로 세우면(기존 top = [0, distance, 0.001], 극각 1e-6도) lookAt이
화면의 가로·세로 방향을 정하지 못한다. 그 자리에서 벗어나는 순간 화면 축이 180° 돌아간다.
실측(2px 드래그 6걸음):
before 극각 0.00° -> 0.86°, 1걸음째 화면축 반전, 이후 같은 방향 드래그 먹통
after 극각 2.00° -> 1.15°, 반전 0회, 반대 방향 20걸음도 반전 0회(1.15° -> 130°)
- TOP_VIEW_TILT(2°) 신설 — 화면상 위에서 내려다보는 그림과 구분되지 않으면서 여유각
(POLAR_EPSILON, 약 1.15°)보다 바깥이라 첫 드래그부터 회전이 이어진다.
- B05 노선 뷰어, B04 지형·포인트클라우드 뷰어의 탑뷰 세 곳에 모두 적용.
typecheck·prettier 통과, 정적 번들 재빌드.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
기본 탑뷰는 시선이 up과 거의 나란하다(극각 1.9e-6 rad). 이때 회전축으로 쓰던
시선×up이 0에 수렴해 축 방향이 잡음으로 정해졌고, 살짝만 끌어도 엉뚱한 축으로 돌아
화면이 뒤집혔다. 앞 커밋의 극점 클램프도 각도를 여유각(0.02 rad) 경계까지 끌어올려,
작은 드래그가 여유각만큼 튀게 만들었다.
- 시선×up이 시선 길이 대비 무시할 만큼 짧으면 카메라 자신의 가로축으로 대체한다.
두 축은 모든 각도에서 방향이 같아(내적 1.000000) 전환 순간에도 조작감이 안 바뀐다.
- 클램프 경계를 현재 극각과 여유각 중 극점에서 먼 쪽으로 잡는다. 이미 여유각 안쪽인
탑뷰에서는 경계로 끌어올리지 않고, 극점에서 멀어지는 쪽만 열어 준다.
검증(탑뷰 재현): 0.005 요청 -> 0.005 적용, 0.05 -> 0.05, 극점 쪽 -0.005 -> 0(정지).
typecheck·prettier 통과, 정적 번들 재빌드.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
세로로 많이 끌면 화면이 멈췄다가 한 번에 움직이는 증상. 원인 두 가지였다.
1) 극점을 넘길 회전을 통째로 버렸다. 끄는 동안 화면이 굳어 있다가 각도가 다시 범위
안으로 들어오는 순간 밀린 만큼 한꺼번에 움직였다. 이제 극점 직전까지만 잘라서
적용한다 — right축이 up과 직교하므로 돌린 각이 곧 극각 변화량이고, 부호만 실제로
재서 클램프한다. 극점에 닿으면 더 안 가고 멈출 뿐, 반대로는 자유롭게 빠져나온다.
2) 드래그가 캔버스 밖(브라우저 위·아래 끝)으로 나가면 pointerleave로 회전이 끊겼다.
다시 누를 때 커서 아래로 회전축을 새로 집어 시점이 튀었다. 포인터를 캡처해 밖으로
나가도 회전을 이어 가고, 놓을 때만 끝낸다.
B04 지형·포인트클라우드 뷰어와 B05 노선 뷰어가 같은 모듈을 쓰므로 양쪽 모두 적용된다.
typecheck·prettier 통과, 정적 번들 재빌드.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>