사용자 피드백 반영(2026-08-03 2차).
유토곡선 일원화
- B05 유토곡선을 B06과 같은 계산(computeMassHaulSeries: 횡단 정식 + 종단 개략
비교)으로 전환. 상세 조회가 미지정 측점에 기본 설계를 즉석 계산해 얹으므로
B05 진입 시점에 이미 정식 곡선 재료가 있다. 표시 토글 sessionStorage 키와
balloon 위치 scope를 B06과 공유해 두 화면이 같은 그림을 유지한다.
- B05 전용 개략 엔진(computeLongitudinalMassHaul) 삭제.
- 유토곡선 펼침 시 종단 그래프:곡선 세로 1:1 분할.
사토장·토취장 자동 선정 삭제
- 임도에는 토취장이 없고 부족분은 설계자가 계획선을 고쳐 맞춘다는 실무 판단에
따라 4옵션(비용/지형안정성/계곡부/임내공간) 엔진·API·UI·config·저장 훅 전부
제거. massHaulPayload/createMassHaulLegend 시그니처 원복.
기본 지반 변경
- 기본 설계 프리뷰·확정 기본값을 토사에서 리핑암 + 예상 암반 경계 0.5m로 변경.
산지 절토는 표토 아래 암이 일반적이라 전량 토사 가정은 물량이 낙관적이다.
발파암은 B06에서 측점별 수정.
계획선 R·선 연결 (배관 구조물 자리)
- 계획선 샘플이 고정 격자로만 평가되어 격자 사이 변화점(배관 측점 승격분)의
모서리를 잘라먹던 결함 수정 — 샘플 집합에 PVI·BVC·EVC를 합집합으로 포함
(프론트 buildAlignment + 서버 build_alignment 동일 규칙). 면적 가중치도
합쳐진 격자로 재계산. 37.3m 변화점 + R=150 수치 검증 통과.
표시 개선
- EP(종점) 잔량 라벨: 곡선 끝점에 "EP {누가토량}㎥" 불투명 판(B05·B06 공통).
- 유토곡선 0선을 붉은 굵은 실선(2.5px)으로, 0 눈금값도 적색.
- 3D 뷰 [측점 가로선] 우측 [측점 라벨] 토글 신설(기본 꺼짐) — 구조물 측점만
"측점번호 구조물명" 스프라이트 표시.
typecheck·vite build·ruff·B03 테스트 통과. 실서버 스모크로 리핑암 기본 프리뷰와
disposal-sites 제거 확인.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
절·성토 균형은 종단 시공계획고로 정해지고 사토장 위치도 계획고를 다시 끌어야
정리되므로, 계획용 유토곡선과 부지 선정을 B05로 옮겼다. B06은 실측 단면적으로
낸 정식 곡선과 확정·B08 인계를 맡는다.
B05 계획 유토곡선
- _UI_Profile_MassHaul.ts: 종단면 패널 안 2차 하단 슬라이드. 펼치면 12행 도면
테이블 자리를 곡선이 대신 차지한다. 곡선 SVG를 종단 그래프와 같은 가로
스크롤러 안 형제로 넣고 MassHaulAxis에 LONG_PAD + originOffset을 넘겨 X축을
종단 chainageMapper와 일치시켰다.
- computeLongitudinalMassHaul(): 횡단 설계가 없는 계획 단계용 개략 엔진. 표준횡단
노반폭을 전 구간 공통으로 물린다. 종단 기반 토량은 국내 기준상 노선계획 개산용
이므로(2026-08-03 조사) 표준단면까지 씌워 정밀화하지 않는다.
사토장·토취장 자동 선정
- B05_wf2_Route_Engine_Disposal.py + POST /route/disposal-sites: 노선 corridor
DEM 격자를 훑어 후보 부지를 추리고 옵션별 점수로 정렬한다. 기준 4가지 —
비용(최단거리+하향 운반), 지형안정성(완경사·계곡 이격), 계곡부(계곡 축 매립),
임내 공간(라이다 수고 기반 공터). 기준값 정의처는 DISPOSAL_SITE_CRITERIA.
- _UI_Profile_Disposal.ts: 범례 줄의 [토량 분배]와 [도형 위치 초기화] 사이에
구분기호와 함께 라디오 토글 4개. 부지 카드에 위치·용량·운반거리와 기준별 근거값,
측점·용량 사용자 정의 편집과 복원. 후보 부족으로 남은 토량은 경고로 알린다.
- 확정 시 종단 정본의 disposal_sites에 심는다(기준 미선택이면 저장분 삭제).
B06 연동
- common_util_mass_haul_sites.ts: 저장된 부지를 정식 곡선의 잔량 위치 기준으로
운반거리를 다시 재 표시하고 mass_haul.disposal_sites로 B08에 넘긴다.
미구현(계획서에 남김): 토취장 토질 판정(지반유형이 B06 산출물), 계곡부 암거 연장.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
B05 계획 유토곡선과 B06 정식 유토곡선이 같은 엔진을 쓰도록 모듈을 옮겼다.
- B06_wf3_ProfileCross_UI_MassHaul{,_Balance,_Balance_View,_Balloon,_Curve,
_Settle,_View}.ts + Style_MassHaul.css → common_util/common_util_mass_haul*.
- common_util_mass_haul_types.ts 신설: GroundType/EarthworkConversion/
HaulEquipmentLimit/BalloonOffsets 정의처를 한 곳으로 모으고 B06 Api_Fetch가
재수출. 엔진 입력은 페이지 API 타입 대신 구조적 부분집합으로 받는다.
- common_util_svg.ts 신설: svgElement/svgText/L/stationLabel/
inferStationInterval 이관, B06 _UI_Section_Common은 재수출로 경로 유지.
- createMassHaulChart에 MassHaulAxis 인자 추가 — 종단 렌더러 상수 의존을
걷어내고 호출한 쪽이 X축(누가거리 최댓값·좌우 여백)을 주입한다.
동작 무변경. npm run typecheck 통과.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
[1] 띠 면이 스스로 겹쳤다. 외곽선을 "아래 현 -> 왼쪽 곡선 -> 위 현 -> 오른쪽 곡선"으로
이어 붙이다 보니, 곡선이 두 현 사이에서 요동치면 그 조각이 띠 밖으로 삐져나가 다각형이
자기교차했다. 정의를 바꿨다 - 띠는 "아래 현의 두 끝 사이에서, 아래 높이부터 곡선과 위
높이 중 안쪽까지"다. 아래 현을 밑변으로 깔고 곡선값을 두 높이 사이로 자른 값만 찍으면
어떤 지형에서도 단순 다각형이라 겹칠 수 없다.
[2] balloon이 화면 밖으로 나갔다. 두 곳이 샜다 - 빈자리를 못 찾았을 때 findSlot이 세로를
자르지 않았고, 저장해 둔 이동량을 그릴 때도 자르지 않아 화면을 줄이면 밖을 가리켰다.
둘 다 상자 안으로 자르고, 드래그 중에도 같은 함수를 쓴다.
[3] 임시 저장 - POST .../sections/{route_id}/save 신설. 저장 내용은 확정과 같고(표준횡단
설정·유토곡선·balloon 위치·암 경계선) 경로 상태·워크플로 단계를 건드리지 않아 페이지
이동이 없다. 미지정 측점을 기본값으로 채우지도 않는다. 버튼은 재계산과 확정 사이(1행 3열)
이고, 재계산이 밀려 있어도 눌린다 - 편집분을 잃지 않는 것이 목적이다.
[4] 토취·사토 화살표를 실제 단차 끝까지 되돌렸다. 끝나는 높이가 새 평형선이라 그 자체가
정보다. 라벨이 곡선을 가리는 문제는 이미 balloon처럼 떼어 놓아 해결됐다.
_Router.py(718줄) -> 저장·확정을 _Router_Confirm.py(203줄)로 분리. 임시 저장과 확정이
저장 본체(_apply_section_edits)를 공유한다.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
판정 기준은 성토측 자연 지반 경사(사용자 확정). 지반이 임계보다 가파르면 부어 놓은 흙이
쌓이지 않고 스스로 흘러내리므로 운반비를 세지 않는다.
계상 방식은 참고 도면을 근거로 정했다. 도면의 사토 balloon은 L=(운반거리) 없이
M.N=측점만 적는다 - 그 노선의 사토가 이미 운반비 없이 처리되고 있다는 뜻이고,
자연방토라는 이름을 안 썼을 뿐 처리 방식이 자연방토다. 그래서 새 항목을 만들지 않고
사토 안에서 가른다. 판정 통과분은 도면과 똑같이 M.N만, 실패분에만 "사토장=X㎥"를 더한다.
수량은 그대로 두고 성토로 흡수하지 않아 유토곡선 모양과 누가토량은 안 바뀐다.
- config NATURAL_SPOIL_MIN_GROUND_SLOPE = 1/1.5 (rise/run, 약 33.7도) 신설.
유일한 정의처이며 프론트는 context로 받아 쓴다. 못 받으면 자연방토 없음(보수적)
- 엔진 fill_ground_slope(): 노면 끝~성토 사면의 첫 지반 교차까지 평균 경사.
양쪽이 다 성토면 완만한 쪽을 택한다(보수적)
- AreaSample/MassHaulPoint에 natural_spoil - 양 끝 측점이 둘 다 가능할 때만 참
- HaulResidual.natural_m3 - 잔량 구간에서 자연방토 가능한 길이 비율만큼 계상.
장거리 상쇄로 깎이면 안분·자연방토도 같은 비율로 감소
- HaulPlan.natural_spoil_m3 + 요약 칩
700줄 초과 2건 분리: _Engine_Areas.py(면적 적분), _UI_MassHaul_Settle.ts(안분·장비·상쇄·
직렬화). 의존은 한 방향(Balance -> Settle 함수, Settle -> Balance 타입만)이라 순환 없음.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
[1] 절토에는 "지반과 1회 교차하면 그 이후는 지반 추종" 규칙(cut_cross_dist)이 있었는데
성토에는 없었다. max(fill_line, ground)만 쓰면 지반이 다시 꺼졌을 때 성토 사면이
되살아나 사면이 끊겼다 이어지는 그림이 나온다. 실측 지면이라 이런 지형이 흔하다.
fill_cross_dist()를 같은 규칙으로 추가하고 design_z·breakpoints에 물렸다. 첫 교차점이
성토사면의 끝이고 그 바깥은 손대지 않은 원지반이다. 설계선뿐 아니라 fill_area_m2도
같은 design_z를 타므로 함께 바로잡힌다.
검증: 지반이 두 번 꺼지는 합성 단면에서 첫 교차(-5.4m) 이후 설계선이 지반보다 높은
점 0개(이전에는 -8m 밖에서 성토가 되살아났다).
[2] 줌 버튼이 스크롤 시 상단 패널 위로 삐져나왔다. 카드 안 오버레이의 z-index가 최상위
쌓임 축에서 겨루고 있어, sticky 패널(z-index 2)과 같은 층에서 DOM 순서로 카드가 이겼다.
.b06-cross-card에 isolation: isolate를 걸어 카드를 자체 쌓임 맥락으로 만든다.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
유토곡선을 측점 사이에서 직선으로 잇는다(C안 확정). PARABOLIC_MASS_CURVE 한 곳으로
그리기(curvePath)와 재기(crossFrom)가 함께 바뀐다 - 둘이 어긋나면 수평선 끝이
곡선에서 뜬다. 대가는 평균운반거리가 포물선 대비 약 40% 짧아지는 것이고, 이는
20m/70m 장비 경계 판정에 직접 영향을 준다.
- 사토·토취를 balloon 계열로 통일: 단차 화살표는 22px 고정으로 잘라 위치만 가리키고
수량 라벨은 balloon과 같은 자리 찾기·지시선·드래그를 쓴다(음수 키). 도형 없이 언더바만
- 토취 색 초록 -> 주황. 초록은 "정상"으로 읽혀 흙이 모자란 경고와 안 맞았다
- balloon 내용을 도면 양식(항목별 세로 표기)으로. 165px 이상이면 6줄
(이름·번호 / Q / L / EA / RR / BR), 사토는 L 대신 M.N=측점, 토취는 지반유형 없음
- HaulResidual에 사토 지반유형 안분 추가. 장거리 상쇄로 깎이면 안분도 같은 비율로 감소
- 횡단도 휠 줌 제거, 우측 상단 + / − / ⤢ 버튼. 팬은 가운데 버튼 유지
- 암 경계선 제어를 그래프 안에서 중심고·방위각 행 가운데로 이동
- 700줄 초과 2건 분리: _UI_MassHaul_Balloon.ts, _UI_Style_Cross_Areas.css
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
지시선이 블록 정점(극값)을 가리키고 있어 측점선과 수평선이 만나는 자리를 찍는
꼴이 됐다. balloon이 설명하는 대상은 정점이 아니라 그 띠의 평균운반거리
수평선이므로 앵커를 그 선의 한가운데로 옮긴다.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
[1] 수평선이 곡선에서 떨어져 보이던 문제. 엔진은 포물선으로 교점을 잡는데 곡선만
직선(polyline)으로 그리고 있었다. 평형선·장비 경계현·평균운반거리선의 양 끝이
곡선 위가 아니게 되어 어긋나 보였다.
곡선을 2차 베지에 경로로 바꿨다. 제어점 (x0 + Δ/2, V0 + a0Δ/2)에 두면 2차 베지에가
구간 포물선과 정확히 같아진다. 0선 아래 음영도 같은 경로로 닫고, 띠 테두리도
측점만 잇던 것을 구간마다 4등분해 곡선에 붙였다.
[2] balloon 위치 저장 경로를 둘로 나눴다.
- 프론트 캐시(localStorage, 프로젝트+경로별 키): 끌어 옮기는 즉시
- 영구저장소: 횡단 확정 시 mass_haul.balloon_offsets로 저장
진입 시에는 영구저장소 값이 이긴다 - 다른 브라우저에서도 같은 자리에 뜬다.
상세 응답에 balloon_offsets를 실어 내려보낸다.
[3] 범례 줄에 "도형 위치 초기화" 버튼(분배 레이어를 켰을 때만). 프론트 캐시를 비우고
다시 그리며, 비워진 값이 다음 확정 때 영구저장소를 덮는다.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
참고 도면(기번3, 측점별 누가토량 81점 + balloon 43개)과 대조해 오류 2건 확인·수정.
[1] 측점 사이는 직선이 아니라 포물선이다. 단면적이 선형으로 변하면 그 적분인
누가토량은 2차식이 된다. 도면에서 측점간격 20m 구간의 반종거가 20/√2 = 14.14m로
12번 반복해 찍히는 것이 근거(직선이면 10m). 직선으로 재던 평균운반거리가 약 40%
짧게 나와 20m 경계 판정이 어긋나고 있었다.
MassHaulPoint에 다짐환산 순단면적을 실어 구간마다 V(t) = V0 + a0t + (a1-a0)t²/(2Δ)를
세운다. V(Δ) = V0 + (a0+a1)Δ/2라 곡선 자체는 그대로고 현 길이만 바뀐다.
두 단면적의 평균이 구간 평균과 어긋나면 포물선이 끝점을 벗어나 수평선 교점을 못 찾고
블록이 통째로 늘어난다(도면 곡선 검증에서 성토 1455㎥가 한 블록에 묻혔다). 두 값을
같은 양만큼 옮겨 끝값을 강제로 맞춘다. 곡률은 보존되므로 포물선 모양은 그대로다.
[2] 남은 사토와 토취를 거리 가까운 짝부터 맞물려 장거리 운반으로 바꾼다. 도면 곡선은
0선 아래로 한 번도 내려가지 않는데 기존 로직은 토취 1435㎥를 만들어 냈다. 도면의
덤프 L=935/1008m가 이 장거리 운반이고, 배분 3원칙 ①(거리 최소) ③(모아서 운반)이다.
- 사토 표기에 측점(M.N) 추가 - 도면은 사토에 운반거리를 안 매긴다
- 검산 칩: 운반(띠) + 장거리 운반 + 토취 = 총 성토량
- 장거리 운반선은 1점쇄선 + 화살촉 (네 번째 선타입)
- 700줄 초과로 곡선 기하를 _UI_MassHaul_Curve.ts로 분리
도면 곡선 재현: 토취 1435 -> 0, 사토 2606 -> 1171(= 최종 누가토량),
운반계 오차 -10.1% -> -0.80%, 종무대 L 0.2~13.2 -> 10.51~18.01m(도면 8.39~15.98).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
도형이 크고 남는 공간을 못 찾는다는 지적 반영.
- balloon을 두 줄 상한(번호·물량 / L·장비)으로 줄이고 여백·육각 노치 축소.
EA/RR/BR은 툴팁으로 옮김
- 배치를 세로 밀기에서 가로·세로 링 탐색으로 바꾸고 curveYAt으로 곡선까지 회피.
못 피하면 곡선 조건만 버리고 재탐색(안 그리는 것보다 낫다)
- balloon을 끌어 옮길 수 있고 지시선 끝점이 따라간다. 옮긴 자리는 세션에 남고
더블클릭이면 자동 배치로 복귀. 지시선은 balloon 밖에 둬야 같이 끌려가지 않는다
- 띠 면과 balloon을 같은 짝으로 묶어 어느 쪽을 눌러도 둘 다 강조된다
검증: 4개 크기에서 NaN 0건, balloon 11개 중 곡선 겹침 0~1개(이전엔 회피 없음),
도형·클릭 짝·드래그·세션 저장·더블클릭 복귀 확인.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
참고 도면의 토량배분도는 블록마다 수평선이 여러 개(A-A' 기선 / B-B' / C-C')이고
그 사이 띠마다 번호가 붙어 종단면 해칭 구간과 1:1로 대응한다. 하단 브래킷의 폭이
각 수평선의 길이와 같다. 즉 수평선 높이는 그 현의 길이가 장비 경계거리와 같아지는
높이이고, 세로축이 곧 토량이므로 두 수평선 사이 띠 두께가 그 장비의 운반토량이다.
블록 하나에 평균운반거리 하나 / 장비 하나이던 모델을 띠(HaulBand) 여럿으로 바꿨다.
경계 탐색이 단조가 아니라는 것을 무작위 검증이 잡았다. 가지치기로 블록을 하나로
묶어도 원래 폴리라인에 잔요철이 남아 높이를 올리는 도중 현이 잠깐 다시 길어진다.
순수 이분법은 엉뚱한 근으로 수렴했다(종무대 경계현 45m). 훑기 64칸 + 이분법 24회
2단계로 바꿔, 현이 상한을 넘는 가장 높은 자리 위를 경계로 잡는다.
- 장비 경계 dozer 50 -> 70m (사용자 확정, 정의처는 config 한 곳 유지)
- balloon 도형 = 운반수단: 종무대 육각 / 도쟈 원 / 덤프 사각, 사토는 언더바만
- 띠 면 클릭 시 balloon 강조, 다른 띠·빈 곳 클릭 시 해제
- 선타입: 기선 실선 / 경계현 파선 / 평균운반거리 점선 + 방향 화살촉
- 유토곡선 0선을 파선에서 실선으로 (파선은 경계현의 몫)
- 암 경계선 오프셋 상한 0 (양수면 경계선이 지표면 위로 떠 토사층이 음수가 된다)
- 종단도 구조물 라벨을 플롯 하단으로 옮기고 맨 마지막에 그려 가리지 않게
- 암 경계선 제어를 그래프 하단 행 가운데로
검증: 수동 4종 + 실측 26측점 + 무작위 100건에서 띠 합=Q, 띠 연속성, 경계현<=상한,
안분합, 보존 성립. 렌더 스모크 4개 크기 NaN 0건 + 도형·클릭 강조 확인.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
누가토량 곡선은 "얼마가 남는가"만 말한다. 어디 흙을 어디로 얼마나 옮기는지를
뽑아내는 계층을 얹었다 — 평형선, 운반 블록, 운반토량 Q, 평균운반거리 L,
EA/RR/BR 안분, 장비 선정.
작도 규칙 근거는 clouds-daily.tistory.com/249 와 교과서 표준 작도법이다
(참고 도면 3공구의 수치·작도는 근거로 삼지 않았다).
평형선을 0선 하나로 고정하면 임도처럼 절토가 우세한 노선에서 사토가 전부
종점 한 덩어리로 몰린다. 그래서 곡선을 왼쪽부터 훑으며 커서를 옮기고, 성토가
절토를 다 못 받는 자리에서 평형선을 계단으로 옮긴다. 구간이 겹치지도 비지도
않고 단차의 합이 최종 누가토량과 정확히 맞는다.
- 신규 _UI_MassHaul_Balance.ts: computeHaulPlan() 순수 계산기
- 신규 _UI_MassHaul_Balance_View.ts: 계단형 평형선 + 반종거 수평선 + 육각 balloon
- MassHaulPoint에 cut_rr_m3/cut_br_m3 추가 (블록별 암종 안분 입력)
- EARTHWORK_HAUL_EQUIPMENT_LIMITS_M을 context 응답으로 노출 (프론트 사본 없음)
- massHaulPayload에 haul_plan 직렬화 (B08 인계)
검증: 수동 6종 + 무작위 100건에서 보존·안분합·L 범위·구간 무결성 성립.
렌더 스모크 4개 크기 NaN 0건. 영구저장소 프로젝트(26측점) 실측 시 블록 6개,
토취 75.4㎥가 최종 누가토량 -75.4㎥와 일치.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
RR이 --color-slate를 쓰고 있었는데, 이 토큰은 --color-text-secondary의 실체라
라이트 테마에서 표 글자가 비활성처럼 읽히고 28% 밴드가 흰 배경에 묻혔다.
RR을 --color-success로 옮긴다(--color-warning은 암 경계선 점선이 선점).
암반 밴드는 하나인데 표는 RR/BR로 갈려 있어 색이 어긋났다. 밴드 그룹에
암종 변형 클래스(--cut_rr / --cut_br)를 실어 표 글자색과 짝을 맞춘다.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- 손잡이가 안 보이던 원인은 패널의 overflow: hidden이었다. .b06-section__panel이
.b06-cross-card와 한 규칙으로 묶여 있어 함께 받고 있었고, 손잡이를 패널 경계 밖으로
내보내자 그대로 잘렸다. 패널을 그룹에서 떼어 자체 규칙으로 분리하고 overflow를 걸지 않는다.
- 접기/펴기에서 전역 ui-collapsible 의존을 끊고 B05처럼 명시한다: .is-collapsed에 height 0을
걸고 헤더·본문·리사이저만 숨겨 손잡이만 남긴다. 펼칠 때는 다음 프레임에 그린다 —
그래프 몫을 실측하므로 같은 프레임에 그리면 접혀 있던 0 높이를 읽는다.
- 진입 시 첫 측점을 자동 선택하던 것을 없앤다. 고르지도 않은 카드가 강조되고 유토곡선
말풍선이 떠 있었다.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 선택 반영이 아직 카드 재생성이라 그 카드의 viewBox(휠 줌·팬)가 초기화됐다. 카드 요소에
applySelection() 핸들을 달아 클래스와 강조 상태만 갈아 끼운다. 재생성을 없애기 위해 면적
밴드는 선택 여부와 무관하게 항상 깔아 둔다(평소 투명이라 화면 변화는 없다).
- RR 절토를 눌러도 단면이 안 켜지던 원인은 구 데이터 폴백 불일치였다. 표는 분리 필드가 없으면
절토 전량을 측점 지반유형으로 돌려 RR에 값을 넣는데, 밴드 쪽은 cut_rock_kind가 없으면 곧장
null을 반환해 암반 밴드를 만들지 않았다. rockKindOf()로 표·밴드·강조 매핑의 폴백 규칙을
하나로 통일한다.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
손잡이 뒤에 보이던 보라색 바는 리사이저의 hover 색이었다. B05 하단 패널은 손잡이를 패널 밖에
두어 리사이저를 z축으로 덮지만, B06은 손잡이를 패널 안 흐름에 넣고 리사이저를 그 위에 나란히
옮겨 놔서 손잡이를 누르러 가는 길에 hover가 먼저 켜졌다.
B05와 같은 구조로 상하만 뒤집는다: 공용 --bottom 손잡이를 패널 경계 바깥 아래로 내보내고
(border-top 제거, 아래쪽 모서리 둥금) 리사이저는 경계(bottom: 0)로 되돌린다. 패널에는
overflow: hidden이 없어 밖으로 나가도 잘리지 않는다.
손잡이가 흐름 높이를 먹지 않으므로 PANEL_CHROME_PX를 줄이고, 선택 카드 스크롤 여백은 손잡이가
아래로 나온 만큼 더한다.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
전역 규칙 `.ui-collapsible.is-collapsed > .ui-collapsible__title::after`(클래스 3개)가 B06 쪽
무력화 규칙(클래스 2개)보다 특정도가 높아, 접힘 상태에서 캐럿(▸)이 삼각형 아이콘(▼)과 함께
그려졌다. 특정도 싸움을 이어 가는 대신 손잡이에서 `ui-collapsible__title` 클래스를 떼고 토글을
직접 처리한다. 접혔을 때 손잡이가 숨지 않도록 display만 다시 켠다.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 유토곡선 아래 빈 공간: chartHeights()가 패널높이 − PANEL_CHROME_PX 어림값을 썼는데, 어림값이
실제 chrome보다 크면 그 차이가 그대로 빈 공간이 됐다. chartWrap.clientHeight를 직접 재서
몫으로 쓴다. chartWrap 높이는 내용이 아니라 패널에서 정해지므로 되먹임 없이 수렴하며, 화면에
붙기 전이라 잴 수 없는 첫 렌더만 어림값으로 출발한 뒤 다음 프레임에 한 번 보정한다.
컨테이너 최소 크기는 건드리지 않았다.
- 팬을 가운데 버튼 전용으로 바꾸고(좌클릭은 선택) 상단 그래프에도 가운데 버튼 팬을 달았다.
가운데 버튼을 누를 때 브라우저 자동 스크롤이 같이 뜨던 문제는 mousedown/auxclick에서 막는다
(자동 스크롤은 mousedown 기본동작이라 pointerdown에서는 막히지 않는다).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 선택이 바뀔 때마다 draw()로 모든 카드를 다시 만들어 카드별 휠 줌·팬이 통째로 초기화됐다.
이전·현재 선택 카드 두 장만 교체하고 상단 패널만 다시 그린다. 선택된 카드 안에서 값 칸을
토글할 때는 원래부터 재렌더가 없다(DOM 클래스만 바뀐다).
- 접기 손잡이에 전역 캐럿(▸)과 삼각형 아이콘(▼)이 겹쳐 보이던 문제: 같은 특정도로 지우려 해
로드 순서에서 밀렸다. 자식 결합자로 특정도를 올려 지운다.
- 그래프 상자 세로 스크롤 제거: 축소 시 두 그래프를 각자 비율로 줄이다 하한에 걸리면 합이
배분 몫을 넘었다. 몫을 먼저 잡고 유토곡선 몫을 종단도 하한이 남도록 클램프해 합이 항상
몫과 같게 했다. 한 축만 auto면 나머지 축도 auto로 올라가므로 overflow-y: hidden도 건다.
- 패널 위 휠은 끝에 닿아도 기본 동작을 넘기지 않는다(아래 횡단도 목록이 대신 스크롤되던 현상).
범례 줄이 먼저 먹지 않도록 캡처 단계에서 잡는다.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 면적표의 모든 칸을 버튼으로 만든다. 예전에는 그 측점의 암종과 맞지 않는 칸(값 0)을 막아
칸마다 눌리는 자리가 달라졌다. 강조 키를 cut_rock 하나에서 cut_rr/cut_br 둘로 갈라, 표는
늘 따로 서되 그림의 암반 밴드는 암종이 맞는 쪽을 눌렀을 때만 켜진다.
- 성토 밴드는 중심선에서 바깥으로 나가다 지면과 처음 만나는 곳까지만 유효하다. 그 너머에서
지면이 다시 설계선 아래로 내려가 생기던 조각을 버린다(좌·우 각각 안쪽 조각만 유지).
- 접기 손잡이 치수를 좌측 사이드 손잡이(24×64, 오른쪽 모서리 둥금)의 시계방향 90° 회전값인
64×24 · 아래쪽 모서리 둥금으로 교정한다. 리사이저 위치와 패널 여유 높이도 함께 맞췄다.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 면적표 값·머리글을 가운데 맞춤으로 바꾼다.
- 값 칸을 모든 카드에서 버튼으로 만든다. 선택되지 않은 카드에서 눌리면 부모에 측점과 키를
함께 올려, 카드 선택과 면적 강조가 한 번에 반영된다. 강조 상태는 부모가 들고 있다가 카드를
다시 그릴 때 되살리고, 측점이 바뀌면 따라가지 않는다.
- 카드 그리드 빈 자리를 누르면 선택을 해제한다.
- 접어도 빈 배경이 남던 문제: 인라인 min-height가 .is-collapsed { height: auto }를 이겨
360px 상자가 그대로 남았다. CSS 변수로 넘기고 :not(.is-collapsed)에만 건다.
- 접기 손잡이를 헤더 캐럿에서 패널 하단 가운데 삼각형 손잡이로 옮긴다. 좌측 사이드 패널과
같은 공용 컴포넌트를 90° 돌린 모양이며, 위로 접히는 패널이라 collapseToward 옵션에
"up"/"down"을 추가했다(기존 좌우 호출부는 그대로). 리사이저는 손잡이 위로 14px 올렸다.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 종단면도 이름표를 플롯 안쪽 상단으로 겹치고 LONG_PAD.top 30 → 12로 줄여 위 여백을 그래프
몫으로 돌린다. 구조물 라벨은 그만큼 내려 겹치지 않게 했다.
- 유토곡선에 같은 양식의 이름표를 하단에 넣는다. 곡선이 지나가는 자리라 불투명 배경판을 깔고
아래 여백을 16 → 8로 줄였다.
- 상단 패널과 횡단 카드 사이의 횡단면도 제목·개수 행을 없앤다. 카드마다 측점이 적혀 있어
무엇을 보는지 이미 분명하고, 공간만 먹었다. 관련 CSS와 로케일 키도 정리.
- 종단 기준 곡선을 기본 비활성화한다(계획고 기반 개략값이라 참고용). 세션 저장 키를 v3로 올려
옛 값이 이 곡선을 되켜지 못하게 했다.
- 면적표 단위를 값 칸에서 좌상단 교차 셀로 옮기고, 열 제목을 가운데 맞춤으로 바꿨다.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 측점 라벨을 종단면도 축선과 유토곡선 사이 틈의 가운데로 옮긴다. LONG_PAD.bottom 52 → 26,
측점선 끝 +8 연장 제거, 유토곡선 상단 여백 12 → 10. 틈이 53 → 36px로 좁아진다.
좌우 여백은 X축 정렬 값이라 건드리지 않았다.
- 곡선 토글을 별도 행에서 유토곡선 우측 상단 오버레이로 되돌린다. 단 스크롤 컨테이너 밖에서
절대 위치로 띄워 컨테이너 폭 계산에 끼어들지 않게 했다(예전 X축 어긋남의 원인).
- 면적표·밴드 색을 고정 RGB에서 테마 토큰으로 교체. 발파암(BR)에 쓰던 검정 계열이 다크
테마에서 배경에 묻혔다. 차트 팔레트는 두 테마 모두에 맞춘 밝기다.
- 같은 측점을 다시 고르면 선택을 푼다. 카드와 측점 세로선이 같은 경로를 타므로 한 곳에서 처리.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 면적 하이라이트가 먹지 않던 원인: 값 칸·밴드 클릭이 카드까지 버블링돼 측점 선택이 다시
걸리고, draw()가 카드를 새로 만들면서 방금 켠 강조가 즉시 지워졌다. stopPropagation 추가.
- 면적 표기를 칩 나열에서 절토/성토 2행 × EA·RR·BR·계 4열 표로 바꾼다. 이름은 도면 표기를
그대로 쓰고, 0값이어도 항목을 유지해 카드끼리 비교가 되게 한다. 성토는 완성 단면이라
지반유형으로 갈리지 않으므로 계 한 칸만 쓴다.
- 암반 밴드는 하나뿐이라 그 측점의 암종에 해당하는 칸만 강조 버튼이 된다.
- 유토곡선 0선에 Y축 눈금값 0을 적어 무슨 선인지 읽히게 한다(선 자체는 원래 상시 표시).
- 오버레이가 1줄에서 3행 표가 되어 상단 여유를 28 → 58px로 키웠다.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 횡단 카드 측점 종류 표기에서 "일반 측점" 제거(BP/EP만 남김).
- 구간 물량을 패널 아래 칩 줄에서 유토곡선 위 둥근 사각 말풍선으로 옮긴다. 말풍선이 놓일
가로 구간의 곡선 세로 범위를 실측해 위/아래 빈 곳 중 들어가는 쪽에 놓고, 좌우 후보를
모두 재서 여유가 큰 조합을 고른다. HTML 오버레이 대신 SVG 안에 그려 X축 정렬을 지킨다.
- 패널 제목 문구 삭제. 헤더는 캐럿만 남긴 손잡이 행이며, 캐럿은 좌측 사이드 패널과 같은
공용 규칙을 쓰되 방향만 상하(펼침 ▴ / 접힘 ▾)로 바꿨다.
- 측점 라벨을 종단 그래프 바닥에 붙이고 유토곡선 상하 여백을 좁혀 두 그래프가 측점 표기를
공유하는 것처럼 보이게 한다. 좌우 여백(LONG_PAD)은 X축 정렬 때문에 그대로 둔다.
- 패널을 줄이면 그래프 폭까지 줄던 문제: SVG가 flex 기본값으로 세로로 눌리면서
preserveAspectRatio(meet)가 가로도 같은 비율로 축소한 것. flex: none으로 막고 패널에
최소 높이를 건다.
- 토사 단일 환산·환산 없음 곡선 삭제. 절토가 암반 경계선으로 갈려 나온 뒤로는 부피비를
단일값이나 1로 넣은 곡선에 정보가 없다. 곡선 키 형식이 바뀌어 세션 저장 키를 v2로 올렸다.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 종단면도 X축 제목을 그래프 상단으로 올린다. 아래쪽은 측점 라벨 몫으로 비워, 바로 밑에
붙는 유토곡선과 X축을 공유하는 것처럼 읽히게 한다(B05 종단 패널도 같은 렌더러).
- 유토곡선 범례를 그래프 위 오버레이에서 패널 본문 하단으로 내린다. 개수가 늘어도 높이
배분이 흔들리지 않게 한 줄 고정 + 가로 스크롤. 유토곡선 X축 제목은 삭제(중복).
- 측점 세로선 어긋남 해소: 유토곡선 SVG만 감싸던 `.b06-masshaul__frame`이 스크롤 컨테이너
폭 계산에 끼어들어 두 SVG의 렌더 폭이 달랐다. SVG는 preserveAspectRatio 기본값이 meet라
렌더 폭 차이가 그대로 X 매핑 차이가 된다. 상자를 없애 같은 부모의 형제로 맞췄다.
- 선택 횡단도가 sticky 패널에 가리지 않게 패널 실측 높이를 `--b06-cross-scroll-margin`으로
넘겨 `scroll-margin-top`에 물리고, 스크롤을 center → nearest로 바꿨다. 패널 리사이즈가
끝나면 선택 카드를 새 높이 기준으로 다시 끌어올린다.
- 패널 위 휠은 페이지 대신 그래프를 좌우로 민다. 더 밀 곳이 없으면 기본 동작을 넘긴다.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
절토부의 토사·암반 구분은 환산계수가 아니라 횡단도 기하로 갈린다. 지표면~암반 경계선이
토사, 그 아래가 암이다. 기존에는 측점당 절토 단면적이 하나뿐이라 리핑암/발파암 측점의
상단 토사층까지 암 환산계수로 곱해졌다(실데이터 기준 다짐환산 +21% 과대).
- Engine_Design: `_split_cut_areas()` 신설. `d=0`, `d=t0` 교차점을 브레이크포인트로 넣어
정확 적분(무작위 2,000회 검산 `soil+rock==cut` 최대오차 1.4e-14).
`cut_soil_area_m2` / `cut_rock_area_m2` / `cut_rock_kind` 3필드 추가(기존 키 불변).
- UI_Cross_Areas(신규): 면적 readout을 4칩으로 확장하고 절토(토사)/절토(암반)/성토 밴드를
그린다. 선택된 카드에서만 붙어 다른 측점을 고르면 자동 해제된다.
- UI_MassHaul: `AreaSample`을 2분할로 교체해 부분별 환산계수를 물리고, 측점별 구간 물량
내역(토사/암반/다짐환산/성토)을 남긴다. 구 데이터는 전량 측점 지반유형으로 폴백.
- UI_MassHaul_View: 선택 측점의 구간 물량 표기 줄과 곡선 위 강조점 추가. 측점 매칭은
id가 아니라 누가거리로 한다(종단 기준 곡선의 점 id는 파생값이라 형태가 다름).
암반 경계선 오프셋을 바꾸면 분리 면적과 유토곡선 환산량이 함께 움직인다.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
패널을 줄여 둔 세션에서 B06 에 다시 들어오면 패널 높이는 복원되는데 차트 높이 배분만
기본값(종단 220 / 유토 190)으로 계산돼, 합계 410px 가 200px 공간에 밀려 들어가면서
종단면도가 20px 로 잘려 사실상 사라졌다. 창 크기를 조금만 바꾸면 정상으로 잡혀
(자가 치유) 구현 당시 검증에서 걸리지 않았다.
원인은 첫 렌더 시점의 조회 방식이다. draw() 는 root.replaceChildren(panel, ...) 보다
먼저 drawPanel() 을 부르므로, 그 시점의 panel 은 아직 root 에 붙기 전(detached)이다.
detached 요소는 getComputedStyle 이 빈 값을 돌려주기 때문에 --b06-profile-height 를
읽지 못하고 BASE_PANEL_HEIGHT(506) 로 폴백했다. 리사이저가 복원해 둔 값 자체는
인라인 스타일에 정상적으로 들어가 있었다.
panelHeight() 가 인라인 스타일을 먼저 읽고, 없을 때만 computed 로 폴백하게 바꿨다.
인라인 조회는 detached 상태에서도 동작하므로 첫 렌더부터 저장값이 반영된다.
구조는 C02 에서 유입됐으나 당시에는 차트가 하나뿐이라 영향이 작았고, C05 로 차트가
둘이 되면서 배분 실패가 종단면도 소멸로 확대됐다.
자체 검증 — 판정 기준은 "첫 렌더 = 재렌더"(결함이 있으면 첫 렌더만 어긋난다):
- 저장값 296px : 296/99/111 = 296/99/111 일치
- 저장값 없음 : 496/220/190 = 496/220/190 일치 (회귀 없음)
- 저장값 700px : 700/220/384 = 700/220/384 일치 (기본 초과 시 종단도 고정, 유토가 흡수)
prettier 변경 없음, tsc --noEmit 오류 0건, 437줄.
근거: docs/raw/verification/2026-08-02_verify_mass_haul_multi_curve.md [F1]
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
임도는 산복 사면을 따라가 편절·편성이 지배적이라, 종단 계획고로 본 절성토 균형과
실제 횡단 단면적으로 본 균형이 크게 어긋난다. 어느 쪽을 정식 기준으로 삼을지
사용자가 그래프를 보고 결정할 수 있도록 두 기준을 한 축에 겹쳐 그린다.
지반유형 처리도 암반 경계선 분리 전까지는 미결이라 세 가지를 함께 낸다.
법령 근거([임도의 설계 및 시설기준] 별표):
- 2.다.(3)(나) "시공계획고는 절토량과 성토량이 균형을 이루게 하되" → 종단 기준 곡선
- 2.다.(4)(마) 측점마다 절토고·성토고·단면적 기입 → 횡단 기준 곡선
- 2.다.(4)(다) "절토부분은 토사·암반으로 구분" → 암반 분리(미결 1번)의 근거
같은 별표에 토공 운반장비 선정거리 기준은 없다. 장비 경계값의 근거는 법령이 아니라
3공구 도면 실측치다.
곡선 6종 = 기준 2(횡단/종단) x 환산 3(지반유형별/토사 단일/환산 없음).
색이 기준, 선모양이 환산 방식을 뜻한다.
- _UI_MassHaul.ts: 공통 적분 함수 integrate(samples, conversion, groundMode)로 통일.
두 기준이 AreaSample[]까지 정규화된 뒤 같은 코드를 탄다 — 평균단면법·환산 로직을
이중으로 두지 않는다. computeMassHaulSeries() 신설.
computeMassHaul()은 시그니처·결과를 그대로 유지해 _UI_Page.ts의 확정 저장 경로는
건드리지 않는다.
종단 기준: difference_m(= 계획고 - 지반고, 음수가 절토) x 노반폭.
노반폭·지반유형은 종단 샘플에 없으므로 최근접 설계 측점에서 상속한다.
- _UI_MassHaul_View.ts: 다중 곡선 렌더 + 그래프 상단 오버레이 범례.
Y 스케일은 표시 여부와 무관하게 항상 전체 곡선 기준으로 잡는다 — 곡선을 껐다 켤 때마다
축이 움직이면 비교 자체가 불가능하다.
면(band)은 맨 앞 곡선 하나에만 칠한다(여러 개면 서로 가려 못 읽는다).
곡선은 범례 역순으로 그려 첫 곡선이 맨 위에 온다.
- _UI_Section_View.ts: 표시 집합을 sessionStorage에 보존. 전부 끈 상태도 사용자의
선택이므로 기본값으로 되돌리지 않는다. 요약 수치는 켜 둔 첫 곡선의 것이며,
어느 곡선인지 요약 끝에 반드시 밝힌다.
- _UI_Style_MassHaul.css(신규): _UI_Style_Cross.css가 742줄로 700줄 제한을 넘어
유토곡선 블록을 분리했다(분리 후 606줄). 범례는 sticky + height:0이라 가로 스크롤에도
왼쪽에 남으면서 곡선 위로 뜬다.
- ui_template_locale_b2.ts: 곡선명·범례 문구 9개 키. 하드코딩 없음.
검증(테스트1 / route 48 / 24측점 중 23측점 설계):
- 계산 엔진 단위 테스트 18건 통과, tsc --noEmit 통과, 전 파일 700줄 이하
- 범례 6개 생성, 토글 2 -> 6 -> 0 -> 2 정상
- Y 눈금이 세 상태 모두 60.5 / -46.3 / -153.0 으로 동일 (축 고정 확인)
- X축 정렬: 종단도 측점선 [62 ... 1454] 24개 = 유토곡선 [62 ... 1454] 24개
- 새로고침 후 켜 둔 곡선 복원 확인
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
유토곡선 운반계획(Phase 2)이 평균운반거리로 장비를 고를 때 쓸 경계값이다.
사용자 확정값이며 현장·발주처 기준에 따라 달라질 수 있어 config 한 곳에만 둔다.
참고 도면 관측치(종무대 14~16m, 도쟈 20m, 덤프 67.8m)와 모순되지 않는다.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
상세 배수유역 정보는 페이지에 들어오면 바로 보여야 하는데 기본값이 접힘이었고,
접기/펼치기 화살표도 반대를 가리키고 있었다.
- 기본값: 저장값이 없을 때 `!== "false"`(접힘)를 `=== "true"`(펼침)로 바꿨다.
같은 페이지 하단 종단 패널(B05_wf2_Route_UI_Profile_Panel.ts:592)이 이미 쓰던 규칙과
같아졌다.
- 화살표: 공용 `createWorkflowPanelHandle`은 왼쪽에 도킹해 왼쪽으로 접히는 패널
(제목 카드)을 전제로 회전값을 고정하고 있었다. 배수유역 패널은 오른쪽에 도킹해
오른쪽으로 접히므로 같은 회전을 쓰면 열기/닫기 표시가 정확히 거꾸로 나온다.
`collapseToward` 인자를 추가하고 이 패널만 "right"를 넘긴다.
기본값 "left"라 나머지 호출처는 회전값이 이전과 동일하다:
- ui_template_overlay.ts:81 제목 카드 — "side" 기본값, 열림 180° / 닫힘 0° 그대로
- B05_wf2_Route_UI_Profile_Panel.ts:244 하단 패널 — "bottom" 배치라 애초에 무관
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
헤드리스 브라우저로 실화면을 확인하다 드래그가 전혀 먹지 않는 것을 발견했다.
손잡이 중심의 hit-test가 손잡이가 아니라 패널을 돌려주고 있었다.
- 손잡이 위치: 패널이 `overflow: hidden`이라 경계에 걸치게 둔 `bottom: -3px`는
아래 절반이 잘려 나가 클릭 영역이 3px도 남지 않았다. `bottom: 0` + 높이 8px로
안쪽에 붙여 전체가 잡히게 했다.
- 높이 상한: 부모 `.b06-profile__main`은 횡단 카드까지 담은 스크롤 콘텐츠라
clientHeight가 5809px였고, 상한이 4647px로 잡혀 사실상 무제한이었다. 이 패널은
화면 위에 sticky로 붙으므로 상한을 화면 높이 기준으로 바꿨다.
- Y축 눈금: 패널을 줄이면 유토곡선 그래프 몫이 60px대까지 내려가 눈금 5개의
라벨이 서로 겹쳤다. 그래프가 낮을 때는 3개만 그린다.
실화면 검증(프로젝트 테스트1, route 48, 측점 24개 / 설계 23개):
- 기본 496px → SVG [220, 190]
- 아래로 드래그 694px → SVG [220, 378] (종단도 고정, 유토곡선이 늘어난 몫 흡수)
- 위로 드래그 392px → SVG [170, 147] (기본값 대비 비율만큼 둘 다 축소)
- 접기 35px / 펼치기 복원
- 종단도와 유토곡선의 첫 측점 x=62, 마지막 측점 x=1454로 세 높이 모두에서 일치
- 요약: 절토(자연) 216.1㎥ (토사 14.9 / 리핑암 201.2 / 발파암 0.0),
절토(다짐환산) 244.8㎥, 성토 321.4㎥, 토취 76.6㎥
→ 14.9×0.90 + 201.2×1.15 = 244.79, 244.8 − 321.4 = −76.6 으로 수식과 일치
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
참고 도면 `13 유토곡선(울진 울진 대흥 산65 외2(3공구)).pdf` 분석 결과를 반영해
B06 종단면도 바로 아래에 유토곡선을 추가하고, 둘을 접이식 상단 슬라이드 패널
하나로 묶었다.
계산 (프론트 전담, 확정 시에만 영구 저장)
- `_UI_MassHaul.ts` 신설: 평균단면법으로 구간 토량을 만들고 토량환산계수로 기준을
통일해 누가토량을 누적하는 순수 함수. DOM 의존 0이라 B08/B09가 재사용 가능.
- 기준상태는 다짐상태 — 운반거리 산정 시 모든 수량은 다짐상태로 환산하고 내역서
수량은 자연상태로 한다(국도건설공사 설계실무 요령). 내역서용 자연상태 수량은
cut_natural_m3로 함께 보존한다.
- 지반유형이 다른 구간은 각 측점이 자기 절반(단면적 × Δd / 2)을 자기 지반유형으로
가져간다. 두 절반의 합이 평균단면법과 정확히 일치한다.
- 측점 조작마다 백엔드를 왕복하지 않고 메모리에서 계산하며, 확정 시점에만
longitudinal_sections.data.mass_haul에 저장한다.
X축 정렬
- longitudinalMaxChainage()를 공용으로 신설해 종단 렌더러와 유토곡선이 같은 X
매핑을 쓰게 했다. 두 SVG는 chart-wrap 하나를 공유해 가로 스크롤도 함께 움직인다.
패널 높이
- 아래 경계 리사이저로 사용자가 조절한다. 기본값 이상으로 키우면 종단도는 220px을
지키고 늘어난 몫은 유토곡선이 먹으며, 기본값보다 줄이면 둘이 같은 비율로 작아진다.
- 종단도가 줄면 Y스케일도 그 높이로 다시 잡아 표고가 잘리지 않게 했다.
토량환산계수
- config_system.py 5-4-3절 신설(유일한 정의처). 표준품셈 암종별 범위를 B06 지반유형
3종에 대응시킨 제안값이며 현장 조정이 전제라 env 없이 상수로 두었다.
검증: tsc 0건, ruff 통과, prettier 적용, 전 파일 700줄 이하.
계산 엔진 테스트 10종 전건 통과(평균단면법·다짐환산·지반유형 배분·비정규 측점
간격·정렬·중복 측점·계수 부재 폴백·페이로드 반올림). 서버 기동 및 번들 포함 확인.
Phase 2(평형선·운반토량 Q·평균운반거리 L·장비 배분·M.N)는 장비 거리 경계와 M.N
정의가 미확정이라 제외했다.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1,230줄이던 ui_template_locale.ts를 얇은 배럴(51줄)로 축소하고,
ui_locales 사전 데이터를 4개 파일로 분리했다.
- ui_template_locale_common.ts (96줄, 60키) — 공통 액션/상태/폼/네비/워크플로우/앱 셸, LocaleEntry 타입 정의
- ui_template_locale_a.ts (263줄, 141키) — A01~A09 로그인 전 페이지
- ui_template_locale_b1.ts (430줄, 260키) — B01~B04
- ui_template_locale_b2.ts (408줄, 253키) — B05~B11
배럴이 4종 사전을 스프레드로 합성하고 LANGUAGES / LanguageCode /
currentLanguageIndex / setLanguage / t / ui_locales / LocaleKey export
시그니처를 그대로 유지하므로, 소비처 13개 이상 파일의 import 수정은 없다.
검증: 분할 전후 714개 키가 값 문자열까지 완전 일치, 파일 간 중복 키 0건,
tsc --noEmit 오류 0건, prettier 5개 파일 모두 unchanged.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
B04/B05 2D 지도·B06 횡단도와 같은 방향으로 맞췄다. openwebcad의 zoomScreen
계산식은 그대로 두고 호출부에서 부호만 뒤집어 넘긴다(외부 코드 변경 최소화).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
B04 2D 지도·B05 배수유역도와 같은 방향으로 맞췄다. viewBox 축소가 확대이므로
factor 판정만 deltaY > 0 기준으로 바꿨고, 커서 아래 지점 고정은 그대로다.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
B04 2D 지도와 B05 배수유역도의 휠 판정을 deltaY > 0 기준으로 바꿨다.
커서 아래 지점을 고정하는 offset 보정은 그대로다. 3D 뷰어는 손대지 않았다.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
하이라이트 열이 덮는 자리의 규칙 측점 값 셀을 통째로 숨겨(hideCoveredCells),
비정규 측점을 고를 때마다 좌우 최대 2개 열의 값이 사라졌다. 표는 그대로 두고
선택된 값만 위에 얹도록 그 함수와 .is-covered 규칙을 걷어냈다.
하이라이트 열에서 계획고만 자주색 테두리·글자색으로 따로 강조되던 것도 없앴다.
평상시에는 다른 셀과 같은 모습이고, 고칠 수 있다는 표시는 hover·focus에서만
나타난다. 직접 입력 기능은 그대로다.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
구조물 측점이 두 곳에 있었다. 화면 정본인 사이드바 목록과, 경로 확정 때 종단
정본 파일에 병합된 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>
1) 사이드바 폼으로 이름을 "배관"이라 적어 넣은 항목은 origin이 "user"라 [초기화]로
지워지지 않고 배수유역도와도 어긋난 채 남았다. isPipeStation()(origin이 pipe이거나
이름이 "배관")으로 판정을 통일해 목록 교체·이동·삭제·선택 동기화가 같은 규칙을 쓴다.
2) 대시보드에서 곧장 B05로 들어오면 배수유역도가 비어 보이고 새로고침해야 나왔다.
패널이 배치되기 전(0×0)에 fitToRoute()가 돌아 엉뚱한 배율이 굳은 것이다. 크기가
2px 미만이면 맞춤을 미뤘다가 첫 배치 때 다시 맞춘다.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
[초기화]가 화면 목록만 자동 배치로 되돌리고 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>
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>
집중점 마커와 유입 외곽선이 세부유역 채움·관 마커 아래에 깔려, 켜도 무엇을 고른
것인지 보이지 않았다. 강도 색칠은 그대로 두고 마커·외곽선만 떼어 맨 마지막에 그린다.
- FlowStrengthOverlay.draw(): 계획선 강도 색칠만
- FlowStrengthOverlay.drawTop(): 집중점 마커 + 선택한 지점의 유입 셀 외곽선
- MapViewer 그리기 순서: 배수유역 오버레이 → 계획선 → 강도 색칠 → 세부유역·관 마커
→ 집중유역
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
하단 패널이나 우측 배수유역 패널을 늘리면 computeMapRect()가 지도를 뷰포트에 다시
맞춰(contain) 지도까지 함께 확대됐다. 배율이 바뀌니 방금 보던 자리를 다시 찾아야 했다.
화면 변환 계수(ax·bx)가 그대로가 되도록 배율·오프셋을 되계산해, 늘린 만큼은 확대가
아니라 더 넓은 범위로 채운다.
- preserveViewOnResize(): 이전 프레임의 변환 계수를 새 뷰포트에서 재현
- observeViewportSize(): 크기 변화를 지켜보며 위 보정을 걸고 다시 그린다
- 700줄 유지를 위해 fitCanvasToViewport / createProgressReporter / pipeMarkerColor도
_Drainage_Parts.ts로 이동
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
채움과 함께 그리던 번호가 등고선·흐름 화살표·관 마커에 가려 읽히지 않았다.
번호만 떼어내 프레임 맨 마지막에 얹는다.
- MapRender에 drawRingBadge()·ringCenterOnScreen()을 분리 노출.
drawFilledRing은 라벨이 있을 때 drawRingBadge를 부르는 형태로 바뀐다.
- B04: drawBasinNumbers() 호출을 관 마커 뒤로 이동(관이 없어도 번호는 그린다).
- B05: 채움은 라벨 없이 그리고 배지 자리만 모아 두었다가 배관 마커 뒤에 그린다.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
구조물 조작이 테이블과 그래프로 나뉘어 있었다. 이동은 그래프 측점선, 추가·삭제는
테이블이라 어디서 무엇을 하는지 알기 어려웠다. 메뉴를 그래프 칸으로 옮겨 셋을 한
자리에 모은다. 테이블은 값만 보여 준다.
- 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>
- 테이블에 얹던 구조물 세로선을 걷어냈다. 위치는 그래프 측점선이 이미 보여 주므로
같은 것을 두 번 그리는 셈이었다. 테이블에는 우클릭 메뉴만 남는다
(가까운 구조물이 있으면 삭제, 없으면 배관 추가).
- 드래그는 종단 그래프의 구조물 측점선에서 한다. createLongitudinalProfile에
onDragStation을 추가하고 kind === "irregular" 측점선에만 붙였다(좌클릭 전용).
- 좌측 구조물 폼에서 "배관" 항목을 고치거나 지우면 그래프와 배수유역도가 함께
갱신된다. DrainagePanel.setPipeChainages() 신설.
reconcilePipes()가 목록이 같으면 null을 돌려 관↔구조물 순환을 끊는다.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>