feat(B05): 계획노선을 폴리라인으로 만드는 초기본 신설
사용자 확인(2026-09-06) — 예상노선은 폴리라인이 아니라 점 묶음이고 규칙 없는
폴리라인과도 맞지 않음. 그래서 계획노선은 원데이터를 복사해 폴리라인으로 바꾼 것이어야
하고 그것이 불변의 초기 데이터가 됨. 곡선 기준은 지식DB(별표2 I.2.다) 값을 씀.
- common_util_route_polyline.py 신설 — 점 묶음을 폴리라인으로.
① Douglas-Peucker 로 꺾임점(IP)만 남김. 예상노선은 격자 탐색이 낸 조밀한 점군이라
(용화: 1,097m 에 331점) 점마다 곡선을 끼우면 접선 자리가 1.5m 뿐이라 R 이 2~6m 로
뭉개짐. 허용오차는 격자 해상도(2m)의 두 배.
② 내각 155도 이상은 곡선 생략(별표2), 그 아래는 최소곡선반지름으로 원호를 끼움.
자리가 모자라면 반지름을 줄이되 막지 않고 위반으로 표시(사용자 확정: 경고만).
③ 점은 옮기지 않음 — 노드는 원본 자리에 그대로 두고 그 사이에 원호를 넣음.
- planned_route_initial_path 신설 — 세 벌 구조(예상노선 점 묶음 / 초기 폴리라인 /
수정본). load_design_route 읽는 순서에 초기 폴리라인을 예상노선보다 앞에 끼움.
- 최소곡선반지름은 임도 종류·설계속도·지형으로 고름
(FOREST_ROAD_PROFILE_CRITERIA[min_plan_radius_m], 못 읽으면 가장 완화된 조건).
- GET /route/plan 이 노드(반지름·내각·위반)까지 함께 돌려줌 — 노드만 옮기면 선이
저절로 규칙을 지키게 하는 것이 목적. POST /route/replan 도 받은 노드로 다시 폴리라인화.
자체검증(용화, 실화면 API) — 예상노선 331점 -> 편집 노드 25개 + 곡선 13곳
(전부 R 12m = 설계속도 20·특수지형 법정 하한, 위반 0) -> 계획노선 정점 142개. 응답 180ms.
단순화 전에는 곡선 15곳이 R 2.75~6.51m 로 전부 위반이었음.
시험 tmp/tests/test_route_polyline.py 7건(원호가 접선과 맞물리는지 좌표로 대조).
전체 407 통과·17 건너뜀.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -246,6 +246,21 @@ def planned_route_working_path(project_root: Path) -> Path:
|
||||
return Path(project_root) / "B05_Profile" / "route" / "planned_route.csv"
|
||||
|
||||
|
||||
def planned_route_initial_path(project_root: Path) -> Path:
|
||||
"""계획노선 **초기 폴리라인** 자리 — 예상노선(점 묶음)을 폴리라인으로 바꾼 한 벌.
|
||||
|
||||
왜 한 벌 더 두나(2026-09-06 사용자 지시) — 예상노선은 폴리라인이 아니라 **점 묶음**이라
|
||||
그대로는 설계선이 못 된다. 계획노선은 「원본을 복사해 폴리라인으로 바꾼 것」이며 그것이
|
||||
**불변의 초기 데이터**다. 노선 초기화는 수정본을 지워 이 파일로 돌아가는 것이다.
|
||||
|
||||
세 벌의 관계 —
|
||||
· `expected_route.csv` 예상노선(원본 점 묶음, 불변)
|
||||
· `planned_route_initial.csv` 그것을 폴리라인화한 것(**불변 초기 데이터**)
|
||||
· `planned_route.csv` 사용자가 고친 수정본(있으면 이것이 설계 노선)
|
||||
"""
|
||||
return Path(project_root) / "B05_Profile" / "route" / "planned_route_initial.csv"
|
||||
|
||||
|
||||
def load_design_route(
|
||||
project_root: Path,
|
||||
surface_params: dict[str, Any] | None = None,
|
||||
@@ -278,10 +293,13 @@ def load_design_route(
|
||||
# 지표면·노선이 바뀌면 `discard_initial_snapshot()`이 폴더째 지우므로 이 경로가 저절로
|
||||
# 닫히고 원본 재판독으로 되돌아간다. 트림 **전** 원본이 필요한 호출(도엽 범위 —
|
||||
# surface_params 없음)은 여기를 타지 않는다.
|
||||
# 읽는 순서 — 계획노선(수정본) → 예상노선(원본) → 초기값 스냅샷(옛 자리).
|
||||
if surface_params:
|
||||
# 읽는 순서 — 수정본 → **초기 폴리라인** → 예상노선(점 묶음) → 초기값 스냅샷.
|
||||
# 초기 폴리라인이 예상노선보다 앞선다: 예상노선은 점 묶음이라 그대로 이으면
|
||||
# 규칙 없는 선이 된다(2026-09-06 사용자 지시).
|
||||
for master in (
|
||||
planned_route_working_path(project_root),
|
||||
planned_route_initial_path(project_root),
|
||||
expected_route_csv_path(project_root),
|
||||
design_route_csv_path(project_root),
|
||||
):
|
||||
|
||||
Reference in New Issue
Block a user