refactor(511-B B-4 기본 설계 셋 Node · preview 걷음): run_calc = 늘 떠 있는 Node(못 띄우면 새 프로세스) · 기본 설계 셋(체인 · 노선 저장 이월 · [측점 만들기] · GET 빈 측점 · B05 확정 측구 방향 역반영) = 측점 묶음 Node cross.design 한 번 · 포장 · 기울임 · 세월교 하강 = TS facilityRanges(cross.design facilities · Node 못 부르면 파이썬 구간 짝) · /cross-design/preview 걷음(창구 · 스키마 · recompute_designs_for_alignment · 화면 refreshFromServer) · crossOptions = logic/B06_Section_Cross_Save.ts(다음 단계 [저장] 횡단 한 바퀴 짝 · 아직 안 부름) · 시험 266 · 475_3 · masshaul_single_source 기대 맞춤 — 요구 320-4
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -11,7 +11,6 @@ from typing import Any
|
||||
from B05_Profile.B05_Profile_Engine_Sections import find_cross_file
|
||||
from B06_Section.B06_Section_Engine_Design import (
|
||||
ROUTE_CARRY_KEYS,
|
||||
compute_cross_design,
|
||||
curve_widening_args,
|
||||
stored_shoulder_extend,
|
||||
stored_tilt,
|
||||
@@ -42,20 +41,6 @@ from common_util.common_util_cross_berm import (
|
||||
from common_util.common_util_route_profile import design_elevation_from_longitudinal
|
||||
from config.config_system import STANDARD_ROCK_BOUNDARY_DEFAULT_OFFSET_M
|
||||
|
||||
PREVIEW_DESIGN_FIELDS = (
|
||||
"ground_type",
|
||||
"roadbed_width_m",
|
||||
"cut_area_m2",
|
||||
"cut_soil_area_m2",
|
||||
"cut_rock_area_m2",
|
||||
"cut_rock_kind",
|
||||
"fill_area_m2",
|
||||
"fill_ground_slope",
|
||||
"design_elevation_m",
|
||||
"slope_unclosed",
|
||||
)
|
||||
|
||||
|
||||
# 사용자 조작값 — 다시 계산해도 그대로 승계한다. **이 목록이 서버의 유일한 한 벌이다.**
|
||||
#
|
||||
# 브라우저 쪽 짝은 `B06_Section_Cross_Refresh.ts` 의 `PRESERVED_KEYS` 다(+ `status`·
|
||||
@@ -375,34 +360,37 @@ def attach_default_designs(
|
||||
project_root: Path | None = None,
|
||||
standard: dict[str, Any] | None = None,
|
||||
) -> None:
|
||||
"""설계 없는 측점 = 기본값 프리뷰 — Node 묶음 한 번(TS 짝 · 시설 구간 TS · 511-B B-4)."""
|
||||
modes = default_section_modes(longitudinal)
|
||||
pavement = pavement_suggestions(longitudinal)
|
||||
paved_ranges = pavement_ranges(project_root) if project_root else []
|
||||
tilts = tilt_ranges(project_root)
|
||||
ford_drops = ford_surface_drops(project_root)
|
||||
jobs: list[tuple[dict[str, Any], float, DesignJob]] = []
|
||||
for section in cross_sections:
|
||||
if section.get("design"):
|
||||
continue
|
||||
try:
|
||||
chainage = float(section.get("chainage_m", 0.0))
|
||||
suggested = pavement.get(round(chainage, 3), False)
|
||||
design = compute_cross_design(
|
||||
section.get("samples", []),
|
||||
design_elevation_from_longitudinal(longitudinal, chainage),
|
||||
ground_type="ripping_rock",
|
||||
section_mode=modes.get(round(chainage, 3), "left_cut"),
|
||||
# 포장은 사용자 구간 지정만 켠다 — 경사 제안은 경고로만 남는다(2026-08-28).
|
||||
paved=paved_at(chainage, paved_ranges),
|
||||
standard=standard,
|
||||
rock_boundary_offset_m=STANDARD_ROCK_BOUNDARY_DEFAULT_OFFSET_M,
|
||||
surface_drop_m=ford_drop_at(chainage, ford_drops),
|
||||
**curve_widening_args(section),
|
||||
**tilt_args(chainage, tilts),
|
||||
)
|
||||
design.update(status="provisional", pavement_suggested=suggested)
|
||||
section["design"] = design
|
||||
except (ValueError, KeyError):
|
||||
chainage = float(section.get("chainage_m", 0.0))
|
||||
options = dict(
|
||||
ground_type="ripping_rock",
|
||||
section_mode=modes.get(round(chainage, 3), "left_cut"),
|
||||
# 포장은 사용자 구간 지정만 켠다 — 경사 제안은 경고로만 남는다(2026-08-28) · 구간 = TS
|
||||
rock_boundary_offset_m=STANDARD_ROCK_BOUNDARY_DEFAULT_OFFSET_M,
|
||||
**curve_widening_args(section),
|
||||
)
|
||||
elevation = design_elevation_from_longitudinal(longitudinal, chainage)
|
||||
jobs.append((section, chainage, (section.get("samples", []), elevation, options)))
|
||||
if not jobs:
|
||||
return
|
||||
designs = compute_cross_designs(
|
||||
[job for *_rest, job in jobs],
|
||||
standard,
|
||||
(project_root, [c for _s, c, _j in jobs]) if project_root else None,
|
||||
)
|
||||
for (section, chainage, _job), design in zip(jobs, designs, strict=True):
|
||||
if design is None:
|
||||
continue
|
||||
design.update(
|
||||
status="provisional", pavement_suggested=pavement.get(round(chainage, 3), False)
|
||||
)
|
||||
section["design"] = design
|
||||
|
||||
|
||||
def stored_cut_slope(stored: dict[str, Any]) -> float | None:
|
||||
@@ -445,96 +433,6 @@ def stored_berm(stored: dict[str, Any]) -> BermSpec | None:
|
||||
return berm_from(stored.get("berm"), stored)
|
||||
|
||||
|
||||
def recompute_designs_for_alignment(
|
||||
longitudinal: dict[str, Any],
|
||||
cross_sections: list[dict[str, Any]],
|
||||
stored_designs: list[dict[str, Any]],
|
||||
standard: dict[str, Any] | None,
|
||||
rock_boundary_offsets: dict[str, float] | None = None,
|
||||
project_root: Path | None = None,
|
||||
berms: dict[str, dict[str, float]] | None = None,
|
||||
cut_slope_ratios: dict[str, float] | None = None,
|
||||
) -> None:
|
||||
modes = default_section_modes(longitudinal)
|
||||
pavement = pavement_suggestions(longitudinal)
|
||||
paved_ranges = pavement_ranges(project_root) if project_root else []
|
||||
tilts = tilt_ranges(project_root)
|
||||
ford_drops = ford_surface_drops(project_root)
|
||||
stored_by_chainage = {
|
||||
round(float(record["chainage_m"]), 3): (record.get("design") or {})
|
||||
for record in stored_designs
|
||||
}
|
||||
# 측점별 암 절토 경사(2026-09-07) — 0 은 「표준값을 씀」이라 저장분을 덮어 지운다.
|
||||
session_cut_slopes: dict[float, float] = {}
|
||||
for raw_key, ratio in (cut_slope_ratios or {}).items():
|
||||
try:
|
||||
session_cut_slopes[round(float(raw_key), 3)] = float(ratio)
|
||||
except (TypeError, ValueError):
|
||||
continue
|
||||
session_offsets: dict[float, float] = {}
|
||||
for raw_key, offset in (rock_boundary_offsets or {}).items():
|
||||
try:
|
||||
session_offsets[round(float(raw_key), 3)] = float(offset)
|
||||
except (TypeError, ValueError):
|
||||
continue
|
||||
# 측점별 소단 제원 — 값이 없는 측점은 소단 없음(종전 설계 그대로).
|
||||
session_berms: dict[float, BermSpec] = {}
|
||||
for raw_key, spec in (berms or {}).items():
|
||||
try:
|
||||
parsed = berm_from(spec, spec if isinstance(spec, dict) else {}) # 쪽 깊이도(194-1)
|
||||
if parsed is not None:
|
||||
session_berms[round(float(raw_key), 3)] = parsed
|
||||
except (TypeError, ValueError):
|
||||
continue
|
||||
for section in cross_sections:
|
||||
chainage = float(section.get("chainage_m", 0.0))
|
||||
key = round(chainage, 3)
|
||||
stored = stored_by_chainage.get(key) or {}
|
||||
suggested = pavement.get(key, False)
|
||||
try:
|
||||
design = compute_cross_design(
|
||||
section.get("samples", []),
|
||||
design_elevation_from_longitudinal(longitudinal, chainage),
|
||||
ground_type=str(stored.get("ground_type") or "ripping_rock"),
|
||||
section_mode=str(stored.get("section_mode") or modes.get(key, "left_cut")),
|
||||
ditch_side=stored.get("ditch_side"),
|
||||
ditch_type=str(stored.get("ditch_type") or "standard"),
|
||||
paved=paved_at(chainage, paved_ranges),
|
||||
standard=standard,
|
||||
rock_boundary_offset_m=session_offsets.get(
|
||||
key,
|
||||
stored.get("rock_boundary_offset_m", STANDARD_ROCK_BOUNDARY_DEFAULT_OFFSET_M),
|
||||
),
|
||||
two_stage_slope=bool(stored.get("two_stage_slope", False)),
|
||||
cut_slope_ratio=(
|
||||
(session_cut_slopes[key] or None)
|
||||
if key in session_cut_slopes
|
||||
else stored_cut_slope(stored)
|
||||
),
|
||||
ditch_enabled=stored.get("ditch_enabled"),
|
||||
ditch_choice=stored.get("ditch_choice"),
|
||||
surface_drop_m=ford_drop_at(chainage, ford_drops),
|
||||
berm=session_berms.get(key) or stored_berm(stored),
|
||||
**curve_widening_args(section),
|
||||
**stored_shoulder_extend(stored), # 노견 확장(139-6)
|
||||
**tilt_args(chainage, tilts),
|
||||
)
|
||||
except (ValueError, KeyError):
|
||||
continue
|
||||
design.update(status="provisional", pavement_suggested=suggested)
|
||||
if stored.get("display_half_width_m") is not None:
|
||||
design["display_half_width_m"] = stored["display_half_width_m"]
|
||||
if stored.get("inlet_structure") is not None:
|
||||
design["inlet_structure"] = stored["inlet_structure"]
|
||||
if stored.get("basin_adjust") is not None:
|
||||
design["basin_adjust"] = stored["basin_adjust"]
|
||||
if stored.get("ford_adjust") is not None:
|
||||
design["ford_adjust"] = stored["ford_adjust"]
|
||||
if stored.get("box_adjust") is not None:
|
||||
design["box_adjust"] = stored["box_adjust"]
|
||||
section["design"] = design
|
||||
|
||||
|
||||
def compute_default_designs(
|
||||
project_root: Path,
|
||||
longitudinal_file_path: str,
|
||||
@@ -562,10 +460,7 @@ def compute_default_designs(
|
||||
cross_dir = longitudinal_path.parent.parent / "cross_sections"
|
||||
default_modes = default_section_modes(longitudinal)
|
||||
pavement = pavement_suggestions(longitudinal)
|
||||
paved_ranges = pavement_ranges(root)
|
||||
tilts = tilt_ranges(root)
|
||||
ford_drops = ford_surface_drops(root)
|
||||
results: list[tuple[float, dict[str, Any]]] = []
|
||||
entries: list[tuple[float, dict[str, Any], DesignJob]] = []
|
||||
for chainage_m in chainages:
|
||||
cross = (crosses or {}).get(round(chainage_m, 3))
|
||||
cross_path = find_cross_file(cross_dir, chainage_m)
|
||||
@@ -577,12 +472,9 @@ def compute_default_designs(
|
||||
samples = cross.get("samples")
|
||||
if not isinstance(samples, list):
|
||||
continue
|
||||
suggested = pavement.get(round(chainage_m, 3), False)
|
||||
user = (carried or {}).get(round(chainage_m, 3)) or {}
|
||||
rock_offset = user.get("rock_boundary_offset_m")
|
||||
design = compute_cross_design(
|
||||
samples,
|
||||
design_elevation_from_longitudinal(longitudinal, chainage_m),
|
||||
options = dict(
|
||||
ground_type=str(user.get("ground_type") or "ripping_rock"),
|
||||
# 손 상단측(같은 자리로 넘긴 단면 유형 · 측구 방향 · 요구 275-3) · 없으면 상단측
|
||||
section_mode=user.get("section_mode")
|
||||
@@ -594,27 +486,32 @@ def compute_default_designs(
|
||||
),
|
||||
ditch_side=user.get("ditch_side"),
|
||||
ditch_type=str(user.get("ditch_type") or "standard"),
|
||||
# 포장은 사용자 구간 지정만 켠다 — 경사 제안은 경고로만 남는다(2026-08-28).
|
||||
paved=paved_at(chainage_m, paved_ranges),
|
||||
standard=standard,
|
||||
# 포장 · 기울임 · 세월교 하강 = 구간 · 관 지점(TS `facilityRanges` · 511-B B-4)
|
||||
rock_boundary_offset_m=(
|
||||
STANDARD_ROCK_BOUNDARY_DEFAULT_OFFSET_M if rock_offset is None else rock_offset
|
||||
),
|
||||
two_stage_slope=bool(user.get("two_stage_slope", False)),
|
||||
cut_slope_ratio=stored_cut_slope(user),
|
||||
ditch_choice=user.get("ditch_choice"),
|
||||
surface_drop_m=ford_drop_at(chainage_m, ford_drops),
|
||||
berm=stored_berm(user),
|
||||
**curve_widening_args(cross),
|
||||
**stored_shoulder_extend(user), # 노선 저장이 넘긴 사면 쉬프트(417)
|
||||
**tilt_args(chainage_m, tilts),
|
||||
)
|
||||
for key in ("berm", "cut_slope_ratio_user", *ROUTE_CARRY_KEYS):
|
||||
if user.get(key) is not None:
|
||||
design[key] = user[key]
|
||||
design["status"] = "provisional"
|
||||
design["pavement_suggested"] = suggested
|
||||
results.append((chainage_m, design))
|
||||
elevation = design_elevation_from_longitudinal(longitudinal, chainage_m)
|
||||
except (ValueError, KeyError, OSError, json.JSONDecodeError):
|
||||
continue
|
||||
entries.append((chainage_m, user, (samples, elevation, options)))
|
||||
designs = compute_cross_designs(
|
||||
[job for *_rest, job in entries], standard, (root, [c for c, _u, _j in entries])
|
||||
)
|
||||
results: list[tuple[float, dict[str, Any]]] = []
|
||||
for (chainage_m, user, _job), design in zip(entries, designs, strict=True):
|
||||
if design is None:
|
||||
continue # 계획고 부재 등 — 조용히 건너뜀(확정을 막지 않음)
|
||||
for key in ("berm", "cut_slope_ratio_user", *ROUTE_CARRY_KEYS):
|
||||
if user.get(key) is not None:
|
||||
design[key] = user[key]
|
||||
design["status"] = "provisional"
|
||||
design["pavement_suggested"] = pavement.get(round(chainage_m, 3), False)
|
||||
results.append((chainage_m, design))
|
||||
return results
|
||||
|
||||
Reference in New Issue
Block a user