/* ============================================================================= * B06_Section_Cross_Design_Surface_Geom.ts * 암선 · 포장층 **기하**(m 좌표) — 그리기는 `../B06_Section_UI_Cross_Design_Surface`(472-3). * ========================================================================== */ import type { PavementEntry } from "@util/common_util_structure_pavement"; import type { CrossDesign } from "../B06_Section_Api_Fetch"; export type Edge = { offset_m: number; elevation_m: number }; /** 암선 — 유효 지반 샘플을 `offsetM` 만큼 올린 꺾은선들(빈 · 무효 샘플에서 끊음 · 두 점 이상만). */ export function rockBoundarySegments( samples: Array<{ offset_m?: number; elevation_m?: number | null; valid: boolean }>, offsetM: number, ): Edge[][] { const segments: Edge[][] = []; let current: Edge[] = []; for (const sample of samples) { const elevation = sample.elevation_m; if (sample.valid === false || elevation === null || !Number.isFinite(elevation ?? NaN)) { if (current.length > 1) segments.push(current); current = []; continue; } current.push({ offset_m: sample.offset_m ?? 0, elevation_m: (elevation as number) + offsetM }); } if (current.length > 1) segments.push(current); return segments; } /** 확폭 끈 구간 — 규격 폭 끝(좌 = left − 확폭좌 · 우 = right + 확폭우 · 표고는 두 끝 사이 직선). */ function standardEdges(edges: { left: Edge; right: Edge }, design: CrossDesign) { const { left, right } = edges; const span = right.offset_m - left.offset_m || 1; const at = (offset: number): Edge => ({ offset_m: offset, elevation_m: left.elevation_m + ((right.elevation_m - left.elevation_m) * (offset - left.offset_m)) / span, }); return { left: at(left.offset_m - (design.widening_left_m ?? 0)), right: at(right.offset_m + (design.widening_right_m ?? 0)), }; } /** * 포장층 — 노면선(= 포장 윗면) 아래로 두께만큼. 노면공 범위(`section.pavement`)면 그 두께 · * 확폭 켬/끔(여러 건은 아래로 차례로 쌓음) · 없으면 카드 포장 켬일 때 표준 두께. * 층마다 네 꼭짓점(좌상 · 우상 · 우하 · 좌하). */ export function pavementLayers( design: CrossDesign, pavement?: readonly PavementEntry[] | null, ): Array<{ entry: PavementEntry | null; corners: Edge[] }> { const edges = design.carriageway_edges ?? design.road_edges; if (!edges) return []; const layers = pavement?.length ? pavement : design.paved ? [null] : []; let depth = 0; return layers.map((entry) => { const thickness = entry?.thickness_m ?? design.pavement_thickness_m ?? 0.2; const { left, right } = entry && !entry.widening_on ? standardEdges(edges, design) : edges; const corners = [ { offset_m: left.offset_m, elevation_m: left.elevation_m - depth }, { offset_m: right.offset_m, elevation_m: right.elevation_m - depth }, { offset_m: right.offset_m, elevation_m: right.elevation_m - depth - thickness }, { offset_m: left.offset_m, elevation_m: left.elevation_m - depth - thickness }, ]; depth += thickness; return { entry, corners }; }); }