2026-08-06 사용자 지시 일괄 구현:
반폭 체계:
- 초기 샘플 반폭 config 기본 20m(SECTION_CROSS_HALF_WIDTH_M 15→20) —
표시 반폭이 이 안이면 재계산 없이 표시만 자름(기존 crossPlotMetrics)
- 재계산 버튼 삭제, [전체 측점 반영]이 반폭 적용 담당: 축소=표시만(즉시),
확대(보유 샘플 폭 초과)=regenerate 후 상세 재로드
- regenerate에 grade_options 재구성 추가 — 계획선(profile_alignment)까지
함께 재계산·저장. 예전 재계산 버튼이 계획 횡단도선·유토곡선·테이블을
지우던 근본 원인 해결(B04 파일입력 파이프라인과 같은 엔진 경로 재활용)
- 높이 배율 옵션 폐지(항상 1), 반폭 입력은 표준 횡단면 설정의
[전체 측점 반영] 위로 이동(Standard_Panel extraControl)
개별 반폭(카드):
- 카드 하단 ◀/▶/↺(±1m·전역 복귀), 암 경계 그룹 우측 정렬. 숫자 표시 없음
- 개별값 > 전역값 우선(StationWidthControl). 세션 보관, 확정·임시저장 시
cross_patches(design.display_half_width_m)로 영구 저장 → 재접근 복원
- 프리뷰·단건 설계 재계산이 이 필드를 이월해 지우지 않게 보강
- 방위각 표기 삭제
측구 방향 확정 동기화(13측점 보고):
- B05 경로확정 uphill 병합 시 저장 횡단 설계도 새 방향으로 재계산·저장
(sync_uphill_overrides_into_designs) — 정본만 갱신하면 B06 표시와
역반영(ditch_side→uphill_side)이 옛 방향으로 순환 덮어쓰던 문제 해결
- 절/성토 역할은 엔진이 지형에서 자동 판정(정상) — 사용자 지정 대상인
측구 방향(ditch_side)이 정확히 동기화됨을 13측점 실측 확인
실측: 축소/확대/개별 조절/저장 복원/확정 동기화/B05 하단 패널 정상,
tsc·ruff·prettier 통과, 콘솔 에러 0.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- 27: 종단 X라벨↔버튼 간격 70%로(bottomInset 19→15)
- 28: 사이드 패널 접힘 시 본문 24px 거터 — 손잡이가 Y축 라벨을 덮지 않음(B04~B07 공용)
- 29: B06 종단·유토곡선 가로 스크롤 고정 Y축 — buildStickyYAxis 재사용, yaxis CSS
정의처를 MassHaul css로 이동(B05·B06 공용). 앵커를 첫 자식으로 넣고 유토축 inner를
종단 높이만큼 내려 자기 구간만 덮음. 스크롤 600px 블리드 테스트 통과
- 30: 배관 측점 곡선 L·R 항상 표기(R 필수), 이웃 곡선 셀 근접 시 배관 셀만 우측 비킴,
선택 오버레이는 한 열 원위치 유지
Playwright: sticky 앵커 2개(x 고정), 거터 24px, gap 7px, 곡선 셀 8, 오류 0.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- revealCard: scrollIntoView block nearest -> start (카드 하단이 브라우저
바닥에 걸리던 문제 수정, 카드 상단이 sticky 패널 아래에 붙음)
- syncScrollMargin 신설: 스크롤 직전 패널 높이 실측 + 손잡이 24px + 여유 8px
(접기 시 drawPanel 미실행이어도 정지선 최신 유지)
- PLAN.md: A~D 항목 완료·취소 정리(2026-08-04 사용자 확정), 아카이빙 대기 표기
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
계획선 1차 로직 (2026-08-03 사용자 확정)
- design_pipe_anchored_profile 신설: 배수유역도가 확정한 배관 배치 측점을
변화점으로 삼아 계획선이 각 배관 자리에서 지면선과 만나도록(계획고=지반고)
시작점→배관1→…→종점을 직선으로 잇고 기본 R을 얹는다. 배관(암거)은 계곡
유하부라 계획선이 그 지점에 붙어야 복토·유입 조건이 성립한다.
- 기존 지반 추종 직선 분할 DP 선형은 2차 폴백으로, 구 균형 최적화 계획선은
3차 폴백으로 강등. 관 지점 파일의 노선 지문이 다르면 배관을 쓰지 않는다.
- 테스트 프로젝트 solve 재실행으로 저장분 재계산 — 변화점이 배관 5개 자리와
일치하고 각 자리 계획고=지반고임을 검증.
유토곡선 UI (사용자 피드백 5건)
- 기준 버튼 라디오화: 횡단/종단 택1로 그 기준 그래프만 전체 영역에 표시
(applyLegendToggle/normalizeVisibleBasis, B05·B06 공통 저장 키 공유).
Y 범위도 표시 중인 기준으로 산정.
- B05 Y축 이중 표시 제거: MassHaulAxis.axisX 신설 — 축 선·눈금을 종단 그래프
축과 같은 자리에 그리고 데이터 매핑은 유지해 측점 세로 정렬 불변.
- 종단↔유토곡선 경계 드래그 리사이저(비율 0.25~0.75, 세션 보존, 기본 1:1).
- B05 범례를 B06과 같은 오버레이 우상단 절대배치로 이동.
- 도면 테이블: 구조물 배치로 갈라진 구배 블록 값을 기본 숨김(윤곽·툴팁만),
해당 측점 선택 시 하이라이트와 함께 표시.
typecheck·vite build·ruff·B03 테스트 통과.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사용자 피드백 반영(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>
판정 기준은 성토측 자연 지반 경사(사용자 확정). 지반이 임계보다 가파르면 부어 놓은 흙이
쌓이지 않고 스스로 흘러내리므로 운반비를 세지 않는다.
계상 방식은 참고 도면을 근거로 정했다. 도면의 사토 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] 수평선이 곡선에서 떨어져 보이던 문제. 엔진은 포물선으로 교점을 잡는데 곡선만
직선(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>
누가토량 곡선은 "얼마가 남는가"만 말한다. 어디 흙을 어디로 얼마나 옮기는지를
뽑아내는 계층을 얹었다 — 평형선, 운반 블록, 운반토량 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>
- 손잡이가 안 보이던 원인은 패널의 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>
- 횡단 카드 측점 종류 표기에서 "일반 측점" 제거(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>
헤드리스 브라우저로 실화면을 확인하다 드래그가 전혀 먹지 않는 것을 발견했다.
손잡이 중심의 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>