Files
GeoData/tests/test_roof_textures.py
s0wlz (Matthias Puchstein) 3b57981a25 fix(buildings): Implement dynamic roof texture extraction from VRT
Fixed the issue where 2km building tiles had incorrect roof textures because they relied on 1km texture files. Now, textures are dynamically extracted from the global Ortho VRT using the exact building tile bounds, ensuring perfect alignment and full coverage.
2026-02-04 21:31:40 +01:00

72 lines
2.9 KiB
Python

import unittest
from unittest.mock import patch, MagicMock
import os
import numpy as np
from geodata_pipeline.buildings import export_buildings
from geodata_pipeline.config import Config
class TestRoofTextures(unittest.TestCase):
@patch("geodata_pipeline.buildings.gdal.WarpOptions")
@patch("geodata_pipeline.buildings.gdal.Warp")
@patch("geodata_pipeline.buildings.gdal.Translate")
@patch("geodata_pipeline.buildings.gdal.Open")
@patch("geodata_pipeline.buildings._ensure_cityjson_for_tile")
@patch("geodata_pipeline.buildings._load_cityjson")
@patch("geodata_pipeline.buildings._collect_faces")
@patch("geodata_pipeline.buildings._compose_glb")
@patch("geodata_pipeline.buildings.ensure_dir")
@patch("geodata_pipeline.buildings.os.path.exists")
@patch("builtins.open")
def test_vrt_roof_texture_extraction(self, mock_open_file, mock_exists, mock_ensure_dir, mock_compose, mock_collect, mock_load_cj, mock_ensure_cj, mock_gdal_open, mock_translate, mock_warp, mock_warp_opts):
# Setup mocks
mock_exists.return_value = True
# Mock manifest: 2km tile (1000, 1000) to (3000, 3000)
mock_handle = MagicMock()
mock_open_file.return_value.__enter__.return_value = mock_handle
mock_handle.__iter__.return_value = [
"tile_id,xmin,ymin,xmax,ymax,global_min,global_max,out_res,tile_key,tile_min,tile_max\n",
"tile_2km,1000,1000,3000,3000,0,100,1025,1_1,0,100\n"
]
mock_ensure_cj.return_value = "dummy.json"
mock_load_cj.return_value = {"CityObjects": {}}
mock_collect.return_value = (
[[10.0, 10.0, 5.0]], # vertices
[([0, 0, 0], "RoofSurface")]
)
cfg = Config.default()
cfg.work.ortho_vrt = "work/dop.vrt"
cfg.export.ortho_dir = "export/ortho_jpg"
cfg.export.manifest_path = "manifest.csv"
# Mock GDAL
mock_ds = MagicMock()
mock_gdal_open.return_value = mock_ds
mock_ds.GetGeoTransform.return_value = (0, 1, 0, 5000, 0, -1)
mock_ds.RasterXSize = 5000
mock_ds.RasterYSize = 5000
mock_ds.RasterCount = 3
mock_band = MagicMock()
mock_ds.GetRasterBand.return_value = mock_band
mock_band.ReadAsArray.return_value = np.zeros((10, 10))
# Mock Warp to return a dataset
mock_warp.return_value = MagicMock()
export_buildings(cfg)
# Verify WarpOptions was called with the 2km bounds
mock_warp_opts.assert_called()
# Find the call that used outputBounds
found_correct_bounds = False
for call in mock_warp_opts.call_args_list:
if call.kwargs.get("outputBounds") == (1000.0, 1000.0, 3000.0, 3000.0):
found_correct_bounds = True
break
self.assertTrue(found_correct_bounds, "WarpOptions not called with expected 2km bounds")
if __name__ == "__main__":
unittest.main()