Updated with core developer feedback: fixed for Tonne and added tests

This commit is contained in:
falken10vdl
2025-09-05 20:22:56 +02:00
parent 146301b0c0
commit a4e76ed6ee
7 changed files with 535 additions and 8 deletions
+2 -2
View File
@@ -592,7 +592,7 @@ class BIMProperties(PropertyGroup):
("GRAM", "Gram", "Grams"),
("POUND", "Pound", "Pounds"),
("OUNCE", "Ounce", "Ounces"),
("TON", "Ton", "Metric Tons"),
("TONNE", "Tonne", "Metric Tons"),
],
name="Mass Unit",
default="KILOGRAM",
@@ -601,7 +601,7 @@ class BIMProperties(PropertyGroup):
time_unit: EnumProperty(
items=[
("SECOND", "Second", "Seconds"),
("MINUTE", "Minutes", "Minutes"),
("MINUTE", "Minute", "Minutes"),
("HOUR", "Hour", "Hours"),
("DAY", "Day", "Days"),
],
+3 -3
View File
@@ -344,9 +344,9 @@ class Unit(bonsai.core.tool.Unit):
elif unit_type == "VOLUMEUNIT":
return bim_props.volume_unit
elif unit_type == "MASSUNIT":
return bim_props.mass_unit
return bim_props.mass_unit.lower()
elif unit_type == "TIMEUNIT":
return bim_props.time_unit
return bim_props.time_unit.lower()
else:
assert_never(unit_type)
@@ -369,7 +369,7 @@ class Unit(bonsai.core.tool.Unit):
return None
elif unit == "KILOGRAM":
return "KILO"
elif unit == "TON":
elif unit == "TONNE":
return "MEGA"
elif unit in ["POUND", "OUNCE"]:
return "CONVERSION"
+153 -2
View File
@@ -26,6 +26,9 @@ class TestAssignSceneUnits:
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(None)
ifc.run("unit.add_si_unit", unit_type="LENGTHUNIT", prefix="prefix").should_be_called().will_return(
"lengthunit"
)
@@ -38,7 +41,13 @@ class TestAssignSceneUnits:
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"]).should_be_called()
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"]
).should_be_called()
subject.assign_scene_units(ifc, unit)
def test_creating_and_assigning_imperial_units(self, ifc, unit):
@@ -54,7 +63,15 @@ class TestAssignSceneUnits:
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"]).should_be_called()
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")
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")
ifc.run(
"unit.assign_unit", units=["lengthunit", "areaunit", "volumeunit", "planeangleunit", "massunit", "timeunit"]
).should_be_called()
subject.assign_scene_units(ifc, unit)
@@ -162,3 +179,137 @@ 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")
+143
View File
@@ -135,6 +135,35 @@ class TestGetSceneUnitName(NewFile):
bpy.context.scene.unit_settings.system = "NONE"
assert subject.get_scene_unit_name("LENGTHUNIT") == "foot"
def test_getting_mass_unit_names(self):
"""Test getting mass unit names for different systems"""
assert bpy.context.scene
props = tool.Blender.get_bim_props()
props.mass_unit = "GRAM"
assert subject.get_scene_unit_name("MASSUNIT") == "gram"
props.mass_unit = "KILOGRAM"
assert subject.get_scene_unit_name("MASSUNIT") == "kilogram"
props.mass_unit = "POUND"
assert subject.get_scene_unit_name("MASSUNIT") == "pound"
props.mass_unit = "OUNCE"
assert subject.get_scene_unit_name("MASSUNIT") == "ounce"
props.mass_unit = "TONNE"
assert subject.get_scene_unit_name("MASSUNIT") == "tonne"
def test_getting_time_unit_names(self):
"""Test getting time unit names for different systems"""
assert bpy.context.scene
props = tool.Blender.get_bim_props()
props.time_unit = "SECOND"
assert subject.get_scene_unit_name("TIMEUNIT") == "second"
props.time_unit = "MINUTE"
assert subject.get_scene_unit_name("TIMEUNIT") == "minute"
props.time_unit = "HOUR"
assert subject.get_scene_unit_name("TIMEUNIT") == "hour"
props.time_unit = "DAY"
assert subject.get_scene_unit_name("TIMEUNIT") == "day"
class TestGetSceneUnitSIPrefix:
def test_run(self):
@@ -162,6 +191,30 @@ class TestGetSceneUnitSIPrefix:
props.volume_unit = "MILLI/CUBIC_METRE"
assert subject.get_scene_unit_si_prefix("VOLUMEUNIT") == "MILLI"
def test_mass_and_time_unit_prefixes(self):
assert bpy.context.scene
props = tool.Blender.get_bim_props()
props.mass_unit = "KILOGRAM"
assert subject.get_scene_unit_si_prefix("MASSUNIT") == "KILO"
props.mass_unit = "GRAM"
assert subject.get_scene_unit_si_prefix("MASSUNIT") is None
props.mass_unit = "POUND"
assert subject.get_scene_unit_si_prefix("MASSUNIT") == "CONVERSION"
props.mass_unit = "OUNCE"
assert subject.get_scene_unit_si_prefix("MASSUNIT") == "CONVERSION"
props.mass_unit = "TONNE"
assert subject.get_scene_unit_si_prefix("MASSUNIT") == "MEGA"
props.time_unit = "SECOND"
assert subject.get_scene_unit_si_prefix("TIMEUNIT") is None
props.time_unit = "MINUTE"
assert subject.get_scene_unit_si_prefix("TIMEUNIT") == "CONVERSION"
props.time_unit = "HOUR"
assert subject.get_scene_unit_si_prefix("TIMEUNIT") == "CONVERSION"
props.time_unit = "DAY"
assert subject.get_scene_unit_si_prefix("TIMEUNIT") == "CONVERSION"
class TestImportUnitAttributes(NewFile):
def test_importing_derived_units(self):
@@ -298,6 +351,96 @@ class TestImportUnits(NewFile):
assert props.units[5].unit_type == unit6.UnitType
assert props.units[5].ifc_class == unit6.is_a()
def test_importing_mass_and_time_units(self):
"""Test importing mass and time conversion based units"""
ifc = ifcopenshell.api.project.create_file()
tool.Ifc.set(ifc)
tonne_unit = ifcopenshell.api.unit.add_conversion_based_unit(ifc, name="tonne")
pound_unit = ifcopenshell.api.unit.add_conversion_based_unit(ifc, name="pound")
ounce_unit = ifcopenshell.api.unit.add_conversion_based_unit(ifc, name="ounce")
minute_unit = ifcopenshell.api.unit.add_conversion_based_unit(ifc, name="minute")
hour_unit = ifcopenshell.api.unit.add_conversion_based_unit(ifc, name="hour")
day_unit = ifcopenshell.api.unit.add_conversion_based_unit(ifc, name="day")
kg_unit = ifcopenshell.api.unit.add_si_unit(ifc, unit_type="MASSUNIT", prefix="KILO")
gram_unit = ifcopenshell.api.unit.add_si_unit(ifc, unit_type="MASSUNIT")
second_unit = ifcopenshell.api.unit.add_si_unit(ifc, unit_type="TIMEUNIT")
ifcopenshell.api.root.create_entity(ifc, ifc_class="IfcProject")
ifcopenshell.api.unit.assign_unit(ifc, units=[tonne_unit, minute_unit, kg_unit])
subject.import_units()
props = tool.Unit.get_unit_props()
assert len(props.units) == 15
unit_ids = [u.ifc_definition_id for u in props.units]
assert tonne_unit.id() in unit_ids
assert pound_unit.id() in unit_ids
assert ounce_unit.id() in unit_ids
assert minute_unit.id() in unit_ids
assert hour_unit.id() in unit_ids
assert day_unit.id() in unit_ids
assert kg_unit.id() in unit_ids
assert gram_unit.id() in unit_ids
assert second_unit.id() in unit_ids
tonne_prop = next(u for u in props.units if u.ifc_definition_id == tonne_unit.id())
assert tonne_prop.name == "tonne"
assert tonne_prop.unit_type == "MASSUNIT"
assert tonne_prop.is_assigned is True
assert tonne_prop.ifc_class == "IfcConversionBasedUnit"
pound_prop = next(u for u in props.units if u.ifc_definition_id == pound_unit.id())
assert pound_prop.name == "pound"
assert pound_prop.unit_type == "MASSUNIT"
assert pound_prop.is_assigned is False
assert pound_prop.ifc_class == "IfcConversionBasedUnit"
ounce_prop = next(u for u in props.units if u.ifc_definition_id == ounce_unit.id())
assert ounce_prop.name == "ounce"
assert ounce_prop.unit_type == "MASSUNIT"
assert ounce_prop.is_assigned is False
assert ounce_prop.ifc_class == "IfcConversionBasedUnit"
kg_prop = next(u for u in props.units if u.ifc_definition_id == kg_unit.id())
assert kg_prop.name == "KILOGRAM"
assert kg_prop.unit_type == "MASSUNIT"
assert kg_prop.is_assigned is True
assert kg_prop.ifc_class == "IfcSIUnit"
gram_prop = next(u for u in props.units if u.ifc_definition_id == gram_unit.id())
assert gram_prop.name == "GRAM"
assert gram_prop.unit_type == "MASSUNIT"
assert gram_prop.is_assigned is False
assert gram_prop.ifc_class == "IfcSIUnit"
minute_prop = next(u for u in props.units if u.ifc_definition_id == minute_unit.id())
assert minute_prop.name == "minute"
assert minute_prop.unit_type == "TIMEUNIT"
assert minute_prop.is_assigned is True
assert minute_prop.ifc_class == "IfcConversionBasedUnit"
hour_prop = next(u for u in props.units if u.ifc_definition_id == hour_unit.id())
assert hour_prop.name == "hour"
assert hour_prop.unit_type == "TIMEUNIT"
assert hour_prop.is_assigned is False
assert hour_prop.ifc_class == "IfcConversionBasedUnit"
day_prop = next(u for u in props.units if u.ifc_definition_id == day_unit.id())
assert day_prop.name == "day"
assert day_prop.unit_type == "TIMEUNIT"
assert day_prop.is_assigned is False
assert day_prop.ifc_class == "IfcConversionBasedUnit"
second_prop = next(u for u in props.units if u.ifc_definition_id == second_unit.id())
assert second_prop.name == "SECOND"
assert second_prop.unit_type == "TIMEUNIT"
assert second_prop.is_assigned is False
assert second_prop.ifc_class == "IfcSIUnit"
class TestIsSceneUnitMetric(NewFile):
def test_run(self):
@@ -32,7 +32,7 @@ def add_conversion_based_unit(
function. You can choose from one of: inch, foot, yard, mile, square
inch, square foot, square yard, acre, square mile, cubic inch, cubic
foot, cubic yard, litre, fluid ounce UK, fluid ounce US, pint UK, pint
US, gallon UK, gallon US, degree, ounce, pound, ton UK, ton US, lbf,
US, gallon UK, gallon US, degree, ounce, pound, ton UK, ton US, tonne, lbf,
kip, psi, ksi, minute, hour, day, btu, and fahrenheit.
:param name: A converted name chosen from the list above.
@@ -209,6 +209,7 @@ si_conversions = {
"pound": 0.454,
"ton UK": 1016.0469088,
"ton US": 907.18474,
"tonne": 1000.0,
"lbf": 4.4482216153,
"kip": 4448.2216153,
"psi": 6894.7572932,
@@ -253,6 +254,7 @@ imperial_types = {
"pound": "MASSUNIT",
"ton UK": "MASSUNIT",
"ton US": "MASSUNIT",
"tonne": "MASSUNIT",
"lbf": "FORCEUNIT",
"kip": "FORCEUNIT",
"psi": "PRESSUREUNIT",
@@ -323,6 +325,7 @@ unit_symbols = {
"pound": "lb",
"ton UK": "ton",
"ton US": "ton",
"tonne": "t",
"lbf": "lbf",
"kip": "kip",
"psi": "psi",
@@ -391,3 +391,233 @@ 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