mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-09 09:21:46 +00:00
Bonsai: allow 4D animation at parent task granularity
For large schedules the reporter of #2381 wants to visualise the construction sequence at a higher level, without the detailed order of subtasks. Add an Aggregate Collapsed Tasks option to the animation settings. When enabled, any task collapsed in the task tree animates as a single unit: products assigned to its nested tasks all use the collapsed task's derived date range. The task tree's expand and collapse state therefore selects the granularity per branch, and the default (everything expanded, option off) keeps existing behaviour. Each product keeps the PredefinedType of its own task, so demolition subtasks still animate as demolition within the aggregated window. Generated with the assistance of an AI coding tool.
This commit is contained in:
@@ -542,6 +542,12 @@ class BIMWorkScheduleProperties(PropertyGroup):
|
||||
should_auto_select: BoolProperty(
|
||||
name="Auto Select", description="Auto select elements when task is selected", default=False
|
||||
)
|
||||
should_aggregate_contracted_tasks: BoolProperty(
|
||||
name="Aggregate Collapsed Tasks",
|
||||
description="Animate tasks collapsed in the task tree as single units, "
|
||||
"using the collapsed task's derived date range for all products of its nested tasks",
|
||||
default=False,
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
work_schedule_predefined_types: str
|
||||
@@ -602,6 +608,8 @@ class BIMWorkScheduleProperties(PropertyGroup):
|
||||
show_task_operators: bool
|
||||
should_show_schedule_baseline_ui: bool
|
||||
filter_by_active_schedule: bool
|
||||
should_auto_select: bool
|
||||
should_aggregate_contracted_tasks: bool
|
||||
|
||||
|
||||
class BIMTaskTreeProperties(PropertyGroup):
|
||||
|
||||
@@ -585,6 +585,9 @@ class BIM_PT_animation_tools(Panel):
|
||||
row.label(text="Display Settings")
|
||||
row = self.layout.row()
|
||||
row.alignment = "RIGHT"
|
||||
row.prop(self.props, "should_aggregate_contracted_tasks", icon="COLLAPSEMENU")
|
||||
row = self.layout.row()
|
||||
row.alignment = "RIGHT"
|
||||
row.prop(self.animation_props, "should_show_task_bar_options", text="Task Bars", icon="NLA_PUSHDOWN")
|
||||
if self.animation_props.should_show_task_bar_options:
|
||||
row = self.layout.row()
|
||||
|
||||
@@ -1335,6 +1335,9 @@ class Sequence(bonsai.core.tool.Sequence):
|
||||
@classmethod
|
||||
def get_animation_product_frames(cls, work_schedule: ifcopenshell.entity_instance, settings: dict[str, Any]):
|
||||
def preprocess_task(task):
|
||||
if task.id() in contracted_tasks and ifcopenshell.util.sequence.get_nested_tasks(task):
|
||||
preprocess_aggregated_task(task)
|
||||
return
|
||||
for subtask in ifcopenshell.util.sequence.get_nested_tasks(task):
|
||||
preprocess_task(subtask)
|
||||
start = ifcopenshell.util.sequence.derive_date(task, "ScheduleStart", is_earliest=True)
|
||||
@@ -1346,6 +1349,19 @@ class Sequence(bonsai.core.tool.Sequence):
|
||||
for input in cls.get_task_inputs(task):
|
||||
add_product_frame(input.id(), task.PredefinedType, start, finish, "input")
|
||||
|
||||
def preprocess_aggregated_task(task):
|
||||
# A collapsed task animates as a single unit: all products of its
|
||||
# nested tasks use the collapsed task's derived date range.
|
||||
start = ifcopenshell.util.sequence.derive_date(task, "ScheduleStart", is_earliest=True)
|
||||
finish = ifcopenshell.util.sequence.derive_date(task, "ScheduleFinish", is_latest=True)
|
||||
if not start or not finish:
|
||||
return
|
||||
for subtask in [task, *ifcopenshell.util.sequence.get_all_nested_tasks(task)]:
|
||||
for output in ifcopenshell.util.sequence.get_task_outputs(subtask):
|
||||
add_product_frame(output.id(), subtask.PredefinedType, start, finish, "output")
|
||||
for input in ifcopenshell.util.sequence.get_task_inputs(subtask):
|
||||
add_product_frame(input.id(), subtask.PredefinedType, start, finish, "input")
|
||||
|
||||
def add_product_frame(product_id, type, product_start, product_finish, relationship):
|
||||
product_frames.setdefault(product_id, []).append(
|
||||
{
|
||||
@@ -1363,6 +1379,10 @@ class Sequence(bonsai.core.tool.Sequence):
|
||||
)
|
||||
|
||||
product_frames = {}
|
||||
contracted_tasks: set[int] = set()
|
||||
props = cls.get_work_schedule_props()
|
||||
if props.should_aggregate_contracted_tasks:
|
||||
contracted_tasks = set(json.loads(props.contracted_tasks))
|
||||
for root_task in ifcopenshell.util.sequence.get_root_tasks(work_schedule):
|
||||
preprocess_task(root_task)
|
||||
return product_frames
|
||||
|
||||
Reference in New Issue
Block a user