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.DisableUnitEditingUI,
operator.RemoveUnit, operator.RemoveUnit,
operator.AddMonetaryUnit, operator.AddMonetaryUnit,
operator.AddSIUnit,
operator.EnableEditingUnit, operator.EnableEditingUnit,
operator.DisableEditingUnit, operator.DisableEditingUnit,
operator.EditUnit, operator.EditUnit,
@@ -1,5 +1,6 @@
import bpy import bpy
import ifcopenshell.api import ifcopenshell.api
import ifcopenshell.util.unit
import blenderbim.bim.helper import blenderbim.bim.helper
from blenderbim.bim.ifc import IfcStore from blenderbim.bim.ifc import IfcStore
from ifcopenshell.api.unit.data import Data from ifcopenshell.api.unit.data import Data
@@ -156,8 +157,29 @@ class AddMonetaryUnit(bpy.types.Operator):
def _execute(self, context): def _execute(self, context):
props = context.scene.BIMUnitProperties props = context.scene.BIMUnitProperties
self.file = IfcStore.get_file() self.file = IfcStore.get_file()
unit = ifcopenshell.api.run("unit.add_monetary_unit", self.file) ifcopenshell.api.run("unit.add_monetary_unit", self.file)
ifcopenshell.api.run("unit.assign_unit", self.file, units=[unit]) 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) Data.load(self.file)
bpy.ops.bim.load_units() bpy.ops.bim.load_units()
return {"FINISHED"} return {"FINISHED"}
@@ -1,6 +1,7 @@
import bpy import bpy
import ifcopenshell import ifcopenshell
import ifcopenshell.util.schema import ifcopenshell.util.schema
import ifcopenshell.util.attribute
from blenderbim.bim.ifc import IfcStore from blenderbim.bim.ifc import IfcStore
from blenderbim.bim.prop import StrProperty, Attribute from blenderbim.bim.prop import StrProperty, Attribute
from bpy.types import PropertyGroup from bpy.types import PropertyGroup
@@ -17,11 +18,14 @@ from bpy.props import (
unitclasses_enum = [] unitclasses_enum = []
namedunittypes_enum = []
def purge(): def purge():
global unitclasses_enum global unitclasses_enum
global namedunittypes_enum
unitclasses_enum = [] unitclasses_enum = []
namedunittypes_enum = []
def getUnitClasses(self, context): def getUnitClasses(self, context):
@@ -33,6 +37,16 @@ def getUnitClasses(self, context):
return unitclasses_enum 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): class Unit(PropertyGroup):
name: StringProperty(name="Name") name: StringProperty(name="Name")
unit_type: StringProperty(name="Unit Type") unit_type: StringProperty(name="Unit Type")
@@ -47,4 +61,5 @@ class BIMUnitProperties(PropertyGroup):
active_unit_index: IntProperty(name="Active Unit Index") active_unit_index: IntProperty(name="Active Unit Index")
active_unit_id: IntProperty(name="Active Unit Id") active_unit_id: IntProperty(name="Active Unit Id")
unit_classes: EnumProperty(items=getUnitClasses, name="Unit Classes") 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) 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") row.operator("bim.add_monetary_unit", text="", icon="ADD")
elif self.props.unit_classes == "IfcDerivedUnit": elif self.props.unit_classes == "IfcDerivedUnit":
pass # TODO 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: else:
pass # TODO row.prop(self.props, "named_unit_types", text="")
self.layout.template_list( self.layout.template_list(
"BIM_UL_units", "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", "CANDELA",
"COULOMB", "COULOMB",
"CUBIC_METRE", "CUBIC_METRE",
"DEGREE CELSIUS", "DEGREE_CELSIUS",
"FARAD", "FARAD",
"GRAM", "GRAM",
"GRAY", "GRAY",
@@ -43,7 +43,7 @@ unit_names = [
"SECOND", "SECOND",
"SIEMENS", "SIEMENS",
"SIEVERT", "SIEVERT",
"SQUARE METRE", "SQUARE_METRE",
"METRE", "METRE",
"STERADIAN", "STERADIAN",
"TESLA", "TESLA",
@@ -52,7 +52,6 @@ unit_names = [
"WEBER", "WEBER",
] ]
si_dimensions = { si_dimensions = {
"METRE": (1, 0, 0, 0, 0, 0, 0), "METRE": (1, 0, 0, 0, 0, 0, 0),
"SQUARE_METRE": (2, 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), "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 = { si_conversions = {
"inch": 0.0254, "inch": 0.0254,
"foot": 0.3048, "foot": 0.3048,
@@ -169,7 +201,7 @@ def get_prefix_multiplier(text):
def get_unit_name(text): def get_unit_name(text):
text = text.upper().replace("METER", "METRE") text = text.upper().replace("METER", "METRE")
for name in unit_names: for name in unit_names:
if name in text: if name.replace("_", " ") in text:
return name return name
@@ -263,19 +295,17 @@ def convert(value, from_prefix, from_unit, to_prefix, to_unit):
return value 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): 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] units = file.by_type("IfcUnitAssignment")[0]
unit_scale = 1 unit_scale = 1
for unit in units.Units: for unit in units.Units: