From 32b841dda3244f259848e7daae22215396ea3218 Mon Sep 17 00:00:00 2001 From: umsangdon Date: Thu, 22 Oct 2026 14:24:12 +0900 Subject: [PATCH] =?UTF-8?q?feat(511-B=20B-2=20=EC=9D=B4=EC=9B=94=20?= =?UTF-8?q?=EC=97=B4=EC=87=A0=20=3D=20Node=20=EC=B6=9C=EB=A0=A5):=20?= =?UTF-8?q?=EB=85=B8=EC=84=A0=20=EC=A0=80=EC=9E=A5=20=ED=9A=A1=EB=8B=A8=20?= =?UTF-8?q?=EC=9D=B4=EC=9B=94(=5Fcarry=5Fcross)=20=EC=97=B4=EC=87=A0=20=3D?= =?UTF-8?q?=20=EC=B8=A1=EC=A0=90=EC=9D=B4=20=EC=A7=80=EB=8B=8C=20key(Node?= =?UTF-8?q?=20=EC=B8=A1=EC=A0=90=20=EC=83=9D=EC=84=B1=20=C2=B7=20keyed=5Fs?= =?UTF-8?q?tations)=20=C2=B7=20=EC=97=B4=EC=87=A0=20=EC=97=86=EB=8A=94=20?= =?UTF-8?q?=EC=B8=A1=EC=A0=90=EC=9D=B4=20=EC=84=9E=EC=9D=B4=EB=A9=B4(?= =?UTF-8?q?=EC=98=9B=20=ED=8C=8C=EC=9D=BC=20=C2=B7=20DTM=20=EC=95=84?= =?UTF-8?q?=EB=8B=8C=20=EC=A7=80=ED=91=9C=EB=A9=B4=20=C2=B7=20=EA=B5=AC?= =?UTF-8?q?=EC=A1=B0=EB=AC=BC=20=EC=B8=A1=EC=A0=90=20=EB=8D=A7)=20?= =?UTF-8?q?=ED=8C=8C=EC=9D=B4=EC=8D=AC=20station=5Fkeys=20=C2=B7=20?= =?UTF-8?q?=EA=B3=A0=EC=A0=95=20=EC=9E=90=EB=A3=8C=20=EC=97=B4=EC=87=A0=20?= =?UTF-8?q?=3D=20=ED=8C=8C=EC=9D=B4=EC=8D=AC=20=EC=97=B4=EC=87=A0=20?= =?UTF-8?q?=EA=B0=99=EC=9D=8C=20=C2=B7=20golden=20=EA=B8=B8=20=EA=B0=99?= =?UTF-8?q?=EC=9D=80=20=EA=B7=9C=EC=B9=99=20=E2=80=94=20=EC=9A=94=EA=B5=AC?= =?UTF-8?q?=20320-4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 --- B05_Profile/B05_Profile_Route_Save.py | 8 ++++++-- B05_Profile/B05_Profile_Route_Save_Parts.py | 15 ++++++++++++++- resources/tester/helper_472_1_paths.py | 16 ++++++++++++---- resources/tester/test_511_b2_stations_node.py | 14 ++++++++++++++ 4 files changed, 46 insertions(+), 7 deletions(-) diff --git a/B05_Profile/B05_Profile_Route_Save.py b/B05_Profile/B05_Profile_Route_Save.py index 388f627ff..6ab2390c9 100644 --- a/B05_Profile/B05_Profile_Route_Save.py +++ b/B05_Profile/B05_Profile_Route_Save.py @@ -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 = { diff --git a/B05_Profile/B05_Profile_Route_Save_Parts.py b/B05_Profile/B05_Profile_Route_Save_Parts.py index eee34ca91..990222a25 100644 --- a/B05_Profile/B05_Profile_Route_Save_Parts.py +++ b/B05_Profile/B05_Profile_Route_Save_Parts.py @@ -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:` · 구조물 `structure:` · 시종점 `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]: diff --git a/resources/tester/helper_472_1_paths.py b/resources/tester/helper_472_1_paths.py index 9540479a3..d4fd974c8 100644 --- a/resources/tester/helper_472_1_paths.py +++ b/resources/tester/helper_472_1_paths.py @@ -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"] diff --git a/resources/tester/test_511_b2_stations_node.py b/resources/tester/test_511_b2_stations_node.py index a8a5a389b..e0dd427b0 100644 --- a/resources/tester/test_511_b2_stations_node.py +++ b/resources/tester/test_511_b2_stations_node.py @@ -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