From 5e6343885cf17e33dfcd87116f2d57bc4c7f000e Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Sat, 21 Aug 2021 21:09:48 +1000 Subject: [PATCH] Filtered imports is now much faster and works with omitted aggregates --- src/blenderbim/blenderbim/bim/import_ifc.py | 48 ++++++++++++------- .../ifcopenshell/util/attribute.py | 4 +- 2 files changed, 33 insertions(+), 19 deletions(-) diff --git a/src/blenderbim/blenderbim/bim/import_ifc.py b/src/blenderbim/blenderbim/bim/import_ifc.py index df92f37c47..1458f0f184 100644 --- a/src/blenderbim/blenderbim/bim/import_ifc.py +++ b/src/blenderbim/blenderbim/bim/import_ifc.py @@ -224,6 +224,8 @@ class IfcImporter: self.profile_code("Create project") self.create_spatial_hierarchy() self.profile_code("Create spatial hierarchy") + self.process_element_filter() + self.profile_code("Process element filter") self.create_aggregates() self.profile_code("Create aggregates") self.create_aggregate_tree() @@ -234,8 +236,6 @@ class IfcImporter: self.profile_code("Create materials") self.create_styles() self.profile_code("Create styles") - self.process_element_filter() - self.profile_code("Process element filter") self.parse_native_elements() self.profile_code("Parsing native elements") self.create_grids() @@ -290,16 +290,20 @@ class IfcImporter: return abs(coords[0]) > limit or abs(coords[1]) > limit or abs(coords[2]) > limit def process_element_filter(self): - if not self.ifc_import_settings.ifc_selector: + if self.ifc_import_settings.ifc_import_filter == "NONE" or not self.ifc_import_settings.ifc_selector: + self.elements = self.file.by_type("IfcElement") return + selector = ifcopenshell.util.selector.Selector() elements = selector.parse(self.file, self.ifc_import_settings.ifc_selector) if self.ifc_import_settings.ifc_import_filter == "WHITELIST": self.filter_mode = "WHITELIST" self.include_elements = set(elements) + self.elements = self.include_elements elif self.ifc_import_settings.ifc_import_filter == "BLACKLIST": - self.exclude_elements = set(elements) self.filter_mode = "BLACKLIST" + self.exclude_elements = set(elements) + self.elements = [e for e in self.file.by_type("IfcElement") if e not in self.exclude_elements] def parse_native_elements(self): if self.filter_mode == "WHITELIST": @@ -637,16 +641,8 @@ class IfcImporter: def create_empty_and_2d_elements(self): curve_products = [] - if self.filter_mode == "WHITELIST": - self.elements = self.include_elements - elif self.filter_mode == "BLACKLIST": - self.elements = [e for e in self.file.by_type("IfcElement") if e not in self.exclude_elements] - else: - self.elements = self.file.by_type("IfcElement") - - for element in self.elements: - if element.id() in self.added_data: - continue + unadded_data = set([e.id() for e in self.elements]) - set(self.added_data) + for element in unadded_data: if element.is_a("IfcPort"): continue if not element.Representation: @@ -1038,9 +1034,17 @@ class IfcImporter: self.add_related_objects(collection, rel_aggregate.RelatedObjects) def create_aggregates(self): - rel_aggregates = [a for a in self.file.by_type("IfcRelAggregates") if a.RelatingObject.is_a("IfcElement")] - for rel_aggregate in rel_aggregates: - self.create_aggregate(rel_aggregate) + if self.filter_mode in ["WHITELIST", "BLACKLIST"]: + rel_aggregates = [e.IsDecomposedBy[0].RelatingObject for e in self.elements if e.IsDecomposedBy] + else: + rel_aggregates = [a for a in self.file.by_type("IfcRelAggregates") if a.RelatingObject.is_a("IfcElement")] + if len(rel_aggregates) > 10000: + # More than 10,000 collections makes Blender unhappy + print("Falling back to SPATIAL_DECOMPOSITION collection mode") + self.ifc_import_settings.collection_mode = "SPATIAL_DECOMPOSITION" + else: + for rel_aggregate in rel_aggregates: + self.create_aggregate(rel_aggregate) def create_aggregate_tree(self): for aggregate in self.aggregates.values(): @@ -1191,8 +1195,15 @@ class IfcImporter: ): bpy.data.objects.remove(self.spatial_structure_elements[global_id]["blender_obj"]) collection = self.spatial_structure_elements[global_id]["blender"] + elif self.ifc_import_settings.collection_mode == "SPATIAL_DECOMPOSITION": + # TODO: refactor this to a more holistic collection mode feature + return self.place_object_in_spatial_tree(element.Decomposes[0].RelatingObject, obj) else: - collection = self.aggregates[element.Decomposes[0].RelatingObject.GlobalId]["blender"] + aggregate = element.Decomposes[0].RelatingObject + aggregate_data = self.aggregates.get(aggregate.GlobalId) + if not aggregate_data: + return self.place_object_in_spatial_tree(aggregate, obj) + collection = aggregate_data["blender"] if collection: collection.objects.link(obj) else: @@ -1472,6 +1483,7 @@ class IfcImportSettings: self.model_offset_coordinates = (0, 0, 0) self.ifc_import_filter = "NONE" self.ifc_selector = "" + self.collection_mode = "DECOMPOSITION" @staticmethod def factory(context, input_file, logger): diff --git a/src/ifcopenshell-python/ifcopenshell/util/attribute.py b/src/ifcopenshell-python/ifcopenshell/util/attribute.py index e874dff672..5d9ebbc0f0 100644 --- a/src/ifcopenshell-python/ifcopenshell/util/attribute.py +++ b/src/ifcopenshell-python/ifcopenshell/util/attribute.py @@ -3,7 +3,9 @@ def get_primitive_type(attribute_or_data_type): data_type = str(attribute_or_data_type.type_of_attribute()) else: data_type = str(attribute_or_data_type) - if data_type.find("