Fix unfinished time/date/duration handling in edit task time, work plan, work schedule, and finally refactor attribute i/o like I promised

This commit is contained in:
Dion Moult
2021-05-06 17:14:28 +10:00
parent a13b257452
commit 8a3e023408
6 changed files with 177 additions and 403 deletions
+54 -145
View File
@@ -1,153 +1,62 @@
import bpy
import json
import math
import ifcopenshell
import ifcopenshell.util.attribute
from mathutils import geometry
from mathutils import Vector
import bpy
from blenderbim.bim.ifc import IfcStore
# TODO: Deprecate this in favour of ifcopenshell.util.unit
def import_attributes(ifc_class, props, data, callback=None):
for attribute in IfcStore.get_schema().declaration_by_name(ifc_class).all_attributes():
data_type = ifcopenshell.util.attribute.get_primitive_type(attribute)
if data_type == "entity":
continue
new = props.add()
new.name = attribute.name()
new.is_null = data[attribute.name()] is None
new.is_optional = attribute.optional()
new.data_type = data_type
is_handled_by_callback = callback(attribute.name(), new, data) if callback else False
if is_handled_by_callback:
pass # Our job is done
elif data_type == "string":
new.string_value = "" if new.is_null else data[attribute.name()]
elif data_type == "boolean":
new.bool_value = False if new.is_null else data[attribute.name()]
elif data_type == "integer":
new.int_value = 0 if new.is_null else data[attribute.name()]
elif data_type == "float":
new.float_value = 0.0 if new.is_null else data[attribute.name()]
elif data_type == "enum":
new.enum_items = json.dumps(ifcopenshell.util.attribute.get_enum_items(attribute))
if data[attribute.name()]:
new.enum_value = data[attribute.name()]
class SIUnitHelper:
prefixes = {
"EXA": 1e18,
"PETA": 1e15,
"TERA": 1e12,
"GIGA": 1e9,
"MEGA": 1e6,
"KILO": 1e3,
"HECTO": 1e2,
"DECA": 1e1,
"DECI": 1e-1,
"CENTI": 1e-2,
"MILLI": 1e-3,
"MICRO": 1e-6,
"NANO": 1e-9,
"PICO": 1e-12,
"FEMTO": 1e-15,
"ATTO": 1e-18,
}
unit_names = [
"AMPERE",
"BECQUEREL",
"CANDELA",
"COULOMB",
"CUBIC_METRE",
"DEGREE CELSIUS",
"FARAD",
"GRAM",
"GRAY",
"HENRY",
"HERTZ",
"JOULE",
"KELVIN",
"LUMEN",
"LUX",
"MOLE",
"NEWTON",
"OHM",
"PASCAL",
"RADIAN",
"SECOND",
"SIEMENS",
"SIEVERT",
"SQUARE METRE",
"METRE",
"STERADIAN",
"TESLA",
"VOLT",
"WATT",
"WEBER",
]
si_conversions = {
"inch": 0.0254,
"foot": 0.3048,
"yard": 0.914,
"mile": 1609,
"square inch": 0.0006452,
"square foot": 0.09290304,
"square yard": 0.83612736,
"acre": 4046.86,
"square mile": 2588881,
"cubic inch": 0.00001639,
"cubic foot": 0.02831684671168849,
"cubic yard": 0.7636,
"litre": 0.001,
"fluid ounce UK": 0.0000284130625,
"fluid ounce US": 0.00002957353,
"pint UK": 0.000568,
"pint US": 0.000473,
"gallon UK": 0.004546,
"gallon US": 0.003785,
"degree": math.pi / 180,
"ounce": 0.02835,
"pound": 0.454,
"ton UK": 1016.0469088,
"ton US": 907.18474,
"lbf": 4.4482216153,
"kip": 4448.2216153,
"psi": 6894.7572932,
"ksi": 6894757.2932,
"minute": 60,
"hour": 3600,
"day": 86400,
"btu": 1055.056,
}
def export_attributes(props, callback=None):
attributes = {}
for attribute in props:
is_handled_by_callback = callback(attributes, attribute) if callback else False
if attribute.is_null:
attributes[attribute.name] = None
elif is_handled_by_callback:
pass # Our job is done
elif attribute.data_type == "string":
attributes[attribute.name] = attribute.string_value
elif attribute.data_type == "boolean":
attributes[attribute.name] = attribute.bool_value
elif attribute.data_type == "integer":
attributes[attribute.name] = attribute.int_value
elif attribute.data_type == "float":
attributes[attribute.name] = attribute.float_value
elif attribute.data_type == "enum":
attributes[attribute.name] = attribute.enum_value
return attributes
@staticmethod
def get_prefix(text):
for prefix in SIUnitHelper.prefixes.keys():
if prefix in text.upper():
return prefix
@staticmethod
def get_prefix_multiplier(text):
if not text:
return 1
prefix = SIUnitHelper.get_prefix(text)
if prefix:
return SIUnitHelper.prefixes[prefix]
return 1
@staticmethod
def get_unit_name(text):
for name in SIUnitHelper.unit_names:
if name in text.upper().replace("METER", "METRE"):
return name
@staticmethod
def convert(value, from_prefix, from_unit, to_prefix, to_unit):
"""Converts between length, area, and volume units
:param value: The numeric value you want to convert
:type value: float
:param from_prefix: A prefix from IfcSIPrefix. Can be None.
:type from_prefix: string
:param from_unit: IfcSIUnitName or IfcConversionBasedUnit.Name
:type from_unit: string
:param to_prefix: A prefix from IfcSIPrefix. Can be None.
:type to_prefix: string
:param to_unit: IfcSIUnitName or IfcConversionBasedUnit.Name
:type to_unit: string
"""
if from_unit in SIUnitHelper.si_conversions:
value *= SIUnitHelper.si_conversions[from_unit]
elif from_prefix:
value *= SIUnitHelper.get_prefix_multiplier(from_prefix)
if "SQUARE" in from_unit:
value *= SIUnitHelper.get_prefix_multiplier(from_prefix)
elif "CUBIC" in from_unit:
value *= SIUnitHelper.get_prefix_multiplier(from_prefix)
value *= SIUnitHelper.get_prefix_multiplier(from_prefix)
if to_unit in SIUnitHelper.si_conversions:
return value * (1 / SIUnitHelper.si_conversions[to_unit])
elif to_prefix:
value *= 1 / SIUnitHelper.get_prefix_multiplier(to_prefix)
if "SQUARE" in from_unit:
value *= 1 / SIUnitHelper.get_prefix_multiplier(to_prefix)
elif "CUBIC" in from_unit:
value *= 1 / SIUnitHelper.get_prefix_multiplier(to_prefix)
value *= 1 / SIUnitHelper.get_prefix_multiplier(to_prefix)
return value
# TODO: migrate the below helper functions into the drawing module, since it is specific to that module
# This function stolen from https://github.com/kevancress/MeasureIt_ARCH/blob/dcf607ce0896aa2284463c6b4ae9cd023fc54cbe/measureit_arch_baseclass.py
@@ -302,7 +211,7 @@ def parse_diagram_scale(camera):
def get_project_collection(scene):
"""Get main project collection"""
colls = [c for c in scene.collection.children if c.name.startswith('IfcProject')]
colls = [c for c in scene.collection.children if c.name.startswith("IfcProject")]
if len(colls) != 1:
raise RuntimeError("project collection missing or not unique")
return colls[0]
@@ -315,7 +224,7 @@ def get_active_drawing(scene):
return None, None
try:
drawing = props.drawings[props.active_drawing_index]
return scene.collection.children['Views'].children[f"IfcGroup/{drawing.name}"], drawing.camera
return scene.collection.children["Views"].children[f"IfcGroup/{drawing.name}"], drawing.camera
except (KeyError, IndexError):
raise RuntimeError("missing drawing collection")
@@ -333,8 +242,8 @@ def ortho_view_frame(camera, margin=0.015):
"""
aspect = camera.BIMCameraProperties.raster_y / camera.BIMCameraProperties.raster_x
size = camera.ortho_scale
hwidth = size * .5
hheight = size * .5 * aspect
hwidth = size * 0.5
hheight = size * 0.5 * aspect
scale = parse_diagram_scale(camera)
xmarg = margin * scale
ymarg = margin * scale * aspect
@@ -1,3 +1,5 @@
import isodate
from dateutil import parser
from ifcopenshell.api.sequence.data import Data
@@ -18,3 +20,19 @@ def derive_date(ifc_definition_id, attribute_name, date=None, is_earliest=False,
if current_date and (date is None or current_date > date):
date = current_date
return date
def parse_datetime(value):
try:
return parser.isoparse(value)
except:
try:
return parser.parse(value, dayfirst=True, fuzzy=True)
except:
return None
def parse_duration(value):
try:
return isodate.parse_duration(value)
except:
return None
@@ -8,6 +8,7 @@ import pystache
import webbrowser
import ifcopenshell.api
import ifcopenshell.util.date
import blenderbim.bim.helper
import blenderbim.bim.module.sequence.helper as helper
from datetime import datetime
from datetime import timedelta
@@ -33,15 +34,7 @@ class EditWorkPlan(bpy.types.Operator):
def execute(self, context):
props = context.scene.BIMWorkPlanProperties
attributes = {}
for attribute in props.work_plan_attributes:
if attribute.is_null:
attributes[attribute.name] = None
else:
if attribute.data_type == "string":
attributes[attribute.name] = attribute.string_value
elif attribute.data_type == "enum":
attributes[attribute.name] = attribute.enum_value
attributes = blenderbim.bim.helper.export_attributes(props.work_plan_attributes, self.export_attributes)
self.file = IfcStore.get_file()
ifcopenshell.api.run(
"sequence.edit_work_plan",
@@ -52,6 +45,14 @@ class EditWorkPlan(bpy.types.Operator):
bpy.ops.bim.disable_editing_work_plan()
return {"FINISHED"}
def export_attributes(self, attributes, prop):
if "Date" in prop.name or "Time" in prop.name:
attributes[prop.name] = helper.parse_datetime(prop.string_value)
return True
elif prop.name == "Duration" or prop.name == "TotalFloat":
attributes[prop.name] = helper.parse_duration(prop.string_value)
return True
class RemoveWorkPlan(bpy.types.Operator):
bl_idname = "bim.remove_work_plan"
@@ -77,27 +78,17 @@ class EnableEditingWorkPlan(bpy.types.Operator):
data = Data.work_plans[self.work_plan]
for attribute in IfcStore.get_schema().declaration_by_name("IfcWorkPlan").all_attributes():
data_type = ifcopenshell.util.attribute.get_primitive_type(attribute)
if data_type == "entity":
continue
new = props.work_plan_attributes.add()
new.name = attribute.name()
new.is_null = data[attribute.name()] is None
new.is_optional = attribute.optional()
new.data_type = data_type
if attribute.name() in ["CreationDate", "StartTime", "FinishTime"]:
new.string_value = "" if new.is_null else data[attribute.name()].isoformat()
elif data_type == "string":
new.string_value = "" if new.is_null else data[attribute.name()]
elif data_type == "enum":
new.enum_items = json.dumps(ifcopenshell.util.attribute.get_enum_items(attribute))
if data[attribute.name()]:
new.enum_value = data[attribute.name()]
blenderbim.bim.helper.import_attributes("IfcWorkPlan", props.work_plan_attributes, data, self.import_attributes)
props.active_work_plan_id = self.work_plan
props.editing_type = "ATTRIBUTES"
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
class DisableEditingWorkPlan(bpy.types.Operator):
bl_idname = "bim.disable_editing_work_plan"
@@ -176,15 +167,7 @@ class EditWorkSchedule(bpy.types.Operator):
def execute(self, context):
props = context.scene.BIMWorkScheduleProperties
attributes = {}
for attribute in props.work_schedule_attributes:
if attribute.is_null:
attributes[attribute.name] = None
else:
if attribute.data_type == "string":
attributes[attribute.name] = attribute.string_value
elif attribute.data_type == "enum":
attributes[attribute.name] = attribute.enum_value
attributes = blenderbim.bim.helper.export_attributes(props.work_schedule_attributes, self.export_attributes)
self.file = IfcStore.get_file()
ifcopenshell.api.run(
"sequence.edit_work_schedule",
@@ -195,6 +178,14 @@ class EditWorkSchedule(bpy.types.Operator):
bpy.ops.bim.disable_editing_work_schedule()
return {"FINISHED"}
def export_attributes(self, attributes, prop):
if "Date" in prop.name or "Time" in prop.name:
attributes[prop.name] = helper.parse_datetime(prop.string_value)
return True
elif prop.name == "Duration" or prop.name == "TotalFloat":
attributes[prop.name] = helper.parse_duration(prop.string_value)
return True
class RemoveWorkSchedule(bpy.types.Operator):
bl_idname = "bim.remove_work_schedule"
@@ -227,23 +218,14 @@ class EnableEditingWorkSchedule(bpy.types.Operator):
def enable_editing_work_schedule(self):
data = Data.work_schedules[self.work_schedule]
for attribute in IfcStore.get_schema().declaration_by_name("IfcWorkSchedule").all_attributes():
data_type = ifcopenshell.util.attribute.get_primitive_type(attribute)
if data_type == "entity":
continue
new = self.props.work_schedule_attributes.add()
new.name = attribute.name()
new.is_null = data[attribute.name()] is None
new.is_optional = attribute.optional()
new.data_type = data_type
if attribute.name() in ["CreationDate", "StartTime", "FinishTime"]:
new.string_value = "" if new.is_null else data[attribute.name()].isoformat()
elif data_type == "string":
new.string_value = "" if new.is_null else data[attribute.name()]
elif data_type == "enum":
new.enum_items = json.dumps(ifcopenshell.util.attribute.get_enum_items(attribute))
if data[attribute.name()]:
new.enum_value = data[attribute.name()]
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):
@@ -439,39 +421,21 @@ class EnableEditingTaskTime(bpy.types.Operator):
data = Data.task_times[task_time_id]
for attribute in IfcStore.get_schema().declaration_by_name("IfcTaskTime").all_attributes():
data_type = ifcopenshell.util.attribute.get_primitive_type(attribute)
if data_type == "entity":
continue
new = props.task_time_attributes.add()
new.name = attribute.name()
new.is_null = data[attribute.name()] is None
new.is_optional = attribute.optional()
new.data_type = data_type
if data_type == "string":
if isinstance(data[attribute.name()], datetime):
new.string_value = "" if new.is_null else data[attribute.name()].isoformat()
elif isinstance(data[attribute.name()], isodate.Duration):
new.string_value = (
""
if new.is_null
else ifcopenshell.util.date.datetime2ifc(data[attribute.name()], "IfcDuration")
)
else:
new.string_value = "" if new.is_null else data[attribute.name()]
elif data_type == "boolean":
new.bool_value = False if new.is_null else data[attribute.name()]
elif data_type == "float":
new.float_value = 0.0 if new.is_null else data[attribute.name()]
elif data_type == "enum":
new.enum_items = json.dumps(ifcopenshell.util.attribute.get_enum_items(attribute))
if data[attribute.name()]:
new.enum_value = data[attribute.name()]
blenderbim.bim.helper.import_attributes("IfcTaskTime", props.task_time_attributes, data, self.import_attributes)
props.active_task_time_id = task_time_id
props.active_task_id = self.task
props.editing_task_type = "TASKTIME"
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):
prop.string_value = "" if prop.is_null else ifcopenshell.util.date.datetime2ifc(data[name], "IfcDuration")
return True
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(IfcStore.get_file())
@@ -484,20 +448,7 @@ class EditTaskTime(bpy.types.Operator):
def execute(self, context):
props = context.scene.BIMWorkScheduleProperties
attributes = {}
for attribute in props.task_time_attributes:
if attribute.is_null:
attributes[attribute.name] = None
else:
if attribute.data_type == "string":
attributes[attribute.name] = attribute.string_value
elif attribute.data_type == "boolean":
attributes[attribute.name] = attribute.bool_value
elif attribute.data_type == "float":
attributes[attribute.name] = attribute.float_value
elif attribute.data_type == "enum":
attributes[attribute.name] = attribute.enum_value
attributes = blenderbim.bim.helper.export_attributes(props.task_time_attributes, self.export_attributes)
attributes = self.convert_strings_to_date_times(attributes)
self.file = IfcStore.get_file()
@@ -511,21 +462,13 @@ class EditTaskTime(bpy.types.Operator):
bpy.ops.bim.load_task_properties(task=props.active_task_id)
return {"FINISHED"}
def convert_strings_to_date_times(self, attributes):
for key, value in attributes.items():
if not value:
continue
if "Start" in key or "Finish" in key or key == "StatusTime":
try:
attributes[key] = parser.isoparse(value)
except:
try:
attributes[key] = parser.parse(value, dayfirst=True, fuzzy=True)
except:
attributes[key] = None
elif key == "ScheduleDuration":
attributes[key] = isodate.parse_duration(value)
return attributes
def export_attributes(self, attributes, prop):
if "Start" in prop.name or "Finish" in prop.name or prop.name == "StatusTime":
attributes[prop.name] = helper.parse_datetime(value)
return True
elif prop.name == "ScheduleDuration":
attributes[prop.name] = helper.parse_duration(value)
return True
class EnableEditingTask(bpy.types.Operator):
@@ -540,25 +483,7 @@ class EnableEditingTask(bpy.types.Operator):
data = Data.tasks[self.task]
for attribute in IfcStore.get_schema().declaration_by_name("IfcTask").all_attributes():
data_type = ifcopenshell.util.attribute.get_primitive_type(attribute)
if data_type == "entity":
continue
new = props.task_attributes.add()
new.name = attribute.name()
new.is_null = data[attribute.name()] is None
new.is_optional = attribute.optional()
new.data_type = data_type
if data_type == "string":
new.string_value = "" if new.is_null else data[attribute.name()]
elif data_type == "boolean":
new.bool_value = False if new.is_null else data[attribute.name()]
elif data_type == "integer":
new.int_value = 0 if new.is_null else data[attribute.name()]
elif data_type == "enum":
new.enum_items = json.dumps(ifcopenshell.util.attribute.get_enum_items(attribute))
if data[attribute.name()]:
new.enum_value = data[attribute.name()]
blenderbim.bim.helper.import_attributes("IfcTask", props.task_attributes, data)
props.active_task_id = self.task
props.editing_task_type = "ATTRIBUTES"
return {"FINISHED"}
@@ -580,19 +505,7 @@ class EditTask(bpy.types.Operator):
def execute(self, context):
props = context.scene.BIMWorkScheduleProperties
attributes = {}
for attribute in props.task_attributes:
if attribute.is_null:
attributes[attribute.name] = None
else:
if attribute.data_type == "string":
attributes[attribute.name] = attribute.string_value
elif attribute.data_type == "boolean":
attributes[attribute.name] = attribute.bool_value
elif attribute.data_type == "integer":
attributes[attribute.name] = attribute.int_value
elif attribute.data_type == "enum":
attributes[attribute.name] = attribute.enum_value
attributes = blenderbim.bim.export_attributes(props.task_attributes)
self.file = IfcStore.get_file()
ifcopenshell.api.run(
"sequence.edit_task", self.file, **{"task": self.file.by_id(props.active_task_id), "attributes": attributes}
@@ -778,15 +691,7 @@ class EditWorkCalendar(bpy.types.Operator):
def execute(self, context):
props = context.scene.BIMWorkCalendarProperties
attributes = {}
for attribute in props.work_calendar_attributes:
if attribute.is_null:
attributes[attribute.name] = None
else:
if attribute.data_type == "string":
attributes[attribute.name] = attribute.string_value
elif attribute.data_type == "enum":
attributes[attribute.name] = attribute.enum_value
attributes = blenderbim.bim.helper.export_attributes(props.work_calendar_attributes)
self.file = IfcStore.get_file()
ifcopenshell.api.run(
"sequence.edit_work_calendar",
@@ -824,21 +729,7 @@ class EnableEditingWorkCalendar(bpy.types.Operator):
data = Data.work_calendars[self.work_calendar]
for attribute in IfcStore.get_schema().declaration_by_name("IfcWorkCalendar").all_attributes():
data_type = ifcopenshell.util.attribute.get_primitive_type(attribute)
if data_type == "entity":
continue
new = self.props.work_calendar_attributes.add()
new.name = attribute.name()
new.is_null = data[attribute.name()] is None
new.is_optional = attribute.optional()
new.data_type = data_type
if data_type == "string":
new.string_value = "" if new.is_null else data[attribute.name()]
elif data_type == "enum":
new.enum_items = json.dumps(ifcopenshell.util.attribute.get_enum_items(attribute))
if data[attribute.name()]:
new.enum_value = data[attribute.name()]
blenderbim.bim.helper.import_attributes("IfcWorkCalendar", self.props.work_calendar_attributes, data)
self.props.active_work_calendar_id = self.work_calendar
self.props.editing_type = "ATTRIBUTES"
return {"FINISHED"}
@@ -936,29 +827,20 @@ class EnableEditingWorkTime(bpy.types.Operator):
data = Data.work_times[self.work_time]
for attribute in IfcStore.get_schema().declaration_by_name("IfcWorkTime").all_attributes():
data_type = ifcopenshell.util.attribute.get_primitive_type(attribute)
if data_type == "entity":
continue
new = self.props.work_time_attributes.add()
new.name = attribute.name()
new.is_null = data[attribute.name()] is None
new.is_optional = attribute.optional()
new.data_type = data_type
if attribute.name() in ["Start", "Finish"]:
new.string_value = "" if new.is_null else data[attribute.name()].isoformat()
elif data_type == "string":
new.string_value = "" if new.is_null else data[attribute.name()]
elif data_type == "enum":
new.enum_items = json.dumps(ifcopenshell.util.attribute.get_enum_items(attribute))
if data[attribute.name()]:
new.enum_value = data[attribute.name()]
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):
@@ -1014,15 +896,7 @@ class EditWorkTime(bpy.types.Operator):
def execute(self, context):
self.props = context.scene.BIMWorkCalendarProperties
attributes = {}
for attribute in self.props.work_time_attributes:
if attribute.is_null:
attributes[attribute.name] = None
else:
if attribute.data_type == "string":
attributes[attribute.name] = attribute.string_value
elif attribute.data_type == "enum":
attributes[attribute.name] = attribute.enum_value
attributes = blenderbim.bim.helper.export_attributes(self.props.work_time_attributes)
self.file = IfcStore.get_file()
ifcopenshell.api.run(
"sequence.edit_work_time",
@@ -1251,21 +1125,7 @@ class EnableEditingSequenceAttributes(bpy.types.Operator):
def enable_editing_sequence_attributes(self):
data = Data.sequences[self.sequence]
for attribute in IfcStore.get_schema().declaration_by_name("IfcRelSequence").all_attributes():
data_type = ifcopenshell.util.attribute.get_primitive_type(attribute)
if data_type == "entity":
continue
new = self.props.sequence_attributes.add()
new.name = attribute.name()
new.is_null = data[attribute.name()] is None
new.is_optional = attribute.optional()
new.data_type = data_type
if data_type == "string":
new.string_value = "" if new.is_null else data[attribute.name()]
elif data_type == "enum":
new.enum_items = json.dumps(ifcopenshell.util.attribute.get_enum_items(attribute))
if data[attribute.name()]:
new.enum_value = data[attribute.name()]
blenderbim.bim.helper.import_attributes("IfcRelSequence", self.props.sequence_attributes, data)
class EnableEditingSequenceTimeLag(bpy.types.Operator):
@@ -1285,34 +1145,24 @@ class EnableEditingSequenceTimeLag(bpy.types.Operator):
def enable_editing_attributes(self):
data = Data.lag_times[self.lag_time]
for attribute in IfcStore.get_schema().declaration_by_name("IfcLagTime").all_attributes():
data_type = ifcopenshell.util.attribute.get_primitive_type(attribute)
if data_type == "entity":
continue
new = self.props.time_lag_attributes.add()
new.name = attribute.name()
new.is_null = data[attribute.name()] is None
new.is_optional = attribute.optional()
new.data_type = data_type
if attribute.name() == "LagValue":
if isinstance(data[attribute.name()], isodate.Duration):
new.data_type = "string"
new.string_value = (
""
if new.is_null
else ifcopenshell.util.date.datetime2ifc(data[attribute.name()], "IfcDuration")
)
else:
new.data_type = "float"
new.float_value = 0.0 if new.is_null else data[attribute.name()]
elif data_type == "string":
new.string_value = "" if new.is_null else data[attribute.name()]
elif data_type == "float":
new.float_value = 0.0 if new.is_null else data[attribute.name()]
elif data_type == "enum":
new.enum_items = json.dumps(ifcopenshell.util.attribute.get_enum_items(attribute))
if data[attribute.name()]:
new.enum_value = data[attribute.name()]
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 = (
""
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):
@@ -1351,15 +1201,7 @@ class EditSequenceAttributes(bpy.types.Operator):
def execute(self, context):
props = context.scene.BIMWorkScheduleProperties
attributes = {}
for attribute in props.sequence_attributes:
if attribute.is_null:
attributes[attribute.name] = None
else:
if attribute.data_type == "string":
attributes[attribute.name] = attribute.string_value
elif attribute.data_type == "enum":
attributes[attribute.name] = attribute.enum_value
attributes = blenderbim.bim.helper.export_attributes(props.sequence_attributes)
self.file = IfcStore.get_file()
ifcopenshell.api.run(
"sequence.edit_sequence",
@@ -1378,17 +1220,7 @@ class EditSequenceTimeLag(bpy.types.Operator):
def execute(self, context):
props = context.scene.BIMWorkScheduleProperties
attributes = {}
for attribute in props.time_lag_attributes:
if attribute.is_null:
attributes[attribute.name] = None
else:
if attribute.data_type == "string":
attributes[attribute.name] = attribute.string_value
elif attribute.data_type == "float":
attributes[attribute.name] = attribute.float_value
elif attribute.data_type == "enum":
attributes[attribute.name] = attribute.enum_value
attributes = blenderbim.bim.helper.export_attributes(props.time_lag_attributes)
self.file = IfcStore.get_file()
ifcopenshell.api.run(
"sequence.edit_lag_time",
@@ -10,10 +10,9 @@ class Usecase:
def execute(self):
for name, value in self.settings["attributes"].items():
if "Start" in name or "Finish" in name or name == "StatusTime":
if value:
if value:
if "Start" in name or "Finish" in name or name == "StatusTime":
value = ifcopenshell.util.date.datetime2ifc(value, "IfcDateTime")
if name == "ScheduleDuration":
if value:
elif name == "ScheduleDuration":
value = ifcopenshell.util.date.datetime2ifc(value, "IfcDuration")
setattr(self.settings["task_time"], name, value)
@@ -1,3 +1,6 @@
import ifcopenshell.util.date
class Usecase:
def __init__(self, file, **settings):
self.file = file
@@ -7,4 +10,9 @@ class Usecase:
def execute(self):
for name, value in self.settings["attributes"].items():
if value:
if "Date" in name or "Time" in name:
value = ifcopenshell.util.date.datetime2ifc(value, "IfcDateTime")
elif name == "Duration" or name == "TotalFloat":
value = ifcopenshell.util.date.datetime2ifc(value, "IfcDuration")
setattr(self.settings["work_plan"], name, value)
@@ -1,3 +1,6 @@
import ifcopenshell.util.date
class Usecase:
def __init__(self, file, **settings):
self.file = file
@@ -7,4 +10,9 @@ class Usecase:
def execute(self):
for name, value in self.settings["attributes"].items():
if value:
if "Date" in name or "Time" in name:
value = ifcopenshell.util.date.datetime2ifc(value, "IfcDateTime")
elif name == "Duration" or name == "TotalFloat":
value = ifcopenshell.util.date.datetime2ifc(value, "IfcDuration")
setattr(self.settings["work_schedule"], name, value)