mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-10 01:41:57 +00:00
BBIM feature to create & view work schedule baselines
This commit is contained in:
@@ -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"
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user