bSDD searches now work on type classes as well as predefined types

This commit is contained in:
Dion Moult
2025-05-26 16:34:25 +10:00
parent 320a4cf4fa
commit 8766cad37e
3 changed files with 31 additions and 62 deletions
-1
View File
@@ -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()
+31 -20
View File
@@ -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
-41
View File
@@ -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