Files
Aislo/resources/tester/test_615_contour_tiles.py
T
eomsangdonandClaude Opus 5.5 b96479fd7e refactor(공용 지도): 겹 목록 · GL 겹 꼴 · 겹 줄 · 범례 · 산림 조각 겹을 새 공용 폴더 A00_Common/map 으로 — D03 은 부르기만 · 겉모습 · 동작 그대로 (PLAN 624-2 · 요구 530 · 결정 A⑧)
- map_layer_list = 겹 스물셋 · 처음 값 · 페이지 표(d03 · b05 보일 겹 · 처음 켬 · 취향 열쇠 — A② · A⑨)
- map_layer_specs = GL 겹 꼴 · 차례(D03 UI_MapGl 에서 옮김 · 선 겹 꼴은 LINE_LAYERS 한 벌)
- map_layer_bar = 겹 단추 줄 · 켬끔 · 취향 · 그래픽 카드 단추 / map_legend = 범례 칸 · 조각 겹 범례
- map_forest_layers = D03_UI_ForestLayers 옮김(이름만)
- D03 UI_Layers 683 → 639 줄 · UI_MapGl 423 → 115 줄 · UI_LayerDefs 는 캔버스 도움 + 옛 이름 다시 내놓음
- 시험 길 고침(553-4 · 581-2 · 584-1 · 584-3 · 606-1 · 615 · 622-2) — 옮긴 파일 자리 · 553-4 겹 목록은 622-2 때 낡은 것(국유림 임도 · 경제림 · 생태자연도 빠짐) 같이 고침

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 20:19:01 +09:00

99 lines
3.9 KiB
Python

"""등고선 줌별 벡터 조각(PLAN 615) — MVT 풀어 읽기(겹 `contour` · `h` · `k`) · 줌별 간격 ·
빈 조각(바다 · 국내 밖) = 빈 MVT · 처음만 만들고 둘째 = 파일 · 조각 번호 범위 · 화면 = 고정 벡터 소스.
./venv/Scripts/python.exe -m pytest resources/tester/test_615_contour_tiles.py -q
"""
import math
from pathlib import Path
import mapbox_vector_tile
import pytest
from B04_PreProcess.B04_PreProcess_Engine_MapSheet import sheet5k_center
from common_util import common_util_contour_tiles as ct
ROOT = Path(__file__).resolve().parents[2]
SHEET = "36901074" # 상주 용화 산지
needs_gpkg = pytest.mark.skipif(not ct.NATIONAL_GPKG.is_file(), reason="전국 등고선 파일 없음")
def _tile(lon: float, lat: float, z: int) -> tuple[int, int, int]:
n = 2**z
r = math.radians(lat)
y = (1 - math.log(math.tan(r) + 1 / math.cos(r)) / math.pi) / 2 * n
return z, int((lon + 180) / 360 * n), int(y)
def _features(data: bytes) -> list[dict]:
return mapbox_vector_tile.decode(data).get(ct.LAYER, {"features": []})["features"]
@needs_gpkg
@pytest.mark.parametrize("z", [12, 13, 14, 15])
def test_zoom_step_and_bold(z: int) -> None:
lat, lon = sheet5k_center(SHEET)
features = _features(ct.build_tile(*_tile(lon, lat, z)))
assert features, "산지 조각에 선이 있어야 함"
step, bold = ct.STEP_M[z], ct.BOLD_M[z]
levels = [f["properties"]["h"] for f in features]
assert len(levels) == len(set(levels)) # 높이 하나 = 지물 하나
for f in features:
h, k = f["properties"]["h"], f["properties"]["k"]
assert h % step == 0 or h % bold == 0
assert k == int(h % bold == 0)
assert f["geometry"]["type"] in ("LineString", "MultiLineString")
if z == 15:
assert any(h % 10 for h in levels) # 5 m 전부
if z == 14:
assert any(h % 25 == 0 and h % 10 for h in levels) # 10 m + 계곡선 25 m
def test_rules_dense_to_sparse() -> None:
zooms = range(ct.MIN_ZOOM, ct.MAX_ZOOM + 1)
steps = [ct.STEP_M[z] for z in zooms]
assert steps == sorted(steps, reverse=True) and steps[-1] == 5
assert all(ct.BOLD_M[z] % ct.STEP_M[z] == 0 or z == 14 for z in zooms)
def test_empty_tiles() -> None:
assert _features(ct.build_tile(*_tile(120.0, 30.0, 10))) == [] # 국내 밖
assert not ct.in_bounds(*_tile(120.0, 30.0, 10))
if ct.NATIONAL_GPKG.is_file():
assert _features(ct.build_tile(*_tile(131.0, 37.8, 13))) == [] # 동해 바다
def test_bad_tile_number() -> None:
for z, x, y in [(7, 0, 0), (16, 0, 0), (10, -1, 0), (10, 0, 1024)]:
with pytest.raises(KeyError):
ct.ensure_tile(z, x, y)
@needs_gpkg
def test_second_read_is_file(tmp_path, monkeypatch) -> None:
monkeypatch.setattr(ct, "TILES_ROOT", tmp_path)
lat, lon = sheet5k_center(SHEET)
z, x, y = _tile(lon, lat, 15)
first = ct.ensure_tile(z, x, y)
files = list(tmp_path.rglob("*.pbf"))
assert len(files) == 1 and files[0].parts[-3:] == (str(z), str(x), f"{y}.pbf")
assert files[0].parent.parent.parent.name.startswith(f"v{ct.RULE_VERSION}_")
assert not list(tmp_path.rglob("*.part")) and not list(tmp_path.rglob("*.lock"))
def boom(*_args):
raise AssertionError("둘째는 파일에서 읽어야 함")
monkeypatch.setattr(ct, "build_tile", boom)
assert ct.ensure_tile(z, x, y) == first
def test_screen_uses_fixed_vector_source() -> None:
gl = (ROOT / "ui_template" / "ui_template_gl_map.ts").read_text(encoding="utf-8")
assert "export function contourTileSource" in gl and '"vector"' in gl
assert "/plan/contour/{z}/{x}/{y}.pbf" in gl
base = (ROOT / "D03_PlanAnalysis" / "D03_PlanAnalysis_UI_MapGl.ts").read_text(encoding="utf-8")
assert "contour: contourTileSource(projectId)" in base
specs = (ROOT / "A00_Common" / "map" / "map_layer_specs.ts").read_text(encoding="utf-8")
assert specs.count('"source-layer": "contour"') == 3 # 624-2 GL 겹 꼴 = 공용