From 7d087d29194b2f0771aa2eb50c9075557928884a Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Fri, 6 Aug 2021 12:38:18 +1000 Subject: [PATCH] You can now view all assigned project units --- .../blenderbim/bim/module/model/workspace.py | 2 + .../blenderbim/bim/module/sequence/ui.py | 2 +- .../blenderbim/bim/module/unit/__init__.py | 11 ++-- .../blenderbim/bim/module/unit/operator.py | 45 ++++++++++++++++ .../blenderbim/bim/module/unit/prop.py | 26 ++++++++++ .../blenderbim/bim/module/unit/ui.py | 51 +++++++++++++++++++ .../ifcopenshell/api/unit/data.py | 35 +++++++++++-- 7 files changed, 165 insertions(+), 7 deletions(-) create mode 100644 src/blenderbim/blenderbim/bim/module/unit/prop.py diff --git a/src/blenderbim/blenderbim/bim/module/model/workspace.py b/src/blenderbim/blenderbim/bim/module/model/workspace.py index c08fec8ebe..0d449baefe 100644 --- a/src/blenderbim/blenderbim/bim/module/model/workspace.py +++ b/src/blenderbim/blenderbim/bim/module/model/workspace.py @@ -86,6 +86,8 @@ class BimTool(WorkSpaceTool): row.label(text="Align Interior", icon="EVENT_V") row = layout.row(align=True) + row = layout.row(align=True) + row.label(text="Mode") row = layout.row(align=True) row.label(text="", icon="EVENT_ALT") row.label(text="Opening", icon="EVENT_O") diff --git a/src/blenderbim/blenderbim/bim/module/sequence/ui.py b/src/blenderbim/blenderbim/bim/module/sequence/ui.py index 8a0c94da3f..7c6148731c 100644 --- a/src/blenderbim/blenderbim/bim/module/sequence/ui.py +++ b/src/blenderbim/blenderbim/bim/module/sequence/ui.py @@ -18,7 +18,7 @@ class BIM_PT_work_plans(Panel): @classmethod def poll(cls, context): file = IfcStore.get_file() - return file and hasattr(file, "schema") and file.schema != "IFC2X3" + return file and file.schema != "IFC2X3" def draw(self, context): if not Data.is_loaded: diff --git a/src/blenderbim/blenderbim/bim/module/unit/__init__.py b/src/blenderbim/blenderbim/bim/module/unit/__init__.py index 87a28250a4..af935164c7 100644 --- a/src/blenderbim/blenderbim/bim/module/unit/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/unit/__init__.py @@ -1,14 +1,19 @@ import bpy -from . import ui, operator +from . import ui, prop, operator classes = ( operator.AssignUnit, + operator.LoadUnits, + prop.Unit, + prop.BIMUnitProperties, + ui.BIM_PT_units, + ui.BIM_UL_units, ) def register(): - pass + bpy.types.Scene.BIMUnitProperties = bpy.props.PointerProperty(type=prop.BIMUnitProperties) def unregister(): - pass + del bpy.types.Scene.BIMUnitProperties diff --git a/src/blenderbim/blenderbim/bim/module/unit/operator.py b/src/blenderbim/blenderbim/bim/module/unit/operator.py index 76afebedc2..dd31ac289d 100644 --- a/src/blenderbim/blenderbim/bim/module/unit/operator.py +++ b/src/blenderbim/blenderbim/bim/module/unit/operator.py @@ -43,3 +43,48 @@ class AssignUnit(bpy.types.Operator): else: data["raw"] = "FEET" return units + + +class LoadUnits(bpy.types.Operator): + bl_idname = "bim.load_units" + bl_label = "Load Units" + bl_options = {"REGISTER", "UNDO"} + + def execute(self, context): + props = context.scene.BIMUnitProperties + while len(props.units) > 0: + props.units.remove(0) + + for ifc_definition_id in Data.unit_assignment: + unit = Data.units[ifc_definition_id] + name = unit.get("Name", "") + + if unit["type"] == "IfcMonetaryUnit": + name = unit["Currency"] + + if unit["type"] == "IfcSIUnit" and unit["Prefix"]: + if "_" in name: + name_components = name.split("_") + name = f"{name_components[0]} {unit['Prefix']}{name_components[1]}" + else: + name = f"{unit['Prefix']}{name}" + + icon = "MOD_MESHDEFORM" + if unit["type"] == "IfcSIUnit": + icon = "SNAP_GRID" + elif unit["type"] == "IfcMonetaryUnit": + icon = "COPY_ID" + + unit_type = unit.get("UserDefinedType", None) + if not unit_type: + unit_type = unit.get("UnitType", None) + + new = props.units.add() + new.ifc_definition_id = ifc_definition_id + new.name = name + new.unit_type = unit_type + new.icon = icon + + props.is_editing = True + # bpy.ops.bim.disable_editing_unit() + return {"FINISHED"} diff --git a/src/blenderbim/blenderbim/bim/module/unit/prop.py b/src/blenderbim/blenderbim/bim/module/unit/prop.py new file mode 100644 index 0000000000..df960f47aa --- /dev/null +++ b/src/blenderbim/blenderbim/bim/module/unit/prop.py @@ -0,0 +1,26 @@ +import bpy +from blenderbim.bim.prop import StrProperty, Attribute +from bpy.types import PropertyGroup +from bpy.props import ( + PointerProperty, + StringProperty, + EnumProperty, + BoolProperty, + IntProperty, + FloatProperty, + FloatVectorProperty, + CollectionProperty, +) + + +class Unit(PropertyGroup): + name: StringProperty(name="Name") + unit_type: StringProperty(name="Unit Type") + icon: StringProperty(name="Icon") + ifc_definition_id: IntProperty(name="IFC Definition ID") + + +class BIMUnitProperties(PropertyGroup): + is_editing: BoolProperty(name="Is Editing") + units: CollectionProperty(name="Units", type=Unit) + active_unit_index: IntProperty(name="Active Unit Index") diff --git a/src/blenderbim/blenderbim/bim/module/unit/ui.py b/src/blenderbim/blenderbim/bim/module/unit/ui.py index e69de29bb2..943f20a08d 100644 --- a/src/blenderbim/blenderbim/bim/module/unit/ui.py +++ b/src/blenderbim/blenderbim/bim/module/unit/ui.py @@ -0,0 +1,51 @@ +import blenderbim.bim.helper +from bpy.types import Panel, UIList +from blenderbim.bim.ifc import IfcStore +from ifcopenshell.api.unit.data import Data + + +class BIM_PT_units(Panel): + bl_label = "IFC Units" + bl_idname = "BIM_PT_units" + bl_options = {"DEFAULT_CLOSED"} + bl_space_type = "PROPERTIES" + bl_region_type = "WINDOW" + bl_context = "scene" + + @classmethod + def poll(cls, context): + file = IfcStore.get_file() + return file + + def draw(self, context): + self.file = IfcStore.get_file() + if not Data.is_loaded: + Data.load(self.file) + self.props = context.scene.BIMUnitProperties + + row = self.layout.row(align=True) + row.label(text="{} Units Found".format(len(Data.unit_assignment)), icon="SNAP_GRID") + if self.props.is_editing: + row.operator("bim.add_group", text="", icon="ADD") + row.operator("bim.disable_group_editing_ui", text="", icon="CANCEL") + else: + row.operator("bim.load_units", text="", icon="GREASEPENCIL") + + if self.props.is_editing: + self.layout.template_list( + "BIM_UL_units", + "", + self.props, + "units", + self.props, + "active_unit_index", + ) + + +class BIM_UL_units(UIList): + def draw_item(self, context, layout, data, item, icon, active_data, active_propname): + props = context.scene.BIMUnitProperties + if item: + row = layout.row(align=True) + row.label(text=item.unit_type or "No Type", icon=item.icon) + row.label(text=item.name or "Unnamed") diff --git a/src/ifcopenshell-python/ifcopenshell/api/unit/data.py b/src/ifcopenshell-python/ifcopenshell/api/unit/data.py index 8b71dad1b4..e9959597f1 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/unit/data.py +++ b/src/ifcopenshell-python/ifcopenshell/api/unit/data.py @@ -1,3 +1,7 @@ +import ifcopenshell +import ifcopenshell.util.unit + + class Data: is_loaded = False units = {} @@ -5,16 +9,41 @@ class Data: @classmethod def purge(cls): cls.is_loaded = False + cls.unit_assignment = [] cls.units = {} @classmethod def load(cls, file): if not file: return - unit_assignment = file.by_type("IfcUnitAssignment") + cls.file = file + unit_assignment = cls.file.by_type("IfcUnitAssignment") if not unit_assignment: return for unit in unit_assignment[0].Units: - pass - # TODO: implement along with UI + cls.unit_assignment.append(unit.id()) + cls.load_unit(unit) cls.is_loaded = True + + @classmethod + def load_unit(cls, unit): + if unit.is_a("IfcDerivedUnit"): + data = unit.get_info() + data["Elements"] = [{"Unit": e.Unit.id(), "Exponent": e.Exponent} for e in unit.Elements] + for element in unit.Elements: + cls.load_unit(element.Unit) + cls.units[unit.id()] = data + elif unit.is_a("IfcNamedUnit"): + data = unit.get_info() + if unit.is_a("IfcSIUnit"): + data["Dimensions"] = ifcopenshell.util.unit.get_si_dimensions(unit.Name) + else: + data["Dimensions"] = unit.Dimensions.get_info() + if unit.is_a("IfcConversionBasedUnit"): + conversion_factor = unit.ConversionFactor.get_info() + cls.load_unit(unit.ConversionFactor.UnitComponent) + conversion_factor["UnitComponent"] = unit.ConversionFactor.UnitComponent.id() + data["ConversionFactor"] = conversion_factor + cls.units[unit.id()] = data + elif unit.is_a("IfcMonetaryUnit"): + cls.units[unit.id()] = unit.get_info()