/* ============================================================================= * design_structure_box.ts * 횡단배수 › 박스암거 명세 — 사용자 구조물 표 02 고친 판(`docs/raw/구조물정의_표/02_횡단배수_박스암거.md`) 그대로. * * 컨테이너 셋(모두 필수): 본체 · 유입 구조 · 유출 구조. 구조 · 정본 = 이 명세 · 이름만 정의(M02)에서 바꿈. * 저장 키 = pipe_points.json 옛 키 그대로(B06 횡단 · B07 · B08 이 읽는 자리): * · 본체 = `body_width_m` · `body_height_m` 수 — 규격 칸은 저장 안 함(폭 · 높이로 되찾음 · `bodyOf`) * · 유입 · 유출 구조 = `wing_in` · `wing_out`(없음 · 날개벽 · 흙막이 · 옛 「있음」 = 날개벽) * — 엔진은 날개벽만 세움(`_wing_spec` ↔ `wingSpec` 짝) * 표 02 에 없는 옛 날개벽 치수 칸은 화면에서 빼고 값은 남김(지난 정의 값). * import 없음(꼴만) — 시험이 이 파일만 옮겨 돌림. * ========================================================================== */ import type { Instance, SpecItem, StructureSpec } from "./design_structure_spec"; export const BOX_CUSTOM = "사용자 입력"; /** 본체 규격 → [가로, 세로](m) — 실무 관측 규격(2026-08-17 사용자 확정). */ const BOX_PRESETS: Record = { "2.0×2.0": [2, 2], "3.0×3.0": [3, 3], }; /** 유입 · 유출 구조 — 같은 선택지 · 키만 다름. */ const structureItem = (key: string): SpecItem => ({ id: "structure", label: "구조", kind: "select", key, choices: [ { value: "없음", label: "없음" }, { value: "날개벽", label: "날개벽" }, { value: "흙막이", label: "흙막이" }, ], }); /** 사용자 입력일 때만 서는 숫자 칸. */ const customSide = (id: string, label: string, key: string): SpecItem => ({ id, label, kind: "number", step: 0.1, by: { item: "size", map: { [BOX_CUSTOM]: { key } } }, }); export const BOX_SPEC: StructureSpec = { typeId: "box_culvert", containers: [ { id: "body", title: "본체", required: true, link: "gboxbody", items: [ { id: "size", label: "본체 규격", kind: "select", choices: [ ...Object.keys(BOX_PRESETS).map((value) => ({ value, label: value.replace("×", " × "), })), { value: BOX_CUSTOM, label: BOX_CUSTOM }, ], }, customSide("width", "가로 (m)", "body_width_m"), customSide("height", "세로 (m)", "body_height_m"), ], }, { id: "inlet", title: "유입 구조", required: true, link: "gboxin", items: [structureItem("wing_in")], }, { id: "outlet", title: "유출 구조", required: true, link: "gboxout", items: [structureItem("wing_out")], }, ], // 표 02 에 없는 옛 날개벽 치수 — 화면에서 빼고 값은 남김(지난 정의 값) retired: ["in", "out"].flatMap((side) => ["height_m", "length_m", "angle_deg"].map((field) => `wing_${side}_${field}`), ), }; /** 옛 저장 → 폼에 줄 옵션 — 설치 「있음」 = 날개벽(같은 뜻 · 저장하면 새 값으로 굳음). */ export function boxOptionsIn( options: Record, ): Record { const out = { ...options }; for (const key of ["wing_in", "wing_out"]) if (out[key] === "있음") out[key] = "날개벽"; return out; } /** 저장 폭 · 높이 → 본체 칸 값 — 규격과 맞으면 그 규격 · 아니면 사용자 입력 · 없으면 빈 값. */ export function bodyOf(options: Record): Instance { const width = Number(options.body_width_m); const height = Number(options.body_height_m); if (!(width > 0 && height > 0)) return { size: "" }; const preset = Object.entries(BOX_PRESETS).find( ([, [w, h]]) => Math.abs(w - width) < 0.05 && Math.abs(h - height) < 0.05, ); return preset ? { size: preset[0] } : { size: BOX_CUSTOM, width: String(width), height: String(height) }; } /** 본체 칸 값 → 저장 폭 · 높이 — 규격이면 규격 수(사용자 입력은 명세 키가 적음). */ export function bodyOptions(body: Instance | undefined): Record { const preset = BOX_PRESETS[body?.size ?? ""]; return preset ? { body_width_m: preset[0], body_height_m: preset[1] } : {}; }