mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-18 22:33:33 +00:00
You can now count elements, tasks, and resources parametrically for cost items
This commit is contained in:
@@ -183,7 +183,7 @@ class IfcStore:
|
|||||||
def commit_link_element(data):
|
def commit_link_element(data):
|
||||||
obj = bpy.data.objects.get(data["obj"])
|
obj = bpy.data.objects.get(data["obj"])
|
||||||
IfcStore.id_map[data["id"]] = obj
|
IfcStore.id_map[data["id"]] = obj
|
||||||
if data["guid"]:
|
if "guid" in data:
|
||||||
IfcStore.guid_map[data["guid"]] = obj
|
IfcStore.guid_map[data["guid"]] = obj
|
||||||
blenderbim.bim.handler.subscribe_to(obj, "mode", blenderbim.bim.handler.mode_callback)
|
blenderbim.bim.handler.subscribe_to(obj, "mode", blenderbim.bim.handler.mode_callback)
|
||||||
blenderbim.bim.handler.subscribe_to(obj, "name", blenderbim.bim.handler.name_callback)
|
blenderbim.bim.handler.subscribe_to(obj, "name", blenderbim.bim.handler.name_callback)
|
||||||
|
|||||||
@@ -640,7 +640,7 @@ class EnableEditingCostItemValue(bpy.types.Operator):
|
|||||||
data["type"],
|
data["type"],
|
||||||
self.props.cost_value_attributes,
|
self.props.cost_value_attributes,
|
||||||
data,
|
data,
|
||||||
lambda name, prop, data: self.import_attributes(name, prop, data, context)
|
lambda name, prop, data: self.import_attributes(name, prop, data, context),
|
||||||
)
|
)
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
@@ -715,8 +715,8 @@ class EditCostValue(bpy.types.Operator):
|
|||||||
def _execute(self, context):
|
def _execute(self, context):
|
||||||
props = context.scene.BIMCostProperties
|
props = context.scene.BIMCostProperties
|
||||||
attributes = blenderbim.bim.helper.export_attributes(
|
attributes = blenderbim.bim.helper.export_attributes(
|
||||||
props.cost_value_attributes,
|
props.cost_value_attributes, lambda attributes, prop: self.export_attributes(attributes, prop, context)
|
||||||
lambda attributes, prop: self.export_attributes(attributes, prop, context))
|
)
|
||||||
self.file = IfcStore.get_file()
|
self.file = IfcStore.get_file()
|
||||||
ifcopenshell.api.run(
|
ifcopenshell.api.run(
|
||||||
"cost.edit_cost_value",
|
"cost.edit_cost_value",
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ def update_schedule_of_rates(self, context):
|
|||||||
bpy.ops.bim.load_schedule_of_rates(cost_schedule=int(self.schedule_of_rates))
|
bpy.ops.bim.load_schedule_of_rates(cost_schedule=int(self.schedule_of_rates))
|
||||||
|
|
||||||
|
|
||||||
def getQuantityTypes(self, context):
|
def get_quantity_types(self, context):
|
||||||
global quantitytypes_enum
|
global quantitytypes_enum
|
||||||
if len(quantitytypes_enum) == 0 and IfcStore.get_schema():
|
if len(quantitytypes_enum) == 0 and IfcStore.get_schema():
|
||||||
quantitytypes_enum.extend(
|
quantitytypes_enum.extend(
|
||||||
@@ -91,7 +91,7 @@ def getQuantityTypes(self, context):
|
|||||||
return quantitytypes_enum
|
return quantitytypes_enum
|
||||||
|
|
||||||
|
|
||||||
def getProductQuantityNames(self, context):
|
def get_product_quantity_names(self, context):
|
||||||
global productquantitynames_enum
|
global productquantitynames_enum
|
||||||
global productquantitynames_count
|
global productquantitynames_count
|
||||||
ifc_file = IfcStore.get_file()
|
ifc_file = IfcStore.get_file()
|
||||||
@@ -115,7 +115,7 @@ def getProductQuantityNames(self, context):
|
|||||||
return productquantitynames_enum
|
return productquantitynames_enum
|
||||||
|
|
||||||
|
|
||||||
def getProcessQuantityNames(self, context):
|
def get_process_quantity_names(self, context):
|
||||||
global processquantitynames_enum
|
global processquantitynames_enum
|
||||||
global processquantitynames_id
|
global processquantitynames_id
|
||||||
ifc_file = IfcStore.get_file()
|
ifc_file = IfcStore.get_file()
|
||||||
@@ -137,7 +137,7 @@ def getProcessQuantityNames(self, context):
|
|||||||
return processquantitynames_enum
|
return processquantitynames_enum
|
||||||
|
|
||||||
|
|
||||||
def getResourceQuantityNames(self, context):
|
def get_resource_quantity_names(self, context):
|
||||||
global resourcequantitynames_enum
|
global resourcequantitynames_enum
|
||||||
global resourcequantitynames_id
|
global resourcequantitynames_id
|
||||||
ifc_file = IfcStore.get_file()
|
ifc_file = IfcStore.get_file()
|
||||||
@@ -166,7 +166,7 @@ def update_active_cost_item_index(self, context):
|
|||||||
bpy.ops.bim.load_cost_item_quantities()
|
bpy.ops.bim.load_cost_item_quantities()
|
||||||
|
|
||||||
|
|
||||||
def updateCostItemIdentification(self, context):
|
def update_cost_item_identification(self, context):
|
||||||
props = context.scene.BIMCostProperties
|
props = context.scene.BIMCostProperties
|
||||||
if not props.is_cost_update_enabled or self.identification == "XXX":
|
if not props.is_cost_update_enabled or self.identification == "XXX":
|
||||||
return
|
return
|
||||||
@@ -182,7 +182,7 @@ def updateCostItemIdentification(self, context):
|
|||||||
attribute.string_value = self.identification
|
attribute.string_value = self.identification
|
||||||
|
|
||||||
|
|
||||||
def updateCostItemName(self, context):
|
def update_cost_item_name(self, context):
|
||||||
props = context.scene.BIMCostProperties
|
props = context.scene.BIMCostProperties
|
||||||
if not props.is_cost_update_enabled or self.name == "Unnamed":
|
if not props.is_cost_update_enabled or self.name == "Unnamed":
|
||||||
return
|
return
|
||||||
@@ -199,8 +199,8 @@ def updateCostItemName(self, context):
|
|||||||
|
|
||||||
|
|
||||||
class CostItem(PropertyGroup):
|
class CostItem(PropertyGroup):
|
||||||
name: StringProperty(name="Name", update=updateCostItemName)
|
name: StringProperty(name="Name", update=update_cost_item_name)
|
||||||
identification: StringProperty(name="Identification", update=updateCostItemIdentification)
|
identification: StringProperty(name="Identification", update=update_cost_item_identification)
|
||||||
ifc_definition_id: IntProperty(name="IFC Definition ID")
|
ifc_definition_id: IntProperty(name="IFC Definition ID")
|
||||||
has_children: BoolProperty(name="Has Children")
|
has_children: BoolProperty(name="Has Children")
|
||||||
is_expanded: BoolProperty(name="Is Expanded")
|
is_expanded: BoolProperty(name="Is Expanded")
|
||||||
@@ -229,10 +229,10 @@ class BIMCostProperties(PropertyGroup):
|
|||||||
active_cost_item_index: IntProperty(name="Active Cost Item Index", update=update_active_cost_item_index)
|
active_cost_item_index: IntProperty(name="Active Cost Item Index", update=update_active_cost_item_index)
|
||||||
cost_item_attributes: CollectionProperty(name="Task Attributes", type=Attribute)
|
cost_item_attributes: CollectionProperty(name="Task Attributes", type=Attribute)
|
||||||
contracted_cost_items: StringProperty(name="Contracted Cost Items", default="[]")
|
contracted_cost_items: StringProperty(name="Contracted Cost Items", default="[]")
|
||||||
quantity_types: EnumProperty(items=getQuantityTypes, name="Quantity Types")
|
quantity_types: EnumProperty(items=get_quantity_types, name="Quantity Types")
|
||||||
product_quantity_names: EnumProperty(items=getProductQuantityNames, name="Product Quantity Names")
|
product_quantity_names: EnumProperty(items=get_product_quantity_names, name="Product Quantity Names")
|
||||||
process_quantity_names: EnumProperty(items=getProcessQuantityNames, name="Process Quantity Names")
|
process_quantity_names: EnumProperty(items=get_process_quantity_names, name="Process Quantity Names")
|
||||||
resource_quantity_names: EnumProperty(items=getResourceQuantityNames, name="Resource Quantity Names")
|
resource_quantity_names: EnumProperty(items=get_resource_quantity_names, name="Resource Quantity Names")
|
||||||
active_cost_item_quantity_id: IntProperty(name="Active Cost Item Quantity Id")
|
active_cost_item_quantity_id: IntProperty(name="Active Cost Item Quantity Id")
|
||||||
quantity_attributes: CollectionProperty(name="Quantity Attributes", type=Attribute)
|
quantity_attributes: CollectionProperty(name="Quantity Attributes", type=Attribute)
|
||||||
cost_types: EnumProperty(
|
cost_types: EnumProperty(
|
||||||
|
|||||||
@@ -373,11 +373,29 @@ class BIM_PT_cost_item_quantities(Panel):
|
|||||||
# Column1
|
# Column1
|
||||||
col = grid.column()
|
col = grid.column()
|
||||||
|
|
||||||
|
has_quantity_names = CostProp.get_product_quantity_names(self, context)
|
||||||
|
|
||||||
row2 = col.row(align=True)
|
row2 = col.row(align=True)
|
||||||
row2.label(text="Elements")
|
row2.label(text="Elements")
|
||||||
op = row2.operator("bim.select_cost_item_products", icon="RESTRICT_SELECT_OFF", text="")
|
op = row2.operator("bim.select_cost_item_products", icon="RESTRICT_SELECT_OFF", text="")
|
||||||
op.cost_item = cost_item.ifc_definition_id
|
op.cost_item = cost_item.ifc_definition_id
|
||||||
|
|
||||||
|
if context.selected_objects:
|
||||||
|
if has_quantity_names:
|
||||||
|
op = row2.operator("bim.assign_cost_item_quantity", text="", icon="PROPERTIES")
|
||||||
|
op.related_object_type = "PRODUCT"
|
||||||
|
op.cost_item = cost_item.ifc_definition_id
|
||||||
|
op.prop_name = self.props.product_quantity_names
|
||||||
|
|
||||||
|
op = row2.operator("bim.assign_cost_item_quantity", text="", icon="ADD")
|
||||||
|
op.related_object_type = "PRODUCT"
|
||||||
|
op.cost_item = cost_item.ifc_definition_id
|
||||||
|
op.prop_name = ""
|
||||||
|
|
||||||
|
op = row2.operator("bim.unassign_cost_item_quantity", text="", icon="REMOVE")
|
||||||
|
op.cost_item = cost_item.ifc_definition_id
|
||||||
|
op.related_object = 0
|
||||||
|
|
||||||
row2 = col.row()
|
row2 = col.row()
|
||||||
row2.template_list(
|
row2.template_list(
|
||||||
"BIM_UL_cost_item_quantities",
|
"BIM_UL_cost_item_quantities",
|
||||||
@@ -388,23 +406,32 @@ class BIM_PT_cost_item_quantities(Panel):
|
|||||||
"active_cost_item_product_index",
|
"active_cost_item_product_index",
|
||||||
)
|
)
|
||||||
|
|
||||||
row2 = col.row(align=True)
|
if has_quantity_names:
|
||||||
row2.prop(self.props, "product_quantity_names", text="")
|
row2 = col.row()
|
||||||
op = row2.operator("bim.unassign_cost_item_quantity", text="", icon="REMOVE")
|
row2.prop(self.props, "product_quantity_names", text="")
|
||||||
op.cost_item = cost_item.ifc_definition_id
|
|
||||||
op.related_object = 0
|
|
||||||
if CostProp.productquantitynames_enum:
|
|
||||||
op = row2.operator("bim.assign_cost_item_quantity", text="", icon="ADD")
|
|
||||||
op.related_object_type = "PRODUCT"
|
|
||||||
op.cost_item = cost_item.ifc_definition_id
|
|
||||||
op.prop_name = self.props.product_quantity_names
|
|
||||||
|
|
||||||
# Column2
|
# Column2
|
||||||
col = grid.column()
|
col = grid.column()
|
||||||
|
|
||||||
|
has_quantity_names = CostProp.get_process_quantity_names(self, context)
|
||||||
|
|
||||||
row2 = col.row(align=True)
|
row2 = col.row(align=True)
|
||||||
row2.label(text="Tasks")
|
row2.label(text="Tasks")
|
||||||
|
|
||||||
|
tprops = context.scene.BIMTaskTreeProperties
|
||||||
|
wprops = context.scene.BIMWorkScheduleProperties
|
||||||
|
if tprops.tasks and wprops.active_task_index < len(tprops.tasks):
|
||||||
|
if has_quantity_names:
|
||||||
|
op = row2.operator("bim.assign_cost_item_quantity", text="", icon="PROPERTIES")
|
||||||
|
op.related_object_type = "PROCESS"
|
||||||
|
op.cost_item = cost_item.ifc_definition_id
|
||||||
|
op.prop_name = self.props.process_quantity_names
|
||||||
|
|
||||||
|
op = row2.operator("bim.assign_cost_item_quantity", text="", icon="ADD")
|
||||||
|
op.related_object_type = "PROCESS"
|
||||||
|
op.cost_item = cost_item.ifc_definition_id
|
||||||
|
op.prop_name = ""
|
||||||
|
|
||||||
row2 = col.row()
|
row2 = col.row()
|
||||||
row2.template_list(
|
row2.template_list(
|
||||||
"BIM_UL_cost_item_quantities",
|
"BIM_UL_cost_item_quantities",
|
||||||
@@ -415,20 +442,32 @@ class BIM_PT_cost_item_quantities(Panel):
|
|||||||
"active_cost_item_process_index",
|
"active_cost_item_process_index",
|
||||||
)
|
)
|
||||||
|
|
||||||
row2 = col.row(align=True)
|
if has_quantity_names:
|
||||||
row2.prop(self.props, "process_quantity_names", text="")
|
row2 = col.row()
|
||||||
if CostProp.processquantitynames_enum:
|
row2.prop(self.props, "process_quantity_names", text="")
|
||||||
op = row2.operator("bim.assign_cost_item_quantity", text="", icon="ADD")
|
|
||||||
op.related_object_type = "PROCESS"
|
|
||||||
op.cost_item = cost_item.ifc_definition_id
|
|
||||||
op.prop_name = self.props.process_quantity_names
|
|
||||||
|
|
||||||
# Column3
|
# Column3
|
||||||
col = grid.column()
|
col = grid.column()
|
||||||
|
|
||||||
|
has_quantity_names = CostProp.get_resource_quantity_names(self, context)
|
||||||
|
|
||||||
row2 = col.row(align=True)
|
row2 = col.row(align=True)
|
||||||
row2.label(text="Resources")
|
row2.label(text="Resources")
|
||||||
|
|
||||||
|
rtprops = context.scene.BIMResourceTreeProperties
|
||||||
|
rprops = context.scene.BIMResourceProperties
|
||||||
|
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")
|
||||||
|
op.related_object_type = "RESOURCE"
|
||||||
|
op.cost_item = cost_item.ifc_definition_id
|
||||||
|
op.prop_name = self.props.resource_quantity_names
|
||||||
|
|
||||||
|
op = row2.operator("bim.assign_cost_item_quantity", text="", icon="ADD")
|
||||||
|
op.related_object_type = "RESOURCE"
|
||||||
|
op.cost_item = cost_item.ifc_definition_id
|
||||||
|
op.prop_name = ""
|
||||||
|
|
||||||
row2 = col.row()
|
row2 = col.row()
|
||||||
row2.template_list(
|
row2.template_list(
|
||||||
"BIM_UL_cost_item_quantities",
|
"BIM_UL_cost_item_quantities",
|
||||||
@@ -439,14 +478,9 @@ class BIM_PT_cost_item_quantities(Panel):
|
|||||||
"active_cost_item_resource_index",
|
"active_cost_item_resource_index",
|
||||||
)
|
)
|
||||||
|
|
||||||
row2 = col.row(align=True)
|
if has_quantity_names:
|
||||||
row2.prop(self.props, "resource_quantity_names", text="")
|
row2 = col.row()
|
||||||
if CostProp.resourcequantitynames_enum:
|
row2.prop(self.props, "resource_quantity_names", text="")
|
||||||
op = row2.operator("bim.assign_cost_item_quantity", text="", icon="ADD")
|
|
||||||
op.related_object_type = "RESOURCE"
|
|
||||||
op.cost_item = cost_item.ifc_definition_id
|
|
||||||
op.prop_name = self.props.resource_quantity_names
|
|
||||||
|
|
||||||
|
|
||||||
class BIM_PT_cost_item_rates(Panel):
|
class BIM_PT_cost_item_rates(Panel):
|
||||||
bl_label = "IFC Cost Item Rates"
|
bl_label = "IFC Cost Item Rates"
|
||||||
|
|||||||
@@ -14,8 +14,10 @@ class Usecase:
|
|||||||
# This is a bold assumption
|
# This is a bold assumption
|
||||||
# https://forums.buildingsmart.org/t/how-does-a-cost-item-know-that-it-is-counting-a-controlled-product/3564
|
# https://forums.buildingsmart.org/t/how-does-a-cost-item-know-that-it-is-counting-a-controlled-product/3564
|
||||||
if self.settings["ifc_class"] == "IfcQuantityCount" and self.settings["cost_item"].Controls:
|
if self.settings["ifc_class"] == "IfcQuantityCount" and self.settings["cost_item"].Controls:
|
||||||
|
count = 0
|
||||||
for rel in self.settings["cost_item"].Controls:
|
for rel in self.settings["cost_item"].Controls:
|
||||||
quantity[3] += len(rel.RelatedObjects)
|
count += len(rel.RelatedObjects)
|
||||||
|
quantity[3] = count
|
||||||
quantities = list(self.settings["cost_item"].CostQuantities or [])
|
quantities = list(self.settings["cost_item"].CostQuantities or [])
|
||||||
quantities.append(quantity)
|
quantities.append(quantity)
|
||||||
self.settings["cost_item"].CostQuantities = quantities
|
self.settings["cost_item"].CostQuantities = quantities
|
||||||
|
|||||||
@@ -9,7 +9,8 @@ class Usecase:
|
|||||||
self.settings[key] = value
|
self.settings[key] = value
|
||||||
|
|
||||||
def execute(self):
|
def execute(self):
|
||||||
self.quantities = set(self.settings["cost_item"].CostQuantities or [])
|
if self.settings["prop_name"]:
|
||||||
|
self.quantities = set(self.settings["cost_item"].CostQuantities or [])
|
||||||
for product in self.settings["products"]:
|
for product in self.settings["products"]:
|
||||||
ifcopenshell.api.run(
|
ifcopenshell.api.run(
|
||||||
"control.assign_control",
|
"control.assign_control",
|
||||||
@@ -17,8 +18,12 @@ class Usecase:
|
|||||||
related_object=product,
|
related_object=product,
|
||||||
relating_control=self.settings["cost_item"],
|
relating_control=self.settings["cost_item"],
|
||||||
)
|
)
|
||||||
self.add_quantity_from_related_object(product)
|
if self.settings["prop_name"]:
|
||||||
self.settings["cost_item"].CostQuantities = list(self.quantities)
|
self.add_quantity_from_related_object(product)
|
||||||
|
if self.settings["prop_name"]:
|
||||||
|
self.settings["cost_item"].CostQuantities = list(self.quantities)
|
||||||
|
else:
|
||||||
|
self.update_cost_item_count()
|
||||||
|
|
||||||
def add_quantity_from_related_object(self, element):
|
def add_quantity_from_related_object(self, element):
|
||||||
if not element.is_a("IfcObject"):
|
if not element.is_a("IfcObject"):
|
||||||
@@ -33,3 +38,21 @@ class Usecase:
|
|||||||
for prop in qto.Quantities:
|
for prop in qto.Quantities:
|
||||||
if prop.is_a("IfcPhysicalSimpleQuantity") and prop.Name.lower() == self.settings["prop_name"].lower():
|
if prop.is_a("IfcPhysicalSimpleQuantity") and prop.Name.lower() == self.settings["prop_name"].lower():
|
||||||
self.quantities.add(prop)
|
self.quantities.add(prop)
|
||||||
|
|
||||||
|
def update_cost_item_count(self):
|
||||||
|
# This is a bold assumption
|
||||||
|
# https://forums.buildingsmart.org/t/how-does-a-cost-item-know-that-it-is-counting-a-controlled-product/3564
|
||||||
|
if not self.settings["cost_item"].CostQuantities:
|
||||||
|
return ifcopenshell.api.run(
|
||||||
|
"cost.add_cost_item_quantity",
|
||||||
|
self.file,
|
||||||
|
cost_item=self.settings["cost_item"],
|
||||||
|
ifc_class="IfcQuantityCount",
|
||||||
|
)
|
||||||
|
if len(self.settings["cost_item"].CostQuantities) == 1:
|
||||||
|
quantity = self.settings["cost_item"].CostQuantities[0]
|
||||||
|
if quantity.is_a("IfcQuantityCount"):
|
||||||
|
count = 0
|
||||||
|
for rel in self.settings["cost_item"].Controls:
|
||||||
|
count += len(rel.RelatedObjects)
|
||||||
|
quantity[3] = count
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ class Usecase:
|
|||||||
if related_object in self.settings["products"]:
|
if related_object in self.settings["products"]:
|
||||||
self.quantities.remove(quantity)
|
self.quantities.remove(quantity)
|
||||||
self.settings["cost_item"].CostQuantities = list(self.quantities)
|
self.settings["cost_item"].CostQuantities = list(self.quantities)
|
||||||
|
|
||||||
for product in self.settings["products"]:
|
for product in self.settings["products"]:
|
||||||
ifcopenshell.api.run(
|
ifcopenshell.api.run(
|
||||||
"control.unassign_control",
|
"control.unassign_control",
|
||||||
@@ -27,3 +26,15 @@ class Usecase:
|
|||||||
related_object=product,
|
related_object=product,
|
||||||
relating_control=self.settings["cost_item"],
|
relating_control=self.settings["cost_item"],
|
||||||
)
|
)
|
||||||
|
self.update_cost_item_count()
|
||||||
|
|
||||||
|
def update_cost_item_count(self):
|
||||||
|
# This is a bold assumption
|
||||||
|
# https://forums.buildingsmart.org/t/how-does-a-cost-item-know-that-it-is-counting-a-controlled-product/3564
|
||||||
|
if len(self.settings["cost_item"].CostQuantities) == 1:
|
||||||
|
quantity = self.settings["cost_item"].CostQuantities[0]
|
||||||
|
if quantity.is_a("IfcQuantityCount"):
|
||||||
|
count = 0
|
||||||
|
for rel in self.settings["cost_item"].Controls:
|
||||||
|
count += len(rel.RelatedObjects)
|
||||||
|
quantity[3] = count
|
||||||
|
|||||||
Reference in New Issue
Block a user