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:
@@ -120,6 +120,70 @@ def load_wall_structures(project_root: Path) -> list[dict[str, Any]]:
|
||||
return []
|
||||
|
||||
|
||||
def load_berm_spans(project_root: Path) -> list[tuple[float, float, dict[str, float]]] | None:
|
||||
"""구조물 정본의 소단 구간 `[(시작, 끝, 제원)]` — [저장] 서버 다시 셈의 소단 원천(194-1).
|
||||
|
||||
짝: TS `bermSpansFromStructures`(같은 규칙 — 폭 0 = 없음 · 깊이 빈 값 = 기본 1.0 · 0 미만 = 0).
|
||||
못 읽으면 None(부르는 쪽이 저장분 `design.berm` 으로 물러섬).
|
||||
"""
|
||||
from common_util.common_util_cross_berm import (
|
||||
BERM_DEFAULT_DEPTH_M,
|
||||
BERM_DEFAULT_INTERVAL_M,
|
||||
BERM_DEFAULT_SLOPE_DEG,
|
||||
BERM_DEFAULT_WIDTH_M,
|
||||
)
|
||||
|
||||
def number(options: dict[str, Any], key: str, fallback: float) -> float:
|
||||
try:
|
||||
value = float(options.get(key))
|
||||
except (TypeError, ValueError):
|
||||
return fallback
|
||||
return value if math.isfinite(value) and value >= 0 else fallback
|
||||
|
||||
try:
|
||||
spans: list[tuple[float, float, dict[str, float]]] = []
|
||||
for item in load_structures(str(project_root))[1]:
|
||||
if item.type_id != BERM_TYPE_ID:
|
||||
continue
|
||||
anchor = item.chainage_m if item.chainage_m is not None else item.start_m
|
||||
start = item.start_m if item.start_m is not None else anchor
|
||||
end = item.end_m if item.end_m is not None else anchor
|
||||
if start is None or end is None:
|
||||
continue
|
||||
options = item.options or {}
|
||||
width = number(options, "width_m", BERM_DEFAULT_WIDTH_M)
|
||||
if width <= 0:
|
||||
continue
|
||||
raw = options.get("depth_m")
|
||||
try:
|
||||
depth = BERM_DEFAULT_DEPTH_M if raw in (None, "") else max(float(raw), 0.0)
|
||||
except (TypeError, ValueError):
|
||||
depth = BERM_DEFAULT_DEPTH_M
|
||||
if not math.isfinite(depth):
|
||||
depth = BERM_DEFAULT_DEPTH_M
|
||||
spec = {
|
||||
"width_m": width,
|
||||
"interval_m": number(options, "interval_m", BERM_DEFAULT_INTERVAL_M),
|
||||
"slope_deg": number(options, "slope_deg", BERM_DEFAULT_SLOPE_DEG),
|
||||
"depth_m": depth,
|
||||
}
|
||||
spans.append((float(min(start, end)), float(max(start, end)), spec))
|
||||
return spans
|
||||
except Exception: # noqa: BLE001 — 정본을 못 읽으면 저장분으로 물러섬
|
||||
logger.exception("B06 소단 구간을 읽지 못했습니다 (저장분 소단을 씀)")
|
||||
return None
|
||||
|
||||
|
||||
def berm_span_at(
|
||||
spans: list[tuple[float, float, dict[str, float]]], chainage_m: float
|
||||
) -> dict[str, float] | None:
|
||||
"""그 측점을 덮는 소단 제원 — 겹치면 먼저 놓은 것(TS `bermSpecAt` 짝)."""
|
||||
for start, end, spec in spans:
|
||||
if start - 1e-6 <= chainage_m <= end + 1e-6:
|
||||
return spec
|
||||
return None
|
||||
|
||||
|
||||
def attach_wall_structures(project_root: Path, cross_sections: list[dict[str, Any]]) -> int:
|
||||
"""구간 안 측점의 횡단 dict에 `revetment` 키를 얹는다. 얹은 개수를 돌려준다.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user