mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-11 22:31:55 +00:00
Update to ifcopenshell.util.date for handling of IfcDuration with python and import of Planned Durations from P6 .xml exports in blenderBIM
This commit is contained in:
@@ -7,6 +7,7 @@ import webbrowser
|
|||||||
import ifcopenshell.api
|
import ifcopenshell.api
|
||||||
import ifcopenshell.util.date
|
import ifcopenshell.util.date
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from datetime import timedelta
|
||||||
from dateutil import parser
|
from dateutil import parser
|
||||||
from blenderbim.bim.ifc import IfcStore
|
from blenderbim.bim.ifc import IfcStore
|
||||||
from bpy_extras.io_utils import ImportHelper
|
from bpy_extras.io_utils import ImportHelper
|
||||||
@@ -301,8 +302,7 @@ class LoadTaskProperties(bpy.types.Operator):
|
|||||||
task_time = Data.task_times[task["TaskTime"]]
|
task_time = Data.task_times[task["TaskTime"]]
|
||||||
item.start = self.canonicalise_time(task_time["ScheduleStart"])
|
item.start = self.canonicalise_time(task_time["ScheduleStart"])
|
||||||
item.finish = self.canonicalise_time(task_time["ScheduleFinish"])
|
item.finish = self.canonicalise_time(task_time["ScheduleFinish"])
|
||||||
# TODO: duration
|
item.duration = str(task_time["ScheduleDuration"].days) if task_time["ScheduleDuration"] else "-"
|
||||||
item.duration = "-"
|
|
||||||
else:
|
else:
|
||||||
item.start = "-"
|
item.start = "-"
|
||||||
item.finish = "-"
|
item.finish = "-"
|
||||||
@@ -431,6 +431,8 @@ class EnableEditingTaskTime(bpy.types.Operator):
|
|||||||
if data_type == "string":
|
if data_type == "string":
|
||||||
if isinstance(data[attribute.name()], datetime):
|
if isinstance(data[attribute.name()], datetime):
|
||||||
new.string_value = "" if new.is_null else data[attribute.name()].isoformat()
|
new.string_value = "" if new.is_null else data[attribute.name()].isoformat()
|
||||||
|
elif isinstance(data[attribute.name()], timedelta):
|
||||||
|
new.string_value = "" if new.is_null else ifcopenshell.util.date.datetime2ifc(data[attribute.name()], "IfcDuration")
|
||||||
else:
|
else:
|
||||||
new.string_value = "" if new.is_null else data[attribute.name()]
|
new.string_value = "" if new.is_null else data[attribute.name()]
|
||||||
elif data_type == "boolean":
|
elif data_type == "boolean":
|
||||||
@@ -497,6 +499,8 @@ class EditTaskTime(bpy.types.Operator):
|
|||||||
attributes[key] = parser.parse(value, dayfirst=True, fuzzy=True)
|
attributes[key] = parser.parse(value, dayfirst=True, fuzzy=True)
|
||||||
except:
|
except:
|
||||||
attributes[key] = None
|
attributes[key] = None
|
||||||
|
elif key == "ScheduleDuration":
|
||||||
|
attributes[key] = ifcopenshell.util.date.ifc2datetime(value)
|
||||||
return attributes
|
return attributes
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
import ifcopenshell.util.date
|
import ifcopenshell.util.date
|
||||||
from datetime import datetime
|
|
||||||
from datetime import timedelta
|
|
||||||
|
|
||||||
class Usecase:
|
class Usecase:
|
||||||
def __init__(self, file, **settings):
|
def __init__(self, file, **settings):
|
||||||
|
|||||||
@@ -154,7 +154,8 @@ class Data:
|
|||||||
continue
|
continue
|
||||||
if "Start" in key or "Finish" in key or key == "StatusTime":
|
if "Start" in key or "Finish" in key or key == "StatusTime":
|
||||||
data[key] = ifcopenshell.util.date.ifc2datetime(value)
|
data[key] = ifcopenshell.util.date.ifc2datetime(value)
|
||||||
# TODO parse duration
|
elif key == "ScheduleDuration":
|
||||||
|
data[key] = ifcopenshell.util.date.ifc2datetime(value)
|
||||||
cls.task_times[task_time.id()] = data
|
cls.task_times[task_time.id()] = data
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|||||||
@@ -13,4 +13,7 @@ class Usecase:
|
|||||||
if "Start" in name or "Finish" in name or name == "StatusTime":
|
if "Start" in name or "Finish" in name or name == "StatusTime":
|
||||||
if value:
|
if value:
|
||||||
value = ifcopenshell.util.date.datetime2ifc(value, "IfcDateTime")
|
value = ifcopenshell.util.date.datetime2ifc(value, "IfcDateTime")
|
||||||
|
if name == "ScheduleDuration":
|
||||||
|
if value:
|
||||||
|
value = ifcopenshell.util.date.datetime2ifc(value, "IfcDuration")
|
||||||
setattr(self.settings["task_time"], name, value)
|
setattr(self.settings["task_time"], name, value)
|
||||||
|
|||||||
@@ -1,6 +1,39 @@
|
|||||||
import datetime
|
import datetime
|
||||||
from re import findall
|
from re import findall
|
||||||
|
|
||||||
|
# https://gist.github.com/spatialtime/c1924a3b178b4fe721fe406e0bf1a1dc
|
||||||
|
import re
|
||||||
|
from datetime import timedelta
|
||||||
|
|
||||||
|
|
||||||
|
def format_duration(td):
|
||||||
|
s = td.seconds
|
||||||
|
ms = td.microseconds
|
||||||
|
if ms != 0: # Round microseconds to milliseconds.
|
||||||
|
ms /= 1000000
|
||||||
|
ms = round(ms,3)
|
||||||
|
s += ms
|
||||||
|
return "P{}DT{}S".format(td.days,s)
|
||||||
|
|
||||||
|
def parse_duration(iso_duration):
|
||||||
|
m = re.match(r'^P(?:(\d+)Y)?(?:(\d+)M)?(?:(\d+)D)?T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+(?:.\d+)?)S)?$',
|
||||||
|
iso_duration)
|
||||||
|
if m is None:
|
||||||
|
raise ValueError("invalid ISO 8601 duration string")
|
||||||
|
days = 0
|
||||||
|
hours = 0
|
||||||
|
minutes = 0
|
||||||
|
seconds = 0.0
|
||||||
|
if m[3]:
|
||||||
|
days = int(m[3])
|
||||||
|
if m[4]:
|
||||||
|
hours = int(m[4])
|
||||||
|
if m[5]:
|
||||||
|
minutes = int(m[5])
|
||||||
|
if m[6]:
|
||||||
|
seconds = float(m[6])
|
||||||
|
return timedelta(days=days, hours=hours, minutes=minutes, seconds=seconds)
|
||||||
|
|
||||||
|
|
||||||
def duration2dict(duration):
|
def duration2dict(duration):
|
||||||
results = {}
|
results = {}
|
||||||
@@ -11,7 +44,7 @@ def duration2dict(duration):
|
|||||||
|
|
||||||
def ifc2datetime(element):
|
def ifc2datetime(element):
|
||||||
if isinstance(element, str) and element[0] == "P": # IfcDuration
|
if isinstance(element, str) and element[0] == "P": # IfcDuration
|
||||||
return duration2dict(element)
|
return parse_duration(element)
|
||||||
elif isinstance(element, str) and element[2] == ":": # IfcTime
|
elif isinstance(element, str) and element[2] == ":": # IfcTime
|
||||||
return datetime.time.fromisoformat(element)
|
return datetime.time.fromisoformat(element)
|
||||||
elif isinstance(element, str) and ":" in element: # IfcDateTime
|
elif isinstance(element, str) and ":" in element: # IfcDateTime
|
||||||
@@ -39,8 +72,10 @@ def ifc2datetime(element):
|
|||||||
|
|
||||||
|
|
||||||
def datetime2ifc(dt, ifc_type):
|
def datetime2ifc(dt, ifc_type):
|
||||||
if isinstance(dt, str):
|
if isinstance(dt, str) and ifc_type != "IfcDuration":
|
||||||
dt = datetime.datetime.fromisoformat(dt)
|
dt = datetime.datetime.fromisoformat(dt)
|
||||||
|
if ifc_type == "IfcDuration":
|
||||||
|
return format_duration(dt)
|
||||||
if ifc_type == "IfcTimeStamp":
|
if ifc_type == "IfcTimeStamp":
|
||||||
return int(dt.timestamp())
|
return int(dt.timestamp())
|
||||||
elif ifc_type == "IfcDateTime":
|
elif ifc_type == "IfcDateTime":
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import datetime
|
import datetime
|
||||||
|
from datetime import timedelta
|
||||||
import ifcopenshell
|
import ifcopenshell
|
||||||
import ifcopenshell.api
|
import ifcopenshell.api
|
||||||
import ifcopenshell.util.date
|
import ifcopenshell.util.date
|
||||||
@@ -121,6 +122,7 @@ class P62Ifc:
|
|||||||
"Identification": activity.find("pr:Id", self.ns).text,
|
"Identification": activity.find("pr:Id", self.ns).text,
|
||||||
"StartDate": datetime.datetime.fromisoformat(activity.find("pr:StartDate", self.ns).text),
|
"StartDate": datetime.datetime.fromisoformat(activity.find("pr:StartDate", self.ns).text),
|
||||||
"FinishDate": datetime.datetime.fromisoformat(activity.find("pr:FinishDate", self.ns).text),
|
"FinishDate": datetime.datetime.fromisoformat(activity.find("pr:FinishDate", self.ns).text),
|
||||||
|
"PlannedDuration": datetime.timedelta(days=float(activity.find("pr:PlannedDuration", self.ns).text)),
|
||||||
"Status": activity.find("pr:Status", self.ns).text,
|
"Status": activity.find("pr:Status", self.ns).text,
|
||||||
"ifc": None,
|
"ifc": None,
|
||||||
}
|
}
|
||||||
@@ -335,6 +337,7 @@ class P62Ifc:
|
|||||||
attributes={
|
attributes={
|
||||||
"ScheduleStart": activity["StartDate"],
|
"ScheduleStart": activity["StartDate"],
|
||||||
"ScheduleFinish": activity["FinishDate"],
|
"ScheduleFinish": activity["FinishDate"],
|
||||||
|
"ScheduleDuration": activity["PlannedDuration"] if activity["PlannedDuration"] else None,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user