mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-11 10:06:47 +00:00
BlenderBIM and ifcopenshell.api features to enable adding and editing resource time information
This commit is contained in:
@@ -14,6 +14,9 @@ classes = (
|
||||
operator.ContractResource,
|
||||
operator.AssignResource,
|
||||
operator.UnassignResource,
|
||||
operator.EnableEditingResourceTime,
|
||||
operator.EditResourceTime,
|
||||
operator.DisableEditingResourceTime,
|
||||
prop.Resource,
|
||||
prop.BIMResourceProperties,
|
||||
prop.BIMResourceTreeProperties,
|
||||
|
||||
@@ -3,6 +3,11 @@ import json
|
||||
import ifcopenshell.api
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
from ifcopenshell.api.resource.data import Data
|
||||
import blenderbim.bim.helper
|
||||
import blenderbim.bim.module.sequence.helper as helper
|
||||
import time
|
||||
from datetime import datetime
|
||||
import isodate
|
||||
|
||||
|
||||
class LoadResources(bpy.types.Operator):
|
||||
@@ -50,6 +55,7 @@ class EnableEditingResource(bpy.types.Operator):
|
||||
self.props.active_resource_id = self.resource
|
||||
while len(self.props.resource_attributes) > 0:
|
||||
self.props.resource_attributes.remove(0)
|
||||
self.props.editing_resource_type = "ATTRIBUTES"
|
||||
self.enable_editing_resource()
|
||||
return {"FINISHED"}
|
||||
|
||||
@@ -72,6 +78,7 @@ class EnableEditingResource(bpy.types.Operator):
|
||||
new.enum_value = data[attribute.name()]
|
||||
|
||||
|
||||
|
||||
class LoadResourceProperties(bpy.types.Operator):
|
||||
bl_idname = "bim.load_resource_properties"
|
||||
bl_label = "Load Resource Properties"
|
||||
@@ -98,6 +105,7 @@ class DisableEditingResource(bpy.types.Operator):
|
||||
|
||||
def execute(self, context):
|
||||
context.scene.BIMResourceProperties.active_resource_id = 0
|
||||
context.scene.BIMResourceProperties.active_task_time_id = 0
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
@@ -143,15 +151,7 @@ class EditResource(bpy.types.Operator):
|
||||
|
||||
def _execute(self, context):
|
||||
props = context.scene.BIMResourceProperties
|
||||
attributes = {}
|
||||
for attribute in props.resource_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.resource_attributes)
|
||||
self.file = IfcStore.get_file()
|
||||
ifcopenshell.api.run(
|
||||
"resource.edit_resource",
|
||||
@@ -265,3 +265,87 @@ class UnassignResource(bpy.types.Operator):
|
||||
)
|
||||
Data.load(self.file)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class EnableEditingResourceTime(bpy.types.Operator):
|
||||
bl_idname = "bim.enable_editing_resource_time"
|
||||
bl_label = "Enable Editing Resource Usage"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
resource: bpy.props.IntProperty()
|
||||
|
||||
def execute(self, context):
|
||||
return IfcStore.execute_ifc_operator(self, context)
|
||||
|
||||
def _execute(self, context):
|
||||
props = context.scene.BIMResourceProperties
|
||||
self.file = IfcStore.get_file()
|
||||
resource_time_id = Data.resources[self.resource]["Usage"] or self.add_resource_time().id()
|
||||
while len(props.resource_time_attributes) > 0:
|
||||
props.resource_time_attributes.remove(0)
|
||||
|
||||
data = Data.resource_times[resource_time_id]
|
||||
|
||||
blenderbim.bim.helper.import_attributes("IfcResourceTime", props.resource_time_attributes, data, self.import_attributes)
|
||||
props.active_resource_time_id = resource_time_id
|
||||
props.active_resource_id = self.resource
|
||||
props.editing_resource_type = "USAGE"
|
||||
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_resource_time(self):
|
||||
resource_time = ifcopenshell.api.run("resource.add_resource_time", self.file, resource=self.file.by_id(self.resource))
|
||||
Data.load(self.file)
|
||||
return resource_time
|
||||
|
||||
|
||||
class DisableEditingResourceTime(bpy.types.Operator):
|
||||
bl_idname = "bim.disable_editing_resource_time"
|
||||
bl_label = "Disable Editing Resource Time"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
context.scene.BIMResourceProperties.active_resource_time_id = 0
|
||||
bpy.ops.bim.disable_editing_resource()
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class EditResourceTime(bpy.types.Operator):
|
||||
bl_idname = "bim.edit_resource_time"
|
||||
bl_label = "Edit Resource Usage"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
return IfcStore.execute_ifc_operator(self, context)
|
||||
|
||||
def _execute(self, context):
|
||||
self.props = context.scene.BIMResourceProperties
|
||||
attributes = blenderbim.bim.helper.export_attributes(self.props.resource_time_attributes, self.export_attributes)
|
||||
|
||||
self.file = IfcStore.get_file()
|
||||
ifcopenshell.api.run(
|
||||
"resource.edit_resource_time",
|
||||
self.file,
|
||||
**{"resource_time": self.file.by_id(self.props.active_resource_time_id), "attributes": attributes},
|
||||
)
|
||||
Data.load(self.file)
|
||||
bpy.ops.bim.disable_editing_resource_time()
|
||||
bpy.ops.bim.load_resource_properties(resource=self.props.active_resource_id)
|
||||
return {"FINISHED"}
|
||||
|
||||
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(prop.string_value)
|
||||
return True
|
||||
elif prop.name =="LevelingDelay" or "Work" in prop.name:
|
||||
attributes[prop.name] = helper.parse_duration(prop.string_value)
|
||||
return True
|
||||
|
||||
@@ -52,3 +52,6 @@ class BIMResourceProperties(PropertyGroup):
|
||||
contracted_resources: StringProperty(name="Contracted Resources", default="[]")
|
||||
is_resource_update_enabled: BoolProperty(name="Is Resource Update Enabled", default=True)
|
||||
is_loaded: BoolProperty(name="Is Editing")
|
||||
active_resource_time_id: IntProperty(name="Active Resource Usage Id")
|
||||
resource_time_attributes: CollectionProperty(name="Resource Usage Attributes", type=Attribute)
|
||||
editing_resource_type: StringProperty(name="Editing Resource Type")
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
from bpy.types import Panel, UIList
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
from ifcopenshell.api.resource.data import Data
|
||||
|
||||
import blenderbim.bim.helper
|
||||
|
||||
class BIM_PT_resources(Panel):
|
||||
bl_label = "IFC Resources"
|
||||
@@ -65,24 +65,17 @@ class BIM_PT_resources(Panel):
|
||||
self.props,
|
||||
"active_resource_index",
|
||||
)
|
||||
if self.props.active_resource_id:
|
||||
self.draw_editable_resource_ui()
|
||||
if self.props.active_resource_id and self.props.editing_resource_type == "ATTRIBUTES":
|
||||
self.draw_editable_resource_attributes_ui()
|
||||
|
||||
def draw_editable_resource_ui(self):
|
||||
for attribute in self.props.resource_attributes:
|
||||
row = self.layout.row(align=True)
|
||||
if attribute.data_type == "string":
|
||||
row.prop(attribute, "string_value", text=attribute.name)
|
||||
elif attribute.data_type == "boolean":
|
||||
row.prop(attribute, "bool_value", text=attribute.name)
|
||||
elif attribute.data_type == "integer":
|
||||
row.prop(attribute, "int_value", text=attribute.name)
|
||||
elif attribute.data_type == "float":
|
||||
row.prop(attribute, "float_value", text=attribute.name)
|
||||
elif attribute.data_type == "enum":
|
||||
row.prop(attribute, "enum_value", text=attribute.name)
|
||||
if attribute.is_optional:
|
||||
row.prop(attribute, "is_null", icon="RADIOBUT_OFF" if attribute.is_null else "RADIOBUT_ON", text="")
|
||||
elif self.props.active_resource_id and self.props.editing_resource_type == "USAGE":
|
||||
self.draw_editable_resource_time_attributes_ui()
|
||||
|
||||
def draw_editable_resource_attributes_ui(self):
|
||||
blenderbim.bim.helper.draw_attributes(self.props.resource_attributes, self.layout)
|
||||
|
||||
def draw_editable_resource_time_attributes_ui(self):
|
||||
blenderbim.bim.helper.draw_attributes(self.props.resource_time_attributes, self.layout)
|
||||
|
||||
|
||||
class BIM_UL_resources(UIList):
|
||||
@@ -124,9 +117,12 @@ class BIM_UL_resources(UIList):
|
||||
op = row.operator("bim.assign_resource", text="", icon="KEYFRAME", emboss=False)
|
||||
op.resource = item.ifc_definition_id
|
||||
|
||||
if props.active_resource_id == item.ifc_definition_id:
|
||||
if props.active_resource_id == item.ifc_definition_id and props.editing_resource_type == "ATTRIBUTES":
|
||||
row.operator("bim.edit_resource", text="", icon="CHECKMARK")
|
||||
row.operator("bim.disable_editing_resource", text="", icon="CANCEL")
|
||||
elif props.active_resource_id == item.ifc_definition_id and props.editing_resource_type == "USAGE":
|
||||
row.operator("bim.edit_resource_time", text="", icon="CHECKMARK")
|
||||
row.operator("bim.disable_editing_resource_time", text="", icon="CANCEL")
|
||||
elif props.active_resource_id:
|
||||
row.operator("bim.add_resource", text="", icon="ADD").resource = item.ifc_definition_id
|
||||
row.operator("bim.remove_resource", text="", icon="X").resource = item.ifc_definition_id
|
||||
@@ -134,5 +130,5 @@ class BIM_UL_resources(UIList):
|
||||
row.operator(
|
||||
"bim.enable_editing_resource", text="", icon="GREASEPENCIL"
|
||||
).resource = item.ifc_definition_id
|
||||
|
||||
row.operator("bim.enable_editing_resource_time", text="", icon="TIME").resource = item.ifc_definition_id
|
||||
row.operator("bim.remove_resource", text="", icon="X").resource = item.ifc_definition_id
|
||||
|
||||
@@ -498,7 +498,7 @@ class RemoveTask(bpy.types.Operator):
|
||||
|
||||
class EnableEditingTaskTime(bpy.types.Operator):
|
||||
bl_idname = "bim.enable_editing_task_time"
|
||||
bl_label = "Enable Editing Task"
|
||||
bl_label = "Enable Editing Task Time"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
task: bpy.props.IntProperty()
|
||||
|
||||
|
||||
@@ -282,7 +282,7 @@ class BIMWorkScheduleProperties(PropertyGroup):
|
||||
],
|
||||
name="Special Columns",
|
||||
)
|
||||
active_task_time_id: IntProperty(name="Active Task Id")
|
||||
active_task_time_id: IntProperty(name="Active Task Time Id")
|
||||
task_time_attributes: CollectionProperty(name="Task Time Attributes", type=Attribute)
|
||||
contracted_tasks: StringProperty(name="Contracted Task Items", default="[]")
|
||||
is_task_update_enabled: BoolProperty(name="Is Task Update Enabled", default=True)
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
import ifcopenshell.util.date
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, **settings):
|
||||
self.file = file
|
||||
self.settings = {
|
||||
"resource": None,
|
||||
}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
resource_time = self.file.create_entity("IfcResourceTime")
|
||||
self.settings["resource"].Usage = resource_time
|
||||
return resource_time
|
||||
@@ -1,11 +1,13 @@
|
||||
class Data:
|
||||
is_loaded = False
|
||||
resources = {}
|
||||
resource_times = {}
|
||||
|
||||
@classmethod
|
||||
def purge(cls):
|
||||
cls.is_loaded = False
|
||||
cls.resources = {}
|
||||
cls.resource_times = {}
|
||||
|
||||
@classmethod
|
||||
def load(cls, file):
|
||||
@@ -13,6 +15,7 @@ class Data:
|
||||
if not cls._file:
|
||||
return
|
||||
cls.load_resources()
|
||||
cls.load_resource_times()
|
||||
cls.is_loaded=True
|
||||
|
||||
@classmethod
|
||||
@@ -31,4 +34,20 @@ class Data:
|
||||
for rel in resource.ResourceOf:
|
||||
[data["ResourceOf"].append(o.id()) for o in rel.RelatedObjects]
|
||||
data["HasContext"] = resource.HasContext[0].RelatingContext.id() if resource.HasContext else None
|
||||
if resource.Usage:
|
||||
data["Usage"] = data["Usage"].id()
|
||||
cls.resources[resource.id()] = data
|
||||
|
||||
@classmethod
|
||||
def load_resource_times(cls):
|
||||
cls.resource_times = {}
|
||||
for resource_time in cls._file.by_type("IfcResourceTime"):
|
||||
data = resource_time.get_info()
|
||||
for key, value in data.items():
|
||||
if not value:
|
||||
continue
|
||||
if "Start" in key or "Finish" in key or key == "StatusTime":
|
||||
data[key] = ifcopenshell.util.date.ifc2datetime(value)
|
||||
elif "Work" in key or key =="LevelingDelay":
|
||||
data[key] = ifcopenshell.util.date.ifc2datetime(value)
|
||||
cls.resource_times[resource_time.id()] = data
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
import datetime
|
||||
import ifcopenshell.util.date
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, **settings):
|
||||
self.file = file
|
||||
self.settings = {"resource_time": None, "attributes": {}}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
self.resource = self.get_resource()
|
||||
|
||||
# If the user specifies both an end date and a duration, the duration takes priority
|
||||
if (
|
||||
"ScheduleWork" in self.settings["attributes"].keys()
|
||||
and "ScheduleFinish" in self.settings["attributes"].keys()
|
||||
):
|
||||
del self.settings["attributes"]["ScheduleFinish"]
|
||||
if (
|
||||
"ActualWork" in self.settings["attributes"].keys()
|
||||
and "ActualFinish" in self.settings["attributes"].keys()
|
||||
):
|
||||
del self.settings["attributes"]["ActualFinish"]
|
||||
|
||||
for name, value in self.settings["attributes"].items():
|
||||
if value:
|
||||
if "Start" in name or "Finish" in name or name == "StatusTime":
|
||||
value = ifcopenshell.util.date.datetime2ifc(value, "IfcDateTime")
|
||||
elif name == "ScheduleWork" or name == "ActualWork" or name == "RemainingTime":
|
||||
value = ifcopenshell.util.date.datetime2ifc(value, "IfcDuration")
|
||||
setattr(self.settings["resource_time"], name, value)
|
||||
|
||||
def get_resource(self):
|
||||
return [e for e in self.file.get_inverse(self.settings["resource_time"]) if e.is_a("IfcResource")][0]
|
||||
Reference in New Issue
Block a user