diff --git a/src/bonsai/bonsai/bim/import_ifc.py b/src/bonsai/bonsai/bim/import_ifc.py index 0893ce404f..8747f28891 100644 --- a/src/bonsai/bonsai/bim/import_ifc.py +++ b/src/bonsai/bonsai/bim/import_ifc.py @@ -300,7 +300,6 @@ class IfcImporter: tool.Spatial.run_spatial_import_spatial_decomposition() if default_container := tool.Spatial.guess_default_container(): tool.Spatial.set_default_container(default_container) - tool.Loader.setup_active_bsdd_classification() self.update_progress(100) bpy.context.window_manager.progress_end() diff --git a/src/bonsai/bonsai/tool/bsdd.py b/src/bonsai/bonsai/tool/bsdd.py index d455a6f21f..bb5a79e1c6 100644 --- a/src/bonsai/bonsai/tool/bsdd.py +++ b/src/bonsai/bonsai/tool/bsdd.py @@ -3,6 +3,8 @@ import bonsai.tool as tool import bpy import json import bsdd +import ifcopenshell.util.type +import ifcopenshell.util.element from typing import Any, Union, Optional, TYPE_CHECKING @@ -131,9 +133,17 @@ class Bsdd(bonsai.core.tool.Bsdd): active_object = bpy.context.active_object related_ifc_entities = [] if cls.should_filter_ifc_class() and active_object: - element = tool.Ifc.get_entity(active_object) - if element: - related_ifc_entities = [element.is_a()] + if element := tool.Ifc.get_entity(active_object): + ifc_class = element.is_a() + if element.is_a("IfcElementType"): + ifc_class = ifcopenshell.util.type.get_applicable_entities(ifc_class, schema=tool.Ifc.get().schema)[ + 0 + ] + related_ifc_entities = [ifc_class] + if ( + predefined_type := ifcopenshell.util.element.get_predefined_type(element) + ) and predefined_type != "NOTDEFINED": + related_ifc_entities.append(ifc_class + predefined_type) return related_ifc_entities @classmethod @@ -152,23 +162,24 @@ class Bsdd(bonsai.core.tool.Bsdd): else [props.active_dictionary] ) for dictionary_uri in dictionary_uris: - response = cls.client.get_classes( - dictionary_uri=dictionary_uri, - use_nested_classes=False, - search_text=keyword, - related_ifc_entity=related_ifc_entities[0] if related_ifc_entities else None, - offset=offset, - limit=limit, - ) - dictionary_name = response.get("name", "") - dictionary_namespace_uri = response.get("uri", "") - for _class in sorted(response.get("classes", []), key=lambda c: c["referenceCode"]): - prop = props.classifications.add() - prop.name = _class["name"] - prop.reference_code = _class["referenceCode"] - prop.uri = _class["uri"] - prop.dictionary_name = dictionary_name - prop.dictionary_namespace_uri = dictionary_namespace_uri + for related_ifc_entity in related_ifc_entities or [None]: + response = cls.client.get_classes( + dictionary_uri=dictionary_uri, + use_nested_classes=False, + search_text=keyword, + related_ifc_entity=related_ifc_entity, + offset=offset, + limit=limit, + ) + dictionary_name = response.get("name", "") + dictionary_namespace_uri = response.get("uri", "") + for _class in sorted(response.get("classes", []), key=lambda c: c["referenceCode"]): + prop = props.classifications.add() + prop.name = _class["name"] + prop.reference_code = _class["referenceCode"] + prop.uri = _class["uri"] + prop.dictionary_name = dictionary_name + prop.dictionary_namespace_uri = dictionary_namespace_uri total_results = response.get("count", response.get("classesCount")) # For now, hard limit at 1000 results because any more and Blender diff --git a/src/bonsai/bonsai/tool/loader.py b/src/bonsai/bonsai/tool/loader.py index 7beb590fda..0f3b97c5ea 100644 --- a/src/bonsai/bonsai/tool/loader.py +++ b/src/bonsai/bonsai/tool/loader.py @@ -1171,47 +1171,6 @@ class Loader(bonsai.core.tool.Loader): return mesh - @classmethod - def setup_active_bsdd_classification(cls) -> None: - ifc_file = tool.Ifc.get() - schema = ifc_file.schema - - # In IFC2X3 IfcClassification doesn't have an attribute for uri. - if schema == "IFC2X3": - classifications = [c for c in ifc_file.by_type("IfcClassification") if c.Name] - if not classifications: - return - pattern = r"^https://identifier\.buildingsmart\.org/uri/([a-zA-Z0-9]+)/([a-zA-Z0-9]+)/([0-9]+\.[0-9]+)" - - # No inverse attribute in IFC2X3... - for ref in ifc_file.by_type("IfcClassificationReference"): - if ( - not (uri := ref.Location) - or not uri.startswith("https://identifier.buildingsmart.org/uri/") - or not (pattern_match := re.match(pattern, uri)) - or not (classification := ref.ReferencedSource) - or classification not in classifications - or not classification.is_a("IfcClassification") - ): - continue - tool.Bsdd.set_active_bsdd(classification.Name, pattern_match.group(0)) - return - - attr_name = "Specification" if schema == "IFC4X3" else "Location" - bsdd_classification, uri, name = None, None, None - for c in ifc_file.by_type("IfcClassification"): - if ( - (uri := getattr(c, attr_name)) - and uri.startswith("https://identifier.buildingsmart.org/uri/") - and (name := c.Name) - ): - bsdd_classification = c - break - if not bsdd_classification: - return - assert name and uri - tool.Bsdd.set_active_bsdd(name, uri) - @classmethod def is_native_swept_disk_solid( cls, element: ifcopenshell.entity_instance, representation: ifcopenshell.entity_instance