""" Core data structures for InteriorGen3D scene representation. """ from dataclasses import dataclass, field from typing import List, Optional, Dict, Tuple import numpy as np @dataclass class BoundingBox3D: """3D oriented bounding box for furniture objects.""" center: np.ndarray dimensions: np.ndarray rotation: np.ndarray confidence: float = 1.0 @property def corners(self) -> np.ndarray: w, h, d = self.dimensions / 2 corners_local = np.array([ [-w, -h, -d], [w, -h, -d], [w, h, -d], [-w, h, -d], [-w, -h, d], [w, -h, d], [w, h, d], [-w, h, d] ]) return (self.rotation @ corners_local.T).T + self.center @property def volume(self) -> float: return float(np.prod(self.dimensions)) @dataclass class WallPlane: normal: np.ndarray offset: float height: float start_point: np.ndarray end_point: np.ndarray has_window: bool = False has_door: bool = False material_id: Optional[str] = None @dataclass class RoomLayout: walls: List[WallPlane] = field(default_factory=list) floor_height: float = 0.0 ceiling_height: float = 2.7 floor_polygon: Optional[np.ndarray] = None doors: List[Dict] = field(default_factory=list) windows: List[Dict] = field(default_factory=list) @dataclass class SceneObject: object_id: str category: str bbox: BoundingBox3D mesh_path: Optional[str] = None texture_paths: Optional[Dict[str, str]] = None gaussian_splat_path: Optional[str] = None confidence: float = 1.0 material_type: Optional[str] = None is_on_floor: bool = True parent_object_id: Optional[str] = None @dataclass class SpatialRelation: subject_id: str object_id: str relation: str confidence: float = 1.0 @dataclass class SceneGraph: room_layout: RoomLayout objects: List[SceneObject] = field(default_factory=list) relations: List[SpatialRelation] = field(default_factory=list) camera_pose: Optional[np.ndarray] = None camera_intrinsics: Optional[np.ndarray] = None metric_scale: float = 1.0 def get_object(self, object_id: str) -> Optional[SceneObject]: for obj in self.objects: if obj.object_id == object_id: return obj return None def get_objects_by_category(self, category: str) -> List[SceneObject]: return [obj for obj in self.objects if obj.category == category] @dataclass class PBRMaterial: albedo_map: Optional[np.ndarray] = None metallic_map: Optional[np.ndarray] = None roughness_map: Optional[np.ndarray] = None normal_map: Optional[np.ndarray] = None base_color: Tuple[float, float, float] = (0.8, 0.8, 0.8) metallic: float = 0.0 roughness: float = 0.5 @dataclass class GeneratedScene: scene_graph: SceneGraph room_mesh_path: str object_meshes: Dict[str, str] materials: Dict[str, PBRMaterial] gaussian_splat_path: Optional[str] = None export_paths: Dict[str, str] = field(default_factory=dict) generation_time_seconds: float = 0.0 metadata: Dict = field(default_factory=dict)