feat(511-B B-2 이월 열쇠 = Node 출력): 노선 저장 횡단 이월(_carry_cross) 열쇠 = 측점이 지닌 key(Node 측점 생성 · keyed_stations) · 열쇠 없는 측점이 섞이면(옛 파일 · DTM 아닌 지표면 · 구조물 측점 덧) 파이썬 station_keys · 고정 자료 열쇠 = 파이썬 열쇠 같음 · golden 길 같은 규칙 — 요구 320-4

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-22 14:24:12 +09:00
co-authored by Claude Opus 5.5
parent f7e9751b81
commit 32b841dda3
4 changed files with 46 additions and 7 deletions
+6 -2
View File
@@ -53,6 +53,7 @@ from B05_Profile.B05_Profile_Route_Save_Parts import (
follow_pipes,
route_moved_stations,
seat_route_moved,
keyed_stations,
station_keys,
station_seats,
vertices_of,
@@ -331,8 +332,11 @@ async def _carry_cross(
new_long = _read_json(project_root / relative)
_, new_structures = load_structures(str(project_root))
old_keys = station_keys(old_long.get("stations") or [], old_pipes, old_structures, interval_m)
new_keys = station_keys(
# 열쇠 = Node 측점 출력(`key` · 511-B B-2) · 없으면(옛 파일 · DTM 아닌 지표면) 파이썬 열쇠
old_keys = keyed_stations(old_long.get("stations") or []) or station_keys(
old_long.get("stations") or [], old_pipes, old_structures, interval_m
)
new_keys = keyed_stations(new_long.get("stations") or []) or station_keys(
new_long.get("stations") or [], [pipe for _, pipe in pairs], new_structures, interval_m
)
designs = {
+14 -1
View File
@@ -10,7 +10,8 @@ DB · 파일 없이 값만 받아 값을 돌려준다(시험이 그대로 부름
같은 세류선 라벨 관(옮겼어도) · 지움 표지가 짝으로 잡은 교차점엔 안 더함(507-2 ·
`common_util_stream_crossing`).
- 관 최대 간격 보충 없음(369) — 간격 보충은 배수유역 [자동 제안]만.
- 측점 열쇠 = `common_util_station_key.station_key` 한 벌(sub2 짝) — 일반 `grid:k` ·
- 측점 열쇠 = Node 측점 생성이 측점에 적은 `key`(511-B B-2 · `keyed_stations`) · 없으면(옛 파일 ·
DTM 아닌 지표면) `common_util_station_key.station_key` 한 벌(sub2 짝) — 일반 `grid:k` ·
관 `pipe:<id>` · 구조물 `structure:<id>` · 시종점 `end:BP` · `end:EP` ·
id 없으면 `at:<누가거리 0.01 m>`.
- 횡단 이월 = 같은 열쇠 측점에 `CARRY_INPUT_KEYS` 일곱 + `ROUTE_CARRY_KEYS`(사면 쉬프트 ·
@@ -176,6 +177,18 @@ def station_keys(
return out
def keyed_stations(stations: Sequence[dict[str, Any]]) -> dict[str, float] | None:
"""측점이 지닌 열쇠(`key` · Node 측점 생성 출력 · 511-B B-2) → 누가거리 · 열쇠 없는 측점이 있으면
None(옛 파일 · DTM 아닌 지표면 = `station_keys` 로 셈)."""
rows = [row for row in stations if row.get("chainage_m") is not None]
if not rows or not all(isinstance(row.get("key"), str) for row in rows):
return None
out: dict[str, float] = {}
for row in rows:
out.setdefault(row["key"], float(row["chainage_m"]))
return out
def station_seats(
stations: Sequence[dict[str, Any]], keys: dict[str, float]
) -> dict[str, tuple[float, float, tuple[float, float] | None] | None]:
+12 -4
View File
@@ -97,7 +97,7 @@ def values_of(
def _keys(longitudinal: dict[str, Any], sections: list[dict[str, Any]], root: Path) -> list:
"""서버 측점 열쇠(`station_keys` · 노선 저장 이월이 쓰는 한 벌) — 상세 측점 차례."""
from B05_Profile.B05_Profile_Route_Save_Parts import station_keys
from B05_Profile.B05_Profile_Route_Save_Parts import keyed_stations, station_keys
from B05_Profile.B05_Profile_Structures_Repository import load_structures
from common_util.common_util_drainage_pipes import pipe_points_path_in, read_pipe_points_file
@@ -107,7 +107,9 @@ def _keys(longitudinal: dict[str, Any], sections: list[dict[str, Any]], root: Pa
(longitudinal.get("profile_alignment") or {}).get("policy", {}).get("station_interval_m")
or 20.0
)
found = station_keys(longitudinal.get("stations") or [], pipes, structures, interval)
found = keyed_stations(longitudinal.get("stations") or []) or station_keys(
longitudinal.get("stations") or [], pipes, structures, interval
)
by_m = {round(at, 3): key for key, at in found.items()}
return [by_m.get(round(float(s["chainage_m"]), 3)) for s in sections]
@@ -179,7 +181,11 @@ def server_route(root: Path) -> dict[str, Any]:
from B05_Profile.B05_Profile_Engine_Grade_Carry import carry_policy
from B05_Profile.B05_Profile_Engine_Sections import run_section_generation
from B05_Profile.B05_Profile_Engine_Sections_Core import SectionGenerationOptions
from B05_Profile.B05_Profile_Route_Save_Parts import carry_cross_inputs, station_keys
from B05_Profile.B05_Profile_Route_Save_Parts import (
carry_cross_inputs,
keyed_stations,
station_keys,
)
from B05_Profile.B05_Profile_Router import _apply_alignment_edits
from B05_Profile.B05_Profile_Structures_Repository import load_structures
from B06_Section.B06_Section_Engine_Design import ROUTE_CARRY_KEYS
@@ -221,7 +227,9 @@ def server_route(root: Path) -> dict[str, Any]:
_, structures = load_structures(str(root))
interval = float(options["station_interval_m"])
old_keys = station_keys(saved["longitudinal"]["stations"], pipes, structures, interval)
new_keys = station_keys(new_long.get("stations") or [], pipes, structures, interval)
new_keys = keyed_stations(new_long.get("stations") or []) or station_keys(
new_long.get("stations") or [], pipes, structures, interval
)
designs = {
round(float(s["chainage_m"]), 3): s["design"]
for s in saved["cross_sections"]
@@ -199,3 +199,17 @@ def test_등록부_측점_줄_Node():
):
row = src.split(f'no: "{no}"')[1].split("\n },")[0]
assert f'runner: "node:{run}"' in row and "until" not in row, no
def test_이월_열쇠_Node_출력_없으면_파이썬(project):
from B05_Profile.B05_Profile_Route_Save_Parts import keyed_stations, station_keys
_, noded = _both(project)
stations = noded["longitudinal"]["stations"]
keyed = keyed_stations(stations)
pipes, structures, _ = project["facilities"]
assert keyed == station_keys(stations, pipes, structures, 20.0) # 고정 자료 = 같은 열쇠
assert keyed_stations([{k: v for k, v in s.items() if k != "key"} for s in stations]) is None
assert keyed_stations([*stations, {"chainage_m": 1.0}]) is None # 섞이면(구조물 측점 덧) 파이썬
route_save = (ROOT / "B05_Profile/B05_Profile_Route_Save.py").read_text(encoding="utf-8")
assert route_save.count("keyed_stations(") == 2