perf(배수유역): 347-1 흐름 방향 · 도엽 좌표 저장 — 격자 원점 좌표 정수 m · 노선이 범위 안이면 읽기만

- 격자 원점 = 좌표 정수 m(GRID_ORIGIN_XY · 옛 「도로 시작점」 지시를 바꿈 · 사용자 확정)
- 흐름 방향 저장본 drainage/descent_<입력 지문>_<범위>.npz — 입력 지문 = 도엽 등고선 지문 + 남긴 등고 단 + 셀 + 계산 규칙 · 덮으면 읽어 잘라 씀 · 최근 2벌
- 도엽(하천 · 등고선) 사업지 좌표 저장본 drainage/00_sheet_metric.pkl — 원본 자국 · 좌표계가 같으면 재투영 안 함
- 검증_sub3 실측: 저장본 읽기 = 지은 것과 칸마다 같음(적색 · 해석 영역 · 화살표 · 귀속 차이 0) · 108 → 10.8 s(붐빔 · 340 기준 약 6 s) · 원점 바뀜으로 적색 460,035 → 459,792칸(−0.05 %) · 관 자리 같음
- 시험 test_347_1_descent_store · 실측 bench 저장본 갈래

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XWh5wNNycMkbwMpACz1rte
This commit is contained in:
2026-10-16 11:21:13 +09:00
co-authored by Claude Opus 5.5
parent fba1eb8a5d
commit 0e0c1be1c0
8 changed files with 334 additions and 31 deletions
@@ -21,6 +21,7 @@ from shapely.geometry import LineString, MultiPolygon, Polygon, shape
from shapely.ops import substring, unary_union
from B04_PreProcess.B04_PreProcess_Engine_Watershed_Grid import (
GRID_ORIGIN_XY,
ContourCloud,
GridSpec,
build_cell_mask,
@@ -344,7 +345,7 @@ def build_primary_region(
노선 버퍼는 세류 교차가 없는 구간의 도로도 격자 안에 들어오게 한다 — 그래야 그 구간
사면이 유역으로 잡힌다. 상류 세류망 선정이 정확해진 뒤 다시 포함했다(2026-07-31 사용자 지시).
격자는 bbox를 통째로 채우지 않는다. **도로 시작점에 셀 모서리를 맞춘 뒤, 1차 영역에
격자는 bbox를 통째로 채우지 않는다. **좌표 정수 m(원점 0,0)에 셀 모서리를 맞춘 뒤, 1차 영역에
조금이라도 걸치는 셀만** 생성한다(2026-07-31 사용자 지시). bbox 전체를 쓰면 영역 밖
빈 셀이 대부분이라 의미가 없고, 원점을 bbox 좌상단에 두면 영역이 조금만 변해도 격자가
통째로 밀려 이전 결과와 셀이 대응되지 않는다.
@@ -359,16 +360,13 @@ def build_primary_region(
logger.warning("배수유역: 상류 세류망이 없어 노선 버퍼만으로 1차 영역을 잡습니다.")
area = unary_union(geometries)
x_min, y_min, x_max, y_max = area.bounds
road_start = route_line.coords[0]
spec = grid_spec_from_bounds(
x_min, y_min, x_max, y_max, cell_m, anchor_xy=(float(road_start[0]), float(road_start[1]))
)
spec = grid_spec_from_bounds(x_min, y_min, x_max, y_max, cell_m, anchor_xy=GRID_ORIGIN_XY)
cell_mask = build_cell_mask(spec, area)
outside = route_line.difference(area)
road_outside_m = float(outside.length) if not outside.is_empty else 0.0
active = int(cell_mask.sum())
logger.info(
"배수유역: 1차 영역 %.0f㎡ → 격자 %d×%d (%.2fm, 도로 시점 기준) 중 %d셀 생성 "
"배수유역: 1차 영역 %.0f㎡ → 격자 %d×%d (%.2fm, 좌표 정수 m 기준) 중 %d셀 생성 "
"(bbox %d셀의 %.0f%%), 노선 이탈 %.0fm/%.0fm",
area.area,
spec.n_rows,