Merge remote-tracking branches 'origin/main_laptop_1' and 'origin/sub_laptop_2' into sub_laptop_3
This commit is contained in:
@@ -0,0 +1,107 @@
|
||||
/* =============================================================================
|
||||
* common_util_berm_spans.ts
|
||||
* 소단 구간 — 구조물 목록(표 형상 berm)에서 구간 · 측점마다 제원(PLAN 472-4 C4 · 화면 파일
|
||||
* `B06_Section_UI_Page_Persist.ts` 에서 옮김 · 그쪽이 다시 내보냄).
|
||||
* 브라우저(시설 줄 · 다시 셈)와 서버 Node 입구(`design_calc_node` · 등록부 `cross.berm_spans`)가 같은 셈.
|
||||
* 파이썬 짝 = `B06_Section_Engine_Structures_Wall.py` `load_berm_spans` · `berm_span_at`
|
||||
* (Node 를 못 부를 때만 · 거울 시험 `test_272_berm_source.py`).
|
||||
* ========================================================================== */
|
||||
|
||||
import {
|
||||
BERM_DEFAULT_DEPTH_M,
|
||||
BERM_DEFAULT_INTERVAL_M,
|
||||
BERM_DEFAULT_SLOPE_DEG,
|
||||
BERM_DEFAULT_WIDTH_M,
|
||||
} from "./common_util_cross_berm";
|
||||
import { catalogRow } from "./common_util_structure_catalog";
|
||||
|
||||
/** 측점 하나의 소단 제원 — 서버 payload 와 같은 이름을 쓴다(그대로 실어 보낸다). */
|
||||
export interface BermSessionSpec {
|
||||
width_m: number;
|
||||
interval_m: number;
|
||||
slope_deg: number;
|
||||
/** 노면 끝 아래 깊이(m · ≥ 0 · 178-2). */
|
||||
depth_m: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 사용자가 놓은 소단 **한 구간** — 종단 범위 + 제원.
|
||||
*
|
||||
* 사용자는 측점 하나가 아니라 **구간**에 놓는다(2026-09-07 확정: 「길이 + 기준측점 전·후」).
|
||||
* 그래서 세션에는 구간 목록으로 두고, 측점별 제원은 읽는 자리에서 편다 — 구간을 측점으로
|
||||
* 펴서 저장하면 나중에 「어디부터 어디까지 놓았나」를 되짚을 수 없다.
|
||||
*/
|
||||
export interface BermSpan extends BermSessionSpec {
|
||||
start_m: number;
|
||||
end_m: number;
|
||||
}
|
||||
|
||||
/** 소단 = 표 형상 berm(323-4 · 파이썬 `load_berm_spans` 짝) — 종류 키로 안 가름. */
|
||||
export const isBermType = (typeId: string): boolean => catalogRow(typeId)?.shape === "berm";
|
||||
|
||||
/**
|
||||
* 구조물 목록에서 **소단 구간**을 뽑는다 — 사용자는 「구조물 배치」에서 놓는다
|
||||
* (2026-09-07 사용자 확정: 별도 폼이 아니라 다른 옹벽·기슭막이와 같은 자리).
|
||||
*
|
||||
* 세션 열쇠 `berm` 은 그 결과를 담는 **사본**이다. 재계산(브라우저·서버)이 측점마다 값을
|
||||
* 읽어야 하는데 구조물 목록은 비동기로 오므로, 목록이 바뀔 때마다 여기서 펴 두고 계산은
|
||||
* 그 사본만 본다.
|
||||
*/
|
||||
export function bermSpansFromStructures(
|
||||
structures: ReadonlyArray<{
|
||||
type_id: string;
|
||||
start_m?: number | null;
|
||||
end_m?: number | null;
|
||||
chainage_m?: number | null;
|
||||
options?: Record<string, string | number>;
|
||||
}>,
|
||||
): BermSpan[] {
|
||||
const spans: BermSpan[] = [];
|
||||
for (const item of structures) {
|
||||
if (!isBermType(item.type_id)) continue;
|
||||
const anchor = item.chainage_m ?? item.start_m ?? null;
|
||||
const start = item.start_m ?? anchor;
|
||||
const end = item.end_m ?? anchor;
|
||||
if (start === null || end === null) continue;
|
||||
const options = item.options ?? {};
|
||||
const number = (key: string, fallback: number): number => {
|
||||
const parsed = Number(options[key]);
|
||||
return Number.isFinite(parsed) && parsed >= 0 ? parsed : fallback;
|
||||
};
|
||||
const width = number("width_m", BERM_DEFAULT_WIDTH_M);
|
||||
const interval = number("interval_m", BERM_DEFAULT_INTERVAL_M);
|
||||
if (width <= 0) continue; // 폭이 0이면 계단이 없다(간격은 성토 한 단에 안 씀 · 178-2)
|
||||
// 깊이 = 노면 끝 아래 · 음수는 0(도로보다 높을 수 없음) · 빈 값은 기본 1.0
|
||||
const rawDepth = Number(options.depth_m);
|
||||
const depth =
|
||||
options.depth_m === undefined || options.depth_m === "" || !Number.isFinite(rawDepth)
|
||||
? BERM_DEFAULT_DEPTH_M
|
||||
: Math.max(rawDepth, 0);
|
||||
spans.push({
|
||||
start_m: Math.min(start, end),
|
||||
end_m: Math.max(start, end),
|
||||
width_m: width,
|
||||
interval_m: interval,
|
||||
slope_deg: number("slope_deg", BERM_DEFAULT_SLOPE_DEG),
|
||||
depth_m: depth,
|
||||
});
|
||||
}
|
||||
return spans;
|
||||
}
|
||||
|
||||
/** 그 측점을 덮는 소단 제원 — 없으면 null. 겹치면 먼저 놓은 것이 이긴다. */
|
||||
export function bermSpecAt(spans: BermSpan[], chainageM: number): BermSessionSpec | null {
|
||||
const found = spans.find(
|
||||
(span) =>
|
||||
chainageM >= Math.min(span.start_m, span.end_m) - 1e-6 &&
|
||||
chainageM <= Math.max(span.start_m, span.end_m) + 1e-6,
|
||||
);
|
||||
return found
|
||||
? {
|
||||
width_m: found.width_m,
|
||||
interval_m: found.interval_m,
|
||||
slope_deg: found.slope_deg,
|
||||
depth_m: found.depth_m ?? BERM_DEFAULT_DEPTH_M,
|
||||
}
|
||||
: null;
|
||||
}
|
||||
@@ -24,6 +24,8 @@ NODE_IDS = frozenset(
|
||||
"haul.plan",
|
||||
"excavation.trench",
|
||||
"corridor.mesh",
|
||||
"cross.design",
|
||||
"cross.berm_spans",
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user