From e54ee5314abd7b37b1bdcf2702c8ef25fc17b760 Mon Sep 17 00:00:00 2001 From: umsangdon Date: Tue, 3 Nov 2026 16:21:04 +0900 Subject: [PATCH] =?UTF-8?q?fix(765-3):=20=EB=91=90=20=EB=B2=8C=20=3D=20?= =?UTF-8?q?=EA=B0=99=EC=9D=80=20=ED=8F=89=EB=A9=B4=20=EB=85=B8=EC=84=A0=20?= =?UTF-8?q?=E2=80=94=20=EC=98=88=EC=83=81=EB=85=B8=EC=84=A0=EC=9D=84=20?= =?UTF-8?q?=EC=84=A4=EA=B3=84=20=EC=A7=80=ED=98=95=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EB=A8=BC=EC=A0=80=20=EC=9E=98=EB=9D=BC=20=EC=A0=81=EA=B3=A0=20?= =?UTF-8?q?=EB=8B=A4=EB=A5=B8=20=EC=A7=80=ED=98=95=20=EB=B2=8C=EB=8F=84=20?= =?UTF-8?q?=EA=B7=B8=20=EB=85=B8=EC=84=A0=EC=9C=BC=EB=A1=9C=20=EC=A7=80?= =?UTF-8?q?=EC=9D=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 검증_sub5 실측: 수치지형도 벌이 수치지형도로 자른 긴 노선(2110 m)으로 지어져 공유 예상노선(라이다로 자름 · 1377 m)과 어긋남 → 그 벌 [초기화] 뒤 초기 폴리라인이 예상노선(라이다)으로 다시 지어져 노선 1359.6 m · 종횡단 2110 m 로 갈림 - 예상노선(공유 · 추천 열쇠)은 하나 · 설계 지형으로 자름 → 옛 지형 칩처럼 평면 노선 같고 지형만 다름 - 다른 지형 벌 끝에 예상노선 지우던 길 걷음(먼저 적으니 필요 없음) - 시험 test_765_design_sets 체인 차례에 예상노선 먼저 적기 Co-Authored-By: Claude Opus 5.5 --- B03_FileInput/B03_FileInput_Service_Chain.py | 29 ++++++++++++++++---- resources/tester/test_765_design_sets.py | 19 ++++++++++--- 2 files changed, 38 insertions(+), 10 deletions(-) diff --git a/B03_FileInput/B03_FileInput_Service_Chain.py b/B03_FileInput/B03_FileInput_Service_Chain.py index e51abe468..c5fac8502 100644 --- a/B03_FileInput/B03_FileInput_Service_Chain.py +++ b/B03_FileInput/B03_FileInput_Service_Chain.py @@ -390,7 +390,6 @@ async def run_preprocess_chain( mark_designing, read_design_failure, ) - from common_util.common_util_route_geometry import expected_route_csv_path from common_util.common_util_storage import resolve_stored_project_path from common_util.common_util_surface_confirmation import ( design_terrain, @@ -416,9 +415,9 @@ async def run_preprocess_chain( missing = "sheet" if design == "las" else "las" sets.note_unbuilt(root, missing, f"{missing} 지표면 모델 없음 — 한 벌만") else: - # 예상노선(공유)은 설계 지형 벌이 씀 — 다른 지형으로 자른 것이 남지 않게 - expected = expected_route_csv_path(root) - had_expected = expected.is_file() + # 예상노선(공유 · 추천이 씀)은 설계 지형으로 자른 것 하나 — 먼저 적어 두면 두 벌이 같은 + # 평면 노선으로 지어짐(지형만 다름 · 다른 지형 벌 [초기화]도 같은 노선) + await _seed_expected_route(project_id, root, params) try: async with pool.acquire() as connection: model_id = await sets.switch_terrain(connection, project_id, other) @@ -438,8 +437,6 @@ async def run_preprocess_chain( await sets.clear_active_set(connection, root, str(project_id)) sets.note_unbuilt(root, other, f"짓기 오류: {exc}") finally: - if not had_expected: - expected.unlink(missing_ok=True) async with pool.acquire() as connection: await sets.switch_terrain(connection, project_id, design) marks.append((f"{other} 벌", time.perf_counter())) @@ -456,6 +453,26 @@ async def run_preprocess_chain( schedule_precompute(project_id) # 추천은 지형 · 예정노선만 씀 — 실패 길에도(763-3) +async def _seed_expected_route(project_id: UUID, root: Path, surface: dict[str, Any]) -> None: + """예상노선 정본을 설계 지형으로 잘라 적음(없을 때만 · 자동 체인 2.5 와 같은 값).""" + from common_util.common_util_route_geometry import expected_route_csv_path, write_route_csv + from config.config_db import get_db_pool + + path = expected_route_csv_path(root) + if path.is_file(): + return + async with get_db_pool().acquire() as connection, connection.cursor() as cursor: + await cursor.execute( + "SELECT route_start_m, route_end_m FROM projects WHERE id = %s", (str(project_id),) + ) + row = await cursor.fetchone() + points = await asyncio.to_thread( + _planned_route_points_in_project_crs, root, surface, (row[0], row[1]) if row else None + ) + if points: + write_route_csv(path, points) + + async def _ensure_initial_polyline( project_id: UUID, project_root: Path, points: list[dict[str, float]] ) -> None: diff --git a/resources/tester/test_765_design_sets.py b/resources/tester/test_765_design_sets.py index fa91eda29..2948283c2 100644 --- a/resources/tester/test_765_design_sets.py +++ b/resources/tester/test_765_design_sets.py @@ -428,9 +428,11 @@ def _chain_world(monkeypatch, tmp_path: Path, *, other, built_other=True): async def auto(pid, model_id=None, inner=False): log.append(("auto", model_id, inner)) - expected.parent.mkdir(parents=True, exist_ok=True) - expected.write_text(str(model_id), encoding="utf-8") # 체인이 처음 쓰는 예상노선 - return {"route_id": 1} if (built_other or len(log) > 2) else None + if not expected.is_file(): # 체인 2.5 — 없을 때만 그 지형으로 자른 예상노선 + expected.parent.mkdir(parents=True, exist_ok=True) + expected.write_text(str(model_id), encoding="utf-8") + first = sum(1 for item in log if item[0] == "auto") == 1 + return {"route_id": 1} if (built_other or not first) else None async def switch(_c, _pid, terrain): log.append(("switch", terrain)) @@ -459,7 +461,14 @@ def _chain_world(monkeypatch, tmp_path: Path, *, other, built_other=True): monkeypatch.setattr(sets, "park_active_set", park) monkeypatch.setattr(sets, "clear_active_set", clear) monkeypatch.setattr(sets, "set_fingerprint", fingerprint) + + async def seed(_pid, _root, surface): + log.append(("seed", surface["source_filter"])) + expected.parent.mkdir(parents=True, exist_ok=True) + expected.write_text("design", encoding="utf-8") + monkeypatch.setattr(chain, "run_auto_design_chain", auto) + monkeypatch.setattr(chain, "_seed_expected_route", seed) monkeypatch.setattr(router, "schedule_precompute", lambda pid: log.append("precompute")) return chain, log, expected @@ -474,6 +483,7 @@ def test_전처리_체인_다른_지형_먼저_떠_두고_설계_지형(monkeypa summary = asyncio.run(chain.run_preprocess_chain(PID, 5)) # type: ignore[arg-type] assert summary == {"route_id": 1} assert log == [ + ("seed", "classification"), # 예상노선 = 설계 지형으로 먼저 ("switch", "sheet"), ("auto", 6, True), ("park", "sheet"), @@ -481,7 +491,7 @@ def test_전처리_체인_다른_지형_먼저_떠_두고_설계_지형(monkeypa ("auto", 5, True), "precompute", ] - assert expected.read_text(encoding="utf-8") == "5" # 예상노선 = 설계 지형 벌이 씀 + assert expected.read_text(encoding="utf-8") == "design" # 두 벌 같은 평면 노선 assert not (tmp_path / SETS_DIR / "las").exists() assert not (tmp_path / "initial_design.lock").exists() @@ -499,6 +509,7 @@ def test_전처리_체인_다른_벌_실패해도_설계_지형(monkeypatch, tmp summary = asyncio.run(chain.run_preprocess_chain(PID, 5)) # type: ignore[arg-type] assert summary == {"route_id": 1} assert log == [ + ("seed", "classification"), ("switch", "sheet"), ("auto", 6, True), "clear",