mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-09 09:21:46 +00:00
Optimisations for construction sequencing task trees where there are thousands of tasks
This commit is contained in:
@@ -42,10 +42,12 @@ classes = (
|
||||
operator.UnassignProduct,
|
||||
operator.GenerateGanttChart,
|
||||
operator.ImportP6,
|
||||
operator.LoadTaskProperties,
|
||||
prop.WorkPlan,
|
||||
prop.BIMWorkPlanProperties,
|
||||
prop.Task,
|
||||
prop.BIMWorkScheduleProperties,
|
||||
prop.BIMTaskTreeProperties,
|
||||
prop.WorkCalendar,
|
||||
prop.BIMWorkCalendarProperties,
|
||||
ui.BIM_PT_work_plans,
|
||||
@@ -64,6 +66,7 @@ def menu_func_import(self, context):
|
||||
def register():
|
||||
bpy.types.Scene.BIMWorkPlanProperties = bpy.props.PointerProperty(type=prop.BIMWorkPlanProperties)
|
||||
bpy.types.Scene.BIMWorkScheduleProperties = bpy.props.PointerProperty(type=prop.BIMWorkScheduleProperties)
|
||||
bpy.types.Scene.BIMTaskTreeProperties = bpy.props.PointerProperty(type=prop.BIMTaskTreeProperties)
|
||||
bpy.types.Scene.BIMWorkCalendarProperties = bpy.props.PointerProperty(type=prop.BIMWorkCalendarProperties)
|
||||
bpy.types.TOPBAR_MT_file_import.append(menu_func_import)
|
||||
|
||||
@@ -71,5 +74,6 @@ def register():
|
||||
def unregister():
|
||||
del bpy.types.Scene.BIMWorkPlanProperties
|
||||
del bpy.types.Scene.BIMWorkScheduleProperties
|
||||
del bpy.types.Scene.BIMTaskTreeProperties
|
||||
del bpy.types.Scene.BIMWorkCalendarProperties
|
||||
bpy.types.TOPBAR_MT_file_import.remove(menu_func_import)
|
||||
|
||||
@@ -223,32 +223,22 @@ class EnableEditingTasks(bpy.types.Operator):
|
||||
|
||||
def execute(self, context):
|
||||
self.props = context.scene.BIMWorkScheduleProperties
|
||||
self.tprops = context.scene.BIMTaskTreeProperties
|
||||
self.props.active_work_schedule_id = self.work_schedule
|
||||
while len(self.props.tasks) > 0:
|
||||
self.props.tasks.remove(0)
|
||||
while len(self.tprops.tasks) > 0:
|
||||
self.tprops.tasks.remove(0)
|
||||
|
||||
self.contracted_tasks = json.loads(self.props.contracted_tasks)
|
||||
for related_object_id in Data.work_schedules[self.work_schedule]["RelatedObjects"]:
|
||||
self.create_new_task_li(related_object_id, 0)
|
||||
bpy.ops.bim.load_task_properties()
|
||||
self.props.is_editing = "TASKS"
|
||||
return {"FINISHED"}
|
||||
|
||||
def create_new_task_li(self, related_object_id, level_index):
|
||||
task = Data.tasks[related_object_id]
|
||||
new = self.props.tasks.add()
|
||||
new = self.tprops.tasks.add()
|
||||
new.ifc_definition_id = related_object_id
|
||||
new.name = task["Name"] or "Unnamed"
|
||||
new.identification = task["Identification"] or "XXX"
|
||||
if task["TaskTime"]:
|
||||
task_time = Data.task_times[task["TaskTime"]]
|
||||
new.start = self.canonicalise_time(task_time["ScheduleStart"])
|
||||
new.finish = self.canonicalise_time(task_time["ScheduleFinish"])
|
||||
# TODO: duration
|
||||
new.duration = "-"
|
||||
else:
|
||||
new.start = "-"
|
||||
new.finish = "-"
|
||||
new.duration = "-"
|
||||
new.is_expanded = related_object_id not in self.contracted_tasks
|
||||
new.level_index = level_index
|
||||
if task["RelatedObjects"]:
|
||||
@@ -258,6 +248,38 @@ class EnableEditingTasks(bpy.types.Operator):
|
||||
self.create_new_task_li(related_object_id, level_index + 1)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class LoadTaskProperties(bpy.types.Operator):
|
||||
bl_idname = "bim.load_task_properties"
|
||||
bl_label = "Load Task Properties"
|
||||
task: bpy.props.IntProperty()
|
||||
|
||||
def execute(self, context):
|
||||
self.props = context.scene.BIMWorkScheduleProperties
|
||||
self.tprops = context.scene.BIMTaskTreeProperties
|
||||
self.props.is_task_update_enabled = False
|
||||
for item in self.tprops.tasks:
|
||||
if self.task and item.ifc_definition_id != self.task:
|
||||
continue
|
||||
task = Data.tasks[item.ifc_definition_id]
|
||||
item.name = task["Name"] or "Unnamed"
|
||||
item.identification = task["Identification"] or "XXX"
|
||||
if self.props.active_task_id:
|
||||
item.is_predecessor = self.props.active_task_id in task["IsPredecessorTo"]
|
||||
item.is_successor = self.props.active_task_id in task["IsSuccessorFrom"]
|
||||
if task["TaskTime"]:
|
||||
task_time = Data.task_times[task["TaskTime"]]
|
||||
item.start = self.canonicalise_time(task_time["ScheduleStart"])
|
||||
item.finish = self.canonicalise_time(task_time["ScheduleFinish"])
|
||||
# TODO: duration
|
||||
item.duration = "-"
|
||||
else:
|
||||
item.start = "-"
|
||||
item.finish = "-"
|
||||
item.duration = "-"
|
||||
self.props.is_task_update_enabled = True
|
||||
return {"FINISHED"}
|
||||
|
||||
def canonicalise_time(self, time):
|
||||
if not time:
|
||||
return "-"
|
||||
@@ -400,6 +422,7 @@ class EnableEditingTaskTime(bpy.types.Operator):
|
||||
new.enum_value = data[attribute.name()]
|
||||
props.active_task_time_id = task_time_id
|
||||
props.active_task_id = self.task
|
||||
bpy.ops.bim.load_task_properties()
|
||||
return {"FINISHED"}
|
||||
|
||||
def add_task_time(self):
|
||||
@@ -448,7 +471,7 @@ class EditTaskTime(bpy.types.Operator):
|
||||
)
|
||||
Data.load(IfcStore.get_file())
|
||||
bpy.ops.bim.disable_editing_task_time()
|
||||
bpy.ops.bim.enable_editing_tasks(work_schedule=props.active_work_schedule_id)
|
||||
bpy.ops.bim.load_task_properties(task=props.active_task_id)
|
||||
return {"FINISHED"}
|
||||
|
||||
def convert_strings_to_date_times(self, attributes):
|
||||
@@ -498,6 +521,7 @@ class EnableEditingTask(bpy.types.Operator):
|
||||
if data[attribute.name()]:
|
||||
new.enum_value = data[attribute.name()]
|
||||
props.active_task_id = self.task
|
||||
bpy.ops.bim.load_task_properties()
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
@@ -535,7 +559,7 @@ class EditTask(bpy.types.Operator):
|
||||
)
|
||||
Data.load(IfcStore.get_file())
|
||||
bpy.ops.bim.disable_editing_task()
|
||||
bpy.ops.bim.enable_editing_tasks(work_schedule=props.active_work_schedule_id)
|
||||
bpy.ops.bim.load_task_properties(task=props.active_task_id)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
@@ -554,6 +578,7 @@ class AssignPredecessor(bpy.types.Operator):
|
||||
related_process=IfcStore.get_file().by_id(props.active_task_id),
|
||||
)
|
||||
Data.load(self.file)
|
||||
bpy.ops.bim.load_task_properties(task=self.task)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
@@ -572,6 +597,7 @@ class AssignSuccessor(bpy.types.Operator):
|
||||
related_process=IfcStore.get_file().by_id(self.task),
|
||||
)
|
||||
Data.load(self.file)
|
||||
bpy.ops.bim.load_task_properties(task=self.task)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
@@ -590,6 +616,7 @@ class UnassignPredecessor(bpy.types.Operator):
|
||||
related_process=IfcStore.get_file().by_id(props.active_task_id),
|
||||
)
|
||||
Data.load(self.file)
|
||||
bpy.ops.bim.load_task_properties(task=self.task)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
@@ -608,6 +635,7 @@ class UnassignSuccessor(bpy.types.Operator):
|
||||
related_process=self.file.by_id(self.task),
|
||||
)
|
||||
Data.load(self.file)
|
||||
bpy.ops.bim.load_task_properties(task=self.task)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
|
||||
@@ -18,10 +18,10 @@ from bpy.props import (
|
||||
|
||||
|
||||
def updateTaskName(self, context):
|
||||
if self.name == "Unnamed":
|
||||
props = context.scene.BIMWorkScheduleProperties
|
||||
if not props.is_task_update_enabled or self.name == "Unnamed":
|
||||
return
|
||||
self.file = IfcStore.get_file()
|
||||
props = context.scene.BIMWorkScheduleProperties
|
||||
ifcopenshell.api.run(
|
||||
"sequence.edit_task",
|
||||
self.file,
|
||||
@@ -34,10 +34,10 @@ def updateTaskName(self, context):
|
||||
|
||||
|
||||
def updateTaskIdentification(self, context):
|
||||
if self.identification == "X":
|
||||
props = context.scene.BIMWorkScheduleProperties
|
||||
if not props.is_task_update_enabled or self.identification == "XXX":
|
||||
return
|
||||
self.file = IfcStore.get_file()
|
||||
props = context.scene.BIMWorkScheduleProperties
|
||||
ifcopenshell.api.run(
|
||||
"sequence.edit_task",
|
||||
self.file,
|
||||
@@ -58,6 +58,11 @@ def updateTaskTimeFinish(self, context):
|
||||
|
||||
|
||||
def updateTaskTimeDateTime(self, context, startfinish):
|
||||
props = context.scene.BIMWorkScheduleProperties
|
||||
|
||||
if not props.is_task_update_enabled:
|
||||
return
|
||||
|
||||
def canonicalise_time(time):
|
||||
if not time:
|
||||
return "-"
|
||||
@@ -112,6 +117,8 @@ class Task(PropertyGroup):
|
||||
duration: StringProperty(name="Duration")
|
||||
start: StringProperty(name="Start", update=updateTaskTimeStart)
|
||||
finish: StringProperty(name="Finish", update=updateTaskTimeFinish)
|
||||
is_predecessor: BoolProperty(name="Is Predecessor")
|
||||
is_successor: BoolProperty(name="Is Successor")
|
||||
|
||||
|
||||
class WorkPlan(PropertyGroup):
|
||||
@@ -132,7 +139,6 @@ class BIMWorkScheduleProperties(PropertyGroup):
|
||||
is_editing: StringProperty(name="Is Editing")
|
||||
active_work_schedule_index: IntProperty(name="Active Work Schedules Index")
|
||||
active_work_schedule_id: IntProperty(name="Active Work Schedules Id")
|
||||
tasks: CollectionProperty(name="Tasks", type=Task)
|
||||
active_task_index: IntProperty(name="Active Task Index")
|
||||
active_task_id: IntProperty(name="Active Task Id")
|
||||
task_attributes: CollectionProperty(name="Task Attributes", type=Attribute)
|
||||
@@ -140,6 +146,13 @@ class BIMWorkScheduleProperties(PropertyGroup):
|
||||
active_task_time_id: IntProperty(name="Active Task Id")
|
||||
task_time_attributes: CollectionProperty(name="Task Time Attributes", type=Attribute)
|
||||
contracted_tasks: StringProperty(name="Contracted Task Items", default="[]")
|
||||
is_task_update_enabled: BoolProperty(name="Is Task Update Enabled", default=True)
|
||||
|
||||
|
||||
class BIMTaskTreeProperties(PropertyGroup):
|
||||
# This belongs by itself for performance reasons.
|
||||
# In Blender if you add thousands of tasks it makes other property access in the same group really slow.
|
||||
tasks: CollectionProperty(name="Tasks", type=Task)
|
||||
|
||||
|
||||
class WorkCalendar(PropertyGroup):
|
||||
|
||||
@@ -81,6 +81,7 @@ class BIM_PT_work_schedules(Panel):
|
||||
|
||||
def draw(self, context):
|
||||
self.props = context.scene.BIMWorkScheduleProperties
|
||||
self.tprops = context.scene.BIMTaskTreeProperties
|
||||
|
||||
if not Data.is_loaded:
|
||||
Data.load(IfcStore.get_file())
|
||||
@@ -130,7 +131,7 @@ class BIM_PT_work_schedules(Panel):
|
||||
self.layout.template_list(
|
||||
"BIM_UL_tasks",
|
||||
"",
|
||||
self.props,
|
||||
self.tprops,
|
||||
"tasks",
|
||||
self.props,
|
||||
"active_task_index",
|
||||
@@ -214,7 +215,7 @@ class BIM_UL_tasks(UIList):
|
||||
row.operator("bim.edit_task", text="", icon="CHECKMARK")
|
||||
row.operator("bim.disable_editing_task", text="", icon="CANCEL")
|
||||
elif props.active_task_id:
|
||||
if props.active_task_id in Data.tasks[item.ifc_definition_id]["IsPredecessorTo"]:
|
||||
if item.is_predecessor:
|
||||
row.operator(
|
||||
"bim.unassign_predecessor", text="", icon="BACK", emboss=False
|
||||
).task = item.ifc_definition_id
|
||||
@@ -223,7 +224,7 @@ class BIM_UL_tasks(UIList):
|
||||
"bim.assign_predecessor", text="", icon="TRACKING_BACKWARDS", emboss=False
|
||||
).task = item.ifc_definition_id
|
||||
|
||||
if props.active_task_id in Data.tasks[item.ifc_definition_id]["IsSuccessorFrom"]:
|
||||
if item.is_successor:
|
||||
row.operator(
|
||||
"bim.unassign_successor", text="", icon="FORWARD", emboss=False
|
||||
).task = item.ifc_definition_id
|
||||
|
||||
Reference in New Issue
Block a user