Merge remote-tracking branch 'origin/sub_laptop_7' into sub_laptop_8

This commit is contained in:
2026-10-08 12:25:23 +09:00
18 changed files with 434 additions and 98 deletions
+61 -39
View File
@@ -37,8 +37,7 @@ const SECTION_KEYS: Record<string, string> = {
const SPAN_LINKED_TYPES = new Set(["ford_pavement"]);
export const MIN_PIPE_COVER_M = 0.5;
export const APRON_LENGTH_FACTOR = 2.0;
export const APRON_THICKNESS_M = 0.45;
export const CHUTE_THICKNESS_CM = 30.0;
export const REVET_FACE_SLOPE = 0.3;
export const INLET_STRUCTURE_BASIN = "집수정";
export const FORD_SLAB_THICKNESS_M = 0.3;
@@ -124,15 +123,35 @@ function sideSpec(
spec.revet_before_m = before;
spec.revet_after_m = after;
spec.face_slope = REVET_FACE_SLOPE;
// 보호공은 기슭막이 바닥의 세굴 방지 구조 — 낙차고(기슭막이 높이)에 종속한다.
if (height !== null && height > 0) {
spec.apron_length_m = round(height * APRON_LENGTH_FACTOR, 3);
spec.apron_thickness_m = APRON_THICKNESS_M;
}
return spec;
}
/** 관 1개소의 세트 제원(관 + 유입·유출 기슭막이 + 보호공). */
/** 도수로 · 돌붙임(90-2) — 첫 상자(`chute_add_{n}_*`) 구조 · 두께(cm → m · 빈 값 30 cm) · 구조를 안
* 고르면 null. 횡단이 유출 성토사면을 따라 띠로 그림. 파이썬 짝 `_chute`. */
export function chute(
values: Record<string, unknown>,
): { structure: string; thickness_m: number } | null {
const picked = Object.entries(values)
.flatMap(([key, value]) => {
const hit = /^chute_add_(\d+)_structure$/.exec(key);
const structure = String(value ?? "").trim();
return hit && structure ? [[Number(hit[1]), structure] as const] : [];
})
.sort((a, b) => a[0] - b[0]);
if (!picked.length) return null;
const [n, structure] = picked[0];
const cm = num(values[`chute_add_${n}_thickness`], null);
return { structure, thickness_m: round((cm && cm > 0 ? cm : CHUTE_THICKNESS_CM) / 100, 3) };
}
/** 도수로 · 돌붙임이 있으면 세트에 `chute` 로 실음(90-2). */
function withChute(spec: CulvertSetSpec, values: Record<string, unknown>): CulvertSetSpec {
const found = chute(values);
if (found) spec.chute = found;
return spec;
}
/** 관 1개소의 세트 제원(관 + 유입·유출 기슭막이 + 도수로 · 돌붙임). */
function culvertSet(
options: Record<string, unknown>,
registry: CulvertRegistryDefaults,
@@ -140,18 +159,21 @@ function culvertSet(
const defaults = registry.pipe ?? {};
const diameterMm = num(options.pipe_diameter_mm, num(defaults.pipe_diameter_mm, 1000.0));
const diameterM = pipeDiameterM(diameterMm);
return {
type: "pipe",
pipe_kind: text(options.pipe_kind),
diameter_m: diameterM,
min_cover_m: MIN_PIPE_COVER_M,
// 관 기슭막이 기초 축 — **유입·유출 한 칸으로** 받는다. 한 공사에서 한쪽만 기초유로
// 하는 일은 드물어 폼을 둘로 늘리지 않았다(2026-09-09). 실무가 갈라 쓰는 것이
// 확인되면 그때 나눌 것.
foundation: text(options.revet_foundation),
inlet: sideSpec(options, defaults, "inlet", diameterM),
outlet: sideSpec(options, defaults, "outlet", diameterM),
};
return withChute(
{
type: "pipe",
pipe_kind: text(options.pipe_kind),
diameter_m: diameterM,
min_cover_m: MIN_PIPE_COVER_M,
// 관 기슭막이 기초 축 — **유입·유출 한 칸으로** 받는다. 한 공사에서 한쪽만 기초유로
// 하는 일은 드물어 폼을 둘로 늘리지 않았다(2026-09-09). 실무가 갈라 쓰는 것이
// 확인되면 그때 나눌 것.
foundation: text(options.revet_foundation),
inlet: sideSpec(options, defaults, "inlet", diameterM),
outlet: sideSpec(options, defaults, "outlet", diameterM),
},
options,
);
}
/**
@@ -175,10 +197,6 @@ function revetSide(values: Record<string, unknown>, role: string): CulvertSetSpe
face_role: values.face_role ?? null,
face_slope_ratio: values.face_slope_ratio ?? null,
};
if (height !== null && height > 0) {
spec.apron_length_m = round(height * APRON_LENGTH_FACTOR, 3);
spec.apron_thickness_m = APRON_THICKNESS_M;
}
return spec;
}
@@ -222,19 +240,23 @@ export function guardSet(
if (inlet.structure) inlet.revet_berm_m = num(values.inlet_revet_berm_m, null);
const outlet = side("outlet", outletKey);
if (!inlet.structure && !outlet.structure) return null;
return {
type: "pipe",
hidden_pipe: true,
body,
side: "양쪽",
tiers: 1,
foundation: null,
pipe_kind: null,
diameter_m: diameterM,
min_cover_m: 0.0,
inlet,
outlet,
};
// 흙막이 쪽 유출 띠는 흙막이 성토선을 따름(90-2)
return withChute(
{
type: "pipe",
hidden_pipe: true,
body,
side: "양쪽",
tiers: 1,
foundation: null,
pipe_kind: null,
diameter_m: diameterM,
min_cover_m: 0.0,
inlet,
outlet,
},
values,
);
}
/** 박스 본체 전체 높이(상판 + 내공 + 저판) — 흙막이 세트의 관경 자리(파이썬 `wall_body_height`). */
@@ -373,7 +395,7 @@ function fordSet(
...wingDefaulted(values, wingOut, "out"),
],
};
return withGuard(spec, guardSet(values, "ford", Number(spec.diameter_m)));
return withChute(withGuard(spec, guardSet(values, "ford", Number(spec.diameter_m))), values);
}
/** 물넘이포장 1개소 — 구조물이 아니라 **파인 노면**이라 형상이 다르다. */
@@ -441,7 +463,7 @@ function boxSet(
...wingDefaulted(values, wingOut, "out"),
],
};
return withGuard(spec, guardSet(values, "box", boxBodyHeight(spec)));
return withChute(withGuard(spec, guardSet(values, "box", boxBodyHeight(spec))), values);
}
/** 관 지점 목록 → 누가거리(소수 2자리)별 세트 제원. */