- 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>
100 lines
4.6 KiB
Python
100 lines
4.6 KiB
Python
"""D 노선분석 GIS 겹 「다음」 묶음(PLAN 581-2) — 산림입지도 잘라 넓이 · 토양형 코드 차례
|
||
이름 없으면 글자 그대로 · 실패 = 오류(파일 안 씀) · 덮으면 다시 안 받음 · 화면 겹 정의 · 색 값.
|
||
|
||
./venv/Scripts/python.exe -m pytest resources/tester/test_581_2_plan_soils.py -q
|
||
"""
|
||
|
||
import json
|
||
import re
|
||
from pathlib import Path
|
||
|
||
import pytest
|
||
|
||
from common_util.common_util_crs import tm_to_lonlat
|
||
from D03_PlanAnalysis import D03_PlanAnalysis_Layers as layers
|
||
|
||
EPSG = 5186
|
||
BOX = (230000.0, 450000.0, 232000.0, 451000.0) # 2 × 1 km
|
||
ROOT = Path(__file__).resolve().parents[2]
|
||
|
||
|
||
def _square(x0: float, y0: float, side: float) -> dict:
|
||
ring = [(x0, y0), (x0 + side, y0), (x0 + side, y0 + side), (x0, y0 + side), (x0, y0)]
|
||
return {"type": "Polygon", "coordinates": [[list(tm_to_lonlat(x, y, EPSG)) for x, y in ring]]}
|
||
|
||
|
||
def _soil(gid: str, geometry: dict, cd: str, code: str, name: str | None) -> dict:
|
||
props = {"sltp_cd": cd, "toyanghyun": code, **({"name": name} if name else {})}
|
||
return {"id": gid, "geometry": geometry, "properties": props}
|
||
|
||
|
||
def test_clip_soils_area_order_names() -> None:
|
||
found = [
|
||
_soil("a", _square(230100.0, 450100.0, 100.0), "03", "B₃", "갈색적윤산림토양"),
|
||
_soil("b", _square(231800.0, 450800.0, 400.0), "01", "B₁", "갈색건조산림토양"), # 귀퉁이
|
||
_soil("b", _square(231800.0, 450800.0, 400.0), "01", "B₁", "갈색건조산림토양"), # 겹침
|
||
_soil("c", _square(230500.0, 450500.0, 100.0), "03", "B₃", "갈색적윤산림토양"),
|
||
_soil("d", _square(230800.0, 450100.0, 50.0), "99", "Xx", None), # 모르는 값
|
||
_soil("e", _square(240000.0, 460000.0, 100.0), "02", "B₂", "갈색약건산림토양"), # 밖
|
||
]
|
||
features, summary = layers.clip_soils(found, BOX, EPSG)
|
||
assert [row["code"] for row in summary] == ["B₁", "B₃", "Xx"]
|
||
assert summary[0]["area_m2"] == pytest.approx(200 * 200, rel=0.01)
|
||
assert summary[1] == {
|
||
"code": "B₃",
|
||
"name": "갈색적윤산림토양",
|
||
"count": 2,
|
||
"area_m2": pytest.approx(2 * 100 * 100, rel=0.01),
|
||
}
|
||
assert summary[2]["name"] == "Xx" # 이름 없으면 글자 그대로
|
||
assert len(features) == 4
|
||
assert {f["properties"]["code"] for f in features} == {"B₁", "B₃", "Xx"}
|
||
|
||
|
||
class FakeWfs:
|
||
def __init__(self, fail: bool = False) -> None:
|
||
self.fail, self.calls = fail, []
|
||
|
||
def __call__(self, typename, filename, bounds, output_dir) -> None:
|
||
self.calls.append(typename)
|
||
if self.fail:
|
||
return
|
||
feats = [_soil("a", _square(230500.0, 450200.0, 300.0), "01", "B₁", "갈색건조산림토양")]
|
||
body = {"type": "FeatureCollection", "features": feats}
|
||
(Path(output_dir) / filename).write_text(json.dumps(body), "utf-8")
|
||
|
||
|
||
def test_soils_fetch_once(tmp_path, monkeypatch) -> None:
|
||
fake = FakeWfs()
|
||
monkeypatch.setattr(layers, "request_vworld_wfs", fake)
|
||
got = layers.ensure_soils(tmp_path, BOX, EPSG)
|
||
assert got["fetched"] and fake.calls == [layers.SOIL_TYPENAME]
|
||
saved = json.loads((tmp_path / layers.SOIL_FILE).read_text("utf-8"))
|
||
assert saved["summary"][0]["count"] == 1 and len(saved["features"]) == 1
|
||
inner = (230500.0, 450100.0, 231000.0, 450900.0)
|
||
assert not layers.ensure_soils(tmp_path, inner, EPSG)["fetched"] # 덮으면 다시 안 받음
|
||
assert len(fake.calls) == 1
|
||
assert layers.ensure_soils(tmp_path, (229000.0, *BOX[1:]), EPSG)["fetched"] # 넓어지면 다시
|
||
|
||
|
||
def test_soils_fail_raises(tmp_path, monkeypatch) -> None:
|
||
monkeypatch.setattr(layers, "request_vworld_wfs", FakeWfs(fail=True))
|
||
with pytest.raises(RuntimeError):
|
||
layers.ensure_soils(tmp_path, BOX, EPSG)
|
||
assert not (tmp_path / layers.SOIL_FILE).exists()
|
||
|
||
|
||
def test_screen_def_and_colors() -> None:
|
||
defs = (ROOT / "A00_Common" / "map" / "map_layer_list.ts").read_text("utf-8") # 624-2
|
||
entry = re.search(r'key: "soils",\s*icon: "(\w+)",[^}]*on: (\w+)', defs)
|
||
assert entry and entry.group(2) == "false" # 처음 값 끔
|
||
icons = (ROOT / "ui_template" / "ui_template_icons.ts").read_text("utf-8")
|
||
assert re.search(rf"^\s+{entry.group(1)}:", icons, re.M)
|
||
theme = (ROOT / "ui_template" / "ui_template_theme.css").read_text("utf-8")
|
||
assert all(f"--draw-map-soil-{n}:" in theme for n in range(1, 7))
|
||
page = (ROOT / "D03_PlanAnalysis" / "D03_PlanAnalysis_UI_LayerPaint.ts").read_text(
|
||
"utf-8"
|
||
) # 586-2
|
||
assert "if (!on.soils || !data.soils) return;" in page
|
||
assert page.count("base: true,") == page.count("draw: (context, map) =>") # 겹 모두 바탕(582)
|