features to guess schedule date range and setup default task columns, and code clean up

This commit is contained in:
Sigma Dimensions
2022-12-26 18:30:25 +01:00
committed by Dion Moult
parent 3fd1209906
commit 8004a45b54
7 changed files with 118 additions and 41 deletions
@@ -77,6 +77,7 @@ classes = (
operator.ExportMSP,
operator.ExportP6,
operator.GenerateGanttChart,
operator.GuessDateRange,
operator.ImportMSP,
operator.ImportP6,
operator.ImportP6XER,
@@ -97,6 +98,7 @@ classes = (
operator.SelectTaskRelatedProducts,
operator.SelectTaskRelatedInputs,
operator.SetTaskSortColumn,
operator.SetupDefaultTaskColumns,
operator.UnassignLagTime,
operator.UnassignPredecessor,
operator.UnassignProcess,
@@ -71,7 +71,6 @@ def get_nested_tasks(task):
def get_parent_task(task):
return task.Nests[0].RelatingObject if task.Nests and task.Nests[0].RelatingObject.is_a("IfcTask") else None
def get_task_work_schedule(task):
parent_task = get_parent_task(task)
if parent_task:
@@ -95,11 +94,44 @@ def get_work_schedule_tasks(work_schedule):
for root_task in get_root_tasks(work_schedule):
nested_tasks = get_all_nested_tasks(root_task)
tasks.extend(nested_tasks)
return tasks
def get_root_tasks(work_schedule):
return [obj for rel in work_schedule.Controls for obj in rel.RelatedObjects if obj.is_a("IfcTask")]
def get_root_tasks_ids(work_schedule):
return [obj.id() for rel in work_schedule.Controls for obj in rel.RelatedObjects if obj.is_a("IfcTask")]
return [obj.id() for rel in work_schedule.Controls for obj in rel.RelatedObjects if obj.is_a("IfcTask")]
def guess_date_range(work_schedule):
earliest = None
latest = None
root_tasks = get_root_tasks(work_schedule)
tasks_with_assignements = []
for task in root_tasks:
if has_task_outputs(task):
tasks_with_assignements.append(task)
for sub_task in get_all_nested_tasks(task):
if has_task_outputs(sub_task):
tasks_with_assignements.append(sub_task)
for task in tasks_with_assignements:
derived_start = derive_date(task, "ScheduleStart", is_earliest=True)
derived_finish = derive_date(task, "ScheduleFinish", is_latest=True)
if derived_start and (not earliest or derived_start < earliest):
earliest = derived_start
if derived_finish and (not latest or derived_finish > latest):
latest = derived_finish
return earliest, latest
def get_direct_task_outputs(task):
return [rel.RelatingProduct for rel in task.HasAssignments if rel.is_a("IfcRelAssignsToProduct")]
def get_task_outputs(task, is_deep=False):
if not is_deep:
return get_direct_task_outputs(task)
else:
nested_tasks = get_all_nested_tasks(task)
return [output for nested_task in nested_tasks for output in get_direct_task_outputs(nested_task)]
def has_task_outputs(task):
return len(get_task_outputs(task)) > 0
@@ -1086,6 +1086,15 @@ class VisualiseWorkScheduleDate(bpy.types.Operator):
self.completed.update(products)
class GuessDateRange(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.guess_date_range"
bl_label = "Guess Work Schedule Date Range"
bl_options = {"REGISTER", "UNDO"}
work_schedule: bpy.props.IntProperty()
def _execute(self, context):
core.guess_date_range(tool.Sequence, work_schedule=tool.Ifc.get().by_id(self.work_schedule))
class VisualiseWorkScheduleDateRange(bpy.types.Operator):
bl_idname = "bim.visualise_work_schedule_date_range"
bl_label = "Visualise Work Schedule Date Range"
@@ -1452,6 +1461,14 @@ class AddTaskColumn(bpy.types.Operator):
core.add_task_column(tool.Sequence, self.column_type, self.name, self.data_type)
return {"FINISHED"}
class SetupDefaultTaskColumns(bpy.types.Operator):
bl_idname = "bim.setup_default_task_columns"
bl_label = "Setip Default Task Columns"
bl_options = {"REGISTER", "UNDO"}
def execute(self, context):
core.setup_default_task_columns(tool.Sequence)
return {"FINISHED"}
class RemoveTaskColumn(bpy.types.Operator):
bl_idname = "bim.remove_task_column"
@@ -193,16 +193,18 @@ class BIM_PT_work_schedules(Panel):
row.operator("bim.remove_task", text="", icon="X").task = ifc_definition_id
def draw_column_ui(self):
row = self.layout.row(align=True)
row.operator("bim.setup_default_task_columns", text="Show Default Columns", icon="ANCHOR_BOTTOM")
row = self.layout.row(align=True)
row.prop(self.props, "column_types", text="")
column_type = self.props.column_types
if self.props.column_types == "IfcTask":
if column_type == "IfcTask":
row.prop(self.props, "task_columns", text="")
name, data_type = self.props.task_columns.split("/")
elif self.props.column_types == "IfcTaskTime":
elif column_type == "IfcTaskTime":
row.prop(self.props, "task_time_columns", text="")
name, data_type = self.props.task_time_columns.split("/")
elif self.props.column_types == "Special":
elif column_type == "Special":
row.prop(self.props, "other_columns", text="")
column_type, name = self.props.other_columns.split(".")
data_type = "string"
@@ -223,6 +225,8 @@ class BIM_PT_work_schedules(Panel):
op.target_prop = "BIMWorkScheduleProperties.visualisation_start"
op = row.operator("bim.datepicker", text=self.props.visualisation_finish or "Finish Date", icon="FF")
op.target_prop = "BIMWorkScheduleProperties.visualisation_finish"
op = row.operator("bim.guess_date_range", text="Guess", icon="FILE_REFRESH")
op.work_schedule = self.props.active_work_schedule_id
op = row.operator("bim.visualise_work_schedule_date", text="", icon="RESTRICT_RENDER_OFF")
op.work_schedule = self.props.active_work_schedule_id
op = row.operator("bim.visualise_work_schedule_date_range", text="", icon="OUTLINER_OB_CAMERA")
@@ -253,8 +257,8 @@ class BIM_PT_work_schedules(Panel):
"active_task_index",
)
row = self.layout.row()
row.operator("bim.expand_all_tasks", text="Expand All Tasks")
row.operator("bim.contract_all_tasks", text="Contract All Tasks")
row.operator("bim.expand_all_tasks", text="Expand All")
row.operator("bim.contract_all_tasks", text="Contract All")
if self.props.active_task_id and self.props.editing_task_type == "ATTRIBUTES":
self.draw_editable_task_attributes_ui()
elif self.props.active_task_id and self.props.editing_task_type == "CALENDAR":
@@ -469,3 +469,10 @@ def highlight_product_related_task(sequence, product_type=None):
is_work_schedule_active = sequence.is_work_schedule_active(work_schedule)
if is_work_schedule_active:
sequence.highlight_task(task)
def guess_date_range(sequence, work_schedule=None):
start, finish = sequence.guess_date_range(work_schedule)
sequence.update_visualisation_date(start,finish)
def setup_default_task_columns(sequence):
sequence.setup_default_task_columns()
+3 -2
View File
@@ -474,7 +474,6 @@ class Sequence:
def get_work_plan_attributes(cls): pass
def load_work_plan_attributes(cls, work_plan): pass
def get_direct_nested_tasks(cls, task):pass
def get_all_nested_tasks(cls, task): pass
def enable_editing_work_plan(cls, work_plan): pass
def disable_editing_work_plan(cls): pass
def enable_editing_work_plan_schedules(cls, work_plan): pass
@@ -544,7 +543,9 @@ class Sequence:
def get_work_schedule(cls, task): pass
def is_work_schedule_active(cls, work_schedule): pass
def highlight_task(cls, task): pass
def setup_default_task_columns(cls): pass
def guess_date_range(cls, task): pass
def update_visualisation_date(cls, date): pass
@interface
+45 -31
View File
@@ -127,20 +127,11 @@ class Sequence(blenderbim.core.tool.Sequence):
@classmethod
def create_task_tree(cls, work_schedule):
def get_root_tasks_ids(work_schedule):
related_objects_ids = []
if work_schedule.Controls:
for rel in work_schedule.Controls:
for obj in rel.RelatedObjects:
if obj.is_a("IfcTask"):
related_objects_ids.append(obj.id())
return related_objects_ids
bpy.context.scene.BIMTaskTreeProperties.tasks.clear()
props = bpy.context.scene.BIMWorkScheduleProperties
cls.contracted_tasks = json.loads(props.contracted_tasks)
related_objects_ids = get_root_tasks_ids(work_schedule)
related_objects_ids = helper.get_root_tasks_ids(work_schedule)
if not related_objects_ids:
return
cls.sort_keys = {i: cls.get_sort_key(tool.Ifc.get().by_id(i)) for i in related_objects_ids}
@@ -466,25 +457,15 @@ class Sequence(blenderbim.core.tool.Sequence):
@classmethod
def get_direct_nested_tasks(cls, task):
return helper.get_nested_tasks(task)
@classmethod
def get_all_nested_tasks(cls, task):
for nested_task in helper.get_nested_tasks(task):
yield nested_task
yield from cls.get_all_nested_tasks(nested_task)
@classmethod
def get_direct_task_outputs(cls, task):
return[rel.RelatingProduct for rel in task.HasAssignments if rel.is_a("IfcRelAssignsToProduct")]
return helper.get_direct_task_outputs(task)
@classmethod
def get_task_outputs(cls, task):
if bpy.context.scene.BIMWorkScheduleProperties.is_nested_task_outputs:
nested_tasks = cls.get_all_nested_tasks(task)
outputs = [output for nested_task in nested_tasks for output in cls.get_direct_task_outputs(nested_task)]
else:
outputs = cls.get_direct_task_outputs(task)
return outputs
is_deep = bpy.context.scene.BIMWorkScheduleProperties.is_nested_task_outputs
return helper.get_task_outputs(task, is_deep)
@classmethod
def get_task_resources(cls, task):
@@ -719,6 +700,30 @@ class Sequence(blenderbim.core.tool.Sequence):
new.name = f"{column_type}.{name}"
new.data_type = data_type
@classmethod
def setup_default_task_columns(cls):
items = [
{
"column_type": "IfcTaskTime",
"name": "ScheduleStart",
},
{
"column_type": "IfcTaskTime",
"name": "ScheduleFinish",
},
{
"column_type": "IfcTaskTime",
"name": "ScheduleDuration",
},
]
props = bpy.context.scene.BIMWorkScheduleProperties
props.columns.clear()
for item in items:
new = props.columns.add()
new.name = f"{item['column_type']}.{item['name']}"
new.data_type = "string"
@classmethod
def remove_task_column(cls, name):
props = bpy.context.scene.BIMWorkScheduleProperties
@@ -759,14 +764,6 @@ class Sequence(blenderbim.core.tool.Sequence):
True if work_schedule.id() == bpy.context.scene.BIMWorkScheduleProperties.active_work_schedule_id else False
)
@classmethod
def get_work_schedule(cls, task):
for rel in task.HasAssignments or []:
if rel.is_a("IfcRelAssignsToControl") and rel.RelatingControl.is_a("IfcWorkSchedule"):
return rel.RelatingControl
for rel in task.Nests or []:
return cls.get_work_schedule(rel.RelatingObject)
@classmethod
def highlight_task(cls, task):
def expand_ancestors(task):
@@ -787,3 +784,20 @@ class Sequence(blenderbim.core.tool.Sequence):
expand_ancestors(task)
task_index = [item.ifc_definition_id for item in task_props.tasks].index(task.id()) or 0
bpy.context.scene.BIMWorkScheduleProperties.active_task_index = task_index
@classmethod
def guess_date_range(cls, work_schedule):
return helper.guess_date_range(work_schedule)
@classmethod
def update_visualisation_date(cls, start_date, finish_date):
def canonicalise_time(time):
if not time:
return "-"
return time.strftime("%d/%m/%y")
print(start_date, finish_date)
props = bpy.context.scene.BIMWorkScheduleProperties
props.visualisation_start = canonicalise_time(start_date)
props.visualisation_finish = canonicalise_time(finish_date)