diff --git a/B05_Profile/B05_Profile_UI_Profile_Layout.ts b/B05_Profile/B05_Profile_UI_Profile_Layout.ts index 987aa863..cbf42e8a 100644 --- a/B05_Profile/B05_Profile_UI_Profile_Layout.ts +++ b/B05_Profile/B05_Profile_UI_Profile_Layout.ts @@ -17,8 +17,9 @@ import { type IrregularStation, } from "./B05_Profile_UI_IrregularStations"; -/** 테이블 12행. 행 높이와 셀 폭에서 글자 크기를 정하는 데 쓴다. */ -export const TABLE_ROW_COUNT = 12; +/** 테이블 6행(구배 S · 계획고 · 지반고 · 측점 · 곡선 L · 곡선 R). 행 높이와 셀 폭에서 + * 글자 크기를 정하는 데 쓴다. 2026-09-06 사용자 지시로 12행에서 줄였다. */ +export const TABLE_ROW_COUNT = 6; /** 측점 사이 여백 — 이웃 셀끼리 붙어 보이지 않게 띄운다. */ export const CELL_GAP_PX = 2; diff --git a/B05_Profile/B05_Profile_UI_Profile_Table.ts b/B05_Profile/B05_Profile_UI_Profile_Table.ts index 581345f4..e1cb163f 100644 --- a/B05_Profile/B05_Profile_UI_Profile_Table.ts +++ b/B05_Profile/B05_Profile_UI_Profile_Table.ts @@ -1,10 +1,11 @@ /* ============================================================================= * B05_Profile_UI_Profile_Table.ts - * 종단면도 하단 도면 테이블 (구배 3행 · 측점값 7행 · 곡선 2행 = 12행). + * 종단면도 하단 도면 테이블 (구배 1행 · 측점값 3행 · 곡선 2행 = 6행). * - * 실무 종단면도 좌측 하단 표를 그대로 옮긴 구성이다. 구배와 곡선은 단일값 행이 아니라 - * 도면에서도 여러 줄로 찍히므로 각각 물리적인 행으로 분리했다. - * - 구배: 연장 / 고저차 / 기울기 3행. 블록은 곡선 구간을 뺀 실제 직선부만 덮는다. + * 실무 종단면도 좌측 하단 표를 옮긴 구성이되, **화면에서는 판단에 쓰는 행만** 둔다 + * (2026-09-06 사용자 지시 — 표가 그래프 자리를 너무 먹었다). 뺀 6행은 구배 L·H, + * 절토고, 성토고, 누가거리, 거리이며 **B07 도면 종단도는 12행 그대로**다(별도 코드). + * - 구배: 기울기(S) 1행. 블록은 곡선 구간을 뺀 실제 직선부만 덮는다. * - 곡선: 곡선길이 / 반경 2행. 반경 R만 입력 가능하고 L = R × |대수차| 로 따라온다. * * 값에는 `L=` 같은 접두를 붙이지 않는다 — 행 이름표가 이미 항목과 단위를 말해준다. @@ -173,10 +174,9 @@ function createRow(className: string, label: string, unit: string): HTMLElement return row; } -/** 도면의 구배 블록 3행: 구간 연장(m) / 고저차(m) / 기울기(%). 단위는 행 이름표가 대신한다. */ +/** 화면 구배 블록 1행: 기울기(%). 연장·고저차 두 행은 2026-09-06 사용자 지시로 뺐다 — + * 두 값은 블록 툴팁에 그대로 남아 있어 필요할 때 짚어 볼 수 있다. */ const SEGMENT_ROWS: SegmentRowSpec[] = [ - { label: "구배 L", unit: "m 구간 연장", cell: (segment) => segment.length_m.toFixed(2) }, - { label: "구배 H", unit: "m 구간 고저차", cell: (segment) => segment.height_m.toFixed(2) }, { label: "구배 S", unit: "% 구간 기울기", cell: (segment) => segment.grade_percent.toFixed(2) }, ]; @@ -194,19 +194,9 @@ function buildStationRows( display: { station: number; cumulative: number }, ): StationRowSpec[] { const stations = alignment.stations; + // 절토고·성토고·누가거리·거리 네 행은 2026-09-06 사용자 지시로 뺐다 — 절·성토는 + // 그래프 음영과 유토곡선이, 누가거리는 측점 라벨이 이미 말해 준다. return [ - { - label: "절토고", - unit: "m", - modifier: "cut", - cell: (index) => (stations[index].cut_m > 0.005 ? stations[index].cut_m.toFixed(2) : ""), - }, - { - label: "성토고", - unit: "m", - modifier: "fill", - cell: (index) => (stations[index].fill_m > 0.005 ? stations[index].fill_m.toFixed(2) : ""), - }, { label: "계획고", unit: "m", @@ -214,16 +204,6 @@ function buildStationRows( cell: (index) => stations[index].plan_elevation_m.toFixed(2), }, { label: "지반고", unit: "m", cell: (index) => stations[index].ground_elevation_m.toFixed(2) }, - { - label: "누가거리", - unit: "m", - cell: (index) => (stations[index].chainage_m + display.cumulative).toFixed(2), - }, - { - label: "거리", - unit: "m 전 측점 대비", - cell: (index) => (index ? stations[index].distance_m.toFixed(2) : ""), - }, { label: "측점", unit: "측점번호+잔여거리", @@ -233,7 +213,7 @@ function buildStationRows( } /** - * 구배 3행. 각 블록은 **변화점에서 변화점까지**를 덮는다. + * 구배 행. 각 블록은 **변화점에서 변화점까지**를 덮는다. * * 구분선을 곡선의 접선점(BVC/EVC)에 두면 곡선 길이만큼 블록 사이에 틈이 생기고, * 양옆 블록의 테두리가 그 틈을 감싸 "빈 셀"처럼 보인다. 변화점은 곧 **생성된 R의 @@ -268,7 +248,7 @@ function buildSegmentRows( const span = x(segment.to_m) - left; const text = spec.cell(segment); const node = element("span", "b05-profile-table__segment", ""); - // 구배 3행(L·H·S)은 **늘 보인다** — 구조물로 갈라진 좁은 구간도 값을 적는다 + // 구배 행은 **늘 보인다** — 구조물로 갈라진 좁은 구간도 값을 적는다 // (2026-09-04 사용자 확정: 값 열을 접는 규칙에서 구배 행은 제외). // 옛 규칙(2026-08-03: 구조물 구간은 고를 때만 값 표시)은 여기서 걷어냈고, // 구조물 구간 표시(색·하이라이트)와 툴팁은 그대로 둔다. @@ -499,27 +479,13 @@ function buildSelectedColumn( const curveAt = alignment.curves.find((entry) => Math.abs(entry.chainage_m - chainage) < 0.01); // 값 열 오버레이도 같은 규칙 — 직선화된 자리는 곡선 L·R 을 비운다. const curve = curveAt && !isStraightCurve(curveAt) ? curveAt : undefined; - // 거리: 바로 앞 측점(계획선 측점)까지의 간격. - const previous = alignment.stations - .filter((row) => row.chainage_m < chainage - 1e-6) - .reduce( - (acc, row) => (acc === null ? row.chainage_m : Math.max(acc, row.chainage_m)), - null, - ); - const distance = previous !== null ? chainage - previous : null; - - // 테이블 행 순서(구배 3 · 측점값 7 · 곡선 2)와 정확히 같게 채운다. 없는 값은 공백. - // `plan: true`인 계획고 행만 직접 입력 셀로 만든다(값 열은 오버레이라 실제 12행 격자는 불변). + // 테이블 행 순서(구배 1 · 측점값 3 · 곡선 2)와 정확히 같게 채운다. 없는 값은 공백. + // `plan: true`인 계획고 행만 직접 입력 셀로 만든다(값 열은 오버레이라 실제 6행 격자는 불변). + // 절토·성토고는 행이 빠졌어도 값 자체는 툴팁에 남긴다 — 고른 측점에서 흔히 찾는 값이다. const rows: Array<{ value: CellValue; modifier: string; plan?: boolean }> = [ - { value: gradeCell((segment) => segment.length_m, 2), modifier: "" }, // 구배 L - { value: gradeCell((segment) => segment.height_m, 2), modifier: "" }, // 구배 H { value: gradeCell((segment) => segment.grade_percent, 2), modifier: "grade" }, // 구배 S - { value: { text: cut !== null ? cut.toFixed(2) : "" }, modifier: "cut" }, // 절토고 - { value: { text: fill !== null ? fill.toFixed(2) : "" }, modifier: "fill" }, // 성토고 { value: { text: plan !== null ? plan.toFixed(2) : "" }, modifier: "plan", plan: true }, // 계획고 { value: { text: ground !== null ? ground.toFixed(2) : "" }, modifier: "" }, // 지반고 - { value: { text: (chainage + display.cumulative).toFixed(2) }, modifier: "" }, // 누가거리 - { value: { text: distance !== null ? distance.toFixed(2) : "" }, modifier: "" }, // 거리 { value: { text: displayStationLabel(chainage, interval, display.station) }, modifier: "" }, // 측점 { value: { text: curve ? curve.l_m.toFixed(2) : "" }, modifier: "" }, // 곡선 L { value: { text: curve ? curve.r_m.toFixed(1) : "" }, modifier: "" }, // 곡선 R @@ -560,9 +526,16 @@ function buildSelectedColumn( } column.append(cell); }); - column.title = `${displayStationLabel(chainage, interval, display.station)} · ${( + // 행에서 뺀 값(절토고·성토고·누가거리)은 툴팁에 남긴다 — 고른 측점에서 흔히 찾는 값이다. + const cutFillText = + cut !== null + ? ` · 절토 ${cut.toFixed(2)}m` + : fill !== null + ? ` · 성토 ${fill.toFixed(2)}m` + : ""; + column.title = `${displayStationLabel(chainage, interval, display.station)} · 누가거리 ${( chainage + display.cumulative - ).toFixed(2)}m`; + ).toFixed(2)}m${cutFillText}`; return column; }