Files
Aislo/A00_Common/design/design_structure_box.ts
T
eomsangdonandClaude Opus 5.5 1a53e045c5 feat(design): 횡단배수 박스암거(표 02 고친 판) 컨테이너 폼 — 본체 · 유입 구조 · 유출 구조 (PLAN 52-2)
- 박스암거 명세(design_structure_box) — 본체 규격 2.0×2.0 · 3.0×3.0 · 사용자 입력(가로 × 세로 숫자 칸) · 유입 · 유출 구조 없음 · 날개벽 · 흙막이 · 컨테이너마다 구조물 조합 잇기(gboxbody · gboxin · gboxout)
- 저장 키 = 옛 키 그대로(body_width_m · body_height_m · wing_in · wing_out) · 규격 칸은 저장 안 함(폭 · 높이로 되찾음) · 옛 「있음」 = 날개벽 · 옛 날개벽 치수는 화면에서 빼고 지난 정의 값
- 명세 등록(STRUCTURE_SPECS) · 배관 시험 헬퍼가 같은 폴더 명세를 옮겨 읽음
- B06 날개벽 설치 판정 한 곳(wingInstalled) — 흙막이 = 날개벽 안 세움 · 저장 글을 있음/없음으로 안 덮음 · 날개벽 조정 행은 명세 유입 · 유출 칸으로
- 정의 판 7 — box_culvert 이름 표 · 그룹 셋 · wing_in/out 선택지 · 판 6 이력 보관
- 시험 test_52_structure_spec_box · 레지스트리 · 새 구조물 기본값 기대값

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W4uKaV4ZBhsJN4GHG7yRj4
2026-10-05 23:38:48 +09:00

118 lines
4.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* =============================================================================
* 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<string, readonly [number, number]> = {
"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<string, string | number>,
): Record<string, string | number> {
const out = { ...options };
for (const key of ["wing_in", "wing_out"]) if (out[key] === "있음") out[key] = "날개벽";
return out;
}
/** 저장 폭 · 높이 → 본체 칸 값 — 규격과 맞으면 그 규격 · 아니면 사용자 입력 · 없으면 빈 값. */
export function bodyOf(options: Record<string, string | number>): 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<string, number> {
const preset = BOX_PRESETS[body?.size ?? ""];
return preset ? { body_width_m: preset[0], body_height_m: preset[1] } : {};
}