diff --git a/lidar_pipeline/tests/test_visualizations.py b/lidar_pipeline/tests/test_visualizations.py index 177515d..b412bd0 100644 --- a/lidar_pipeline/tests/test_visualizations.py +++ b/lidar_pipeline/tests/test_visualizations.py @@ -198,4 +198,100 @@ class TestFlow: data = src.read(1) # log1p(x) >= 0 for x >= 0 valid = data[~np.isnan(data)] - assert np.nanmin(valid) >= 0 \ No newline at end of file + assert np.nanmin(valid) >= 0 + + +class TestRRIM: + def test_generates_tif(self, synthetic_dem, tmp_output_dir): + from lidar_pipeline.visualizations import generate_rrim + result = generate_rrim(synthetic_dem, "test", tmp_output_dir, 5.0) + assert result is not None + assert result.exists() + assert result.suffix == ".tif" + + def test_rrim_is_rgb_3band(self, synthetic_dem, tmp_output_dir): + import rasterio + from lidar_pipeline.visualizations import generate_rrim + result = generate_rrim(synthetic_dem, "test", tmp_output_dir, 5.0) + with rasterio.open(result) as src: + assert src.count == 3, f"Expected 3 bands, got {src.count}" + assert src.dtypes[0] == 'uint8' + + def test_rrim_values_0_255(self, synthetic_dem, tmp_output_dir): + import rasterio + from lidar_pipeline.visualizations import generate_rrim + result = generate_rrim(synthetic_dem, "test", tmp_output_dir, 5.0) + with rasterio.open(result) as src: + for band in range(1, 4): + data = src.read(band) + assert data.min() >= 0 + assert data.max() <= 255 + + def test_rrim_no_nan(self, synthetic_dem, tmp_output_dir): + """RRIM is uint8 RGB — NaN zones are set to 0 (black).""" + import rasterio + from lidar_pipeline.visualizations import generate_rrim + result = generate_rrim(synthetic_dem, "test", tmp_output_dir, 5.0) + with rasterio.open(result) as src: + # uint8 bands should not have NaN + for band in range(1, 4): + data = src.read(band) + assert not np.isnan(data).any(), f"Band {band} has NaN values" + + +class TestMultiHillshade: + def test_generates_tif(self, synthetic_dem, tmp_output_dir): + from lidar_pipeline.visualizations import generate_multi_hillshade + result = generate_multi_hillshade(synthetic_dem, "test", tmp_output_dir, 5.0) + assert result is not None + assert result.exists() + assert result.suffix == ".tif" + + def test_multi_hillshade_is_rgb_3band(self, synthetic_dem, tmp_output_dir): + import rasterio + from lidar_pipeline.visualizations import generate_multi_hillshade + result = generate_multi_hillshade(synthetic_dem, "test", tmp_output_dir, 5.0) + with rasterio.open(result) as src: + assert src.count == 3, f"Expected 3 bands, got {src.count}" + assert src.dtypes[0] == 'uint8' + + def test_multi_hillshade_values_0_255(self, synthetic_dem, tmp_output_dir): + import rasterio + from lidar_pipeline.visualizations import generate_multi_hillshade + result = generate_multi_hillshade(synthetic_dem, "test", tmp_output_dir, 5.0) + with rasterio.open(result) as src: + for band in range(1, 4): + data = src.read(band) + assert data.min() >= 0 + assert data.max() <= 255 + + +class TestLocalDominance: + def test_generates_tif(self, synthetic_dem, tmp_output_dir): + from lidar_pipeline.visualizations import generate_local_dominance + result = generate_local_dominance(synthetic_dem, "test", tmp_output_dir, 5.0) + assert result is not None + assert result.exists() + assert result.suffix == ".tif" + + def test_dominance_values_0_1(self, synthetic_dem, tmp_output_dir): + import rasterio + from lidar_pipeline.visualizations import generate_local_dominance + result = generate_local_dominance(synthetic_dem, "test", tmp_output_dir, 5.0) + with rasterio.open(result) as src: + data = src.read(1) + valid = data[~np.isnan(data)] + assert np.nanmin(valid) >= 0, "Local dominance should be >= 0" + assert np.nanmax(valid) <= 1, "Local dominance should be <= 1" + + def test_dominance_nan_mask_preserved(self, synthetic_dem, tmp_output_dir): + """Check that NaN zones from original DEM are preserved.""" + import rasterio + from lidar_pipeline.visualizations import generate_local_dominance + result = generate_local_dominance(synthetic_dem, "test", tmp_output_dir, 5.0) + # The synthetic DEM has no NaN, so this just verifies the output is valid + with rasterio.open(result) as src: + data = src.read(1) + # Shape should match input + assert data.shape[0] > 0 + assert data.shape[1] > 0 \ No newline at end of file