From 778a839e5f2085fae9105f052c878675c0965414 Mon Sep 17 00:00:00 2001 From: Andrej730 Date: Mon, 17 Mar 2025 16:33:32 +0500 Subject: [PATCH] get_shape_aspects to consider element's type #6374 See diagram in https://github.com/IfcOpenShell/IfcOpenShell/issues/5839#issuecomment-2661296683 when IfcShapeAspect assigned to IfcRepresentationMap instead of being assigned to IfcProductDefinitionShape directly. --- .../ifcopenshell/util/element.py | 14 ++++++++++++-- .../test/util/test_element.py | 19 +++++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/ifcopenshell-python/ifcopenshell/util/element.py b/src/ifcopenshell-python/ifcopenshell/util/element.py index 3f9dc7e40f..85cc192ceb 100644 --- a/src/ifcopenshell-python/ifcopenshell/util/element.py +++ b/src/ifcopenshell-python/ifcopenshell/util/element.py @@ -591,10 +591,16 @@ def get_types(type: ifcopenshell.entity_instance) -> list[ifcopenshell.entity_in return [] -def get_shape_aspects(element: ifcopenshell.entity_instance) -> list[ifcopenshell.entity_instance]: +def get_shape_aspects( + element: ifcopenshell.entity_instance, + should_inherit: bool = True, +) -> list[ifcopenshell.entity_instance]: """Get element's shape aspects. :param element: IfcProduct or IfcTypeProduct. + :param should_inherit: If True, the shape aspects of the element's type will be considered. + Useful in cases when IfcShapeAspects are assigned to the type's IfcRepresentationMap + instead of the element's IfcProductDefinitionShape. :return: The associated shape aspects of the element. Example: @@ -607,7 +613,11 @@ def get_shape_aspects(element: ifcopenshell.entity_instance) -> list[ifcopenshel # IfcProduct if (representation := getattr(element, "Representation", ...)) != ...: - return representation.HasShapeAspects + shape_aspects: list[ifcopenshell.entity_instance] = [] + if should_inherit and (element_type := get_type(element)): + shape_aspects.extend(get_shape_aspects(element_type)) + shape_aspects.extend(representation.HasShapeAspects) + return shape_aspects if element.file.schema == "IFC2X3": return [] diff --git a/src/ifcopenshell-python/test/util/test_element.py b/src/ifcopenshell-python/test/util/test_element.py index f40cb295da..54e4db0c58 100644 --- a/src/ifcopenshell-python/test/util/test_element.py +++ b/src/ifcopenshell-python/test/util/test_element.py @@ -387,6 +387,25 @@ class TestGetShapeAspects(test.bootstrap.IFC4): shape_aspect.PartOfProductDefinitionShape = product_shape assert tuple(subject.get_shape_aspects(element)) == (shape_aspect,) + def test_getting_the_shape_aspects_of_a_product_with_inheritance(self): + element = ifcopenshell.api.root.create_entity(self.file, ifc_class="IfcWall") + element_type = ifcopenshell.api.root.create_entity(self.file, ifc_class="IfcWallType") + ifcopenshell.api.type.assign_type(self.file, related_objects=[element], relating_type=element_type) + + # Setup type shape aspect. + type_shape_aspect = self.file.create_entity("IfcShapeAspect") + representation_map = self.file.create_entity("IfcRepresentationMap") + element_type.RepresentationMaps = (representation_map,) + type_shape_aspect.PartOfProductDefinitionShape = representation_map + + # Setup occurrence shape aspect. + occurrence_shape_aspect = self.file.create_entity("IfcShapeAspect") + product_shape = self.file.create_entity("IfcProductDefinitionShape") + element.Representation = product_shape + occurrence_shape_aspect.PartOfProductDefinitionShape = product_shape + + assert subject.get_shape_aspects(element) == [type_shape_aspect, occurrence_shape_aspect] + class TestGetMaterial(test.bootstrap.IFC4): def test_getting_the_material_of_a_product(self):