Derive start and finish dates and elapsed durations where possible in the task tree

This commit is contained in:
Dion Moult
2021-05-05 11:59:33 +10:00
parent 925c40c6ba
commit ee46e76340
4 changed files with 72 additions and 19 deletions
@@ -307,12 +307,43 @@ class LoadTaskProperties(bpy.types.Operator):
isodate.duration_isoformat(task_time["ScheduleDuration"]) if task_time["ScheduleDuration"] else "-"
)
else:
derived_start = self.derive_start(item.ifc_definition_id)
derived_finish = self.derive_finish(item.ifc_definition_id)
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:
derived_duration = ifcopenshell.util.date.timedelta2duration(derived_finish - derived_start)
item.derived_duration = isodate.duration_isoformat(derived_duration)
item.start = "-"
item.finish = "-"
item.duration = "-"
self.props.is_task_update_enabled = True
return {"FINISHED"}
def derive_start(self, ifc_definition_id, start=None):
task = Data.tasks[ifc_definition_id]
if task["TaskTime"]:
schedule_start = Data.task_times[task["TaskTime"]]["ScheduleStart"]
if schedule_start:
return schedule_start
for subtask in task["RelatedObjects"]:
schedule_start = self.derive_start(subtask, start)
if schedule_start and (start is None or schedule_start < start):
start = schedule_start
return start
def derive_finish(self, ifc_definition_id, finish=None):
task = Data.tasks[ifc_definition_id]
if task["TaskTime"]:
schedule_finish = Data.task_times[task["TaskTime"]]["ScheduleFinish"]
if schedule_finish:
return schedule_finish
for subtask in task["RelatedObjects"]:
schedule_finish = self.derive_finish(subtask, finish)
if schedule_finish and (finish is None or schedule_finish > finish):
finish = schedule_finish
return finish
def canonicalise_time(self, time):
if not time:
return "-"
@@ -850,7 +881,7 @@ class ImportP6(bpy.types.Operator, ImportHelper):
p62ifc = P62Ifc()
p62ifc.xml = self.filepath
p62ifc.file = self.file
p62ifc.work_plan = self.file.by_type("IfcWorkPlan")[0]
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))
@@ -1284,7 +1315,9 @@ class UnassignLagTime(bpy.types.Operator):
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)})
ifcopenshell.api.run(
"sequence.unassign_lag_time", self.file, **{"rel_sequence": self.file.by_id(self.sequence)}
)
Data.load(IfcStore.get_file())
return {"FINISHED"}
@@ -1296,12 +1329,15 @@ class AssignLagTime(bpy.types.Operator):
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"})
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"
@@ -1357,7 +1393,6 @@ class EditSequenceTimeLag(bpy.types.Operator):
return {"FINISHED"}
class DisableEditingSequence(bpy.types.Operator):
bl_idname = "bim.disable_editing_sequence"
bl_label = "Disable Editing Sequence Attributes"
@@ -128,6 +128,9 @@ class Task(PropertyGroup):
duration: StringProperty(name="Duration")
start: StringProperty(name="Start", update=updateTaskTimeStart)
finish: StringProperty(name="Finish", update=updateTaskTimeFinish)
derived_start: StringProperty(name="Derived Start")
derived_finish: StringProperty(name="Derived Finish")
derived_duration: StringProperty(name="Derived Duration")
is_predecessor: BoolProperty(name="Is Predecessor")
is_successor: BoolProperty(name="Is Successor")
@@ -298,9 +298,20 @@ class BIM_UL_tasks(UIList):
row.prop(item, "name", emboss=False, text="")
if props.should_show_times:
row.prop(item, "start", emboss=False, text="")
row.prop(item, "finish", emboss=False, text="")
row.prop(item, "duration", emboss=False, text="")
if item.derived_start:
row.label(text=item.derived_start + "*")
else:
row.prop(item, "start", emboss=False, text="")
if item.derived_finish:
row.label(text=item.derived_finish + "*")
else:
row.prop(item, "finish", emboss=False, text="")
if item.derived_duration:
row.label(text=item.derived_duration + "*")
else:
row.prop(item, "duration", emboss=False, text="")
if context.active_object:
oprops = context.active_object.BIMObjectProperties
@@ -7,21 +7,25 @@ except:
pass # Duration parsing not supported
def timedelta2duration(timedelta):
components = {
"days": getattr(timedelta, "days", 0),
"hours": 0,
"minutes": 0,
"seconds": getattr(timedelta, "seconds", 0),
}
if components["seconds"]:
components["hours"], components["minutes"], components["seconds"] = [
int(i) for i in str(datetime.timedelta(seconds=components["seconds"])).split(":")
]
return isodate.Duration(**components)
def ifc2datetime(element):
if isinstance(element, str) and element[0] == "P": # IfcDuration
duration = isodate.parse_duration(element)
if isinstance(duration, datetime.timedelta):
components = {
"days": getattr(duration, "days", 0),
"hours": 0,
"minutes": 0,
"seconds": getattr(duration, "seconds", 0),
}
if components["seconds"]:
components["hours"], components["minutes"], components["seconds"] = [
int(i) for i in str(datetime.timedelta(seconds=components["seconds"])).split(":")
]
duration = isodate.Duration(**components)
return timedelta2duration(duration)
return duration
elif isinstance(element, str) and element[2] == ":": # IfcTime
return datetime.time.fromisoformat(element)