diff --git a/src/bonsai/test/core/test_unit.py b/src/bonsai/test/core/test_unit.py index d758b7829c..00ffe1dd5e 100644 --- a/src/bonsai/test/core/test_unit.py +++ b/src/bonsai/test/core/test_unit.py @@ -32,45 +32,78 @@ class TestAssignSceneUnits: ifc.run("unit.add_si_unit", unit_type="LENGTHUNIT", prefix="prefix").should_be_called().will_return( "lengthunit" ) - ifc.run("unit.add_si_unit", unit_type="AREAUNIT", prefix="prefix").should_be_called().will_return("areaunit") - ifc.run("unit.add_si_unit", unit_type="VOLUMEUNIT", prefix="prefix").should_be_called().will_return( "volumeunit" ) - + ifc.run("unit.add_si_unit", unit_type="MASSUNIT", prefix="KILO").should_be_called().will_return("massunit") + ifc.run("unit.add_si_unit", unit_type="TIMEUNIT", prefix=None).should_be_called().will_return("timeunit") ifc.run("unit.add_conversion_based_unit", name="degree").should_be_called().will_return("planeangleunit") - ifc.run("unit.add_si_unit", unit_type="MASSUNIT", prefix="KILO").should_be_called().will_return("massunit") - - ifc.run("unit.add_si_unit", unit_type="TIMEUNIT", prefix=None).should_be_called().will_return("timeunit") - ifc.run( - "unit.assign_unit", units=["lengthunit", "areaunit", "volumeunit", "planeangleunit", "massunit", "timeunit"] + "unit.assign_unit", units=["lengthunit", "areaunit", "volumeunit", "massunit", "timeunit", "planeangleunit"] ).should_be_called() subject.assign_scene_units(ifc, unit) def test_creating_and_assigning_imperial_units(self, ifc, unit): unit.is_scene_unit_metric().should_be_called().will_return(False) - unit.get_scene_unit_name("LENGTHUNIT").should_be_called().will_return("lengthname") - ifc.run("unit.add_conversion_based_unit", name="lengthname").should_be_called().will_return("lengthunit") - - unit.get_scene_unit_name("AREAUNIT").should_be_called().will_return("areaname") - ifc.run("unit.add_conversion_based_unit", name="areaname").should_be_called().will_return("areaunit") - - unit.get_scene_unit_name("VOLUMEUNIT").should_be_called().will_return("volumename") - ifc.run("unit.add_conversion_based_unit", name="volumename").should_be_called().will_return("volumeunit") + unit.get_scene_unit_name("LENGTHUNIT").should_be_called().will_return("foot") + unit.get_scene_unit_name("AREAUNIT").should_be_called().will_return("square foot") + unit.get_scene_unit_name("VOLUMEUNIT").should_be_called().will_return("cubic foot") + unit.get_scene_unit_name("MASSUNIT").should_be_called().will_return("pound") + unit.get_scene_unit_name("TIMEUNIT").should_be_called().will_return("SECOND") + ifc.run("unit.add_conversion_based_unit", name="foot").should_be_called().will_return("lengthunit") + ifc.run("unit.add_conversion_based_unit", name="square foot").should_be_called().will_return("areaunit") + ifc.run("unit.add_conversion_based_unit", name="cubic foot").should_be_called().will_return("volumeunit") + ifc.run("unit.add_conversion_based_unit", name="pound").should_be_called().will_return("massunit") + ifc.run("unit.add_si_unit", unit_type="TIMEUNIT", prefix=None).should_be_called().will_return("timeunit") ifc.run("unit.add_conversion_based_unit", name="degree").should_be_called().will_return("planeangleunit") - unit.get_scene_unit_name("MASSUNIT").should_be_called().will_return("massname") - ifc.run("unit.add_conversion_based_unit", name="massname").should_be_called().will_return("massunit") + ifc.run( + "unit.assign_unit", units=["lengthunit", "areaunit", "volumeunit", "massunit", "timeunit", "planeangleunit"] + ).should_be_called() + subject.assign_scene_units(ifc, unit) - unit.get_scene_unit_name("TIMEUNIT").should_be_called().will_return("timename") - ifc.run("unit.add_conversion_based_unit", name="timename").should_be_called().will_return("timeunit") + def test_creating_metric_units_with_conversion_based_mass_and_time(self, ifc, unit): + unit.is_scene_unit_metric().should_be_called().will_return(True) + unit.get_scene_unit_si_prefix("LENGTHUNIT").should_be_called().will_return("MILLI") + unit.get_scene_unit_si_prefix("AREAUNIT").should_be_called().will_return(None) + unit.get_scene_unit_si_prefix("VOLUMEUNIT").should_be_called().will_return(None) + unit.get_scene_unit_si_prefix("MASSUNIT").should_be_called().will_return("CONVERSION") + unit.get_scene_unit_name("MASSUNIT").should_be_called().will_return("tonne") + unit.get_scene_unit_si_prefix("TIMEUNIT").should_be_called().will_return("CONVERSION") + unit.get_scene_unit_name("TIMEUNIT").should_be_called().will_return("minute") + + ifc.run("unit.add_si_unit", unit_type="LENGTHUNIT", prefix="MILLI").should_be_called().will_return("lengthunit") + ifc.run("unit.add_si_unit", unit_type="AREAUNIT", prefix=None).should_be_called().will_return("areaunit") + ifc.run("unit.add_si_unit", unit_type="VOLUMEUNIT", prefix=None).should_be_called().will_return("volumeunit") + ifc.run("unit.add_conversion_based_unit", name="tonne").should_be_called().will_return("massunit") + ifc.run("unit.add_conversion_based_unit", name="minute").should_be_called().will_return("timeunit") + ifc.run("unit.add_conversion_based_unit", name="degree").should_be_called().will_return("planeangleunit") ifc.run( - "unit.assign_unit", units=["lengthunit", "areaunit", "volumeunit", "planeangleunit", "massunit", "timeunit"] + "unit.assign_unit", units=["lengthunit", "areaunit", "volumeunit", "massunit", "timeunit", "planeangleunit"] + ).should_be_called() + subject.assign_scene_units(ifc, unit) + + def test_creating_imperial_units_with_conversion_based_units(self, ifc, unit): + unit.is_scene_unit_metric().should_be_called().will_return(False) + unit.get_scene_unit_name("LENGTHUNIT").should_be_called().will_return("inch") + unit.get_scene_unit_name("AREAUNIT").should_be_called().will_return("square inch") + unit.get_scene_unit_name("VOLUMEUNIT").should_be_called().will_return("cubic inch") + unit.get_scene_unit_name("MASSUNIT").should_be_called().will_return("ounce") + unit.get_scene_unit_name("TIMEUNIT").should_be_called().will_return("hour") + + ifc.run("unit.add_conversion_based_unit", name="inch").should_be_called().will_return("lengthunit") + ifc.run("unit.add_conversion_based_unit", name="square inch").should_be_called().will_return("areaunit") + ifc.run("unit.add_conversion_based_unit", name="cubic inch").should_be_called().will_return("volumeunit") + ifc.run("unit.add_conversion_based_unit", name="ounce").should_be_called().will_return("massunit") + ifc.run("unit.add_conversion_based_unit", name="hour").should_be_called().will_return("timeunit") + ifc.run("unit.add_conversion_based_unit", name="degree").should_be_called().will_return("planeangleunit") + + ifc.run( + "unit.assign_unit", units=["lengthunit", "areaunit", "volumeunit", "massunit", "timeunit", "planeangleunit"] ).should_be_called() subject.assign_scene_units(ifc, unit) @@ -179,137 +212,3 @@ class TestEditUnit: unit.import_units().should_be_called() unit.clear_active_unit().should_be_called() subject.edit_unit(ifc, unit, unit="unit") - - -class TestAssignSceneUnitsWithMassAndTime: - def test_creating_and_assigning_metric_units_with_mass_and_time(self, ifc, unit): - unit.is_scene_unit_metric().should_be_called().will_return(True) - unit.get_scene_unit_si_prefix("LENGTHUNIT").should_be_called().will_return("prefix") - unit.get_scene_unit_si_prefix("AREAUNIT").should_be_called().will_return("prefix") - unit.get_scene_unit_si_prefix("VOLUMEUNIT").should_be_called().will_return("prefix") - unit.get_scene_unit_si_prefix("MASSUNIT").should_be_called().will_return("KILO") - unit.get_scene_unit_si_prefix("TIMEUNIT").should_be_called().will_return("CONVERSION") - unit.get_scene_unit_name("TIMEUNIT").should_be_called().will_return("minute") - - ifc.run("unit.add_si_unit", unit_type="LENGTHUNIT", prefix="prefix").should_be_called().will_return( - "lengthunit" - ) - ifc.run("unit.add_si_unit", unit_type="AREAUNIT", prefix="prefix").should_be_called().will_return("areaunit") - ifc.run("unit.add_si_unit", unit_type="VOLUMEUNIT", prefix="prefix").should_be_called().will_return( - "volumeunit" - ) - ifc.run("unit.add_si_unit", unit_type="MASSUNIT", prefix="KILO").should_be_called().will_return("massunit") - ifc.run("unit.add_conversion_based_unit", name="minute").should_be_called().will_return("timeunit") - ifc.run("unit.add_conversion_based_unit", name="degree").should_be_called().will_return("planeangleunit") - - ifc.run( - "unit.assign_unit", units=["lengthunit", "areaunit", "volumeunit", "planeangleunit", "massunit", "timeunit"] - ).should_be_called() - subject.assign_scene_units(ifc, unit) - - def test_creating_and_assigning_imperial_units_with_mass_and_time(self, ifc, unit): - unit.is_scene_unit_metric().should_be_called().will_return(False) - unit.get_scene_unit_name("LENGTHUNIT").should_be_called().will_return("foot") - unit.get_scene_unit_name("AREAUNIT").should_be_called().will_return("square foot") - unit.get_scene_unit_name("VOLUMEUNIT").should_be_called().will_return("cubic foot") - unit.get_scene_unit_name("MASSUNIT").should_be_called().will_return("pound") - unit.get_scene_unit_name("TIMEUNIT").should_be_called().will_return("SECOND") - - ifc.run("unit.add_conversion_based_unit", name="foot").should_be_called().will_return("lengthunit") - ifc.run("unit.add_conversion_based_unit", name="square foot").should_be_called().will_return("areaunit") - ifc.run("unit.add_conversion_based_unit", name="cubic foot").should_be_called().will_return("volumeunit") - ifc.run("unit.add_conversion_based_unit", name="pound").should_be_called().will_return("massunit") - ifc.run("unit.add_si_unit", unit_type="TIMEUNIT", prefix=None).should_be_called().will_return("timeunit") - ifc.run("unit.add_conversion_based_unit", name="degree").should_be_called().will_return("planeangleunit") - - ifc.run( - "unit.assign_unit", units=["lengthunit", "areaunit", "volumeunit", "planeangleunit", "massunit", "timeunit"] - ).should_be_called() - subject.assign_scene_units(ifc, unit) - - def test_creating_and_assigning_conversion_based_mass_units(self, ifc, unit): - unit.is_scene_unit_metric().should_be_called().will_return(False) - unit.get_scene_unit_name("LENGTHUNIT").should_be_called().will_return("foot") - unit.get_scene_unit_name("AREAUNIT").should_be_called().will_return("square foot") - unit.get_scene_unit_name("VOLUMEUNIT").should_be_called().will_return("cubic foot") - unit.get_scene_unit_name("MASSUNIT").should_be_called().will_return("tonne") - unit.get_scene_unit_name("TIMEUNIT").should_be_called().will_return("minute") - - ifc.run("unit.add_conversion_based_unit", name="foot").should_be_called().will_return("lengthunit") - ifc.run("unit.add_conversion_based_unit", name="square foot").should_be_called().will_return("areaunit") - ifc.run("unit.add_conversion_based_unit", name="cubic foot").should_be_called().will_return("volumeunit") - ifc.run("unit.add_conversion_based_unit", name="tonne").should_be_called().will_return("massunit") - ifc.run("unit.add_conversion_based_unit", name="minute").should_be_called().will_return("timeunit") - ifc.run("unit.add_conversion_based_unit", name="degree").should_be_called().will_return("planeangleunit") - - ifc.run( - "unit.assign_unit", units=["lengthunit", "areaunit", "volumeunit", "planeangleunit", "massunit", "timeunit"] - ).should_be_called() - subject.assign_scene_units(ifc, unit) - - -class TestAddTimeUnit: - def test_adding_si_time_unit(self, ifc, unit): - ifc.run("unit.add_si_unit", unit_type="TIMEUNIT").should_be_called().will_return("unit") - unit.import_units().should_be_called() - assert subject.add_si_unit(ifc, unit, unit_type="TIMEUNIT") == "unit" - - def test_adding_conversion_based_time_unit_minute(self, ifc, unit): - ifc.run("unit.add_conversion_based_unit", name="minute").should_be_called().will_return("unit") - unit.import_units().should_be_called() - assert subject.add_conversion_based_unit(ifc, unit, name="minute") == "unit" - - def test_adding_conversion_based_time_unit_hour(self, ifc, unit): - ifc.run("unit.add_conversion_based_unit", name="hour").should_be_called().will_return("unit") - unit.import_units().should_be_called() - assert subject.add_conversion_based_unit(ifc, unit, name="hour") == "unit" - - def test_adding_conversion_based_time_unit_day(self, ifc, unit): - ifc.run("unit.add_conversion_based_unit", name="day").should_be_called().will_return("unit") - unit.import_units().should_be_called() - assert subject.add_conversion_based_unit(ifc, unit, name="day") == "unit" - - -class TestAssignMassAndTimeUnits: - def test_assigning_mass_unit(self, ifc, unit): - ifc.run("unit.assign_unit", units=["massunit"]).should_be_called() - unit.import_units().should_be_called() - subject.assign_unit(ifc, unit, unit="massunit") - - def test_assigning_time_unit(self, ifc, unit): - ifc.run("unit.assign_unit", units=["timeunit"]).should_be_called() - unit.import_units().should_be_called() - subject.assign_unit(ifc, unit, unit="timeunit") - - def test_assigning_multiple_mass_and_time_units(self, ifc, unit): - ifc.run("unit.assign_unit", units=["massunit"]).should_be_called() - unit.import_units().should_be_called() - ifc.run("unit.assign_unit", units=["timeunit"]).should_be_called() - unit.import_units().should_be_called() - - subject.assign_unit(ifc, unit, unit="massunit") - subject.assign_unit(ifc, unit, unit="timeunit") - - -class TestUnassignMassAndTimeUnits: - def test_unassigning_mass_unit(self, ifc, unit): - ifc.run("unit.unassign_unit", units=["massunit"]).should_be_called() - unit.import_units().should_be_called() - subject.unassign_unit(ifc, unit, unit="massunit") - - def test_unassigning_time_unit(self, ifc, unit): - ifc.run("unit.unassign_unit", units=["timeunit"]).should_be_called() - unit.import_units().should_be_called() - subject.unassign_unit(ifc, unit, unit="timeunit") - - -class TestRemoveMassAndTimeUnits: - def test_removing_mass_unit(self, ifc, unit): - ifc.run("unit.remove_unit", unit="massunit").should_be_called() - unit.import_units().should_be_called() - subject.remove_unit(ifc, unit, unit="massunit") - - def test_removing_time_unit(self, ifc, unit): - ifc.run("unit.remove_unit", unit="timeunit").should_be_called() - unit.import_units().should_be_called() - subject.remove_unit(ifc, unit, unit="timeunit") diff --git a/src/ifcopenshell-python/ifcopenshell/api/unit/assign_unit.py b/src/ifcopenshell-python/ifcopenshell/api/unit/assign_unit.py index 58abfd4ea4..f9563410cd 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/unit/assign_unit.py +++ b/src/ifcopenshell-python/ifcopenshell/api/unit/assign_unit.py @@ -27,8 +27,6 @@ def assign_unit( length: Optional[dict] = None, area: Optional[dict] = None, volume: Optional[dict] = None, - mass: Optional[dict] = None, - time: Optional[dict] = None, ) -> ifcopenshell.entity_instance: """Assign default project units @@ -53,19 +51,16 @@ def assign_unit( # You need a project before you can assign units. ifcopenshell.api.root.create_entity(model, ifc_class="IfcProject") - # Millimeters, square meters, kilograms, and seconds + # Create units explicitly length = ifcopenshell.api.unit.add_si_unit(model, unit_type="LENGTHUNIT", prefix="MILLI") area = ifcopenshell.api.unit.add_si_unit(model, unit_type="AREAUNIT") mass = ifcopenshell.api.unit.add_si_unit(model, unit_type="MASSUNIT", prefix="KILO") - time = ifcopenshell.api.unit.add_si_unit(model, unit_type="TIMEUNIT") + time = ifcopenshell.api.unit.add_conversion_based_unit(model, name="minute") - # Make it our default units, if we are doing a metric building - ifcopenshell.api.unit.assign_unit(model, units=[length, area]) + # Assign all units to the project + ifcopenshell.api.unit.assign_unit(model, units=[length, area, mass, time]) - # Alternatively, you may specify without any arguments to - # automatically create millimeters, square meters, and cubic meters - # as a convenience for testing purposes. Sorry imperial folks, we - # prioritise metric here. + # Alternatively, for basic metric units (length, area, volume only) ifcopenshell.api.unit.assign_unit(model) """ usecase = Usecase() @@ -75,8 +70,6 @@ def assign_unit( usecase.settings["length"] = length or {"is_metric": True, "raw": "MILLIMETERS"} usecase.settings["area"] = area or {"is_metric": True, "raw": "METERS"} usecase.settings["volume"] = volume or {"is_metric": True, "raw": "METERS"} - usecase.settings["mass"] = mass or {"is_metric": True, "raw": "KILOGRAM"} - usecase.settings["time"] = time or {"is_metric": True, "raw": "SECOND"} return usecase.execute() @@ -122,45 +115,7 @@ class Usecase: units.add(unit) unit_assignment.Units = list(units) - def create_time_conversion_unit(self, name: str, factor: float) -> ifcopenshell.entity_instance: - """Create a conversion-based time unit""" - dimensional_exponents = self.file.createIfcDimensionalExponents(0, 0, 1, 0, 0, 0, 0) - si_unit = self.file.createIfcSIUnit(None, "TIMEUNIT", None, "SECOND") - value_component = self.file.create_entity("IfcReal", **{"wrappedValue": factor}) - conversion_factor = self.file.createIfcMeasureWithUnit(value_component, si_unit) - return self.file.createIfcConversionBasedUnit(dimensional_exponents, "TIMEUNIT", name, conversion_factor) - - def create_mass_conversion_unit(self, name: str, factor: float) -> ifcopenshell.entity_instance: - """Create a conversion-based mass unit""" - dimensional_exponents = self.file.createIfcDimensionalExponents(0, 1, 0, 0, 0, 0, 0) # Mass dimension - si_unit = self.file.createIfcSIUnit(None, "MASSUNIT", "KILO", "GRAM") - value_component = self.file.create_entity("IfcReal", **{"wrappedValue": factor}) - conversion_factor = self.file.createIfcMeasureWithUnit(value_component, si_unit) - return self.file.createIfcConversionBasedUnit(dimensional_exponents, "MASSUNIT", name, conversion_factor) - def create_metric_unit(self, unit_type: str, data: dict) -> ifcopenshell.entity_instance: - if unit_type == "mass": - if data["raw"] == "KILOGRAM": - return self.file.createIfcSIUnit(None, "MASSUNIT", "KILO", "GRAM") - elif data["raw"] == "GRAM": - return self.file.createIfcSIUnit(None, "MASSUNIT", None, "GRAM") - elif data["raw"] == "TON": - return self.file.createIfcSIUnit(None, "MASSUNIT", "MEGA", "GRAM") - else: - return self.file.createIfcSIUnit(None, "MASSUNIT", "KILO", "GRAM") - - elif unit_type == "time": - if data["raw"] == "SECOND": - return self.file.createIfcSIUnit(None, "TIMEUNIT", None, "SECOND") - elif data["raw"] == "MINUTE": - return self.create_time_conversion_unit("minute", 60.0) - elif data["raw"] == "HOUR": - return self.create_time_conversion_unit("hour", 3600.0) - elif data["raw"] == "DAY": - return self.create_time_conversion_unit("day", 86400.0) - else: - return self.file.createIfcSIUnit(None, "TIMEUNIT", None, "SECOND") - type_prefix = "" if unit_type == "area": type_prefix = "SQUARE_" @@ -183,25 +138,6 @@ class Usecase: elif unit_type == "volume": dimensional_exponents = self.file.createIfcDimensionalExponents(3, 0, 0, 0, 0, 0, 0) name_prefix = "cubic" - elif unit_type == "mass": - if data["raw"] == "POUND": - return self.create_mass_conversion_unit("pound", 0.45359237) - elif data["raw"] == "OUNCE": - return self.create_mass_conversion_unit("ounce", 0.0283495) - else: - return self.create_mass_conversion_unit("pound", 0.45359237) - - elif unit_type == "time": - if data["raw"] == "SECOND": - return self.file.createIfcSIUnit(None, "TIMEUNIT", None, "SECOND") - elif data["raw"] == "MINUTE": - return self.create_time_conversion_unit("minute", 60.0) - elif data["raw"] == "HOUR": - return self.create_time_conversion_unit("hour", 3600.0) - elif data["raw"] == "DAY": - return self.create_time_conversion_unit("day", 86400.0) - else: - return self.file.createIfcSIUnit(None, "TIMEUNIT", None, "SECOND") si_unit = self.file.createIfcSIUnit( None, diff --git a/src/ifcopenshell-python/test/api/unit/test_add_conversion_based_unit.py b/src/ifcopenshell-python/test/api/unit/test_add_conversion_based_unit.py index 03a8a7edfd..87ed50ec8f 100644 --- a/src/ifcopenshell-python/test/api/unit/test_add_conversion_based_unit.py +++ b/src/ifcopenshell-python/test/api/unit/test_add_conversion_based_unit.py @@ -18,6 +18,7 @@ import test.bootstrap import ifcopenshell.api.unit +import ifcopenshell.util.unit as subject class TestAddConversionBasedUnitIFC2X3(test.bootstrap.IFC2X3): @@ -61,3 +62,110 @@ class TestAddConversionBasedUnitIFC4(test.bootstrap.IFC4, TestAddConversionBased assert si_unit.Prefix is None assert si_unit.Name == "KELVIN" assert unit.ConversionOffset == -459.67 + + def test_adding_mass_units_creates_proper_massunit(self): + mass_units = [ + ("tonne", 1000.0), + ("pound", 0.454), + ("ounce", 0.02835), + ("ton UK", 1016.0469088), + ("ton US", 907.18474), + ] + + for name, expected_conversion in mass_units: + unit = ifcopenshell.api.unit.add_conversion_based_unit(self.file, name=name) + + assert unit.is_a("IfcConversionBasedUnit") + assert unit.UnitType == "MASSUNIT" + assert unit.Name == name + + actual_conversion = unit.ConversionFactor.ValueComponent.wrappedValue + assert actual_conversion == expected_conversion + + target_unit = unit.ConversionFactor.UnitComponent + assert target_unit.is_a("IfcSIUnit") + assert target_unit.UnitType == "MASSUNIT" + assert target_unit.Name == "GRAM" + assert target_unit.Prefix == "KILO" + + def test_adding_time_units_creates_proper_timeunit(self): + time_units = [ + ("minute", 60), + ("hour", 3600), + ("day", 86400), + ] + + for name, expected_conversion in time_units: + unit = ifcopenshell.api.unit.add_conversion_based_unit(self.file, name=name) + + assert unit.is_a("IfcConversionBasedUnit") + assert unit.UnitType == "TIMEUNIT" + assert unit.Name == name + + actual_conversion = unit.ConversionFactor.ValueComponent.wrappedValue + assert actual_conversion == expected_conversion + + target_unit = unit.ConversionFactor.UnitComponent + assert target_unit.is_a("IfcSIUnit") + assert target_unit.UnitType == "TIMEUNIT" + assert target_unit.Name == "SECOND" + assert target_unit.Prefix is None + + def test_unknown_units_fall_back_to_userdefined(self): + unknown_unit = ifcopenshell.api.unit.add_conversion_based_unit(self.file, name="unknown_unit") + assert unknown_unit.UnitType == "USERDEFINED" + assert unknown_unit.Name == "unknown_unit" + + def test_mass_units_in_imperial_types(self): + expected_mass_units = ["ounce", "pound", "ton UK", "ton US", "tonne"] + + for unit_name in expected_mass_units: + assert unit_name in subject.imperial_types + assert subject.imperial_types[unit_name] == "MASSUNIT" + + def test_time_units_in_imperial_types(self): + expected_time_units = ["minute", "hour", "day"] + + for unit_name in expected_time_units: + assert unit_name in subject.imperial_types + assert subject.imperial_types[unit_name] == "TIMEUNIT" + + def test_mass_units_have_conversion_factors(self): + expected_mass_conversions = { + "ounce": 0.02835, + "pound": 0.454, + "ton UK": 1016.0469088, + "ton US": 907.18474, + "tonne": 1000.0, + } + + for unit_name, expected_factor in expected_mass_conversions.items(): + assert unit_name in subject.si_conversions + assert subject.si_conversions[unit_name] == expected_factor + + def test_time_units_have_conversion_factors(self): + expected_time_conversions = { + "minute": 60, + "hour": 3600, + "day": 86400, + } + + for unit_name, expected_factor in expected_time_conversions.items(): + assert unit_name in subject.si_conversions + assert subject.si_conversions[unit_name] == expected_factor + + def test_mass_and_time_units_have_symbols(self): + expected_symbols = { + "ounce": "oz", + "pound": "lb", + "ton UK": "ton", + "ton US": "ton", + "tonne": "t", + "minute": "min", + "hour": "hr", + "day": "day", + } + + for unit_name, expected_symbol in expected_symbols.items(): + assert unit_name in subject.unit_symbols + assert subject.unit_symbols[unit_name] == expected_symbol diff --git a/src/ifcopenshell-python/test/util/test_unit.py b/src/ifcopenshell-python/test/util/test_unit.py index ff7b7eede5..6e28a28e70 100644 --- a/src/ifcopenshell-python/test/util/test_unit.py +++ b/src/ifcopenshell-python/test/util/test_unit.py @@ -391,233 +391,3 @@ class TestConvertFileLengthUnitsIFC4(test.bootstrap.IFC4, TestConvertFileLengthU class TestConvertFileLengthUnitsIFC4X3(test.bootstrap.IFC4X3, TestConvertFileLengthUnits): pass - - -class TestAddConversionBasedUnitMassAndTime(test.bootstrap.IFC4): - def test_adding_mass_units_creates_proper_massunit(self): - mass_units = [ - ("tonne", 1000.0), - ("pound", 0.454), - ("ounce", 0.02835), - ("ton UK", 1016.0469088), - ("ton US", 907.18474), - ] - - for name, expected_conversion in mass_units: - unit = ifcopenshell.api.unit.add_conversion_based_unit(self.file, name=name) - - assert unit.is_a("IfcConversionBasedUnit") - - assert unit.UnitType == "MASSUNIT" - - assert unit.Name == name - - actual_conversion = unit.ConversionFactor.ValueComponent.wrappedValue - assert actual_conversion == expected_conversion - - target_unit = unit.ConversionFactor.UnitComponent - assert target_unit.is_a("IfcSIUnit") - assert target_unit.UnitType == "MASSUNIT" - assert target_unit.Name == "GRAM" - assert target_unit.Prefix == "KILO" - - def test_adding_time_units_creates_proper_timeunit(self): - time_units = [ - ("minute", 60), - ("hour", 3600), - ("day", 86400), - ] - - for name, expected_conversion in time_units: - unit = ifcopenshell.api.unit.add_conversion_based_unit(self.file, name=name) - - assert unit.is_a("IfcConversionBasedUnit") - - assert unit.UnitType == "TIMEUNIT" - - assert unit.Name == name - - actual_conversion = unit.ConversionFactor.ValueComponent.wrappedValue - assert actual_conversion == expected_conversion - - target_unit = unit.ConversionFactor.UnitComponent - assert target_unit.is_a("IfcSIUnit") - assert target_unit.UnitType == "TIMEUNIT" - assert target_unit.Name == "SECOND" - assert target_unit.Prefix is None - - def test_mass_unit_integration_with_project(self): - ifcopenshell.api.root.create_entity(self.file, ifc_class="IfcProject") - - kg_unit = ifcopenshell.api.unit.add_si_unit(self.file, unit_type="MASSUNIT", prefix="KILO") - tonne_unit = ifcopenshell.api.unit.add_conversion_based_unit(self.file, name="tonne") - pound_unit = ifcopenshell.api.unit.add_conversion_based_unit(self.file, name="pound") - - ifcopenshell.api.unit.assign_unit(self.file, units=[kg_unit]) - project_mass_unit = subject.get_project_unit(self.file, "MASSUNIT") - assert project_mass_unit == kg_unit - - unit_assignment = subject.get_unit_assignment(self.file) - assert unit_assignment - assigned_units = list(unit_assignment.Units or []) - assert kg_unit in assigned_units - - ifcopenshell.api.unit.assign_unit(self.file, units=[tonne_unit]) - project_mass_unit = subject.get_project_unit(self.file, "MASSUNIT") - assert project_mass_unit == tonne_unit - - unit_assignment = subject.get_unit_assignment(self.file) - assigned_units = list(unit_assignment.Units or []) - assert tonne_unit in assigned_units - - length_unit = ifcopenshell.api.unit.add_si_unit(self.file, unit_type="LENGTHUNIT") - ifcopenshell.api.unit.assign_unit(self.file, units=[pound_unit, length_unit]) - - unit_assignment = subject.get_unit_assignment(self.file) - assigned_units = list(unit_assignment.Units or []) - assert pound_unit in assigned_units - assert length_unit in assigned_units - - def test_time_unit_integration_with_project(self): - ifcopenshell.api.root.create_entity(self.file, ifc_class="IfcProject") - - second_unit = ifcopenshell.api.unit.add_si_unit(self.file, unit_type="TIMEUNIT") - minute_unit = ifcopenshell.api.unit.add_conversion_based_unit(self.file, name="minute") - hour_unit = ifcopenshell.api.unit.add_conversion_based_unit(self.file, name="hour") - - ifcopenshell.api.unit.assign_unit(self.file, units=[second_unit]) - project_time_unit = subject.get_project_unit(self.file, "TIMEUNIT") - assert project_time_unit == second_unit - - unit_assignment = subject.get_unit_assignment(self.file) - assert unit_assignment - assigned_units = list(unit_assignment.Units or []) - assert second_unit in assigned_units - - ifcopenshell.api.unit.assign_unit(self.file, units=[minute_unit]) - project_time_unit = subject.get_project_unit(self.file, "TIMEUNIT") - assert project_time_unit == minute_unit - - unit_assignment = subject.get_unit_assignment(self.file) - assigned_units = list(unit_assignment.Units or []) - assert minute_unit in assigned_units - - length_unit = ifcopenshell.api.unit.add_si_unit(self.file, unit_type="LENGTHUNIT") - ifcopenshell.api.unit.assign_unit(self.file, units=[hour_unit, length_unit]) - - unit_assignment = subject.get_unit_assignment(self.file) - assigned_units = list(unit_assignment.Units or []) - assert hour_unit in assigned_units - assert length_unit in assigned_units - - def test_multiple_unit_types_can_coexist(self): - ifcopenshell.api.root.create_entity(self.file, ifc_class="IfcProject") - - kg_unit = ifcopenshell.api.unit.add_si_unit(self.file, unit_type="MASSUNIT", prefix="KILO") - minute_unit = ifcopenshell.api.unit.add_conversion_based_unit(self.file, name="minute") - meter_unit = ifcopenshell.api.unit.add_si_unit(self.file, unit_type="LENGTHUNIT") - - ifcopenshell.api.unit.assign_unit(self.file, units=[kg_unit, minute_unit, meter_unit]) - - unit_assignment = subject.get_unit_assignment(self.file) - assigned_units = list(unit_assignment.Units or []) - - assert kg_unit in assigned_units - assert minute_unit in assigned_units - assert meter_unit in assigned_units - - assert subject.get_project_unit(self.file, "MASSUNIT") == kg_unit - assert subject.get_project_unit(self.file, "TIMEUNIT") == minute_unit - assert subject.get_project_unit(self.file, "LENGTHUNIT") == meter_unit - - def test_unknown_mass_or_time_units_fall_back_to_userdefined(self): - unknown_mass_unit = ifcopenshell.api.unit.add_conversion_based_unit(self.file, name="unknown_mass_unit") - assert unknown_mass_unit.UnitType == "USERDEFINED" - - unknown_time_unit = ifcopenshell.api.unit.add_conversion_based_unit(self.file, name="unknown_time_unit") - assert unknown_time_unit.UnitType == "USERDEFINED" - - def test_mass_units_individually(self): - tonne_unit = ifcopenshell.api.unit.add_conversion_based_unit(self.file, name="tonne") - assert tonne_unit.UnitType == "MASSUNIT" - assert tonne_unit.ConversionFactor.ValueComponent.wrappedValue == 1000.0 - - pound_unit = ifcopenshell.api.unit.add_conversion_based_unit(self.file, name="pound") - assert pound_unit.UnitType == "MASSUNIT" - assert pound_unit.ConversionFactor.ValueComponent.wrappedValue == 0.454 - - ounce_unit = ifcopenshell.api.unit.add_conversion_based_unit(self.file, name="ounce") - assert ounce_unit.UnitType == "MASSUNIT" - assert ounce_unit.ConversionFactor.ValueComponent.wrappedValue == 0.02835 - - def test_time_units_individually(self): - minute_unit = ifcopenshell.api.unit.add_conversion_based_unit(self.file, name="minute") - assert minute_unit.UnitType == "TIMEUNIT" - assert minute_unit.ConversionFactor.ValueComponent.wrappedValue == 60 - - hour_unit = ifcopenshell.api.unit.add_conversion_based_unit(self.file, name="hour") - assert hour_unit.UnitType == "TIMEUNIT" - assert hour_unit.ConversionFactor.ValueComponent.wrappedValue == 3600 - - day_unit = ifcopenshell.api.unit.add_conversion_based_unit(self.file, name="day") - assert day_unit.UnitType == "TIMEUNIT" - assert day_unit.ConversionFactor.ValueComponent.wrappedValue == 86400 - - -class TestMassAndTimeUnitDictionaries(test.bootstrap.IFC4): - def test_mass_units_in_imperial_types(self): - expected_mass_units = ["ounce", "pound", "ton UK", "ton US", "tonne"] - - def test_mass_units_in_imperial_types(self): - expected_mass_units = ["ounce", "pound", "ton UK", "ton US", "tonne"] - - for unit_name in expected_mass_units: - assert unit_name in subject.imperial_types - assert subject.imperial_types[unit_name] == "MASSUNIT" - - def test_time_units_in_imperial_types(self): - expected_time_units = ["minute", "hour", "day"] - - for unit_name in expected_time_units: - assert unit_name in subject.imperial_types - assert subject.imperial_types[unit_name] == "TIMEUNIT" - - def test_mass_units_have_conversion_factors(self): - expected_mass_conversions = { - "ounce": 0.02835, - "pound": 0.454, - "ton UK": 1016.0469088, - "ton US": 907.18474, - "tonne": 1000.0, - } - - for unit_name, expected_factor in expected_mass_conversions.items(): - assert unit_name in subject.si_conversions - assert subject.si_conversions[unit_name] == expected_factor - - def test_time_units_have_conversion_factors(self): - expected_time_conversions = { - "minute": 60, - "hour": 3600, - "day": 86400, - } - - for unit_name, expected_factor in expected_time_conversions.items(): - assert unit_name in subject.si_conversions - assert subject.si_conversions[unit_name] == expected_factor - - def test_mass_and_time_units_have_symbols(self): - expected_symbols = { - "ounce": "oz", - "pound": "lb", - "ton UK": "ton", - "ton US": "ton", - "tonne": "t", - "minute": "min", - "hour": "hr", - "day": "day", - } - - for unit_name, expected_symbol in expected_symbols.items(): - assert unit_name in subject.unit_symbols - assert subject.unit_symbols[unit_name] == expected_symbol