This commit is contained in:
Andrej730
2025-07-17 12:09:42 +05:00
parent 83a3813f53
commit 577d46eb70
13 changed files with 239 additions and 168 deletions
+7 -10
View File
@@ -369,13 +369,13 @@ class CostItemQuantitiesData:
cls.is_loaded = True
@classmethod
def product_quantity_names(cls):
elements = tool.Spatial.get_selected_products()
def product_quantity_names(cls) -> tool.Blender.BLENDER_ENUM_ITEMS:
elements = list(tool.Spatial.get_selected_products())
names = ifcopenshell.util.cost.get_product_quantity_names(elements)
return [(n, n, "") for n in names]
@classmethod
def process_quantity_names(cls):
def process_quantity_names(cls) -> tool.Blender.BLENDER_ENUM_ITEMS:
props = tool.Sequence.get_work_schedule_props()
active_task_index = props.active_task_index
tprops = tool.Sequence.get_task_tree_props()
@@ -391,14 +391,11 @@ class CostItemQuantitiesData:
return [(n, n, "") for n in names if n != "id"]
@classmethod
def resource_quantity_names(cls):
active_resource_index = bpy.context.scene.BIMResourceProperties.active_resource_index
total_resources = len(bpy.context.scene.BIMResourceTreeProperties.resources)
if not total_resources or active_resource_index >= total_resources:
def resource_quantity_names(cls) -> tool.Blender.BLENDER_ENUM_ITEMS:
active_resource = tool.Resource.get_resource_props().active_resource
if not active_resource:
return []
ifc_definition_id = bpy.context.scene.BIMResourceTreeProperties.resources[
active_resource_index
].ifc_definition_id
ifc_definition_id = active_resource.ifc_definition_id
element = tool.Ifc.get().by_id(ifc_definition_id)
names = set()
qtos = ifcopenshell.util.element.get_psets(element, qtos_only=True)
+3 -4
View File
@@ -393,7 +393,7 @@ class BIM_PT_cost_item_types(Panel):
op.cost_item = cost_item.ifc_definition_id
rtprops = context.scene.BIMResourceTreeProperties
rprops = context.scene.BIMResourceProperties
rprops = tool.Resource.get_resource_props()
if rtprops.resources and rprops.active_resource_index < len(rtprops.resources):
if has_quantity_names:
op = row2.operator("bim.assign_cost_item_quantity", text="", icon="PROPERTIES")
@@ -552,9 +552,8 @@ class BIM_PT_cost_item_quantities(Panel):
op = row2.operator("bim.calculate_cost_item_resource_value", text="", icon="DISC")
op.cost_item = cost_item.ifc_definition_id
rtprops = context.scene.BIMResourceTreeProperties
rprops = context.scene.BIMResourceProperties
if rtprops.resources and rprops.active_resource_index < len(rtprops.resources):
active_resource = tool.Resource.get_resource_props().active_resource
if active_resource:
if has_quantity_names:
op = row2.operator("bim.assign_cost_item_quantity", text="", icon="PROPERTIES")
op.related_object_type = "RESOURCE"
+6 -6
View File
@@ -239,9 +239,9 @@ class ResourceQtosData(Data):
@classmethod
def load(cls):
rprops = bpy.context.scene.BIMResourceProperties
rtprops = bpy.context.scene.BIMResourceTreeProperties
ifc_definition_id = rtprops.resources[rprops.active_resource_index].ifc_definition_id
active_resource = tool.Resource.get_resource_props().active_resource
assert active_resource
ifc_definition_id = active_resource.ifc_definition_id
cls.data = {"qtos": cls.psetqtos(tool.Ifc.get().by_id(ifc_definition_id), qtos_only=True)}
cls.is_loaded = True
@@ -252,9 +252,9 @@ class ResourcePsetsData(Data):
@classmethod
def load(cls):
rprops = bpy.context.scene.BIMResourceProperties
rtprops = bpy.context.scene.BIMResourceTreeProperties
ifc_definition_id = rtprops.resources[rprops.active_resource_index].ifc_definition_id
active_resource = tool.Resource.get_resource_props().active_resource
assert active_resource
ifc_definition_id = active_resource.ifc_definition_id
cls.data = {"psets": cls.psetqtos(tool.Ifc.get().by_id(ifc_definition_id), psets_only=True)}
cls.is_loaded = True
+6 -6
View File
@@ -155,9 +155,9 @@ def get_task_qto_names(self: "PsetProperties", context: object) -> tool.Blender.
def get_resource_pset_names(self: "PsetProperties", context: bpy.types.Context) -> tool.Blender.BLENDER_ENUM_ITEMS:
global psetnames
rprops = context.scene.BIMResourceProperties
rtprops = context.scene.BIMResourceTreeProperties
ifc_class = tool.Ifc.get().by_id(rtprops.resources[rprops.active_resource_index].ifc_definition_id).is_a()
active_resource = tool.Resource.get_resource_props().active_resource
assert active_resource
ifc_class = tool.Ifc.get().by_id(active_resource.ifc_definition_id).is_a()
if ifc_class not in psetnames:
psets = bonsai.bim.schema.ifc.psetqto.get_applicable(ifc_class, pset_only=True, schema=tool.Ifc.get_schema())
psetnames[ifc_class] = blender_formatted_enum_from_psets(psets)
@@ -166,9 +166,9 @@ def get_resource_pset_names(self: "PsetProperties", context: bpy.types.Context)
def get_resource_qto_names(self: "PsetProperties", context: bpy.types.Context) -> tool.Blender.BLENDER_ENUM_ITEMS:
global qtonames
rprops = context.scene.BIMResourceProperties
rtprops = context.scene.BIMResourceTreeProperties
ifc_class = tool.Ifc.get().by_id(rtprops.resources[rprops.active_resource_index].ifc_definition_id).is_a()
active_resource = tool.Resource.get_resource_props().active_resource
assert active_resource
ifc_class = tool.Ifc.get().by_id(active_resource.ifc_definition_id).is_a()
if ifc_class not in qtonames:
psets = bonsai.bim.schema.ifc.psetqto.get_applicable(ifc_class, qto_only=True, schema=tool.Ifc.get_schema())
qtonames[ifc_class] = blender_formatted_enum_from_psets(psets)
+4 -10
View File
@@ -596,11 +596,8 @@ class BIM_PT_resource_qtos(Panel):
@classmethod
def poll(cls, context):
props = context.scene.BIMResourceProperties
total_resources = len(context.scene.BIMResourceTreeProperties.resources)
if total_resources > 0 and props.active_resource_index < total_resources:
return True
return False
active_resource = tool.Resource.get_resource_props().active_resource
return bool(active_resource)
def draw(self, context):
if not ResourceQtosData.is_loaded:
@@ -631,11 +628,8 @@ class BIM_PT_resource_psets(Panel):
@classmethod
def poll(cls, context):
props = context.scene.BIMResourceProperties
total_resources = len(context.scene.BIMResourceTreeProperties.resources)
if total_resources > 0 and props.active_resource_index < total_resources:
return True
return False
active_resource = tool.Resource.get_resource_props().active_resource
return bool(active_resource)
def draw(self, context):
if not ResourcePsetsData.is_loaded:
@@ -124,7 +124,7 @@ class ResourceData:
@classmethod
def cost_values(cls) -> list[dict[str, Any]]:
results = []
ifc_id = bpy.context.scene.BIMResourceProperties.active_resource_id
ifc_id = tool.Resource.get_resource_props().active_resource_id
if not ifc_id:
return results
resource = tool.Ifc.get().by_id(ifc_id)
@@ -87,10 +87,11 @@ class EditResource(bpy.types.Operator, tool.Ifc.Operator):
bl_options = {"REGISTER", "UNDO"}
def _execute(self, context):
props = tool.Resource.get_resource_props()
core.edit_resource(
tool.Ifc,
tool.Resource,
resource=tool.Ifc.get().by_id(context.scene.BIMResourceProperties.active_resource_id),
resource=tool.Ifc.get().by_id(props.active_resource_id),
)
@@ -174,10 +175,11 @@ class EditResourceTime(bpy.types.Operator, tool.Ifc.Operator):
bl_options = {"REGISTER", "UNDO"}
def _execute(self, context):
props = tool.Resource.get_resource_props()
core.edit_resource_time(
tool.Ifc,
tool.Resource,
resource_time=tool.Ifc.get().by_id(context.scene.BIMResourceProperties.active_resource_time_id),
resource_time=tool.Ifc.get().by_id(props.active_resource_time_id),
)
+84 -16
View File
@@ -24,7 +24,7 @@ import bonsai.tool as tool
import bonsai.bim.module.pset.data
import bonsai.bim.module.resource.data
import bonsai.bim.module.sequence.data
from bonsai.bim.prop import StrProperty, Attribute
from bonsai.bim.prop import Attribute
from bpy.types import PropertyGroup
from bpy.props import (
PointerProperty,
@@ -36,11 +36,12 @@ from bpy.props import (
FloatVectorProperty,
CollectionProperty,
)
from typing import TYPE_CHECKING, Literal, get_args
quantitytypes_enum = {}
quantitytypes_enum: dict[str, tool.Blender.BLENDER_ENUM_ITEMS] = {}
def setup_quantity_types_enum():
def setup_quantity_types_enum() -> None:
resources = ifcopenshell.util.resource.RESOURCES_TO_QUANTITIES
for resource, quantities in resources.items():
quantitytypes_enum[resource] = [(q, q, "") for q in quantities]
@@ -49,8 +50,8 @@ def setup_quantity_types_enum():
setup_quantity_types_enum()
def updateResourceName(self, context):
props = context.scene.BIMResourceProperties
def updateResourceName(self: "Resource", context: object) -> None:
props = tool.Resource.get_resource_props()
if not props.is_resource_update_enabled:
return
ifc_file = tool.Ifc.get()
@@ -66,18 +67,19 @@ def updateResourceName(self, context):
tool.Sequence.refresh_task_resources()
def get_quantity_types(self, context):
def get_quantity_types(self: "BIMResourceProperties", context: object) -> tool.Blender.BLENDER_ENUM_ITEMS:
return quantitytypes_enum[self.active_resource_class]
def update_active_resource_index(self, context):
def update_active_resource_index(self: "BIMResourceProperties", context: object) -> None:
bonsai.bim.module.pset.data.refresh()
if self.should_show_resource_tools:
tool.Resource.load_productivity_data()
def updateResourceUsage(self, context):
if not context.scene.BIMResourceProperties.is_resource_update_enabled:
def updateResourceUsage(self: "Resource", context: object) -> None:
props = tool.Resource.get_resource_props()
if not props.is_resource_update_enabled:
return
if not self.schedule_usage:
return
@@ -102,6 +104,15 @@ class ISODuration(PropertyGroup):
minutes: IntProperty(name="Minutes", default=0)
seconds: IntProperty(name="Seconds", default=0)
if TYPE_CHECKING:
name: str
years: int
months: int
days: int
hours: int
minutes: int
seconds: int
class Resource(PropertyGroup):
name: StringProperty(name="Name", update=updateResourceName)
@@ -111,10 +122,26 @@ class Resource(PropertyGroup):
is_expanded: BoolProperty(name="Is Expanded")
level_index: IntProperty(name="Level Index")
if TYPE_CHECKING:
name: str
ifc_definition_id: int
schedule_usage: float
has_children: bool
is_expanded: bool
level_index: int
# Separate from BIMResourceProperties - see BIMTaskTreeProperties note.
class BIMResourceTreeProperties(PropertyGroup):
resources: CollectionProperty(name="Resources", type=Resource)
if TYPE_CHECKING:
resources: bpy.types.bpy_prop_collection_idprop[Resource]
EditingResourceType = Literal["ATTRIBUTES", "USAGE", "COSTS", "QUANTITY"]
CostType = Literal["FIXED", "SUM", "CATEGORY"]
class BIMResourceProperties(PropertyGroup):
resource_attributes: CollectionProperty(name="Resource Attributes", type=Attribute)
@@ -128,13 +155,7 @@ class BIMResourceProperties(PropertyGroup):
active_resource_time_id: IntProperty(name="Active Resource Usage Id")
resource_time_attributes: CollectionProperty(name="Resource Usage Attributes", type=Attribute)
editing_resource_type: EnumProperty(
name="Editing Resource Type",
items=(
("ATTRIBUTES", "", ""),
("USAGE", "", ""),
("COSTS", "", ""),
("QUANTITY", "", ""),
),
name="Editing Resource Type", items=[(i, i, "") for i in get_args(EditingResourceType)]
)
cost_types: EnumProperty(
items=[
@@ -154,9 +175,56 @@ class BIMResourceProperties(PropertyGroup):
quantity_attributes: CollectionProperty(name="Quantity Attributes", type=Attribute)
should_show_resource_tools: BoolProperty(name="Edit Productivity", update=update_active_resource_index)
if TYPE_CHECKING:
resource_attributes: bpy.types.bpy_prop_collection_idprop[Attribute]
is_editing: bool
active_resource_index: int
active_resource_id: int
active_resource_class: str
contracted_resources: str
is_resource_update_enabled: bool
is_loaded: bool
active_resource_time_id: int
resource_time_attributes: bpy.types.bpy_prop_collection_idprop[Attribute]
editing_resource_type: EditingResourceType
cost_types: CostType
cost_category: str
active_cost_value_id: int
cost_value_editing_type: str
cost_value_attributes: bpy.types.bpy_prop_collection_idprop[Attribute]
cost_value_formula: str
quantity_types: str
is_editing_quantity: bool
quantity_attributes: bpy.types.bpy_prop_collection_idprop[Attribute]
should_show_resource_tools: bool
@property
def tree(self) -> "BIMResourceTreeProperties":
assert bpy.context.scene
tprops = bpy.context.scene.BIMResourceTreeProperties # pyright: ignore[reportAttributeAccessIssue]
assert isinstance(tprops, BIMResourceTreeProperties)
return tprops
@property
def productivity(self) -> "BIMResourceProductivity":
assert bpy.context.scene
productivity = bpy.context.scene.BIMResourceProductivity
assert isinstance(productivity, BIMResourceProductivity)
return productivity
@property
def active_resource(self) -> Resource | None:
return tool.Blender.get_active_uilist_element(self.tree.resources, self.active_resource_index)
class BIMResourceProductivity(PropertyGroup):
ifc_definition_id: IntProperty(name="IFC Definition ID")
quantity_consumed: CollectionProperty(name="Duration", type=ISODuration)
quantity_produced: FloatProperty(name="Quantity Produced")
quantity_produced_name: StringProperty(name="Quantity Produced Name")
if TYPE_CHECKING:
ifc_definition_id: int
quantity_consumed: bpy.types.bpy_prop_collection_idprop[ISODuration]
quantity_produced: float
quantity_produced_name: str
+41 -33
View File
@@ -16,12 +16,16 @@
# You should have received a copy of the GNU General Public License
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
from __future__ import annotations
import bpy
import bonsai.tool as tool
import bonsai.bim.helper
from bpy.types import Panel, UIList
from bonsai.bim.module.resource.data import ResourceData
from typing import Any
from typing import Any, TYPE_CHECKING
if TYPE_CHECKING:
from bonsai.bim.module.resource.prop import ISODuration, Resource, BIMResourceTreeProperties
class BIM_PT_resources(Panel):
@@ -38,9 +42,10 @@ class BIM_PT_resources(Panel):
file = tool.Ifc.get()
return file and hasattr(file, "schema") and file.schema != "IFC2X3"
layout: bpy.types.UILayout
def draw(self, context):
self.props = context.scene.BIMResourceProperties
self.tprops = context.scene.BIMResourceTreeProperties
self.props = tool.Resource.get_resource_props()
if not ResourceData.is_loaded:
ResourceData.load()
@@ -64,7 +69,7 @@ class BIM_PT_resources(Panel):
self.layout.template_list(
"BIM_UL_resources",
"",
self.tprops,
self.props.tree,
"resources",
self.props,
"active_resource_index",
@@ -79,18 +84,18 @@ class BIM_PT_resources(Panel):
self.draw_editable_resource_costs_ui()
elif self.props.active_resource_id and self.props.editing_resource_type == "USAGE":
self.draw_editable_resource_time_attributes_ui()
self.draw_productivity_ui(context)
self.draw_productivity_ui()
def draw_productivity_ui(self, context):
def draw_productivity_ui(self) -> None:
row = self.layout.row(align=True)
row.alignment = "RIGHT"
row.prop(self.props, "should_show_resource_tools", text="Resource Tools", icon="RECOVER_LAST")
if self.props.should_show_resource_tools:
total_resources = len(self.tprops.resources)
if not total_resources or self.props.active_resource_index >= total_resources:
active_resource = self.props.active_resource
if not active_resource:
return
ifc_definition_id = self.tprops.resources[self.props.active_resource_index].ifc_definition_id
ifc_definition_id = active_resource.ifc_definition_id
resource = ResourceData.data["resources"][ifc_definition_id]
if not resource["type"] in ["IfcConstructionEquipmentResource", "IfcLaborResource"]:
@@ -145,7 +150,7 @@ class BIM_PT_resources(Panel):
row2_col1 = col1.row()
row2_col1.label(text="Schedule Usage")
row2col2 = col2.row()
row2col2.prop(self.tprops.resources[self.props.active_resource_index], "schedule_usage", text="")
row2col2.prop(active_resource, "schedule_usage", text="")
row2col3 = col3.row()
row2col3.operator("bim.calculate_resource_usage", text="", icon="TEMP")
op = row2col3.operator(
@@ -189,7 +194,7 @@ class BIM_PT_resources(Panel):
row.label(text="{}".format(produtivitiy_rate_message), icon="ARMATURE_DATA")
row.operator("bim.add_productivity_data", text="", icon="ADD")
def draw_resource_operators(self):
def draw_resource_operators(self) -> None:
row = self.layout.row(align=True)
op = row.operator("bim.add_resource", text="Add SubContract", icon="TEXT")
op.ifc_class = "IfcSubContractResource"
@@ -198,11 +203,11 @@ class BIM_PT_resources(Panel):
op.ifc_class = "IfcCrewResource"
op.parent_resource = 0
total_resources = len(self.tprops.resources)
if not total_resources or self.props.active_resource_index >= total_resources:
active_resource = self.props.active_resource
if not active_resource:
return
ifc_definition_id = self.tprops.resources[self.props.active_resource_index].ifc_definition_id
ifc_definition_id = active_resource.ifc_definition_id
resource = ResourceData.data["resources"][ifc_definition_id]
if resource["type"] != "IfcSubContractResource":
@@ -239,13 +244,13 @@ class BIM_PT_resources(Panel):
row.operator("bim.edit_resource_time", text="", icon="CHECKMARK")
row.operator("bim.disable_editing_resource", text="", icon="CANCEL")
def draw_editable_resource_attributes_ui(self):
def draw_editable_resource_attributes_ui(self) -> None:
bonsai.bim.helper.draw_attributes(self.props.resource_attributes, self.layout)
def draw_editable_resource_time_attributes_ui(self):
def draw_editable_resource_time_attributes_ui(self) -> None:
bonsai.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) -> None:
resource = ResourceData.data["resources"][self.props.active_resource_id]
if resource["BaseQuantity"]:
@@ -278,7 +283,7 @@ class BIM_PT_resources(Panel):
op.resource = self.props.active_resource_id
op.ifc_class = self.props.quantity_types
def draw_editable_resource_costs_ui(self):
def draw_editable_resource_costs_ui(self) -> None:
row = self.layout.row(align=True)
row.prop(self.props, "cost_types", text="")
if self.props.cost_types == "CATEGORY":
@@ -326,16 +331,6 @@ class BIM_PT_resources(Panel):
op.parent = parent_id
op.cost_value = cost_value_id
def draw_duration_property(self, duration_props, layout):
for duration_prop in duration_props:
if duration_prop.name == "BaseQuantityConsumed":
layout.prop(duration_prop, "years", text="Y")
layout.prop(duration_prop, "months", text="M")
layout.prop(duration_prop, "days", text="D")
layout.prop(duration_prop, "hours", text="H")
layout.prop(duration_prop, "minutes", text="Min")
layout.prop(duration_prop, "seconds", text="S")
class BIM_UL_resources(UIList):
@classmethod
@@ -358,7 +353,16 @@ class BIM_UL_resources(UIList):
col = row.column()
col.label(text="")
def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
def draw_item(
self,
context: bpy.types.Context,
layout: bpy.types.UILayout,
data: BIMResourceTreeProperties,
item: Resource,
icon,
active_data,
active_propname,
) -> None:
icon_map = {
"IfcSubContractResource": "TEXT",
"IfcCrewResource": "COMMUNITY",
@@ -369,7 +373,7 @@ class BIM_UL_resources(UIList):
}
if item:
resource = ResourceData.data["resources"][item.ifc_definition_id]
props = context.scene.BIMResourceProperties
props = tool.Resource.get_resource_props()
row = layout.row(align=True)
for i in range(0, item.level_index):
row.label(text="", icon="BLANK1")
@@ -403,8 +407,12 @@ class BIM_UL_resources(UIList):
row.operator("bim.disable_editing_resource", text="", icon="CANCEL")
def draw_productivity_ui(self, context):
def draw_duration_property(duration_props, layout):
def draw_productivity_ui(self: bpy.types.Operator, context: object) -> None:
assert self.layout
def draw_duration_property(
duration_props: bpy.types.bpy_prop_collection_idprop[ISODuration], layout: bpy.types.UILayout
) -> None:
for duration_prop in duration_props:
if duration_prop.name == "BaseQuantityConsumed":
layout.prop(duration_prop, "years", text="Y")
@@ -414,7 +422,7 @@ def draw_productivity_ui(self, context):
layout.prop(duration_prop, "minutes", text="Min")
layout.prop(duration_prop, "seconds", text="S")
productivity_props = context.scene.BIMResourceProductivity
productivity_props = tool.Resource.get_resource_props().productivity
grid = self.layout.grid_flow(columns=2, even_columns=False, even_rows=False, align=False)
col1 = grid.column(align=False)
col2 = grid.column(align=False)
@@ -386,12 +386,11 @@ class TaskICOMData:
cls.is_loaded = True
@classmethod
def can_active_resource_be_assigned(cls):
resource_props = bpy.context.scene.BIMResourceProperties
resource_tprops = bpy.context.scene.BIMResourceTreeProperties
total_resources = len(resource_tprops.resources)
if total_resources and resource_props.active_resource_index < total_resources:
resource_id = resource_tprops.resources[resource_props.active_resource_index].ifc_definition_id
def can_active_resource_be_assigned(cls) -> bool:
props = tool.Resource.get_resource_props()
active_resource = props.active_resource
if active_resource:
resource_id = active_resource.ifc_definition_id
return not tool.Ifc.get().by_id(resource_id).is_a("IfcCrewResource")
return False
@@ -308,8 +308,9 @@ def updateAssignedResourceName(self, context):
pass
def updateAssignedResourceUsage(self, context):
if not context.scene.BIMResourceProperties.is_resource_update_enabled:
def updateAssignedResourceUsage(self: "TaskResource", context: object) -> None:
props = tool.Resource.get_resource_props()
if not props.is_resource_update_enabled:
return
if not self.schedule_usage:
return
+3 -3
View File
@@ -246,9 +246,9 @@ class Blender(bonsai.core.tool.Blender):
cost_props = tool.Cost.get_cost_props()
return cost_props.cost_items[cost_props.active_cost_item_index].ifc_definition_id
elif obj_type == "Resource":
return context.scene.BIMResourceTreeProperties.resources[
context.scene.BIMResourceProperties.active_resource_index
].ifc_definition_id
active_resource = tool.Resource.get_resource_props().active_resource
assert active_resource
return active_resource.ifc_definition_id
elif obj_type == "Profile":
props = tool.Profile.get_profile_props()
return props.profiles[props.active_profile_index].ifc_definition_id
+72 -69
View File
@@ -37,18 +37,25 @@ from typing import Any, Union, TYPE_CHECKING, Literal
if TYPE_CHECKING:
from bonsai.bim.prop import Attribute
from bonsai.bim.module.resource.prop import BIMResourceProperties
from bonsai.bim.module.resource.prop import BIMResourceProperties, BIMResourceProductivity
class Resource(bonsai.core.tool.Resource):
@classmethod
def get_resource_props(cls) -> BIMResourceProperties:
"""
BIMResourceTreeProperties can be accessed using `.tree`.
BIMResourceProductivity - using `.productivity`.
"""
return bpy.context.scene.BIMResourceProperties
@classmethod
def load_resources(cls) -> None:
def create_new_resource_li(resource, level_index):
new = bpy.context.scene.BIMResourceTreeProperties.resources.add()
props = cls.get_resource_props()
tprops = props.tree
def create_new_resource_li(resource: ifcopenshell.entity_instance, level_index: int) -> None:
new = tprops.resources.add()
new.ifc_definition_id = resource.id()
new.is_expanded = resource.id() not in contracted_resources
new.level_index = level_index
@@ -61,8 +68,6 @@ class Resource(bonsai.core.tool.Resource):
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)
props.is_resource_update_enabled = False
@@ -77,8 +82,8 @@ class Resource(bonsai.core.tool.Resource):
@classmethod
def load_resource_properties(cls) -> None:
props = bpy.context.scene.BIMResourceProperties
tprops = bpy.context.scene.BIMResourceTreeProperties
props = cls.get_resource_props()
tprops = props.tree
props.is_resource_update_enabled = False
for item in tprops.resources:
resource = tool.Ifc.get().by_id(item.ifc_definition_id)
@@ -90,20 +95,23 @@ class Resource(bonsai.core.tool.Resource):
@classmethod
def disable_editing_resource(cls) -> None:
bpy.context.scene.BIMResourceProperties.active_resource_id = 0
bpy.context.scene.BIMResourceProperties.active_resource_time_id = 0
props = cls.get_resource_props()
props.property_unset("active_resource_id")
props.property_unset("active_resource_time_id")
@classmethod
def disable_resource_editing_ui(cls) -> None:
bpy.context.scene.BIMResourceProperties.is_editing = False
props = cls.get_resource_props()
props.property_unset("is_editing")
@classmethod
def load_resource_attributes(cls, resource: ifcopenshell.entity_instance) -> None:
bonsai.bim.helper.import_attributes(resource, bpy.context.scene.BIMResourceProperties.resource_attributes)
props = cls.get_resource_props()
bonsai.bim.helper.import_attributes(resource, props.resource_attributes)
@classmethod
def enable_editing_resource(cls, resource: ifcopenshell.entity_instance) -> None:
props = bpy.context.scene.BIMResourceProperties
props = cls.get_resource_props()
props.active_resource_id = resource.id()
props.resource_attributes.clear()
props.editing_resource_type = "ATTRIBUTES"
@@ -111,11 +119,12 @@ class Resource(bonsai.core.tool.Resource):
@classmethod
def get_resource_attributes(cls) -> dict[str, Any]:
return bonsai.bim.helper.export_attributes(bpy.context.scene.BIMResourceProperties.resource_attributes)
props = cls.get_resource_props()
return bonsai.bim.helper.export_attributes(props.resource_attributes)
@classmethod
def enable_editing_resource_time(cls, resource: ifcopenshell.entity_instance) -> None:
props = bpy.context.scene.BIMResourceProperties
props = cls.get_resource_props()
props.resource_time_attributes.clear()
props.active_resource_time_id = resource.Usage.id()
props.active_resource_id = resource.id()
@@ -128,8 +137,10 @@ class Resource(bonsai.core.tool.Resource):
@classmethod
def load_resource_time_attributes(cls, resource_time: ifcopenshell.entity_instance) -> None:
def callback(name, prop, data):
if prop.data_type == "string":
props = cls.get_resource_props()
def callback(name: str, prop: Union[Attribute, None], data: dict[str, Any]) -> None | Literal[True]:
if prop and prop.data_type == "string":
if isinstance(data[name], datetime):
prop.string_value = "" if prop.is_null else data[name].isoformat()
return True
@@ -137,9 +148,7 @@ class Resource(bonsai.core.tool.Resource):
prop.string_value = "" if prop.is_null else ifcdateutils.datetime2ifc(data[name], "IfcDuration")
return True
bonsai.bim.helper.import_attributes(
resource_time, bpy.context.scene.BIMResourceProperties.resource_time_attributes, callback
)
bonsai.bim.helper.import_attributes(resource_time, props.resource_time_attributes, callback)
@classmethod
def get_resource_time_attributes(cls) -> dict[str, Any]:
@@ -160,25 +169,25 @@ class Resource(bonsai.core.tool.Resource):
return True
return False
props = bpy.context.scene.BIMResourceProperties
props = cls.get_resource_props()
return bonsai.bim.helper.export_attributes(props.resource_time_attributes, callback)
@classmethod
def enable_editing_resource_costs(cls, resource: ifcopenshell.entity_instance) -> None:
props = bpy.context.scene.BIMResourceProperties
props = cls.get_resource_props()
props.active_resource_id = resource.id()
props.editing_resource_type = "COSTS"
cls.update_cost_values_ui_data()
@classmethod
def disable_editing_resource_cost_value(cls) -> None:
props = bpy.context.scene.BIMResourceProperties
props = cls.get_resource_props()
props.active_cost_value_id = 0
props.cost_value_editing_type = ""
@classmethod
def enable_editing_resource_cost_value_formula(cls, cost_value: ifcopenshell.entity_instance) -> None:
props = bpy.context.scene.BIMResourceProperties
props = cls.get_resource_props()
props.cost_value_attributes.clear()
props.active_cost_value_id = cost_value.id()
props.cost_value_editing_type = "FORMULA"
@@ -234,48 +243,44 @@ class Resource(bonsai.core.tool.Resource):
prop.enum_value = str(data["UnitBasis"].UnitComponent.id())
return True
props = bpy.context.scene.BIMResourceProperties
props = cls.get_resource_props()
bonsai.bim.helper.import_attributes(cost_value, props.cost_value_attributes, callback)
@classmethod
def enable_editing_cost_value_attributes(cls, cost_value: ifcopenshell.entity_instance) -> None:
props = bpy.context.scene.BIMResourceProperties
props = cls.get_resource_props()
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
props = cls.get_resource_props()
return props.cost_value_formula
@classmethod
def get_resource_cost_value_attributes(cls) -> dict[str, Any]:
def callback(attributes, prop):
props = cls.get_resource_props()
def callback(data: dict[str, Any], prop: Attribute) -> bool:
if prop.name == "UnitBasisValue":
if prop.is_null:
attributes["UnitBasis"] = None
data["UnitBasis"] = None
return True
attributes["UnitBasis"] = {
data["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
)
),
"UnitComponent": tool.Ifc.get().by_id(int(props.cost_value_attributes["UnitBasisUnit"].enum_value)),
}
return True
if prop.name == "UnitBasisUnit":
return True
return False
return bonsai.bim.helper.export_attributes(
bpy.context.scene.BIMResourceProperties.cost_value_attributes, callback
)
return bonsai.bim.helper.export_attributes(props.cost_value_attributes, callback)
@classmethod
def enable_editing_resource_base_quantity(cls, resource: ifcopenshell.entity_instance) -> None:
props = bpy.context.scene.BIMResourceProperties
props = cls.get_resource_props()
props.active_resource_id = resource.id()
props.editing_resource_type = "QUANTITY"
props.active_resource_class = resource.is_a()
@@ -283,22 +288,24 @@ class Resource(bonsai.core.tool.Resource):
@classmethod
def enable_editing_resource_quantity(cls, resource_quantity: ifcopenshell.entity_instance) -> None:
props = bpy.context.scene.BIMResourceProperties
props = cls.get_resource_props()
props.quantity_attributes.clear()
props.is_editing_quantity = True
bonsai.bim.helper.import_attributes(resource_quantity, props.quantity_attributes)
@classmethod
def disable_editing_resource_quantity(cls) -> None:
bpy.context.scene.BIMResourceProperties.is_editing_quantity = False
props = cls.get_resource_props()
props.property_unset("is_editing_quantity")
@classmethod
def get_resource_quantity_attributes(cls) -> dict[str, Any]:
return bonsai.bim.helper.export_attributes(bpy.context.scene.BIMResourceProperties.quantity_attributes)
props = cls.get_resource_props()
return bonsai.bim.helper.export_attributes(props.quantity_attributes)
@classmethod
def expand_resource(cls, resource: ifcopenshell.entity_instance) -> None:
props = bpy.context.scene.BIMResourceProperties
props = cls.get_resource_props()
contracted_resources = json.loads(props.contracted_resources)
if not resource.id() in contracted_resources:
return
@@ -307,7 +314,7 @@ class Resource(bonsai.core.tool.Resource):
@classmethod
def contract_resource(cls, resource: ifcopenshell.entity_instance) -> None:
props = bpy.context.scene.BIMResourceProperties
props = cls.get_resource_props()
contracted_resources = json.loads(props.contracted_resources)
contracted_resources.append(resource.id())
props.contracted_resources = json.dumps(contracted_resources)
@@ -332,16 +339,13 @@ class Resource(bonsai.core.tool.Resource):
@classmethod
def get_highlighted_resource(cls) -> Union[ifcopenshell.entity_instance, None]:
resources = len(bpy.context.scene.BIMResourceTreeProperties.resources)
if resources and resources > bpy.context.scene.BIMResourceProperties.active_resource_index:
return tool.Ifc.get().by_id(
bpy.context.scene.BIMResourceTreeProperties.resources[
bpy.context.scene.BIMResourceProperties.active_resource_index
].ifc_definition_id
)
props = cls.get_resource_props()
active_resource = props.active_resource
if active_resource:
return tool.Ifc.get().by_id(active_resource.ifc_definition_id)
@classmethod
def clear_productivity_data(cls, props: bpy.types.PropertyGroup) -> None:
def clear_productivity_data(cls, props: BIMResourceProductivity) -> None:
for duration_prop in props.quantity_consumed or []:
if duration_prop.name == "BaseQuantityConsumed":
duration_prop.years = 0
@@ -356,22 +360,21 @@ class Resource(bonsai.core.tool.Resource):
@classmethod
def load_productivity_data(cls) -> None:
duration_props = None
for collection_prop in bpy.context.scene.BIMResourceProductivity.quantity_consumed:
productivity_props = tool.Resource.get_resource_props().productivity
for collection_prop in productivity_props.quantity_consumed:
duration_props = collection_prop if collection_prop.name == "BaseQuantityConsumed" else None
break
if not duration_props:
duration_props = bpy.context.scene.BIMResourceProductivity.quantity_consumed.add()
duration_props = productivity_props.quantity_consumed.add()
duration_props.name = "BaseQuantityConsumed"
cls.clear_productivity_data(bpy.context.scene.BIMResourceProductivity)
cls.clear_productivity_data(productivity_props)
current_resource = tool.Resource.get_highlighted_resource()
if current_resource:
productivity = cls.get_productivity(current_resource)
if productivity:
bpy.context.scene.BIMResourceProductivity.quantity_produced = (
ifcopenshell.util.resource.get_quantity_produced(productivity)
)
bpy.context.scene.BIMResourceProductivity.quantity_produced_name = (
ifcopenshell.util.resource.get_quantity_produced_name(productivity)
productivity_props.quantity_produced = ifcopenshell.util.resource.get_quantity_produced(productivity)
productivity_props.quantity_produced_name = ifcopenshell.util.resource.get_quantity_produced_name(
productivity
)
time_consumed = ifcopenshell.util.resource.get_unit_consumed(productivity)
if time_consumed:
@@ -387,7 +390,7 @@ class Resource(bonsai.core.tool.Resource):
@classmethod
def get_productivity_attributes(cls) -> dict[str, Any]:
props = bpy.context.scene.BIMResourceProductivity
props = tool.Resource.get_resource_props().productivity
productivity = {}
if props.quantity_consumed:
import bonsai.bim.module.sequence.helper as helper
@@ -446,24 +449,24 @@ class Resource(bonsai.core.tool.Resource):
@classmethod
def go_to_resource(cls, resource: ifcopenshell.entity_instance) -> None:
def get_ancestors_ids(resource):
ids = []
def get_ancestors_ids(resource: ifcopenshell.entity_instance) -> list[int]:
ids: list[int] = []
for rel in resource.Nests or []:
ids.append(rel.RelatingObject.id())
ids.extend(get_ancestors_ids(rel.RelatingObject))
return ids
props = cls.get_resource_props()
ancestors = get_ancestors_ids(resource)
contracted_resources = json.loads(bpy.context.scene.BIMResourceProperties.contracted_resources)
contracted_resources = json.loads(props.contracted_resources)
for ancestor in ancestors:
if ancestor in contracted_resources:
contracted_resources.remove(ancestor)
bpy.context.scene.BIMResourceProperties.contracted_resources = json.dumps(contracted_resources)
props.contracted_resources = json.dumps(contracted_resources)
cls.load_resources()
resource_props = bpy.context.scene.BIMResourceTreeProperties
expanded_resources = [item.ifc_definition_id for item in resource_props.resources]
bpy.context.scene.BIMResourceProperties.active_resource_index = expanded_resources.index(resource.id())
expanded_resources = [item.ifc_definition_id for item in props.tree.resources]
props.active_resource_index = expanded_resources.index(resource.id())
@classmethod
def run_calculate_resource_usage(cls, resource: ifcopenshell.entity_instance) -> None: