Implement ability to add SI units

This commit is contained in:
Dion Moult
2021-08-13 16:18:05 +10:00
parent 671f1ab9cf
commit fd163a3d1e
6 changed files with 99 additions and 19 deletions
@@ -8,6 +8,7 @@ classes = (
operator.DisableUnitEditingUI,
operator.RemoveUnit,
operator.AddMonetaryUnit,
operator.AddSIUnit,
operator.EnableEditingUnit,
operator.DisableEditingUnit,
operator.EditUnit,
@@ -1,5 +1,6 @@
import bpy
import ifcopenshell.api
import ifcopenshell.util.unit
import blenderbim.bim.helper
from blenderbim.bim.ifc import IfcStore
from ifcopenshell.api.unit.data import Data
@@ -156,8 +157,29 @@ class AddMonetaryUnit(bpy.types.Operator):
def _execute(self, context):
props = context.scene.BIMUnitProperties
self.file = IfcStore.get_file()
unit = ifcopenshell.api.run("unit.add_monetary_unit", self.file)
ifcopenshell.api.run("unit.assign_unit", self.file, units=[unit])
ifcopenshell.api.run("unit.add_monetary_unit", self.file)
Data.load(self.file)
bpy.ops.bim.load_units()
return {"FINISHED"}
class AddSIUnit(bpy.types.Operator):
bl_idname = "bim.add_si_unit"
bl_label = "Add SI Unit"
bl_options = {"REGISTER", "UNDO"}
def execute(self, context):
return IfcStore.execute_ifc_operator(self, context)
def _execute(self, context):
props = context.scene.BIMUnitProperties
self.file = IfcStore.get_file()
unit = ifcopenshell.api.run(
"unit.add_si_unit",
self.file,
unit_type=props.named_unit_types,
name=ifcopenshell.util.unit.si_type_names[props.named_unit_types],
)
Data.load(self.file)
bpy.ops.bim.load_units()
return {"FINISHED"}
@@ -1,6 +1,7 @@
import bpy
import ifcopenshell
import ifcopenshell.util.schema
import ifcopenshell.util.attribute
from blenderbim.bim.ifc import IfcStore
from blenderbim.bim.prop import StrProperty, Attribute
from bpy.types import PropertyGroup
@@ -17,11 +18,14 @@ from bpy.props import (
unitclasses_enum = []
namedunittypes_enum = []
def purge():
global unitclasses_enum
global namedunittypes_enum
unitclasses_enum = []
namedunittypes_enum = []
def getUnitClasses(self, context):
@@ -33,6 +37,16 @@ def getUnitClasses(self, context):
return unitclasses_enum
def getNamedUnitTypes(self, context):
global namedunittypes_enum
if not len(namedunittypes_enum) and IfcStore.get_file():
values = ifcopenshell.util.attribute.get_enum_items(
IfcStore.get_schema().declaration_by_name("IfcNamedUnit").all_attributes()[1]
)
namedunittypes_enum.extend([(c, c, "") for c in sorted(values)])
return namedunittypes_enum
class Unit(PropertyGroup):
name: StringProperty(name="Name")
unit_type: StringProperty(name="Unit Type")
@@ -47,4 +61,5 @@ class BIMUnitProperties(PropertyGroup):
active_unit_index: IntProperty(name="Active Unit Index")
active_unit_id: IntProperty(name="Active Unit Id")
unit_classes: EnumProperty(items=getUnitClasses, name="Unit Classes")
named_unit_types: EnumProperty(items=getNamedUnitTypes, name="Named Unit Types")
unit_attributes: CollectionProperty(name="Unit Attributes", type=Attribute)
@@ -40,8 +40,11 @@ class BIM_PT_units(Panel):
row.operator("bim.add_monetary_unit", text="", icon="ADD")
elif self.props.unit_classes == "IfcDerivedUnit":
pass # TODO
elif self.props.unit_classes == "IfcSIUnit":
row.prop(self.props, "named_unit_types", text="")
row.operator("bim.add_si_unit", text="", icon="ADD")
else:
pass # TODO
row.prop(self.props, "named_unit_types", text="")
self.layout.template_list(
"BIM_UL_units",
@@ -0,0 +1,9 @@
class Usecase:
def __init__(self, file, **settings):
self.file = file
self.settings = {"unit_type": "LENGTHUNIT", "name": "METRE"}
for key, value in settings.items():
self.settings[key] = value
def execute(self):
return self.file.create_entity("IfcSIUnit", UnitType=self.settings["unit_type"], Name=self.settings["name"])
@@ -25,7 +25,7 @@ unit_names = [
"CANDELA",
"COULOMB",
"CUBIC_METRE",
"DEGREE CELSIUS",
"DEGREE_CELSIUS",
"FARAD",
"GRAM",
"GRAY",
@@ -43,7 +43,7 @@ unit_names = [
"SECOND",
"SIEMENS",
"SIEVERT",
"SQUARE METRE",
"SQUARE_METRE",
"METRE",
"STERADIAN",
"TESLA",
@@ -52,7 +52,6 @@ unit_names = [
"WEBER",
]
si_dimensions = {
"METRE": (1, 0, 0, 0, 0, 0, 0),
"SQUARE_METRE": (2, 0, 0, 0, 0, 0, 0),
@@ -87,6 +86,39 @@ si_dimensions = {
"OTHERWISE": (0, 0, 0, 0, 0, 0, 0),
}
# See https://github.com/buildingSMART/IFC4.3.x-development/issues/72
si_type_names = {
"ABSORBEDDOSEUNIT": "GRAY",
"AMOUNTOFSUBSTANCEUNIT": "MOLE",
"AREAUNIT": "SQUARE_METRE",
"DOSEEQUIVALENTUNIT": "SIEVERT",
"ELECTRICCAPACITANCEUNIT": "FARAD",
"ELECTRICCHARGEUNIT": "COULOMB",
"ELECTRICCONDUCTANCEUNIT": "SIEMENS",
"ELECTRICCURRENTUNIT": "AMPERE",
"ELECTRICRESISTANCEUNIT": "OHM",
"ELECTRICVOLTAGEUNIT": "VOLT",
"ENERGYUNIT": "JOULE",
"FORCEUNIT": "NEWTON",
"FREQUENCYUNIT": "HERTZ",
"ILLUMINANCEUNIT": "LUX",
"INDUCTANCEUNIT": "HENRY",
"LENGTHUNIT": "METRE",
"LUMINOUSFLUXUNIT": "LUMEN",
"LUMINOUSINTENSITYUNIT": "CANDELA",
"MAGNETICFLUXDENSITYUNIT": "TESLA",
"MAGNETICFLUXUNIT": "WEBER",
"MASSUNIT": "GRAM",
"PLANEANGLEUNIT": "RADIAN",
"POWERUNIT": "WATT",
"PRESSUREUNIT": "PASCAL",
"RADIOACTIVITYUNIT": "BECQUEREL",
"SOLIDANGLEUNIT": "STERADIAN",
"THERMODYNAMICTEMPERATUREUNIT": "KELVIN", # Or, DEGREE_CELSIUS, but this is a quirk of IFC
"TIMEUNIT": "SECOND",
"VOLUMEUNIT": "CUBIC_METRE",
}
si_conversions = {
"inch": 0.0254,
"foot": 0.3048,
@@ -169,7 +201,7 @@ def get_prefix_multiplier(text):
def get_unit_name(text):
text = text.upper().replace("METER", "METRE")
for name in unit_names:
if name in text:
if name.replace("_", " ") in text:
return name
@@ -263,19 +295,17 @@ def convert(value, from_prefix, from_unit, to_prefix, to_unit):
return value
"""Returns a unit scale factor to convert to and from IFC project length units and SI meters
Example::
ifc_project_length * unit_scale = si_meters
si_meters / unit_scale = ifc_project_length
:returns: The scale factor
:rtype: float
"""
def calculate_unit_scale(file):
"""Returns a unit scale factor to convert to and from IFC project length units and SI meters
Example::
ifc_project_length * unit_scale = si_meters
si_meters / unit_scale = ifc_project_length
:returns: The scale factor
:rtype: float
"""
units = file.by_type("IfcUnitAssignment")[0]
unit_scale = 1
for unit in units.Units: