diff --git a/src/blenderbim/blenderbim/bim/module/sequence/operator.py b/src/blenderbim/blenderbim/bim/module/sequence/operator.py index 36cafcc9d8..3b333fca6a 100644 --- a/src/blenderbim/blenderbim/bim/module/sequence/operator.py +++ b/src/blenderbim/blenderbim/bim/module/sequence/operator.py @@ -464,62 +464,9 @@ class GenerateGanttChart(bpy.types.Operator): work_schedule: bpy.props.IntProperty() def execute(self, context): - self.file = IfcStore.get_file() - self.json = [] - self.sequence_type_map = { - None: "FS", - "START_START": "SS", - "START_FINISH": "SF", - "FINISH_START": "FS", - "FINISH_FINISH": "FF", - "USERDEFINED": "FS", - "NOTDEFINED": "FS", - } - Data.load(self.file) - for task_id in Data.work_schedules[self.work_schedule]["RelatedObjects"]: - self.create_new_task_json(task_id) - with open(os.path.join(context.scene.BIMProperties.data_dir, "gantt", "index.html"), "w") as f: - with open(os.path.join(context.scene.BIMProperties.data_dir, "gantt", "index.mustache"), "r") as t: - f.write(pystache.render(t.read(), {"json_data": json.dumps(self.json)})) - webbrowser.open("file://" + os.path.join(context.scene.BIMProperties.data_dir, "gantt", "index.html")) + core.generate_gantt_chart(tool.Sequence, work_schedule=tool.Ifc.get().by_id(self.work_schedule)) return {"FINISHED"} - def create_new_task_json(self, task_id): - task = self.file.by_id(task_id) - data = { - "pID": task.id(), - "pName": task.Name, - "pCaption": task.Name, - "pStart": task.TaskTime.ScheduleStart if task.TaskTime else "", - "pEnd": task.TaskTime.ScheduleFinish if task.TaskTime else "", - "pPlanStart": task.TaskTime.ScheduleStart if task.TaskTime else "", - "pPlanEnd": task.TaskTime.ScheduleFinish if task.TaskTime else "", - "pMile": 1 if task.IsMilestone else 0, - "pComp": 0, - "pGroup": 1 if task.IsNestedBy else 0, - "pParent": task.Nests[0].RelatingObject.id() if task.Nests else 0, - "pOpen": 1, - "pCost": 1, - "ifcduration": task.TaskTime.ScheduleDuration if task.TaskTime else "", - } - if task.TaskTime and task.TaskTime.IsCritical: - data["pClass"] = "gtaskred" - elif data["pGroup"]: - data["pClass"] = "ggroupblack" - elif data["pMile"]: - data["pClass"] = "gmilestone" - else: - data["pClass"] = "gtaskblue" - data["pDepend"] = ",".join( - [ - "{}{}".format(rel.RelatingProcess.id(), self.sequence_type_map[rel.SequenceType]) - for rel in task.IsSuccessorFrom or [] - ] - ) - self.json.append(data) - for task_id in Data.tasks[task_id]["RelatedObjects"]: - self.create_new_task_json(task_id) - class AddWorkCalendar(bpy.types.Operator, tool.Ifc.Operator): bl_idname = "bim.add_work_calendar" @@ -1097,7 +1044,7 @@ class VisualiseWorkScheduleDateRange(bpy.types.Operator): @classmethod def poll(cls, context): has_start, has_finish = bpy.context.scene.BIMWorkScheduleProperties.visualisation_start, bpy.context.scene.BIMWorkScheduleProperties.visualisation_finish - return bool(has_start and has_finish) + return bool(has_start and has_finish) and not "-" in (has_start, has_finish) def execute(self, context): core.visualise_work_schedule_date_range(tool.Sequence, work_schedule=tool.Ifc.get().by_id(self.work_schedule)) @@ -1364,3 +1311,13 @@ class DisableEditingTaskAnimationColors(bpy.types.Operator): def execute(self, context): core.disable_editing_task_animation_colors(tool.Sequence) return {"FINISHED"} + +class CopyTask(bpy.types.Operator): + bl_idname = "bim.copy_task" + bl_label = "Copy Task" + bl_options = {"REGISTER", "UNDO"} + task: bpy.props.IntProperty() + + def execute(self, context): + core.copy_task(tool.Ifc, tool.Sequence, task=tool.Ifc.get().by_id(self.task)) + return {"FINISHED"} \ No newline at end of file diff --git a/src/blenderbim/blenderbim/core/sequence.py b/src/blenderbim/blenderbim/core/sequence.py index 02a8e71385..4ef8bf8720 100644 --- a/src/blenderbim/blenderbim/core/sequence.py +++ b/src/blenderbim/blenderbim/core/sequence.py @@ -500,4 +500,8 @@ def visualise_work_schedule_date_range(sequence, work_schedule=None): product_frames = sequence.get_animation_product_frames(work_schedule, settings) sequence.load_task_animation_colors() sequence.animate_objects(settings, product_frames) - sequence.add_text_animation_handler(settings) \ No newline at end of file + sequence.add_text_animation_handler(settings) + +def generate_gantt_chart(sequence, work_schedule): + json = sequence.create_tasks_json(work_schedule) + sequence.generate_gantt_browser_chart(json) diff --git a/src/blenderbim/blenderbim/core/tool.py b/src/blenderbim/blenderbim/core/tool.py index 9836b795fd..7729de4d07 100644 --- a/src/blenderbim/blenderbim/core/tool.py +++ b/src/blenderbim/blenderbim/core/tool.py @@ -501,7 +501,7 @@ class Sequence: def expand_task(cls, task): pass def find_related_output_tasks(cls, column): pass def get_active_task(cls): pass - def get_active_work_schedule_id(cls): pass + def get_active_work_schedule(cls): pass def get_checked_tasks(cls): pass def get_direct_nested_tasks(cls, task):pass def get_direct_task_outputs(cls, task): pass diff --git a/src/blenderbim/blenderbim/tool/sequence.py b/src/blenderbim/blenderbim/tool/sequence.py index 18ebe6ba86..c2f5a10936 100644 --- a/src/blenderbim/blenderbim/tool/sequence.py +++ b/src/blenderbim/blenderbim/tool/sequence.py @@ -18,10 +18,13 @@ import bpy import re +import os import isodate import ifcopenshell import ifcopenshell.util.sequence import ifcopenshell.util.date +import ifcopenshell.util.element +import ifcopenshell.util.unit import json import blenderbim.core.tool import blenderbim.tool as tool @@ -30,6 +33,8 @@ import blenderbim.bim.module.sequence.helper as helper from dateutil import parser from datetime import datetime import mathutils +import pystache +import webbrowser class Sequence(blenderbim.core.tool.Sequence): @@ -1271,3 +1276,61 @@ class Sequence(blenderbim.core.tool.Sequence): obj.data.BIMDateTextProperties.start = bpy.context.scene.BIMWorkScheduleProperties.visualisation_start obj.data.BIMDateTextProperties.finish = bpy.context.scene.BIMWorkScheduleProperties.visualisation_finish append_handler(animate_text_handler) + + @classmethod + def create_tasks_json(cls, work_schedule=None): + sequence_type_map = { + None: "FS", + "START_START": "SS", + "START_FINISH": "SF", + "FINISH_START": "FS", + "FINISH_FINISH": "FF", + "USERDEFINED": "FS", + "NOTDEFINED": "FS", + } + + tasks_json = [] + for task in ifcopenshell.util.sequence.get_root_tasks(work_schedule): + cls.create_new_task_json(task, tasks_json, sequence_type_map) + return tasks_json + + @classmethod + def create_new_task_json(cls, task, json, type_map=None): + task_time = task.TaskTime + data = { + "pID": task.id(), + "pName": task.Name, + "pCaption": task.Name, + "pStart": task_time.ScheduleStart if task_time else "", + "pEnd": task_time.ScheduleFinish if task_time else "", + "pPlanStart": task_time.ScheduleStart if task_time else "", + "pPlanEnd": task_time.ScheduleFinish if task_time else "", + "pMile": 1 if task.IsMilestone else 0, + "pComp": 0, + "pGroup": 1 if task.IsNestedBy else 0, + "pParent": task.Nests[0].RelatingObject.id() if task.Nests else 0, + "pOpen": 1, + "pCost": 1, + "ifcduration": task_time.ScheduleDuration if task_time else "", + } + + if task_time and task_time.IsCritical: + data["pClass"] = "gtaskred" + elif data["pGroup"]: + data["pClass"] = "ggroupblack" + elif data["pMile"]: + data["pClass"] = "gmilestone" + else: + data["pClass"] = "gtaskblue" + + data["pDepend"] = ",".join([f"{rel.RelatingProcess.id()}{type_map[rel.SequenceType]}" for rel in task.IsSuccessorFrom or []]) + json.append(data) + for nested_task in ifcopenshell.util.sequence.get_nested_tasks(task): + cls.create_new_task_json(nested_task, json, type_map) + + @classmethod + def generate_gantt_browser_chart(cls, task_json): + with open(os.path.join(bpy.context.scene.BIMProperties.data_dir, "gantt", "index.html"), "w") as f: + with open(os.path.join(bpy.context.scene.BIMProperties.data_dir, "gantt", "index.mustache"), "r") as t: + f.write(pystache.render(t.read(), {"json_data": json.dumps(task_json)})) + webbrowser.open("file://" + os.path.join(bpy.context.scene.BIMProperties.data_dir, "gantt", "index.html")) \ No newline at end of file