diff --git a/src/blenderbim/blenderbim/bim/import_ifc.py b/src/blenderbim/blenderbim/bim/import_ifc.py index 0aac7c023e..7db325ecdb 100644 --- a/src/blenderbim/blenderbim/bim/import_ifc.py +++ b/src/blenderbim/blenderbim/bim/import_ifc.py @@ -32,12 +32,13 @@ import ifcopenshell.geom import ifcopenshell.util.unit import ifcopenshell.util.element import ifcopenshell.util.geolocation +import ifcopenshell.util.placement import blenderbim.tool as tool import ifcopenshell.ifcopenshell_wrapper as ifcopenshell_wrapper from itertools import chain, accumulate -from blenderbim.bim.ifc import IfcStore +from blenderbim.bim.ifc import IfcStore, IFC_CONNECTED_TYPE from blenderbim.bim.module.drawing.prop import ANNOTATION_TYPES_DATA -from typing import Dict, Union +from typing import Dict, Union, Optional class MaterialCreator: @@ -200,20 +201,26 @@ class IfcImporter: self.ifc_import_settings = ifc_import_settings self.diff = None self.file: ifcopenshell.file = None - self.context_settings = [] - self.gross_context_settings = [] + self.context_settings: list[ifcopenshell.geom.main.settings] = [] + self.gross_context_settings: list[ifcopenshell.geom.main.settings] = [] self.contexts = [] self.project = None self.has_existing_project = False - self.collections = {} - self.elements = set() - self.type_collection = None + # element guids to blender collections mapping + self.collections: dict[str, bpy.types.Collection] = {} + self.elements: set[ifcopenshell.entity_instance] = set() + self.annotations: set[ifcopenshell.entity_instance] = set() + self.gross_elements: set[ifcopenshell.entity_instance] = set() + self.element_types: set[ifcopenshell.entity_instance] = set() + self.spatial_elements: set[ifcopenshell.entity_instance] = set() + self.type_collection: bpy.types.Collection = None self.type_products = {} self.meshes = {} self.mesh_shapes = {} self.time = 0 self.unit_scale = 1 - self.added_data = {} + # ifc definition ids to blender elements mapping + self.added_data: dict[int, IFC_CONNECTED_TYPE] = {} self.native_elements = set() self.native_data = {} self.progress = 0 @@ -452,7 +459,9 @@ class IfcImporter: for element in self.gross_elements: print(element) - def get_spatial_elements_filtered_by_elements(self, elements): + def get_spatial_elements_filtered_by_elements( + self, elements: set[ifcopenshell.entity_instance] + ) -> set[ifcopenshell.entity_instance]: leaf_spatial_elements = set([ifcopenshell.util.element.get_container(e) for e in elements]) results = set() for spatial_element in leaf_spatial_elements: @@ -864,7 +873,7 @@ class IfcImporter: except: pass - def create_generic_elements(self, elements): + def create_generic_elements(self, elements: set[ifcopenshell.entity_instance]) -> None: if isinstance(self.file, ifcopenshell.sqlite): return self.create_generic_sqlite_elements(elements) @@ -883,7 +892,7 @@ class IfcImporter: print("{} / {} elements processed ...".format(i, total)) self.create_product(element) - def create_generic_sqlite_elements(self, elements): + def create_generic_sqlite_elements(self, elements: set[ifcopenshell.entity_instance]) -> None: self.geometry_cache = self.file.get_geometry([e.id() for e in elements]) for geometry_id, geometry in self.geometry_cache["geometry"].items(): mesh_name = tool.Loader.get_mesh_name(type("Geometry", (), {"id": geometry_id})) @@ -930,7 +939,9 @@ class IfcImporter: mesh = self.meshes.get(mesh_name) self.create_product(element, mesh=mesh) - def create_products(self, products, settings=None): + def create_products( + self, products, settings: Optional[ifcopenshell.geom.main.settings] = None + ) -> set[ifcopenshell.entity_instance]: results = set() if not products: return results @@ -1053,7 +1064,7 @@ class IfcImporter: return mapped_representation return None - def create_pointclouds(self, products): + def create_pointclouds(self, products: set[ifcopenshell.entity_instance]) -> set[ifcopenshell.entity_instance]: result = set() for product in products: representation = self.get_pointcloud_representation(product) @@ -1064,7 +1075,9 @@ class IfcImporter: return result - def create_pointcloud(self, product, representation): + def create_pointcloud( + self, product: ifcopenshell.entity_instance, representation: ifcopenshell.entity_instance + ) -> Union[ifcopenshell.entity_instance, None]: placement_matrix = self.get_element_matrix(product) vertex_list = [] for item in representation.Items: @@ -1547,14 +1560,14 @@ class IfcImporter: self.project["blender"].BIMCollectionProperties.obj = obj obj.BIMObjectProperties.collection = self.collections[project.GlobalId] = self.project["blender"] - def create_collections(self): + def create_collections(self) -> None: self.create_spatial_decomposition_collections() if self.ifc_import_settings.collection_mode == "DECOMPOSITION": self.create_aggregate_and_nest_collections() elif self.ifc_import_settings.collection_mode == "SPATIAL_DECOMPOSITION": pass - def create_spatial_decomposition_collections(self): + def create_spatial_decomposition_collections(self) -> None: for rel_aggregate in self.project["ifc"].IsDecomposedBy or []: self.create_spatial_decomposition_collection(self.project["blender"], rel_aggregate.RelatedObjects) @@ -1567,7 +1580,9 @@ class IfcImporter: tool.Loader.create_project_collection("Views") self.type_collection = tool.Loader.create_project_collection("Types") - def create_spatial_decomposition_collection(self, parent, related_objects): + def create_spatial_decomposition_collection( + self, parent: Union[bpy.types.Collection, bpy.types.Object], related_objects: list[ifcopenshell.entity_instance] + ) -> None: for element in related_objects: if element not in self.spatial_elements: continue @@ -1617,9 +1632,9 @@ class IfcImporter: self.ifc_import_settings.collection_mode = "SPATIAL_DECOMPOSITION" return - aggregates = {} + aggregates: dict[str, dict] = {} for rel_aggregate in rel_aggregates: - element = rel_aggregate.RelatingObject + element: ifcopenshell.entity_instance = rel_aggregate.RelatingObject collection = bpy.data.collections.new(tool.Loader.get_name(element)) aggregates[element.GlobalId] = {"element": element, "collection": collection} self.collections[element.GlobalId] = collection @@ -1688,18 +1703,20 @@ class IfcImporter: else: blender_material.BIMStyleProperties.active_style_type = "Shading" - def place_objects_in_collections(self): + def place_objects_in_collections(self) -> None: for ifc_definition_id, obj in self.added_data.items(): if isinstance(obj, bpy.types.Object): self.place_object_in_collection(self.file.by_id(ifc_definition_id), obj) - def place_object_in_collection(self, element, obj): + def place_object_in_collection(self, element: ifcopenshell.entity_instance, obj: bpy.types.Object) -> None: if self.ifc_import_settings.collection_mode == "DECOMPOSITION": self.place_object_in_decomposition_collection(element, obj) elif self.ifc_import_settings.collection_mode == "SPATIAL_DECOMPOSITION": self.place_object_in_spatial_decomposition_collection(element, obj) - def place_object_in_decomposition_collection(self, element, obj): + def place_object_in_decomposition_collection( + self, element: ifcopenshell.entity_instance, obj: bpy.types.Object + ) -> None: if element.is_a("IfcProject"): return elif element.is_a("IfcGridAxis"): @@ -1719,7 +1736,9 @@ class IfcImporter: else: return self.place_object_in_spatial_decomposition_collection(element, obj) - def place_object_in_spatial_decomposition_collection(self, element, obj): + def place_object_in_spatial_decomposition_collection( + self, element: ifcopenshell.entity_instance, obj: bpy.types.Object + ) -> None: if element.is_a("IfcProject"): return elif element.is_a("IfcGridAxis"): @@ -1763,7 +1782,7 @@ class IfcImporter: if rel.is_a("IfcRelAssignsToGroup") and rel.RelatingGroup.ObjectType == "DRAWING": return rel.RelatingGroup - def get_element_matrix(self, element): + def get_element_matrix(self, element: ifcopenshell.entity_instance) -> np.array: if isinstance(element, ifcopenshell.sqlite_entity): result = self.geometry_cache["shapes"][element.id()]["matrix"] else: @@ -1773,7 +1792,7 @@ class IfcImporter: result[2][3] *= self.unit_scale return result - def scale_matrix(self, matrix): + def scale_matrix(self, matrix: np.array) -> np.array: matrix[0][3] *= self.unit_scale matrix[1][3] *= self.unit_scale matrix[2][3] *= self.unit_scale @@ -2002,7 +2021,7 @@ class IfcImportSettings: self.has_filter = None self.should_filter_spatial_elements = True self.should_setup_viewport_camera = True - self.elements = set() + self.elements: set[ifcopenshell.entity_instance] = set() self.collection_mode = "DECOMPOSITION" @staticmethod diff --git a/src/blenderbim/blenderbim/tool/loader.py b/src/blenderbim/blenderbim/tool/loader.py index 32952b461c..3ffb807f98 100644 --- a/src/blenderbim/blenderbim/tool/loader.py +++ b/src/blenderbim/blenderbim/tool/loader.py @@ -36,7 +36,7 @@ from pathlib import Path class Loader(blenderbim.core.tool.Loader): @classmethod - def create_project_collection(self, name): + def create_project_collection(cls, name: str) -> bpy.types.Collection: project_obj = tool.Ifc.get_object(tool.Ifc.get().by_type("IfcProject")[0]) project_collection = project_obj.BIMObjectProperties.collection for collection in project_collection.children: diff --git a/src/ifcopenshell-python/ifcopenshell/sql.py b/src/ifcopenshell-python/ifcopenshell/sql.py index d258ca0378..546b2b4101 100644 --- a/src/ifcopenshell-python/ifcopenshell/sql.py +++ b/src/ifcopenshell-python/ifcopenshell/sql.py @@ -183,7 +183,7 @@ class sqlite(file): return True return False - def get_geometry(self, ids): + def get_geometry(self, ids: list[int]) -> dict[str, dict]: import numpy as np ids_csv = ",".join(map(str, ids))