- E03_StabSection_Walls_Node.ts — B06 computeStoredLayouts(옹벽 · 석축 · 돌쌓기 · 관 기슭막이) 꼭짓점 · drawnProfile 지표 · 계산 없음
- E03_StabSection_Walls.py — walls_by_station(복사본 루트) → {chainage_key: {walls, design_line}} · design_with_walls · walls_of · 입구 TS 가 묶음보다 새로우면 다시 지음
- common_util_cross_structure_areas.ts drawnProfile 내보냄(동작 그대로) · package.json build:e03-walls 줄 · .gitignore 묶음 폴더
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
115 lines
4.9 KiB
Python
115 lines
4.9 KiB
Python
"""E03 2D 모형의 벽(옹벽 · 석축 · 돌쌓기 · 관 기슭막이) — 복사본 → 측점별 walls
|
|
(532-4 · 분석 345-D ② ⑤).
|
|
|
|
도형은 짓지 않음 — B06 화면 TS 를 서버 Node 로 돌림(`E03_StabSection_Walls_Node.ts` · 5장 ②).
|
|
얹기(어느 측점에 어느 벽) = B06 `attach_saved_shapes` 그대로(복사본 = 원본 프로젝트 배치).
|
|
벽 재료 = 모형 `WALL_MATERIAL`(고강도 — 활동면이 벽을 못 지남) · 꼴 = `build_section_model(walls)`.
|
|
벽이 선 측점은 지표도 B06 면적과 같은 「그려지는 설계선」(벽 상단에서 끊김)으로 바꿔 넘김.
|
|
|
|
부르는 법(E03 분석 길):
|
|
found = walls_by_station(root) # 복사본 루트 → {chainage_key: entry}
|
|
entry = found.get(chainage_key(cross["chainage_m"]))
|
|
model = section_model_from_b06(cross, design_with_walls(design, entry), walls=walls_of(entry))
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import logging
|
|
from pathlib import Path
|
|
from typing import Any
|
|
|
|
from common_util.common_util_node_bundle import ROOT, build_bundle, bundle_stale, run_bundle_json
|
|
from common_util.common_util_station_key import chainage_key
|
|
from E01_StabRegister import E01_StabRegister_Source as source
|
|
from E03_StabSection.E03_StabSection_Engine_Model import WALL_MATERIAL
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
NPM_SCRIPT = "build:e03-walls"
|
|
ENTRY = ROOT / "E03_StabSection" / "E03_StabSection_Walls_Node.ts"
|
|
BUNDLE = ROOT / "config" / "e03_walls_node" / "E03_StabSection_Walls_Node.js"
|
|
|
|
|
|
def _sections(root: Path) -> list[dict[str, Any]]:
|
|
"""복사본 측점 → B06 상세 꼴(chainage_m · 중심 · samples · design)
|
|
+ 형상 얹기(revetment · culvert …)."""
|
|
from B06_Section.B06_Section_Engine_Attach import attach_saved_shapes
|
|
|
|
sections = []
|
|
for station in source.stations(root):
|
|
cross = source.cross_section(root, station["chainage_m"])
|
|
sections.append(
|
|
{
|
|
**cross,
|
|
"center_x": station.get("center_x"),
|
|
"center_y": station.get("center_y"),
|
|
}
|
|
)
|
|
route = source.db_snapshot(root).get("route") or {}
|
|
attach_saved_shapes(root, sections, route.get("route_data_path"))
|
|
return sections
|
|
|
|
|
|
def _fresh_bundle() -> bool:
|
|
"""입구 TS 는 `SOURCE_DIRS` 밖(E03) — 입구가 묶음보다 새로우면 여기서 다시 지음."""
|
|
stale = bundle_stale(BUNDLE) or ENTRY.stat().st_mtime > BUNDLE.stat().st_mtime
|
|
return not stale or build_bundle(NPM_SCRIPT)
|
|
|
|
|
|
def walls_by_station(root: Path | str) -> dict[str, dict[str, Any]]:
|
|
"""복사본 루트 → {chainage_key: {walls: [모형 벽 …], design_line: [[offset, z] …] | None}}.
|
|
|
|
벽 · 트림이 없는 측점은 안 실음(그 측점 모형 = 종전 그대로). Node 실패는 던짐 — 벽을 빼고
|
|
해석하면 활동면이 벽을 지난 값이 조용히 남음.
|
|
"""
|
|
return walls_for_sections(_sections(Path(root)))
|
|
|
|
|
|
def walls_for_sections(sections: list[dict[str, Any]]) -> dict[str, dict[str, Any]]:
|
|
"""형상 얹은 B06 횡단 목록 → 측점 entry(`walls_by_station` 몸 · 시험이 바로 부름)."""
|
|
from B05_Profile.B05_Profile_Structures_Schema import load_definition
|
|
|
|
if not any(s.get("revetment") or s.get("culvert") for s in sections):
|
|
return {}
|
|
if not _fresh_bundle():
|
|
raise RuntimeError("E03 벽 도형 번들을 못 지음")
|
|
payload = json.loads(
|
|
json.dumps({"definition": load_definition(), "sections": sections}, default=str)
|
|
)
|
|
out = run_bundle_json(BUNDLE, NPM_SCRIPT, payload)
|
|
if not isinstance(out, dict):
|
|
raise RuntimeError("E03 벽 도형 Node 실패")
|
|
found: dict[str, dict[str, Any]] = {}
|
|
for row in out["stations"]:
|
|
walls = [
|
|
{
|
|
"material_id": WALL_MATERIAL["id"],
|
|
"kind": w["kind"],
|
|
"name": w.get("name"),
|
|
"structure_id": w.get("structure_id"),
|
|
"form": w.get("form"),
|
|
"polygon": w["polygon"],
|
|
}
|
|
for w in row["walls"]
|
|
]
|
|
if walls or row.get("design_line"):
|
|
found[chainage_key(float(row["chainage_m"]))] = {
|
|
"walls": walls,
|
|
"design_line": row.get("design_line"),
|
|
}
|
|
return found
|
|
|
|
|
|
def walls_of(entry: dict[str, Any] | None) -> list[dict[str, Any]] | None:
|
|
"""측점 entry → `section_model_from_b06(walls=…)` 값(없으면 None = 벽 없음)."""
|
|
return (entry or {}).get("walls") or None
|
|
|
|
|
|
def design_with_walls(design: dict[str, Any], entry: dict[str, Any] | None) -> dict[str, Any]:
|
|
"""벽이 선 측점 = 설계선을 그려지는 선(벽 상단에서 끊김)으로 바꾼 사본 · 아니면 그대로."""
|
|
line = (entry or {}).get("design_line")
|
|
if not line:
|
|
return design
|
|
return {**design, "design_line": [{"offset_m": o, "elevation_m": z} for o, z in line]}
|