Files
Aislo/A00_Common/design/design_structure_pipe.ts
T
eomsangdonandClaude Opus 5.5 532c20085c feat(design): 횡단배수 세월교(표 04) 컨테이너 폼 · 월류 폭 ↔ 높이 연동
- 세월교 명세(design_structure_ford) — 세월교(관경 · 월류 폭 · 월류 높이 · 수량(련)) · 유입 구조 · 유출 구조(없음 · 날개벽 · 흙막이) · 모두 필수 · 컨테이너마다 구조물 조합 잇기(gford · gfordin · gfordout)
- 구조 키 inlet_type · outlet_type + 옛 날개벽 설치 칸(wing_in · wing_out) 함께 씀 · 옛 저장 · B06 조정창 설치 칸으로 구조를 맞춤 · 옛 관종 · 날개벽 치수는 지난 정의 값
- 계산 파일 따로(design_structure_ford_calc) — 높이 = 설계유량을 그 폭으로 넘기는 Manning 필요 수심 · 0.01 올림 · 폭을 바꾸면 채움 · 그 아래는 안 받음 · 근거 통수단면.md:23~33 · :59
- B06 날개벽 조정 행 자리 = 유입 · 유출 구조 컨테이너 끝 · 세월교 옛 관종 · 관경 · 월류 칸 걷음
- 정의 종류.ford_bridge.이름 표 · 명세 등록(STRUCTURE_SPECS) · 52-1 시험 헬퍼가 같은 폴더 명세 import 를 읽음
- 시험 test_52_4_structure_spec_ford · 화면 시나리오 ui_checks/52-4_세월교_컨테이너

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

192 lines
6.2 KiB
TypeScript

/* =============================================================================
* design_structure_pipe.ts
* 횡단배수 › 배관 명세 — 사용자 구조물 표 01(`docs/raw/구조물정의_표/01_횡단배수_배관.md`) 그대로.
*
* 컨테이너 다섯: 관(필수) · 관 보호공(유입)(필수) · 관 보호공(유출)(필수) · 흙막이 추가(선택 · 여러 개) ·
* 도수로/돌붙임(선택 · 여러 개). 구조 · 정본 = 이 명세 · 이름만 정의(M02)에서 바꿈.
* 저장 키 = pipe_points.json 옛 키 그대로(B06 횡단 · B07 · B08 이 읽는 자리) — 흙막이 값은 옛 「기슭막이」
* (`inlet_type` · `*_revet_*`)에 둠. 새 키 = 집수정 높이 · 선택 컨테이너(`soil_add_{n}_*` · `chute_add_{n}_*`).
* 정함(PLAN 52): 유출 형태 = 흙막이 6가지 · 도수로/돌붙임 = 구조만 · 길이 = 전 + 후 맞물림.
* 계산(관 길이 · 높이 안내)은 `design_structure_pipe_calc`.
* import = 같은 폴더 명세뿐 — 시험이 이 폴더 파일만 옮겨 돌림.
* ========================================================================== */
import type { SpecChoice, SpecItem, StructureSpec } from "./design_structure_spec";
import { FORD_SPEC } from "./design_structure_ford";
const SOIL = "기슭막이"; // 저장 값(옛 키 그대로) — 화면 이름은 흙막이
const BASIN = "집수정";
const SOIL_FORMS: SpecChoice[] = [
{ value: "돌쌓기(찰)", label: "돌 쌓기(찰)" },
{ value: "돌쌓기(메)", label: "돌 쌓기(메)" },
{ value: "콘크리트", label: "콘크리트" },
{ value: "돌망태", label: "돌망태" },
{ value: "통나무·목재틀", label: "통나무/목재틀" },
{ value: "바자", label: "바자" },
];
const BASIN_FORMS: SpecChoice[] = [
{ value: "I", label: "I형" },
{ value: "L", label: "L형" },
{ value: "U", label: "ㄷ형" },
];
/** 형태 · 길이 · 높이 · 전 · 후 — 필수 보호공은 구조 갈래마다 옛 키 · 선택 흙막이는 인스턴스 키. */
function guardItems(keys?: Record<string, Record<string, string>>): SpecItem[] {
const by = (field: string, choices?: Record<string, SpecChoice[]>) =>
keys
? {
item: "structure",
map: Object.fromEntries(
Object.entries(keys).map(([structure, k]) => [
structure,
{ key: k[field], choices: choices?.[structure] },
]),
),
}
: undefined;
return [
{
id: "form",
label: "형태",
kind: "select",
choices: SOIL_FORMS,
by: by("form", { [BASIN]: BASIN_FORMS, [SOIL]: SOIL_FORMS }),
},
{ id: "length", label: "길이 (m)", kind: "number", split: "length", step: 1, by: by("length") },
{ id: "height", label: "높이 (m)", kind: "number", step: 0.1, by: by("height") },
{
id: "before",
label: "기준측점 전 (m)",
kind: "number",
split: "before",
step: 0.5,
by: by("before"),
},
{
id: "after",
label: "기준측점 후 (m)",
kind: "number",
split: "after",
step: 0.5,
by: by("after"),
},
];
}
const revetKeys = (side: "inlet" | "outlet"): Record<string, string> => ({
form: `${side}_revet_form`,
length: `${side}_revet_length_m`,
height: `${side}_revet_height_m`,
before: `${side}_revet_before_m`,
after: `${side}_revet_after_m`,
});
export const PIPE_SPEC: StructureSpec = {
typeId: "pipe",
containers: [
{
id: "pipe",
title: "관",
required: true,
link: "grv6lny", // 정의 그룹 「관」(46장) — 집계표 잇기 자리 그대로
items: [
{
id: "diameter",
label: "관경",
kind: "select",
key: "pipe_diameter_mm",
asNumber: true,
choices: ["800", "1000", "1200", "1500"].map((v) => ({ value: v, label: v })),
},
{ id: "length", label: "관 길이 (m)", kind: "auto" },
],
},
{
id: "inlet",
title: "관 보호공 (유입)",
required: true,
link: "gnbf9m9",
items: [
{
id: "structure",
label: "구조",
kind: "select",
key: "inlet_type",
choices: [
{ value: BASIN, label: "집수정" },
{ value: SOIL, label: "흙막이", also: { inlet_structure: "revet" } },
],
},
...guardItems({
[BASIN]: {
form: "inlet_structure",
length: "inlet_basin_length_m",
height: "inlet_basin_height_m",
before: "inlet_basin_before_m",
after: "inlet_basin_after_m",
},
[SOIL]: revetKeys("inlet"),
}),
],
},
{
id: "outlet",
title: "관 보호공 (유출)",
required: true,
link: "g9lq9uk",
items: [
{
id: "structure",
label: "구조",
kind: "select",
key: "outlet_type",
choices: [{ value: SOIL, label: "흙막이" }],
},
...guardItems({ [SOIL]: revetKeys("outlet") }),
],
},
{
id: "soil_add",
title: "흙막이 추가",
required: false,
prefix: "soil_add",
link: "gsoiladd",
items: [
{
id: "structure",
label: "구조",
kind: "select",
choices: [{ value: SOIL, label: "흙막이" }],
},
...guardItems(),
],
},
{
id: "chute_add",
title: "도수로/돌붙임",
required: false,
prefix: "chute_add",
link: "gchuteadd",
items: [
{
id: "structure",
label: "구조",
kind: "select",
choices: [
{ value: "도수로", label: "도수로" },
{ value: "돌붙임", label: "돌붙임" },
],
},
],
},
],
// 표 01 에 없는 옛 칸 — 화면에서 빼고 값은 남김(지난 정의 값)
retired: ["pipe_kind", "wing_wall_type", "inlet_basin_form", "inlet_basin_material"],
};
/** 명세로 그리는 종류 — 종류 키 → 명세(표가 오는 대로 더함). */
export const STRUCTURE_SPECS: Readonly<Record<string, StructureSpec>> = {
pipe: PIPE_SPEC,
ford_bridge: FORD_SPEC,
};