mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-16 21:42:19 +00:00
BBIM 4D: implement human readable duration to read/edit durations.
new IOS Fuzzy Duration Parsing utility
This commit is contained in:
@@ -33,11 +33,7 @@ def parse_datetime(value):
|
|||||||
|
|
||||||
|
|
||||||
def parse_duration(value):
|
def parse_duration(value):
|
||||||
try:
|
return ifcopenshell.util.date.parse_duration(value)
|
||||||
return isodate.parse_duration(value)
|
|
||||||
except:
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def canonicalise_time(time):
|
def canonicalise_time(time):
|
||||||
if not time:
|
if not time:
|
||||||
|
|||||||
@@ -203,9 +203,8 @@ def updateTaskDuration(self, context):
|
|||||||
if self.duration == "-":
|
if self.duration == "-":
|
||||||
return
|
return
|
||||||
|
|
||||||
try:
|
duration = ifcopenshell.util.date.parse_duration(self.duration)
|
||||||
isodate.parse_duration(self.duration),
|
if not duration:
|
||||||
except:
|
|
||||||
self.duration = "-"
|
self.duration = "-"
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -215,17 +214,12 @@ def updateTaskDuration(self, context):
|
|||||||
task_time = task.TaskTime
|
task_time = task.TaskTime
|
||||||
else:
|
else:
|
||||||
task_time = ifcopenshell.api.run("sequence.add_task_time", self.file, task=task)
|
task_time = ifcopenshell.api.run("sequence.add_task_time", self.file, task=task)
|
||||||
SequenceData.load()
|
|
||||||
ifcopenshell.api.run(
|
ifcopenshell.api.run(
|
||||||
"sequence.edit_task_time",
|
"sequence.edit_task_time",
|
||||||
self.file,
|
self.file,
|
||||||
**{"task_time": task_time, "attributes": {"ScheduleDuration": self.duration}},
|
**{"task_time": task_time, "attributes": {"ScheduleDuration": duration}},
|
||||||
)
|
)
|
||||||
SequenceData.load()
|
SequenceData.load()
|
||||||
if props.active_task_id == self.ifc_definition_id:
|
|
||||||
attribute = props.task_time_attributes.get("Duration")
|
|
||||||
if attribute:
|
|
||||||
attribute.string_value = self.duration
|
|
||||||
bpy.ops.bim.load_task_properties()
|
bpy.ops.bim.load_task_properties()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -374,7 +374,7 @@ class BIM_PT_work_schedules(Panel):
|
|||||||
|
|
||||||
def draw_editable_task_ui(self, work_schedule_id):
|
def draw_editable_task_ui(self, work_schedule_id):
|
||||||
row = self.layout.row(align=True)
|
row = self.layout.row(align=True)
|
||||||
row.label(text="")
|
row.label(text="Task Tools")
|
||||||
row = self.layout.row(align=True)
|
row = self.layout.row(align=True)
|
||||||
row.alignment = "RIGHT"
|
row.alignment = "RIGHT"
|
||||||
row.operator("bim.add_summary_task", text="Add Summary Task", icon="ADD").work_schedule = work_schedule_id
|
row.operator("bim.add_summary_task", text="Add Summary Task", icon="ADD").work_schedule = work_schedule_id
|
||||||
|
|||||||
@@ -225,7 +225,7 @@ class Sequence(blenderbim.core.tool.Sequence):
|
|||||||
else "-"
|
else "-"
|
||||||
)
|
)
|
||||||
item.duration = (
|
item.duration = (
|
||||||
isodate.duration_isoformat(ifcopenshell.util.date.ifc2datetime(task_time.ScheduleDuration))
|
str(ifcopenshell.util.date.readable_ifc_duration(task_time.ScheduleDuration))
|
||||||
if task_time.ScheduleDuration
|
if task_time.ScheduleDuration
|
||||||
else "-"
|
else "-"
|
||||||
)
|
)
|
||||||
@@ -243,7 +243,7 @@ class Sequence(blenderbim.core.tool.Sequence):
|
|||||||
item.finish = "-"
|
item.finish = "-"
|
||||||
item.duration = "-"
|
item.duration = "-"
|
||||||
|
|
||||||
bpy.context.scene.BIMWorkScheduleProperties.is_task_update_enabled = True
|
props.is_task_update_enabled = True
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_active_work_schedule(cls):
|
def get_active_work_schedule(cls):
|
||||||
|
|||||||
@@ -35,14 +35,15 @@ def timedelta2duration(timedelta):
|
|||||||
}
|
}
|
||||||
if components["seconds"]:
|
if components["seconds"]:
|
||||||
components["hours"], components["minutes"], components["seconds"] = [
|
components["hours"], components["minutes"], components["seconds"] = [
|
||||||
int(i) for i in str(datetime.timedelta(seconds=components["seconds"])).split(":")
|
int(i)
|
||||||
|
for i in str(datetime.timedelta(seconds=components["seconds"])).split(":")
|
||||||
]
|
]
|
||||||
return isodate.Duration(**components)
|
return isodate.Duration(**components)
|
||||||
|
|
||||||
|
|
||||||
def ifc2datetime(element):
|
def ifc2datetime(element):
|
||||||
if isinstance(element, str) and "P" in element[0:2]: # IfcDuration
|
if isinstance(element, str) and "P" in element[0:2]: # IfcDuration
|
||||||
duration = isodate.parse_duration(element)
|
duration = parse_duration(element)
|
||||||
if isinstance(duration, datetime.timedelta):
|
if isinstance(duration, datetime.timedelta):
|
||||||
return timedelta2duration(duration)
|
return timedelta2duration(duration)
|
||||||
return duration
|
return duration
|
||||||
@@ -72,6 +73,38 @@ def ifc2datetime(element):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def get_isosplit(s, split):
|
||||||
|
if split in s:
|
||||||
|
n, s = s.split(split)
|
||||||
|
else:
|
||||||
|
n = 0
|
||||||
|
return n, s
|
||||||
|
|
||||||
|
|
||||||
|
def readable_ifc_duration(string):
|
||||||
|
string = string.split("P")[-1]
|
||||||
|
|
||||||
|
years, string = get_isosplit(string, "Y")
|
||||||
|
months, string = get_isosplit(string, "M")
|
||||||
|
weeks, string = get_isosplit(string, "W")
|
||||||
|
days, string = get_isosplit(string, "D")
|
||||||
|
_, string = get_isosplit(string, "T")
|
||||||
|
hours, string = get_isosplit(string, "H")
|
||||||
|
minutes, string = get_isosplit(string, "M")
|
||||||
|
seconds, string = get_isosplit(string, "S")
|
||||||
|
|
||||||
|
final_string = ""
|
||||||
|
final_string += f"{years} y " if years else ""
|
||||||
|
final_string += f"{months} m " if months else ""
|
||||||
|
final_string += f"{weeks} w " if weeks else ""
|
||||||
|
final_string += f"{days} d " if days else ""
|
||||||
|
final_string += f"{hours} h " if hours else ""
|
||||||
|
final_string += f"{minutes} m " if minutes else ""
|
||||||
|
final_string += f"{seconds} s " if seconds else ""
|
||||||
|
|
||||||
|
return final_string
|
||||||
|
|
||||||
|
|
||||||
def datetime2ifc(dt, ifc_type):
|
def datetime2ifc(dt, ifc_type):
|
||||||
if isinstance(dt, str):
|
if isinstance(dt, str):
|
||||||
if ifc_type == "IfcDuration":
|
if ifc_type == "IfcDuration":
|
||||||
@@ -89,7 +122,9 @@ def datetime2ifc(dt, ifc_type):
|
|||||||
if isinstance(dt, datetime.datetime):
|
if isinstance(dt, datetime.datetime):
|
||||||
return dt.isoformat()
|
return dt.isoformat()
|
||||||
elif isinstance(dt, datetime.date):
|
elif isinstance(dt, datetime.date):
|
||||||
return datetime.datetime.combine(dt, datetime.datetime.min.time()).isoformat()
|
return datetime.datetime.combine(
|
||||||
|
dt, datetime.datetime.min.time()
|
||||||
|
).isoformat()
|
||||||
elif ifc_type == "IfcDate":
|
elif ifc_type == "IfcDate":
|
||||||
if isinstance(dt, datetime.datetime):
|
if isinstance(dt, datetime.datetime):
|
||||||
return dt.date().isoformat()
|
return dt.date().isoformat()
|
||||||
@@ -101,10 +136,19 @@ def datetime2ifc(dt, ifc_type):
|
|||||||
elif isinstance(dt, datetime.time):
|
elif isinstance(dt, datetime.time):
|
||||||
return dt.isoformat()
|
return dt.isoformat()
|
||||||
elif ifc_type == "IfcCalendarDate":
|
elif ifc_type == "IfcCalendarDate":
|
||||||
return {"DayComponent": dt.day, "MonthComponent": dt.month, "YearComponent": dt.year}
|
return {
|
||||||
|
"DayComponent": dt.day,
|
||||||
|
"MonthComponent": dt.month,
|
||||||
|
"YearComponent": dt.year,
|
||||||
|
}
|
||||||
elif ifc_type == "IfcLocalTime":
|
elif ifc_type == "IfcLocalTime":
|
||||||
# TODO implement timezones
|
# TODO implement timezones
|
||||||
return {"HourComponent": dt.hour, "MinuteComponent": dt.minute, "SecondComponent": dt.second}
|
return {
|
||||||
|
"HourComponent": dt.hour,
|
||||||
|
"MinuteComponent": dt.minute,
|
||||||
|
"SecondComponent": dt.second,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def string_to_date(string):
|
def string_to_date(string):
|
||||||
if not string:
|
if not string:
|
||||||
@@ -117,6 +161,7 @@ def string_to_date(string):
|
|||||||
except:
|
except:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def string_to_duration(duration_string):
|
def string_to_duration(duration_string):
|
||||||
# TODO support years, months, weeks aswell
|
# TODO support years, months, weeks aswell
|
||||||
days = 0
|
days = 0
|
||||||
@@ -135,4 +180,62 @@ def string_to_duration(duration_string):
|
|||||||
match = findall(r"(\d+\.?\d*)s", duration_string)
|
match = findall(r"(\d+\.?\d*)s", duration_string)
|
||||||
if match:
|
if match:
|
||||||
seconds = float(match[0])
|
seconds = float(match[0])
|
||||||
return isodate.duration_isoformat(datetime.timedelta(days=days, hours=hours, minutes=minutes, seconds=seconds))
|
return isodate.duration_isoformat(
|
||||||
|
datetime.timedelta(days=days, hours=hours, minutes=minutes, seconds=seconds)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_duration(value):
|
||||||
|
print("parsing duration", value)
|
||||||
|
if not value:
|
||||||
|
return None
|
||||||
|
if isinstance(value, str):
|
||||||
|
if "P" in value:
|
||||||
|
try:
|
||||||
|
return isodate.parse_duration(value)
|
||||||
|
except:
|
||||||
|
print("error parsing ISO string duration")
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
final_string = "P"
|
||||||
|
value_upper = value.upper()
|
||||||
|
for char in value_upper:
|
||||||
|
if char.isdigit():
|
||||||
|
final_string += char
|
||||||
|
elif char == "D":
|
||||||
|
final_string += "D"
|
||||||
|
if (
|
||||||
|
"H" in value_upper
|
||||||
|
or "S" in value_upper
|
||||||
|
or "MIN" in value_upper
|
||||||
|
):
|
||||||
|
final_string += "T"
|
||||||
|
elif char == "W":
|
||||||
|
final_string += "W"
|
||||||
|
elif char == "M":
|
||||||
|
final_string += "M"
|
||||||
|
elif char == "Y":
|
||||||
|
final_string += "Y"
|
||||||
|
elif char == "H":
|
||||||
|
final_string = (
|
||||||
|
final_string[:1] + "T" + final_string[1:]
|
||||||
|
if "T" not in final_string
|
||||||
|
else final_string
|
||||||
|
)
|
||||||
|
final_string += "H"
|
||||||
|
elif char == "M":
|
||||||
|
if "MIN" in value_upper and "T" not in final_string:
|
||||||
|
final_string = final_string[:1] + "T" + final_string[1:]
|
||||||
|
final_string += "M"
|
||||||
|
elif char == "S":
|
||||||
|
final_string = (
|
||||||
|
final_string[:1] + "T" + final_string[1:]
|
||||||
|
if "T" not in final_string
|
||||||
|
else final_string
|
||||||
|
)
|
||||||
|
final_string += "S"
|
||||||
|
return isodate.parse_duration(final_string)
|
||||||
|
except:
|
||||||
|
print("error fuzzy parsing duration")
|
||||||
|
return None
|
||||||
|
|||||||
Reference in New Issue
Block a user