import tempfile import unittest from pathlib import Path import laspy import numpy as np from B04_wf1_Surface.B04_wf1_Surface_Engine import run_surface_analysis from B04_wf1_Surface.B04_wf1_Surface_Engine_Ground import ( build_ground_masks, summarize_masks, ) class GroundMasksTest(unittest.TestCase): def test_build_and_summarize(self) -> None: coords = np.linspace(0.0, 20.0, 21) gx, gy = np.meshgrid(coords, coords) z = 5.0 + 0.03 * gx xyz = np.column_stack([gx.ravel(), gy.ravel(), z.ravel()]).astype(np.float64) bounds = np.array([[0.0, 20.0], [0.0, 20.0], [float(z.min()), float(z.max())]]) data = {"xyz": xyz, "bounds": bounds} masks = build_ground_masks(data, ["grid_min_z"]) self.assertIn("grid_min_z", masks) self.assertEqual(masks["grid_min_z"].dtype, bool) summary = summarize_masks(data, masks) self.assertEqual(summary["grid_min_z"]["total_point_count"], len(xyz)) self.assertGreater(summary["grid_min_z"]["ground_ratio"], 0.9) def test_unknown_filter(self) -> None: data = {"xyz": np.zeros((1, 3)), "bounds": np.zeros((3, 2))} with self.assertRaises(ValueError): build_ground_masks(data, ["unknown"]) class RunSurfaceAnalysisTest(unittest.TestCase): def test_full_pipeline(self) -> None: with tempfile.TemporaryDirectory() as directory: root = Path(directory) / "proj" root.mkdir() coords = np.linspace(0.0, 30.0, 31) gx, gy = np.meshgrid(coords, coords) z = 5.0 + 0.04 * gx + 0.02 * gy src = Path(directory) / "cloud.las" las = laspy.LasData(laspy.LasHeader(point_format=3, version="1.2")) las.x, las.y, las.z = gx.ravel(), gy.ravel(), z.ravel() las.write(src) result = run_surface_analysis( root, src, source_filters=["grid_min_z"], methods=["dtm", "tin"] ) self.assertEqual(result["processed"]["point_count"], 961) self.assertEqual(result["manifest"]["status"], "completed") self.assertGreater(result["ground_summary"]["grid_min_z"]["ground_ratio"], 0.9) model_types = {m["model_type"] for m in result["models"]} self.assertEqual(model_types, {"dtm", "tin"}) for model in result["models"]: self.assertTrue(model["model_file_path"].startswith("B04_wf1_Surface/")) self.assertTrue(model["layers"]) # structured.npz가 processed 폴더에 생성됨 self.assertTrue((root / "B04_wf1_Surface" / "processed" / "structured.npz").is_file())