diff --git a/src/ifcopenshell-python/ifcopenshell/util/element.py b/src/ifcopenshell-python/ifcopenshell/util/element.py index bc2e28bc55..b4d90ce464 100644 --- a/src/ifcopenshell-python/ifcopenshell/util/element.py +++ b/src/ifcopenshell-python/ifcopenshell/util/element.py @@ -808,6 +808,35 @@ def get_elements_by_representation( return results +def get_elements_by_profile(profile: ifcopenshell.entity_instance) -> set[ifcopenshell.entity_instance]: + """Get all elements using provided IfcProfileDef. + + Skip elements that have the profile in IfcMaterialProfileSet + but not actually use it in their representations. + + :param profile: IfcProfileDef: + :return: The elements using the profile. + """ + ifc_file = profile.file + queue = ifc_file.get_inverse(profile) + processed: set[ifcopenshell.entity_instance] = set() + representations: set[ifcopenshell.entity_instance] = set() + while queue: + item = queue.pop() + if item.is_a("IfcRepresentationItem"): + queue.update(i for i in ifc_file.get_inverse(item) if i not in processed) + elif item.is_a("IfcShapeRepresentation"): + representations.add(item) + else: + pass + processed.add(item) + + elements = set() + for representation in representations: + elements.update(get_elements_by_representation(ifc_file, representation)) + return elements + + def get_elements_by_layer( ifc_file: ifcopenshell.file, layer: ifcopenshell.entity_instance ) -> set[ifcopenshell.entity_instance]: diff --git a/src/ifcopenshell-python/test/util/test_element.py b/src/ifcopenshell-python/test/util/test_element.py index 17e244738d..62cca30d31 100644 --- a/src/ifcopenshell-python/test/util/test_element.py +++ b/src/ifcopenshell-python/test/util/test_element.py @@ -38,6 +38,7 @@ import ifcopenshell.api.aggregate import ifcopenshell.api.group import ifcopenshell.guid import ifcopenshell.util.element as subject +from ifcopenshell.util.shape_builder import ShapeBuilder class TestGetPsetIFC4(test.bootstrap.IFC4): @@ -708,6 +709,18 @@ class TestGetElementsByRepresentation(test.bootstrap.IFC4): assert subject.get_elements_by_representation(self.file, representation) == {element} +class TestGetElementsByProfile(test.bootstrap.IFC4): + def test_getting_elements_by_profile(self): + builder = ShapeBuilder(self.file) + self.file.create_entity("IfcProject") # add_context. + element = self.file.create_entity("IfcWall") + model = ifcopenshell.api.context.add_context(self.file, context_type="Model") + extrusion = builder.extrude(profile := builder.profile(builder.rectangle())) + representation = builder.get_representation(model, items=[extrusion]) + ifcopenshell.api.geometry.assign_representation(self.file, element, representation) + assert subject.get_elements_by_profile(profile) == {element} + + class TestGetElementsByLayer(test.bootstrap.IFC4): def test_getting_the_elements_of_a_layer(self): element = ifcopenshell.api.root.create_entity(self.file, ifc_class="IfcWall")