From f76d792a251e914dd4900f337fda1b87b7f00579 Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Tue, 5 Jan 2021 21:13:44 +1100 Subject: [PATCH] WIP port unit assignment to partial editing. See #1222. --- .../blenderbim/bim/__init__.py | 4 + .../blenderbim/bim/module/context/ui.py | 1 + .../blenderbim/bim/module/unit/__init__.py | 14 ++++ .../blenderbim/bim/module/unit/assign_unit.py | 76 +++++++++++++++++++ .../blenderbim/bim/module/unit/data.py | 19 +++++ .../blenderbim/bim/module/unit/operator.py | 40 ++++++++++ .../blenderbim/bim/module/unit/ui.py | 0 7 files changed, 154 insertions(+) create mode 100644 src/ifcblenderexport/blenderbim/bim/module/unit/__init__.py create mode 100644 src/ifcblenderexport/blenderbim/bim/module/unit/assign_unit.py create mode 100644 src/ifcblenderexport/blenderbim/bim/module/unit/data.py create mode 100644 src/ifcblenderexport/blenderbim/bim/module/unit/operator.py create mode 100644 src/ifcblenderexport/blenderbim/bim/module/unit/ui.py diff --git a/src/ifcblenderexport/blenderbim/bim/__init__.py b/src/ifcblenderexport/blenderbim/bim/__init__.py index 475cbdb5a3..fcb602a154 100644 --- a/src/ifcblenderexport/blenderbim/bim/__init__.py +++ b/src/ifcblenderexport/blenderbim/bim/__init__.py @@ -14,6 +14,7 @@ if bpy is not None: import blenderbim.bim.module.geometry as module_geometry import blenderbim.bim.module.model as module_model import blenderbim.bim.module.spatial as module_spatial + import blenderbim.bim.module.unit as module_unit from . import ui, prop, operator classes = [ @@ -320,6 +321,7 @@ if bpy is not None: classes.extend(module_geometry.classes) classes.extend(module_model.classes) classes.extend(module_spatial.classes) + classes.extend(module_unit.classes) def menu_func_export(self, context): self.layout.operator(operator.ExportIFC.bl_idname, text="Industry Foundation Classes (.ifc/.ifczip/.ifcjson)") @@ -360,6 +362,7 @@ if bpy is not None: module_geometry.register() module_model.register() module_spatial.register() + module_unit.register() bpy.app.handlers.depsgraph_update_pre.append(operator.depsgraph_update_pre_handler) def unregister(): @@ -380,6 +383,7 @@ if bpy is not None: del bpy.types.Camera.BIMCameraProperties del bpy.types.TextCurve.BIMTextProperties bpy.types.SCENE_PT_unit.remove(ui.ifc_units) + module_unit.unregister() module_spatial.unregister() module_model.unregister() module_geometry.unregister() diff --git a/src/ifcblenderexport/blenderbim/bim/module/context/ui.py b/src/ifcblenderexport/blenderbim/bim/module/context/ui.py index 8a404c85b9..678ae87b76 100644 --- a/src/ifcblenderexport/blenderbim/bim/module/context/ui.py +++ b/src/ifcblenderexport/blenderbim/bim/module/context/ui.py @@ -1,6 +1,7 @@ from bpy.types import Panel from blenderbim.bim.module.context.data import Data + class BIM_PT_context(Panel): bl_label = "IFC Geometric Representation Contexts" bl_idname = "BIM_PT_context" diff --git a/src/ifcblenderexport/blenderbim/bim/module/unit/__init__.py b/src/ifcblenderexport/blenderbim/bim/module/unit/__init__.py new file mode 100644 index 0000000000..87a28250a4 --- /dev/null +++ b/src/ifcblenderexport/blenderbim/bim/module/unit/__init__.py @@ -0,0 +1,14 @@ +import bpy +from . import ui, operator + +classes = ( + operator.AssignUnit, +) + + +def register(): + pass + + +def unregister(): + pass diff --git a/src/ifcblenderexport/blenderbim/bim/module/unit/assign_unit.py b/src/ifcblenderexport/blenderbim/bim/module/unit/assign_unit.py new file mode 100644 index 0000000000..3872a50829 --- /dev/null +++ b/src/ifcblenderexport/blenderbim/bim/module/unit/assign_unit.py @@ -0,0 +1,76 @@ +import ifcopenshell.util.unit + + +class Usecase(): + def __init__(self, file, settings=None): + self.file = file + self.settings = { + "length": { + "is_metric": True, + "raw": "MILLIMETERS" + }, + "area": { + "is_metric": True, + "raw": "METERS" + }, + "volume": { + "is_metric": True, + "raw": "METERS" + }, + } + for key, value in settings.items(): + self.settings[key] = value + + def execute(self): + for unit_type, data in self.settings.items(): + if data["is_metric"]: + data["ifc"] = self.create_metric_unit(unit_type, data) + else: + data["ifc"] = self.create_imperial_unit(unit_type, data) + unit_assignment = self.file.by_type("IfcUnitAssignment") + if unit_assignment: + unit_assignment = unit_assignment[0] + # TODO: handle unit rewriting, which is complicated + else: + unit_assignment = self.file.createIfcUnitAssignment([u["ifc"] for u in self.settings.values()]) + self.file.by_type("IfcProject")[0].UnitsInContext = unit_assignment + return unit_assignment + + def create_metric_unit(self, unit_type, data): + type_prefix = "" + if unit_type == "area": + type_prefix = "SQUARE_" + elif unit_type == "volume": + type_prefix = "CUBIC_" + return self.file.createIfcSIUnit( + None, + "{}UNIT".format(unit_type.upper()), + ifcopenshell.util.unit.get_prefix(data["raw"]), + type_prefix + ifcopenshell.util.unit.get_unit_name(data["raw"]), + ) + + def create_imperial_unit(self, unit_type, data): + if unit_type == "length": + dimensional_exponents = self.file.createIfcDimensionalExponents(1, 0, 0, 0, 0, 0, 0) + name_prefix = "" + elif unit_type == "area": + dimensional_exponents = self.file.createIfcDimensionalExponents(2, 0, 0, 0, 0, 0, 0) + name_prefix = "square" + elif unit_type == "volume": + dimensional_exponents = self.file.createIfcDimensionalExponents(3, 0, 0, 0, 0, 0, 0) + name_prefix = "cubic" + si_unit = self.file.createIfcSIUnit( + None, + "{}UNIT".format(unit_type.upper()), + None, + "{}METRE".format(name_prefix.upper() + "_" if name_prefix else ""), + ) + if data["raw"] == "INCHES": + name = "{}inch".format(name_prefix + " " if name_prefix else "") + elif data["raw"] == "FEET": + name = "{}foot".format(name_prefix + " " if name_prefix else "") + value_component = self.file.create_entity("IfcReal", **{"wrappedValue": ifcopenshell.util.unit.si_conversions[name]}) + conversion_factor = self.file.createIfcMeasureWithUnit(value_component, si_unit) + return self.file.createIfcConversionBasedUnit( + dimensional_exponents, "{}UNIT".format(unit_type.upper()), name, conversion_factor + ) diff --git a/src/ifcblenderexport/blenderbim/bim/module/unit/data.py b/src/ifcblenderexport/blenderbim/bim/module/unit/data.py new file mode 100644 index 0000000000..f61a07c58b --- /dev/null +++ b/src/ifcblenderexport/blenderbim/bim/module/unit/data.py @@ -0,0 +1,19 @@ +from blenderbim.bim.ifc import IfcStore + + +class Data: + is_loaded = False + units = {} + + @classmethod + def load(cls): + file = IfcStore.get_file() + if not file: + return + unit_assignment = file.by_type("IfcUnitAssignment") + if not unit_assignment: + return + for unit in unit_assignment[0].Units: + pass + # TODO: implement along with UI + cls.is_loaded = True diff --git a/src/ifcblenderexport/blenderbim/bim/module/unit/operator.py b/src/ifcblenderexport/blenderbim/bim/module/unit/operator.py new file mode 100644 index 0000000000..5ec9155c8e --- /dev/null +++ b/src/ifcblenderexport/blenderbim/bim/module/unit/operator.py @@ -0,0 +1,40 @@ +import bpy +import blenderbim.bim.module.unit.assign_unit as assign_unit +from blenderbim.bim.ifc import IfcStore +from blenderbim.bim.module.unit.data import Data + + +class AssignUnit(bpy.types.Operator): + bl_idname = "bim.assign_unit" + bl_label = "Assign Unit" + + def execute(self, context): + assign_unit.Usecase(IfcStore.get_file(), self.get_units()).execute() + Data.load() + return {"FINISHED"} + + def get_units(self): + units = { + "length": { + "ifc": None, + "is_metric": bpy.context.scene.unit_settings.system != "IMPERIAL", + "raw": bpy.context.scene.unit_settings.length_unit, + }, + "area": { + "ifc": None, + "is_metric": bpy.context.scene.unit_settings.system != "IMPERIAL", + "raw": bpy.context.scene.unit_settings.length_unit, + }, + "volume": { + "ifc": None, + "is_metric": bpy.context.scene.unit_settings.system != "IMPERIAL", + "raw": bpy.context.scene.unit_settings.length_unit, + }, + } + for data in units.values(): + if data["raw"] == "ADAPTIVE": + if data["is_metric"]: + data["raw"] = "METERS" + else: + data["raw"] = "FEET" + return units diff --git a/src/ifcblenderexport/blenderbim/bim/module/unit/ui.py b/src/ifcblenderexport/blenderbim/bim/module/unit/ui.py new file mode 100644 index 0000000000..e69de29bb2