Refactor Resource module

This commit is contained in:
bosonprojets
2022-09-09 02:17:28 +01:00
parent e4c1f7518d
commit e2d4a3ae24
8 changed files with 712 additions and 466 deletions
@@ -27,7 +27,7 @@ from blenderbim.bim.ifc import IfcStore
from bpy_extras.io_utils import ImportHelper from bpy_extras.io_utils import ImportHelper
from ifcopenshell.api.cost.data import Data from ifcopenshell.api.cost.data import Data
from ifcopenshell.api.unit.data import Data as UnitData 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): 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) 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) ifcopenshell.api.run("cost.edit_cost_value", self.file, cost_value=value, attributes=attributes)
if parent.is_a("IfcConstructionResource"): if parent.is_a("IfcConstructionResource"):
ResourceData.load(self.file) ResourceData.load()
else: else:
Data.load(self.file) Data.load(self.file)
return {"FINISHED"} return {"FINISHED"}
@@ -630,7 +630,7 @@ class RemoveCostItemValue(bpy.types.Operator):
cost_value=self.file.by_id(self.cost_value), cost_value=self.file.by_id(self.cost_value),
) )
if parent.is_a("IfcConstructionResource"): if parent.is_a("IfcConstructionResource"):
ResourceData.load(self.file) ResourceData.load()
else: else:
Data.load(self.file) Data.load(self.file)
return {"FINISHED"} 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/>. # along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
import bpy import bpy
import json from bpy_extras.io_utils import ImportHelper
import time import blenderbim.core.resource as core
import isodate import blenderbim.tool as tool
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
class LoadResources(bpy.types.Operator): class LoadResources(bpy.types.Operator):
bl_idname = "bim.load_resources" bl_idname = "bim.load_resources"
@@ -35,66 +27,9 @@ class LoadResources(bpy.types.Operator):
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
def execute(self, context): def execute(self, context):
self.props = context.scene.BIMResourceProperties core.load_resources(tool.Resource)
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
return {"FINISHED"} 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): class LoadResourceProperties(bpy.types.Operator):
bl_idname = "bim.load_resource_properties" bl_idname = "bim.load_resource_properties"
@@ -103,15 +38,36 @@ class LoadResourceProperties(bpy.types.Operator):
resource: bpy.props.IntProperty() resource: bpy.props.IntProperty()
def execute(self, context): def execute(self, context):
self.props = context.scene.BIMResourceProperties core.load_resource_properties(
self.tprops = context.scene.BIMResourceTreeProperties tool.Resource, resource=tool.Ifc.get().by_id(self.resource) if self.resource else None
self.props.is_resource_update_enabled = False )
for item in self.tprops.resources: return {"FINISHED"}
if self.resource and item.ifc_definition_id != self.resource:
continue
resource = Data.resources[item.ifc_definition_id] class AddResource(bpy.types.Operator, tool.Ifc.Operator):
item.name = resource["Name"] or "Unnamed" bl_idname = "bim.add_resource"
self.props.is_resource_update_enabled = True 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"} return {"FINISHED"}
@@ -121,8 +77,7 @@ class DisableEditingResource(bpy.types.Operator):
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
def execute(self, context): def execute(self, context):
context.scene.BIMResourceProperties.active_resource_id = 0 core.disable_editing_resource(tool.Resource)
context.scene.BIMResourceProperties.active_task_time_id = 0
return {"FINISHED"} return {"FINISHED"}
@@ -132,73 +87,31 @@ class DisableResourceEditingUI(bpy.types.Operator):
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
def execute(self, context): def execute(self, context):
context.scene.BIMResourceProperties.is_editing = False core.disable_resource_editing_ui(tool.Resource)
return {"FINISHED"} return {"FINISHED"}
class AddResource(bpy.types.Operator): class EditResource(bpy.types.Operator, tool.Ifc.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):
bl_idname = "bim.edit_resource" bl_idname = "bim.edit_resource"
bl_label = "Edit Resource" bl_label = "Edit Resource"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
def execute(self, context):
return IfcStore.execute_ifc_operator(self, context)
def _execute(self, context): def _execute(self, context):
props = context.scene.BIMResourceProperties core.edit_resource(
attributes = blenderbim.bim.helper.export_attributes(props.resource_attributes) tool.Ifc,
self.file = IfcStore.get_file() tool.Resource,
ifcopenshell.api.run( resource=tool.Ifc.get().by_id(context.scene.BIMResourceProperties.active_resource_id),
"resource.edit_resource",
self.file,
**{"resource": self.file.by_id(props.active_resource_id), "attributes": attributes},
) )
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_idname = "bim.remove_resource"
bl_label = "Remove Resource" bl_label = "Remove Resource"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
resource: bpy.props.IntProperty() resource: bpy.props.IntProperty()
def execute(self, context):
return IfcStore.execute_ifc_operator(self, context)
def _execute(self, context): def _execute(self, context):
ifcopenshell.api.run( core.remove_resource(tool.Ifc, tool.Resource, resource=tool.Ifc.get().by_id(self.resource))
"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"}
class ExpandResource(bpy.types.Operator): class ExpandResource(bpy.types.Operator):
@@ -208,13 +121,7 @@ class ExpandResource(bpy.types.Operator):
resource: bpy.props.IntProperty() resource: bpy.props.IntProperty()
def execute(self, context): def execute(self, context):
props = context.scene.BIMResourceProperties core.expand_resource(tool.Resource, resource=tool.Ifc.get().by_id(self.resource))
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()
return {"FINISHED"} return {"FINISHED"}
@@ -225,107 +132,40 @@ class ContractResource(bpy.types.Operator):
resource: bpy.props.IntProperty() resource: bpy.props.IntProperty()
def execute(self, context): def execute(self, context):
props = context.scene.BIMResourceProperties core.contract_resource(tool.Resource, resource=tool.Ifc.get().by_id(self.resource))
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()
return {"FINISHED"} return {"FINISHED"}
class AssignResource(bpy.types.Operator): class AssignResource(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.assign_resource" bl_idname = "bim.assign_resource"
bl_label = "Assign Resource" bl_label = "Assign Resource"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
resource: bpy.props.IntProperty() resource: bpy.props.IntProperty()
related_object: bpy.props.StringProperty() related_object: bpy.props.StringProperty()
def execute(self, context):
return IfcStore.execute_ifc_operator(self, context)
def _execute(self, context): def _execute(self, context):
related_objects = ( core.assign_resource(tool.Ifc, tool.Resource, resource=tool.Ifc.get().by_id(self.resource))
[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"}
class UnassignResource(bpy.types.Operator): class UnassignResource(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.unassign_resource" bl_idname = "bim.unassign_resource"
bl_label = "Unassign Resource" bl_label = "Unassign Resource"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
resource: bpy.props.IntProperty() resource: bpy.props.IntProperty()
related_object: bpy.props.StringProperty() related_object: bpy.props.StringProperty()
def execute(self, context): def _execute(self, context):
related_objects = ( core.unassign_resource(tool.Ifc, tool.Resource, resource=tool.Ifc.get().by_id(self.resource))
[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"}
class EnableEditingResourceTime(bpy.types.Operator): class EnableEditingResourceTime(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.enable_editing_resource_time" bl_idname = "bim.enable_editing_resource_time"
bl_label = "Enable Editing Resource Usage" bl_label = "Enable Editing Resource Usage"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
resource: bpy.props.IntProperty() resource: bpy.props.IntProperty()
def execute(self, context):
return IfcStore.execute_ifc_operator(self, context)
def _execute(self, context): def _execute(self, context):
props = context.scene.BIMResourceProperties core.enable_editing_resource_time(tool.Ifc, tool.Resource, resource=tool.Ifc.get().by_id(self.resource))
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
class DisableEditingResourceTime(bpy.types.Operator): class DisableEditingResourceTime(bpy.types.Operator):
@@ -334,63 +174,31 @@ class DisableEditingResourceTime(bpy.types.Operator):
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
def execute(self, context): def execute(self, context):
context.scene.BIMResourceProperties.active_resource_time_id = 0 core.disable_editing_resource_time(tool.Resource)
bpy.ops.bim.disable_editing_resource()
return {"FINISHED"} return {"FINISHED"}
class EditResourceTime(bpy.types.Operator): class EditResourceTime(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.edit_resource_time" bl_idname = "bim.edit_resource_time"
bl_label = "Edit Resource Usage" bl_label = "Edit Resource Usage"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
def execute(self, context):
return IfcStore.execute_ifc_operator(self, context)
def _execute(self, context): def _execute(self, context):
self.props = context.scene.BIMResourceProperties core.edit_resource_time(
attributes = blenderbim.bim.helper.export_attributes( tool.Ifc,
self.props.resource_time_attributes, self.export_attributes 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): class CalculateResourceWork(bpy.types.Operator, tool.Ifc.Operator):
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):
bl_idname = "bim.calculate_resource_work" bl_idname = "bim.calculate_resource_work"
bl_label = "Calculate Resource Work" bl_label = "Calculate Resource Work"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
resource: bpy.props.IntProperty() resource: bpy.props.IntProperty()
def execute(self, context): def _execute(self, context):
self.file = IfcStore.get_file() core.calculate_resource_work(tool.Ifc, tool.Resource, resource=tool.Ifc.get().by_id(self.resource))
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"}
class EnableEditingResourceCosts(bpy.types.Operator): class EnableEditingResourceCosts(bpy.types.Operator):
@@ -400,10 +208,7 @@ class EnableEditingResourceCosts(bpy.types.Operator):
resource: bpy.props.IntProperty() resource: bpy.props.IntProperty()
def execute(self, context): def execute(self, context):
props = context.scene.BIMResourceProperties core.enable_editing_resource_costs(tool.Resource, resource=tool.Ifc.get().by_id(self.resource))
props.active_resource_id = self.resource
props.editing_resource_type = "COSTS"
bpy.ops.bim.disable_editing_resource_cost_value()
return {"FINISHED"} return {"FINISHED"}
@@ -413,21 +218,7 @@ class DisableEditingResourceCostValue(bpy.types.Operator):
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
def execute(self, context): def execute(self, context):
props = context.scene.BIMResourceProperties core.disable_editing_resource_cost_value(tool.Resource)
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 = ""
return {"FINISHED"} return {"FINISHED"}
@@ -438,11 +229,7 @@ class EnableEditingResourceCostValueFormula(bpy.types.Operator):
cost_value: bpy.props.IntProperty() cost_value: bpy.props.IntProperty()
def execute(self, context): def execute(self, context):
self.props = context.scene.BIMResourceProperties core.enable_editing_resource_cost_value_formula(tool.Resource, cost_value=tool.Ifc.get().by_id(self.cost_value))
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"]
return {"FINISHED"} return {"FINISHED"}
@@ -453,127 +240,28 @@ class EnableEditingResourceCostValue(bpy.types.Operator):
cost_value: bpy.props.IntProperty() cost_value: bpy.props.IntProperty()
def execute(self, context): def execute(self, context):
self.props = context.scene.BIMResourceProperties core.enable_editing_resource_cost_value(tool.Resource, cost_value=tool.Ifc.get().by_id(self.cost_value))
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),
)
return {"FINISHED"} 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() class EditResourceCostValueFormula(bpy.types.Operator, tool.Ifc.Operator):
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):
bl_idname = "bim.edit_resource_cost_value_formula" bl_idname = "bim.edit_resource_cost_value_formula"
bl_label = "Edit Resource Cost Value Formula" bl_label = "Edit Resource Cost Value Formula"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
cost_value: bpy.props.IntProperty() cost_value: bpy.props.IntProperty()
def execute(self, context):
return IfcStore.execute_ifc_operator(self, context)
def _execute(self, context): def _execute(self, context):
props = context.scene.BIMResourceProperties core.edit_resource_cost_value_formula(tool.Ifc, tool.Resource, cost_value=tool.Ifc.get().by_id(self.cost_value))
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"}
class EditResourceCostValue(bpy.types.Operator): class EditResourceCostValue(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.edit_resource_cost_value" bl_idname = "bim.edit_resource_cost_value"
bl_label = "Edit Resource Cost Value" bl_label = "Edit Resource Cost Value"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
cost_value: bpy.props.IntProperty() cost_value: bpy.props.IntProperty()
def execute(self, context):
return IfcStore.execute_ifc_operator(self, context)
def _execute(self, context): def _execute(self, context):
props = context.scene.BIMResourceProperties core.edit_resource_cost_value(tool.Ifc, tool.Resource, cost_value=tool.Ifc.get().by_id(self.cost_value))
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
class EnableEditingResourceBaseQuantity(bpy.types.Operator): class EnableEditingResourceBaseQuantity(bpy.types.Operator):
@@ -583,52 +271,29 @@ class EnableEditingResourceBaseQuantity(bpy.types.Operator):
resource: bpy.props.IntProperty() resource: bpy.props.IntProperty()
def execute(self, context): def execute(self, context):
props = context.scene.BIMResourceProperties core.enable_editing_resource_base_quantity(tool.Resource, resource=tool.Ifc.get().by_id(self.resource))
props.active_resource_id = self.resource
props.editing_resource_type = "QUANTITY"
return {"FINISHED"} return {"FINISHED"}
class AddResourceQuantity(bpy.types.Operator): class AddResourceQuantity(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.add_resource_quantity" bl_idname = "bim.add_resource_quantity"
bl_label = "Add Resource Quantity" bl_label = "Add Resource Quantity"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
resource: bpy.props.IntProperty() resource: bpy.props.IntProperty()
ifc_class: bpy.props.StringProperty() ifc_class: bpy.props.StringProperty()
def execute(self, context):
return IfcStore.execute_ifc_operator(self, context)
def _execute(self, context): def _execute(self, context):
self.file = IfcStore.get_file() core.add_resource_quantity(tool.Ifc, ifc_class=self.ifc_class, resource=tool.Ifc.get().by_id(self.resource))
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"}
class RemoveResourceQuantity(bpy.types.Operator): class RemoveResourceQuantity(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.remove_resource_quantity" bl_idname = "bim.remove_resource_quantity"
bl_label = "Remove Resource Quantity" bl_label = "Remove Resource Quantity"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
resource: bpy.props.IntProperty() resource: bpy.props.IntProperty()
def execute(self, context):
return IfcStore.execute_ifc_operator(self, context)
def _execute(self, context): def _execute(self, context):
self.file = IfcStore.get_file() core.remove_resource_quantity(tool.Ifc, resource=tool.Ifc.get().by_id(self.resource))
ifcopenshell.api.run(
"resource.remove_resource_quantity",
self.file,
resource=self.file.by_id(self.resource),
)
Data.load(self.file)
return {"FINISHED"}
class EnableEditingResourceQuantity(bpy.types.Operator): class EnableEditingResourceQuantity(bpy.types.Operator):
@@ -638,11 +303,9 @@ class EnableEditingResourceQuantity(bpy.types.Operator):
resource: bpy.props.IntProperty() resource: bpy.props.IntProperty()
def execute(self, context): def execute(self, context):
self.props = context.scene.BIMResourceProperties core.enable_editing_resource_quantity(
self.props.quantity_attributes.clear() tool.Resource, resource_quantity=tool.Ifc.get().by_id(self.resource).BaseQuantity
self.props.is_editing_quantity = True )
data = Data.resources[self.resource]["BaseQuantity"]
blenderbim.bim.helper.import_attributes(data["type"], self.props.quantity_attributes, data)
return {"FINISHED"} return {"FINISHED"}
@@ -652,29 +315,18 @@ class DisableEditingResourceQuantity(bpy.types.Operator):
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
def execute(self, context): def execute(self, context):
props = context.scene.BIMResourceProperties core.disable_editing_resource_quantity(tool.Resource)
props.is_editing_quantity = False
return {"FINISHED"} return {"FINISHED"}
class EditResourceQuantity(bpy.types.Operator): class EditResourceQuantity(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.edit_resource_quantity" bl_idname = "bim.edit_resource_quantity"
bl_label = "Edit Resource Quantity" bl_label = "Edit Resource Quantity"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
physical_quantity: bpy.props.IntProperty() physical_quantity: bpy.props.IntProperty()
def execute(self, context):
return IfcStore.execute_ifc_operator(self, context)
def _execute(self, context): def _execute(self, context):
props = context.scene.BIMResourceProperties core.edit_resource_quantity(
attributes = blenderbim.bim.helper.export_attributes(props.quantity_attributes) tool.Resource, tool.Ifc, physical_quantity=tool.Ifc.get().by_id(self.physical_quantity)
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},
) )
Data.load(IfcStore.get_file())
bpy.ops.bim.disable_editing_resource_quantity()
return {"FINISHED"}
@@ -19,7 +19,7 @@
import blenderbim.bim.helper import blenderbim.bim.helper
from bpy.types import Panel, UIList from bpy.types import Panel, UIList
from blenderbim.bim.ifc import IfcStore 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): class BIM_PT_resources(Panel):
@@ -39,17 +39,21 @@ class BIM_PT_resources(Panel):
def draw(self, context): def draw(self, context):
self.props = context.scene.BIMResourceProperties self.props = context.scene.BIMResourceProperties
self.tprops = context.scene.BIMResourceTreeProperties self.tprops = context.scene.BIMResourceTreeProperties
if not ResourceData.is_loaded:
if not Data.is_loaded: ResourceData.load()
Data.load(IfcStore.get_file())
row = self.layout.row(align=True) 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: if self.props.is_editing:
row.operator("bim.disable_resource_editing_ui", text="", icon="CANCEL") row.operator("bim.disable_resource_editing_ui", text="", icon="CANCEL")
else: 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: if not self.props.is_editing:
return return
@@ -76,17 +80,17 @@ class BIM_PT_resources(Panel):
row = self.layout.row(align=True) row = self.layout.row(align=True)
op = row.operator("bim.add_resource", text="Add SubContract", icon="TEXT") op = row.operator("bim.add_resource", text="Add SubContract", icon="TEXT")
op.ifc_class = "IfcSubContractResource" op.ifc_class = "IfcSubContractResource"
op.resource = 0 op.parent_resource = 0
op = row.operator("bim.add_resource", text="Add Crew", icon="COMMUNITY") op = row.operator("bim.add_resource", text="Add Crew", icon="COMMUNITY")
op.ifc_class = "IfcCrewResource" op.ifc_class = "IfcCrewResource"
op.resource = 0 op.parent_resource = 0
total_resources = len(self.tprops.resources) total_resources = len(self.tprops.resources)
if not total_resources or self.props.active_resource_index >= total_resources: if not total_resources or self.props.active_resource_index >= total_resources:
return return
ifc_definition_id = self.tprops.resources[self.props.active_resource_index].ifc_definition_id 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": if resource["type"] != "IfcSubContractResource":
icon_map = { icon_map = {
@@ -100,26 +104,13 @@ class BIM_PT_resources(Panel):
for ifc_class, icon in icon_map.items(): for ifc_class, icon in icon_map.items():
label = ifc_class.replace("Ifc", "").replace("Construction", "").replace("Resource", "") label = ifc_class.replace("Ifc", "").replace("Construction", "").replace("Resource", "")
op = row.operator("bim.add_resource", text=label, icon=icon) 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 op.ifc_class = ifc_class
row = self.layout.row(align=True) row = self.layout.row(align=True)
row.alignment = "RIGHT" row.alignment = "RIGHT"
if self.props.active_resource_id == ifc_definition_id and self.props.editing_resource_type == "ATTRIBUTES": if not self.props.active_resource_id:
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 resource["type"] in ["IfcLaborResource", "IfcConstructionEquipmentResource"]: if resource["type"] in ["IfcLaborResource", "IfcConstructionEquipmentResource"]:
op = row.operator("bim.calculate_resource_work", text="", icon="TEMP") op = row.operator("bim.calculate_resource_work", text="", icon="TEMP")
op.resource = ifc_definition_id 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) blenderbim.bim.helper.draw_attributes(self.props.resource_time_attributes, self.layout)
def draw_editable_resource_quantity_ui(self): 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"]: if resource["BaseQuantity"]:
quantity = resource["BaseQuantity"] quantity = resource["BaseQuantity"]
@@ -177,16 +168,16 @@ class BIM_PT_resources(Panel):
if self.props.cost_types == "CATEGORY": if self.props.cost_types == "CATEGORY":
op.cost_category = self.props.cost_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) row = self.layout.row(align=True)
self.draw_readonly_cost_value_ui(row, cost_value_id) self.draw_readonly_cost_value_ui(row, cost_value_id)
if self.props.cost_value_editing_type == "ATTRIBUTES": if self.props.cost_value_editing_type == "ATTRIBUTES":
box = self.layout.box() 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): 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": 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="") layout.prop(self.props, "cost_value_formula", text="")
@@ -225,7 +216,7 @@ class BIM_PT_resources(Panel):
class BIM_UL_resources(UIList): class BIM_UL_resources(UIList):
def draw_item(self, context, layout, data, item, icon, active_data, active_propname): 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 = { icon_map = {
"IfcSubContractResource": "TEXT", "IfcSubContractResource": "TEXT",
"IfcCrewResource": "COMMUNITY", "IfcCrewResource": "COMMUNITY",
@@ -251,13 +242,19 @@ class BIM_UL_resources(UIList):
else: else:
row.label(text="", icon="DOT") row.label(text="", icon="DOT")
row.prop(item, "name", emboss=False, text="", icon=icon_map[resource["type"]]) row.prop(item, "name", emboss=False, text="", icon=icon_map[resource["type"]])
if context.active_object and not props.active_resource_id:
if context.active_object:
oprops = context.active_object.BIMObjectProperties oprops = context.active_object.BIMObjectProperties
row = layout.row(align=True) 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 = row.operator("bim.unassign_resource", text="", icon="KEYFRAME_HLT", emboss=False)
op.resource = item.ifc_definition_id op.resource = item.ifc_definition_id
else: else:
op = row.operator("bim.assign_resource", text="", icon="KEYFRAME", emboss=False) op = row.operator("bim.assign_resource", text="", icon="KEYFRAME", emboss=False)
op.resource = item.ifc_definition_id 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")
+172
View File
@@ -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)
+27
View File
@@ -401,6 +401,33 @@ class Qto:
def set_qto_result(cls, result): pass 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 @interface
class Root: class Root:
def add_dynamic_opening_voids(cls, element, obj): pass 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.project import Project
from blenderbim.tool.pset import Pset from blenderbim.tool.pset import Pset
from blenderbim.tool.qto import Qto from blenderbim.tool.qto import Qto
from blenderbim.tool.resource import Resource
from blenderbim.tool.root import Root from blenderbim.tool.root import Root
from blenderbim.tool.sequence import Sequence from blenderbim.tool.sequence import Sequence
from blenderbim.tool.spatial import Spatial from blenderbim.tool.spatial import Spatial
+308
View File
@@ -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))