- 새 D03_PlanAnalysis_SheetTiles.py — 도엽 도곽으로 자른 선 겹 조각(등고 · 계곡 = 전국 등고선 · 세류 · 물 면 · 도로 · 건물 · 지명 = 도엽 zip) · zip 은 프로젝트 · 공용 지형 창고에서 복사(원본 안 지움) 뒤 받기 · 빈 도엽 = 빈 조각 · 받기 실패 저장 안 함 · B04 함수 부르기만 - 라우터 길 둘 — 보이는 도엽 목록(bbox) · 조각 하나 - 새 UI_SheetTiles.ts — 보기 멈춘 뒤 보이는 도엽 · 없는 조각만 하나씩 · 12 장 이하 다 · 13~30 계곡선만 · 넘음 숨김 · 서클 - UI_Layers — 도엽 선 겹 원천을 조각으로 · 시험 606 새 · 475 옛 겹 길 단언 바꿈 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
122 lines
4.8 KiB
Python
122 lines
4.8 KiB
Python
"""도엽 조각(PLAN 606) — 보이는 도엽 수 · 차례 · 30 장 넘음 = 목록 없음 · 조각 = 도곽 안 ·
|
|
처음만 만듦 · 계곡선 = 등고선 중 25 m 배수 · 빈 도엽 = 빈 조각 · 받기 실패는 저장 안 함 ·
|
|
화면 = 보이는 도엽만(12 · 30 문턱) · 옛 받은 범위 겹 길 안 씀.
|
|
|
|
./venv/Scripts/python.exe -m pytest resources/tester/test_606_sheet_tiles.py -q
|
|
"""
|
|
|
|
import json
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
from B04_PreProcess.B04_PreProcess_Engine_MapSheet import sheet5k_center, sheet5k_to_bounds
|
|
from D03_PlanAnalysis import D03_PlanAnalysis_SheetTiles as st
|
|
|
|
ROOT = Path(__file__).resolve().parents[2]
|
|
SHEET = "36901074"
|
|
|
|
|
|
def _inside(collection, rect, eps=1e-6):
|
|
lon0, lat0, lon1, lat1 = rect
|
|
|
|
def walk(c):
|
|
if isinstance(c[0], (int, float)):
|
|
assert lon0 - eps <= c[0] <= lon1 + eps and lat0 - eps <= c[1] <= lat1 + eps
|
|
else:
|
|
for part in c:
|
|
walk(part)
|
|
|
|
for feature in collection["features"]:
|
|
walk(feature["geometry"]["coordinates"])
|
|
|
|
|
|
def test_sheets_in_box_count_order_cap() -> None:
|
|
lat, lon = sheet5k_center(SHEET)
|
|
assert st.sheets_in_box((lon - 0.001, lat - 0.001, lon + 0.001, lat + 0.001)) == (1, [SHEET])
|
|
count, sheets = st.sheets_in_box((lon - 0.02, lat - 0.02, lon + 0.02, lat + 0.02))
|
|
assert count == len(sheets) == 9 and sheets[0] == SHEET # 가운데부터
|
|
count, sheets = st.sheets_in_box((lon - 0.1, lat - 0.1, lon + 0.1, lat + 0.1))
|
|
assert count > st.INDEX_MAX and sheets == []
|
|
|
|
|
|
@pytest.fixture()
|
|
def shelf(tmp_path, monkeypatch):
|
|
found = sorted(ROOT.glob(f"storage/*/*/*/B04_PreProcess/processed/map_sheets/{SHEET}.zip"))
|
|
found += sorted((ROOT / "storage" / "_shared" / "sheets" / SHEET).glob("*.zip"))
|
|
if not found:
|
|
pytest.skip("도엽 zip 없음")
|
|
monkeypatch.setattr(st, "SHEETS_ROOT", tmp_path)
|
|
monkeypatch.setattr(st, "_project_zips", lambda no: found[:1] if no == SHEET else [])
|
|
return tmp_path
|
|
|
|
|
|
def test_zip_tile_clipped_and_made_once(shelf) -> None:
|
|
path = st.ensure_tile(SHEET, "하천중심선")
|
|
collection = json.loads(path.read_text(encoding="utf-8"))
|
|
assert collection["features"]
|
|
_inside(collection, sheet5k_to_bounds(SHEET))
|
|
stamp = path.stat().st_mtime_ns
|
|
assert st.ensure_tile(SHEET, "하천중심선") == path and path.stat().st_mtime_ns == stamp
|
|
assert (shelf / SHEET / f"{SHEET}.zip").is_file() # 옮겨 담음(원본은 그대로)
|
|
|
|
|
|
def test_contour_and_index(shelf) -> None:
|
|
full = json.loads(st.ensure_tile(SHEET, st.CONTOUR).read_text(encoding="utf-8"))
|
|
index = json.loads(st.ensure_tile(SHEET, st.INDEX).read_text(encoding="utf-8"))
|
|
levels = [f["properties"]["등고수치"] for f in full["features"]]
|
|
assert levels and all(isinstance(v, (int, float)) for v in levels)
|
|
assert index["features"] and all(
|
|
f["properties"]["등고수치"] % 25 == 0 for f in index["features"]
|
|
)
|
|
assert len(index["features"]) == sum(1 for v in levels if v % 25 == 0)
|
|
_inside(full, sheet5k_to_bounds(SHEET))
|
|
|
|
|
|
def test_bad_name_rejected(shelf) -> None:
|
|
with pytest.raises(KeyError):
|
|
st.ensure_tile(SHEET, "../x")
|
|
with pytest.raises(KeyError):
|
|
st.ensure_tile("1234", "건물")
|
|
|
|
|
|
def _no_download(monkeypatch, reason):
|
|
import B04_PreProcess.B04_PreProcess_Engine_SheetStore as sheet_store
|
|
|
|
monkeypatch.setattr(
|
|
sheet_store,
|
|
"ensure_sheets",
|
|
lambda folder, nos: {"available": {}, "failed": {nos[0]: reason}},
|
|
)
|
|
|
|
|
|
def test_empty_sheet_gives_empty_tile(tmp_path, monkeypatch) -> None:
|
|
monkeypatch.setattr(st, "SHEETS_ROOT", tmp_path)
|
|
monkeypatch.setattr(st, "_project_zips", lambda no: [])
|
|
_no_download(monkeypatch, "LookupError: 검색 결과 없음")
|
|
path = st.ensure_tile("37507039", "건물")
|
|
assert json.loads(path.read_text(encoding="utf-8"))["features"] == []
|
|
|
|
|
|
def test_download_failure_not_saved(tmp_path, monkeypatch) -> None:
|
|
monkeypatch.setattr(st, "SHEETS_ROOT", tmp_path)
|
|
monkeypatch.setattr(st, "_project_zips", lambda no: [])
|
|
_no_download(monkeypatch, "PermissionError: 로그인")
|
|
with pytest.raises(RuntimeError):
|
|
st.ensure_tile("37507039", "건물")
|
|
assert not list(tmp_path.rglob("*.geojson"))
|
|
|
|
|
|
def _src(name: str) -> str:
|
|
return (ROOT / "D03_PlanAnalysis" / name).read_text(encoding="utf-8")
|
|
|
|
|
|
def test_screen_uses_visible_sheets() -> None:
|
|
tiles = _src("D03_PlanAnalysis_UI_SheetTiles.ts")
|
|
assert "export const FULL_MAX = 12;" in tiles and "export const INDEX_MAX = 30;" in tiles
|
|
assert '"등고선" ? "계곡선" : null' in tiles # 13~30 = 계곡선만
|
|
layers = _src("D03_PlanAnalysis_UI_Layers.ts")
|
|
assert "fetchPlanSheetLayer" not in layers
|
|
assert "tiles.view(m, meta)" in layers
|
|
assert len(layers.splitlines()) <= 700
|