mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-19 06:39:13 +00:00
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:
@@ -1,153 +1,62 @@
|
|||||||
|
import bpy
|
||||||
|
import json
|
||||||
import math
|
import math
|
||||||
|
import ifcopenshell
|
||||||
|
import ifcopenshell.util.attribute
|
||||||
from mathutils import geometry
|
from mathutils import geometry
|
||||||
from mathutils import Vector
|
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:
|
def export_attributes(props, callback=None):
|
||||||
prefixes = {
|
attributes = {}
|
||||||
"EXA": 1e18,
|
for attribute in props:
|
||||||
"PETA": 1e15,
|
is_handled_by_callback = callback(attributes, attribute) if callback else False
|
||||||
"TERA": 1e12,
|
if attribute.is_null:
|
||||||
"GIGA": 1e9,
|
attributes[attribute.name] = None
|
||||||
"MEGA": 1e6,
|
elif is_handled_by_callback:
|
||||||
"KILO": 1e3,
|
pass # Our job is done
|
||||||
"HECTO": 1e2,
|
elif attribute.data_type == "string":
|
||||||
"DECA": 1e1,
|
attributes[attribute.name] = attribute.string_value
|
||||||
"DECI": 1e-1,
|
elif attribute.data_type == "boolean":
|
||||||
"CENTI": 1e-2,
|
attributes[attribute.name] = attribute.bool_value
|
||||||
"MILLI": 1e-3,
|
elif attribute.data_type == "integer":
|
||||||
"MICRO": 1e-6,
|
attributes[attribute.name] = attribute.int_value
|
||||||
"NANO": 1e-9,
|
elif attribute.data_type == "float":
|
||||||
"PICO": 1e-12,
|
attributes[attribute.name] = attribute.float_value
|
||||||
"FEMTO": 1e-15,
|
elif attribute.data_type == "enum":
|
||||||
"ATTO": 1e-18,
|
attributes[attribute.name] = attribute.enum_value
|
||||||
}
|
return attributes
|
||||||
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,
|
|
||||||
}
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_prefix(text):
|
|
||||||
for prefix in SIUnitHelper.prefixes.keys():
|
|
||||||
if prefix in text.upper():
|
|
||||||
return prefix
|
|
||||||
|
|
||||||
@staticmethod
|
# TODO: migrate the below helper functions into the drawing module, since it is specific to that module
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
# This function stolen from https://github.com/kevancress/MeasureIt_ARCH/blob/dcf607ce0896aa2284463c6b4ae9cd023fc54cbe/measureit_arch_baseclass.py
|
# 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):
|
def get_project_collection(scene):
|
||||||
"""Get main project collection"""
|
"""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:
|
if len(colls) != 1:
|
||||||
raise RuntimeError("project collection missing or not unique")
|
raise RuntimeError("project collection missing or not unique")
|
||||||
return colls[0]
|
return colls[0]
|
||||||
@@ -315,7 +224,7 @@ def get_active_drawing(scene):
|
|||||||
return None, None
|
return None, None
|
||||||
try:
|
try:
|
||||||
drawing = props.drawings[props.active_drawing_index]
|
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):
|
except (KeyError, IndexError):
|
||||||
raise RuntimeError("missing drawing collection")
|
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
|
aspect = camera.BIMCameraProperties.raster_y / camera.BIMCameraProperties.raster_x
|
||||||
size = camera.ortho_scale
|
size = camera.ortho_scale
|
||||||
hwidth = size * .5
|
hwidth = size * 0.5
|
||||||
hheight = size * .5 * aspect
|
hheight = size * 0.5 * aspect
|
||||||
scale = parse_diagram_scale(camera)
|
scale = parse_diagram_scale(camera)
|
||||||
xmarg = margin * scale
|
xmarg = margin * scale
|
||||||
ymarg = margin * scale * aspect
|
ymarg = margin * scale * aspect
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import isodate
|
||||||
|
from dateutil import parser
|
||||||
from ifcopenshell.api.sequence.data import Data
|
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):
|
if current_date and (date is None or current_date > date):
|
||||||
date = current_date
|
date = current_date
|
||||||
return 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 webbrowser
|
||||||
import ifcopenshell.api
|
import ifcopenshell.api
|
||||||
import ifcopenshell.util.date
|
import ifcopenshell.util.date
|
||||||
|
import blenderbim.bim.helper
|
||||||
import blenderbim.bim.module.sequence.helper as helper
|
import blenderbim.bim.module.sequence.helper as helper
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
@@ -33,15 +34,7 @@ class EditWorkPlan(bpy.types.Operator):
|
|||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
props = context.scene.BIMWorkPlanProperties
|
props = context.scene.BIMWorkPlanProperties
|
||||||
attributes = {}
|
attributes = blenderbim.bim.helper.export_attributes(props.work_plan_attributes, self.export_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
|
|
||||||
self.file = IfcStore.get_file()
|
self.file = IfcStore.get_file()
|
||||||
ifcopenshell.api.run(
|
ifcopenshell.api.run(
|
||||||
"sequence.edit_work_plan",
|
"sequence.edit_work_plan",
|
||||||
@@ -52,6 +45,14 @@ class EditWorkPlan(bpy.types.Operator):
|
|||||||
bpy.ops.bim.disable_editing_work_plan()
|
bpy.ops.bim.disable_editing_work_plan()
|
||||||
return {"FINISHED"}
|
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):
|
class RemoveWorkPlan(bpy.types.Operator):
|
||||||
bl_idname = "bim.remove_work_plan"
|
bl_idname = "bim.remove_work_plan"
|
||||||
@@ -77,27 +78,17 @@ class EnableEditingWorkPlan(bpy.types.Operator):
|
|||||||
|
|
||||||
data = Data.work_plans[self.work_plan]
|
data = Data.work_plans[self.work_plan]
|
||||||
|
|
||||||
for attribute in IfcStore.get_schema().declaration_by_name("IfcWorkPlan").all_attributes():
|
blenderbim.bim.helper.import_attributes("IfcWorkPlan", props.work_plan_attributes, data, self.import_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()]
|
|
||||||
props.active_work_plan_id = self.work_plan
|
props.active_work_plan_id = self.work_plan
|
||||||
props.editing_type = "ATTRIBUTES"
|
props.editing_type = "ATTRIBUTES"
|
||||||
return {"FINISHED"}
|
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):
|
class DisableEditingWorkPlan(bpy.types.Operator):
|
||||||
bl_idname = "bim.disable_editing_work_plan"
|
bl_idname = "bim.disable_editing_work_plan"
|
||||||
@@ -176,15 +167,7 @@ class EditWorkSchedule(bpy.types.Operator):
|
|||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
props = context.scene.BIMWorkScheduleProperties
|
props = context.scene.BIMWorkScheduleProperties
|
||||||
attributes = {}
|
attributes = blenderbim.bim.helper.export_attributes(props.work_schedule_attributes, self.export_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
|
|
||||||
self.file = IfcStore.get_file()
|
self.file = IfcStore.get_file()
|
||||||
ifcopenshell.api.run(
|
ifcopenshell.api.run(
|
||||||
"sequence.edit_work_schedule",
|
"sequence.edit_work_schedule",
|
||||||
@@ -195,6 +178,14 @@ class EditWorkSchedule(bpy.types.Operator):
|
|||||||
bpy.ops.bim.disable_editing_work_schedule()
|
bpy.ops.bim.disable_editing_work_schedule()
|
||||||
return {"FINISHED"}
|
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):
|
class RemoveWorkSchedule(bpy.types.Operator):
|
||||||
bl_idname = "bim.remove_work_schedule"
|
bl_idname = "bim.remove_work_schedule"
|
||||||
@@ -227,23 +218,14 @@ class EnableEditingWorkSchedule(bpy.types.Operator):
|
|||||||
def enable_editing_work_schedule(self):
|
def enable_editing_work_schedule(self):
|
||||||
data = Data.work_schedules[self.work_schedule]
|
data = Data.work_schedules[self.work_schedule]
|
||||||
|
|
||||||
for attribute in IfcStore.get_schema().declaration_by_name("IfcWorkSchedule").all_attributes():
|
blenderbim.bim.helper.import_attributes(
|
||||||
data_type = ifcopenshell.util.attribute.get_primitive_type(attribute)
|
"IfcWorkSchedule", self.props.work_schedule_attributes, data, self.import_attributes
|
||||||
if data_type == "entity":
|
)
|
||||||
continue
|
|
||||||
new = self.props.work_schedule_attributes.add()
|
def import_attributes(self, name, prop, data):
|
||||||
new.name = attribute.name()
|
if name in ["CreationDate", "StartTime", "FinishTime"]:
|
||||||
new.is_null = data[attribute.name()] is None
|
prop.string_value = "" if prop.is_null else data[name].isoformat()
|
||||||
new.is_optional = attribute.optional()
|
return True
|
||||||
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()]
|
|
||||||
|
|
||||||
|
|
||||||
class EnableEditingTasks(bpy.types.Operator):
|
class EnableEditingTasks(bpy.types.Operator):
|
||||||
@@ -439,39 +421,21 @@ class EnableEditingTaskTime(bpy.types.Operator):
|
|||||||
|
|
||||||
data = Data.task_times[task_time_id]
|
data = Data.task_times[task_time_id]
|
||||||
|
|
||||||
for attribute in IfcStore.get_schema().declaration_by_name("IfcTaskTime").all_attributes():
|
blenderbim.bim.helper.import_attributes("IfcTaskTime", props.task_time_attributes, data, self.import_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()]
|
|
||||||
props.active_task_time_id = task_time_id
|
props.active_task_time_id = task_time_id
|
||||||
props.active_task_id = self.task
|
props.active_task_id = self.task
|
||||||
props.editing_task_type = "TASKTIME"
|
props.editing_task_type = "TASKTIME"
|
||||||
return {"FINISHED"}
|
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):
|
def add_task_time(self):
|
||||||
task_time = ifcopenshell.api.run("sequence.add_task_time", self.file, task=self.file.by_id(self.task))
|
task_time = ifcopenshell.api.run("sequence.add_task_time", self.file, task=self.file.by_id(self.task))
|
||||||
Data.load(IfcStore.get_file())
|
Data.load(IfcStore.get_file())
|
||||||
@@ -484,20 +448,7 @@ class EditTaskTime(bpy.types.Operator):
|
|||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
props = context.scene.BIMWorkScheduleProperties
|
props = context.scene.BIMWorkScheduleProperties
|
||||||
attributes = {}
|
attributes = blenderbim.bim.helper.export_attributes(props.task_time_attributes, self.export_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 = self.convert_strings_to_date_times(attributes)
|
attributes = self.convert_strings_to_date_times(attributes)
|
||||||
|
|
||||||
self.file = IfcStore.get_file()
|
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)
|
bpy.ops.bim.load_task_properties(task=props.active_task_id)
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
def convert_strings_to_date_times(self, attributes):
|
def export_attributes(self, attributes, prop):
|
||||||
for key, value in attributes.items():
|
if "Start" in prop.name or "Finish" in prop.name or prop.name == "StatusTime":
|
||||||
if not value:
|
attributes[prop.name] = helper.parse_datetime(value)
|
||||||
continue
|
return True
|
||||||
if "Start" in key or "Finish" in key or key == "StatusTime":
|
elif prop.name == "ScheduleDuration":
|
||||||
try:
|
attributes[prop.name] = helper.parse_duration(value)
|
||||||
attributes[key] = parser.isoparse(value)
|
return True
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
class EnableEditingTask(bpy.types.Operator):
|
class EnableEditingTask(bpy.types.Operator):
|
||||||
@@ -540,25 +483,7 @@ class EnableEditingTask(bpy.types.Operator):
|
|||||||
|
|
||||||
data = Data.tasks[self.task]
|
data = Data.tasks[self.task]
|
||||||
|
|
||||||
for attribute in IfcStore.get_schema().declaration_by_name("IfcTask").all_attributes():
|
blenderbim.bim.helper.import_attributes("IfcTask", props.task_attributes, data)
|
||||||
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()]
|
|
||||||
props.active_task_id = self.task
|
props.active_task_id = self.task
|
||||||
props.editing_task_type = "ATTRIBUTES"
|
props.editing_task_type = "ATTRIBUTES"
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
@@ -580,19 +505,7 @@ class EditTask(bpy.types.Operator):
|
|||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
props = context.scene.BIMWorkScheduleProperties
|
props = context.scene.BIMWorkScheduleProperties
|
||||||
attributes = {}
|
attributes = blenderbim.bim.export_attributes(props.task_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
|
|
||||||
self.file = IfcStore.get_file()
|
self.file = IfcStore.get_file()
|
||||||
ifcopenshell.api.run(
|
ifcopenshell.api.run(
|
||||||
"sequence.edit_task", self.file, **{"task": self.file.by_id(props.active_task_id), "attributes": attributes}
|
"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):
|
def execute(self, context):
|
||||||
props = context.scene.BIMWorkCalendarProperties
|
props = context.scene.BIMWorkCalendarProperties
|
||||||
attributes = {}
|
attributes = blenderbim.bim.helper.export_attributes(props.work_calendar_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
|
|
||||||
self.file = IfcStore.get_file()
|
self.file = IfcStore.get_file()
|
||||||
ifcopenshell.api.run(
|
ifcopenshell.api.run(
|
||||||
"sequence.edit_work_calendar",
|
"sequence.edit_work_calendar",
|
||||||
@@ -824,21 +729,7 @@ class EnableEditingWorkCalendar(bpy.types.Operator):
|
|||||||
|
|
||||||
data = Data.work_calendars[self.work_calendar]
|
data = Data.work_calendars[self.work_calendar]
|
||||||
|
|
||||||
for attribute in IfcStore.get_schema().declaration_by_name("IfcWorkCalendar").all_attributes():
|
blenderbim.bim.helper.import_attributes("IfcWorkCalendar", self.props.work_calendar_attributes, data)
|
||||||
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()]
|
|
||||||
self.props.active_work_calendar_id = self.work_calendar
|
self.props.active_work_calendar_id = self.work_calendar
|
||||||
self.props.editing_type = "ATTRIBUTES"
|
self.props.editing_type = "ATTRIBUTES"
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
@@ -936,29 +827,20 @@ class EnableEditingWorkTime(bpy.types.Operator):
|
|||||||
|
|
||||||
data = Data.work_times[self.work_time]
|
data = Data.work_times[self.work_time]
|
||||||
|
|
||||||
for attribute in IfcStore.get_schema().declaration_by_name("IfcWorkTime").all_attributes():
|
blenderbim.bim.helper.import_attributes(
|
||||||
data_type = ifcopenshell.util.attribute.get_primitive_type(attribute)
|
"IfcWorkTime", self.props.work_time_attributes, data, self.import_attributes
|
||||||
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()]
|
|
||||||
|
|
||||||
self.initialise_recurrence_components()
|
self.initialise_recurrence_components()
|
||||||
self.load_recurrence_pattern_data(data)
|
self.load_recurrence_pattern_data(data)
|
||||||
self.props.active_work_time_id = self.work_time
|
self.props.active_work_time_id = self.work_time
|
||||||
return {"FINISHED"}
|
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):
|
def initialise_recurrence_components(self):
|
||||||
if len(self.props.day_components) == 0:
|
if len(self.props.day_components) == 0:
|
||||||
for i in range(0, 31):
|
for i in range(0, 31):
|
||||||
@@ -1014,15 +896,7 @@ class EditWorkTime(bpy.types.Operator):
|
|||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
self.props = context.scene.BIMWorkCalendarProperties
|
self.props = context.scene.BIMWorkCalendarProperties
|
||||||
attributes = {}
|
attributes = blenderbim.bim.helper.export_attributes(self.props.work_time_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
|
|
||||||
self.file = IfcStore.get_file()
|
self.file = IfcStore.get_file()
|
||||||
ifcopenshell.api.run(
|
ifcopenshell.api.run(
|
||||||
"sequence.edit_work_time",
|
"sequence.edit_work_time",
|
||||||
@@ -1251,21 +1125,7 @@ class EnableEditingSequenceAttributes(bpy.types.Operator):
|
|||||||
|
|
||||||
def enable_editing_sequence_attributes(self):
|
def enable_editing_sequence_attributes(self):
|
||||||
data = Data.sequences[self.sequence]
|
data = Data.sequences[self.sequence]
|
||||||
for attribute in IfcStore.get_schema().declaration_by_name("IfcRelSequence").all_attributes():
|
blenderbim.bim.helper.import_attributes("IfcRelSequence", self.props.sequence_attributes, data)
|
||||||
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()]
|
|
||||||
|
|
||||||
|
|
||||||
class EnableEditingSequenceTimeLag(bpy.types.Operator):
|
class EnableEditingSequenceTimeLag(bpy.types.Operator):
|
||||||
@@ -1285,34 +1145,24 @@ class EnableEditingSequenceTimeLag(bpy.types.Operator):
|
|||||||
|
|
||||||
def enable_editing_attributes(self):
|
def enable_editing_attributes(self):
|
||||||
data = Data.lag_times[self.lag_time]
|
data = Data.lag_times[self.lag_time]
|
||||||
for attribute in IfcStore.get_schema().declaration_by_name("IfcLagTime").all_attributes():
|
blenderbim.bim.helper.import_attributes(
|
||||||
data_type = ifcopenshell.util.attribute.get_primitive_type(attribute)
|
"IfcLagTime", self.props.time_lag_attributes, data, self.import_attributes
|
||||||
if data_type == "entity":
|
)
|
||||||
continue
|
|
||||||
new = self.props.time_lag_attributes.add()
|
def import_attributes(self, name, prop, data):
|
||||||
new.name = attribute.name()
|
if name == "LagValue":
|
||||||
new.is_null = data[attribute.name()] is None
|
if isinstance(data[name], isodate.Duration):
|
||||||
new.is_optional = attribute.optional()
|
prop.data_type = "string"
|
||||||
new.data_type = data_type
|
prop.string_value = (
|
||||||
if attribute.name() == "LagValue":
|
""
|
||||||
if isinstance(data[attribute.name()], isodate.Duration):
|
if prop.is_null
|
||||||
new.data_type = "string"
|
else ifcopenshell.util.date.datetime2ifc(data[name], "IfcDuration")
|
||||||
new.string_value = (
|
)
|
||||||
""
|
return True
|
||||||
if new.is_null
|
else:
|
||||||
else ifcopenshell.util.date.datetime2ifc(data[attribute.name()], "IfcDuration")
|
prop.data_type = "float"
|
||||||
)
|
prop.float_value = 0.0 if prop.is_null else data[name]
|
||||||
else:
|
return True
|
||||||
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()]
|
|
||||||
|
|
||||||
|
|
||||||
class UnassignLagTime(bpy.types.Operator):
|
class UnassignLagTime(bpy.types.Operator):
|
||||||
@@ -1351,15 +1201,7 @@ class EditSequenceAttributes(bpy.types.Operator):
|
|||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
props = context.scene.BIMWorkScheduleProperties
|
props = context.scene.BIMWorkScheduleProperties
|
||||||
attributes = {}
|
attributes = blenderbim.bim.helper.export_attributes(props.sequence_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
|
|
||||||
self.file = IfcStore.get_file()
|
self.file = IfcStore.get_file()
|
||||||
ifcopenshell.api.run(
|
ifcopenshell.api.run(
|
||||||
"sequence.edit_sequence",
|
"sequence.edit_sequence",
|
||||||
@@ -1378,17 +1220,7 @@ class EditSequenceTimeLag(bpy.types.Operator):
|
|||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
props = context.scene.BIMWorkScheduleProperties
|
props = context.scene.BIMWorkScheduleProperties
|
||||||
attributes = {}
|
attributes = blenderbim.bim.helper.export_attributes(props.time_lag_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
|
|
||||||
self.file = IfcStore.get_file()
|
self.file = IfcStore.get_file()
|
||||||
ifcopenshell.api.run(
|
ifcopenshell.api.run(
|
||||||
"sequence.edit_lag_time",
|
"sequence.edit_lag_time",
|
||||||
|
|||||||
@@ -10,10 +10,9 @@ class Usecase:
|
|||||||
|
|
||||||
def execute(self):
|
def execute(self):
|
||||||
for name, value in self.settings["attributes"].items():
|
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")
|
value = ifcopenshell.util.date.datetime2ifc(value, "IfcDateTime")
|
||||||
if name == "ScheduleDuration":
|
elif name == "ScheduleDuration":
|
||||||
if value:
|
|
||||||
value = ifcopenshell.util.date.datetime2ifc(value, "IfcDuration")
|
value = ifcopenshell.util.date.datetime2ifc(value, "IfcDuration")
|
||||||
setattr(self.settings["task_time"], name, value)
|
setattr(self.settings["task_time"], name, value)
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
import ifcopenshell.util.date
|
||||||
|
|
||||||
|
|
||||||
class Usecase:
|
class Usecase:
|
||||||
def __init__(self, file, **settings):
|
def __init__(self, file, **settings):
|
||||||
self.file = file
|
self.file = file
|
||||||
@@ -7,4 +10,9 @@ class Usecase:
|
|||||||
|
|
||||||
def execute(self):
|
def execute(self):
|
||||||
for name, value in self.settings["attributes"].items():
|
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)
|
setattr(self.settings["work_plan"], name, value)
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
import ifcopenshell.util.date
|
||||||
|
|
||||||
|
|
||||||
class Usecase:
|
class Usecase:
|
||||||
def __init__(self, file, **settings):
|
def __init__(self, file, **settings):
|
||||||
self.file = file
|
self.file = file
|
||||||
@@ -7,4 +10,9 @@ class Usecase:
|
|||||||
|
|
||||||
def execute(self):
|
def execute(self):
|
||||||
for name, value in self.settings["attributes"].items():
|
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)
|
setattr(self.settings["work_schedule"], name, value)
|
||||||
|
|||||||
Reference in New Issue
Block a user