feat(b05,b06): 사면안정 흙막이 · 옹벽 추가 단 상자 · 단마다 형태 · 높이 횡단 형상 (178-3)
- 추가 단 상자 = 유출 흙막이 상자 양식 · 공용 [추가] · [빼기] · 흙막이 형태 · 높이 · 옹벽 높이(콘크리트) · 키 tier_{n}_*
- 정의 그룹 종류 덧붙임 명세(ADDON_SPECS) — 좌측 폼만 · 그룹 상자 · 목록 · M02 그대로
- 벽 제원 짝(TS tierExtras · 파이썬 tier_extras) · 단 수 = 1 + 상자 수 · 횡단 단 조정 m · h
- 새 시험 test_178_3_slope_tiers · walls_mirror extras 대조
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015sDZSjFvoiDjdGpgj3muc3
This commit is contained in:
@@ -35,6 +35,8 @@ export interface WallSpec {
|
||||
/** 기초 축 — "기초유" | "기초버림". 저장 칸과 같은 글자(터파기 그림이 이 값으로 갈린다). */
|
||||
foundation: string | null;
|
||||
tiers: number | null;
|
||||
/** 추가 단(2단부터) 형태 · 높이 — 좌측 폼 「추가 단」 상자(178-3 · `tier_{n}_*`). 없으면 빈 목록. */
|
||||
extras: WallTier[];
|
||||
lift_m: number | null;
|
||||
shift_m: number | null;
|
||||
/** 전면 기울기 판정 칸 — 성토/절토 · 전면 기울기(저장 원본 · B08 과 같은 칸, 2026-09-14 B5). */
|
||||
@@ -42,6 +44,12 @@ export interface WallSpec {
|
||||
face_slope_ratio: number | string | null;
|
||||
}
|
||||
|
||||
/** 추가 단 한 벌 — 형태 빈 값 = 본 벽 형태 · 높이 빈 값 = 기본 단 높이(그리는 쪽). */
|
||||
export interface WallTier {
|
||||
form: string | null;
|
||||
height_m: number | null;
|
||||
}
|
||||
|
||||
/** 구간 경계 측점을 구간 안으로 볼 허용 오차(m) — 파이썬 `_EDGE_TOLERANCE_M`. */
|
||||
const EDGE_TOLERANCE_M = 0.02;
|
||||
|
||||
@@ -67,6 +75,24 @@ export const FORM_BY_TYPE: Record<string, string> = {
|
||||
const num = (value: unknown): number | null =>
|
||||
typeof value === "number" && Number.isFinite(value) ? value : null;
|
||||
|
||||
const TIER_KEY = /^tier_(\d+)_/;
|
||||
|
||||
/** 「추가 단」 상자(`tier_{n}_*` · n 차례) → 추가 단 목록 — 옹벽 = 콘크리트(178-3) · 파이썬 `tier_extras` 짝. */
|
||||
export function tierExtras(typeId: string, options: Record<string, unknown>): WallTier[] {
|
||||
const ns = [
|
||||
...new Set(
|
||||
Object.keys(options)
|
||||
.map((key) => TIER_KEY.exec(key)?.[1])
|
||||
.filter((n): n is string => !!n)
|
||||
.map(Number),
|
||||
),
|
||||
].sort((a, b) => a - b);
|
||||
return ns.map((n) => ({
|
||||
form: typeId === "retaining_wall" ? "콘크리트" : (options[`tier_${n}_form`] as string) || null,
|
||||
height_m: num(options[`tier_${n}_height`]),
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* C군 벽 구조물을 제원 목록으로 바꾼다. 이름표(`names`)는 타입 레지스트리에서 온다.
|
||||
* 구간(start·end)이 없는 항목은 건너뛴다 — 벽은 구간형이다.
|
||||
@@ -83,6 +109,7 @@ export function wallSpecsFrom(
|
||||
const end = num(structure.end_m);
|
||||
if (start === null || end === null) continue;
|
||||
const options = (structure.options ?? {}) as Record<string, unknown>;
|
||||
const extras = tierExtras(structure.type_id, options);
|
||||
specs.push({
|
||||
structure_id: structure.structure_id ?? null,
|
||||
type_id: structure.type_id,
|
||||
@@ -95,7 +122,9 @@ export function wallSpecsFrom(
|
||||
side: (options.side as string) ?? null,
|
||||
// 기초 축 — 저장 칸과 **같은 글자**. 초안 경로에서 빠지면 터파기가 안 그려진다.
|
||||
foundation: (options.foundation as string) ?? null,
|
||||
tiers: num(options.tiers),
|
||||
// 단 수 = 1 + 추가 단 상자 수 · 상자 없으면 옛 `tiers`(178-3)
|
||||
tiers: extras.length ? extras.length + 1 : num(options.tiers),
|
||||
extras,
|
||||
lift_m: num(options.lift_m),
|
||||
shift_m: num(options.shift_m),
|
||||
face_role: (options.face_role as string) ?? null,
|
||||
|
||||
Reference in New Issue
Block a user