/* ============================================================================= * common_util/common_util_structure_underdrain.ts * 맹암거(cross_underdrain · A군 점형) 제원을 횡단 측점에 얹는다(288-1). * * 기준 측점(0.02 m 안) 횡단 dict 에 `underdrain` = 높이 · 경사 — 횡단도가 돌 무늬 형상을 그리고, * 설계 계산은 그 측점을 측구 없이 지대 낮은 쪽 한 경사로 기울임(`tilted`). * 파이썬 짝 = `B06_Section/B06_Section_Engine_Tilt.py`(`load_underdrains` · `attach_underdrains`). * ========================================================================== */ export const UNDERDRAIN_TYPE_ID = "cross_underdrain"; const EDGE_TOLERANCE_M = 0.02; /** 맹암거 제원 — 높이 · 경사가 비면 null(높이 없으면 형상 없음 · 경사 없으면 표준 횡단경사). */ export interface UnderdrainSpec { structure_id: string | null; chainage_m: number; height_m: number | null; slope_pct: number | null; } export interface UnderdrainInput { structure_id?: string | null; type_id: string; chainage_m?: number | null; start_m?: number | null; options?: Record | null; } const positive = (value: unknown): number | null => { const parsed = value === "" || value === null || value === undefined ? NaN : Number(value); return Number.isFinite(parsed) && parsed > 0 ? parsed : null; }; /** 구조물 목록의 맹암거 제원(파이썬 `load_underdrains` 짝). */ export function underdrainSpecsFrom(structures: readonly UnderdrainInput[]): UnderdrainSpec[] { return structures.flatMap((structure) => { const at = structure.chainage_m ?? structure.start_m; if (structure.type_id !== UNDERDRAIN_TYPE_ID || typeof at !== "number") return []; const options = structure.options ?? {}; return [ { structure_id: structure.structure_id ?? null, chainage_m: at, height_m: positive(options.culvert_height_m), slope_pct: positive(options.culvert_slope_pct), }, ]; }); } /** 기준 측점 횡단 dict 에 `underdrain` 을 얹는다(옛 값은 걷음) — 얹은 개수(파이썬 `attach_underdrains` 짝). */ export function attachUnderdrainSpecs( sections: Array>, specs: readonly UnderdrainSpec[], ): number { let attached = 0; for (const section of sections) { delete section.underdrain; const chainage = Number(section.chainage_m); const hit = specs.find((spec) => Math.abs(spec.chainage_m - chainage) <= EDGE_TOLERANCE_M); if (!hit) continue; section.underdrain = { ...hit }; attached += 1; } return attached; }