feat(B05): 계획노선 두 벌 + 노선 갈아 끼우기·초기화 서버 경로
노선을 예상노선(원본)·계획노선(수정본) 두 벌로 나눔 (PLAN 0-7 사용자 확정). - 예상노선 정본 `B05_Profile/route/expected_route.csv` 신설 — 자동 체인이 한 번 씀. 초기값 스냅샷 안에도 같은 CSV 가 있으나 그 폴더는 재확정 체인이 지우므로 스냅샷 밖에 한 벌 둠. - 계획노선 수정본 `B05_Profile/route/planned_route.csv` — 설계 계통(`load_design_route`)이 수정본 → 예상노선 → 스냅샷 순으로 읽음. 노선 초기화는 수정본을 지우는 것. - `GET /route/plan` 두 노선 정점 반환(모달이 점선·실선으로 그림). - `POST /route/replan` 고친 노선을 수정본에 쓰고(조밀화) 재확정 체인 재사용 — 배수유역 다시 → 관 새로 → 계획선·종횡단 재생성 → 옛 측점 설계 누가거리 이월. - `POST /route/replan/reset` 수정본 삭제 후 같은 재계산. - 횡단배수 지점은 노선이 바뀌면 저장분을 버리고 새로 계산(사용자 확정). 구조물은 프로젝트 정본이라 옛 측점값 그대로 남음. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -212,6 +212,40 @@ def find_planned_route_file(input_dir: Path) -> Path | None:
|
||||
return None
|
||||
|
||||
|
||||
def expected_route_csv_path(project_root: Path) -> Path:
|
||||
"""예상노선(원본) CSV 자리 — 자동 체인이 낸 노선을 **그대로** 보관한다.
|
||||
|
||||
초기값 스냅샷(`initial_snapshot/`) 안에도 같은 CSV가 있지만 그 폴더는 재확정 체인이
|
||||
통째로 지운다(`discard_initial_snapshot`). 노선 초기화는 언제나 예상노선으로 돌아갈 수
|
||||
있어야 하므로 스냅샷 **밖**에 한 벌 둔다(2026-09-06).
|
||||
"""
|
||||
return Path(project_root) / "B05_Profile" / "route" / "expected_route.csv"
|
||||
|
||||
|
||||
def write_route_csv(path: Path, points: list[dict[str, float]]) -> None:
|
||||
"""노선 정점을 CSV로 적는다. 열 이름은 `read_planned_route_csv()`가 아는 것."""
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
with path.open("w", encoding="utf-8", newline="") as file:
|
||||
writer = csv.writer(file)
|
||||
writer.writerow(("sequence", "x", "y"))
|
||||
writer.writerows(
|
||||
(index, round(float(point["x"]), 4), round(float(point["y"]), 4))
|
||||
for index, point in enumerate(points)
|
||||
)
|
||||
|
||||
|
||||
def planned_route_working_path(project_root: Path) -> Path:
|
||||
"""계획노선(수정본) CSV 자리 — 사용자가 노선을 고치면 여기에 쓴다.
|
||||
|
||||
노선은 두 벌이다(2026-09-06 사용자 확정): **예상노선**(원본,
|
||||
`initial_snapshot/planned_route.csv`)은 자동 체인이 한 번 쓰고 안 바뀌며,
|
||||
**계획노선**(수정본)은 예상노선과 같은 값으로 시작해 사용자가 고쳐 쓴다.
|
||||
설계 계통은 수정본이 있으면 그것을 읽는다 — 노선 초기화는 이 파일을 지우는 것이며,
|
||||
그것이 곧 「원본을 수정본으로 복사」와 같다.
|
||||
"""
|
||||
return Path(project_root) / "B05_Profile" / "route" / "planned_route.csv"
|
||||
|
||||
|
||||
def load_design_route(
|
||||
project_root: Path,
|
||||
surface_params: dict[str, Any] | None = None,
|
||||
@@ -244,9 +278,15 @@ def load_design_route(
|
||||
# 지표면·노선이 바뀌면 `discard_initial_snapshot()`이 폴더째 지우므로 이 경로가 저절로
|
||||
# 닫히고 원본 재판독으로 되돌아간다. 트림 **전** 원본이 필요한 호출(도엽 범위 —
|
||||
# surface_params 없음)은 여기를 타지 않는다.
|
||||
# 읽는 순서 — 계획노선(수정본) → 예상노선(원본) → 초기값 스냅샷(옛 자리).
|
||||
if surface_params:
|
||||
master = design_route_csv_path(project_root)
|
||||
if master.is_file():
|
||||
for master in (
|
||||
planned_route_working_path(project_root),
|
||||
expected_route_csv_path(project_root),
|
||||
design_route_csv_path(project_root),
|
||||
):
|
||||
if not master.is_file():
|
||||
continue
|
||||
stored = read_planned_route_csv(master)
|
||||
if stored is not None and len(stored.vertices) >= 2:
|
||||
return replace_vertices(
|
||||
|
||||
Reference in New Issue
Block a user