mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-09 01:11:40 +00:00
Refactor Resource module
This commit is contained in:
@@ -27,7 +27,7 @@ from blenderbim.bim.ifc import IfcStore
|
||||
from bpy_extras.io_utils import ImportHelper
|
||||
from ifcopenshell.api.cost.data import Data
|
||||
from ifcopenshell.api.unit.data import Data as UnitData
|
||||
from ifcopenshell.api.resource.data import Data as ResourceData
|
||||
from blenderbim.bim.module.resource.data import ResourceData
|
||||
|
||||
|
||||
class AddCostSchedule(bpy.types.Operator):
|
||||
@@ -604,7 +604,7 @@ class AddCostValue(bpy.types.Operator):
|
||||
value = ifcopenshell.api.run("cost.add_cost_value", self.file, parent=parent)
|
||||
ifcopenshell.api.run("cost.edit_cost_value", self.file, cost_value=value, attributes=attributes)
|
||||
if parent.is_a("IfcConstructionResource"):
|
||||
ResourceData.load(self.file)
|
||||
ResourceData.load()
|
||||
else:
|
||||
Data.load(self.file)
|
||||
return {"FINISHED"}
|
||||
@@ -630,7 +630,7 @@ class RemoveCostItemValue(bpy.types.Operator):
|
||||
cost_value=self.file.by_id(self.cost_value),
|
||||
)
|
||||
if parent.is_a("IfcConstructionResource"):
|
||||
ResourceData.load(self.file)
|
||||
ResourceData.load()
|
||||
else:
|
||||
Data.load(self.file)
|
||||
return {"FINISHED"}
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2021-2022 Dion Moult <dion@thinkmoult.com>, Yassine Oualid <yassine@sigmadimensions.com>
|
||||
#
|
||||
# This file is part of BlenderBIM Add-on.
|
||||
#
|
||||
# BlenderBIM Add-on is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# BlenderBIM Add-on is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import bpy
|
||||
import blenderbim.tool as tool
|
||||
from ifcopenshell.api.cost.data import CostValueTrait
|
||||
import ifcopenshell
|
||||
|
||||
|
||||
def refresh():
|
||||
ResourceData.is_loaded = False
|
||||
|
||||
|
||||
class ResourceData(CostValueTrait):
|
||||
data = {}
|
||||
is_loaded = False
|
||||
cost_values = {}
|
||||
|
||||
@classmethod
|
||||
def load(cls):
|
||||
cls.data = {
|
||||
"has_resources": cls.has_resources(),
|
||||
}
|
||||
cls.load_resources()
|
||||
cls.is_loaded = True
|
||||
|
||||
@classmethod
|
||||
def has_resources(cls):
|
||||
return bool(tool.Ifc.get().by_type("IfcResource"))
|
||||
|
||||
@classmethod
|
||||
def number_of_resources_loaded(cls):
|
||||
return len(tool.Ifc.get().by_type("IfcResource"))
|
||||
|
||||
@classmethod
|
||||
def load_resources(cls):
|
||||
cls.data["resources"] = {}
|
||||
for resource in tool.Ifc.get().by_type("IfcResource"):
|
||||
data = resource.get_info()
|
||||
del data["OwnerHistory"]
|
||||
data["IsNestedBy"] = []
|
||||
for rel in resource.IsNestedBy:
|
||||
[data["IsNestedBy"].append(o.id()) for o in rel.RelatedObjects]
|
||||
data["Nests"] = []
|
||||
for rel in resource.Nests:
|
||||
[data["Nests"].append(rel.RelatingObject.id())]
|
||||
data["ResourceOf"] = []
|
||||
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()
|
||||
data["TotalCostQuantity"] = cls.get_total_quantity(resource)
|
||||
if resource.BaseQuantity:
|
||||
data["BaseQuantity"] = resource.BaseQuantity.get_info()
|
||||
del data["BaseQuantity"]["Unit"]
|
||||
if resource.BaseCosts:
|
||||
data["BaseCosts"] = [e.id() for e in resource.BaseCosts]
|
||||
cls.load_cost_values(resource, data)
|
||||
cls.data["resources"][resource.id()] = data
|
||||
cls.data["number_of_resources_loaded"] = cls.number_of_resources_loaded()
|
||||
|
||||
def load_resource_times(cls):
|
||||
cls.data["resource_times"] = {}
|
||||
for resource_time in tool.Ifc.get().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.data["resource_times"][resource_time.id()] = data
|
||||
@@ -17,17 +17,9 @@
|
||||
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import bpy
|
||||
import json
|
||||
import time
|
||||
import isodate
|
||||
import ifcopenshell.api
|
||||
import blenderbim.bim.helper
|
||||
import blenderbim.bim.module.sequence.helper as helper
|
||||
from datetime import datetime
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
from ifcopenshell.api.resource.data import Data
|
||||
from ifcopenshell.api.unit.data import Data as UnitData
|
||||
|
||||
from bpy_extras.io_utils import ImportHelper
|
||||
import blenderbim.core.resource as core
|
||||
import blenderbim.tool as tool
|
||||
|
||||
class LoadResources(bpy.types.Operator):
|
||||
bl_idname = "bim.load_resources"
|
||||
@@ -35,66 +27,9 @@ class LoadResources(bpy.types.Operator):
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
self.props = context.scene.BIMResourceProperties
|
||||
self.tprops = context.scene.BIMResourceTreeProperties
|
||||
self.tprops.resources.clear()
|
||||
|
||||
self.contracted_resources = json.loads(self.props.contracted_resources)
|
||||
Data.load(IfcStore.get_file())
|
||||
for resource_id, data in Data.resources.items():
|
||||
if not data["HasContext"]:
|
||||
continue
|
||||
self.create_new_resource_li(resource_id, 0)
|
||||
bpy.ops.bim.load_resource_properties()
|
||||
self.props.is_editing = True
|
||||
core.load_resources(tool.Resource)
|
||||
return {"FINISHED"}
|
||||
|
||||
def create_new_resource_li(self, related_object_id, level_index):
|
||||
resource = Data.resources[related_object_id]
|
||||
new = self.tprops.resources.add()
|
||||
new.ifc_definition_id = related_object_id
|
||||
new.is_expanded = related_object_id not in self.contracted_resources
|
||||
new.level_index = level_index
|
||||
if resource["IsNestedBy"]:
|
||||
new.has_children = True
|
||||
if new.is_expanded:
|
||||
for related_object_id in resource["IsNestedBy"]:
|
||||
self.create_new_resource_li(related_object_id, level_index + 1)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class EnableEditingResource(bpy.types.Operator):
|
||||
bl_idname = "bim.enable_editing_resource"
|
||||
bl_label = "Enable Editing Resource"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
resource: bpy.props.IntProperty()
|
||||
|
||||
def execute(self, context):
|
||||
self.props = context.scene.BIMResourceProperties
|
||||
self.props.active_resource_id = self.resource
|
||||
self.props.resource_attributes.clear()
|
||||
self.props.editing_resource_type = "ATTRIBUTES"
|
||||
self.enable_editing_resource()
|
||||
return {"FINISHED"}
|
||||
|
||||
def enable_editing_resource(self):
|
||||
data = Data.resources[self.resource]
|
||||
for attribute in IfcStore.get_schema().declaration_by_name(data["type"]).all_attributes():
|
||||
data_type = ifcopenshell.util.attribute.get_primitive_type(attribute)
|
||||
if data_type == "entity" or isinstance(data_type, tuple):
|
||||
continue
|
||||
new = self.props.resource_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 LoadResourceProperties(bpy.types.Operator):
|
||||
bl_idname = "bim.load_resource_properties"
|
||||
@@ -103,15 +38,36 @@ class LoadResourceProperties(bpy.types.Operator):
|
||||
resource: bpy.props.IntProperty()
|
||||
|
||||
def execute(self, context):
|
||||
self.props = context.scene.BIMResourceProperties
|
||||
self.tprops = context.scene.BIMResourceTreeProperties
|
||||
self.props.is_resource_update_enabled = False
|
||||
for item in self.tprops.resources:
|
||||
if self.resource and item.ifc_definition_id != self.resource:
|
||||
continue
|
||||
resource = Data.resources[item.ifc_definition_id]
|
||||
item.name = resource["Name"] or "Unnamed"
|
||||
self.props.is_resource_update_enabled = True
|
||||
core.load_resource_properties(
|
||||
tool.Resource, resource=tool.Ifc.get().by_id(self.resource) if self.resource else None
|
||||
)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class AddResource(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bl_idname = "bim.add_resource"
|
||||
bl_label = "Add resource"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
ifc_class: bpy.props.StringProperty()
|
||||
parent_resource: bpy.props.IntProperty()
|
||||
|
||||
def _execute(self, context):
|
||||
core.add_resource(
|
||||
tool.Ifc,
|
||||
tool.Resource,
|
||||
ifc_class=self.ifc_class,
|
||||
parent_resource=tool.Ifc.get().by_id(self.parent_resource) if self.parent_resource else None,
|
||||
)
|
||||
|
||||
|
||||
class EnableEditingResource(bpy.types.Operator):
|
||||
bl_idname = "bim.enable_editing_resource"
|
||||
bl_label = "Enable Editing Resource"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
resource: bpy.props.IntProperty()
|
||||
|
||||
def execute(self, context):
|
||||
core.enable_editing_resource(tool.Resource, resource=tool.Ifc.get().by_id(self.resource))
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
@@ -121,8 +77,7 @@ class DisableEditingResource(bpy.types.Operator):
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
context.scene.BIMResourceProperties.active_resource_id = 0
|
||||
context.scene.BIMResourceProperties.active_task_time_id = 0
|
||||
core.disable_editing_resource(tool.Resource)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
@@ -132,73 +87,31 @@ class DisableResourceEditingUI(bpy.types.Operator):
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
context.scene.BIMResourceProperties.is_editing = False
|
||||
core.disable_resource_editing_ui(tool.Resource)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class AddResource(bpy.types.Operator):
|
||||
bl_idname = "bim.add_resource"
|
||||
bl_label = "Add resource"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
ifc_class: bpy.props.StringProperty()
|
||||
resource: bpy.props.IntProperty()
|
||||
|
||||
def execute(self, context):
|
||||
return IfcStore.execute_ifc_operator(self, context)
|
||||
|
||||
def _execute(self, context):
|
||||
ifcopenshell.api.run(
|
||||
"resource.add_resource",
|
||||
IfcStore.get_file(),
|
||||
parent_resource=IfcStore.get_file().by_id(self.resource) if self.resource else None,
|
||||
ifc_class=self.ifc_class,
|
||||
)
|
||||
Data.load(IfcStore.get_file())
|
||||
bpy.ops.bim.load_resources()
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class EditResource(bpy.types.Operator):
|
||||
class EditResource(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bl_idname = "bim.edit_resource"
|
||||
bl_label = "Edit Resource"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
return IfcStore.execute_ifc_operator(self, context)
|
||||
|
||||
def _execute(self, context):
|
||||
props = context.scene.BIMResourceProperties
|
||||
attributes = blenderbim.bim.helper.export_attributes(props.resource_attributes)
|
||||
self.file = IfcStore.get_file()
|
||||
ifcopenshell.api.run(
|
||||
"resource.edit_resource",
|
||||
self.file,
|
||||
**{"resource": self.file.by_id(props.active_resource_id), "attributes": attributes},
|
||||
core.edit_resource(
|
||||
tool.Ifc,
|
||||
tool.Resource,
|
||||
resource=tool.Ifc.get().by_id(context.scene.BIMResourceProperties.active_resource_id),
|
||||
)
|
||||
Data.load(IfcStore.get_file())
|
||||
bpy.ops.bim.load_resource_properties(resource=props.active_resource_id)
|
||||
bpy.ops.bim.disable_editing_resource()
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class RemoveResource(bpy.types.Operator):
|
||||
class RemoveResource(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bl_idname = "bim.remove_resource"
|
||||
bl_label = "Remove Resource"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
resource: bpy.props.IntProperty()
|
||||
|
||||
def execute(self, context):
|
||||
return IfcStore.execute_ifc_operator(self, context)
|
||||
|
||||
def _execute(self, context):
|
||||
ifcopenshell.api.run(
|
||||
"resource.remove_resource",
|
||||
IfcStore.get_file(),
|
||||
resource=IfcStore.get_file().by_id(self.resource),
|
||||
)
|
||||
Data.load(IfcStore.get_file())
|
||||
bpy.ops.bim.load_resources()
|
||||
return {"FINISHED"}
|
||||
core.remove_resource(tool.Ifc, tool.Resource, resource=tool.Ifc.get().by_id(self.resource))
|
||||
|
||||
|
||||
class ExpandResource(bpy.types.Operator):
|
||||
@@ -208,13 +121,7 @@ class ExpandResource(bpy.types.Operator):
|
||||
resource: bpy.props.IntProperty()
|
||||
|
||||
def execute(self, context):
|
||||
props = context.scene.BIMResourceProperties
|
||||
self.file = IfcStore.get_file()
|
||||
contracted_resources = json.loads(props.contracted_resources)
|
||||
contracted_resources.remove(self.resource)
|
||||
props.contracted_resources = json.dumps(contracted_resources)
|
||||
Data.load(self.file)
|
||||
bpy.ops.bim.load_resources()
|
||||
core.expand_resource(tool.Resource, resource=tool.Ifc.get().by_id(self.resource))
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
@@ -225,107 +132,40 @@ class ContractResource(bpy.types.Operator):
|
||||
resource: bpy.props.IntProperty()
|
||||
|
||||
def execute(self, context):
|
||||
props = context.scene.BIMResourceProperties
|
||||
self.file = IfcStore.get_file()
|
||||
contracted_resources = json.loads(props.contracted_resources)
|
||||
contracted_resources.append(self.resource)
|
||||
props.contracted_resources = json.dumps(contracted_resources)
|
||||
Data.load(self.file)
|
||||
bpy.ops.bim.load_resources()
|
||||
core.contract_resource(tool.Resource, resource=tool.Ifc.get().by_id(self.resource))
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class AssignResource(bpy.types.Operator):
|
||||
class AssignResource(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bl_idname = "bim.assign_resource"
|
||||
bl_label = "Assign Resource"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
resource: bpy.props.IntProperty()
|
||||
related_object: bpy.props.StringProperty()
|
||||
|
||||
def execute(self, context):
|
||||
return IfcStore.execute_ifc_operator(self, context)
|
||||
|
||||
def _execute(self, context):
|
||||
related_objects = (
|
||||
[bpy.data.objects.get(self.related_object)] if self.related_object else context.selected_objects
|
||||
)
|
||||
for related_object in related_objects:
|
||||
self.file = IfcStore.get_file()
|
||||
ifcopenshell.api.run(
|
||||
"resource.assign_resource",
|
||||
self.file,
|
||||
relating_resource=self.file.by_id(self.resource),
|
||||
related_object=self.file.by_id(related_object.BIMObjectProperties.ifc_definition_id),
|
||||
)
|
||||
Data.load(self.file)
|
||||
return {"FINISHED"}
|
||||
core.assign_resource(tool.Ifc, tool.Resource, resource=tool.Ifc.get().by_id(self.resource))
|
||||
|
||||
|
||||
class UnassignResource(bpy.types.Operator):
|
||||
class UnassignResource(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bl_idname = "bim.unassign_resource"
|
||||
bl_label = "Unassign Resource"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
resource: bpy.props.IntProperty()
|
||||
related_object: bpy.props.StringProperty()
|
||||
|
||||
def execute(self, context):
|
||||
related_objects = (
|
||||
[bpy.data.objects.get(self.related_object)] if self.related_object else context.selected_objects
|
||||
)
|
||||
for related_object in related_objects:
|
||||
self.file = IfcStore.get_file()
|
||||
ifcopenshell.api.run(
|
||||
"resource.unassign_resource",
|
||||
self.file,
|
||||
relating_resource=self.file.by_id(self.resource),
|
||||
related_object=self.file.by_id(related_object.BIMObjectProperties.ifc_definition_id),
|
||||
)
|
||||
Data.load(self.file)
|
||||
return {"FINISHED"}
|
||||
def _execute(self, context):
|
||||
core.unassign_resource(tool.Ifc, tool.Resource, resource=tool.Ifc.get().by_id(self.resource))
|
||||
|
||||
|
||||
class EnableEditingResourceTime(bpy.types.Operator):
|
||||
class EnableEditingResourceTime(bpy.types.Operator, tool.Ifc.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()
|
||||
props.resource_time_attributes.clear()
|
||||
|
||||
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
|
||||
core.enable_editing_resource_time(tool.Ifc, tool.Resource, resource=tool.Ifc.get().by_id(self.resource))
|
||||
|
||||
|
||||
class DisableEditingResourceTime(bpy.types.Operator):
|
||||
@@ -334,63 +174,31 @@ class DisableEditingResourceTime(bpy.types.Operator):
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
context.scene.BIMResourceProperties.active_resource_time_id = 0
|
||||
bpy.ops.bim.disable_editing_resource()
|
||||
core.disable_editing_resource_time(tool.Resource)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class EditResourceTime(bpy.types.Operator):
|
||||
class EditResourceTime(bpy.types.Operator, tool.Ifc.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
|
||||
core.edit_resource_time(
|
||||
tool.Ifc,
|
||||
tool.Resource,
|
||||
resource_time=tool.Ifc.get().by_id(context.scene.BIMResourceProperties.active_resource_time_id),
|
||||
)
|
||||
|
||||
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":
|
||||
if prop.is_null:
|
||||
attributes[prop.name] = None
|
||||
return True
|
||||
attributes[prop.name] = helper.parse_datetime(prop.string_value)
|
||||
return True
|
||||
elif prop.name == "LevelingDelay" or "Work" in prop.name:
|
||||
if prop.is_null:
|
||||
attributes[prop.name] = None
|
||||
return True
|
||||
attributes[prop.name] = helper.parse_duration(prop.string_value)
|
||||
return True
|
||||
|
||||
|
||||
class CalculateResourceWork(bpy.types.Operator):
|
||||
class CalculateResourceWork(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bl_idname = "bim.calculate_resource_work"
|
||||
bl_label = "Calculate Resource Work"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
resource: bpy.props.IntProperty()
|
||||
|
||||
def execute(self, context):
|
||||
self.file = IfcStore.get_file()
|
||||
ifcopenshell.api.run("resource.calculate_resource_work", self.file, resource=self.file.by_id(self.resource))
|
||||
Data.load(self.file)
|
||||
bpy.ops.bim.load_resources()
|
||||
return {"FINISHED"}
|
||||
def _execute(self, context):
|
||||
core.calculate_resource_work(tool.Ifc, tool.Resource, resource=tool.Ifc.get().by_id(self.resource))
|
||||
|
||||
|
||||
class EnableEditingResourceCosts(bpy.types.Operator):
|
||||
@@ -400,10 +208,7 @@ class EnableEditingResourceCosts(bpy.types.Operator):
|
||||
resource: bpy.props.IntProperty()
|
||||
|
||||
def execute(self, context):
|
||||
props = context.scene.BIMResourceProperties
|
||||
props.active_resource_id = self.resource
|
||||
props.editing_resource_type = "COSTS"
|
||||
bpy.ops.bim.disable_editing_resource_cost_value()
|
||||
core.enable_editing_resource_costs(tool.Resource, resource=tool.Ifc.get().by_id(self.resource))
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
@@ -413,21 +218,7 @@ class DisableEditingResourceCostValue(bpy.types.Operator):
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
props = context.scene.BIMResourceProperties
|
||||
props.active_cost_value_id = 0
|
||||
props.cost_value_editing_type = ""
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class DisableEditingResourceCostValue(bpy.types.Operator):
|
||||
bl_idname = "bim.disable_editing_resource_cost_value"
|
||||
bl_label = "Disable Editing Resource Cost Value"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
props = context.scene.BIMResourceProperties
|
||||
props.active_cost_value_id = 0
|
||||
props.cost_value_editing_type = ""
|
||||
core.disable_editing_resource_cost_value(tool.Resource)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
@@ -438,11 +229,7 @@ class EnableEditingResourceCostValueFormula(bpy.types.Operator):
|
||||
cost_value: bpy.props.IntProperty()
|
||||
|
||||
def execute(self, context):
|
||||
self.props = context.scene.BIMResourceProperties
|
||||
self.props.cost_value_attributes.clear()
|
||||
self.props.active_cost_value_id = self.cost_value
|
||||
self.props.cost_value_editing_type = "FORMULA"
|
||||
self.props.cost_value_formula = Data.cost_values[self.cost_value]["Formula"]
|
||||
core.enable_editing_resource_cost_value_formula(tool.Resource, cost_value=tool.Ifc.get().by_id(self.cost_value))
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
@@ -453,127 +240,28 @@ class EnableEditingResourceCostValue(bpy.types.Operator):
|
||||
cost_value: bpy.props.IntProperty()
|
||||
|
||||
def execute(self, context):
|
||||
self.props = context.scene.BIMResourceProperties
|
||||
self.props.cost_value_attributes.clear()
|
||||
self.props.active_cost_value_id = self.cost_value
|
||||
self.props.cost_value_editing_type = "ATTRIBUTES"
|
||||
data = Data.cost_values[self.cost_value]
|
||||
|
||||
blenderbim.bim.helper.import_attributes(
|
||||
data["type"],
|
||||
self.props.cost_value_attributes,
|
||||
data,
|
||||
lambda name, prop, data: self.import_attributes(name, prop, data, context),
|
||||
)
|
||||
core.enable_editing_resource_cost_value(tool.Resource, cost_value=tool.Ifc.get().by_id(self.cost_value))
|
||||
return {"FINISHED"}
|
||||
|
||||
def import_attributes(self, name, prop, data, context):
|
||||
if name == "AppliedValue":
|
||||
# TODO: for now, only support simple IfcValues (which are effectively IfcMonetaryMeasure)
|
||||
prop = self.props.cost_value_attributes.add()
|
||||
prop.data_type = "float"
|
||||
prop.name = "AppliedValue"
|
||||
prop.is_optional = True
|
||||
prop.float_value = 0.0 if prop.is_null else data[name]
|
||||
return True
|
||||
elif name == "UnitBasis":
|
||||
prop = self.props.cost_value_attributes.add()
|
||||
prop.name = "UnitBasisValue"
|
||||
prop.data_type = "float"
|
||||
prop.is_null = data["UnitBasis"] is None
|
||||
prop.is_optional = True
|
||||
if data["UnitBasis"]:
|
||||
prop.float_value = data["UnitBasis"]["ValueComponent"] or 0
|
||||
else:
|
||||
prop.float_value = 0
|
||||
|
||||
prop = self.props.cost_value_attributes.add()
|
||||
prop.name = "UnitBasisUnit"
|
||||
prop.data_type = "enum"
|
||||
prop.is_null = prop.is_optional = False
|
||||
units = {}
|
||||
for unit_id, unit in UnitData.units.items():
|
||||
if unit.get("UnitType", None) in [
|
||||
"AREAUNIT",
|
||||
"LENGTHUNIT",
|
||||
"TIMEUNIT",
|
||||
"VOLUMEUNIT",
|
||||
"MASSUNIT",
|
||||
"USERDEFINED",
|
||||
]:
|
||||
if unit["type"] == "IfcContextDependentUnit":
|
||||
units[unit_id] = f"{unit['UnitType']} / {unit['Name']}"
|
||||
else:
|
||||
name = unit["Name"]
|
||||
if unit.get("Prefix", None):
|
||||
name = f"(unit['Prefix']) {name}"
|
||||
units[unit_id] = f"{unit['UnitType']} / {name}"
|
||||
prop.enum_items = json.dumps(units)
|
||||
if data["UnitBasis"] and data["UnitBasis"]["UnitComponent"]:
|
||||
prop.enum_value = str(data["UnitBasis"]["UnitComponent"])
|
||||
return True
|
||||
|
||||
|
||||
class EditResourceCostValueFormula(bpy.types.Operator):
|
||||
class EditResourceCostValueFormula(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bl_idname = "bim.edit_resource_cost_value_formula"
|
||||
bl_label = "Edit Resource Cost Value Formula"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
cost_value: 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()
|
||||
ifcopenshell.api.run(
|
||||
"cost.edit_cost_value_formula",
|
||||
self.file,
|
||||
**{"cost_value": self.file.by_id(self.cost_value), "formula": props.cost_value_formula},
|
||||
)
|
||||
Data.load(IfcStore.get_file())
|
||||
bpy.ops.bim.disable_editing_resource_cost_value()
|
||||
return {"FINISHED"}
|
||||
core.edit_resource_cost_value_formula(tool.Ifc, tool.Resource, cost_value=tool.Ifc.get().by_id(self.cost_value))
|
||||
|
||||
|
||||
class EditResourceCostValue(bpy.types.Operator):
|
||||
class EditResourceCostValue(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bl_idname = "bim.edit_resource_cost_value"
|
||||
bl_label = "Edit Resource Cost Value"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
cost_value: bpy.props.IntProperty()
|
||||
|
||||
def execute(self, context):
|
||||
return IfcStore.execute_ifc_operator(self, context)
|
||||
|
||||
def _execute(self, context):
|
||||
props = context.scene.BIMResourceProperties
|
||||
attributes = blenderbim.bim.helper.export_attributes(
|
||||
props.cost_value_attributes, lambda attributes, prop: self.export_attributes(attributes, prop, context)
|
||||
)
|
||||
self.file = IfcStore.get_file()
|
||||
ifcopenshell.api.run(
|
||||
"cost.edit_cost_value",
|
||||
self.file,
|
||||
**{"cost_value": self.file.by_id(self.cost_value), "attributes": attributes},
|
||||
)
|
||||
Data.load(IfcStore.get_file())
|
||||
bpy.ops.bim.disable_editing_resource_cost_value()
|
||||
return {"FINISHED"}
|
||||
|
||||
def export_attributes(self, attributes, prop, context):
|
||||
if prop.name == "UnitBasisValue":
|
||||
if prop.is_null:
|
||||
attributes["UnitBasis"] = None
|
||||
return True
|
||||
attributes["UnitBasis"] = {
|
||||
"ValueComponent": prop.float_value or 1,
|
||||
"UnitComponent": IfcStore.get_file().by_id(
|
||||
int(context.scene.BIMResourceProperties.cost_value_attributes.get("UnitBasisUnit").enum_value)
|
||||
),
|
||||
}
|
||||
return True
|
||||
if prop.name == "UnitBasisUnit":
|
||||
return True
|
||||
core.edit_resource_cost_value(tool.Ifc, tool.Resource, cost_value=tool.Ifc.get().by_id(self.cost_value))
|
||||
|
||||
|
||||
class EnableEditingResourceBaseQuantity(bpy.types.Operator):
|
||||
@@ -583,52 +271,29 @@ class EnableEditingResourceBaseQuantity(bpy.types.Operator):
|
||||
resource: bpy.props.IntProperty()
|
||||
|
||||
def execute(self, context):
|
||||
props = context.scene.BIMResourceProperties
|
||||
props.active_resource_id = self.resource
|
||||
props.editing_resource_type = "QUANTITY"
|
||||
core.enable_editing_resource_base_quantity(tool.Resource, resource=tool.Ifc.get().by_id(self.resource))
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class AddResourceQuantity(bpy.types.Operator):
|
||||
class AddResourceQuantity(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bl_idname = "bim.add_resource_quantity"
|
||||
bl_label = "Add Resource Quantity"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
resource: bpy.props.IntProperty()
|
||||
ifc_class: bpy.props.StringProperty()
|
||||
|
||||
def execute(self, context):
|
||||
return IfcStore.execute_ifc_operator(self, context)
|
||||
|
||||
def _execute(self, context):
|
||||
self.file = IfcStore.get_file()
|
||||
ifcopenshell.api.run(
|
||||
"resource.add_resource_quantity",
|
||||
self.file,
|
||||
resource=self.file.by_id(self.resource),
|
||||
ifc_class=self.ifc_class,
|
||||
)
|
||||
Data.load(self.file)
|
||||
return {"FINISHED"}
|
||||
core.add_resource_quantity(tool.Ifc, ifc_class=self.ifc_class, resource=tool.Ifc.get().by_id(self.resource))
|
||||
|
||||
|
||||
class RemoveResourceQuantity(bpy.types.Operator):
|
||||
class RemoveResourceQuantity(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bl_idname = "bim.remove_resource_quantity"
|
||||
bl_label = "Remove Resource Quantity"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
resource: bpy.props.IntProperty()
|
||||
|
||||
def execute(self, context):
|
||||
return IfcStore.execute_ifc_operator(self, context)
|
||||
|
||||
def _execute(self, context):
|
||||
self.file = IfcStore.get_file()
|
||||
ifcopenshell.api.run(
|
||||
"resource.remove_resource_quantity",
|
||||
self.file,
|
||||
resource=self.file.by_id(self.resource),
|
||||
)
|
||||
Data.load(self.file)
|
||||
return {"FINISHED"}
|
||||
core.remove_resource_quantity(tool.Ifc, resource=tool.Ifc.get().by_id(self.resource))
|
||||
|
||||
|
||||
class EnableEditingResourceQuantity(bpy.types.Operator):
|
||||
@@ -638,11 +303,9 @@ class EnableEditingResourceQuantity(bpy.types.Operator):
|
||||
resource: bpy.props.IntProperty()
|
||||
|
||||
def execute(self, context):
|
||||
self.props = context.scene.BIMResourceProperties
|
||||
self.props.quantity_attributes.clear()
|
||||
self.props.is_editing_quantity = True
|
||||
data = Data.resources[self.resource]["BaseQuantity"]
|
||||
blenderbim.bim.helper.import_attributes(data["type"], self.props.quantity_attributes, data)
|
||||
core.enable_editing_resource_quantity(
|
||||
tool.Resource, resource_quantity=tool.Ifc.get().by_id(self.resource).BaseQuantity
|
||||
)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
@@ -652,29 +315,18 @@ class DisableEditingResourceQuantity(bpy.types.Operator):
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
props = context.scene.BIMResourceProperties
|
||||
props.is_editing_quantity = False
|
||||
core.disable_editing_resource_quantity(tool.Resource)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class EditResourceQuantity(bpy.types.Operator):
|
||||
class EditResourceQuantity(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bl_idname = "bim.edit_resource_quantity"
|
||||
bl_label = "Edit Resource Quantity"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
physical_quantity: bpy.props.IntProperty()
|
||||
|
||||
def execute(self, context):
|
||||
return IfcStore.execute_ifc_operator(self, context)
|
||||
|
||||
def _execute(self, context):
|
||||
props = context.scene.BIMResourceProperties
|
||||
attributes = blenderbim.bim.helper.export_attributes(props.quantity_attributes)
|
||||
self.file = IfcStore.get_file()
|
||||
ifcopenshell.api.run(
|
||||
"resource.edit_resource_quantity",
|
||||
self.file,
|
||||
**{"physical_quantity": self.file.by_id(self.physical_quantity), "attributes": attributes},
|
||||
core.edit_resource_quantity(
|
||||
tool.Resource, tool.Ifc, physical_quantity=tool.Ifc.get().by_id(self.physical_quantity)
|
||||
)
|
||||
Data.load(IfcStore.get_file())
|
||||
bpy.ops.bim.disable_editing_resource_quantity()
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
import blenderbim.bim.helper
|
||||
from bpy.types import Panel, UIList
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
from ifcopenshell.api.resource.data import Data
|
||||
from blenderbim.bim.module.resource.data import ResourceData
|
||||
|
||||
|
||||
class BIM_PT_resources(Panel):
|
||||
@@ -39,17 +39,21 @@ class BIM_PT_resources(Panel):
|
||||
def draw(self, context):
|
||||
self.props = context.scene.BIMResourceProperties
|
||||
self.tprops = context.scene.BIMResourceTreeProperties
|
||||
|
||||
if not Data.is_loaded:
|
||||
Data.load(IfcStore.get_file())
|
||||
if not ResourceData.is_loaded:
|
||||
ResourceData.load()
|
||||
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text=f"{len(Data.resources)} Resources Found")
|
||||
if ResourceData.data["has_resources"]:
|
||||
row.label(
|
||||
text="{} Resources Found".format(ResourceData.data["number_of_resources_loaded"]),
|
||||
icon="TEXT",
|
||||
)
|
||||
else:
|
||||
row.label(text="No Resources found.", icon="COMMUNITY")
|
||||
if self.props.is_editing:
|
||||
row.operator("bim.disable_resource_editing_ui", text="", icon="CANCEL")
|
||||
else:
|
||||
row.operator("bim.load_resources", text="", icon="GREASEPENCIL")
|
||||
|
||||
row.operator("bim.load_resources", text="Load Resources", icon="GREASEPENCIL")
|
||||
if not self.props.is_editing:
|
||||
return
|
||||
|
||||
@@ -76,17 +80,17 @@ class BIM_PT_resources(Panel):
|
||||
row = self.layout.row(align=True)
|
||||
op = row.operator("bim.add_resource", text="Add SubContract", icon="TEXT")
|
||||
op.ifc_class = "IfcSubContractResource"
|
||||
op.resource = 0
|
||||
op.parent_resource = 0
|
||||
op = row.operator("bim.add_resource", text="Add Crew", icon="COMMUNITY")
|
||||
op.ifc_class = "IfcCrewResource"
|
||||
op.resource = 0
|
||||
op.parent_resource = 0
|
||||
|
||||
total_resources = len(self.tprops.resources)
|
||||
if not total_resources or self.props.active_resource_index >= total_resources:
|
||||
return
|
||||
|
||||
ifc_definition_id = self.tprops.resources[self.props.active_resource_index].ifc_definition_id
|
||||
resource = Data.resources[ifc_definition_id]
|
||||
resource = ResourceData.data["resources"][ifc_definition_id]
|
||||
|
||||
if resource["type"] != "IfcSubContractResource":
|
||||
icon_map = {
|
||||
@@ -100,26 +104,13 @@ class BIM_PT_resources(Panel):
|
||||
for ifc_class, icon in icon_map.items():
|
||||
label = ifc_class.replace("Ifc", "").replace("Construction", "").replace("Resource", "")
|
||||
op = row.operator("bim.add_resource", text=label, icon=icon)
|
||||
op.resource = ifc_definition_id
|
||||
op.parent_resource = ifc_definition_id
|
||||
op.ifc_class = ifc_class
|
||||
|
||||
row = self.layout.row(align=True)
|
||||
row.alignment = "RIGHT"
|
||||
|
||||
if self.props.active_resource_id == ifc_definition_id and self.props.editing_resource_type == "ATTRIBUTES":
|
||||
row.operator("bim.edit_resource", text="", icon="CHECKMARK")
|
||||
row.operator("bim.disable_editing_resource", text="", icon="CANCEL")
|
||||
elif self.props.active_resource_id == ifc_definition_id and self.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 self.props.active_resource_id == ifc_definition_id and self.props.editing_resource_type == "COSTS":
|
||||
row.operator("bim.disable_editing_resource", text="", icon="CANCEL")
|
||||
elif self.props.active_resource_id == ifc_definition_id and self.props.editing_resource_type == "QUANTITY":
|
||||
row.operator("bim.disable_editing_resource", text="", icon="CANCEL")
|
||||
elif self.props.active_resource_id:
|
||||
row.operator("bim.add_resource", text="", icon="ADD").resource = ifc_definition_id
|
||||
row.operator("bim.remove_resource", text="", icon="X").resource = ifc_definition_id
|
||||
else:
|
||||
if not self.props.active_resource_id:
|
||||
if resource["type"] in ["IfcLaborResource", "IfcConstructionEquipmentResource"]:
|
||||
op = row.operator("bim.calculate_resource_work", text="", icon="TEMP")
|
||||
op.resource = ifc_definition_id
|
||||
@@ -138,7 +129,7 @@ class BIM_PT_resources(Panel):
|
||||
blenderbim.bim.helper.draw_attributes(self.props.resource_time_attributes, self.layout)
|
||||
|
||||
def draw_editable_resource_quantity_ui(self):
|
||||
resource = Data.resources[self.props.active_resource_id]
|
||||
resource = ResourceData.data["resources"][self.props.active_resource_id]
|
||||
|
||||
if resource["BaseQuantity"]:
|
||||
quantity = resource["BaseQuantity"]
|
||||
@@ -177,16 +168,16 @@ class BIM_PT_resources(Panel):
|
||||
if self.props.cost_types == "CATEGORY":
|
||||
op.cost_category = self.props.cost_category
|
||||
|
||||
for cost_value_id in Data.resources[self.props.active_resource_id]["BaseCosts"] or []:
|
||||
for cost_value_id in ResourceData.data["resources"][self.props.active_resource_id]["BaseCosts"] or []:
|
||||
row = self.layout.row(align=True)
|
||||
self.draw_readonly_cost_value_ui(row, cost_value_id)
|
||||
|
||||
if self.props.cost_value_editing_type == "ATTRIBUTES":
|
||||
box = self.layout.box()
|
||||
self.draw_editable_cost_value_ui(box, Data.cost_values[self.props.active_cost_value_id])
|
||||
self.draw_editable_cost_value_ui(box, ResourceData.cost_values[self.props.active_cost_value_id])
|
||||
|
||||
def draw_readonly_cost_value_ui(self, layout, cost_value_id):
|
||||
cost_value = Data.cost_values[cost_value_id]
|
||||
cost_value = ResourceData.cost_values[cost_value_id]
|
||||
|
||||
if self.props.active_cost_value_id == cost_value_id and self.props.cost_value_editing_type == "FORMULA":
|
||||
layout.prop(self.props, "cost_value_formula", text="")
|
||||
@@ -225,7 +216,7 @@ class BIM_PT_resources(Panel):
|
||||
|
||||
class BIM_UL_resources(UIList):
|
||||
def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
|
||||
resource = Data.resources[item.ifc_definition_id]
|
||||
resource = ResourceData.data["resources"][item.ifc_definition_id]
|
||||
icon_map = {
|
||||
"IfcSubContractResource": "TEXT",
|
||||
"IfcCrewResource": "COMMUNITY",
|
||||
@@ -251,13 +242,19 @@ class BIM_UL_resources(UIList):
|
||||
else:
|
||||
row.label(text="", icon="DOT")
|
||||
row.prop(item, "name", emboss=False, text="", icon=icon_map[resource["type"]])
|
||||
|
||||
if context.active_object:
|
||||
if context.active_object and not props.active_resource_id:
|
||||
oprops = context.active_object.BIMObjectProperties
|
||||
row = layout.row(align=True)
|
||||
if oprops.ifc_definition_id in Data.resources[item.ifc_definition_id]["ResourceOf"]:
|
||||
if oprops.ifc_definition_id in ResourceData.data["resources"][item.ifc_definition_id]["ResourceOf"]:
|
||||
op = row.operator("bim.unassign_resource", text="", icon="KEYFRAME_HLT", emboss=False)
|
||||
op.resource = item.ifc_definition_id
|
||||
else:
|
||||
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.editing_resource_type == "ATTRIBUTES":
|
||||
row.operator("bim.edit_resource", text="", icon="CHECKMARK")
|
||||
elif props.editing_resource_type == "USAGE":
|
||||
row.operator("bim.edit_resource_time", text="", icon="CHECKMARK")
|
||||
row.operator("bim.disable_editing_resource", text="", icon="CANCEL")
|
||||
|
||||
@@ -0,0 +1,172 @@
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2022 Dion Moult, Yassine Oualid <dion@thinkmoult.com>
|
||||
#
|
||||
# This file is part of BlenderBIM Add-on.
|
||||
#
|
||||
# BlenderBIM Add-on is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# BlenderBIM Add-on is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# ############################################################################ #
|
||||
|
||||
|
||||
def load_resources(resource):
|
||||
resource.load_resources()
|
||||
resource.load_resource_properties()
|
||||
|
||||
|
||||
def add_resource(tool_ifc, resource_tool, ifc_class, parent_resource=None):
|
||||
tool_ifc.run("resource.add_resource", ifc_class=ifc_class, parent_resource=parent_resource)
|
||||
resource_tool.load_resources()
|
||||
resource_tool.load_resource_properties()
|
||||
|
||||
|
||||
def load_resource_properties(resource_tool, resource=None):
|
||||
resource_tool.load_resource_properties()
|
||||
|
||||
|
||||
def disable_editing_resource(resource_tool):
|
||||
resource_tool.disable_editing_resource()
|
||||
|
||||
|
||||
def disable_resource_editing_ui(resource_tool):
|
||||
resource_tool.disable_resource_editing_ui()
|
||||
|
||||
|
||||
def enable_editing_resource(resource_tool, resource):
|
||||
resource_tool.enable_editing_resource(resource)
|
||||
resource_tool.load_resource_attributes(resource)
|
||||
|
||||
|
||||
def edit_resource(ifc, resource_tool, resource):
|
||||
attributes = resource_tool.get_resource_attributes()
|
||||
ifc.run("resource.edit_resource", resource=resource, attributes=attributes)
|
||||
resource_tool.load_resource_properties()
|
||||
resource_tool.disable_editing_resource()
|
||||
|
||||
|
||||
def remove_resource(ifc, resource_tool, resource=None):
|
||||
ifc.run("resource.remove_resource", resource=resource)
|
||||
resource_tool.load_resources()
|
||||
resource_tool.load_resource_properties()
|
||||
|
||||
|
||||
def enable_editing_resource_time(ifc_tool, resource_tool, resource):
|
||||
resource_time = resource_tool.get_resource_time(resource)
|
||||
if resource_time is None:
|
||||
resource_time = ifc_tool.run("resource.add_resource_time", resource=resource)
|
||||
resource_tool.enable_editing_resource_time(resource)
|
||||
resource_tool.load_resource_time_attributes(resource_time)
|
||||
|
||||
|
||||
def edit_resource_time(ifc, resource_tool, resource_time):
|
||||
attributes = resource_tool.get_resource_time_attributes()
|
||||
ifc.run("resource.edit_resource_time", resource_time=resource_time, attributes=attributes)
|
||||
resource_tool.disable_editing_resource()
|
||||
|
||||
|
||||
def disable_editing_resource_time(resource_tool):
|
||||
resource_tool.disable_editing_resource()
|
||||
|
||||
|
||||
def calculate_resource_work(ifc, resource_tool, resource):
|
||||
ifc.run("calculate_resource_work", resource=resource)
|
||||
resource_tool.load_resources()
|
||||
resource_tool.load_resource_properties()
|
||||
|
||||
|
||||
def enable_editing_resource_costs(resource_tool, resource):
|
||||
resource_tool.enable_editing_resource_costs(resource)
|
||||
resource_tool.disable_editing_resource_cost_value()
|
||||
|
||||
|
||||
def disable_editing_resource_cost_value(resource_tool):
|
||||
resource_tool.disable_editing_resource_cost_value()
|
||||
|
||||
|
||||
def enable_editing_resource_cost_value(resource_tool, cost_value):
|
||||
resource_tool.enable_editing_cost_value_attributes(cost_value)
|
||||
resource_tool.load_cost_value_attributes(cost_value)
|
||||
|
||||
|
||||
def enable_editing_resource_cost_value_formula(resource_tool, cost_value):
|
||||
resource_tool.enable_editing_resource_cost_value_formula(cost_value)
|
||||
|
||||
|
||||
def edit_resource_cost_value_formula(ifc, resource_tool, cost_value):
|
||||
formula = resource_tool.get_resource_cost_value_formula()
|
||||
ifc.run("cost.edit_cost_value_formula", cost_value=cost_value, formula=formula)
|
||||
resource_tool.disable_editing_resource_cost_value()
|
||||
|
||||
|
||||
def edit_resource_cost_value(ifc, resource_tool, cost_value):
|
||||
attributes = resource_tool.get_resource_cost_value_attributes()
|
||||
ifc.run("cost.edit_cost_value", cost_value=cost_value, attributes=attributes)
|
||||
resource_tool.disable_editing_resource_cost_value()
|
||||
|
||||
|
||||
def enable_editing_resource_base_quantity(resource_tool, resource):
|
||||
resource_tool.enable_editing_resource_base_quantity(resource)
|
||||
|
||||
|
||||
def add_resource_quantity(ifc, ifc_class, resource):
|
||||
ifc.run("resource.add_resource_quantity", resource=resource, ifc_class=ifc_class)
|
||||
|
||||
|
||||
def remove_resource_quantity(ifc, resource):
|
||||
ifc.run("resource.remove_resource_quantity", resource=resource)
|
||||
|
||||
|
||||
def enable_editing_resource_quantity(resource_tool, resource_quantity=None):
|
||||
resource_tool.enable_editing_resource_quantity(resource_quantity)
|
||||
|
||||
|
||||
def disable_editing_resource_quantity(resource_tool):
|
||||
resource_tool.disable_editing_resource_quantity()
|
||||
|
||||
|
||||
def edit_resource_quantity(resource_tool, ifc, physical_quantity=None):
|
||||
attributes = resource_tool.get_resource_quantity_attributes()
|
||||
ifc.run("resource.edit_resource_quantity", physical_quantity=physical_quantity, attributes=attributes)
|
||||
resource_tool.disable_editing_resource_quantity()
|
||||
|
||||
|
||||
def import_resources(resource_tool, file_path):
|
||||
resource_tool.import_resources(file_path)
|
||||
resource_tool.load_resources()
|
||||
resource_tool.load_resource_properties()
|
||||
|
||||
|
||||
def expand_resource(resource_tool, resource):
|
||||
resource_tool.expand_resource(resource)
|
||||
resource_tool.load_resources()
|
||||
resource_tool.load_resource_properties()
|
||||
|
||||
|
||||
def contract_resource(resource_tool, resource):
|
||||
resource_tool.contract_resource(resource)
|
||||
resource_tool.load_resources()
|
||||
resource_tool.load_resource_properties()
|
||||
|
||||
|
||||
def assign_resource(ifc, resource_tool, resource=None, products=None):
|
||||
if not products:
|
||||
products = resource_tool.get_selected_products()
|
||||
for product in products:
|
||||
rel = ifc.run("resource.assign_resource", relating_resource=resource, related_object=product)
|
||||
|
||||
|
||||
def unassign_resource(ifc, resource_tool, resource=None, products=None):
|
||||
if not products:
|
||||
products = resource_tool.get_selected_products()
|
||||
for product in products:
|
||||
ifc.run("resource.unassign_resource", relating_resource=resource, related_object=product)
|
||||
@@ -401,6 +401,33 @@ class Qto:
|
||||
def set_qto_result(cls, result): pass
|
||||
|
||||
|
||||
@interface
|
||||
class Resource:
|
||||
def load_resources(cls): pass
|
||||
def load_resource_properties(cls): pass
|
||||
def disable_editing_resource(cls): pass
|
||||
def disable_resource_editing_ui(cls): pass
|
||||
def load_resource_attributes(cls, resource): pass
|
||||
def enable_editing_resource(cls, resource): pass
|
||||
def get_resource_attributes(cls): pass
|
||||
def enable_editing_resource_time(cls, resource): pass
|
||||
def get_resource_time(cls, resource): pass
|
||||
def load_resource_time_attributes(cls, resource_time): pass
|
||||
def get_resource_time_attributes(cls): pass
|
||||
def enable_editing_resource_costs(cls, resource): pass
|
||||
def disable_editing_resource_cost_value(cls): pass
|
||||
def enable_editing_resource_cost_value_formula(cls, cost_value): pass
|
||||
def load_cost_value_attributes(cls, cost_value): pass
|
||||
def enable_editing_cost_value_attributes(cls, cost_value): pass
|
||||
def get_resource_cost_value_formula(cls): pass
|
||||
def get_resource_cost_value_attributes(cls): pass
|
||||
def enable_editing_resource_base_quantity(cls, resource): pass
|
||||
def enable_editing_resource_quantity(cls, resource_quantity): pass
|
||||
def disable_editing_resource_quantity(cls): pass
|
||||
def get_resource_quantity_attributes(cls): pass
|
||||
def expand_resource(cls, resource): pass
|
||||
def contract_resource(cls, resource): pass
|
||||
|
||||
@interface
|
||||
class Root:
|
||||
def add_dynamic_opening_voids(cls, element, obj): pass
|
||||
|
||||
@@ -39,6 +39,7 @@ from blenderbim.tool.patch import Patch
|
||||
from blenderbim.tool.project import Project
|
||||
from blenderbim.tool.pset import Pset
|
||||
from blenderbim.tool.qto import Qto
|
||||
from blenderbim.tool.resource import Resource
|
||||
from blenderbim.tool.root import Root
|
||||
from blenderbim.tool.sequence import Sequence
|
||||
from blenderbim.tool.spatial import Spatial
|
||||
|
||||
@@ -0,0 +1,308 @@
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2022 Dion Moult, Yassine Oualid <dion@thinkmoult.com>
|
||||
#
|
||||
# This file is part of BlenderBIM Add-on.
|
||||
#
|
||||
# BlenderBIM Add-on is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# BlenderBIM Add-on is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# ############################################################################ #
|
||||
|
||||
import bpy
|
||||
import blenderbim.core.tool
|
||||
import blenderbim.tool as tool
|
||||
import blenderbim.bim.helper
|
||||
import blenderbim.bim.module.sequence.helper as helper
|
||||
import json
|
||||
import time
|
||||
import isodate
|
||||
from datetime import datetime
|
||||
from dateutil import parser
|
||||
import ifcopenshell.util.date as ifcdateutils
|
||||
import ifcopenshell.util.cost
|
||||
from ifcopenshell.api.unit.data import Data as UnitData
|
||||
|
||||
|
||||
class Resource(blenderbim.core.tool.Resource):
|
||||
@classmethod
|
||||
def load_resources(cls):
|
||||
def create_new_resource_li(resource, level_index):
|
||||
new = bpy.context.scene.BIMResourceTreeProperties.resources.add()
|
||||
new.ifc_definition_id = resource.id()
|
||||
new.is_expanded = resource.id() not in contracted_resources
|
||||
new.level_index = level_index
|
||||
if resource.IsNestedBy:
|
||||
new.has_children = True
|
||||
if new.is_expanded:
|
||||
for rel in resource.IsNestedBy:
|
||||
[
|
||||
create_new_resource_li(nested_resource, level_index + 1)
|
||||
for nested_resource in rel.RelatedObjects
|
||||
]
|
||||
|
||||
props = bpy.context.scene.BIMResourceProperties
|
||||
tprops = bpy.context.scene.BIMResourceTreeProperties
|
||||
tprops.resources.clear()
|
||||
contracted_resources = json.loads(props.contracted_resources)
|
||||
|
||||
for resource in tool.Ifc.get().by_type("IfcResource"):
|
||||
if not resource.HasContext:
|
||||
continue
|
||||
create_new_resource_li(resource, 0)
|
||||
props.is_editing = True
|
||||
|
||||
@classmethod
|
||||
def load_resource_properties(cls):
|
||||
props = bpy.context.scene.BIMResourceProperties
|
||||
tprops = bpy.context.scene.BIMResourceTreeProperties
|
||||
props.is_resource_update_enabled = False
|
||||
for item in tprops.resources:
|
||||
resource = tool.Ifc.get().by_id(item.ifc_definition_id)
|
||||
item.name = resource.Name if resource else "Unnamed"
|
||||
props.is_resource_update_enabled = True
|
||||
|
||||
@classmethod
|
||||
def disable_editing_resource(cls):
|
||||
bpy.context.scene.BIMResourceProperties.active_resource_id = 0
|
||||
bpy.context.scene.BIMResourceProperties.active_resource_time_id = 0
|
||||
|
||||
@classmethod
|
||||
def disable_resource_editing_ui(cls):
|
||||
bpy.context.scene.BIMResourceProperties.is_editing = False
|
||||
|
||||
@classmethod
|
||||
def load_resource_attributes(cls, resource):
|
||||
blenderbim.bim.helper.import_attributes2(resource, bpy.context.scene.BIMResourceProperties.resource_attributes)
|
||||
|
||||
@classmethod
|
||||
def enable_editing_resource(cls, resource):
|
||||
props = bpy.context.scene.BIMResourceProperties
|
||||
props.active_resource_id = resource.id()
|
||||
props.resource_attributes.clear()
|
||||
props.editing_resource_type = "ATTRIBUTES"
|
||||
|
||||
@classmethod
|
||||
def get_resource_attributes(cls):
|
||||
return blenderbim.bim.helper.export_attributes(bpy.context.scene.BIMResourceProperties.resource_attributes)
|
||||
|
||||
@classmethod
|
||||
def enable_editing_resource_time(cls, resource):
|
||||
props = bpy.context.scene.BIMResourceProperties
|
||||
props.resource_time_attributes.clear()
|
||||
props.active_resource_time_id = resource.Usage.id()
|
||||
props.active_resource_id = resource.id()
|
||||
props.editing_resource_type = "USAGE"
|
||||
|
||||
@classmethod
|
||||
def get_resource_time(cls, resource):
|
||||
return resource.Usage if resource.Usage else None
|
||||
|
||||
@classmethod
|
||||
def load_resource_time_attributes(cls, resource_time):
|
||||
def callback(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 ifcdateutils.datetime2ifc(data[name], "IfcDuration")
|
||||
return True
|
||||
|
||||
blenderbim.bim.helper.import_attributes2(
|
||||
resource_time, bpy.context.scene.BIMResourceProperties.resource_time_attributes, callback
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def get_resource_time_attributes(cls):
|
||||
def callback(attributes, prop):
|
||||
if "Start" in prop.name or "Finish" in prop.name or prop.name == "StatusTime":
|
||||
if prop.is_null:
|
||||
attributes[prop.name] = None
|
||||
return True
|
||||
attributes[prop.name] = helper.parse_datetime(prop.string_value)
|
||||
return True
|
||||
elif prop.name == "LevelingDelay" or "Work" in prop.name:
|
||||
if prop.is_null:
|
||||
attributes[prop.name] = None
|
||||
return True
|
||||
attributes[prop.name] = helper.parse_duration(prop.string_value)
|
||||
return True
|
||||
|
||||
props = bpy.context.scene.BIMResourceProperties
|
||||
return blenderbim.bim.helper.export_attributes(props.resource_time_attributes, callback)
|
||||
|
||||
@classmethod
|
||||
def enable_editing_resource_costs(cls, resource):
|
||||
props = bpy.context.scene.BIMResourceProperties
|
||||
props.active_resource_id = resource.id()
|
||||
props.editing_resource_type = "COSTS"
|
||||
resource
|
||||
|
||||
@classmethod
|
||||
def disable_editing_resource_cost_value(cls):
|
||||
props = bpy.context.scene.BIMResourceProperties
|
||||
props.active_cost_value_id = 0
|
||||
props.cost_value_editing_type = ""
|
||||
|
||||
@classmethod
|
||||
def enable_editing_resource_cost_value_formula(cls, cost_value):
|
||||
props = bpy.context.scene.BIMResourceProperties
|
||||
props.cost_value_attributes.clear()
|
||||
props.active_cost_value_id = cost_value.id()
|
||||
props.cost_value_editing_type = "FORMULA"
|
||||
props.cost_value_formula = ifcopenshell.util.cost.serialise_cost_value(cost_value) if cost_value else ""
|
||||
|
||||
@classmethod
|
||||
def load_cost_value_attributes(cls, cost_value):
|
||||
def callback(name, prop, data):
|
||||
if name == "AppliedValue":
|
||||
# TODO: for now, only support simple IfcValues (which are effectively IfcMonetaryMeasure)
|
||||
prop = props.cost_value_attributes.add()
|
||||
prop.data_type = "float"
|
||||
prop.name = "AppliedValue"
|
||||
prop.is_optional = True
|
||||
prop.float_value = 0.0 if prop.is_null or not data[name] else data[name][0]
|
||||
return True
|
||||
elif name == "UnitBasis":
|
||||
prop = props.cost_value_attributes.add()
|
||||
prop.name = "UnitBasisValue"
|
||||
prop.data_type = "float"
|
||||
prop.is_null = data["UnitBasis"] is None
|
||||
prop.is_optional = True
|
||||
if data["UnitBasis"]:
|
||||
prop.float_value = data["UnitBasis"].ValueComponent[0] or 0
|
||||
else:
|
||||
prop.float_value = 0
|
||||
|
||||
prop = props.cost_value_attributes.add()
|
||||
prop.name = "UnitBasisUnit"
|
||||
prop.data_type = "enum"
|
||||
prop.is_null = prop.is_optional = False
|
||||
units = {}
|
||||
if not UnitData.is_loaded:
|
||||
UnitData.load(tool.Ifc.get())
|
||||
for unit_id, unit in UnitData.units.items():
|
||||
if unit.get("UnitType", None) in [
|
||||
"AREAUNIT",
|
||||
"LENGTHUNIT",
|
||||
"TIMEUNIT",
|
||||
"VOLUMEUNIT",
|
||||
"MASSUNIT",
|
||||
"USERDEFINED",
|
||||
]:
|
||||
if unit["type"] == "IfcContextDependentUnit":
|
||||
units[unit_id] = f"{unit['UnitType']} / {unit['Name']}"
|
||||
else:
|
||||
name = unit["Name"]
|
||||
if unit.get("Prefix", None):
|
||||
name = f"(unit['Prefix']) {name}"
|
||||
units[unit_id] = f"{unit['UnitType']} / {name}"
|
||||
prop.enum_items = json.dumps(units)
|
||||
if data["UnitBasis"] and data["UnitBasis"].UnitComponent:
|
||||
name = data["UnitBasis"].UnitComponent.Name
|
||||
unit_type = data["UnitBasis"].UnitComponent.UnitType
|
||||
prop.enum_value = str(data["UnitBasis"].UnitComponent.id())
|
||||
return True
|
||||
|
||||
props = bpy.context.scene.BIMResourceProperties
|
||||
blenderbim.bim.helper.import_attributes2(cost_value, props.cost_value_attributes, callback)
|
||||
|
||||
@classmethod
|
||||
def enable_editing_cost_value_attributes(cls, cost_value):
|
||||
props = bpy.context.scene.BIMResourceProperties
|
||||
props.cost_value_attributes.clear()
|
||||
props.active_cost_value_id = cost_value.id()
|
||||
props.cost_value_editing_type = "ATTRIBUTES"
|
||||
|
||||
@classmethod
|
||||
def get_resource_cost_value_formula(cls):
|
||||
return bpy.context.scene.BIMResourceProperties.cost_value_formula
|
||||
|
||||
@classmethod
|
||||
def get_resource_cost_value_attributes(cls):
|
||||
def callback(attributes, prop):
|
||||
if prop.name == "UnitBasisValue":
|
||||
if prop.is_null:
|
||||
attributes["UnitBasis"] = None
|
||||
return True
|
||||
attributes["UnitBasis"] = {
|
||||
"ValueComponent": prop.float_value or 1,
|
||||
"UnitComponent": tool.Ifc.get().by_id(
|
||||
int(
|
||||
bpy.context.scene.BIMResourceProperties.cost_value_attributes.get(
|
||||
"UnitBasisUnit"
|
||||
).enum_value
|
||||
)
|
||||
),
|
||||
}
|
||||
return True
|
||||
if prop.name == "UnitBasisUnit":
|
||||
return True
|
||||
|
||||
return blenderbim.bim.helper.export_attributes(
|
||||
bpy.context.scene.BIMResourceProperties.cost_value_attributes, callback
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def enable_editing_resource_base_quantity(cls, resource):
|
||||
props = bpy.context.scene.BIMResourceProperties
|
||||
props.active_resource_id = resource.id()
|
||||
props.editing_resource_type = "QUANTITY"
|
||||
|
||||
@classmethod
|
||||
def enable_editing_resource_quantity(cls, resource_quantity):
|
||||
props = bpy.context.scene.BIMResourceProperties
|
||||
props.quantity_attributes.clear()
|
||||
props.is_editing_quantity = True
|
||||
blenderbim.bim.helper.import_attributes2(resource_quantity, props.quantity_attributes)
|
||||
|
||||
@classmethod
|
||||
def disable_editing_resource_quantity(cls):
|
||||
bpy.context.scene.BIMResourceProperties.is_editing_quantity = False
|
||||
|
||||
@classmethod
|
||||
def get_resource_quantity_attributes(cls):
|
||||
return blenderbim.bim.helper.export_attributes(bpy.context.scene.BIMResourceProperties.quantity_attributes)
|
||||
|
||||
@classmethod
|
||||
def expand_resource(cls, resource):
|
||||
props = bpy.context.scene.BIMResourceProperties
|
||||
contracted_resources = json.loads(props.contracted_resources)
|
||||
contracted_resources.remove(resource.id())
|
||||
props.contracted_resources = json.dumps(contracted_resources)
|
||||
|
||||
@classmethod
|
||||
def contract_resource(cls, resource):
|
||||
props = bpy.context.scene.BIMResourceProperties
|
||||
contracted_resources = json.loads(props.contracted_resources)
|
||||
contracted_resources.append(resource.id())
|
||||
props.contracted_resources = json.dumps(contracted_resources)
|
||||
|
||||
@classmethod
|
||||
def get_selected_products(cls):
|
||||
return [
|
||||
tool.Ifc.get_entity(obj)
|
||||
for obj in bpy.context.selected_objects
|
||||
if obj.BIMObjectProperties.ifc_definition_id
|
||||
] or []
|
||||
|
||||
@classmethod
|
||||
def import_resources(cls, file_path):
|
||||
from ifc4d.csv2ifc import Csv2Ifc
|
||||
|
||||
start = time.time()
|
||||
p62ifc = Csv2Ifc()
|
||||
p62ifc.csv = file_path
|
||||
p62ifc.file = tool.Ifc.get()
|
||||
p62ifc.execute()
|
||||
print("Importing Resources CSV finished in {:.2f} seconds".format(time.time() - start))
|
||||
Reference in New Issue
Block a user