From 871cd45f53a9cf3cf99b8abf225ec37b10d74952 Mon Sep 17 00:00:00 2001 From: Andrej730 Date: Fri, 6 Sep 2024 17:35:31 +0500 Subject: [PATCH] selector.set_element_value to support 'predefined_type' keyword See more details in https://community.osarch.org/discussion/comment/22134/#Comment_22134 --- .../ifcopenshell/util/selector.py | 38 ++++++++++++-- .../test/util/test_selector.py | 51 +++++++++++++++++++ 2 files changed, 86 insertions(+), 3 deletions(-) diff --git a/src/ifcopenshell-python/ifcopenshell/util/selector.py b/src/ifcopenshell-python/ifcopenshell/util/selector.py index dadcaa689e..824b7f1864 100644 --- a/src/ifcopenshell-python/ifcopenshell/util/selector.py +++ b/src/ifcopenshell-python/ifcopenshell/util/selector.py @@ -21,6 +21,7 @@ import lark import numpy as np import ifcopenshell.api.pset import ifcopenshell.api.geometry +import ifcopenshell.ifcopenshell_wrapper as W import ifcopenshell.util import ifcopenshell.util.attribute import ifcopenshell.util.fm @@ -508,9 +509,40 @@ def set_element_value( elif key == "id": return elif key == "predefined_type": - print( - f"WARNING. Assigning 'predefined_type' is not yet supported. Skipping value '{value}' for element: '{element}'." - ) + current_value = ifcopenshell.util.element.get_predefined_type(element) + if current_value == value: + return + + def set_predefined_type( + element: ifcopenshell.entity_instance, value: Union[str, None], *, is_type: bool + ) -> None: + predefined_type = element.PredefinedType + declaration = element.wrapped_data.declaration() + entity = declaration.as_entity() + enum_attr = next(attr for attr in entity.attributes() if attr.name() == "PredefinedType") + enum_items = ifcopenshell.util.attribute.get_enum_items(enum_attr) + + # USERDEFINED shouldn't occur here, if it does then it means + # then it was artificially added and PredefinedType is actually unset. + if value in (None, "NOTDEFINED", "USERDEFINED"): + element.PredefinedType = "NOTDEFINED" + setattr(element, "ElementType" if is_type else "ObjectType", None) + elif value in enum_items: + if predefined_type == value: + return + element.PredefinedType = value + return + + # Value not in PredefinedType enum items. + if predefined_type != "USERDEFINED": + element.PredefinedType = "USERDEFINED" + setattr(element, "ElementType" if is_type else "ObjectType", value) + return + + if element_type := ifcopenshell.util.element.get_type(element): + set_predefined_type(element_type, value, is_type=True) + return + set_predefined_type(element, value, is_type=False) return elif key == "classification": element = ifcopenshell.util.classification.get_references(element) diff --git a/src/ifcopenshell-python/test/util/test_selector.py b/src/ifcopenshell-python/test/util/test_selector.py index a20372a9d7..4cb29c0523 100644 --- a/src/ifcopenshell-python/test/util/test_selector.py +++ b/src/ifcopenshell-python/test/util/test_selector.py @@ -28,6 +28,7 @@ import ifcopenshell.api.material import ifcopenshell.api.geometry import ifcopenshell.api.aggregate import ifcopenshell.api.group +import ifcopenshell.api.sequence import ifcopenshell.util.selector as subject import ifcopenshell.util.placement import ifcopenshell.util.pset @@ -352,3 +353,53 @@ class TestSetElementValue(test.bootstrap.IFC4): layer.Material = material subject.set_element_value(self.file, layer, "Material.Name", "Foo") assert material.Name == "Foo" + + +class TestSetElementValuePredefinedType(test.bootstrap.IFC4): + def test_setting_an_element_predefined_type(self): + element = ifcopenshell.api.root.create_entity(self.file, ifc_class="IfcWindow") + subject.set_element_value(self.file, element, "predefined_type", "LIGHTDOME") + assert element.PredefinedType == "LIGHTDOME" + assert element.ObjectType == None + + def test_setting_an_element_predefined_type_to_none(self): + element = ifcopenshell.api.root.create_entity(self.file, ifc_class="IfcWindow") + subject.set_element_value(self.file, element, "predefined_type", None) + assert element.PredefinedType == None + assert element.ObjectType == None + + def test_setting_an_element_userdefined_type(self): + element = ifcopenshell.api.root.create_entity(self.file, ifc_class="IfcWindow") + subject.set_element_value(self.file, element, "predefined_type", "FOOBAR") + assert element.PredefinedType == "USERDEFINED" + assert element.ObjectType == "FOOBAR" + + def test_setting_an_element_inherited_predefined_type(self): + element = ifcopenshell.api.root.create_entity(self.file, ifc_class="IfcWindow") + element_type = ifcopenshell.api.root.create_entity(self.file, ifc_class="IfcWindowType") + ifcopenshell.api.type.assign_type(self.file, related_objects=[element], relating_type=element_type) + subject.set_element_value(self.file, element, "predefined_type", "LIGHTDOME") + assert element_type.PredefinedType == "LIGHTDOME" + assert element_type.ElementType == None + assert element.PredefinedType == None + assert element.ObjectType == None + + def test_setting_an_element_inherited_predefined_type_to_none(self): + element = ifcopenshell.api.root.create_entity(self.file, ifc_class="IfcWindow") + element_type = ifcopenshell.api.root.create_entity(self.file, ifc_class="IfcWindowType") + ifcopenshell.api.type.assign_type(self.file, related_objects=[element], relating_type=element_type) + subject.set_element_value(self.file, element, "predefined_type", None) + assert element_type.PredefinedType == "NOTDEFINED" + assert element_type.ElementType == None + assert element.PredefinedType == None + assert element.ObjectType == None + + def test_setting_an_element_inherited_userdefined_type(self): + element = ifcopenshell.api.root.create_entity(self.file, ifc_class="IfcWindow") + element_type = ifcopenshell.api.root.create_entity(self.file, ifc_class="IfcWindowType") + ifcopenshell.api.type.assign_type(self.file, related_objects=[element], relating_type=element_type) + subject.set_element_value(self.file, element, "predefined_type", "FOOBAR") + assert element_type.PredefinedType == "USERDEFINED" + assert element_type.ElementType == "FOOBAR" + assert element.PredefinedType == None + assert element.ObjectType == None