From 7e16cb797ffb5f53bec06e714deaeedb72d1714e Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Wed, 1 Feb 2023 17:37:59 +1100 Subject: [PATCH] See #1848. Some straggling refactoring for resource data. --- .../blenderbim/bim/module/resource/data.py | 82 +++++++++---------- .../blenderbim/bim/module/resource/ui.py | 36 +++----- src/blenderbim/blenderbim/tool/resource.py | 19 ++--- 3 files changed, 57 insertions(+), 80 deletions(-) diff --git a/src/blenderbim/blenderbim/bim/module/resource/data.py b/src/blenderbim/blenderbim/bim/module/resource/data.py index 0822299186..95f1c6886c 100644 --- a/src/blenderbim/blenderbim/bim/module/resource/data.py +++ b/src/blenderbim/blenderbim/bim/module/resource/data.py @@ -18,7 +18,6 @@ import bpy import blenderbim.tool as tool -from ifcopenshell.api.cost.data import CostValueTrait import ifcopenshell @@ -26,7 +25,7 @@ def refresh(): ResourceData.is_loaded = False -class ResourceData(CostValueTrait): +class ResourceData: data = {} is_loaded = False cost_values = {} @@ -34,56 +33,49 @@ class ResourceData(CostValueTrait): @classmethod def load(cls): cls.data = { - "has_resources": cls.has_resources(), + "total_resources": cls.total_resources(), + "resources": cls.resources(), + "active_resource_ids": cls.active_resource_ids(), + "cost_values": cls.cost_values(), } - cls.load_resources() cls.is_loaded = True @classmethod - def has_resources(cls): - return bool(tool.Ifc.get().by_type("IfcResource")) - - @classmethod - def number_of_resources_loaded(cls): + def total_resources(cls): return len(tool.Ifc.get().by_type("IfcResource")) @classmethod - def load_resources(cls): - cls.data["resources"] = {} + def resources(cls): + results = {} for resource in tool.Ifc.get().by_type("IfcResource"): - data = resource.get_info() - del data["OwnerHistory"] - data["IsNestedBy"] = [] - for rel in resource.IsNestedBy: - [data["IsNestedBy"].append(o.id()) for o in rel.RelatedObjects] - data["Nests"] = [] - for rel in resource.Nests: - [data["Nests"].append(rel.RelatingObject.id())] - data["ResourceOf"] = [] - for rel in resource.ResourceOf: - [data["ResourceOf"].append(o.id()) for o in rel.RelatedObjects] - data["HasContext"] = resource.HasContext[0].RelatingContext.id() if resource.HasContext else None - if resource.Usage: - data["Usage"] = data["Usage"].id() - data["TotalCostQuantity"] = cls.get_total_quantity(resource) + base_quantity = None if resource.BaseQuantity: - data["BaseQuantity"] = resource.BaseQuantity.get_info() - del data["BaseQuantity"]["Unit"] - if resource.BaseCosts: - data["BaseCosts"] = [e.id() for e in resource.BaseCosts] - cls.load_cost_values(resource, data) - cls.data["resources"][resource.id()] = data - cls.data["number_of_resources_loaded"] = cls.number_of_resources_loaded() + base_quantity = resource.BaseQuantity.get_info() + del base_quantity["Unit"] + results[resource.id()] = {"type": resource.is_a(), "BaseQuantity": base_quantity} + return results - def load_resource_times(cls): - cls.data["resource_times"] = {} - for resource_time in tool.Ifc.get().by_type("IfcResourceTime"): - data = resource_time.get_info() - for key, value in data.items(): - if not value: - continue - if "Start" in key or "Finish" in key or key == "StatusTime": - data[key] = ifcopenshell.util.date.ifc2datetime(value) - elif "Work" in key or key == "LevelingDelay": - data[key] = ifcopenshell.util.date.ifc2datetime(value) - cls.data["resource_times"][resource_time.id()] = data + @classmethod + def cost_values(cls): + results = [] + ifc_id = bpy.context.scene.BIMResourceProperties.active_resource_id + if not ifc_id: + return results + resource = tool.Ifc.get().by_id(ifc_id) + for cost_value in resource.BaseCosts or []: + label = "{0:.2f}".format(ifcopenshell.util.cost.calculate_applied_value(resource, cost_value)) + label += " = {}".format(ifcopenshell.util.cost.serialise_cost_value(cost_value)) + results.append({"id": cost_value.id(), "label": label}) + return results + + @classmethod + def active_resource_ids(cls): + obj = bpy.context.active_object + element = tool.Ifc.get_entity(obj) + if not element: + return [] + results = [] + for rel in getattr(element, "HasAssignments", []) or []: + if rel.is_a("IfcRelAssignsToResource"): + results.append(rel.RelatingResource.id()) + return results diff --git a/src/blenderbim/blenderbim/bim/module/resource/ui.py b/src/blenderbim/blenderbim/bim/module/resource/ui.py index 73774a31cb..e2c1300afc 100644 --- a/src/blenderbim/blenderbim/bim/module/resource/ui.py +++ b/src/blenderbim/blenderbim/bim/module/resource/ui.py @@ -43,18 +43,15 @@ class BIM_PT_resources(Panel): ResourceData.load() row = self.layout.row(align=True) - if ResourceData.data["has_resources"]: - row.label( - text="{} Resources Found".format(ResourceData.data["number_of_resources_loaded"]), - icon="TEXT", - ) + if ResourceData.data["total_resources"]: + row.label(text=f"{ResourceData.data['total_resources']} Resources Found", icon="TEXT") else: row.label(text="No Resources found.", icon="COMMUNITY") if self.props.is_editing: row.operator("bim.disable_resource_editing_ui", text="", icon="CANCEL") else: - row.operator("bim.load_resources", text="Load Resources", icon="GREASEPENCIL") - row.operator("import_resources.bim", text="Import Resources", icon="IMPORT") + row.operator("bim.load_resources", text="", icon="GREASEPENCIL") + row.operator("import_resources.bim", text="", icon="IMPORT") if not self.props.is_editing: return @@ -170,25 +167,20 @@ class BIM_PT_resources(Panel): if self.props.cost_types == "CATEGORY": op.cost_category = self.props.cost_category - for cost_value_id in ResourceData.data["resources"][self.props.active_resource_id]["BaseCosts"] or []: + for cost_value in ResourceData.data["cost_values"]: row = self.layout.row(align=True) - self.draw_readonly_cost_value_ui(row, cost_value_id) + self.draw_readonly_cost_value_ui(row, cost_value) if self.props.cost_value_editing_type == "ATTRIBUTES": - box = self.layout.box() - self.draw_editable_cost_value_ui(box, ResourceData.cost_values[self.props.active_cost_value_id]) + blenderbim.bim.helper.draw_attributes(self.props.cost_value_attributes, self.layout.box()) - def draw_readonly_cost_value_ui(self, layout, cost_value_id): - cost_value = ResourceData.cost_values[cost_value_id] - - if self.props.active_cost_value_id == cost_value_id and self.props.cost_value_editing_type == "FORMULA": + def draw_readonly_cost_value_ui(self, layout, cost_value): + if self.props.active_cost_value_id == cost_value["id"] and self.props.cost_value_editing_type == "FORMULA": layout.prop(self.props, "cost_value_formula", text="") else: - cost_value_label = "{0:.2f}".format(cost_value["AppliedValue"]) - cost_value_label += " = " + cost_value["Formula"] - layout.label(text=cost_value_label, icon="DISC") + layout.label(text=cost_value["label"], icon="DISC") - self.draw_cost_value_operator_ui(layout, cost_value_id, self.props.active_resource_id) + self.draw_cost_value_operator_ui(layout, cost_value["id"], self.props.active_resource_id) def draw_cost_value_operator_ui(self, layout, cost_value_id, parent_id): if self.props.active_cost_value_id and self.props.active_cost_value_id == cost_value_id: @@ -212,9 +204,6 @@ class BIM_PT_resources(Panel): op.parent = parent_id op.cost_value = cost_value_id - def draw_editable_cost_value_ui(self, layout, cost_value): - blenderbim.bim.helper.draw_attributes(self.props.cost_value_attributes, layout) - class BIM_UL_resources(UIList): def draw_item(self, context, layout, data, item, icon, active_data, active_propname): @@ -246,9 +235,8 @@ class BIM_UL_resources(UIList): row.prop(item, "name", emboss=False, text="", icon=icon_map[resource["type"]]) row.prop(item, "schedule_usage", text="", emboss=False) if context.active_object and not props.active_resource_id: - oprops = context.active_object.BIMObjectProperties row = layout.row(align=True) - if oprops.ifc_definition_id in ResourceData.data["resources"][item.ifc_definition_id]["ResourceOf"]: + if item.ifc_definition_id in ResourceData.data["active_resource_ids"]: op = row.operator("bim.unassign_resource", text="", icon="KEYFRAME_HLT", emboss=False) op.resource = item.ifc_definition_id else: diff --git a/src/blenderbim/blenderbim/tool/resource.py b/src/blenderbim/blenderbim/tool/resource.py index 9d725bde16..159631a8a8 100644 --- a/src/blenderbim/blenderbim/tool/resource.py +++ b/src/blenderbim/blenderbim/tool/resource.py @@ -30,7 +30,6 @@ from datetime import datetime from dateutil import parser import ifcopenshell.util.date as ifcdateutils import ifcopenshell.util.cost -from ifcopenshell.api.unit.data import Data as UnitData class Resource(blenderbim.core.tool.Resource): @@ -190,10 +189,8 @@ class Resource(blenderbim.core.tool.Resource): prop.data_type = "enum" prop.is_null = prop.is_optional = False units = {} - if not UnitData.is_loaded: - UnitData.load(tool.Ifc.get()) - for unit_id, unit in UnitData.units.items(): - if unit.get("UnitType", None) in [ + for unit in tool.Ifc.get().by_type("IfcNamedUnit"): + if getattr(unit, "UnitType", None) in [ "AREAUNIT", "LENGTHUNIT", "TIMEUNIT", @@ -201,13 +198,13 @@ class Resource(blenderbim.core.tool.Resource): "MASSUNIT", "USERDEFINED", ]: - if unit["type"] == "IfcContextDependentUnit": - units[unit_id] = f"{unit['UnitType']} / {unit['Name']}" + if unit.is_a("IfcContextDependentUnit"): + units[unit.id()] = f"{unit.is_a()} / {unit.Name}" else: - name = unit["Name"] - if unit.get("Prefix", None): - name = f"(unit['Prefix']) {name}" - units[unit_id] = f"{unit['UnitType']} / {name}" + name = unit.Name + if getattr(unit, "Prefix", None): + name = f"(unit.Prefix) {name}" + units[unit.id()] = f"{unit.UnitType} / {name}" prop.enum_items = json.dumps(units) if data["UnitBasis"] and data["UnitBasis"].UnitComponent: name = data["UnitBasis"].UnitComponent.Name