From 7b490bbc6990f1904c24f6ca06374e4354f5c6aa Mon Sep 17 00:00:00 2001 From: Andrej730 Date: Fri, 5 Sep 2025 10:50:54 +0500 Subject: [PATCH] Bonsai - support loading element types from ifcsqlite --- src/bonsai/bonsai/bim/import_ifc.py | 41 ++++++++++++++++++++++++++++- src/bonsai/bonsai/tool/model.py | 3 +++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/src/bonsai/bonsai/bim/import_ifc.py b/src/bonsai/bonsai/bim/import_ifc.py index e8a1d9794c..fdaf56e2ff 100644 --- a/src/bonsai/bonsai/bim/import_ifc.py +++ b/src/bonsai/bonsai/bim/import_ifc.py @@ -520,11 +520,50 @@ class IfcImporter: def create_element_types(self): # TODO: if isinstance(self.file, ifcopenshell.sqlite): - print("WARNING. Loading element types from IFCSQLite is not supported.") + self.create_element_types_sqlite(self.element_types) return for element_type in self.element_types: self.create_element_type(element_type) + def create_element_types_sqlite(self, element_types: set[ifcopenshell.entity_instance]) -> None: + assert isinstance(self.file, ifcopenshell.sqlite) + geometry_cache = self.file.get_geometry([e.id() for e in element_types]) + geometry_meshes: dict[str, bpy.types.Mesh] = {} + for geometry_id, geometry in geometry_cache["geometry"].items(): + verts = geometry["verts"] + fake_geometry = type("Geometry", (), {"id": geometry_id}) + mesh_name = tool.Loader.get_mesh_name_from_shape(fake_geometry) # pyright: ignore[reportArgumentType] + mesh = bpy.data.meshes.new(mesh_name) + + if geometry["faces"].size: + mesh = tool.Loader.create_mesh_from_shape( + mesh=mesh, faces=geometry["faces"].reshape(-1, 3), verts=verts.reshape(-1, 3) + ) + else: + vertices = verts.reshape(-1, 3).tolist() + edges = geometry["edges"].reshape(-1, 2).tolist() + mesh.from_pydata(vertices, edges, []) + tool.Loader.link_mesh(fake_geometry, mesh) # pyright: ignore[reportArgumentType] + + mesh["ios_materials"] = geometry["materials"] + mesh["ios_material_ids"] = geometry["material_ids"] + self.meshes[mesh_name] = mesh + geometry_meshes[geometry_id] = mesh + + shapes = geometry_cache["shapes"] + for element in element_types: + # Allow missing element types to accomodate older ifcsqlite files + # that didn't store element types geometry. + shape = shapes.get(element.id()) + if shape: + geometry_id = shapes[element.id()]["geometry"] + else: + geometry_id = None + mesh = None if geometry_id is None else geometry_meshes[geometry_id] + obj = bpy.data.objects.new(tool.Loader.get_name(element), mesh) + self.link_element(element, obj) + self.material_creator.create(element, obj, mesh, False) + def create_element_type(self, element: ifcopenshell.entity_instance) -> None: self.ifc_import_settings.logger.info("Creating object %s", element) mesh = None diff --git a/src/bonsai/bonsai/tool/model.py b/src/bonsai/bonsai/tool/model.py index 7da6f83e1a..0f29f2d733 100644 --- a/src/bonsai/bonsai/tool/model.py +++ b/src/bonsai/bonsai/tool/model.py @@ -1085,6 +1085,9 @@ class Model(bonsai.core.tool.Model): # No need to preview to update, Blender will do it in background, # `preview.icon_id` doesn't change after `asset_generate_preview()`. obj.asset_generate_preview() + # Avoid issues with sqlite files. + elif type(tool.Ifc.get()) is not ifcopenshell.file: + return else: unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get()) size = 128