Files
Aislo/resources/tester/test_640_lidar_default.py
T
eomsangdonandClaude Opus 5.5 366fd7a700 feat(640-1): 라이다 기본 고름 — 확정 implicit · 평활 끔 · 분류 덮임 조건 · implicit 기본 필터에만
- 확정 기본 표현 implicit · 평활 False · WF1 자동 짓기에 확정 표현 더함(SURFACE_AUTO_METHODS 는 dtm 그대로)
- 「분류 있음」 자동 고름 = 비율 0.2 % + 10 m 칸 덮임 50 % · 덮임 저장본(classification_coverage.json · 점군 안 풂)
- 분류 LAS 의 implicit 는 기본 필터에만 지음(csf 두 번 안 지음)
- B04 화면 확정 없을 때 기본 표현 implicit
- 지킴 시험 test_640_lidar_default

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 21:20:24 +09:00

82 lines
3.3 KiB
Python

"""640 라이다 기본 고름 · implicit 점 수 · 격자 칸 뽑기 · 지문 · 틈 닫기 (요구 558).
서버 함수만 — 작은 합성 점군 · 임시 폴더.
"""
from pathlib import Path
import numpy as np
from B04_PreProcess.B04_PreProcess_Engine_Filter_Classification import (
classified_coverage,
has_classified_coverage,
)
from B04_PreProcess.B04_PreProcess_Engine_Ground import resolve_auto_source_filters
from B04_PreProcess.B04_PreProcess_Engine_Pipeline import build_all_terrain_models
from config import config_system as cfg
def _plane(size_m: float = 60.0, spacing_m: float = 0.5) -> np.ndarray:
axis = np.arange(0.0, size_m, spacing_m)
x, y = np.meshgrid(axis, axis)
z = 100.0 + 0.2 * x + 0.1 * np.sin(y / 5.0)
return np.column_stack([x.ravel(), y.ravel(), z.ravel()])
def _structured(points: np.ndarray, classification: np.ndarray | None = None) -> dict:
data = {"xyz": points, "bounds": np.array([points.min(axis=0), points.max(axis=0)]).T}
if classification is not None:
data["classification"] = classification
return data
def test_확정_기본값은_implicit_평활_끔() -> None:
assert cfg.SURFACE_CONFIRM_DEFAULT_METHOD == "implicit"
assert cfg.SURFACE_CONFIRM_DEFAULT_SMOOTH is False
assert cfg.SURFACE_AUTO_METHODS == ("dtm",) # D03 자체 라이다는 dtm 만 그대로
def test_일부만_분류된_LAS_는_자동_기본에서_csf() -> None:
points = _plane(100.0)
partial = np.ones(len(points), dtype=np.uint8)
partial[(points[:, 0] < 30) & (np.arange(len(points)) % 4 == 0)] = 2 # 비율 7 % · 덮임 30 %
assert classified_coverage(_structured(points, partial)) < 0.5
assert resolve_auto_source_filters(_structured(points, partial)) == ["csf"]
spread = np.ones(len(points), dtype=np.uint8)
spread[::37] = 2 # 비율 2.7 % · 덮임 100 %
assert classified_coverage(_structured(points, spread)) == 1.0
assert resolve_auto_source_filters(_structured(points, spread)) == ["classification", "csf"]
def test_덮임은_저장본을_다시_씀(tmp_path: Path) -> None:
points = _plane(40.0)
classes = np.full(len(points), 2, dtype=np.uint8)
(tmp_path / "structured.npz").write_bytes(b"x")
assert has_classified_coverage(_structured(points, classes), tmp_path)
assert (tmp_path / "classification_coverage.json").is_file()
class _NoXyz(dict):
def __getitem__(self, key): # type: ignore[no-untyped-def]
assert key != "xyz", "저장본이 맞으면 점군을 풀지 않아야 함"
return dict.__getitem__(self, key)
assert has_classified_coverage(_NoXyz(_structured(points, classes)), tmp_path)
def _config(**override: object) -> dict:
config = cfg.build_surface_model_config()
config.update({"source_filters": ["a", "b"], "precompute": ["dtm", "implicit"]})
config.update(override)
return config
def test_implicit_은_기본_필터에만(tmp_path: Path) -> None:
points = _plane()
data = _structured(points)
masks = {"a": np.ones(len(points), bool), "b": np.arange(len(points)) % 2 == 0}
manifest = build_all_terrain_models(data, masks, tmp_path, _config())
assert set(manifest["source_filters"]["a"]["methods"]) == {"dtm", "implicit"}
assert set(manifest["source_filters"]["b"]["methods"]) == {"dtm"}
assert not (tmp_path / "implicit_b.npz").exists()