- 겹 표(map_layer_list) = 그룹1 22 줄 표 차례 · title = 호버제목 · group(수계망도 · 도로 · 토지·건물 · 제한·재해) · pages · 숨김 표 걷음 · 도로300m 한 줄(「도로」 묶음 · 기능 남김) - 겹 줄(map_layer_bar) = 단독 넷 | 묶음 넷(여럿 고르기 메뉴 · 켠 수 배지 · 안 닫힘) | 그래픽 카드 · sync 가 단추 · 메뉴 줄 막힘 · 글을 맞춤(why = 페이지 까닭) - 도구 표(map_toolbar) = 그룹2 17 줄 title · mapToolGroups 가 글을 표로 맞춤 · 기본 단추 생성 · 지형 칩 막힘 「수치지형도/라이다 — 까닭」 - 띠 = 한 자료 · 겹 둘(GL fillEdge 거름 · 옛 캔버스 · 범례 줄 따로) · B05 띠 받기(D03 과 같은 서버 길 · bandCollection 공용) - D03 = 겹 줄 · 도구줄 한 행(createMapToolRow) · 222px 기댐 · 줄바꿈 CSS 걷음 · 측점 · 기울기 호버 덮어쓰기 걷음 · LAS 올리기 호버 걷음 - B05 = 세로 두 줄 → 한 행 · 호버 덮어쓰기 걷음(도구줄 · 1m 등고선 · 3D · 추천) · 겹 막힘 querySelector 덮어쓰기 → 공용 sync · 임도(업로드) 보임 + 「받은 임도 자료 없음」 막힘 · 스냅 간격 날 select → 고르기 메뉴(하나) - 켬끔 기억 열쇠 · 측점 · 기울기 처음 값 · 그래픽 카드 취향 열쇠 둘 그대로 - 낡은 시험 고침(568_1 · 622_2 · 624_2 · 624_3 · 553_4 · 625_draw · b05_routeedit_initial · 626_3 · 390_4 · 346_2 · 353_1 · 581_2 · 584_1 · 584_3) — 표 꼴 row() · 호버 글 = 표 · 한 행 · 고르기 메뉴로 바뀐 글을 잡음 · 새 지킴 634_2 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
101 lines
4.7 KiB
Python
101 lines
4.7 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
|
||
# 634-2 표 한 줄 = row(열쇠, 아이콘, 호버제목, 묶음[, true]) · true 없음 = 처음 끔
|
||
entry = re.search(r'row\("soils", "(\w+)", "[^"]+", (?:"\w+"|null)(, true)?\)', defs)
|
||
assert entry and not entry.group(2) # 처음 값 끔
|
||
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)
|