feat(B02/B03/B04/B05): 계획노선 사용 범위 · 절단 여유 3m · 배수유역도 줌·측점 표기

- 계획노선 사용 범위: B02 등록에 시작·종료 누가거리 두 칸 추가, B01 수정 모달에서도
  변경. projects.route_start_m·route_end_m 신설(015_route_range.sql).
  load_design_route 가 범위 절단 → 서피스 트림 순서로 적용. 시작 >= 종료는 화면·서버
  양쪽에서 차단. 비우면 전 구간으로 종전과 같음.
- 서피스 절단 여유 기본값 30m → 3m (SURFACE_ROUTE_EDGE_TRIM_M).
- B04 지도·B05 배수유역도 줌 상한을 「화면 폭 20m」 기준으로 계산(고정 8배·16배 폐지).
  4배를 넘으면 배경 그림 흐림 보간 해제.
- 계획선 위 측점 눈금·번호 표기(측점번호+잔여거리). 관 마커와 겹치면 반대쪽으로 밀고,
  되꺾임 구간에서 라벨이 겹치면 건너뜀. 그리기 코드는 두 화면 공용.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-04 19:08:11 +09:00
co-authored by Claude Opus 5
parent cc15a83f67
commit 4e4bfa2354
20 changed files with 412 additions and 36 deletions
+16 -4
View File
@@ -26,16 +26,19 @@ logger = logging.getLogger(__name__)
def _planned_route_points_in_project_crs(
project_root: Path, surface: dict[str, Any] | None = None
project_root: Path,
surface: dict[str, Any] | None = None,
route_range: tuple[float | None, float | None] | None = None,
) -> list[dict[str, float]] | None:
"""설계용 계획노선을 프로젝트 좌표계(m) 점 목록으로 돌려준다. 없으면 None.
읽기·좌표계 변환·트림·조밀화는 `load_design_route()` 한 곳에서 한다 — 배수유역·유입도
같은 함수를 쓰므로 여기만 트림되는 일이 없다.
같은 함수를 쓰므로 여기만 트림되는 일이 없다. 사용자가 정한 사용 범위(`route_range`)는
서피스 트림보다 먼저 적용된다 (2026-09-04 사용자 지시).
"""
from common_util.common_util_route_geometry import load_design_route
planned = load_design_route(project_root, surface)
planned = load_design_route(project_root, surface, route_range)
if planned is None:
if surface:
logger.warning(
@@ -176,8 +179,17 @@ async def run_auto_design_chain(
# 끊긴다(2026-08-30 실사고). 노선 트림도 이 지표면을 기준으로 한다.
async with pool.acquire() as connection:
defaults = await get_surface_confirmation_params(connection, str(project_id))
# 사용자가 B02·B01 에서 정한 계획노선 사용 범위 (2026-09-04 사용자 지시).
# 비어 있으면 전 구간 — 지금까지와 같다.
async with connection.cursor() as cursor:
await cursor.execute(
"SELECT route_start_m, route_end_m FROM projects WHERE id = %s",
(str(project_id),),
)
range_row = await cursor.fetchone()
route_range = (range_row[0], range_row[1]) if range_row else None
points = _planned_route_points_in_project_crs(project_root, defaults)
points = _planned_route_points_in_project_crs(project_root, defaults, route_range)
if not points:
logger.warning("자동 설계 체인 중단(계획노선 없음): project_id=%s", project_id)
mark_design_failed(project_root, "계획노선이 없어 초기 노선을 세울 수 없습니다.")