Files
IfcOpenShell/src/blenderbim/blenderbim/bim/module/sequence/operator.py
T

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

2176 lines
83 KiB
Python
Raw Normal View History

2021-08-17 08:55:29 +10:00
# BlenderBIM Add-on - OpenBIM Blender Add-on
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
#
# This file is part of BlenderBIM Add-on.
#
# BlenderBIM Add-on is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# BlenderBIM Add-on is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
import re
import os
2021-02-17 22:54:11 +11:00
import bpy
2021-04-07 00:04:57 +01:00
import json
import time
import calendar
import isodate
import pystache
import webbrowser
import ifcopenshell.api
import ifcopenshell.util.date
import ifcopenshell.util.sequence
import blenderbim.bim.helper
import blenderbim.bim.module.sequence.helper as helper
2021-04-20 17:11:06 +10:00
from datetime import datetime
from datetime import timedelta
from dateutil import parser, relativedelta
2021-02-17 22:54:11 +11:00
from blenderbim.bim.ifc import IfcStore
from bpy_extras.io_utils import ImportHelper
from ifcopenshell.api.sequence.data import Data
from ifcopenshell.api.resource.data import Data as ResourceData
2021-02-17 22:54:11 +11:00
class AddWorkPlan(bpy.types.Operator):
bl_idname = "bim.add_work_plan"
bl_label = "Add Work Plan"
bl_options = {"REGISTER", "UNDO"}
def execute(self, context):
return IfcStore.execute_ifc_operator(self, context)
def _execute(self, context):
ifcopenshell.api.run("sequence.add_work_plan", IfcStore.get_file())
Data.load(IfcStore.get_file())
return {"FINISHED"}
2021-04-07 00:04:57 +01:00
class EditWorkPlan(bpy.types.Operator):
bl_idname = "bim.edit_work_plan"
bl_options = {"REGISTER", "UNDO"}
2021-04-07 00:04:57 +01:00
bl_label = "Edit Work Plan"
def execute(self, context):
return IfcStore.execute_ifc_operator(self, context)
def _execute(self, context):
2021-04-07 00:04:57 +01:00
props = context.scene.BIMWorkPlanProperties
attributes = blenderbim.bim.helper.export_attributes(props.work_plan_attributes, self.export_attributes)
2021-04-07 00:04:57 +01:00
self.file = IfcStore.get_file()
ifcopenshell.api.run(
"sequence.edit_work_plan",
self.file,
**{"work_plan": self.file.by_id(props.active_work_plan_id), "attributes": attributes},
2021-04-07 00:04:57 +01:00
)
Data.load(IfcStore.get_file())
bpy.ops.bim.disable_editing_work_plan()
2021-04-07 00:04:57 +01:00
return {"FINISHED"}
def export_attributes(self, attributes, prop):
if "Date" in prop.name or "Time" in prop.name:
if prop.is_null:
attributes[prop.name] = None
return True
attributes[prop.name] = helper.parse_datetime(prop.string_value)
return True
elif prop.name == "Duration" or prop.name == "TotalFloat":
if prop.is_null:
attributes[prop.name] = None
return True
attributes[prop.name] = helper.parse_duration(prop.string_value)
return True
class RemoveWorkPlan(bpy.types.Operator):
bl_idname = "bim.remove_work_plan"
bl_label = "Remove Work Plan"
bl_options = {"REGISTER", "UNDO"}
work_plan: bpy.props.IntProperty()
def execute(self, context):
return IfcStore.execute_ifc_operator(self, context)
def _execute(self, context):
2021-04-07 00:04:57 +01:00
self.file = IfcStore.get_file()
ifcopenshell.api.run("sequence.remove_work_plan", self.file, **{"work_plan": self.file.by_id(self.work_plan)})
Data.load(self.file)
2021-04-07 00:04:57 +01:00
return {"FINISHED"}
2021-04-07 00:04:57 +01:00
class EnableEditingWorkPlan(bpy.types.Operator):
bl_idname = "bim.enable_editing_work_plan"
bl_label = "Enable Editing Work Plan"
bl_options = {"REGISTER", "UNDO"}
2021-04-07 00:04:57 +01:00
work_plan: bpy.props.IntProperty()
def execute(self, context):
props = context.scene.BIMWorkPlanProperties
props.work_plan_attributes.clear()
2021-04-07 00:04:57 +01:00
data = Data.work_plans[self.work_plan]
blenderbim.bim.helper.import_attributes("IfcWorkPlan", props.work_plan_attributes, data, self.import_attributes)
2021-04-07 00:04:57 +01:00
props.active_work_plan_id = self.work_plan
2021-04-30 17:40:00 +10:00
props.editing_type = "ATTRIBUTES"
2021-04-07 00:04:57 +01:00
return {"FINISHED"}
def import_attributes(self, name, prop, data):
if name in ["CreationDate", "StartTime", "FinishTime"]:
prop.string_value = "" if prop.is_null else data[name].isoformat()
return True
2021-04-07 00:04:57 +01:00
class DisableEditingWorkPlan(bpy.types.Operator):
bl_idname = "bim.disable_editing_work_plan"
bl_options = {"REGISTER", "UNDO"}
2021-04-07 00:04:57 +01:00
bl_label = "Disable Editing Work Plan"
def execute(self, context):
context.scene.BIMWorkPlanProperties.active_work_plan_id = 0
return {"FINISHED"}
2021-04-07 00:31:16 +01:00
class EnableEditingWorkPlanSchedules(bpy.types.Operator):
bl_idname = "bim.enable_editing_work_plan_schedules"
bl_label = "Enable Editing Work Plan Schedules"
bl_options = {"REGISTER", "UNDO"}
work_plan: bpy.props.IntProperty()
2021-04-28 02:17:08 +00:00
def execute(self, context):
props = context.scene.BIMWorkPlanProperties
props.active_work_plan_id = self.work_plan
2021-04-30 17:40:00 +10:00
props.editing_type = "SCHEDULES"
2021-04-28 02:17:08 +00:00
return {"FINISHED"}
class AssignWorkSchedule(bpy.types.Operator):
bl_idname = "bim.assign_work_schedule"
bl_label = "Assign Work Schedule"
bl_options = {"REGISTER", "UNDO"}
work_plan: bpy.props.IntProperty()
2021-04-28 02:17:08 +00:00
work_schedule: bpy.props.IntProperty()
def execute(self, context):
return IfcStore.execute_ifc_operator(self, context)
def _execute(self, context):
self.file = IfcStore.get_file()
2021-04-28 02:17:08 +00:00
ifcopenshell.api.run(
"aggregate.assign_object",
self.file,
**{
"relating_object": self.file.by_id(self.work_plan),
"product": self.file.by_id(self.work_schedule),
},
)
Data.load(IfcStore.get_file())
return {"FINISHED"}
class UnassignWorkSchedule(bpy.types.Operator):
bl_idname = "bim.unassign_work_schedule"
bl_label = "Unassign Work Schedule"
bl_options = {"REGISTER", "UNDO"}
work_plan: bpy.props.IntProperty()
work_schedule: bpy.props.IntProperty()
def execute(self, context):
return IfcStore.execute_ifc_operator(self, context)
def _execute(self, context):
self.file = IfcStore.get_file()
ifcopenshell.api.run(
"aggregate.unassign_object",
self.file,
**{
"relating_object": self.file.by_id(self.work_plan),
"product": self.file.by_id(self.work_schedule),
},
2021-04-28 02:17:08 +00:00
)
Data.load(IfcStore.get_file())
return {"FINISHED"}
2021-04-28 02:17:08 +00:00
2021-04-07 00:31:16 +01:00
class AddWorkSchedule(bpy.types.Operator):
bl_idname = "bim.add_work_schedule"
bl_label = "Add Work Schedule"
bl_options = {"REGISTER", "UNDO"}
2021-04-07 00:31:16 +01:00
def execute(self, context):
return IfcStore.execute_ifc_operator(self, context)
def _execute(self, context):
ifcopenshell.api.run("sequence.add_work_schedule", IfcStore.get_file())
2021-04-07 00:31:16 +01:00
Data.load(IfcStore.get_file())
return {"FINISHED"}
class EditWorkSchedule(bpy.types.Operator):
bl_idname = "bim.edit_work_schedule"
bl_label = "Edit Work Schedule"
bl_options = {"REGISTER", "UNDO"}
2021-04-07 00:31:16 +01:00
def execute(self, context):
return IfcStore.execute_ifc_operator(self, context)
def _execute(self, context):
2021-04-07 00:31:16 +01:00
props = context.scene.BIMWorkScheduleProperties
attributes = blenderbim.bim.helper.export_attributes(props.work_schedule_attributes, self.export_attributes)
2021-04-07 00:31:16 +01:00
self.file = IfcStore.get_file()
ifcopenshell.api.run(
"sequence.edit_work_schedule",
self.file,
**{"work_schedule": self.file.by_id(props.active_work_schedule_id), "attributes": attributes},
)
2021-04-07 00:31:16 +01:00
Data.load(IfcStore.get_file())
bpy.ops.bim.disable_editing_work_schedule()
2021-04-07 00:31:16 +01:00
return {"FINISHED"}
def export_attributes(self, attributes, prop):
if "Date" in prop.name or "Time" in prop.name:
if prop.is_null:
attributes[prop.name] = None
return True
attributes[prop.name] = helper.parse_datetime(prop.string_value)
return True
elif prop.name == "Duration" or prop.name == "TotalFloat":
if prop.is_null:
attributes[prop.name] = None
return True
attributes[prop.name] = helper.parse_duration(prop.string_value)
return True
2021-04-07 00:31:16 +01:00
class RemoveWorkSchedule(bpy.types.Operator):
bl_idname = "bim.remove_work_schedule"
bl_label = "Remove Work Schedule"
bl_options = {"REGISTER", "UNDO"}
2021-04-07 00:31:16 +01:00
work_schedule: bpy.props.IntProperty()
def execute(self, context):
return IfcStore.execute_ifc_operator(self, context)
def _execute(self, context):
2021-04-07 00:31:16 +01:00
self.file = IfcStore.get_file()
ifcopenshell.api.run(
2021-04-19 10:27:47 +10:00
"sequence.remove_work_schedule", self.file, work_schedule=self.file.by_id(self.work_schedule)
)
Data.load(self.file)
2021-04-07 00:31:16 +01:00
return {"FINISHED"}
2021-04-07 00:31:16 +01:00
class EnableEditingWorkSchedule(bpy.types.Operator):
bl_idname = "bim.enable_editing_work_schedule"
bl_label = "Enable Editing Work Schedule"
bl_options = {"REGISTER", "UNDO"}
2021-04-07 00:31:16 +01:00
work_schedule: bpy.props.IntProperty()
def execute(self, context):
self.props = context.scene.BIMWorkScheduleProperties
self.props.active_work_schedule_id = self.work_schedule
self.props.work_schedule_attributes.clear()
self.enable_editing_work_schedule()
2021-04-30 17:40:00 +10:00
self.props.editing_type = "WORK_SCHEDULE"
return {"FINISHED"}
2021-04-07 00:31:16 +01:00
def enable_editing_work_schedule(self):
2021-04-07 00:31:16 +01:00
data = Data.work_schedules[self.work_schedule]
blenderbim.bim.helper.import_attributes(
"IfcWorkSchedule", self.props.work_schedule_attributes, data, self.import_attributes
)
def import_attributes(self, name, prop, data):
if name in ["CreationDate", "StartTime", "FinishTime"]:
prop.string_value = "" if prop.is_null else data[name].isoformat()
return True
class EnableEditingTasks(bpy.types.Operator):
bl_idname = "bim.enable_editing_tasks"
bl_label = "Enable Editing Tasks"
bl_options = {"REGISTER", "UNDO"}
work_schedule: bpy.props.IntProperty()
def execute(self, context):
self.props = context.scene.BIMWorkScheduleProperties
self.tprops = context.scene.BIMTaskTreeProperties
self.props.active_work_schedule_id = self.work_schedule
self.tprops.tasks.clear()
self.contracted_tasks = json.loads(self.props.contracted_tasks)
self.sort_keys = {
i: self.get_sort_key(Data.tasks[i]) for i in Data.work_schedules[self.work_schedule]["RelatedObjects"]
}
related_object_ids = sorted(self.sort_keys, key=self.natural_sort_key)
if self.props.is_sort_reversed:
related_object_ids.reverse()
for related_object_id in related_object_ids:
self.create_new_task_li(related_object_id, 0)
bpy.ops.bim.load_task_properties()
2021-04-30 17:40:00 +10:00
self.props.editing_type = "TASKS"
2021-04-07 00:31:16 +01:00
return {"FINISHED"}
def create_new_task_li(self, related_object_id, level_index):
task = Data.tasks[related_object_id]
new = self.tprops.tasks.add()
new.ifc_definition_id = related_object_id
new.is_expanded = related_object_id not in self.contracted_tasks
new.level_index = level_index
if task["RelatedObjects"]:
new.has_children = True
if new.is_expanded:
self.sort_keys = {i: self.get_sort_key(Data.tasks[i]) for i in task["RelatedObjects"]}
related_object_ids = sorted(self.sort_keys, key=self.natural_sort_key)
if self.props.is_sort_reversed:
related_object_ids.reverse()
for related_object_id in related_object_ids:
self.create_new_task_li(related_object_id, level_index + 1)
def get_sort_key(self, task):
# Sorting only applies to actual tasks, not the WBS
if task["RelatedObjects"]:
# Sorry for the hack
return "0000000000" + (task["Identification"] or "")
if not self.props.sort_column:
return task["Identification"] or ""
column_type, name = self.props.sort_column.split(".")
if column_type == "IfcTask":
return task.get(name)
elif column_type == "IfcTaskTime" and task.get("TaskTime"):
task_time = Data.task_times[task.get("TaskTime")].get(name)
return task["Identification"] or ""
def natural_sort_key(self, i, _nsre=re.compile("([0-9]+)")):
s = self.sort_keys[i]
return [int(text) if text.isdigit() else text.lower() for text in _nsre.split(s)]
class LoadTaskProperties(bpy.types.Operator):
bl_idname = "bim.load_task_properties"
bl_label = "Load Task Properties"
bl_options = {"REGISTER", "UNDO"}
task: bpy.props.IntProperty()
def execute(self, context):
self.file = IfcStore.get_file()
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 [
Data.sequences[r]["RelatedProcess"] for r in task["IsPredecessorTo"]
]
item.is_successor = self.props.active_task_id in [
Data.sequences[r]["RelatingProcess"] for r in task["IsSuccessorFrom"]
]
calendar = ifcopenshell.util.sequence.derive_calendar(self.file.by_id(item.ifc_definition_id))
if calendar:
calendar = Data.work_calendars[calendar.id()]
if task["HasAssignmentsWorkCalendar"]:
item.calendar = calendar["Name"] or "Unnamed"
else:
item.calendar = ""
item.derived_calendar = calendar["Name"] or "Unnamed" if calendar else ""
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"])
item.duration = (
isodate.duration_isoformat(task_time["ScheduleDuration"]) if task_time["ScheduleDuration"] else "-"
)
else:
derived_start = helper.derive_date(item.ifc_definition_id, "ScheduleStart", is_earliest=True)
derived_finish = helper.derive_date(item.ifc_definition_id, "ScheduleFinish", is_latest=True)
item.derived_start = self.canonicalise_time(derived_start) if derived_start else ""
item.derived_finish = self.canonicalise_time(derived_finish) if derived_finish else ""
if derived_start and derived_finish and calendar:
derived_duration = ifcopenshell.util.sequence.count_working_days(
derived_start, derived_finish, self.file.by_id(calendar["id"])
)
item.derived_duration = f"P{derived_duration}D"
item.start = "-"
item.finish = "-"
item.duration = "-"
self.props.is_task_update_enabled = True
return {"FINISHED"}
2021-04-20 17:11:06 +10:00
def canonicalise_time(self, time):
if not time:
return "-"
return time.strftime("%d/%m/%y")
2021-04-07 00:31:16 +01:00
class DisableEditingWorkSchedule(bpy.types.Operator):
bl_idname = "bim.disable_editing_work_schedule"
bl_label = "Disable Editing Work Schedule"
bl_options = {"REGISTER", "UNDO"}
2021-04-07 00:31:16 +01:00
def execute(self, context):
context.scene.BIMWorkScheduleProperties.active_work_schedule_id = 0
return {"FINISHED"}
class AddTask(bpy.types.Operator):
bl_idname = "bim.add_task"
bl_label = "Add Task"
bl_options = {"REGISTER", "UNDO"}
task: bpy.props.IntProperty()
def execute(self, context):
return IfcStore.execute_ifc_operator(self, context)
def _execute(self, context):
props = context.scene.BIMWorkScheduleProperties
self.file = IfcStore.get_file()
ifcopenshell.api.run("sequence.add_task", self.file, parent_task=self.file.by_id(self.task))
Data.load(self.file)
bpy.ops.bim.enable_editing_tasks(work_schedule=props.active_work_schedule_id)
return {"FINISHED"}
class AddSummaryTask(bpy.types.Operator):
bl_idname = "bim.add_summary_task"
bl_label = "Add Task"
bl_options = {"REGISTER", "UNDO"}
work_schedule: bpy.props.IntProperty()
def execute(self, context):
return IfcStore.execute_ifc_operator(self, context)
def _execute(self, context):
props = context.scene.BIMWorkScheduleProperties
self.file = IfcStore.get_file()
ifcopenshell.api.run("sequence.add_task", self.file, work_schedule=self.file.by_id(self.work_schedule))
Data.load(self.file)
bpy.ops.bim.enable_editing_tasks(work_schedule=props.active_work_schedule_id)
return {"FINISHED"}
class ExpandTask(bpy.types.Operator):
bl_idname = "bim.expand_task"
bl_label = "Expand Task"
bl_options = {"REGISTER", "UNDO"}
task: bpy.props.IntProperty()
def execute(self, context):
props = context.scene.BIMWorkScheduleProperties
self.file = IfcStore.get_file()
contracted_tasks = json.loads(props.contracted_tasks)
contracted_tasks.remove(self.task)
props.contracted_tasks = json.dumps(contracted_tasks)
Data.load(self.file)
bpy.ops.bim.enable_editing_tasks(work_schedule=props.active_work_schedule_id)
return {"FINISHED"}
class ContractTask(bpy.types.Operator):
bl_idname = "bim.contract_task"
bl_label = "Contract Task"
bl_options = {"REGISTER", "UNDO"}
task: bpy.props.IntProperty()
def execute(self, context):
props = context.scene.BIMWorkScheduleProperties
self.file = IfcStore.get_file()
contracted_tasks = json.loads(props.contracted_tasks)
contracted_tasks.append(self.task)
props.contracted_tasks = json.dumps(contracted_tasks)
Data.load(self.file)
bpy.ops.bim.enable_editing_tasks(work_schedule=props.active_work_schedule_id)
return {"FINISHED"}
class RemoveTask(bpy.types.Operator):
bl_idname = "bim.remove_task"
bl_label = "Remove Task"
bl_options = {"REGISTER", "UNDO"}
task: bpy.props.IntProperty()
def execute(self, context):
return IfcStore.execute_ifc_operator(self, context)
def _execute(self, context):
props = context.scene.BIMWorkScheduleProperties
self.file = IfcStore.get_file()
ifcopenshell.api.run(
"sequence.remove_task",
self.file,
task=IfcStore.get_file().by_id(self.task),
)
Data.load(self.file)
bpy.ops.bim.enable_editing_tasks(work_schedule=props.active_work_schedule_id)
return {"FINISHED"}
2021-04-19 11:10:49 +10:00
2021-04-20 05:12:13 +00:00
class EnableEditingTaskTime(bpy.types.Operator):
bl_idname = "bim.enable_editing_task_time"
bl_label = "Enable Editing Task Time"
bl_options = {"REGISTER", "UNDO"}
2021-04-20 05:12:13 +00:00
task: bpy.props.IntProperty()
def execute(self, context):
return IfcStore.execute_ifc_operator(self, context)
def _execute(self, context):
2021-04-20 05:12:13 +00:00
props = context.scene.BIMWorkScheduleProperties
self.file = IfcStore.get_file()
2021-04-20 17:11:06 +10:00
task_time_id = Data.tasks[self.task]["TaskTime"] or self.add_task_time().id()
props.task_time_attributes.clear()
2021-04-20 05:12:13 +00:00
data = Data.task_times[task_time_id]
blenderbim.bim.helper.import_attributes("IfcTaskTime", props.task_time_attributes, data, self.import_attributes)
2021-04-20 17:11:06 +10:00
props.active_task_time_id = task_time_id
props.active_task_id = self.task
2021-04-30 17:40:00 +10:00
props.editing_task_type = "TASKTIME"
2021-04-20 05:12:13 +00:00
return {"FINISHED"}
def import_attributes(self, name, prop, data):
if prop.data_type == "string":
if isinstance(data[name], datetime):
prop.string_value = "" if prop.is_null else data[name].isoformat()
return True
elif isinstance(data[name], isodate.Duration):
2021-05-07 10:58:12 +10:00
prop.string_value = (
"" if prop.is_null else ifcopenshell.util.date.datetime2ifc(data[name], "IfcDuration")
)
return True
2021-04-20 17:11:06 +10:00
def add_task_time(self):
task_time = ifcopenshell.api.run("sequence.add_task_time", self.file, task=self.file.by_id(self.task))
Data.load(self.file)
2021-04-20 17:11:06 +10:00
return task_time
class EditTaskTime(bpy.types.Operator):
bl_idname = "bim.edit_task_time"
bl_label = "Edit Task Time"
bl_options = {"REGISTER", "UNDO"}
2021-04-20 17:11:06 +10:00
def execute(self, context):
return IfcStore.execute_ifc_operator(self, context)
def _execute(self, context):
2021-04-20 17:11:06 +10:00
props = context.scene.BIMWorkScheduleProperties
attributes = blenderbim.bim.helper.export_attributes(props.task_time_attributes, self.export_attributes)
2021-04-20 17:11:06 +10:00
self.file = IfcStore.get_file()
ifcopenshell.api.run(
"sequence.edit_task_time",
self.file,
**{"task_time": self.file.by_id(props.active_task_time_id), "attributes": attributes},
2021-04-20 17:11:06 +10:00
)
Data.load(IfcStore.get_file())
bpy.ops.bim.disable_editing_task_time()
bpy.ops.bim.load_task_properties(task=props.active_task_id)
2021-04-20 17:11:06 +10:00
return {"FINISHED"}
def export_attributes(self, attributes, prop):
if "Start" in prop.name or "Finish" in prop.name or prop.name == "StatusTime":
if prop.is_null:
attributes[prop.name] = None
return True
attributes[prop.name] = helper.parse_datetime(prop.string_value)
return True
elif prop.name == "ScheduleDuration":
if prop.is_null:
attributes[prop.name] = None
return True
attributes[prop.name] = helper.parse_duration(prop.string_value)
return True
2021-04-20 17:11:06 +10:00
2021-04-20 05:12:13 +00:00
2021-04-19 11:10:49 +10:00
class EnableEditingTask(bpy.types.Operator):
bl_idname = "bim.enable_editing_task"
bl_label = "Enable Editing Task"
bl_options = {"REGISTER", "UNDO"}
2021-04-19 11:10:49 +10:00
task: bpy.props.IntProperty()
def execute(self, context):
props = context.scene.BIMWorkScheduleProperties
props.task_attributes.clear()
2021-04-19 11:10:49 +10:00
data = Data.tasks[self.task]
blenderbim.bim.helper.import_attributes("IfcTask", props.task_attributes, data)
2021-04-19 11:10:49 +10:00
props.active_task_id = self.task
2021-04-30 17:40:00 +10:00
props.editing_task_type = "ATTRIBUTES"
2021-04-19 11:10:49 +10:00
return {"FINISHED"}
class DisableEditingTask(bpy.types.Operator):
bl_idname = "bim.disable_editing_task"
bl_label = "Disable Editing Task"
bl_options = {"REGISTER", "UNDO"}
2021-04-19 11:10:49 +10:00
def execute(self, context):
context.scene.BIMWorkScheduleProperties.active_task_id = 0
2021-04-30 17:40:00 +10:00
context.scene.BIMWorkScheduleProperties.active_task_time_id = 0
2021-04-19 11:10:49 +10:00
return {"FINISHED"}
class EditTask(bpy.types.Operator):
bl_idname = "bim.edit_task"
bl_label = "Edit Task"
bl_options = {"REGISTER", "UNDO"}
2021-04-19 11:10:49 +10:00
def execute(self, context):
return IfcStore.execute_ifc_operator(self, context)
def _execute(self, context):
2021-04-19 11:10:49 +10:00
props = context.scene.BIMWorkScheduleProperties
attributes = blenderbim.bim.helper.export_attributes(props.task_attributes)
2021-04-19 11:10:49 +10:00
self.file = IfcStore.get_file()
ifcopenshell.api.run(
"sequence.edit_task", self.file, **{"task": self.file.by_id(props.active_task_id), "attributes": attributes}
2021-04-19 11:10:49 +10:00
)
Data.load(IfcStore.get_file())
bpy.ops.bim.disable_editing_task()
bpy.ops.bim.load_task_properties(task=props.active_task_id)
2021-04-19 11:10:49 +10:00
return {"FINISHED"}
class CopyTaskAttribute(bpy.types.Operator):
bl_idname = "bim.copy_task_attribute"
bl_label = "Copy Task Attribute"
bl_options = {"REGISTER", "UNDO"}
2021-10-25 19:32:37 +11:00
name: bpy.props.StringProperty()
def execute(self, context):
return IfcStore.execute_ifc_operator(self, context)
def _execute(self, context):
2021-10-25 19:32:37 +11:00
value = context.scene.BIMWorkScheduleProperties.task_attributes.get(self.name).get_value()
self.file = IfcStore.get_file()
props = context.scene.BIMTaskTreeProperties
for task in props.tasks:
if task.is_selected:
ifcopenshell.api.run(
"sequence.edit_task",
self.file,
2021-10-25 19:32:37 +11:00
task=self.file.by_id(task.ifc_definition_id),
attributes={self.name: value},
)
Data.load(IfcStore.get_file())
bpy.ops.bim.load_task_properties()
return {"FINISHED"}
class AssignPredecessor(bpy.types.Operator):
bl_idname = "bim.assign_predecessor"
bl_label = "Assign Predecessor"
bl_options = {"REGISTER", "UNDO"}
task: bpy.props.IntProperty()
def execute(self, context):
return IfcStore.execute_ifc_operator(self, context)
def _execute(self, context):
props = context.scene.BIMWorkScheduleProperties
self.file = IfcStore.get_file()
rel = ifcopenshell.api.run(
"sequence.assign_sequence",
self.file,
relating_process=IfcStore.get_file().by_id(self.task),
related_process=IfcStore.get_file().by_id(props.active_task_id),
)
Data.load(self.file)
bpy.ops.bim.load_task_properties()
return {"FINISHED"}
class AssignSuccessor(bpy.types.Operator):
bl_idname = "bim.assign_successor"
bl_label = "Assign Successor"
bl_options = {"REGISTER", "UNDO"}
task: bpy.props.IntProperty()
def execute(self, context):
return IfcStore.execute_ifc_operator(self, context)
def _execute(self, context):
props = context.scene.BIMWorkScheduleProperties
self.file = IfcStore.get_file()
rel = ifcopenshell.api.run(
"sequence.assign_sequence",
self.file,
relating_process=IfcStore.get_file().by_id(props.active_task_id),
related_process=IfcStore.get_file().by_id(self.task),
)
Data.load(self.file)
bpy.ops.bim.load_task_properties()
return {"FINISHED"}
class UnassignPredecessor(bpy.types.Operator):
bl_idname = "bim.unassign_predecessor"
bl_label = "Unassign Predecessor"
bl_options = {"REGISTER", "UNDO"}
task: bpy.props.IntProperty()
def execute(self, context):
return IfcStore.execute_ifc_operator(self, context)
def _execute(self, context):
props = context.scene.BIMWorkScheduleProperties
self.file = IfcStore.get_file()
ifcopenshell.api.run(
"sequence.unassign_sequence",
self.file,
relating_process=IfcStore.get_file().by_id(self.task),
related_process=IfcStore.get_file().by_id(props.active_task_id),
)
Data.load(self.file)
bpy.ops.bim.load_task_properties()
return {"FINISHED"}
class UnassignSuccessor(bpy.types.Operator):
bl_idname = "bim.unassign_successor"
bl_label = "Unassign Successor"
bl_options = {"REGISTER", "UNDO"}
task: bpy.props.IntProperty()
def execute(self, context):
return IfcStore.execute_ifc_operator(self, context)
def _execute(self, context):
props = context.scene.BIMWorkScheduleProperties
self.file = IfcStore.get_file()
ifcopenshell.api.run(
"sequence.unassign_sequence",
self.file,
2021-04-20 05:12:13 +00:00
relating_process=self.file.by_id(props.active_task_id),
related_process=self.file.by_id(self.task),
)
Data.load(self.file)
bpy.ops.bim.load_task_properties()
2021-04-20 05:12:13 +00:00
return {"FINISHED"}
class AssignProduct(bpy.types.Operator):
bl_idname = "bim.assign_product"
bl_label = "Assign Product"
bl_options = {"REGISTER", "UNDO"}
task: bpy.props.IntProperty()
relating_product: bpy.props.StringProperty()
def execute(self, context):
return IfcStore.execute_ifc_operator(self, context)
def _execute(self, context):
self.file = IfcStore.get_file()
relating_products = (
[bpy.data.objects.get(self.relating_product)] if self.relating_product else context.selected_objects
)
for relating_product in relating_products:
if not relating_product.BIMObjectProperties.ifc_definition_id:
continue
ifcopenshell.api.run(
"sequence.assign_product",
self.file,
relating_product=self.file.by_id(relating_product.BIMObjectProperties.ifc_definition_id),
related_object=self.file.by_id(self.task),
)
Data.load(self.file)
bpy.ops.bim.load_task_outputs()
return {"FINISHED"}
2021-04-21 11:53:33 +10:00
class UnassignProduct(bpy.types.Operator):
bl_idname = "bim.unassign_product"
bl_label = "Unassign Product"
bl_options = {"REGISTER", "UNDO"}
2021-04-21 11:53:33 +10:00
task: bpy.props.IntProperty()
relating_product: bpy.props.StringProperty()
2021-04-21 11:53:33 +10:00
def execute(self, context):
return IfcStore.execute_ifc_operator(self, context)
def _execute(self, context):
self.file = IfcStore.get_file()
relating_products = (
[bpy.data.objects.get(self.relating_product)] if self.relating_product else context.selected_objects
2021-04-21 11:53:33 +10:00
)
for relating_product in relating_products:
if not relating_product.BIMObjectProperties.ifc_definition_id:
continue
2021-04-21 11:53:33 +10:00
ifcopenshell.api.run(
"sequence.unassign_product",
self.file,
relating_product=self.file.by_id(relating_product.BIMObjectProperties.ifc_definition_id),
2021-04-21 11:53:33 +10:00
related_object=self.file.by_id(self.task),
)
Data.load(self.file)
bpy.ops.bim.load_task_outputs()
2021-04-21 11:53:33 +10:00
return {"FINISHED"}
class AssignProcess(bpy.types.Operator):
bl_idname = "bim.assign_process"
bl_label = "Assign Process"
bl_options = {"REGISTER", "UNDO"}
task: bpy.props.IntProperty()
related_object_type: bpy.props.StringProperty()
related_object: bpy.props.StringProperty()
resource: bpy.props.IntProperty()
def execute(self, context):
return IfcStore.execute_ifc_operator(self, context)
def _execute(self, context):
self.file = IfcStore.get_file()
if self.related_object_type == "RESOURCE":
self.assign_resource()
elif self.related_object_type == "PRODUCT":
self.assign_product(context)
elif self.related_object_type == "CONTROL":
pass # TODO
return {"FINISHED"}
def assign_resource(self):
task = self.file.by_id(self.task)
resource = self.file.by_id(self.resource)
subresource = ifcopenshell.api.run(
"resource.add_resource",
self.file,
**{"parent_resource": resource, "ifc_class": resource.is_a(), "name": resource.Name},
)
ifcopenshell.api.run(
"sequence.assign_process", self.file, **{"related_object": subresource, "relating_process": task}
)
ResourceData.load(self.file)
Data.load(self.file)
bpy.ops.bim.load_resources()
bpy.ops.bim.load_task_resources()
def assign_product(self, context):
task = self.file.by_id(self.task)
related_objects = (
[bpy.data.objects.get(self.related_object)] if self.related_object else context.selected_objects
)
for related_object in related_objects:
if not related_object.BIMObjectProperties.ifc_definition_id:
continue
ifcopenshell.api.run(
"sequence.assign_process",
self.file,
related_object=self.file.by_id(related_object.BIMObjectProperties.ifc_definition_id),
relating_process=task,
)
Data.load(self.file)
bpy.ops.bim.load_task_inputs()
class UnassignProcess(bpy.types.Operator):
bl_idname = "bim.unassign_process"
bl_label = "Unassign Process"
bl_options = {"REGISTER", "UNDO"}
task: bpy.props.IntProperty()
related_object_type: bpy.props.StringProperty()
related_object: bpy.props.StringProperty()
resource: bpy.props.IntProperty()
def execute(self, context):
return IfcStore.execute_ifc_operator(self, context)
def _execute(self, context):
self.file = IfcStore.get_file()
if self.related_object_type == "RESOURCE":
self.unassign_resource()
elif self.related_object_type == "PRODUCT":
self.unassign_product(context)
elif self.related_object_type == "CONTROL":
pass # TODO
return {"FINISHED"}
def unassign_resource(self):
task = self.file.by_id(self.task)
resource = self.file.by_id(self.resource)
ifcopenshell.api.run("sequence.unassign_process", self.file, related_object=resource, relating_process=task)
ifcopenshell.api.run("resource.remove_resource", self.file, resource=resource)
ResourceData.load(self.file)
Data.load(self.file)
bpy.ops.bim.load_resources()
bpy.ops.bim.load_task_resources()
def unassign_product(self, context):
task = self.file.by_id(self.task)
related_objects = (
[bpy.data.objects.get(self.related_object)] if self.related_object else context.selected_objects
)
for related_object in related_objects:
if not related_object.BIMObjectProperties.ifc_definition_id:
continue
ifcopenshell.api.run(
"sequence.unassign_process",
self.file,
related_object=self.file.by_id(related_object.BIMObjectProperties.ifc_definition_id),
relating_process=task,
)
Data.load(self.file)
bpy.ops.bim.load_task_inputs()
class GenerateGanttChart(bpy.types.Operator):
bl_idname = "bim.generate_gantt_chart"
bl_label = "Generate Gantt Chart"
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",
}
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"))
return {"FINISHED"}
def create_new_task_json(self, task_id):
task = self.file.by_id(task_id)
data = {
"pID": task.id(),
"pName": 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,
}
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):
bl_idname = "bim.add_work_calendar"
bl_label = "Add Work Calendar"
bl_options = {"REGISTER", "UNDO"}
def execute(self, context):
return IfcStore.execute_ifc_operator(self, context)
def _execute(self, context):
ifcopenshell.api.run("sequence.add_work_calendar", IfcStore.get_file())
Data.load(IfcStore.get_file())
return {"FINISHED"}
class EditWorkCalendar(bpy.types.Operator):
bl_idname = "bim.edit_work_calendar"
bl_label = "Edit Work Calendar"
bl_options = {"REGISTER", "UNDO"}
def execute(self, context):
return IfcStore.execute_ifc_operator(self, context)
def _execute(self, context):
props = context.scene.BIMWorkCalendarProperties
attributes = blenderbim.bim.helper.export_attributes(props.work_calendar_attributes)
self.file = IfcStore.get_file()
ifcopenshell.api.run(
"sequence.edit_work_calendar",
self.file,
**{"work_calendar": self.file.by_id(props.active_work_calendar_id), "attributes": attributes},
)
Data.load(IfcStore.get_file())
2021-04-29 09:55:50 +10:00
bpy.ops.bim.disable_editing_work_calendar()
return {"FINISHED"}
class RemoveWorkCalendar(bpy.types.Operator):
bl_idname = "bim.remove_work_calendar"
bl_label = "Remove Work Plan"
bl_options = {"REGISTER", "UNDO"}
work_calendar: bpy.props.IntProperty()
def execute(self, context):
return IfcStore.execute_ifc_operator(self, context)
def _execute(self, context):
self.file = IfcStore.get_file()
ifcopenshell.api.run(
"sequence.remove_work_calendar", self.file, **{"work_calendar": self.file.by_id(self.work_calendar)}
)
Data.load(self.file)
return {"FINISHED"}
class EnableEditingWorkCalendar(bpy.types.Operator):
bl_idname = "bim.enable_editing_work_calendar"
bl_label = "Enable Editing Work Calendar"
bl_options = {"REGISTER", "UNDO"}
work_calendar: bpy.props.IntProperty()
def execute(self, context):
self.props = context.scene.BIMWorkCalendarProperties
self.props.work_calendar_attributes.clear()
data = Data.work_calendars[self.work_calendar]
blenderbim.bim.helper.import_attributes("IfcWorkCalendar", self.props.work_calendar_attributes, data)
self.props.active_work_calendar_id = self.work_calendar
2021-04-30 17:40:00 +10:00
self.props.editing_type = "ATTRIBUTES"
return {"FINISHED"}
class DisableEditingWorkCalendar(bpy.types.Operator):
bl_idname = "bim.disable_editing_work_calendar"
bl_label = "Disable Editing Work Calendar"
bl_options = {"REGISTER", "UNDO"}
def execute(self, context):
context.scene.BIMWorkCalendarProperties.active_work_calendar_id = 0
return {"FINISHED"}
class ImportP6(bpy.types.Operator, ImportHelper):
bl_idname = "import_p6.bim"
bl_label = "Import P6"
bl_options = {"REGISTER", "UNDO"}
filename_ext = ".xml"
filter_glob: bpy.props.StringProperty(default="*.xml", options={"HIDDEN"})
def execute(self, context):
from ifc4d.p62ifc import P62Ifc
self.file = IfcStore.get_file()
start = time.time()
p62ifc = P62Ifc()
p62ifc.xml = self.filepath
p62ifc.file = self.file
p62ifc.work_plan = self.file.by_type("IfcWorkPlan")[0] if self.file.by_type("IfcWorkPlan") else None
p62ifc.execute()
Data.load(IfcStore.get_file())
print("Import finished in {:.2f} seconds".format(time.time() - start))
return {"FINISHED"}
class ImportMSP(bpy.types.Operator, ImportHelper):
bl_idname = "import_msp.bim"
bl_label = "Import MSP"
bl_options = {"REGISTER", "UNDO"}
filename_ext = ".xml"
filter_glob: bpy.props.StringProperty(default="*.xml", options={"HIDDEN"})
def execute(self, context):
from ifc4d.msp2ifc import MSP2Ifc
self.file = IfcStore.get_file()
start = time.time()
msp2ifc = MSP2Ifc()
msp2ifc.xml = self.filepath
msp2ifc.file = self.file
msp2ifc.work_plan = self.file.by_type("IfcWorkPlan")[0] if self.file.by_type("IfcWorkPlan") else None
msp2ifc.execute()
Data.load(IfcStore.get_file())
print("Import finished in {:.2f} seconds".format(time.time() - start))
return {"FINISHED"}
class EnableEditingWorkCalendarTimes(bpy.types.Operator):
bl_idname = "bim.enable_editing_work_calendar_times"
bl_label = "Enable Editing Work Calendar Times"
bl_options = {"REGISTER", "UNDO"}
work_calendar: bpy.props.IntProperty()
def execute(self, context):
props = context.scene.BIMWorkCalendarProperties
props.active_work_calendar_id = self.work_calendar
2021-04-30 17:40:00 +10:00
props.editing_type = "WORKTIMES"
return {"FINISHED"}
class AddWorkTime(bpy.types.Operator):
bl_idname = "bim.add_work_time"
bl_label = "Add Work Time"
bl_options = {"REGISTER", "UNDO"}
work_calendar: bpy.props.IntProperty()
time_type: bpy.props.StringProperty()
def execute(self, context):
return IfcStore.execute_ifc_operator(self, context)
def _execute(self, context):
self.file = IfcStore.get_file()
ifcopenshell.api.run(
"sequence.add_work_time",
self.file,
**{"work_calendar": self.file.by_id(self.work_calendar), "time_type": self.time_type},
)
Data.load(IfcStore.get_file())
return {"FINISHED"}
class EnableEditingWorkTime(bpy.types.Operator):
bl_idname = "bim.enable_editing_work_time"
bl_label = "Enable Editing Work Time"
bl_options = {"REGISTER", "UNDO"}
work_time: bpy.props.IntProperty()
def execute(self, context):
self.props = context.scene.BIMWorkCalendarProperties
self.props.work_time_attributes.clear()
data = Data.work_times[self.work_time]
blenderbim.bim.helper.import_attributes(
"IfcWorkTime", self.props.work_time_attributes, data, self.import_attributes
)
self.initialise_recurrence_components()
self.load_recurrence_pattern_data(data)
self.props.active_work_time_id = self.work_time
return {"FINISHED"}
def import_attributes(self, name, prop, data):
if name in ["Start", "Finish"]:
prop.string_value = "" if prop.is_null else data[name].isoformat()
return True
def initialise_recurrence_components(self):
if len(self.props.day_components) == 0:
for i in range(0, 31):
new = self.props.day_components.add()
new.name = str(i + 1)
if len(self.props.weekday_components) == 0:
for d in ["M", "T", "W", "T", "F", "S", "S"]:
new = self.props.weekday_components.add()
new.name = d
if len(self.props.month_components) == 0:
for m in ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]:
new = self.props.month_components.add()
new.name = m
def load_recurrence_pattern_data(self, work_time):
self.props.position = 0
self.props.interval = 0
self.props.occurrences = 0
self.props.start_time = ""
self.props.end_time = ""
for component in self.props.day_components:
component.is_specified = False
for component in self.props.weekday_components:
component.is_specified = False
for component in self.props.month_components:
component.is_specified = False
if not work_time["RecurrencePattern"]:
return
recurrence_pattern = Data.recurrence_patterns[work_time["RecurrencePattern"]]
for attribute in ["Position", "Interval", "Occurrences"]:
if recurrence_pattern[attribute]:
setattr(self.props, attribute.lower(), recurrence_pattern[attribute])
for component in recurrence_pattern["DayComponent"] or []:
self.props.day_components[component - 1].is_specified = True
for component in recurrence_pattern["WeekdayComponent"] or []:
self.props.weekday_components[component - 1].is_specified = True
for component in recurrence_pattern["MonthComponent"] or []:
self.props.month_components[component - 1].is_specified = True
class DisableEditingWorkTime(bpy.types.Operator):
bl_idname = "bim.disable_editing_work_time"
bl_label = "Disable Editing Work Time"
bl_options = {"REGISTER", "UNDO"}
def execute(self, context):
context.scene.BIMWorkCalendarProperties.active_work_time_id = 0
return {"FINISHED"}
class EditWorkTime(bpy.types.Operator):
bl_idname = "bim.edit_work_time"
bl_label = "Edit Work Time"
bl_options = {"REGISTER", "UNDO"}
def execute(self, context):
return IfcStore.execute_ifc_operator(self, context)
def _execute(self, context):
self.props = context.scene.BIMWorkCalendarProperties
attributes = blenderbim.bim.helper.export_attributes(self.props.work_time_attributes)
self.file = IfcStore.get_file()
ifcopenshell.api.run(
"sequence.edit_work_time",
self.file,
**{"work_time": self.file.by_id(self.props.active_work_time_id), "attributes": attributes},
)
work_time = Data.work_times[self.props.active_work_time_id]
if work_time["RecurrencePattern"]:
self.edit_recurrence_pattern(work_time["RecurrencePattern"])
Data.load(IfcStore.get_file())
bpy.ops.bim.disable_editing_work_time()
return {"FINISHED"}
def edit_recurrence_pattern(self, recurrence_pattern_id):
recurrence_pattern = self.file.by_id(recurrence_pattern_id)
attributes = {
"Interval": self.props.interval if self.props.interval > 0 else None,
"Occurrences": self.props.occurrences if self.props.occurrences > 0 else None,
}
applicable_data = {
"DAILY": ["Interval", "Occurrences"],
"WEEKLY": ["WeekdayComponent", "Interval", "Occurrences"],
"MONTHLY_BY_DAY_OF_MONTH": ["DayComponent", "Interval", "Occurrences"],
"MONTHLY_BY_POSITION": ["WeekdayComponent", "Position", "Interval", "Occurrences"],
"BY_DAY_COUNT": ["Interval", "Occurrences"],
"BY_WEEKDAY_COUNT": ["WeekdayComponent", "Interval", "Occurrences"],
"YEARLY_BY_DAY_OF_MONTH": ["DayComponent", "MonthComponent", "Interval", "Occurrences"],
"YEARLY_BY_POSITION": ["WeekdayComponent", "MonthComponent", "Position", "Interval", "Occurrences"],
}
if "Position" in applicable_data[recurrence_pattern.RecurrenceType]:
attributes["Position"] = self.props.position if self.props.position != 0 else None
if "DayComponent" in applicable_data[recurrence_pattern.RecurrenceType]:
attributes["DayComponent"] = [i + 1 for i, c in enumerate(self.props.day_components) if c.is_specified]
if "WeekdayComponent" in applicable_data[recurrence_pattern.RecurrenceType]:
attributes["WeekdayComponent"] = [
i + 1 for i, c in enumerate(self.props.weekday_components) if c.is_specified
]
if "MonthComponent" in applicable_data[recurrence_pattern.RecurrenceType]:
attributes["MonthComponent"] = [i + 1 for i, c in enumerate(self.props.month_components) if c.is_specified]
ifcopenshell.api.run(
"sequence.edit_recurrence_pattern",
self.file,
**{"recurrence_pattern": recurrence_pattern, "attributes": attributes},
)
class RemoveWorkTime(bpy.types.Operator):
bl_idname = "bim.remove_work_time"
bl_label = "Remove Work Plan"
bl_options = {"REGISTER", "UNDO"}
work_time: bpy.props.IntProperty()
def execute(self, context):
return IfcStore.execute_ifc_operator(self, context)
def _execute(self, context):
self.file = IfcStore.get_file()
ifcopenshell.api.run("sequence.remove_work_time", self.file, **{"work_time": self.file.by_id(self.work_time)})
Data.load(self.file)
return {"FINISHED"}
class AssignRecurrencePattern(bpy.types.Operator):
bl_idname = "bim.assign_recurrence_pattern"
bl_label = "Assign Recurrence Pattern"
bl_options = {"REGISTER", "UNDO"}
work_time: bpy.props.IntProperty()
recurrence_type: bpy.props.StringProperty()
def execute(self, context):
return IfcStore.execute_ifc_operator(self, context)
def _execute(self, context):
self.file = IfcStore.get_file()
ifcopenshell.api.run(
"sequence.assign_recurrence_pattern",
self.file,
**{"parent": self.file.by_id(self.work_time), "recurrence_type": self.recurrence_type},
)
Data.load(IfcStore.get_file())
return {"FINISHED"}
class UnassignRecurrencePattern(bpy.types.Operator):
bl_idname = "bim.unassign_recurrence_pattern"
bl_label = "Unassign Recurrence Pattern"
bl_options = {"REGISTER", "UNDO"}
recurrence_pattern: bpy.props.IntProperty()
def execute(self, context):
return IfcStore.execute_ifc_operator(self, context)
def _execute(self, context):
self.file = IfcStore.get_file()
ifcopenshell.api.run(
"sequence.unassign_recurrence_pattern",
self.file,
**{"recurrence_pattern": self.file.by_id(self.recurrence_pattern)},
)
Data.load(self.file)
return {"FINISHED"}
class AddTimePeriod(bpy.types.Operator):
bl_idname = "bim.add_time_period"
bl_label = "Add Time Period"
bl_options = {"REGISTER", "UNDO"}
recurrence_pattern: bpy.props.IntProperty()
def execute(self, context):
return IfcStore.execute_ifc_operator(self, context)
def _execute(self, context):
self.props = context.scene.BIMWorkCalendarProperties
self.file = IfcStore.get_file()
try:
start_time = parser.parse(self.props.start_time)
end_time = parser.parse(self.props.end_time)
except:
return {"FINISHED"}
ifcopenshell.api.run(
"sequence.add_time_period",
self.file,
**{
"recurrence_pattern": self.file.by_id(self.recurrence_pattern),
"start_time": start_time,
"end_time": end_time,
},
)
self.props.start_time = ""
self.props.end_time = ""
Data.load(IfcStore.get_file())
return {"FINISHED"}
class RemoveTimePeriod(bpy.types.Operator):
bl_idname = "bim.remove_time_period"
bl_label = "Remove Time Period"
bl_options = {"REGISTER", "UNDO"}
time_period: bpy.props.IntProperty()
def execute(self, context):
return IfcStore.execute_ifc_operator(self, context)
def _execute(self, context):
self.file = IfcStore.get_file()
ifcopenshell.api.run(
"sequence.remove_time_period",
self.file,
**{"time_period": self.file.by_id(self.time_period)},
)
Data.load(self.file)
return {"FINISHED"}
2021-04-30 17:40:00 +10:00
class EnableEditingTaskCalendar(bpy.types.Operator):
bl_idname = "bim.enable_editing_task_calendar"
bl_label = "Enable Editing Task Calendar"
bl_options = {"REGISTER", "UNDO"}
2021-04-30 17:40:00 +10:00
task: bpy.props.IntProperty()
def execute(self, context):
props = context.scene.BIMWorkScheduleProperties
props.active_task_id = self.task
props.editing_task_type = "CALENDAR"
return {"FINISHED"}
class EditTaskCalendar(bpy.types.Operator):
bl_idname = "bim.edit_task_calendar"
bl_label = "Edit Task Calendar"
bl_options = {"REGISTER", "UNDO"}
2021-04-30 17:40:00 +10:00
work_calendar: bpy.props.IntProperty()
task: bpy.props.IntProperty()
def execute(self, context):
return IfcStore.execute_ifc_operator(self, context)
def _execute(self, context):
2021-04-30 17:40:00 +10:00
self.file = IfcStore.get_file()
task = self.file.by_id(self.task)
2021-04-30 17:40:00 +10:00
ifcopenshell.api.run(
"control.assign_control",
self.file,
**{
"relating_control": self.file.by_id(self.work_calendar),
"related_object": task,
2021-04-30 17:40:00 +10:00
},
)
ifcopenshell.api.run("sequence.cascade_schedule", self.file, task=task)
2021-04-30 17:40:00 +10:00
Data.load(IfcStore.get_file())
bpy.ops.bim.load_task_properties()
2021-04-30 17:40:00 +10:00
return {"FINISHED"}
class RemoveTaskCalendar(bpy.types.Operator):
bl_idname = "bim.remove_task_calendar"
bl_label = "Remove Task Calendar"
bl_options = {"REGISTER", "UNDO"}
2021-04-30 17:40:00 +10:00
work_calendar: bpy.props.IntProperty()
task: bpy.props.IntProperty()
def execute(self, context):
return IfcStore.execute_ifc_operator(self, context)
def _execute(self, context):
2021-04-30 17:40:00 +10:00
self.file = IfcStore.get_file()
task = self.file.by_id(self.task)
2021-04-30 17:40:00 +10:00
ifcopenshell.api.run(
"control.unassign_control",
self.file,
**{
"relating_control": self.file.by_id(self.work_calendar),
"related_object": task,
2021-04-30 17:40:00 +10:00
},
)
ifcopenshell.api.run("sequence.cascade_schedule", self.file, task=task)
2021-04-30 17:40:00 +10:00
Data.load(IfcStore.get_file())
bpy.ops.bim.load_task_properties()
2021-04-30 17:40:00 +10:00
return {"FINISHED"}
class EnableEditingTaskSequence(bpy.types.Operator):
bl_idname = "bim.enable_editing_task_sequence"
bl_label = "Enable Editing Task Sequence"
task: bpy.props.IntProperty()
def execute(self, context):
props = context.scene.BIMWorkScheduleProperties
props.active_task_id = self.task
props.editing_task_type = "SEQUENCE"
bpy.ops.bim.load_task_properties()
return {"FINISHED"}
class DisableEditingTaskTime(bpy.types.Operator):
bl_idname = "bim.disable_editing_task_time"
bl_label = "Disable Editing Task Time"
bl_options = {"REGISTER", "UNDO"}
def execute(self, context):
context.scene.BIMWorkScheduleProperties.active_task_time_id = 0
bpy.ops.bim.disable_editing_task()
return {"FINISHED"}
class EnableEditingSequenceAttributes(bpy.types.Operator):
bl_idname = "bim.enable_editing_sequence_attributes"
bl_label = "Enable Editing Sequence Attributes"
bl_options = {"REGISTER", "UNDO"}
sequence: bpy.props.IntProperty()
def execute(self, context):
self.props = context.scene.BIMWorkScheduleProperties
self.props.active_sequence_id = self.sequence
self.props.editing_sequence_type = "ATTRIBUTES"
self.props.sequence_attributes.clear()
self.enable_editing_sequence_attributes()
return {"FINISHED"}
def enable_editing_sequence_attributes(self):
data = Data.sequences[self.sequence]
blenderbim.bim.helper.import_attributes("IfcRelSequence", self.props.sequence_attributes, data)
class EnableEditingSequenceTimeLag(bpy.types.Operator):
bl_idname = "bim.enable_editing_sequence_time_lag"
bl_label = "Enable Editing Sequence Time Lag"
bl_options = {"REGISTER", "UNDO"}
sequence: bpy.props.IntProperty()
lag_time: bpy.props.IntProperty()
def execute(self, context):
self.props = context.scene.BIMWorkScheduleProperties
self.props.active_sequence_id = self.sequence
self.props.editing_sequence_type = "TIME_LAG"
self.props.time_lag_attributes.clear()
self.enable_editing_attributes()
return {"FINISHED"}
def enable_editing_attributes(self):
data = Data.lag_times[self.lag_time]
blenderbim.bim.helper.import_attributes(
"IfcLagTime", self.props.time_lag_attributes, data, self.import_attributes
)
def import_attributes(self, name, prop, data):
if name == "LagValue":
if isinstance(data[name], isodate.Duration):
prop.data_type = "string"
prop.string_value = (
2021-05-07 10:58:12 +10:00
"" if prop.is_null else ifcopenshell.util.date.datetime2ifc(data[name], "IfcDuration")
)
return True
else:
prop.data_type = "float"
prop.float_value = 0.0 if prop.is_null else data[name]
return True
class UnassignLagTime(bpy.types.Operator):
bl_idname = "bim.unassign_lag_time"
bl_label = "Unassign Time Lag"
bl_options = {"REGISTER", "UNDO"}
sequence: bpy.props.IntProperty()
def execute(self, context):
return IfcStore.execute_ifc_operator(self, context)
def _execute(self, context):
self.file = IfcStore.get_file()
ifcopenshell.api.run(
"sequence.unassign_lag_time", self.file, **{"rel_sequence": self.file.by_id(self.sequence)}
)
Data.load(IfcStore.get_file())
bpy.ops.bim.load_task_properties()
return {"FINISHED"}
class AssignLagTime(bpy.types.Operator):
bl_idname = "bim.assign_lag_time"
bl_label = "Assign Time Lag"
bl_options = {"REGISTER", "UNDO"}
sequence: bpy.props.IntProperty()
def execute(self, context):
return IfcStore.execute_ifc_operator(self, context)
def _execute(self, context):
self.file = IfcStore.get_file()
ifcopenshell.api.run(
"sequence.assign_lag_time",
self.file,
**{"rel_sequence": self.file.by_id(self.sequence), "lag_value": "P0D"},
)
Data.load(IfcStore.get_file())
return {"FINISHED"}
class EditSequenceAttributes(bpy.types.Operator):
bl_idname = "bim.edit_sequence_attributes"
bl_label = "Edit Sequence"
bl_options = {"REGISTER", "UNDO"}
def execute(self, context):
return IfcStore.execute_ifc_operator(self, context)
def _execute(self, context):
props = context.scene.BIMWorkScheduleProperties
attributes = blenderbim.bim.helper.export_attributes(props.sequence_attributes)
self.file = IfcStore.get_file()
ifcopenshell.api.run(
"sequence.edit_sequence",
self.file,
**{"rel_sequence": self.file.by_id(props.active_sequence_id), "attributes": attributes},
)
Data.load(self.file)
bpy.ops.bim.disable_editing_sequence()
bpy.ops.bim.load_task_properties()
return {"FINISHED"}
class EditSequenceTimeLag(bpy.types.Operator):
bl_idname = "bim.edit_sequence_time_lag"
bl_label = "Edit Time Lag"
bl_options = {"REGISTER", "UNDO"}
lag_time: bpy.props.IntProperty()
def execute(self, context):
return IfcStore.execute_ifc_operator(self, context)
def _execute(self, context):
props = context.scene.BIMWorkScheduleProperties
attributes = blenderbim.bim.helper.export_attributes(props.time_lag_attributes)
self.file = IfcStore.get_file()
ifcopenshell.api.run(
"sequence.edit_lag_time",
self.file,
**{"lag_time": self.file.by_id(self.lag_time), "attributes": attributes},
)
Data.load(self.file)
bpy.ops.bim.disable_editing_sequence()
bpy.ops.bim.load_task_properties()
return {"FINISHED"}
class DisableEditingSequence(bpy.types.Operator):
bl_idname = "bim.disable_editing_sequence"
bl_label = "Disable Editing Sequence Attributes"
bl_options = {"REGISTER", "UNDO"}
def execute(self, context):
context.scene.BIMWorkScheduleProperties.active_sequence_id = 0
return {"FINISHED"}
class SelectTaskRelatedProducts(bpy.types.Operator):
bl_idname = "bim.select_task_related_products"
bl_label = "Select Similar Type"
bl_options = {"REGISTER", "UNDO"}
task: bpy.props.IntProperty()
def execute(self, context):
return IfcStore.execute_ifc_operator(self, context)
def _execute(self, context):
self.file = IfcStore.get_file()
related_products = ifcopenshell.api.run(
"sequence.get_related_products", self.file, **{"related_object": self.file.by_id(self.task)}
)
for obj in context.visible_objects:
obj.select_set(False)
if obj.BIMObjectProperties.ifc_definition_id in related_products:
obj.select_set(True)
return {"FINISHED"}
class VisualiseWorkScheduleDate(bpy.types.Operator):
bl_idname = "bim.visualise_work_schedule_date"
bl_label = "Visualise Work Schedule Date"
bl_options = {"REGISTER", "UNDO"}
work_schedule: bpy.props.IntProperty()
def execute(self, context):
props = context.scene.BIMWorkScheduleProperties
self.file = IfcStore.get_file()
self.date = parser.parse(props.visualisation_start, dayfirst=True, fuzzy=True)
self.preprocess_tasks()
for obj in bpy.data.objects:
if not obj.BIMObjectProperties.ifc_definition_id:
continue
obj.color = (1.0, 1.0, 1.0, 1)
obj.hide_set(False)
if obj.BIMObjectProperties.ifc_definition_id in self.not_yet_started:
obj.hide_set(True)
elif obj.BIMObjectProperties.ifc_definition_id in self.started:
obj.color = (0.0, 1.0, 0.0, 1)
elif obj.BIMObjectProperties.ifc_definition_id in self.completed:
pass
else:
obj.color = (1.0, 0.0, 0.0, 1)
area = next(area for area in context.screen.areas if area.type == "VIEW_3D")
area.spaces[0].shading.color_type = "OBJECT"
return {"FINISHED"}
def preprocess_tasks(self):
self.not_yet_started = set()
self.started = set()
self.completed = set()
for rel in self.file.by_id(self.work_schedule).Controls or []:
for related_object in rel.RelatedObjects:
if related_object.is_a("IfcTask"):
self.preprocess_task(related_object)
def preprocess_task(self, task):
for rel in task.IsNestedBy or []:
for related_object in rel.RelatedObjects:
self.preprocess_task(related_object)
start = helper.derive_date(task.id(), "ScheduleStart", is_earliest=True)
finish = helper.derive_date(task.id(), "ScheduleFinish", is_latest=True)
if not start or not finish:
return
products = [r.RelatingProduct.id() for r in task.HasAssignments or [] if r.is_a("IfcRelAssignsToProduct")]
if not products:
return
if self.date < start:
self.not_yet_started.update(products)
elif self.date < finish:
self.started.update(products)
else:
self.completed.update(products)
class VisualiseWorkScheduleDateRange(bpy.types.Operator):
bl_idname = "bim.visualise_work_schedule_date_range"
bl_label = "Visualise Work Schedule Date Range"
bl_options = {"REGISTER", "UNDO"}
work_schedule: bpy.props.IntProperty()
def execute(self, context):
self.file = IfcStore.get_file()
self.props = context.scene.BIMWorkScheduleProperties
self.start = parser.parse(self.props.visualisation_start, dayfirst=True, fuzzy=True)
self.finish = parser.parse(self.props.visualisation_finish, dayfirst=True, fuzzy=True)
self.duration = self.finish - self.start
self.start_frame = 1
self.total_frames = self.calculate_total_frames(context)
self.preprocess_tasks()
for obj in bpy.data.objects:
if not obj.BIMObjectProperties.ifc_definition_id:
continue
product_frames = self.product_frames.get(obj.BIMObjectProperties.ifc_definition_id, [])
for product_frame in product_frames:
if product_frame["relationship"] == "input":
self.animate_input(obj, product_frame)
elif product_frame["relationship"] == "output":
self.animate_output(obj, product_frame)
self.add_text_animation_handler()
area = next(area for area in context.screen.areas if area.type == "VIEW_3D")
area.spaces[0].shading.color_type = "OBJECT"
context.scene.frame_start = self.start_frame
context.scene.frame_end = int(self.start_frame + self.total_frames)
# with open("/home/dion/animation.json", "w") as json_file:
# guid_frames = {}
# for k, v in self.product_frames.items():
# guid_frames[self.file.by_id(k).GlobalId] = v
# json.dump(guid_frames, json_file)
return {"FINISHED"}
def add_text_animation_handler(self):
data = bpy.data.curves.get("Timeline")
if not data:
data = bpy.data.curves.new(type="FONT", name="Timeline")
obj = bpy.data.objects.get("Timeline")
if not obj:
obj = bpy.data.objects.new(name="Timeline", object_data=data)
bpy.context.scene.collection.objects.link(obj)
obj.data.BIMDateTextProperties.start_frame = self.start_frame
obj.data.BIMDateTextProperties.total_frames = int(self.total_frames)
obj.data.BIMDateTextProperties.start = self.props.visualisation_start
obj.data.BIMDateTextProperties.finish = self.props.visualisation_finish
bpy.app.handlers.frame_change_post.append(self.animate_text)
def remove_text_animation_handler(self):
bpy.app.handlers.frame_change_post.remove(self.animate_text)
def animate_text(self, scene, context):
data = bpy.data.curves.get("Timeline")
if not data or not bpy.data.objects.get("Timeline"):
self.remove_text_animation_handler()
scene.frame_current
props = data.BIMDateTextProperties
start = parser.parse(props.start, dayfirst=True, fuzzy=True)
finish = parser.parse(props.finish, dayfirst=True, fuzzy=True)
duration = finish - start
frame_date = (((scene.frame_current - props.start_frame) / props.total_frames) * duration) + start
data.body = frame_date.date().isoformat()
def animate_input(self, obj, product_frame):
if product_frame["type"] in ["LOGISTIC", "MOVE", "DISPOSAL"]:
self.animate_movement_from(obj, product_frame)
else:
self.animate_consumption(obj, product_frame)
def animate_output(self, obj, product_frame):
if product_frame["type"] in ["CONSTRUCTION", "INSTALLATION"]:
self.animate_creation(obj, product_frame)
elif product_frame["type"] in ["DEMOLITION", "DISMANTLE", "DISPOSAL", "REMOVAL"]:
self.animate_destruction(obj, product_frame)
elif product_frame["type"] in ["ATTENDANCE", "MAINTENANCE", "OPERATION", "RENOVATION"]:
self.animate_operation(obj, product_frame)
elif product_frame["type"] in ["LOGISTIC", "MOVE", "DISPOSAL"]:
self.animate_movement_to(obj, product_frame)
else:
self.animate_operation(obj, product_frame)
def animate_creation(self, obj, product_frame):
obj.hide_viewport = True
obj.hide_render = True
obj.keyframe_insert(data_path="hide_viewport", frame=self.start_frame)
obj.keyframe_insert(data_path="hide_render", frame=self.start_frame)
obj.hide_viewport = False
obj.hide_render = False
obj.color = (0.0, 1.0, 0.0, 1)
obj.keyframe_insert(data_path="hide_viewport", frame=product_frame["STARTED"])
obj.keyframe_insert(data_path="hide_render", frame=product_frame["STARTED"])
obj.keyframe_insert(data_path="color", frame=product_frame["STARTED"])
obj.color = (1.0, 1.0, 1.0, 1)
obj.keyframe_insert(data_path="color", frame=product_frame["COMPLETED"])
def animate_destruction(self, obj, product_frame):
obj.color = (1.0, 1.0, 1.0, 1)
obj.hide_viewport = False
obj.hide_render = False
obj.keyframe_insert(data_path="color", frame=self.start_frame)
obj.keyframe_insert(data_path="hide_viewport", frame=self.start_frame)
obj.keyframe_insert(data_path="hide_render", frame=self.start_frame)
obj.keyframe_insert(data_path="color", frame=product_frame["STARTED"] - 1)
obj.color = (1.0, 0.0, 0.0, 1)
obj.keyframe_insert(data_path="color", frame=product_frame["STARTED"])
obj.hide_viewport = True
obj.hide_render = True
obj.color = (0.0, 0.0, 0.0, 1)
obj.keyframe_insert(data_path="color", frame=product_frame["COMPLETED"])
obj.keyframe_insert(data_path="hide_viewport", frame=product_frame["COMPLETED"])
obj.keyframe_insert(data_path="hide_render", frame=product_frame["COMPLETED"])
def animate_operation(self, obj, product_frame):
obj.color = (1.0, 1.0, 1.0, 1)
obj.keyframe_insert(data_path="color", frame=self.start_frame)
obj.keyframe_insert(data_path="color", frame=product_frame["STARTED"] - 1)
obj.color = (0.0, 0.0, 1.0, 1)
obj.keyframe_insert(data_path="color", frame=product_frame["STARTED"])
obj.color = (1.0, 1.0, 1.0, 1)
obj.keyframe_insert(data_path="color", frame=product_frame["COMPLETED"])
def animate_movement_to(self, obj, product_frame):
obj.hide_viewport = True
obj.hide_render = True
obj.keyframe_insert(data_path="hide_viewport", frame=self.start_frame)
obj.keyframe_insert(data_path="hide_render", frame=self.start_frame)
obj.hide_viewport = False
obj.hide_render = False
obj.color = (1.0, 1.0, 0.0, 1)
obj.keyframe_insert(data_path="hide_viewport", frame=product_frame["STARTED"])
obj.keyframe_insert(data_path="hide_render", frame=product_frame["STARTED"])
obj.keyframe_insert(data_path="color", frame=product_frame["STARTED"])
obj.color = (1.0, 1.0, 1.0, 1)
obj.keyframe_insert(data_path="color", frame=product_frame["COMPLETED"])
def animate_movement_from(self, obj, product_frame):
obj.color = (1.0, 1.0, 1.0, 1)
obj.keyframe_insert(data_path="color", frame=self.start_frame)
obj.hide_viewport = False
obj.hide_render = False
obj.keyframe_insert(data_path="color", frame=product_frame["STARTED"] - 1)
obj.keyframe_insert(data_path="hide_viewport", frame=product_frame["STARTED"] - 1)
obj.keyframe_insert(data_path="hide_render", frame=product_frame["STARTED"] - 1)
obj.color = (1.0, 0.5, 0.0, 1)
obj.keyframe_insert(data_path="color", frame=product_frame["STARTED"])
obj.hide_viewport = True
obj.hide_render = True
obj.color = (0.0, 0.0, 0.0, 1)
obj.keyframe_insert(data_path="color", frame=product_frame["COMPLETED"])
obj.keyframe_insert(data_path="hide_viewport", frame=product_frame["COMPLETED"])
obj.keyframe_insert(data_path="hide_render", frame=product_frame["COMPLETED"])
def animate_consumption(self, obj, product_frame):
obj.color = (1.0, 1.0, 1.0, 1)
obj.keyframe_insert(data_path="color", frame=self.start_frame)
obj.hide_viewport = False
obj.hide_render = False
obj.keyframe_insert(data_path="color", frame=product_frame["STARTED"] - 1)
obj.keyframe_insert(data_path="hide_viewport", frame=product_frame["STARTED"] - 1)
obj.keyframe_insert(data_path="hide_render", frame=product_frame["STARTED"] - 1)
obj.color = (0.0, 1.0, 1.0, 1)
obj.keyframe_insert(data_path="color", frame=product_frame["STARTED"])
obj.hide_viewport = True
obj.hide_render = True
obj.color = (0.0, 0.0, 0.0, 1)
obj.keyframe_insert(data_path="color", frame=product_frame["COMPLETED"])
obj.keyframe_insert(data_path="hide_viewport", frame=product_frame["COMPLETED"])
obj.keyframe_insert(data_path="hide_render", frame=product_frame["COMPLETED"])
def calculate_total_frames(self, context):
if self.props.speed_types == "FRAME_SPEED":
return self.calculate_using_frames(
self.start,
self.finish,
self.props.speed_animation_frames,
isodate.parse_duration(self.props.speed_real_duration),
)
elif self.props.speed_types == "DURATION_SPEED":
return self.calculate_using_duration(
self.start,
self.finish,
context.scene.render.fps,
isodate.parse_duration(self.props.speed_animation_duration),
isodate.parse_duration(self.props.speed_real_duration),
)
elif self.props.speed_types == "MULTIPLIER_SPEED":
return self.calculate_using_multiplier(
self.start,
self.finish,
context.scene.render.fps,
self.props.speed_multiplier,
)
def calculate_using_multiplier(self, start, finish, fps, multiplier):
animation_time = (finish - start) / multiplier
return animation_time.total_seconds() * fps
def calculate_using_duration(self, start, finish, fps, animation_duration, real_duration):
return self.calculate_using_multiplier(start, finish, fps, real_duration / animation_duration)
def calculate_using_frames(self, start, finish, animation_frames, real_duration):
return ((finish - start) / real_duration) * animation_frames
def preprocess_tasks(self):
self.product_frames = {}
for rel in self.file.by_id(self.work_schedule).Controls or []:
for related_object in rel.RelatedObjects:
if related_object.is_a("IfcTask"):
self.preprocess_task(related_object)
def preprocess_task(self, task):
for rel in task.IsNestedBy or []:
for related_object in rel.RelatedObjects:
self.preprocess_task(related_object)
start = helper.derive_date(task.id(), "ScheduleStart", is_earliest=True)
finish = helper.derive_date(task.id(), "ScheduleFinish", is_latest=True)
if not start or not finish:
return
for output_id in Data.tasks[task.id()]["Outputs"]:
self.add_product_frame(output_id, task, start, finish, "output")
for input_id in Data.tasks[task.id()]["Inputs"]:
self.add_product_frame(input_id, task, start, finish, "input")
def add_product_frame(self, product_id, task, start, finish, relationship):
self.product_frames.setdefault(product_id, []).append(
{
"type": task.PredefinedType,
"relationship": relationship,
"STARTED": round(self.start_frame + (((start - self.start) / self.duration) * self.total_frames)),
"COMPLETED": round(self.start_frame + (((finish - self.start) / self.duration) * self.total_frames)),
}
)
class BlenderBIM_DatePicker(bpy.types.Operator):
bl_label = "Date Picker"
bl_idname = "bim.datepicker"
bl_options = {"REGISTER", "UNDO"}
display_date: bpy.props.StringProperty(name="Display Date")
selected_date: bpy.props.StringProperty(name="Selected Date")
target_prop: bpy.props.StringProperty(name="Target date prop to set")
def execute(self, context):
helper.set_scene_prop(self.target_prop, self.selected_date)
return {"FINISHED"}
def draw(self, context):
self.selected_date = helper.get_scene_prop("DatePickerProperties.selected_date") or helper.canonicalise_time(
datetime.now()
)
current_date = parser.parse(context.scene.DatePickerProperties.display_date, dayfirst=True, fuzzy=True)
current_month = (current_date.year, current_date.month)
lines = calendar.monthcalendar(*current_month)
month_title, week_titles = calendar.month(*current_month).splitlines()[:2]
layout = self.layout
row = layout.row()
row.prop(self, "selected_date")
split = layout.split()
col = split.row()
op = col.operator("bim.redraw_datepicker", icon="TRIA_LEFT", text="")
op.action = "previous"
col = split.row()
col.label(text=month_title.strip())
col = split.row()
col.alignment = "RIGHT"
op = col.operator("bim.redraw_datepicker", icon="TRIA_RIGHT", text="")
op.action = "next"
row = layout.row(align=True)
for title in week_titles.split():
col = row.column(align=True)
col.alignment = "CENTER"
col.label(text=title.strip())
for line in lines:
row = layout.row(align=True)
for i in line:
col = row.column(align=True)
if i == 0:
col.label(text=" ")
else:
op = col.operator("bim.datepicker_setdate", text="{:2d}".format(i))
selected_date = "{}/{}/{}".format(i, current_date.month, current_date.year)
selected_date = parser.parse(selected_date, dayfirst=True, fuzzy=True)
op.selected_date = helper.canonicalise_time(selected_date)
def invoke(self, context, event):
self.display_date = helper.get_scene_prop(self.target_prop) or helper.canonicalise_time(datetime.now())
context.scene.DatePickerProperties.display_date = self.display_date
context.scene.DatePickerProperties.selected_date = self.display_date
return context.window_manager.invoke_props_dialog(self)
class BlenderBIM_DatePickerSetDate(bpy.types.Operator):
bl_label = "set date"
bl_idname = "bim.datepicker_setdate"
bl_options = {"REGISTER", "UNDO"}
selected_date: bpy.props.StringProperty()
def invoke(self, context, event):
context.scene.DatePickerProperties.selected_date = self.selected_date
return {"FINISHED"}
class BlenderBIM_RedrawDatePicker(bpy.types.Operator):
bl_label = "redraw datepicker window"
bl_idname = "bim.redraw_datepicker"
bl_options = {"REGISTER", "UNDO"}
action: bpy.props.StringProperty()
def invoke(self, context, event):
current_date = parser.parse(context.scene.DatePickerProperties.display_date, dayfirst=True, fuzzy=True)
if self.action == "previous":
date_to_set = current_date - relativedelta.relativedelta(months=1)
elif self.action == "next":
date_to_set = current_date + relativedelta.relativedelta(months=1)
context.scene.DatePickerProperties.display_date = helper.canonicalise_time(date_to_set)
return {"FINISHED"}
class RecalculateSchedule(bpy.types.Operator):
bl_idname = "bim.recalculate_schedule"
bl_label = "Recalculate Schedule"
bl_options = {"REGISTER", "UNDO"}
work_schedule: bpy.props.IntProperty()
def execute(self, context):
return IfcStore.execute_ifc_operator(self, context)
def _execute(self, context):
self.file = IfcStore.get_file()
ifcopenshell.api.run(
"sequence.recalculate_schedule", self.file, work_schedule=self.file.by_id(self.work_schedule)
)
Data.load(self.file)
return {"FINISHED"}
class AddTaskColumn(bpy.types.Operator):
bl_idname = "bim.add_task_column"
bl_label = "Add Task Column"
bl_options = {"REGISTER", "UNDO"}
column_type: bpy.props.StringProperty()
name: bpy.props.StringProperty()
data_type: bpy.props.StringProperty()
def execute(self, context):
self.props = context.scene.BIMWorkScheduleProperties
new = self.props.columns.add()
new.name = f"{self.column_type}.{self.name}"
new.data_type = self.data_type
return {"FINISHED"}
class RemoveTaskColumn(bpy.types.Operator):
bl_idname = "bim.remove_task_column"
bl_label = "Remove Task Column"
bl_options = {"REGISTER", "UNDO"}
name: bpy.props.StringProperty()
def execute(self, context):
self.props = context.scene.BIMWorkScheduleProperties
self.props.columns.remove(self.props.columns.find(self.name))
return {"FINISHED"}
class SetTaskSortColumn(bpy.types.Operator):
bl_idname = "bim.set_task_sort_column"
bl_label = "Set Task Sort Column"
bl_options = {"REGISTER", "UNDO"}
column: bpy.props.StringProperty()
def execute(self, context):
self.props = context.scene.BIMWorkScheduleProperties
self.props.sort_column = self.column
bpy.ops.bim.enable_editing_tasks(work_schedule=self.props.active_work_schedule_id)
return {"FINISHED"}
class LoadTaskResources(bpy.types.Operator):
bl_idname = "bim.load_task_resources"
bl_label = "Load Task Resources"
bl_options = {"REGISTER", "UNDO"}
def execute(self, context):
self.file = IfcStore.get_file()
self.props = context.scene.BIMWorkScheduleProperties
self.tprops = context.scene.BIMTaskTreeProperties
ifc_definition_id = self.tprops.tasks[self.props.active_task_index].ifc_definition_id
self.props.task_resources.clear()
for resource_id in Data.tasks[ifc_definition_id]["Resources"]:
resource = self.file.by_id(resource_id)
new = self.props.task_resources.add()
new.ifc_definition_id = resource_id
new.name = resource.Name or "Unnamed"
return {"FINISHED"}
class LoadTaskInputs(bpy.types.Operator):
bl_idname = "bim.load_task_inputs"
bl_label = "Load Task Inputs"
bl_options = {"REGISTER", "UNDO"}
def execute(self, context):
self.file = IfcStore.get_file()
self.props = context.scene.BIMWorkScheduleProperties
self.tprops = context.scene.BIMTaskTreeProperties
ifc_definition_id = self.tprops.tasks[self.props.active_task_index].ifc_definition_id
self.props.task_inputs.clear()
for input_id in Data.tasks[ifc_definition_id]["Inputs"]:
product = self.file.by_id(input_id)
new = self.props.task_inputs.add()
new.ifc_definition_id = input_id
new.name = product.Name or "Unnamed"
return {"FINISHED"}
class LoadTaskOutputs(bpy.types.Operator):
bl_idname = "bim.load_task_outputs"
bl_label = "Load Task Outputs"
bl_options = {"REGISTER", "UNDO"}
def execute(self, context):
self.file = IfcStore.get_file()
self.props = context.scene.BIMWorkScheduleProperties
self.tprops = context.scene.BIMTaskTreeProperties
ifc_definition_id = self.tprops.tasks[self.props.active_task_index].ifc_definition_id
self.props.task_outputs.clear()
for output_id in Data.tasks[ifc_definition_id]["Outputs"]:
product = self.file.by_id(output_id)
new = self.props.task_outputs.add()
new.ifc_definition_id = output_id
new.name = product.Name or "Unnamed"
return {"FINISHED"}
class CalculateTaskDuration(bpy.types.Operator):
bl_idname = "bim.calculate_task_duration"
bl_label = "Calculate Task Duration"
bl_options = {"REGISTER", "UNDO"}
task: bpy.props.IntProperty()
def execute(self, context):
props = context.scene.BIMWorkScheduleProperties
self.file = IfcStore.get_file()
ifcopenshell.api.run("sequence.calculate_task_duration", self.file, task=self.file.by_id(self.task))
Data.load(self.file)
bpy.ops.bim.enable_editing_tasks(work_schedule=props.active_work_schedule_id)
return {"FINISHED"}