From 0a7ef80ca7a4ebb4f47003a37cd875173c28e81f Mon Sep 17 00:00:00 2001 From: Sigma Dimensions <79010126+myoualid@users.noreply.github.com> Date: Fri, 5 May 2023 18:26:32 +0100 Subject: [PATCH] BBIM4D: Enable filtering by active work schedule when retrieve tasks related to objects --- .../blenderbim/bim/module/sequence/prop.py | 1 + .../blenderbim/bim/module/sequence/ui.py | 2 +- src/blenderbim/blenderbim/core/sequence.py | 8 +- src/blenderbim/blenderbim/core/tool.py | 6 +- src/blenderbim/blenderbim/tool/sequence.py | 11 +- .../ifcopenshell/util/sequence.py | 104 ++++++++++++++---- 6 files changed, 103 insertions(+), 29 deletions(-) diff --git a/src/blenderbim/blenderbim/bim/module/sequence/prop.py b/src/blenderbim/blenderbim/bim/module/sequence/prop.py index cf81f8da40..e6ce095872 100644 --- a/src/blenderbim/blenderbim/bim/module/sequence/prop.py +++ b/src/blenderbim/blenderbim/bim/module/sequence/prop.py @@ -420,6 +420,7 @@ class BIMWorkScheduleProperties(PropertyGroup): 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) + filter_by_active_schedule: BoolProperty(name="Filter By Active Schedule", default=False) class BIMTaskTreeProperties(PropertyGroup): diff --git a/src/blenderbim/blenderbim/bim/module/sequence/ui.py b/src/blenderbim/blenderbim/bim/module/sequence/ui.py index 97a53930c9..ca667dc6bf 100644 --- a/src/blenderbim/blenderbim/bim/module/sequence/ui.py +++ b/src/blenderbim/blenderbim/bim/module/sequence/ui.py @@ -977,7 +977,7 @@ class BIM_PT_4D_Tools(Panel): self.props = context.scene.BIMWorkScheduleProperties row = self.layout.row() row.operator("bim.load_product_related_tasks", text="Load Tasks", icon="FILE_REFRESH") - + row.prop(self.props, "filter_by_active_schedule", text="Filter by Active Schedule") grid = self.layout.grid_flow(columns=2, even_columns=True) col1 = grid.column() col1.label(text="Product Input Tasks") diff --git a/src/blenderbim/blenderbim/core/sequence.py b/src/blenderbim/blenderbim/core/sequence.py index dd039d9846..f25bf70c7e 100644 --- a/src/blenderbim/blenderbim/core/sequence.py +++ b/src/blenderbim/blenderbim/core/sequence.py @@ -553,7 +553,13 @@ def generate_gantt_chart(sequence, work_schedule): def load_product_related_tasks(sequence, product=None): - sequence.load_product_related_tasks(product) + filter_by_schedule = sequence.is_filter_by_active_schedule() + if filter_by_schedule: + work_schedule = sequence.get_active_work_schedule() + task_inputs, task_ouputs = sequence.get_tasks_for_product(product, work_schedule) + else: + task_inputs, task_ouputs = sequence.get_tasks_for_product(product) + sequence.load_product_related_tasks(task_inputs, task_ouputs) def reorder_task_nesting(ifc, sequence, task, new_index): diff --git a/src/blenderbim/blenderbim/core/tool.py b/src/blenderbim/blenderbim/core/tool.py index efdbb07122..e6cb519f11 100644 --- a/src/blenderbim/blenderbim/core/tool.py +++ b/src/blenderbim/blenderbim/core/tool.py @@ -641,7 +641,6 @@ class Sequence: def contract_task(cls, task): pass def create_bars(cls, tasks): pass def create_new_task_json(cls, task, json, type_map=None): pass - def load_task_tree(cls, work_schedule): pass def create_tasks_json(cls, work_schedule=None): pass def disable_editing_rel_sequence(cls): pass def disable_editing_task_animation_colors(cls): pass @@ -656,10 +655,10 @@ class Sequence: def enable_editing_rel_sequence_attributes(cls, rel_sequence): pass def enable_editing_sequence_lag_time(cls, rel_sequence): pass def enable_editing_task_animation_colors(cls): pass + def enable_editing_task_attributes(cls, task): pass def enable_editing_task_calendar(cls, task): pass def enable_editing_task_sequence(cls, task): pass def enable_editing_task_time(cls, task): pass - def enable_editing_task_attributes(cls, task): pass def enable_editing_work_calendar_times(cls, work_calendar): pass def enable_editing_work_calendar(cls, work_calendar): pass def enable_editing_work_plan_schedules(cls, work_plan): pass @@ -695,6 +694,7 @@ class Sequence: def get_task_resources(cls, task):pass def get_task_time_attributes(cls): pass def get_task_time(cls, task): pass + def get_tasks_for_product(cls, product, work_schedule): pass def get_work_calendar_attributes(cls): pass def get_work_plan_attributes(cls): pass def get_work_schedule_attributes(cls): pass @@ -704,6 +704,7 @@ class Sequence: def guess_date_range(cls, work_schedule): pass def has_task_assignments(cls, product, cost_schedule=None): pass def highlight_task(cls, task): pass + def is_filter_by_active_schedule(cls): pass def is_work_schedule_active(cls, work_schedule): pass def load_lag_time_attributes(cls, lag_time): pass def load_product_related_tasks(cls, product): pass @@ -716,6 +717,7 @@ class Sequence: def load_task_properties(cls, task): pass def load_task_resources(cls,resources): pass def load_task_time_attributes(cls, task_time): pass + def load_task_tree(cls, work_schedule): pass def load_work_calendar_attributes(cls, work_calendar): pass def load_work_plan_attributes(cls, work_plan): pass def load_work_schedule_attributes(cls, work_schedule): pass diff --git a/src/blenderbim/blenderbim/tool/sequence.py b/src/blenderbim/blenderbim/tool/sequence.py index 46b7876a55..3634d7efbd 100644 --- a/src/blenderbim/blenderbim/tool/sequence.py +++ b/src/blenderbim/blenderbim/tool/sequence.py @@ -1555,11 +1555,18 @@ class Sequence(blenderbim.core.tool.Sequence): webbrowser.open("file://" + os.path.join(bpy.context.scene.BIMProperties.data_dir, "gantt", "index.html")) @classmethod - def load_product_related_tasks(cls, product): + def is_filter_by_active_schedule(cls): + return bpy.context.scene.BIMWorkScheduleProperties.filter_by_active_schedule + + @classmethod + def get_tasks_for_product(cls, product, work_schedule=None): + return ifcopenshell.util.sequence.get_tasks_for_product(product, work_schedule) + + @classmethod + def load_product_related_tasks(cls, task_inputs, task_ouputs): props = bpy.context.scene.BIMWorkScheduleProperties props.product_input_tasks.clear() props.product_output_tasks.clear() - task_inputs, task_ouputs = ifcopenshell.util.sequence.get_tasks_for_product(product) for task in task_inputs or []: new = props.product_input_tasks.add() new.name = task.Name or "Unnamed" diff --git a/src/ifcopenshell-python/ifcopenshell/util/sequence.py b/src/ifcopenshell-python/ifcopenshell/util/sequence.py index f03a39e79e..27db7330d5 100644 --- a/src/ifcopenshell-python/ifcopenshell/util/sequence.py +++ b/src/ifcopenshell-python/ifcopenshell/util/sequence.py @@ -237,15 +237,14 @@ def is_work_time_applicable_to_day(work_time, day): def get_task_work_schedule(task): parent_task = get_parent_task(task) if parent_task: - get_task_work_schedule(parent_task) + return get_task_work_schedule(parent_task) or get_task_work_schedule(task) else: - schedules = [ - rel.RelatingControl - for rel in task.HasAssignments - if rel.is_a("IfcRelAssignsToControl") - and rel.RelatingControl.is_a("IfcWorkSchedule") - ] - return schedules + for rel in task.HasAssignments: + if rel.is_a("IfcRelAssignsToControl") and rel.RelatingControl.is_a( + "IfcWorkSchedule" + ): + return rel.RelatingControl + return None def get_nested_tasks(task): @@ -332,39 +331,98 @@ def get_task_outputs(task, is_deep=False): for output in get_direct_task_outputs(nested_task) ] + def get_task_inputs(task, is_deep=False): if not is_deep: - return [object for rel in task.OperatesOn if rel.is_a("IfcRelAssignsToProcess") for object in rel.RelatedObjects if object.is_a("IfcProduct")] + return [ + object + for rel in task.OperatesOn + if rel.is_a("IfcRelAssignsToProcess") + for object in rel.RelatedObjects + if object.is_a("IfcProduct") + ] else: return [ output for nested_task in get_all_nested_tasks(task) - for output in [object for rel in nested_task.OperatesOn if rel.is_a("IfcRelAssignsToProcess") for object in rel.RelatedObjects if object.is_a("IfcProduct")] + for output in [ + object + for rel in nested_task.OperatesOn + if rel.is_a("IfcRelAssignsToProcess") + for object in rel.RelatedObjects + if object.is_a("IfcProduct") + ] ] + def get_task_resources(task, is_deep=False): if not is_deep: - return [object for rel in task.OperatesOn if rel.is_a("IfcRelAssignsToProcess") for object in rel.RelatedObjects if object.is_a("IfcResource")] + return [ + object + for rel in task.OperatesOn + if rel.is_a("IfcRelAssignsToProcess") + for object in rel.RelatedObjects + if object.is_a("IfcResource") + ] else: return [ - output + resource for nested_task in get_all_nested_tasks(task) - for output in [object for rel in nested_task.OperatesOn if rel.is_a("IfcRelAssignsToProcess") for object in rel.RelatedObjects if object.is_a("IfcResource")] + for resource in [ + object + for rel in nested_task.OperatesOn + if rel.is_a("IfcRelAssignsToProcess") + for object in rel.RelatedObjects + if object.is_a("IfcResource") + ] ] + def has_task_outputs(task): return len(get_task_outputs(task)) > 0 + def has_task_inputs(task): return len(get_task_inputs(task)) > 0 -def get_tasks_for_product(product): - inputs = [] - outputs = [] - for assignment in product.HasAssignments: - if assignment.is_a("IfcRelAssignsToProcess") and assignment.RelatingProcess.is_a("IfcTask"): - inputs.append(assignment.RelatingProcess) - for reference in product.ReferencedBy: - if reference.is_a("IfcRelAssignsToProduct") and reference.RelatedObjects[0].is_a("IfcTask"): - outputs.extend([obj for obj in reference.RelatedObjects if obj.is_a("IfcTask")]) - return inputs, outputs \ No newline at end of file + +def get_tasks_for_product(product, schedule=None): + """ + Get all tasks assigned to or referenced by the given product. + + Args: + product: An object that is assigned tasks or references tasks. + schedule: An optional string representing the schedule name to filter tasks by. + + Returns: + A tuple of two lists: + - The first list contains all tasks assigned to the product. + - The second list contains all tasks referenced by the product that are part of the given schedule. + """ + inputs = [ + assignement.RelatingProcess + for assignement in product.HasAssignments + if assignement.is_a("IfcRelAssignsToProcess") + and assignement.RelatingProcess.is_a("IfcTask") + ] + outputs = [ + obj + for ref in product.ReferencedBy + if ref.is_a("IfcRelAssignsToProduct") + for obj in ref.RelatedObjects + if obj.is_a("IfcTask") + ] + + if schedule: + inputs = [ + task + for task in inputs + if get_task_work_schedule(task).id() == schedule.id() + ] + outputs = [ + task + for task in outputs + if get_task_work_schedule(task).id() == schedule.id() + ] + + return inputs, outputs