Merge remote-tracking branches 'origin/sub_laptop_5' and 'origin/sub_laptop_8' into main_laptop_1
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
"""766-2 외곽 안 구멍 메움 지킴 시험 — 다듬기 판은 바탕 필터 외곽 · 구멍은 막 펴기로 매끈하게.
|
||||
|
||||
합성 비탈(평면) 120 × 120 m · 가운데 30 × 30 m 땅 점이 다 걸러짐(다듬기가 지운 자리 흉내).
|
||||
"""
|
||||
|
||||
import numpy as np
|
||||
|
||||
from B04_PreProcess.B04_PreProcess_Engine_ModelBuild import build_dtm, build_implicit
|
||||
from B04_PreProcess.B04_PreProcess_Engine_ModelContext import TerrainContext, fill_holes_smooth
|
||||
from B04_PreProcess.B04_PreProcess_Engine_Quality import filled_stats
|
||||
from common_util.common_util_surface_sampler import build_surface_sampler
|
||||
from config.config_system import build_surface_model_config
|
||||
|
||||
RNG = np.random.default_rng(7662)
|
||||
|
||||
|
||||
def _scene() -> tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]:
|
||||
count = 120 * 120 * 3
|
||||
x, y = RNG.uniform(0, 120, count), RNG.uniform(0, 120, count)
|
||||
xyz = np.column_stack((x, y, 0.3 * x + 0.1 * y + 100.0)).astype(np.float32)
|
||||
base = np.ones(count, dtype=bool)
|
||||
hole = (np.abs(x - 60) < 15) & (np.abs(y - 60) < 15)
|
||||
bounds = np.array([[0, 120], [0, 120], [90, 150]], dtype=np.float64)
|
||||
return xyz, base, base & ~hole, bounds
|
||||
|
||||
|
||||
def test_fill_keeps_plane_and_curved_slope() -> None:
|
||||
yy, xx = np.mgrid[0:60, 0:60].astype(float)
|
||||
known = np.ones(xx.shape, dtype=bool)
|
||||
known[20:40, 20:40] = False
|
||||
inside = np.ones(xx.shape, dtype=bool)
|
||||
for truth in (0.3 * xx + 0.1 * yy, 0.004 * (xx - 25) ** 2 + 0.002 * (yy - 35) ** 2):
|
||||
work = np.where(known, truth, 0.0)
|
||||
filled = fill_holes_smooth(work, known, inside, 3.0)
|
||||
assert filled.sum() == 14 * 14 # 땅 칸에서 3 칸 넘게 먼 자리만 메운 넓이로 셈
|
||||
assert np.abs(work - truth).max() < 0.1 # 둘레 높이 · 기울기 그대로 이어짐(계단 · 혹 없음)
|
||||
# 작은 틈(3 칸 안)은 메움 대상이 아님 — 지금처럼 가까운 칸 값
|
||||
small = np.ones(xx.shape, dtype=bool)
|
||||
small[10:13, 10:13] = False
|
||||
assert not fill_holes_smooth(xx.copy(), small, inside, 3.0).any()
|
||||
|
||||
|
||||
def test_refine_hole_inside_outer_is_filled(tmp_path) -> None:
|
||||
xyz, base, refined, bounds = _scene()
|
||||
config = build_surface_model_config()
|
||||
plain = TerrainContext(xyz=xyz, mask=refined, bounds=bounds, config=config)
|
||||
outer = TerrainContext(xyz=xyz, mask=refined, bounds=bounds, config=config, outer_mask=base)
|
||||
# 외곽 = 바탕 필터 그대로(넓히지 않음) · 구멍 칸만 메움
|
||||
base_ctx = TerrainContext(xyz=xyz, mask=base, bounds=bounds, config=config)
|
||||
assert outer.footprint()[3].sum() == base_ctx.footprint()[3].sum()
|
||||
resolution = float(config["dtm_grid_resolution_meters"])
|
||||
assert outer.filled(resolution).sum() > 400
|
||||
assert not base_ctx.filled(resolution).any()
|
||||
build_dtm(outer, tmp_path, "dtm_ptd_refine", lambda _: None)
|
||||
build_implicit(outer, tmp_path, "implicit_ptd_refine", lambda _: None)
|
||||
xy = np.column_stack([np.linspace(50, 70, 21), np.full(21, 60.0)])
|
||||
truth = 0.3 * xy[:, 0] + 0.1 * xy[:, 1] + 100.0
|
||||
for method in ("dtm", "implicit"):
|
||||
z, valid = build_surface_sampler(tmp_path, "ptd_refine", method, False).sample_xy(xy)
|
||||
assert valid.all(), method # 구멍 0
|
||||
# 둘레 비탈과 같은 면 — dtm 둘레 칸 = 칸 최저점(0.1~0.2 m 들쭉날쭉)이라 0.5 m 안
|
||||
assert np.abs(z - truth).max() < 0.5, method
|
||||
with np.load(tmp_path / "dtm_ptd_refine.npz") as data:
|
||||
valid = np.asarray(data["valid_mask"], dtype=bool)
|
||||
stats = filled_stats(tmp_path, "ptd_refine", valid, 1.0)
|
||||
assert 400 < stats["filled_m2"] < 900 and stats["filled_pct"] > 0
|
||||
# 바탕 외곽 없이(옛 길)는 구멍 자리가 외곽 밖 — 구멍이 열린 만이면 비어 있었음
|
||||
assert plain.footprint()[3].sum() <= outer.footprint()[3].sum()
|
||||
Reference in New Issue
Block a user