Fix calculating resource work based from parent's productivity and improve UI to show this

This commit is contained in:
Sigma Dimensions (Yass)
2023-08-22 19:54:37 +01:00
parent 2e4e2c3173
commit 3582ccc1d4
5 changed files with 107 additions and 50 deletions
@@ -58,6 +58,7 @@ class ResourceData:
} }
if resource.is_a() in ["IfcLaborResource", "IfcConstructionEquipmentResource"]: if resource.is_a() in ["IfcLaborResource", "IfcConstructionEquipmentResource"]:
results[resource.id()]["Productivity"] = {} results[resource.id()]["Productivity"] = {}
results[resource.id()]["InheritedProductivity"] = {}
productivity = cls.get_productivity(resource) productivity = cls.get_productivity(resource)
if productivity: if productivity:
results[resource.id()]["Productivity"] = { results[resource.id()]["Productivity"] = {
@@ -65,12 +66,34 @@ class ResourceData:
"TimeConsumed": ifcopenshell.util.resource.get_unit_consumed(productivity), "TimeConsumed": ifcopenshell.util.resource.get_unit_consumed(productivity),
"QuantityProducedName": ifcopenshell.util.resource.get_quantity_produced_name(productivity), "QuantityProducedName": ifcopenshell.util.resource.get_quantity_produced_name(productivity),
} }
inherited_productivity = cls.get_parent_productivity(resource)
if inherited_productivity:
results[resource.id()]["InheritedProductivity"] = {
"QuantityProduced": ifcopenshell.util.resource.get_quantity_produced(inherited_productivity),
"TimeConsumed": ifcopenshell.util.resource.get_unit_consumed(inherited_productivity),
"QuantityProducedName": ifcopenshell.util.resource.get_quantity_produced_name(
inherited_productivity
),
}
if resource.Usage:
results[resource.id()]["ScheduleWork"] = (
ifcopenshell.util.date.readable_ifc_duration(resource.Usage.ScheduleWork)
if resource.Usage.ScheduleWork
else "Calculate",
)
results[resource.id()]["ScheduleUsage"] = (
resource.Usage.ScheduleUsage if resource.Usage.ScheduleUsage else ""
)
return results return results
@classmethod @classmethod
def get_productivity(cls, resource): def get_productivity(cls, resource):
return ifcopenshell.util.resource.get_productivity(resource, should_inherit=False) return ifcopenshell.util.resource.get_productivity(resource, should_inherit=False)
@classmethod
def get_parent_productivity(cls, resource):
return ifcopenshell.util.resource.get_parent_productivity(resource)
@classmethod @classmethod
def cost_values(cls): def cost_values(cls):
results = [] results = []
@@ -198,6 +198,13 @@ class CalculateResourceWork(bpy.types.Operator, tool.Ifc.Operator):
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
resource: bpy.props.IntProperty() resource: bpy.props.IntProperty()
@classmethod
def poll(cls, context):
active_resource = tool.Resource.get_highlighted_resource()
if active_resource:
if tool.Resource.get_productivity(active_resource, should_inherit=True):
return True
def _execute(self, context): def _execute(self, context):
core.calculate_resource_work(tool.Ifc, tool.Resource, resource=tool.Ifc.get().by_id(self.resource)) core.calculate_resource_work(tool.Ifc, tool.Resource, resource=tool.Ifc.get().by_id(self.resource))
@@ -22,6 +22,8 @@ import ifcopenshell.util.resource
from blenderbim.bim.ifc import IfcStore from blenderbim.bim.ifc import IfcStore
import blenderbim.tool as tool import blenderbim.tool as tool
import blenderbim.bim.module.pset.data import blenderbim.bim.module.pset.data
from blenderbim.bim.module.resource.data import refresh
from blenderbim.bim.module.sequence.data import refresh as refresh_sequence
from blenderbim.bim.prop import StrProperty, Attribute from blenderbim.bim.prop import StrProperty, Attribute
from bpy.types import PropertyGroup from bpy.types import PropertyGroup
from bpy.props import ( from bpy.props import (
@@ -56,6 +58,8 @@ def updateResourceName(self, context):
if props.active_resource_id == self.ifc_definition_id: if props.active_resource_id == self.ifc_definition_id:
attribute = props.resource_attributes.get("Name") attribute = props.resource_attributes.get("Name")
attribute.string_value = self.name attribute.string_value = self.name
refresh()
tool.Sequence.refresh_task_resources()
def get_quantity_types(self, context): def get_quantity_types(self, context):
@@ -72,7 +76,7 @@ def get_quantity_types(self, context):
def update_active_resource_index(self, context): def update_active_resource_index(self, context):
blenderbim.bim.module.pset.data.refresh() blenderbim.bim.module.pset.data.refresh()
if self.should_show_productivity: if self.should_show_resource_tools:
tool.Resource.load_productivity_data() tool.Resource.load_productivity_data()
@@ -91,7 +95,9 @@ def updateResourceUsage(self, context):
) )
resource.Usage.ScheduleUsage = self.schedule_usage resource.Usage.ScheduleUsage = self.schedule_usage
blenderbim.bim.module.pset.data.refresh() blenderbim.bim.module.pset.data.refresh()
refresh()
tool.Resource.load_resource_properties() tool.Resource.load_resource_properties()
tool.Sequence.refresh_task_resources()
class ISODuration(PropertyGroup): class ISODuration(PropertyGroup):
@@ -144,7 +150,7 @@ class BIMResourceProperties(PropertyGroup):
quantity_types: EnumProperty(items=get_quantity_types, name="Quantity Types") quantity_types: EnumProperty(items=get_quantity_types, name="Quantity Types")
is_editing_quantity: BoolProperty(name="Is Editing Quantity") is_editing_quantity: BoolProperty(name="Is Editing Quantity")
quantity_attributes: CollectionProperty(name="Quantity Attributes", type=Attribute) quantity_attributes: CollectionProperty(name="Quantity Attributes", type=Attribute)
should_show_productivity: BoolProperty(name="Edit Productivity", update=update_active_resource_index) should_show_resource_tools: BoolProperty(name="Edit Productivity", update=update_active_resource_index)
class BIMResourceProductivity(PropertyGroup): class BIMResourceProductivity(PropertyGroup):
@@ -64,11 +64,8 @@ class BIM_PT_resources(Panel):
self.props, self.props,
"active_resource_index", "active_resource_index",
) )
row = self.layout.row(align=True) self.draw_productivity_ui(context)
row.alignment = "RIGHT"
row.prop(self.props, "should_show_productivity", icon="RECOVER_LAST")
if self.props.should_show_productivity:
self.draw_productivity_ui(context)
if self.props.active_resource_id and self.props.editing_resource_type == "ATTRIBUTES": if self.props.active_resource_id and self.props.editing_resource_type == "ATTRIBUTES":
self.draw_editable_resource_attributes_ui() self.draw_editable_resource_attributes_ui()
elif self.props.active_resource_id and self.props.editing_resource_type == "QUANTITY": elif self.props.active_resource_id and self.props.editing_resource_type == "QUANTITY":
@@ -79,43 +76,66 @@ class BIM_PT_resources(Panel):
self.draw_editable_resource_time_attributes_ui() self.draw_editable_resource_time_attributes_ui()
def draw_productivity_ui(self, context): def draw_productivity_ui(self, context):
total_resources = len(self.tprops.resources)
if not total_resources or self.props.active_resource_index >= total_resources:
return
ifc_definition_id = self.tprops.resources[self.props.active_resource_index].ifc_definition_id
resource = ResourceData.data["resources"][ifc_definition_id]
if not resource["type"] in ["IfcConstructionEquipmentResource", "IfcLaborResource"]:
row = self.layout.row(align=True)
row.label(text="Resource type cannot have productivity data", icon="ERROR")
return
self.productivity_props = context.scene.BIMResourceProductivity
if resource["Productivity"]:
produtivitiy_rate_message = "Current Rate: {}/{}".format(
resource["Productivity"]["QuantityProduced"], resource["Productivity"]["TimeConsumed"]
)
row = self.layout.row()
row.alignment = "LEFT"
row.label(text=produtivitiy_rate_message, icon="ARMATURE_DATA")
else:
row = self.layout.row(align=True)
row.alignment = "LEFT"
produtivitiy_rate_message = "No productivity data found"
row.label(text=produtivitiy_rate_message, icon="ARMATURE_DATA")
row = self.layout.row(align=True) row = self.layout.row(align=True)
row.alignment = "RIGHT" row.alignment = "RIGHT"
row.prop(self.productivity_props, "quantity_produced", text="Quantity Produced") row.prop(self.props, "should_show_resource_tools", icon="RECOVER_LAST")
row.prop(self.productivity_props, "quantity_produced_name", text="Quantity Name") if self.props.should_show_resource_tools:
row = self.layout.row() total_resources = len(self.tprops.resources)
row.alignment = "RIGHT" if not total_resources or self.props.active_resource_index >= total_resources:
self.draw_duration_property(self.productivity_props.quantity_consumed, row) return
row = self.layout.row()
row.alignment = "RIGHT" ifc_definition_id = self.tprops.resources[self.props.active_resource_index].ifc_definition_id
row.operator("bim.edit_productivity_data", text="Apply", icon="CHECKMARK") resource = ResourceData.data["resources"][ifc_definition_id]
if not resource["type"] in ["IfcConstructionEquipmentResource", "IfcLaborResource"]:
row = self.layout.row(align=True)
row.label(text="Resource type cannot have productivity data", icon="ERROR")
else:
productivity = resource["Productivity"]
parent_productivity = resource["InheritedProductivity"]
row = self.layout.row()
row.operator(
"bim.calculate_resource_work", text="Calculate Work", icon="TEMP"
).resource = ifc_definition_id
row = self.layout.row()
row.label(text="Productivity")
row = self.layout.row()
if productivity:
produtivitiy_rate_message = "Current Productivity Rate: {} {} / {}".format(
productivity["QuantityProduced"],
productivity["QuantityProducedName"],
productivity["TimeConsumed"],
)
row.alignment = "LEFT"
row.label(text=produtivitiy_rate_message, icon="ARMATURE_DATA")
elif parent_productivity:
produtivitiy_rate_message = "Inherited Productivity Rate: {} {} / {}*".format(
parent_productivity["QuantityProduced"],
parent_productivity["QuantityProducedName"],
parent_productivity["TimeConsumed"],
)
row.alignment = "LEFT"
row.label(text=produtivitiy_rate_message, icon="ARMATURE_DATA")
else:
row = self.layout.row(align=True)
row.alignment = "LEFT"
produtivitiy_rate_message = "No productivity data found"
row.label(text=produtivitiy_rate_message, icon="ARMATURE_DATA")
productivity_props = context.scene.BIMResourceProductivity
row = self.layout.row(align=True)
row.alignment = "RIGHT"
row.prop(productivity_props, "quantity_produced", text="Quantity Produced")
row.prop(productivity_props, "quantity_produced_name", text="Quantity Name")
row = self.layout.row()
row.alignment = "RIGHT"
self.draw_duration_property(productivity_props.quantity_consumed, row)
row = self.layout.row()
row.alignment = "RIGHT"
row.operator("bim.edit_productivity_data", text="Apply", icon="CHECKMARK")
def draw_resource_operators(self): def draw_resource_operators(self):
row = self.layout.row(align=True) row = self.layout.row(align=True)
@@ -153,9 +173,6 @@ class BIM_PT_resources(Panel):
if not self.props.active_resource_id: if not self.props.active_resource_id:
if resource["type"] in ["IfcLaborResource", "IfcConstructionEquipmentResource"]: if resource["type"] in ["IfcLaborResource", "IfcConstructionEquipmentResource"]:
if resource["Productivity"]:
op = row.operator("bim.calculate_resource_work", text="", icon="TEMP")
op.resource = ifc_definition_id
row.operator("bim.enable_editing_resource_time", text="", icon="TIME").resource = ifc_definition_id row.operator("bim.enable_editing_resource_time", text="", icon="TIME").resource = ifc_definition_id
op = row.operator("bim.enable_editing_resource_base_quantity", text="", icon="PROPERTIES") op = row.operator("bim.enable_editing_resource_base_quantity", text="", icon="PROPERTIES")
op.resource = ifc_definition_id op.resource = ifc_definition_id
@@ -23,14 +23,18 @@ import ifcopenshell.util.date
def get_productivity(resource, should_inherit=True): def get_productivity(resource, should_inherit=True):
productivity = ifcopenshell.util.element.get_psets(resource).get("EPset_Productivity", None) productivity = ifcopenshell.util.element.get_psets(resource).get("EPset_Productivity", None)
if should_inherit and not productivity: if should_inherit and not productivity:
# Proposal for Schema - If instance doesn't have any productivity, inherit it's parent's productivity #Note: This is not part of the Schema - but it makes sense to inherit from parent
if not resource.Nests: productivity = get_parent_productivity(resource)
return None
else:
parent_resource = resource.Nests[0].RelatingObject
productivity = ifcopenshell.util.element.get_psets(parent_resource).get("EPset_Productivity", None)
return productivity return productivity
def get_parent_productivity(resource):
if not resource.Nests:
return
else:
parent_resource = resource.Nests[0].RelatingObject
productivity = ifcopenshell.util.element.get_psets(parent_resource).get("EPset_Productivity", None)
return productivity
def get_unit_consumed(productivity): def get_unit_consumed(productivity):
duration = productivity.get("BaseQuantityConsumed", None) duration = productivity.get("BaseQuantityConsumed", None)