- 세트 연결 = 638-1 그대로(B 하나 = 세트 하나 · 열쇠만 세트) - 새 D04_PlanConfirm_Context — 같은 예정노선 세트 모두 · 내 세트 · 연도 · 임도 좌표계로 pyproj 변환 · 업체 이름 없음 · 보기 전용 - 새 B05_Profile_Router_PlanSource — 원본 꼭짓점 = 범위 + 지표면 트림 · 조밀화만 뺌(Router_Replan 안 늘림 · 덧칸 대신 새 길) - RouteFollow 추적 전 체인과 같은 3.6 m 조밀화(브레인 허락 · 옛 촘촘 입력은 그대로 = 626-2 같음) - 실측 검증_sub3: 원본 64 점 → follow = 초기선 181 점 거리 0 · 파일 안 바뀜 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
85 lines
3.5 KiB
Python
85 lines
3.5 KiB
Python
"""받은 예정노선 원본 꼭짓점(635-2 · 요구 546) — B05 「예정노선 수정」이 고칠 선.
|
|
|
|
계산 자리 ③ 서버 단독 · 읽기만(파일 안 만듦). 원본 = 올린(받은) 노선 파일 꼭짓점을 사업지 좌표로 ·
|
|
사용 범위(`projects.route_start_m · route_end_m`) · 지표면 트림까지 — 체인 예정노선
|
|
(`load_design_route`)과 같은 차례에서 **조밀화만 뺌**. 고친 꼭짓점은 `POST /route/follow` 가
|
|
같은 간격(`spacing_m`)으로 조밀화한 뒤 추적 → 안 고친 원본 = 체인 초기선과 거리 0(`test_635_2`).
|
|
|
|
GET /api/projects/{id}/route/plan/source
|
|
→ {status, expected_source: [[x, y], …], spacing_m} (원본 없음 = 빈 목록)
|
|
404 프로젝트 없음
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import asyncio
|
|
from pathlib import Path
|
|
from typing import Any
|
|
from uuid import UUID
|
|
|
|
from fastapi import APIRouter
|
|
from fastapi.responses import JSONResponse
|
|
|
|
from B05_Profile.B05_Profile_Router_Replan import _PROJECT_PATH_MISSING, _project_paths
|
|
from common_util.common_util_route_geometry import load_design_route, trim_route_to_surface
|
|
from common_util.common_util_surface_confirmation import get_surface_confirmation_params
|
|
from common_util.common_util_surface_sampler import build_surface_sampler
|
|
from config.config_db import get_db_pool
|
|
from config.config_system import (
|
|
ROUTE_DIRECT_LINK_CELL_FACTOR,
|
|
ROUTE_GRID_RES_M,
|
|
ROUTE_PLANNED_DENSIFY_SAFETY,
|
|
)
|
|
|
|
router = APIRouter(prefix="/api/projects", tags=["B05 Plan Source"])
|
|
|
|
#: 체인 예정노선 조밀화 간격(`load_design_route` 와 같은 값)
|
|
SPACING_M = ROUTE_DIRECT_LINK_CELL_FACTOR * ROUTE_GRID_RES_M * ROUTE_PLANNED_DENSIFY_SAFETY
|
|
|
|
|
|
def source_vertices(
|
|
root: Path, surface: dict[str, Any] | None, route_range: tuple | None
|
|
) -> list[list[float]]:
|
|
"""원본 꼭짓점 — 사업지 좌표 · 범위 · 지표면 트림(지표면을 못 열면 트림 없이) · 조밀화 없음."""
|
|
planned = load_design_route(root, None, route_range)
|
|
if planned is None:
|
|
return []
|
|
points = [(v.x, v.y) for v in planned.vertices]
|
|
if surface:
|
|
try:
|
|
sampler = build_surface_sampler(
|
|
root / "B04_PreProcess" / "models",
|
|
str(surface["source_filter"]),
|
|
str(surface["method"]),
|
|
bool(surface["smooth"]),
|
|
)
|
|
except (FileNotFoundError, KeyError, OSError):
|
|
sampler = None
|
|
if sampler is not None:
|
|
points = trim_route_to_surface(points, sampler)
|
|
return [[float(x), float(y)] for x, y in points] if len(points) >= 2 else []
|
|
|
|
|
|
@router.get("/{project_id}/route/plan/source", response_model=None)
|
|
async def read_plan_source(project_id: UUID) -> dict[str, Any] | JSONResponse:
|
|
paths = await _project_paths(project_id)
|
|
if paths is None:
|
|
return JSONResponse(status_code=404, content=_PROJECT_PATH_MISSING)
|
|
async with get_db_pool().acquire() as connection:
|
|
surface = await get_surface_confirmation_params(connection, str(project_id))
|
|
async with 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()
|
|
vertices = await asyncio.to_thread(
|
|
source_vertices, paths[0], surface, (row[0], row[1]) if row else None
|
|
)
|
|
return {
|
|
"status": "success",
|
|
"project_id": str(project_id),
|
|
"expected_source": vertices,
|
|
"spacing_m": SPACING_M,
|
|
}
|