fix(B05): 노선 원천을 한 곳으로 모으고 도엽 서피스를 기본 하나만 만든다
용화 자동 체인이 끝까지 돌았는데 종단 계획선이 PVI 3개 직선으로 나왔다. 관 22개 측점이 92.6~2044.9m 로 트림 전 원본(2,136m) 기준인데 확정 노선은 1,070.4m 라 21개가 노선 밖이었다. 좌표계도 갈려 있었다 — 관은 EPSG 5179(노선 파일), 노선은 5176(프로젝트)에 저장돼 누가거리만 우연히 맞물려 있었다. 원인은 계획노선을 읽는 곳이 흩어져 있는 것이다. 트림·조밀화를 체인 한 곳에만 넣었더니 배수유역·유입·도엽은 원본을 그대로 읽었다. - load_design_route() 신규 — 읽기·좌표계 변환·트림·조밀화를 한 곳에서 끝낸다. 설계 계통(체인·배수유역)은 전부 이 함수를 지난다. - Router_Watershed 도 이 함수를 쓴다. 좌표계가 프로젝트 기준으로 통일돼 관과 노선이 같은 공간에 놓인다. - 도엽 서피스는 SHEET_SURFACE_AUTO_METHODS(기본 laplace 1종)만 자동 생성한다. 여섯 방식을 매번 만들면 WF1 891초 중 655초를 여기서 쓴다. 나머지는 관리자가 화면에서 고를 때 만든다. Router_Inflow 는 노선을 EPSG 라벨용으로만 쓰고 기하를 안 써서 제외했다. Engine_Extent(배경 지도 범위)도 제외 — 지도는 트림 전 전 구간을 덮어야 사용자가 측량 범위 밖을 볼 수 있다. 실측(용화 route 120): 배수유역 노선 2,136m -> 1,070m 격자 889x1435 -> 545x831 1차 영역 538,574㎡ -> 263,170㎡ 관 좌표계 EPSG 5179 -> 5176 관 22개(10개가 노선 밖) -> 11개 전부 노선 안 종단 PVI 3개 -> 13개, 종곡선 1 -> 11, 불균형 97.0% -> 86.2% PVI 측점이 관 측점과 일치한다(반올림 오차 제외). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -28,70 +28,23 @@ logger = logging.getLogger(__name__)
|
||||
def _planned_route_points_in_project_crs(
|
||||
project_root: Path, surface: dict[str, Any] | None = None
|
||||
) -> list[dict[str, float]] | None:
|
||||
"""계획노선 파일(CSV·shapefile)을 읽어 프로젝트 좌표계(m) 점 목록으로 돌려준다.
|
||||
"""설계용 계획노선을 프로젝트 좌표계(m) 점 목록으로 돌려준다. 없으면 None.
|
||||
|
||||
B04 `/planned-route` 조회와 같은 규칙 — 파일이 제 좌표계를 싣고 있고
|
||||
프로젝트 좌표계와 다르면 한 번 옮긴다.
|
||||
|
||||
`surface`(확정 필터·방식·스무딩)를 받으면 지표면이 덮지 못하는 구간을 잘라 낸다.
|
||||
라이다 측량이 노선 전 구간을 덮지 않는 현장이 있다(용화: 2,136m 중 1,400m).
|
||||
자르지 않으면 체인이 서피스 밖 정점에서 끊긴다.
|
||||
읽기·좌표계 변환·트림·조밀화는 `load_design_route()` 한 곳에서 한다 — 배수유역·유입도
|
||||
같은 함수를 쓰므로 여기만 트림되는 일이 없다.
|
||||
"""
|
||||
from B04_PreProcess.B04_PreProcess_Engine_Extent import project_epsg_from_prj
|
||||
from common_util.common_util_route_geometry import (
|
||||
densify_route,
|
||||
find_planned_route_file,
|
||||
read_planned_route,
|
||||
trim_route_to_surface,
|
||||
)
|
||||
from config.config_system import (
|
||||
ROUTE_DIRECT_LINK_CELL_FACTOR,
|
||||
ROUTE_GRID_RES_M,
|
||||
ROUTE_PLANNED_DENSIFY_SAFETY,
|
||||
)
|
||||
from common_util.common_util_route_geometry import load_design_route
|
||||
|
||||
route_file = find_planned_route_file(project_root / "B03_FileInput" / "input")
|
||||
planned = read_planned_route(route_file) if route_file else None
|
||||
if planned is None or len(planned.vertices) < 2:
|
||||
planned = load_design_route(project_root, surface)
|
||||
if planned is None:
|
||||
if surface:
|
||||
logger.warning(
|
||||
"자동 설계 체인 중단(설계 노선 없음): 계획노선을 읽지 못했거나 라이다 측량"
|
||||
" 범위와 겹치지 않습니다 — %s",
|
||||
project_root.name,
|
||||
)
|
||||
return None
|
||||
target_epsg = project_epsg_from_prj(project_root)
|
||||
points = [(float(vertex.x), float(vertex.y)) for vertex in planned.vertices]
|
||||
source_epsg = planned.crs_input or target_epsg
|
||||
if source_epsg.upper() != target_epsg.upper():
|
||||
from pyproj import Transformer
|
||||
|
||||
transformer = Transformer.from_crs(source_epsg, target_epsg, always_xy=True)
|
||||
points = [transformer.transform(x, y) for x, y in points]
|
||||
|
||||
if surface:
|
||||
from common_util.common_util_surface_sampler import build_surface_sampler
|
||||
|
||||
try:
|
||||
sampler = build_surface_sampler(
|
||||
project_root / "B04_PreProcess" / "models",
|
||||
str(surface["source_filter"]),
|
||||
str(surface["method"]),
|
||||
bool(surface["smooth"]),
|
||||
)
|
||||
except (FileNotFoundError, KeyError, OSError) as exc:
|
||||
logger.warning("자동 설계 체인 노선 트림 건너뜀 — 지표면을 열지 못했습니다: %s", exc)
|
||||
else:
|
||||
points = trim_route_to_surface(points, sampler)
|
||||
# 예정노선은 정점이 성기다(용화 평균 17.6m). 그대로 넘기면 구간마다 격자
|
||||
# 탐색을 타고 급경사 현에서 끊긴다. 문턱 아래로 간격만 좁히면 계획노선이
|
||||
# 손대지 않은 채 채택된다 — 같은 직선 위에 점을 더 찍는 것이라 형상 불변.
|
||||
points = densify_route(
|
||||
points,
|
||||
ROUTE_DIRECT_LINK_CELL_FACTOR * ROUTE_GRID_RES_M * ROUTE_PLANNED_DENSIFY_SAFETY,
|
||||
)
|
||||
if len(points) < 2:
|
||||
logger.warning(
|
||||
"자동 설계 체인 중단(노선이 지표면 밖): 계획노선과 라이다 측량 범위가"
|
||||
" 겹치지 않습니다 — %s",
|
||||
project_root.name,
|
||||
)
|
||||
return None
|
||||
return [{"x": x, "y": y} for x, y in points]
|
||||
return [{"x": v.x, "y": v.y} for v in planned.vertices]
|
||||
|
||||
|
||||
async def _prepare_drainage_pipes_and_reprofile(
|
||||
|
||||
Reference in New Issue
Block a user