mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-10-02 13:04:49 +00:00
features to guess schedule date range and setup default task columns, and code clean up
This commit is contained in:
@@ -77,6 +77,7 @@ classes = (
|
|||||||
operator.ExportMSP,
|
operator.ExportMSP,
|
||||||
operator.ExportP6,
|
operator.ExportP6,
|
||||||
operator.GenerateGanttChart,
|
operator.GenerateGanttChart,
|
||||||
|
operator.GuessDateRange,
|
||||||
operator.ImportMSP,
|
operator.ImportMSP,
|
||||||
operator.ImportP6,
|
operator.ImportP6,
|
||||||
operator.ImportP6XER,
|
operator.ImportP6XER,
|
||||||
@@ -97,6 +98,7 @@ classes = (
|
|||||||
operator.SelectTaskRelatedProducts,
|
operator.SelectTaskRelatedProducts,
|
||||||
operator.SelectTaskRelatedInputs,
|
operator.SelectTaskRelatedInputs,
|
||||||
operator.SetTaskSortColumn,
|
operator.SetTaskSortColumn,
|
||||||
|
operator.SetupDefaultTaskColumns,
|
||||||
operator.UnassignLagTime,
|
operator.UnassignLagTime,
|
||||||
operator.UnassignPredecessor,
|
operator.UnassignPredecessor,
|
||||||
operator.UnassignProcess,
|
operator.UnassignProcess,
|
||||||
|
|||||||
@@ -71,7 +71,6 @@ def get_nested_tasks(task):
|
|||||||
def get_parent_task(task):
|
def get_parent_task(task):
|
||||||
return task.Nests[0].RelatingObject if task.Nests and task.Nests[0].RelatingObject.is_a("IfcTask") else None
|
return task.Nests[0].RelatingObject if task.Nests and task.Nests[0].RelatingObject.is_a("IfcTask") else None
|
||||||
|
|
||||||
|
|
||||||
def get_task_work_schedule(task):
|
def get_task_work_schedule(task):
|
||||||
parent_task = get_parent_task(task)
|
parent_task = get_parent_task(task)
|
||||||
if parent_task:
|
if parent_task:
|
||||||
@@ -95,11 +94,44 @@ def get_work_schedule_tasks(work_schedule):
|
|||||||
for root_task in get_root_tasks(work_schedule):
|
for root_task in get_root_tasks(work_schedule):
|
||||||
nested_tasks = get_all_nested_tasks(root_task)
|
nested_tasks = get_all_nested_tasks(root_task)
|
||||||
tasks.extend(nested_tasks)
|
tasks.extend(nested_tasks)
|
||||||
|
|
||||||
return tasks
|
return tasks
|
||||||
|
|
||||||
def get_root_tasks(work_schedule):
|
def get_root_tasks(work_schedule):
|
||||||
return [obj for rel in work_schedule.Controls for obj in rel.RelatedObjects if obj.is_a("IfcTask")]
|
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):
|
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)
|
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):
|
class VisualiseWorkScheduleDateRange(bpy.types.Operator):
|
||||||
bl_idname = "bim.visualise_work_schedule_date_range"
|
bl_idname = "bim.visualise_work_schedule_date_range"
|
||||||
bl_label = "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)
|
core.add_task_column(tool.Sequence, self.column_type, self.name, self.data_type)
|
||||||
return {"FINISHED"}
|
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):
|
class RemoveTaskColumn(bpy.types.Operator):
|
||||||
bl_idname = "bim.remove_task_column"
|
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
|
row.operator("bim.remove_task", text="", icon="X").task = ifc_definition_id
|
||||||
|
|
||||||
def draw_column_ui(self):
|
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 = self.layout.row(align=True)
|
||||||
row.prop(self.props, "column_types", text="")
|
row.prop(self.props, "column_types", text="")
|
||||||
column_type = self.props.column_types
|
column_type = self.props.column_types
|
||||||
if self.props.column_types == "IfcTask":
|
if column_type == "IfcTask":
|
||||||
row.prop(self.props, "task_columns", text="")
|
row.prop(self.props, "task_columns", text="")
|
||||||
name, data_type = self.props.task_columns.split("/")
|
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="")
|
row.prop(self.props, "task_time_columns", text="")
|
||||||
name, data_type = self.props.task_time_columns.split("/")
|
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="")
|
row.prop(self.props, "other_columns", text="")
|
||||||
column_type, name = self.props.other_columns.split(".")
|
column_type, name = self.props.other_columns.split(".")
|
||||||
data_type = "string"
|
data_type = "string"
|
||||||
@@ -223,6 +225,8 @@ class BIM_PT_work_schedules(Panel):
|
|||||||
op.target_prop = "BIMWorkScheduleProperties.visualisation_start"
|
op.target_prop = "BIMWorkScheduleProperties.visualisation_start"
|
||||||
op = row.operator("bim.datepicker", text=self.props.visualisation_finish or "Finish Date", icon="FF")
|
op = row.operator("bim.datepicker", text=self.props.visualisation_finish or "Finish Date", icon="FF")
|
||||||
op.target_prop = "BIMWorkScheduleProperties.visualisation_finish"
|
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 = row.operator("bim.visualise_work_schedule_date", text="", icon="RESTRICT_RENDER_OFF")
|
||||||
op.work_schedule = self.props.active_work_schedule_id
|
op.work_schedule = self.props.active_work_schedule_id
|
||||||
op = row.operator("bim.visualise_work_schedule_date_range", text="", icon="OUTLINER_OB_CAMERA")
|
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",
|
"active_task_index",
|
||||||
)
|
)
|
||||||
row = self.layout.row()
|
row = self.layout.row()
|
||||||
row.operator("bim.expand_all_tasks", text="Expand All Tasks")
|
row.operator("bim.expand_all_tasks", text="Expand All")
|
||||||
row.operator("bim.contract_all_tasks", text="Contract All Tasks")
|
row.operator("bim.contract_all_tasks", text="Contract All")
|
||||||
if self.props.active_task_id and self.props.editing_task_type == "ATTRIBUTES":
|
if self.props.active_task_id and self.props.editing_task_type == "ATTRIBUTES":
|
||||||
self.draw_editable_task_attributes_ui()
|
self.draw_editable_task_attributes_ui()
|
||||||
elif self.props.active_task_id and self.props.editing_task_type == "CALENDAR":
|
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)
|
is_work_schedule_active = sequence.is_work_schedule_active(work_schedule)
|
||||||
if is_work_schedule_active:
|
if is_work_schedule_active:
|
||||||
sequence.highlight_task(task)
|
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()
|
||||||
@@ -474,7 +474,6 @@ class Sequence:
|
|||||||
def get_work_plan_attributes(cls): pass
|
def get_work_plan_attributes(cls): pass
|
||||||
def load_work_plan_attributes(cls, work_plan): pass
|
def load_work_plan_attributes(cls, work_plan): pass
|
||||||
def get_direct_nested_tasks(cls, task):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 enable_editing_work_plan(cls, work_plan): pass
|
||||||
def disable_editing_work_plan(cls): pass
|
def disable_editing_work_plan(cls): pass
|
||||||
def enable_editing_work_plan_schedules(cls, work_plan): 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 get_work_schedule(cls, task): pass
|
||||||
def is_work_schedule_active(cls, work_schedule): pass
|
def is_work_schedule_active(cls, work_schedule): pass
|
||||||
def highlight_task(cls, task): 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
|
@interface
|
||||||
|
|||||||
@@ -127,20 +127,11 @@ class Sequence(blenderbim.core.tool.Sequence):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def create_task_tree(cls, work_schedule):
|
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()
|
bpy.context.scene.BIMTaskTreeProperties.tasks.clear()
|
||||||
props = bpy.context.scene.BIMWorkScheduleProperties
|
props = bpy.context.scene.BIMWorkScheduleProperties
|
||||||
cls.contracted_tasks = json.loads(props.contracted_tasks)
|
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:
|
if not related_objects_ids:
|
||||||
return
|
return
|
||||||
cls.sort_keys = {i: cls.get_sort_key(tool.Ifc.get().by_id(i)) for i in related_objects_ids}
|
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
|
@classmethod
|
||||||
def get_direct_nested_tasks(cls, task):
|
def get_direct_nested_tasks(cls, task):
|
||||||
return helper.get_nested_tasks(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
|
@classmethod
|
||||||
def get_direct_task_outputs(cls, task):
|
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
|
@classmethod
|
||||||
def get_task_outputs(cls, task):
|
def get_task_outputs(cls, task):
|
||||||
if bpy.context.scene.BIMWorkScheduleProperties.is_nested_task_outputs:
|
is_deep = bpy.context.scene.BIMWorkScheduleProperties.is_nested_task_outputs
|
||||||
nested_tasks = cls.get_all_nested_tasks(task)
|
return helper.get_task_outputs(task, is_deep)
|
||||||
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
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_task_resources(cls, task):
|
def get_task_resources(cls, task):
|
||||||
@@ -719,6 +700,30 @@ class Sequence(blenderbim.core.tool.Sequence):
|
|||||||
new.name = f"{column_type}.{name}"
|
new.name = f"{column_type}.{name}"
|
||||||
new.data_type = data_type
|
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
|
@classmethod
|
||||||
def remove_task_column(cls, name):
|
def remove_task_column(cls, name):
|
||||||
props = bpy.context.scene.BIMWorkScheduleProperties
|
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
|
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
|
@classmethod
|
||||||
def highlight_task(cls, task):
|
def highlight_task(cls, task):
|
||||||
def expand_ancestors(task):
|
def expand_ancestors(task):
|
||||||
@@ -787,3 +784,20 @@ class Sequence(blenderbim.core.tool.Sequence):
|
|||||||
expand_ancestors(task)
|
expand_ancestors(task)
|
||||||
task_index = [item.ifc_definition_id for item in task_props.tasks].index(task.id()) or 0
|
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
|
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)
|
||||||
Reference in New Issue
Block a user