From 0d401c9272e0834e62e04f90d75eb4c8adecae32 Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Sat, 29 Jun 2024 17:04:27 +1000 Subject: [PATCH] Fix bug where migrating length units didn't change properties. Unit utility for checking attribute types now considers select types too Changing properties is very critical for IFC2X3 georeferencing which is stored in a pset. --- .../ifcopenshell/util/unit.py | 24 +++++++++++++++++-- .../test/util/test_unit.py | 10 ++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/src/ifcopenshell-python/ifcopenshell/util/unit.py b/src/ifcopenshell-python/ifcopenshell/util/unit.py index 475aca0f71..45905ca595 100644 --- a/src/ifcopenshell-python/ifcopenshell/util/unit.py +++ b/src/ifcopenshell-python/ifcopenshell/util/unit.py @@ -749,10 +749,23 @@ def format_length( def is_attr_type( content_type: ifcopenshell_wrapper.parameter_type, ifc_unit_type_name: str, + include_select_types: bool = True ) -> Union[ifcopenshell_wrapper.type_declaration, None]: cur_decl = content_type + + if include_select_types: + if hasattr(cur_decl, "select_list"): + for select_item in cur_decl.select_list(): + if is_attr_type(select_item, ifc_unit_type_name): + return select_item + while hasattr(cur_decl, "declared_type") is True: cur_decl = cur_decl.declared_type() + if include_select_types: + if hasattr(cur_decl, "select_list"): + for select_item in cur_decl.select_list(): + if is_attr_type(select_item, ifc_unit_type_name): + return select_item if hasattr(cur_decl, "name") is False: continue if cur_decl.name() == ifc_unit_type_name: @@ -800,6 +813,9 @@ def iter_element_and_attributes_per_type( if val is None: continue + if isinstance(val, ifcopenshell.entity_instance) and not val.is_a(attr_type_name): + continue + yield element, attr, val @@ -833,8 +849,12 @@ def convert_file_length_units(ifc_file: ifcopenshell.file, target_units: str = " # Traverse all elements and their nested attributes in the file and convert them for element, attr, val in iter_element_and_attributes_per_type(file_patched, "IfcLengthMeasure"): - new_value = convert_value(val) - setattr(element, attr.name(), new_value) + if isinstance(val, ifcopenshell.entity_instance): + new_value = convert_value(val.wrappedValue) + getattr(element, attr.name()).wrappedValue = new_value + else: + new_value = convert_value(val) + setattr(element, attr.name(), new_value) file_patched.remove(old_length) unit_assignment.Units = tuple([new_length, *unit_assignment.Units]) diff --git a/src/ifcopenshell-python/test/util/test_unit.py b/src/ifcopenshell-python/test/util/test_unit.py index 59b3c3371b..29a09fea5c 100644 --- a/src/ifcopenshell-python/test/util/test_unit.py +++ b/src/ifcopenshell-python/test/util/test_unit.py @@ -82,3 +82,13 @@ class TestFormatLength(test.bootstrap.IFC4): assert ( subject.format_length(25.23, 4, unit_system="imperial", input_unit="inch", output_unit="inch") == '25 1/4"' ) + + +class TestIsAttrType(test.bootstrap.IFC4): + def test_run(self): + schema = ifcopenshell.schema_by_name("IFC4") + declaration = schema.declaration_by_name("IfcPropertySingleValue") + nominal_value = declaration.attribute_by_index(2).type_of_attribute() + assert subject.is_attr_type(nominal_value, "IfcValue") + assert subject.is_attr_type(nominal_value, "IfcLengthMeasure") + assert not subject.is_attr_type(nominal_value, "IfcLengthMeasure", include_select_types=False)