Support auto detection of unit type when adding imperial units

This commit is contained in:
Dion Moult
2021-10-14 12:44:13 +11:00
parent 464b0c2ebc
commit 1fa1a9e3d3
8 changed files with 216 additions and 0 deletions
@@ -117,6 +117,7 @@ si_type_names = {
"THERMODYNAMICTEMPERATUREUNIT": "KELVIN", # Or, DEGREE_CELSIUS, but this is a quirk of IFC
"TIMEUNIT": "SECOND",
"VOLUMEUNIT": "CUBIC_METRE",
"USERDEFINED": "METRE",
}
# See IfcDimensionalExponents:
@@ -151,6 +152,7 @@ named_dimensions = {
"THERMODYNAMICTEMPERATUREUNIT": (0, 0, 0, 0, 1, 0, 0),
"TIMEUNIT": (0, 0, 1, 0, 0, 0, 0),
"VOLUMEUNIT": (3, 0, 0, 0, 0, 0, 0),
"USERDEFINED": (0, 0, 0, 0, 0, 0, 0),
}
si_conversions = {
@@ -192,6 +194,48 @@ si_conversions = {
"btu": 1055.056,
}
imperial_types = {
"thou": "LENGTHUNIT",
"inch": "LENGTHUNIT",
"foot": "LENGTHUNIT",
"yard": "LENGTHUNIT",
"mile": "LENGTHUNIT",
"square thou": "AREAUNIT",
"square inch": "AREAUNIT",
"square foot": "AREAUNIT",
"square yard": "AREAUNIT",
"acre": "AREAUNIT",
"square mile": "AREAUNIT",
"cubic thou": "VOLUMEUNIT",
"cubic inch": "VOLUMEUNIT",
"cubic foot": "VOLUMEUNIT",
"cubic yard": "VOLUMEUNIT",
"cubic mile": "VOLUMEUNIT",
"litre": "VOLUMEUNIT",
"fluid ounce UK": "VOLUMEUNIT",
"fluid ounce US": "VOLUMEUNIT",
"pint UK": "VOLUMEUNIT",
"pint US": "VOLUMEUNIT",
"gallon UK": "VOLUMEUNIT",
"gallon US": "VOLUMEUNIT",
"degree": "PLANEANGLEUNIT",
"ounce": "MASSUNIT",
"pound": "MASSUNIT",
"ton UK": "MASSUNIT",
"ton US": "MASSUNIT",
"lbf": "FORCEUNIT",
"kip": "FORCEUNIT",
"psi": "PRESSUREUNIT",
"ksi": "PRESSUREUNIT",
"minute": "TIMEUNIT",
"hour": "TIMEUNIT",
"day": "TIMEUNIT",
"btu": "ENERGYUNIT",
}
prefix_symbols = {
"EXA": "E",
"PETA": "P",
@@ -0,0 +1,23 @@
import test.bootstrap
import ifcopenshell.api
class TestAddContextDependentUnit(test.bootstrap.IFC4):
def test_run(self):
unit = ifcopenshell.api.run(
"unit.add_context_dependent_unit",
self.file,
unit_type="LENGTHUNIT",
name="foobar",
dimensions=(1, 2, 3, 4, 5, 6, 7),
)
assert unit.is_a("IfcContextDependentUnit")
assert unit.Dimensions.LengthExponent == 1
assert unit.Dimensions.MassExponent == 2
assert unit.Dimensions.TimeExponent == 3
assert unit.Dimensions.ElectricCurrentExponent == 4
assert unit.Dimensions.ThermodynamicTemperatureExponent == 5
assert unit.Dimensions.AmountOfSubstanceExponent == 6
assert unit.Dimensions.LuminousIntensityExponent == 7
assert unit.UnitType == "LENGTHUNIT"
assert unit.Name == "foobar"
@@ -0,0 +1,9 @@
import test.bootstrap
import ifcopenshell.api
class TestAddMonetaryUnit(test.bootstrap.IFC4):
def test_run(self):
unit = ifcopenshell.api.run("unit.add_monetary_unit", self.file, currency="USD")
assert unit.is_a("IfcMonetaryUnit")
assert unit.Currency == "USD"
@@ -0,0 +1,25 @@
import test.bootstrap
import ifcopenshell.api
class TestAssignUnit(test.bootstrap.IFC4):
def test_run(self):
project = self.file.createIfcProject()
unit1 = ifcopenshell.api.run("unit.add_monetary_unit", self.file, currency="FOO")
unit2 = ifcopenshell.api.run("unit.add_monetary_unit", self.file, currency="BAR")
assignment = ifcopenshell.api.run("unit.assign_unit", self.file, units=[unit1, unit2])
assert project.UnitsInContext == assignment
assert assignment.is_a("IfcUnitAssignment")
assert unit1 in assignment.Units
assert unit2 in assignment.Units
def test_assign_units_to_an_existing_assignment(self):
project = self.file.createIfcProject()
unit1 = ifcopenshell.api.run("unit.add_monetary_unit", self.file, currency="FOO")
unit2 = ifcopenshell.api.run("unit.add_monetary_unit", self.file, currency="BAR")
assignment1 = ifcopenshell.api.run("unit.assign_unit", self.file, units=[unit1])
assignment2 = ifcopenshell.api.run("unit.assign_unit", self.file, units=[unit2])
assert project.UnitsInContext == assignment1
assert assignment1 == assignment2
assert unit1 in assignment1.Units
assert unit2 in assignment1.Units
@@ -0,0 +1,12 @@
import test.bootstrap
import ifcopenshell.api
class TestEditDerivedUnit(test.bootstrap.IFC4):
def test_run(self):
unit = self.file.createIfcDerivedUnit()
ifcopenshell.api.run("unit.edit_derived_unit", self.file, unit=unit, attributes={
"UnitType": "USERDEFINED", "UserDefinedType": "UserDefinedType"
})
assert unit.UnitType == "USERDEFINED"
assert unit.UserDefinedType == "UserDefinedType"
@@ -0,0 +1,11 @@
import test.bootstrap
import ifcopenshell.api
class TestEditMonetaryUnit(test.bootstrap.IFC4):
def test_run(self):
unit = self.file.createIfcMonetaryUnit()
ifcopenshell.api.run("unit.edit_monetary_unit", self.file, unit=unit, attributes={
"Currency": "FOO"
})
assert unit.Currency == "FOO"
@@ -0,0 +1,61 @@
import test.bootstrap
import ifcopenshell.api
class TestEditNamedUnit(test.bootstrap.IFC4):
def test_edit_context_dependent_unit(self):
unit = self.file.createIfcContextDependentUnit()
unit.Dimensions = self.file.createIfcDimensionalExponents()
ifcopenshell.api.run(
"unit.edit_named_unit",
self.file,
unit=unit,
attributes={"Dimensions": (1, 2, 3, 4, 5, 6, 7), "UnitType": "LENGTHUNIT", "Name": "Name"},
)
assert [a for a in unit.Dimensions] == [1, 2, 3, 4, 5, 6, 7]
assert unit.UnitType == "LENGTHUNIT"
assert unit.Name == "Name"
def test_edit_si_unit(self):
unit = self.file.createIfcSIUnit()
ifcopenshell.api.run(
"unit.edit_named_unit",
self.file,
unit=unit,
attributes={"UnitType": "LENGTHUNIT", "Prefix": "MILLI", "Name": "METRE"},
)
assert unit.UnitType == "LENGTHUNIT"
assert unit.Prefix == "MILLI"
assert unit.Name == "METRE"
def test_edit_conversion_based_unit(self):
unit = self.file.createIfcConversionBasedUnit()
unit.Dimensions = self.file.createIfcDimensionalExponents()
ifcopenshell.api.run(
"unit.edit_named_unit",
self.file,
unit=unit,
attributes={"Dimensions": (1, 2, 3, 4, 5, 6, 7), "UnitType": "LENGTHUNIT", "Name": "Name"},
)
assert [a for a in unit.Dimensions] == [1, 2, 3, 4, 5, 6, 7]
assert unit.UnitType == "LENGTHUNIT"
assert unit.Name == "Name"
def test_edit_conversion_based_unit_with_offset(self):
unit = self.file.createIfcConversionBasedUnitWithOffset()
unit.Dimensions = self.file.createIfcDimensionalExponents()
ifcopenshell.api.run(
"unit.edit_named_unit",
self.file,
unit=unit,
attributes={
"Dimensions": (1, 2, 3, 4, 5, 6, 7),
"UnitType": "LENGTHUNIT",
"Name": "Name",
"ConversionOffset": 1,
},
)
assert [a for a in unit.Dimensions] == [1, 2, 3, 4, 5, 6, 7]
assert unit.UnitType == "LENGTHUNIT"
assert unit.Name == "Name"
assert unit.ConversionOffset == 1
@@ -0,0 +1,31 @@
import test.bootstrap
import ifcopenshell.api
class TestRemoveUnit(test.bootstrap.IFC4):
def test_remove_a_single_unit(self):
unit = self.file.createIfcContextDependentUnit()
ifcopenshell.api.run("unit.remove_unit", self.file, unit=unit)
assert len(self.file.by_type("IfcContextDependentUnit")) == 0
def test_remove_the_only_assigned_unit(self):
self.file.createIfcProject()
unit = self.file.createIfcContextDependentUnit()
ifcopenshell.api.run("unit.assign_unit", self.file, units=[unit])
ifcopenshell.api.run("unit.remove_unit", self.file, unit=unit)
assert len(self.file.by_type("IfcContextDependentUnit")) == 0
assert len(self.file.by_type("IfcUnitAssignment")) == 0
def test_remove_an_assigned_unit(self):
self.file.createIfcProject()
unit1 = self.file.createIfcContextDependentUnit()
unit2 = self.file.createIfcSIUnit()
assignment = ifcopenshell.api.run("unit.assign_unit", self.file, units=[unit1, unit2])
ifcopenshell.api.run("unit.remove_unit", self.file, unit=unit1)
assert len(self.file.by_type("IfcContextDependentUnit")) == 0
assert assignment.Units == (unit2,)
def test_removing_a_unit_deeply(self):
unit = ifcopenshell.api.run("unit.add_conversion_based_unit", self.file, name="foot")
ifcopenshell.api.run("unit.remove_unit", self.file, unit=unit)
assert len([e for e in self.file]) == 0