From 1516237537ead2e502574787997dac9e749a151b Mon Sep 17 00:00:00 2001 From: Andrej730 Date: Mon, 14 Apr 2025 17:14:00 +0500 Subject: [PATCH] Allow Undefined topology representations for IfcStructuralPointConnection #6459 Because apparently it's not invalid IFC. IfcStructuralPointConnection documentation says that they should have a topology representation with a IfcVertexPoint but it doesn't restict this representation from having Undefined type if it does have a IfcVertexPoint as it's item. --- src/bonsai/bonsai/bim/import_ifc.py | 12 ++++++--- src/bonsai/bonsai/tool/loader.py | 1 + src/bonsai/bonsai/tool/structural.py | 39 ++++++++++++++++++++++++++++ 3 files changed, 49 insertions(+), 3 deletions(-) diff --git a/src/bonsai/bonsai/bim/import_ifc.py b/src/bonsai/bonsai/bim/import_ifc.py index 903f0ca6a3..671c81958a 100644 --- a/src/bonsai/bonsai/bim/import_ifc.py +++ b/src/bonsai/bonsai/bim/import_ifc.py @@ -717,9 +717,15 @@ class IfcImporter: def create_structural_point_connections(self): for product in self.file.by_type("IfcStructuralPointConnection"): # TODO: make this based off ifcopenshell. See #1409 - representation: ifcopenshell.entity_instance = next( - rep for rep in product.Representation.Representations if rep.RepresentationType == "Vertex" - ) + + representation = tool.Structural.get_vertex_representation(product) + if not representation: + print( + "WARNING. Skipping invalid IfcStructuralPointConnection - " + f"element has no valid representation:\n{product}." + ) + continue + mesh = tool.Loader.create_structural_point_connection_mesh(representation) if mesh is None: continue diff --git a/src/bonsai/bonsai/tool/loader.py b/src/bonsai/bonsai/tool/loader.py index 0e8dee0305..a8b2fa77f7 100644 --- a/src/bonsai/bonsai/tool/loader.py +++ b/src/bonsai/bonsai/tool/loader.py @@ -799,6 +799,7 @@ class Loader(bonsai.core.tool.Loader): # TODO implement non cartesian point vertices. if not point.is_a("IfcCartesianPoint"): + print(f"WARNING. Unsupported point type for IfcStructuralPointConnection: {point}.") return ifc_file = tool.Ifc.get() diff --git a/src/bonsai/bonsai/tool/structural.py b/src/bonsai/bonsai/tool/structural.py index 54c73ca537..68ff8448f9 100644 --- a/src/bonsai/bonsai/tool/structural.py +++ b/src/bonsai/bonsai/tool/structural.py @@ -172,3 +172,42 @@ class Structural(bonsai.core.tool.Structural): new = props.structural_analysis_models.add() new.ifc_definition_id = ifc_definition_id new.name = model["Name"] or "Unnamed" + + @classmethod + def get_vertex_representation( + cls, product: ifcopenshell.entity_instance + ) -> Union[ifcopenshell.entity_instance, None]: + """ + :param product: IfcStructuralPointConnection + :return: IfcTopologyRepresentation if it's valid. + """ + vertex_representation, undefined_representation = None, None + # At least 1 representation is mandatory in IFC for IfcStructuralPointConnection. + for rep in product.Representation.Representations: + rep: ifcopenshell.entity_instance + rep_type: str = rep.RepresentationType + if rep_type == "Vertex": + vertex_representation = rep + break + # It's possible to have 'Undefined' or some other non-predefined type. + elif rep_type not in ("Edge", "Path", "Face", "Shell"): + undefined_representation = rep + + if not vertex_representation and not undefined_representation: + return + + # All other checks in this case are covered by IFC validation. + if vertex_representation: + items = vertex_representation.Items + if len(items) != 1: + return None + return vertex_representation + + if undefined_representation is None: + return + + items = undefined_representation.Items + if len(items) != 1 or not all(item.is_a("IfcVertex") for item in items): + return None + + return undefined_representation