# -*- coding: utf-8 -*- """509-6 배수유역도용 도엽 — 평면도와 따로 줄임(유역 + 여유). - 범위 = 세부 유역(노선 교차 관으로 모이는 유역) ∪ 줌아웃 한계(노선 bbox 2 배) + 여유 300 m - 평면도(route) 범위와 따로 저장(`_derived/sheet_drainage/`) · 유역이 없으면 사본 그대로 - 배수유역 계산 값 그대로 — 유역 · 관 파일 · 원본 도엽은 안 바뀜 · 배수유역 엔진은 이 사본을 안 읽음 임시 폴더 사업지(1 m = 0.00001 도) — 공유 storage · DB 안 씀. """ import hashlib import json from pathlib import Path import pytest from B04_PreProcess import B04_PreProcess_Engine_SheetClip as clip from common_util.common_util_route_geometry import planned_route_working_path, write_route_csv from config.config_system import DRAINAGE_CACHE_DIRNAME, DRAINAGE_DETAIL_FILENAME ROOT = Path(__file__).resolve().parents[2] META = { "x_min": 0, "y_min": 0, "width_meters": 10000, "height_meters": 10000, "lon_min": 127.0, "lon_max": 127.1, "lat_min": 37.0, "lat_max": 37.1, } def lonlat(x: float, y: float) -> list[float]: return [127.0 + x * 1e-5, 37.0 + y * 1e-5] @pytest.fixture() def project(tmp_path: Path) -> tuple[Path, Path]: processed = tmp_path / "B04_PreProcess" / "processed" processed.mkdir(parents=True) (processed / "vworld_satellite_meta.json").write_text(json.dumps(META), encoding="utf-8") write_route_csv( planned_route_working_path(tmp_path), [{"x": 5000, "y": 5000}, {"x": 5500, "y": 5200}] ) ring = [lonlat(x, y) for x, y in [(4800, 5100), (6000, 5100), (6000, 6500), (4800, 6500)]] basins = tmp_path / "B04_PreProcess" / DRAINAGE_CACHE_DIRNAME / DRAINAGE_DETAIL_FILENAME basins.parent.mkdir(parents=True) basins.write_text( json.dumps( { "type": "FeatureCollection", "features": [ { "type": "Feature", "properties": {"chainage_m": 100.0}, "geometry": {"type": "Polygon", "coordinates": [ring + [ring[0]]]}, } ], } ), encoding="utf-8", ) source = processed / "도엽_등고선.display.geojson" lines = [[lonlat(x, y) for x in range(0, 10001, 100)] for y in (4000, 4700, 5500, 6700, 7000)] source.write_text( json.dumps( { "type": "FeatureCollection", "features": [ { "type": "Feature", "properties": {"등고수치": i}, "geometry": {"type": "LineString", "coordinates": c}, } for i, c in enumerate(lines) ], } ), encoding="utf-8", ) return tmp_path, source def _digest(folder: Path) -> dict[str, str]: return { str(p.relative_to(folder)): hashlib.sha256(p.read_bytes()).hexdigest() for p in sorted(folder.rglob("*")) if p.is_file() } def test_범위는_유역_줌아웃_더하기_여유(project): root, _ = project # 줌아웃 4750~5750 · 4900~5300 ∪ 유역 4800~6000 · 5100~6500 → + 300 m assert clip.clip_rect_m(root, "drainage", META) == (4450, 4600, 6300, 6800) def test_평면도와_따로(project): root, source = project drainage = clip.clipped_sheet(root, source, "drainage") route = clip.clipped_sheet(root, source, "route") assert drainage.parent.name == "sheet_drainage" and route.parent.name == "sheet_route" levels = [ f["properties"]["등고수치"] for f in json.loads(drainage.read_text(encoding="utf-8"))["features"] ] assert levels == [1, 2, 3] # y 4700 · 5500 · 6700 만 범위 안 route_levels = [ f["properties"]["등고수치"] for f in json.loads(route.read_text(encoding="utf-8"))["features"] ] assert route_levels == [1, 2] # 노선 띠 4400~5800 def test_유역이_없으면_사본_그대로(project): root, source = project (root / "B04_PreProcess" / DRAINAGE_CACHE_DIRNAME / DRAINAGE_DETAIL_FILENAME).unlink() assert clip.clipped_sheet(root, source, "drainage") == source def test_배수유역_값_그대로(project): root, source = project drainage_folder = root / "B04_PreProcess" / DRAINAGE_CACHE_DIRNAME processed = root / "B04_PreProcess" / "processed" before = (_digest(drainage_folder), _digest(processed)) clip.clipped_sheet(root, source, "drainage") clip.clipped_sheet(root, source, "route") assert (_digest(drainage_folder), _digest(processed)) == before def test_배수유역_엔진은_잘린_사본을_안_읽음(): """분석 · 관 자리 · 유역 계산 길에 SheetClip · `_derived/sheet_` 가 없음.""" for path in (ROOT / "B04_PreProcess").glob("B04_PreProcess_*Watershed*.py"): text = path.read_text(encoding="utf-8") assert "SheetClip" not in text and "sheet_route" not in text, path.name basins = (ROOT / "B04_PreProcess" / "B04_PreProcess_Router_Basins.py").read_text("utf-8") assert "SheetClip" not in basins