diff --git a/src/ifcopenshell-python/ifcopenshell/util/schema.py b/src/ifcopenshell-python/ifcopenshell/util/schema.py index fdae211b44..2587bb0dd1 100644 --- a/src/ifcopenshell-python/ifcopenshell/util/schema.py +++ b/src/ifcopenshell-python/ifcopenshell/util/schema.py @@ -364,15 +364,21 @@ class Migrator: def migrate_class( self, element: ifcopenshell.entity_instance, new_file: ifcopenshell.file ) -> ifcopenshell.entity_instance: + ifc_class = element.is_a() + if ifc_class == "IfcQuantityCount" and new_file.schema == "IFC4X3": + # 3 IfcPhysicalSimpleQuantity Value + value = element[3] + if isinstance(value, float): + ifc_class = "IfcQuantityNumber" try: - new_element = new_file.create_entity(element.is_a()) + new_element = new_file.create_entity(ifc_class) except: # The element does not exist in this schema # Complex migration is not yet supported (e.g. polygonal face set to faceted brep) if new_file.schema == "IFC2X3": - new_element = new_file.create_entity(self.class_4_to_2x3[element.is_a()]) + new_element = new_file.create_entity(self.class_4_to_2x3[ifc_class]) elif new_file.schema == "IFC4": - new_element = new_file.create_entity(self.class_2x3_to_4[element.is_a()]) + new_element = new_file.create_entity(self.class_2x3_to_4[ifc_class]) return new_element def migrate_attributes(self, element, new_file, new_element, new_element_schema): @@ -393,21 +399,32 @@ class Migrator: reverse_mapping: bool = False, ) -> Union[Any, None]: # print("Searching for an equivalent", element, new_element, attribute.name()) + ifc_class = new_element.is_a() + attr_name = attribute.name() try: if reverse_mapping: - equivalent_map = attributes_mapping[new_element.is_a()] - equivalent = list(equivalent_map.keys())[list(equivalent_map.values()).index(attribute.name())] + equivalent_map = attributes_mapping[ifc_class] + equivalent = list(equivalent_map.keys())[list(equivalent_map.values()).index(attr_name)] else: - equivalent = attributes_mapping[new_element.is_a()][attribute.name()] + equivalent = attributes_mapping[ifc_class][attr_name] if hasattr(element, equivalent): # print("Equivalent found", equivalent) return getattr(element, equivalent) else: return except Exception as e: + if ( + ifc_class == "IfcQuantityNumber" + and attr_name == "NumberValue" + and new_element.file.schema == "IFC4X3" + and element.is_a("IfcQuantityCount") + ): + # 3 IfcPhysicalSimpleQuantity Value + return element[3] + print( "Unable to find equivalent attribute of {} to migrate from {} to {}".format( - attribute.name(), element, new_element + attr_name, element, new_element ) ) raise e diff --git a/src/ifcopenshell-python/test/util/test_schema.py b/src/ifcopenshell-python/test/util/test_schema.py index d814ecf7b5..071ffb8cea 100644 --- a/src/ifcopenshell-python/test/util/test_schema.py +++ b/src/ifcopenshell-python/test/util/test_schema.py @@ -71,3 +71,50 @@ class TestMigrator(test.bootstrap.IFC4): new_element = ifc2x3_file.by_type(original_element.is_a())[0] assert original_element.Mode == new_element.TextureType + + def test_migrate_ifccountmeasure_to_ifc4x3(self): + ifc_str = """ +ISO-10303-21; +HEADER; +FILE_DESCRIPTION(('ViewDefinition[DesignTransferView]'),'2;1'); +FILE_NAME('count.ifc','2024-11-18T12:44:20+05:00',(''),(''),'','','Nobody'); +FILE_SCHEMA(('IFC4')); +ENDSEC; +DATA; +#1=IFCPROPERTYSINGLEVALUE('PropCountInt',$,IFCCOUNTMEASURE(232),$); +#2=IFCPROPERTYSINGLEVALUE('PropCountFloat',$,IFCCOUNTMEASURE(232.),$); +#3=IFCQUANTITYCOUNT('QuantityCountInt',$,$,723,$); +#4=IFCQUANTITYCOUNT('QuantityCountFloat',$,$,723.,$); +ENDSEC; +END-ISO-10303-21; +""" + ifc4_file = ifcopenshell.file.from_string(ifc_str) + ifc4x3_file = ifcopenshell.api.project.create_file(version="IFC4X3") + + migrator = subject.Migrator() + + prop_int_count_measure = ifc4_file.by_id(1) + prop_int_count_measure_ifc4x3 = migrator.migrate(prop_int_count_measure, ifc4x3_file) + value = prop_int_count_measure_ifc4x3.NominalValue + assert value.is_a("IfcCountMeasure") + assert isinstance(value.wrappedValue, int) + assert value.wrappedValue == 232 + + float_count_measure = ifc4_file.by_id(2) + float_count_measure_ifc4x3 = migrator.migrate(float_count_measure, ifc4x3_file) + value = float_count_measure_ifc4x3.NominalValue + assert value.is_a("IfcNumericMeasure") + assert isinstance(value.wrappedValue, float) + assert value.wrappedValue == 232.0 + + qt_int_count_measure = ifc4_file.by_id(3) + qt_int_count_measure_ifc4x3 = migrator.migrate(qt_int_count_measure, ifc4x3_file) + assert qt_int_count_measure_ifc4x3.is_a("IfcQuantityCount") + assert isinstance(qt_int_count_measure_ifc4x3[3], int) + assert qt_int_count_measure_ifc4x3[3] == 723 + + qt_float_count_measure = ifc4_file.by_id(4) + qt_float_count_measure_ifc4x3 = migrator.migrate(qt_float_count_measure, ifc4x3_file) + assert qt_float_count_measure_ifc4x3.is_a("IfcQuantityNumber") + assert isinstance(qt_float_count_measure_ifc4x3[3], float) + assert qt_float_count_measure_ifc4x3[3] == 723.0