diff --git a/B03_FileInput/B03_FileInput_Service_Chain.py b/B03_FileInput/B03_FileInput_Service_Chain.py index 618764d9..ec0b0431 100644 --- a/B03_FileInput/B03_FileInput_Service_Chain.py +++ b/B03_FileInput/B03_FileInput_Service_Chain.py @@ -205,6 +205,12 @@ async def run_auto_design_chain( if not expected_path.is_file(): write_route_csv(expected_path, points) + # 2.6) 계획노선 **초기 폴리라인**도 여기서 세운다(2026-09-06 PLAN 0-10). + # 예상노선은 점 묶음이라 그대로는 설계선이 못 된다 — 지식DB 의 R 기준으로 + # 곡선을 끼운 폴리라인이 불변 초기 데이터다. 화면이 처음 열릴 때 만들면 + # 「화면을 안 열면 값이 없다」가 되므로 초기값은 서버가 낸다(0-4 원칙). + await _ensure_initial_polyline(project_id, project_root, points) + # 3) B05 경로 계산 request = RouteSolveRequest( filter_key=str(defaults["source_filter"]), @@ -327,6 +333,30 @@ async def run_auto_design_chain( clear_designing(project_root) +async def _ensure_initial_polyline( + project_id: UUID, project_root: Path, points: list[dict[str, float]] +) -> None: + """계획노선 초기 폴리라인을 세운다 — 이미 있으면 그대로 둔다. 실패는 비치명적.""" + import asyncio + + from B05_Profile.B05_Profile_Router_Replan import _ensure_planned_initial, _min_plan_radius_m + + try: + radius_m = await _min_plan_radius_m(project_id) + summary = await asyncio.to_thread(_ensure_planned_initial, project_root, radius_m) + if summary: + logger.info( + "초기 계획노선 폴리라인: project_id=%s 노드 %d · 곡선 %d · 위반 %d (R %.1fm)", + project_id, + summary["nodes"], + summary["curves"], + summary["violations"], + radius_m, + ) + except Exception: # noqa: BLE001 — 없으면 화면이 처음 열릴 때 만든다 + logger.exception("초기 계획노선 폴리라인 생성 실패(계속 진행): %s", project_id) + + async def run_redesign_chain( project_id: UUID, surface_model_id: int, diff --git a/B05_Profile/B05_Profile_Router_Replan.py b/B05_Profile/B05_Profile_Router_Replan.py index 0af08e06..8c68c3a4 100644 --- a/B05_Profile/B05_Profile_Router_Replan.py +++ b/B05_Profile/B05_Profile_Router_Replan.py @@ -175,11 +175,18 @@ def _write_planned_polyline(path: Path, points: list[tuple[float, float]], radiu def _ensure_planned_initial(project_root: Path, radius_m: float) -> dict | None: - """계획노선 **초기 폴리라인**이 없으면 예상노선을 폴리라인화해 세운다.""" + """계획노선 **초기 폴리라인**이 없거나 낡았으면 예상노선을 폴리라인화해 세운다. + + 「낡았다」 = 예상노선 파일이 더 나중에 쓰였다. 파일을 다시 올리면 예상노선이 새로 + 깔리는데 초기본이 옛 노선인 채로 남으면 노선 초기화가 옛 자리로 돌아간다. + """ target = planned_route_initial_path(project_root) + source = expected_route_csv_path(project_root) if target.is_file(): - return None - points = [(x, y) for x, y in _vertices_of(expected_route_csv_path(project_root))] + if not source.is_file() or source.stat().st_mtime <= target.stat().st_mtime: + return None + logger.info("예상노선이 새로 깔려 초기 폴리라인을 다시 만듭니다: %s", target) + points = [(x, y) for x, y in _vertices_of(source)] if len(points) < 2: return None summary = _write_planned_polyline(target, points, radius_m)