From 1fa1a9e3d39b1c9302a878c87f8fe580802b11ab Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Thu, 14 Oct 2021 12:44:13 +1100 Subject: [PATCH] Support auto detection of unit type when adding imperial units --- .../ifcopenshell/util/unit.py | 44 +++++++++++++ .../unit/test_add_context_dependent_unit.py | 23 +++++++ .../test/api/unit/test_add_monetary_unit.py | 9 +++ .../test/api/unit/test_assign_unit.py | 25 ++++++++ .../test/api/unit/test_edit_derived_unit.py | 12 ++++ .../test/api/unit/test_edit_monetary_unit.py | 11 ++++ .../test/api/unit/test_edit_named_unit.py | 61 +++++++++++++++++++ .../test/api/unit/test_remove_unit.py | 31 ++++++++++ 8 files changed, 216 insertions(+) create mode 100644 src/ifcopenshell-python/test/api/unit/test_add_context_dependent_unit.py create mode 100644 src/ifcopenshell-python/test/api/unit/test_add_monetary_unit.py create mode 100644 src/ifcopenshell-python/test/api/unit/test_assign_unit.py create mode 100644 src/ifcopenshell-python/test/api/unit/test_edit_derived_unit.py create mode 100644 src/ifcopenshell-python/test/api/unit/test_edit_monetary_unit.py create mode 100644 src/ifcopenshell-python/test/api/unit/test_edit_named_unit.py create mode 100644 src/ifcopenshell-python/test/api/unit/test_remove_unit.py diff --git a/src/ifcopenshell-python/ifcopenshell/util/unit.py b/src/ifcopenshell-python/ifcopenshell/util/unit.py index 1229c8db89..1027bd52c7 100644 --- a/src/ifcopenshell-python/ifcopenshell/util/unit.py +++ b/src/ifcopenshell-python/ifcopenshell/util/unit.py @@ -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", diff --git a/src/ifcopenshell-python/test/api/unit/test_add_context_dependent_unit.py b/src/ifcopenshell-python/test/api/unit/test_add_context_dependent_unit.py new file mode 100644 index 0000000000..ade8cbbb70 --- /dev/null +++ b/src/ifcopenshell-python/test/api/unit/test_add_context_dependent_unit.py @@ -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" diff --git a/src/ifcopenshell-python/test/api/unit/test_add_monetary_unit.py b/src/ifcopenshell-python/test/api/unit/test_add_monetary_unit.py new file mode 100644 index 0000000000..50b48d3018 --- /dev/null +++ b/src/ifcopenshell-python/test/api/unit/test_add_monetary_unit.py @@ -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" diff --git a/src/ifcopenshell-python/test/api/unit/test_assign_unit.py b/src/ifcopenshell-python/test/api/unit/test_assign_unit.py new file mode 100644 index 0000000000..b1a6a8185e --- /dev/null +++ b/src/ifcopenshell-python/test/api/unit/test_assign_unit.py @@ -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 diff --git a/src/ifcopenshell-python/test/api/unit/test_edit_derived_unit.py b/src/ifcopenshell-python/test/api/unit/test_edit_derived_unit.py new file mode 100644 index 0000000000..4e6092b776 --- /dev/null +++ b/src/ifcopenshell-python/test/api/unit/test_edit_derived_unit.py @@ -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" diff --git a/src/ifcopenshell-python/test/api/unit/test_edit_monetary_unit.py b/src/ifcopenshell-python/test/api/unit/test_edit_monetary_unit.py new file mode 100644 index 0000000000..3cdbd3a860 --- /dev/null +++ b/src/ifcopenshell-python/test/api/unit/test_edit_monetary_unit.py @@ -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" diff --git a/src/ifcopenshell-python/test/api/unit/test_edit_named_unit.py b/src/ifcopenshell-python/test/api/unit/test_edit_named_unit.py new file mode 100644 index 0000000000..8341ece238 --- /dev/null +++ b/src/ifcopenshell-python/test/api/unit/test_edit_named_unit.py @@ -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 diff --git a/src/ifcopenshell-python/test/api/unit/test_remove_unit.py b/src/ifcopenshell-python/test/api/unit/test_remove_unit.py new file mode 100644 index 0000000000..106237cbbf --- /dev/null +++ b/src/ifcopenshell-python/test/api/unit/test_remove_unit.py @@ -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