From 3995e91a1c301cfaaed03b2cfba53ec58e33b0ae Mon Sep 17 00:00:00 2001 From: umsangdon Date: Fri, 16 Oct 2026 11:59:38 +0900 Subject: [PATCH] =?UTF-8?q?refactor(346-3):=20=EB=85=B8=EC=84=A0=20?= =?UTF-8?q?=EC=A0=80=EC=9E=A5=20=ED=9A=A1=EB=8B=A8=20=EC=9D=B4=EC=9B=94=20?= =?UTF-8?q?=EC=B8=A1=EC=A0=90=20=EC=97=B4=EC=87=A0=20=3D=20common=5Futil?= =?UTF-8?q?=5Fstation=5Fkey=20=ED=95=9C=20=EB=B2=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - station_keys 가 station_key(sub2 짝)를 부름 · 관 pipe:(id 없으면 at:<0.01 m>) · 구조물 structure: · 같은 열쇠 둘째는 at:(B06 stationKeysOf 와 같음) - 파일 차례 관 열쇠 없앰 · 시험 test_346_3_route_save 고쳐 씀 Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01Ji4nuyLVHcxrXWHTdb5nRD --- B05_Profile/B05_Profile_Route_Save.py | 6 +- B05_Profile/B05_Profile_Route_Save_Parts.py | 77 +++++++++++---------- resources/tester/test_346_3_route_save.py | 23 +++--- 3 files changed, 59 insertions(+), 47 deletions(-) diff --git a/B05_Profile/B05_Profile_Route_Save.py b/B05_Profile/B05_Profile_Route_Save.py index d1e344d79..9354d5d44 100644 --- a/B05_Profile/B05_Profile_Route_Save.py +++ b/B05_Profile/B05_Profile_Route_Save.py @@ -284,10 +284,10 @@ 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 [], list(enumerate(old_pipes)), old_structures, interval_m + old_keys = station_keys(old_long.get("stations") or [], old_pipes, old_structures, interval_m) + new_keys = station_keys( + new_long.get("stations") or [], [pipe for _, pipe in pairs], new_structures, interval_m ) - new_keys = station_keys(new_long.get("stations") or [], pairs, new_structures, interval_m) designs = { round(float(row["chainage_m"]), 3): row["design"] for row in old_designs diff --git a/B05_Profile/B05_Profile_Route_Save_Parts.py b/B05_Profile/B05_Profile_Route_Save_Parts.py index f3ec307f5..d31a7277a 100644 --- a/B05_Profile/B05_Profile_Route_Save_Parts.py +++ b/B05_Profile/B05_Profile_Route_Save_Parts.py @@ -8,9 +8,9 @@ DB · 파일 없이 값만 받아 값을 돌려준다(시험이 그대로 부름 (사용자 관 편집 지킴). - 새 세류선 교차점(옛 노선 위에 없던 자리)에 관이 없으면 기본 관 하나(`_base_pipes` 결과를 받음). - 관 최대 간격 보충 = 옛 노선에서 벗어난 자리의 **오목 지점**(지반 종단 낮은 곳)에만 — 격자 없음. - - 측점 열쇠(계약 `design_pipeline_types.ts` 머리) = 일반 `grid:k`(누가거리 ÷ 측점 간격 반올림) · - 관 `pipe:` · 구조물 `structure:`(구간 시작 · 끝은 `:start` · `:end`) · 시종점 - `end:BP` · `end:EP`. 관 id = 저장 파일 차례(노선 저장 한 번 안에서 옛 · 새가 같음). + - 측점 열쇠 = `common_util_station_key.station_key` 한 벌(sub2 짝) — 일반 `grid:k` · + 관 `pipe:` · 구조물 `structure:` · 시종점 `end:BP` · `end:EP` · + id 없으면 `at:<누가거리 0.01 m>`. - 횡단 이월 = 같은 열쇠 측점에 `CARRY_INPUT_KEYS` 일곱 · 관 · 구조물 열쇠면 `STRUCTURE_ADJUST_KEYS` 도(구조물 조정은 구조물 따라) · 열쇠가 사라진 측점 수 = 「노선 밖 고침」. @@ -32,6 +32,8 @@ from common_util.common_util_drainage_pipes import ( project_pipe_points, ) from common_util.common_util_route_geometry import RouteVertex +from common_util.common_util_station_key import chainage_key as station_chainage_key +from common_util.common_util_station_key import station_key from common_util.common_util_structure_station import plan_stations, snap_structure_station from config.config_system import DRAINAGE_PIPE_MAX_SPACING_M, DRAINAGE_PIPE_MIN_SPACING_M @@ -59,7 +61,7 @@ def vertices_of(xy: Sequence[Sequence[float]]) -> list[RouteVertex]: def follow_pipes( old_pipes: list[PipePoint], vertices: list[RouteVertex] ) -> list[tuple[int, PipePoint]]: - """관이 새 노선 좌표를 따라감 → [(관 id = 옛 차례, 새 관)] 누가거리 순 · 옛 목록 그대로.""" + """관이 새 노선 좌표를 따라감 → [(옛 차례 · 더한 관 -1, 새 관)] 누가거리 순 · 옛 목록 그대로.""" pairs = [(index, copy.deepcopy(pipe)) for index, pipe in enumerate(old_pipes)] for _, pipe in pairs: project_pipe_points([pipe], vertices) @@ -145,49 +147,54 @@ def fill_concave_pipes( added += 1 -def _facility_keys( - pipes: Sequence[tuple[int, PipePoint]], structures: Sequence[Any] -) -> dict[float, str]: - """측점 자리(0.01 m) → 관 · 구조물 열쇠. 같은 자리면 관이 먼저(`plan_stations` 이름 규칙).""" - keys: dict[float, str] = {} - - def put(marks: list[dict[str, object]], head: str) -> None: - for mark in marks: - role = str(mark.get("role") or "anchor") - keys.setdefault( - round(float(mark["chainage_m"]), 2), head if role == "anchor" else f"{head}:{role}" +def _facility_owners( + pipes: Sequence[PipePoint], structures: Sequence[Any] +) -> dict[float, tuple[str, str | None]]: + """측점 자리(0.01 m) → (관 · 구조물, id). 같은 자리면 관이 먼저(`plan_stations` 이름 규칙).""" + owners: dict[float, tuple[str, str | None]] = {} + for pipe in pipes: + for mark in plan_stations([pipe], []): + owners.setdefault( + round(float(mark["chainage_m"]), 2), ("pipe", getattr(pipe, "id", None)) ) - - for pipe_id, pipe in pipes: - if pipe_id >= 0: - put(plan_stations([pipe], []), f"pipe:{pipe_id}") for item in structures: - if getattr(item, "structure_id", None): - put(plan_stations([], [item]), f"structure:{item.structure_id}") - return keys + for mark in plan_stations([], [item]): + owners.setdefault( + round(float(mark["chainage_m"]), 2), + ("structure", getattr(item, "structure_id", None)), + ) + return owners def station_keys( stations: Sequence[dict[str, Any]], - pipes: Sequence[tuple[int, PipePoint]], + pipes: Sequence[PipePoint], structures: Sequence[Any], interval_m: float, ) -> dict[str, float]: - """측점 열쇠 → 누가거리. 관 · 구조물 자리 > 시종점 > 일반 격자(간격 배수인 것만).""" - facility = _facility_keys(pipes, structures) + """측점 열쇠(`common_util_station_key.station_key` 한 벌) → 누가거리. + + 관 · 구조물 자리 > 시종점 > 일반 격자(간격 배수인 것만) · id 없는 관 · 구조물은 `at:` · + 같은 열쇠가 둘이면 뒤엣것은 `at:`(B06 `stationKeysOf` 와 같음). + """ + owners = _facility_owners(pipes, structures) values = [float(row["chainage_m"]) for row in stations if row.get("chainage_m") is not None] out: dict[str, float] = {} for index, chainage in enumerate(values): - key = facility.get(round(chainage, 2)) - if key is None and index == 0: - key = "end:BP" - elif key is None and index == len(values) - 1: - key = "end:EP" - elif key is None and interval_m > 0: - k = round(chainage / interval_m) - key = f"grid:{k}" if abs(chainage - k * interval_m) < _SAME_M else None - if key is not None: - out.setdefault(key, chainage) + owner = owners.get(round(chainage, 2)) + if owner is not None: + key = station_key(owner[0], chainage, interval_m, owner[1]) + elif index == 0: + key = station_key("bp", chainage, interval_m) + elif index == len(values) - 1: + key = station_key("ep", chainage, interval_m) + elif interval_m > 0 and abs(chainage - round(chainage / interval_m) * interval_m) < _SAME_M: + key = station_key("regular", chainage, interval_m) + else: + continue + if key in out: + key = f"at:{station_chainage_key(chainage)}" + out.setdefault(key, chainage) return out diff --git a/resources/tester/test_346_3_route_save.py b/resources/tester/test_346_3_route_save.py index 3a0618cb5..55bf9a055 100644 --- a/resources/tester/test_346_3_route_save.py +++ b/resources/tester/test_346_3_route_save.py @@ -131,31 +131,36 @@ def _structure(sid, type_id, anchor, start=None, end=None): def test_측점_열쇠_규칙(): - stations = [{"chainage_m": s} for s in (0.0, 20.0, 40.0, 50.0, 60.0, 77.0, 80.0, 95.5)] - pipes = [(3, PipePoint(chainage_m=50.0))] + """`common_util_station_key` 한 벌 — 관 · 구조물 id · id 없으면 at: · 같은 열쇠 둘째는 at:.""" + stations = [{"chainage_m": s} for s in (0.0, 20.0, 33.3, 40.0, 50.0, 60.0, 77.0, 80.0, 95.5)] + with_id = PipePoint(chainage_m=50.0) + with_id.id = "p-7" # sub3 이 넣는 관 id + no_id = PipePoint(chainage_m=33.3) structures = [_structure("w1", "retaining_wall", 77.0, 60.0, 80.0)] - keys = station_keys(stations, pipes, structures, 20.0) + keys = station_keys(stations, [with_id, no_id], structures, 20.0) assert keys == { "end:BP": 0.0, "grid:1": 20.0, + "at:33.30": 33.3, # id 없는 관 "grid:2": 40.0, - "pipe:3": 50.0, - "structure:w1:start": 60.0, - "structure:w1": 77.0, - "structure:w1:end": 80.0, + "pipe:p-7": 50.0, + "structure:w1": 60.0, # 구간 시작 측점이 먼저 열쇠를 가짐 + "at:77.00": 77.0, # 같은 구조물 열쇠 둘째 — at: + "at:80.00": 80.0, "end:EP": 95.5, } + assert "pipe:0" not in keys and "pipe:1" not in keys # 파일 차례 열쇠 없음 def test_이월은_열쇠로_누가거리가_밀려도(): old_keys = { "end:BP": 0.0, "grid:1": 20.0, - "pipe:0": 50.0, + "pipe:p-7": 50.0, "structure:w1": 77.0, "grid:5": 100.0, } - new_keys = {"end:BP": 0.0, "grid:1": 20.0, "pipe:0": 57.0, "structure:w1": 84.0} + new_keys = {"end:BP": 0.0, "grid:1": 20.0, "pipe:p-7": 57.0, "structure:w1": 84.0} designs = { 0.0: {"ground_type": "soil"}, 20.0: {"ground_type": "rock", "berm": {"on": True}, "cut_area_m2": 9.0},