| import h5py |
| import numpy as np |
| from pathlib import Path |
|
|
| def load_map_from_hdf5(h5_source): |
| """ |
| Load map data from HDF5 file. Accepts: |
| - string path (e.g., "map.h5") |
| - file-like object (e.g., SpooledTemporaryFile) |
| |
| Returns structured dict. |
| """ |
| with h5py.File(h5_source, 'r') as f: |
| |
| occupancy = f['map_structure'][:] |
| M, N = occupancy.shape |
| |
| |
| obstacles = [] |
| obs_positions = np.where(occupancy == 1) |
| for i, j in zip(obs_positions[0], obs_positions[1]): |
| obstacles.append((int(i), int(j))) |
|
|
| |
| map_name = f.attrs.get('map_name', None) |
| |
| |
| |
| if map_name is None: |
| |
| try: |
| if isinstance(h5_source, (str, Path)): |
| map_name = Path(h5_source).stem |
| elif hasattr(h5_source, 'name') and isinstance(h5_source.name, str): |
| map_name = Path(h5_source.name).stem |
| else: |
| map_name = "unknown_map" |
| except Exception: |
| map_name = "unknown_map" |
|
|
| resolution = f.attrs.get('resolution', 1.0) |
|
|
| |
| materials = [] |
| if 'materials' in f: |
| materials = [mat.decode('utf-8') for mat in f['materials'][:]] |
|
|
| result = { |
| 'name': map_name, |
| 'grid': { |
| 'M': M, |
| 'N': N, |
| 'obstacles': obstacles |
| }, |
| 'resolution': resolution, |
| 'materials': materials |
| } |
|
|
| if 'terrain' in f: |
| result['terrain_grid'] = f['terrain'][:] |
| if 'elevation' in f: |
| result['elevation_grid'] = f['elevation'][:] |
|
|
| return result |
|
|
|
|
| def load_graph_from_hdf5(h5_source): |
| with h5py.File(h5_source, "r") as f: |
| nodes = f["graph/nodes"][:] |
| edges = f["graph/edges"][:] |
|
|
| |
| map_name = f.attrs.get('map_name', None) |
| |
| |
| |
| if map_name is None: |
| |
| try: |
| if isinstance(h5_source, (str, Path)): |
| map_name = Path(h5_source).stem |
| elif hasattr(h5_source, 'name') and isinstance(h5_source.name, str): |
| map_name = Path(h5_source.name).stem |
| else: |
| map_name = "unknown_map" |
| except Exception: |
| map_name = "unknown_map" |
|
|
| resolution = f.attrs.get('resolution', 1.0) |
|
|
| result = { |
| 'name': map_name, |
| 'edges': edges, |
| 'nodes': nodes, |
| 'resolution': resolution, |
| } |
|
|
| return result |
|
|
| def load_both_from_hdf5(h5_source): |
| """ |
| Load both map (grid) and graph data from HDF5 file. |
| This is useful for synthetic maps that support both approaches. |
| |
| Args: |
| h5_source: HDF5 file path or file-like object |
| |
| Returns: |
| dict: Contains both 'map_data' and 'graph_data' keys, plus metadata |
| """ |
| with h5py.File(h5_source, 'r') as f: |
| |
| map_name = f.attrs.get('map_name', None) |
| |
| |
| if map_name is None: |
| try: |
| if isinstance(h5_source, (str, Path)): |
| map_name = Path(h5_source).stem |
| elif hasattr(h5_source, 'name') and isinstance(h5_source.name, str): |
| map_name = Path(h5_source.name).stem |
| else: |
| map_name = "unknown_map" |
| except Exception: |
| map_name = "unknown_map" |
|
|
| resolution = f.attrs.get('resolution', 1.0) |
| |
| |
| has_map = 'map_structure' in f |
| has_graph = 'graph' in f |
| |
| result = { |
| 'name': map_name, |
| 'resolution': resolution, |
| 'has_map': has_map, |
| 'has_graph': has_graph, |
| 'map_data': None, |
| 'graph_data': None |
| } |
| |
| |
| if has_map: |
| occupancy = f['map_structure'][:] |
| M, N = occupancy.shape |
| |
| |
| obstacles = [] |
| obs_positions = np.where(occupancy == 1) |
| for i, j in zip(obs_positions[0], obs_positions[1]): |
| obstacles.append((int(i), int(j))) |
|
|
| |
| materials = [] |
| if 'materials' in f: |
| materials = [mat.decode('utf-8') for mat in f['materials'][:]] |
|
|
| map_data = { |
| 'name': map_name, |
| 'grid': { |
| 'M': M, |
| 'N': N, |
| 'obstacles': obstacles |
| }, |
| 'resolution': resolution, |
| 'materials': materials |
| } |
|
|
| if 'terrain' in f: |
| map_data['terrain_grid'] = f['terrain'][:] |
| if 'elevation' in f: |
| map_data['elevation_grid'] = f['elevation'][:] |
| |
| result['map_data'] = map_data |
| |
| |
| if has_graph: |
| nodes = f["graph/nodes"][:] |
| edges = f["graph/edges"][:] |
|
|
| graph_data = { |
| 'name': map_name, |
| 'edges': edges, |
| 'nodes': nodes, |
| 'resolution': resolution, |
| } |
| |
| result['graph_data'] = graph_data |
|
|
| return result |
|
|
| |
| |
| if __name__ == "__main__": |
| import sys |
| h5_path = sys.argv[1] if len(sys.argv) > 1 else "quantum/maps/synthetic/3x3/no_obs3x3.h5" |
| |
| |
| print("=== Loading both map and graph data ===") |
| both_data = load_both_from_hdf5(h5_path) |
| print(f"Name: {both_data['name']}") |
| print(f"Has map data: {both_data['has_map']}") |
| print(f"Has graph data: {both_data['has_graph']}") |
| print(f"Resolution: {both_data['resolution']}") |
| |
| if both_data['map_data']: |
| print("\nMap data:") |
| print(f"Grid: {both_data['map_data']['grid']['M']}x{both_data['map_data']['grid']['N']}") |
| print(f"Obstacles: {both_data['map_data']['grid']['obstacles']}") |
| if 'terrain_grid' in both_data['map_data']: |
| print("Terrain grid loaded (shape):", both_data['map_data']['terrain_grid'].shape) |
| if 'elevation_grid' in both_data['map_data']: |
| print("Elevation grid loaded (shape):", both_data['map_data']['elevation_grid'].shape) |
| |
| if both_data['graph_data']: |
| print("\nGraph data:") |
| print(f"Nodes shape: {both_data['graph_data']['nodes'].shape}") |
| print(f"Edges shape: {both_data['graph_data']['edges'].shape}") |
| |
| |
| print("\n=== Loading only map data (backward compatibility) ===") |
| map_data = load_map_from_hdf5(h5_path) |
| print(f"Name: {map_data['name']}") |
| print(f"Grid: {map_data['grid']['M']}x{map_data['grid']['N']}") |
| print(f"Obstacles: {map_data['grid']['obstacles']}") |
| print(f"Resolution: {map_data['resolution']}") |
| |
| |
| print("\n=== Loading only graph data (backward compatibility) ===") |
| graph_data = load_graph_from_hdf5(h5_path) |
| print(f"Name: {graph_data['name']}") |
| print(f"Nodes shape: {graph_data['nodes'].shape}") |
| print(f"Edges shape: {graph_data['edges'].shape}") |
| print(f"Resolution: {graph_data['resolution']}") |