BBIM feature to create & view work schedule baselines

This commit is contained in:
Sigma Dimensions
2023-05-02 02:43:54 +01:00
parent ca77a895e0
commit 1c1706fde3
7 changed files with 190 additions and 63 deletions
@@ -117,6 +117,7 @@ classes = (
operator.DisableEditingTaskAnimationColors,
operator.LoadProductTasks,
operator.HighlightTask,
operator.CreateBaseline,
prop.WorkPlan,
prop.BIMWorkPlanProperties,
prop.Task,
@@ -20,12 +20,14 @@ import bpy
import blenderbim.tool as tool
import ifcopenshell
from ifcopenshell.util.doc import get_predefined_type_doc
import ifcopenshell.util.date as dateutil
def refresh():
SequenceData.is_loaded = False
WorkPlansData.is_loaded = False
TaskICOMData.is_loaded = False
WorkScheduleData.is_loaded = False
class SequenceData:
@@ -245,6 +247,45 @@ class SequenceData:
return results
class WorkScheduleData:
data = {}
is_loaded = False
@classmethod
def load(cls):
cls.data = {
"can_have_baselines": cls.can_have_baselines(),
"active_work_schedule_baselines": cls.active_work_schedule_baselines(),
}
cls.is_loaded = True
@classmethod
def can_have_baselines(cls):
if not bpy.context.scene.BIMWorkScheduleProperties.active_work_schedule_id:
return False
return (
tool.Ifc.get().by_id(bpy.context.scene.BIMWorkScheduleProperties.active_work_schedule_id).PredefinedType
== "PLANNED"
)
@classmethod
def active_work_schedule_baselines(cls):
results = []
if not bpy.context.scene.BIMWorkScheduleProperties.active_work_schedule_id:
return []
for rel in tool.Ifc.get().by_id(bpy.context.scene.BIMWorkScheduleProperties.active_work_schedule_id).Declares:
for work_schedule in rel.RelatedObjects:
if work_schedule.PredefinedType == "BASELINE":
results.append(
{
"id": work_schedule.id(),
"name": work_schedule.Name or "Unnamed",
"date": str(dateutil.ifc2datetime(work_schedule.CreationDate)),
}
)
return results
class WorkPlansData:
data = {}
is_loaded = False
@@ -168,15 +168,14 @@ class EnableEditingWorkSchedule(bpy.types.Operator):
return {"FINISHED"}
class EnableEditingWorkScheduleTasks(bpy.types.Operator):
class EnableEditingWorkScheduleTasks(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.enable_editing_work_schedule_tasks"
bl_label = "Enable Editing Work Schedule Tasks"
bl_options = {"REGISTER", "UNDO"}
work_schedule: bpy.props.IntProperty()
def execute(self, context):
def _execute(self, context):
core.enable_editing_work_schedule_tasks(tool.Sequence, work_schedule=tool.Ifc.get().by_id(self.work_schedule))
return {"FINISHED"}
class LoadTaskProperties(bpy.types.Operator):
@@ -1370,3 +1369,23 @@ class ReorderTask(bpy.types.Operator, tool.Ifc.Operator):
)
if isinstance(r, str):
self.report({"WARNING"}, r)
class CreateBaseline(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.create_baseline"
bl_label = "Create Schedule Baseline"
bl_options = {"REGISTER", "UNDO"}
work_schedule: bpy.props.IntProperty()
name: bpy.props.StringProperty()
def _execute(self, context):
core.create_baseline(
tool.Ifc, tool.Sequence, work_schedule=tool.Ifc.get().by_id(self.work_schedule), name=self.name
)
def draw(self, context):
layout = self.layout
layout.prop(self, "name", text="Baseline Name")
def invoke(self, context, event):
return context.window_manager.invoke_props_dialog(self)
@@ -425,6 +425,7 @@ class BIMWorkScheduleProperties(PropertyGroup):
active_product_input_task_index: IntProperty(name="Active Product Input Task Index")
enable_reorder: BoolProperty(name="Enable Reorder", default=False)
show_task_operators: BoolProperty(name="Show Task Options", default=True)
should_show_schedule_baseline_ui: BoolProperty(name="Baselines", default=False)
class BIMTaskTreeProperties(PropertyGroup):
@@ -21,7 +21,7 @@ import blenderbim.bim.helper
from bpy.types import Panel, UIList
from blenderbim.bim.ifc import IfcStore
from blenderbim.bim.helper import draw_attributes
from blenderbim.bim.module.sequence.data import WorkPlansData, SequenceData, TaskICOMData
from blenderbim.bim.module.sequence.data import WorkPlansData, WorkScheduleData, SequenceData, TaskICOMData
class BIM_PT_work_plans(Panel):
@@ -113,6 +113,8 @@ class BIM_PT_work_schedules(Panel):
def draw(self, context):
if not SequenceData.is_loaded:
SequenceData.load()
if not WorkScheduleData.is_loaded:
WorkScheduleData.load()
self.props = context.scene.BIMWorkScheduleProperties
self.tprops = context.scene.BIMTaskTreeProperties
self.animation_props = context.scene.BIMAnimationProperties
@@ -132,68 +134,80 @@ class BIM_PT_work_schedules(Panel):
row.operator("bim.add_work_schedule", text="Add new", icon="ADD")
for work_schedule_id, work_schedule in SequenceData.data["work_schedules"].items():
self.draw_work_schedule_ui(work_schedule_id, work_schedule)
def draw_work_schedule_ui(self, work_schedule_id, work_schedule):
row = self.layout.row(align=True)
row.label(text=work_schedule["Name"] or "Unnamed", icon="LINENUMBERS_ON")
if self.props.active_work_schedule_id == work_schedule_id:
if self.props.editing_type == "WORK_SCHEDULE":
row.operator("bim.edit_work_schedule", text="", icon="CHECKMARK")
elif self.props.editing_type == "TASKS":
grid = self.layout.grid_flow(columns=2, even_columns=True)
if not work_schedule["PredefinedType"] == "BASELINE":
row = self.layout.row(align=True)
row.label(text=work_schedule["Name"] or "Unnamed", icon="LINENUMBERS_ON")
if self.props.active_work_schedule_id == work_schedule_id:
if self.props.editing_type == "WORK_SCHEDULE":
row.operator("bim.edit_work_schedule", text="", icon="CHECKMARK")
elif self.props.editing_type == "TASKS":
grid = self.layout.grid_flow(columns=2, even_columns=True)
col = grid.column()
row1 = col.row(align=True)
row1.alignment = "LEFT"
row1.label(text="Schedule tools")
row1 = col.row(align=True)
row1.alignment = "RIGHT"
row1.operator(
"bim.generate_gantt_chart", text="Generate Gantt", icon="NLA"
col = grid.column()
row1 = col.row(align=True)
row1.alignment = "LEFT"
row1.label(text="Schedule tools")
row1 = col.row(align=True)
row1.alignment = "RIGHT"
row1.operator(
"bim.generate_gantt_chart", text="Generate Gantt", icon="NLA"
).work_schedule = work_schedule_id
row1.operator(
"bim.recalculate_schedule", text="Re-calculate Schedule", icon="FILE_REFRESH"
).work_schedule = work_schedule_id
row2 = col.row(align=True)
row2.alignment = "RIGHT"
row2.operator(
"bim.select_work_schedule_products", text="Select Assigned", icon="RESTRICT_SELECT_OFF"
).work_schedule = work_schedule_id
row2.operator(
"bim.select_unassigned_work_schedule_products",
text="Select Unassigned",
icon="RESTRICT_SELECT_OFF",
).work_schedule = work_schedule_id
if WorkScheduleData.data["can_have_baselines"]:
row3 = col.row()
row3.alignment = "RIGHT"
row3.prop(self.props, "should_show_schedule_baseline_ui", icon="RESTRICT_INSTANCED_OFF")
col = grid.column()
row1 = col.row(align=True)
row1.alignment = "LEFT"
row1.label(text="Settings")
row1 = col.row(align=True)
row1.alignment = "RIGHT"
row1.prop(self.props, "should_show_column_ui", text="Schedule Columns", icon="SHORTDISPLAY")
row2 = col.row(align=True)
row2.prop(
self.props, "should_show_visualisation_ui", text="Animation Options", icon="CAMERA_STEREO"
)
row2.prop(self.props, "should_show_snapshot_ui", text="Snapshot Options", icon="CAMERA_STEREO")
row.operator("bim.disable_editing_work_schedule", text="Disable editing", icon="CANCEL")
else:
row.operator(
"bim.enable_editing_work_schedule_tasks", text="", icon="ACTION"
).work_schedule = work_schedule_id
row1.operator(
"bim.recalculate_schedule", text="Re-calculate Schedule", icon="FILE_REFRESH"
row.operator(
"bim.enable_editing_work_schedule", text="", icon="GREASEPENCIL"
).work_schedule = work_schedule_id
row2 = col.row(align=True)
row2.alignment = "RIGHT"
row2.operator(
"bim.select_work_schedule_products", text="Select Assigned", icon="RESTRICT_SELECT_OFF"
).work_schedule = work_schedule_id
row2.operator(
"bim.select_unassigned_work_schedule_products", text="Select Unassigned", icon="RESTRICT_SELECT_OFF"
).work_schedule = work_schedule_id
col = grid.column()
row1 = col.row(align=True)
row1.alignment = "LEFT"
row1.label(text="Settings")
row1 = col.row(align=True)
row1.alignment = "RIGHT"
row1.prop(self.props, "should_show_column_ui", text="Schedule Columns", icon="SHORTDISPLAY")
row2 = col.row(align=True)
row2.prop(self.props, "should_show_visualisation_ui", text="Animation Options", icon="CAMERA_STEREO")
row2.prop(self.props, "should_show_snapshot_ui", text="Snapshot Options", icon="CAMERA_STEREO")
row.operator("bim.disable_editing_work_schedule", text="Disable editing", icon="CANCEL")
else:
row.operator(
"bim.enable_editing_work_schedule_tasks", text="", icon="ACTION"
).work_schedule = work_schedule_id
row.operator(
"bim.enable_editing_work_schedule", text="", icon="GREASEPENCIL"
).work_schedule = work_schedule_id
row.operator("bim.remove_work_schedule", text="", icon="X").work_schedule = work_schedule_id
row.operator("bim.remove_work_schedule", text="", icon="X").work_schedule = work_schedule_id
if self.props.active_work_schedule_id == work_schedule_id:
if self.props.editing_type == "WORK_SCHEDULE":
self.draw_editable_work_schedule_ui()
elif self.props.editing_type == "TASKS":
if self.props.should_show_column_ui:
if self.props.active_work_schedule_id == work_schedule_id:
if self.props.editing_type == "WORK_SCHEDULE":
self.draw_editable_work_schedule_ui()
elif self.props.editing_type == "TASKS":
self.draw_baseline_ui(work_schedule_id)
self.draw_column_ui()
if self.props.should_show_visualisation_ui:
self.draw_visualisation_ui()
if self.props.should_show_snapshot_ui:
self.draw_snapshot_ui()
self.draw_editable_task_ui(work_schedule_id)
if self.props.should_show_visualisation_ui:
self.draw_visualisation_ui()
if self.props.should_show_snapshot_ui:
self.draw_snapshot_ui()
self.draw_editable_task_ui(work_schedule_id)
else:
self.draw_readonly_work_schedule_ui(work_schedule_id)
def draw_task_operators(self):
row = self.layout.row(align=True)
@@ -229,6 +243,8 @@ class BIM_PT_work_schedules(Panel):
row.operator("bim.remove_task", text="Delete", icon="X").task = ifc_definition_id
def draw_column_ui(self):
if not self.props.should_show_column_ui:
return
row = self.layout.row()
row.operator("bim.setup_default_task_columns", text="Add Default Columns", icon="ANCHOR_BOTTOM")
row.alignment = "RIGHT"
@@ -456,6 +472,48 @@ class BIM_PT_work_schedules(Panel):
def draw_editable_task_time_attributes_ui(self):
blenderbim.bim.helper.draw_attributes(self.props.task_time_attributes, self.layout)
def draw_baseline_ui(self, work_schedule_id):
if not self.props.should_show_schedule_baseline_ui:
return
row3 = self.layout.row()
row3.alignment = "RIGHT"
row3.operator("bim.create_baseline", text="Add Baseline", icon="ADD").work_schedule = work_schedule_id
if WorkScheduleData.data["active_work_schedule_baselines"]:
for baseline in WorkScheduleData.data["active_work_schedule_baselines"]:
baseline_row = self.layout.row()
baseline_row.alignment = "RIGHT"
baseline_row.label(
text="{} @ {}".format(baseline["name"], baseline["date"]), icon="RESTRICT_INSTANCED_OFF"
)
baseline_row.operator("bim.remove_work_schedule", text="", icon="X").work_schedule = baseline["id"]
baseline_row.operator(
"bim.enable_editing_work_schedule_tasks", text="", icon="ACTION"
).work_schedule = baseline["id"]
def draw_readonly_work_schedule_ui(self, work_schedule_id):
if self.props.active_work_schedule_id == work_schedule_id:
row = self.layout.row()
row.alignment = "RIGHT"
row.operator("bim.disable_editing_work_schedule", text="Disable editing", icon="CANCEL")
grid = self.layout.grid_flow(columns=2, even_columns=True)
col = grid.column()
row1 = col.row(align=True)
row1.alignment = "LEFT"
row1.label(text="Settings")
row1 = col.row(align=True)
row1.alignment = "RIGHT"
row1.prop(self.props, "should_show_column_ui", text="Schedule Columns", icon="SHORTDISPLAY")
row2 = col.row(align=True)
if self.props.editing_type == "TASKS":
self.draw_column_ui()
self.layout.template_list(
"BIM_UL_tasks",
"",
self.tprops,
"tasks",
self.props,
"active_task_index",
)
class BIM_PT_task_icom(Panel):
bl_label = "IFC Task ICOM"
+12 -4
View File
@@ -143,6 +143,7 @@ def add_task(ifc, sequence, parent_task=None):
def enable_editing_task(sequence, task=None):
sequence.enable_editing_task(task)
def enable_editing_task_attributes(sequence, task=None):
sequence.load_task_attributes(task)
sequence.enable_editing_task_attributes(task)
@@ -248,7 +249,10 @@ def unassign_input_products(ifc, sequence, spatial, task=None, products=None):
def assign_resource(ifc, sequence, task=None):
resource = sequence.get_selected_resource()
sub_resource = ifc.run(
"resource.add_resource", parent_resource=resource, ifc_class=resource.is_a(), name=resource.Name
"resource.add_resource",
parent_resource=resource,
ifc_class=resource.is_a(),
name="{}/{}".format(resource.Name or "Unnamed", task.Name or ""),
)
ifc.run("sequence.assign_process", relating_process=task, related_object=sub_resource)
resources = sequence.get_task_resources(task)
@@ -552,7 +556,11 @@ def reorder_task_nesting(ifc, sequence, task, new_index):
if is_sorting_enabled or is_sort_reversed:
return "Remove manual sorting"
else:
ifc.run("nest.reorder_nesting", item= task, new_index= new_index)
work_schedule= sequence.get_active_work_schedule()
ifc.run("nest.reorder_nesting", item=task, new_index=new_index)
work_schedule = sequence.get_active_work_schedule()
sequence.load_task_tree(work_schedule)
sequence.load_task_properties()
sequence.load_task_properties()
def create_baseline(ifc, sequence, work_schedule, name):
ifc.run("sequence.create_baseline", work_schedule=work_schedule, name=name)
@@ -336,7 +336,6 @@ class Resource(blenderbim.core.tool.Resource):
current_resource = tool.Resource.get_highlighted_resource()
if current_resource:
productivity = cls.get_productivity(current_resource)
print("Resource:", current_resource, "productivity", productivity)
if productivity:
bpy.context.scene.BIMResourceProductivity.quantity_produced = (
ifcopenshell.util.resource.get_quantity_produced(productivity)