refactor(B05·B06): 소단 = 옹벽처럼 측점에 제원 얹음 — 형상 얹기 한 벌 · 세션 사본 berm 걷음 (PLAN 577-2 · 요구 434 · 437)
- 얹기: attachShapes · attach_shapes 에 소단(section.berm · 덮는 소단 없음 = null) · SHAPE_KEYS 에 berm · TS attachBermSpecs ↔ 파이썬 attach_berm_specs · berm_spans_from 짝 - 읽기: 저장 노선 다시 셈(브라우저 · Node cross.refresh) = 얹힌 section.berm(칸 없음 = 저장분 design.berm) · 노선 초안 · 서버 Node 묶음 cross = crossWithShapes 의 얹힌 제원(bermAt · crossWithBerm 걷음) - 계단은 계산 안쪽 그대로 · [저장] 길(구조물 정본 → cross.berm_spans) 그대로 - 지움: 시설 줄 syncBerm · putBerm(C4.copy) · writeBermSpans · 세션 칸 berm · bermRequest · design_shared bermAt - 시험: test_272_berm_source 측점 얹기 거울로 · test_323_4 소단 얹음 · 477 · 511-A · 472 떠남 · 365 · 272 고름 헬퍼가 사본 대신 얹힌 소단 · design_pipeline_page 700 줄 → 699(주석 한 줄) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -110,11 +110,10 @@ def wall_specs_from(structures: list[Any]) -> list[dict[str, Any]]:
|
||||
return found
|
||||
|
||||
|
||||
def load_berm_spans(project_root: Path) -> list[tuple[float, float, dict[str, float]]] | None:
|
||||
"""구조물 정본의 소단 구간 `[(시작, 끝, 제원)]` — [저장] 서버 다시 셈의 소단 원천(194-1).
|
||||
def berm_spans_from(structures: list[Any]) -> list[tuple[float, float, dict[str, float]]]:
|
||||
"""구조물 목록 → 소단 구간 `[(시작, 끝, 제원)]`(형상 얹기 한 벌 577-2 · [저장] 194-1).
|
||||
|
||||
짝: TS `bermSpansFromStructures`(같은 규칙 — 폭 0 = 없음 · 깊이 빈 값 = 기본 1.0 · 0 미만 = 0).
|
||||
못 읽으면 None(부르는 쪽이 저장분 `design.berm` 으로 물러섬).
|
||||
"""
|
||||
from common_util.common_util_cross_berm import (
|
||||
BERM_DEFAULT_DEPTH_M,
|
||||
@@ -130,35 +129,41 @@ def load_berm_spans(project_root: Path) -> list[tuple[float, float, dict[str, fl
|
||||
return fallback
|
||||
return value if math.isfinite(value) and value >= 0 else fallback
|
||||
|
||||
spans: list[tuple[float, float, dict[str, float]]] = []
|
||||
for item in structures:
|
||||
if (catalog_row(item.type_id) or {}).get("shape") != "berm": # 표 형상(323-4)
|
||||
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
|
||||
|
||||
|
||||
def load_berm_spans(project_root: Path) -> list[tuple[float, float, dict[str, float]]] | None:
|
||||
"""구조물 정본의 소단 구간 — [저장] 서버 다시 셈의 소단 원천(194-1) · 못 읽으면 None(부르는 쪽이
|
||||
저장분 `design.berm` 으로 물러섬)."""
|
||||
try:
|
||||
spans: list[tuple[float, float, dict[str, float]]] = []
|
||||
for item in load_structures(str(project_root))[1]:
|
||||
if (catalog_row(item.type_id) or {}).get("shape") != "berm": # 표 형상(323-4)
|
||||
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
|
||||
return berm_spans_from(load_structures(str(project_root))[1])
|
||||
except Exception: # noqa: BLE001 — 정본을 못 읽으면 저장분으로 물러섬
|
||||
logger.exception("B06 소단 구간을 읽지 못했습니다 (저장분 소단을 씀)")
|
||||
return None
|
||||
@@ -174,6 +179,24 @@ def berm_span_at(
|
||||
return None
|
||||
|
||||
|
||||
def attach_berm_specs(
|
||||
cross_sections: list[dict[str, Any]], spans: list[tuple[float, float, dict[str, float]]]
|
||||
) -> int:
|
||||
"""측점마다 소단 제원을 얹음(TS `attachBermSpecs` 짝 · 577-2) — 덮는 소단 없음 = None
|
||||
(얹었음 표시). 얹은 측점 수."""
|
||||
attached = 0
|
||||
for section in cross_sections:
|
||||
chainage = section.get("chainage_m")
|
||||
if isinstance(chainage, bool) or not isinstance(chainage, (int, float)):
|
||||
continue
|
||||
if not math.isfinite(chainage):
|
||||
continue
|
||||
spec = berm_span_at(spans, float(chainage))
|
||||
section["berm"] = dict(spec) if spec else None
|
||||
attached += 1 if spec else 0
|
||||
return attached
|
||||
|
||||
|
||||
def attach_wall_specs(cross_sections: list[dict[str, Any]], walls: list[dict[str, Any]]) -> int:
|
||||
"""구간 안 측점에 벽 제원을 얹는다(TS `attachWallSpecs` 짝). 얹은 개수를 돌려준다."""
|
||||
if not walls:
|
||||
|
||||
Reference in New Issue
Block a user