feat(B06): 소단 = 좌측 깊이 칸 숨김 · 횡단도 소단 고름 ▲▼ 만 · 측점 · 쪽마다 깊이 patch · 고름 조각 키 · 좌측 소단 상자 켬(194-1 · 194-2)

- 정의 「상세 내용」 = 폭만 · depth_m 표시 끔(옛 구간 값 = 기본값으로 읽음 · 새 기본 1 m)
- 짝: BermSpec 쪽마다 깊이 · side_berm ↔ sideBerm · 설계 결과 berm_depth_{side}_m 되싣기(파이썬 ↔ TS)
- 저장: patch berm_depth_{side}_m(≥ 0) · 재계산 살림 목록 짝(RD ↔ CR) · 세션 bermdepth
- 서버 [저장] 다시 셈 = 구조물 정본 소단 구간(load_berm_spans) + 측점 깊이 · 구간 지우면 소단 없음
- 고름: 소단 수평 단 = 높이만(▲ 0 에서 멈춤 · ▼ 사면 끝 앞 멈춤 · ◀▶ 막힘) · 사면 = 가로 · 노면 = 종단
- 고름을 조각 키(갈래 + 쪽 + 차례)로 기억 — 옮겨 다시 그려도 같은 조각
- 새 시험 test_194_1_berm_depth + helper · test_178_2 · test_54_26 고침

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F3mdb91125mPoC6tpsQx4P
This commit is contained in:
2026-10-10 13:59:43 +09:00
co-authored by Claude Opus 5.5
parent e442777cc8
commit cb7a140c10
24 changed files with 1090 additions and 69 deletions
+11
View File
@@ -50,6 +50,17 @@ class BermSpec(NamedTuple):
interval_m: float = BERM_DEFAULT_INTERVAL_M
slope_deg: float = BERM_DEFAULT_SLOPE_DEG
depth_m: float = BERM_DEFAULT_DEPTH_M
# 쪽마다 옮긴 깊이(194-1 · 횡단도 ▲▼ · 측점 patch) — None = `depth_m`
depth_left_m: float | None = None
depth_right_m: float | None = None
def side_berm(berm: BermSpec | None, side: str) -> BermSpec | None:
"""그 쪽 소단 — 쪽마다 옮긴 깊이가 있으면 그 값을 `depth_m` 으로(194-1 · 0 미만 = 0)."""
if berm is None:
return None
own = berm.depth_left_m if side == "left" else berm.depth_right_m
return berm if own is None else berm._replace(depth_m=max(float(own), 0.0))
def cut_profile_points(
+10
View File
@@ -39,6 +39,16 @@ export interface BermSpec {
intervalM: number;
slopeDeg: number;
depthM?: number;
/** 쪽마다 옮긴 깊이(194-1 · 횡단도 ▲▼ · 측점 patch) — 없으면 `depthM`. */
depthLeftM?: number | null;
depthRightM?: number | null;
}
/** 짝: `side_berm`. 그 쪽 소단 — 쪽마다 옮긴 깊이가 있으면 그 값을 `depthM` 으로(0 미만 = 0). */
export function sideBerm(berm: BermSpec | null, side: string): BermSpec | null {
if (berm === null) return null;
const own = side === "left" ? berm.depthLeftM : berm.depthRightM;
return own === undefined || own === null ? berm : { ...berm, depthM: Math.max(own, 0) };
}
export function bermSpec(
+9
View File
@@ -143,6 +143,9 @@ export interface CrossDesignResult {
/** 노견 확장(m · 139-6) — 넓힌 쪽만. */
shoulder_extend_left_m?: number;
shoulder_extend_right_m?: number;
/** 소단 쪽마다 옮긴 깊이(m · 194-1) — 옮긴 쪽만. */
berm_depth_left_m?: number;
berm_depth_right_m?: number;
cross_slope_pct: number;
ditch: Record<string, unknown>;
/** 결과 — **실제로 섰나**. */
@@ -588,6 +591,12 @@ export function computeCrossDesign(
slope_deg: round4(options.berm.slopeDeg),
depth_m: round4(Math.max(options.berm.depthM ?? BERM_DEFAULT_DEPTH_M, 0)),
};
// 쪽마다 옮긴 깊이(194-1) — 옮긴 쪽만 되싣는다(짝: 파이썬)
const { depthLeftM, depthRightM } = options.berm;
if (depthLeftM !== undefined && depthLeftM !== null)
result.berm_depth_left_m = round4(Math.max(depthLeftM, 0));
if (depthRightM !== undefined && depthRightM !== null)
result.berm_depth_right_m = round4(Math.max(depthRightM, 0));
}
// 노견 확장(139-6) — 넓힌 쪽만 되싣는다(짝: 파이썬)
if (geometry.shoulderExtendLeft > 0)
@@ -11,6 +11,7 @@ import {
cutProfilePoints,
elevationAt,
fillProfilePoints,
sideBerm,
} from "./common_util_cross_berm";
/** 절토 사면 경사 구간 한 칸 — 짝 파이썬 `cut_slope_segments` 와 같은 항목. */
@@ -306,7 +307,7 @@ export class SectionGeometry {
startDist,
startZ,
this.fillRatio,
this.berm,
sideBerm(this.berm, side), // 쪽마다 옮긴 깊이(194-1)
undefined,
edgeZ,
);