mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-18 22:33:33 +00:00
Implement arithmetic formulas for cost value components
This commit is contained in:
@@ -11,7 +11,7 @@ from blenderbim.bim.ifc import IfcStore
|
|||||||
def import_attributes(ifc_class, props, data, callback=None):
|
def import_attributes(ifc_class, props, data, callback=None):
|
||||||
for attribute in IfcStore.get_schema().declaration_by_name(ifc_class).all_attributes():
|
for attribute in IfcStore.get_schema().declaration_by_name(ifc_class).all_attributes():
|
||||||
data_type = ifcopenshell.util.attribute.get_primitive_type(attribute)
|
data_type = ifcopenshell.util.attribute.get_primitive_type(attribute)
|
||||||
if data_type == "entity":
|
if data_type == "entity" or (isinstance(data_type, tuple) and "entity" in ".".join(data_type)):
|
||||||
continue
|
continue
|
||||||
new = props.add()
|
new = props.add()
|
||||||
new.name = attribute.name()
|
new.name = attribute.name()
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ classes = (
|
|||||||
operator.EditCostSchedule,
|
operator.EditCostSchedule,
|
||||||
operator.EditCostItem,
|
operator.EditCostItem,
|
||||||
operator.EditCostItemQuantity,
|
operator.EditCostItemQuantity,
|
||||||
operator.EditCostItemValue,
|
operator.EditCostValue,
|
||||||
operator.EnableEditingCostSchedule,
|
operator.EnableEditingCostSchedule,
|
||||||
operator.EnableEditingCostItems,
|
operator.EnableEditingCostItems,
|
||||||
operator.EnableEditingCostItem,
|
operator.EnableEditingCostItem,
|
||||||
@@ -28,7 +28,7 @@ classes = (
|
|||||||
operator.UnassignControl,
|
operator.UnassignControl,
|
||||||
operator.AddCostItemQuantity,
|
operator.AddCostItemQuantity,
|
||||||
operator.RemoveCostItemQuantity,
|
operator.RemoveCostItemQuantity,
|
||||||
operator.AddCostItemValue,
|
operator.AddCostValue,
|
||||||
operator.RemoveCostItemValue,
|
operator.RemoveCostItemValue,
|
||||||
prop.CostItem,
|
prop.CostItem,
|
||||||
prop.BIMCostProperties,
|
prop.BIMCostProperties,
|
||||||
|
|||||||
@@ -423,10 +423,10 @@ class EditCostItemQuantity(bpy.types.Operator):
|
|||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
class AddCostItemValue(bpy.types.Operator):
|
class AddCostValue(bpy.types.Operator):
|
||||||
bl_idname = "bim.add_cost_item_value"
|
bl_idname = "bim.add_cost_value"
|
||||||
bl_label = "Add Cost Item Value"
|
bl_label = "Add Cost Value"
|
||||||
cost_item: bpy.props.IntProperty()
|
parent: bpy.props.IntProperty()
|
||||||
cost_type: bpy.props.StringProperty()
|
cost_type: bpy.props.StringProperty()
|
||||||
cost_category: bpy.props.StringProperty()
|
cost_category: bpy.props.StringProperty()
|
||||||
|
|
||||||
@@ -438,9 +438,9 @@ class AddCostItemValue(bpy.types.Operator):
|
|||||||
category = "*"
|
category = "*"
|
||||||
elif self.cost_type == "CATEGORY":
|
elif self.cost_type == "CATEGORY":
|
||||||
category = self.cost_category
|
category = self.cost_category
|
||||||
value = ifcopenshell.api.run("cost.add_cost_item_value", self.file, cost_item=self.file.by_id(self.cost_item))
|
value = ifcopenshell.api.run("cost.add_cost_value", self.file, parent=self.file.by_id(self.parent))
|
||||||
ifcopenshell.api.run(
|
ifcopenshell.api.run(
|
||||||
"cost.edit_cost_item_value", self.file, cost_value=value, attributes={"Category": category}
|
"cost.edit_cost_value", self.file, cost_value=value, attributes={"Category": category}
|
||||||
)
|
)
|
||||||
Data.load(self.file)
|
Data.load(self.file)
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
@@ -497,8 +497,8 @@ class DisableEditingCostItemValue(bpy.types.Operator):
|
|||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
class EditCostItemValue(bpy.types.Operator):
|
class EditCostValue(bpy.types.Operator):
|
||||||
bl_idname = "bim.edit_cost_item_value"
|
bl_idname = "bim.edit_cost_value"
|
||||||
bl_label = "Edit Cost Item Value"
|
bl_label = "Edit Cost Item Value"
|
||||||
cost_value: bpy.props.IntProperty()
|
cost_value: bpy.props.IntProperty()
|
||||||
|
|
||||||
@@ -507,7 +507,7 @@ class EditCostItemValue(bpy.types.Operator):
|
|||||||
attributes = blenderbim.bim.helper.export_attributes(props.cost_value_attributes)
|
attributes = blenderbim.bim.helper.export_attributes(props.cost_value_attributes)
|
||||||
self.file = IfcStore.get_file()
|
self.file = IfcStore.get_file()
|
||||||
ifcopenshell.api.run(
|
ifcopenshell.api.run(
|
||||||
"cost.edit_cost_item_value",
|
"cost.edit_cost_value",
|
||||||
self.file,
|
self.file,
|
||||||
**{"cost_value": self.file.by_id(self.cost_value), "attributes": attributes},
|
**{"cost_value": self.file.by_id(self.cost_value), "attributes": attributes},
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -149,35 +149,59 @@ class BIM_PT_cost_schedules(Panel):
|
|||||||
row.prop(self.props, "cost_types", text="")
|
row.prop(self.props, "cost_types", text="")
|
||||||
if self.props.cost_types == "CATEGORY":
|
if self.props.cost_types == "CATEGORY":
|
||||||
row.prop(self.props, "cost_category", text="")
|
row.prop(self.props, "cost_category", text="")
|
||||||
op = row.operator("bim.add_cost_item_value", text="", icon="ADD")
|
op = row.operator("bim.add_cost_value", text="", icon="ADD")
|
||||||
op.cost_item = self.props.active_cost_item_id
|
op.parent = self.props.active_cost_item_id
|
||||||
op.cost_type = self.props.cost_types
|
op.cost_type = self.props.cost_types
|
||||||
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.cost_items[self.props.active_cost_item_id]["CostValues"]:
|
for cost_value_id in Data.cost_items[self.props.active_cost_item_id]["CostValues"]:
|
||||||
cost_value = Data.cost_values[cost_value_id]
|
self.draw_readonly_cost_value_ui(self.layout, cost_value_id)
|
||||||
row = self.layout.row(align=True)
|
|
||||||
row.label(text=str(cost_value["Category"]))
|
|
||||||
row.label(text=str(cost_value["AppliedValue"]))
|
|
||||||
if self.props.active_cost_item_value_id and self.props.active_cost_item_value_id == cost_value_id:
|
|
||||||
op = row.operator("bim.edit_cost_item_value", text="", icon="CHECKMARK")
|
|
||||||
op.cost_value = cost_value_id
|
|
||||||
row.operator("bim.disable_editing_cost_item_value", text="", icon="CANCEL")
|
|
||||||
elif self.props.active_cost_item_value_id:
|
|
||||||
op = row.operator("bim.remove_cost_item_value", text="", icon="X")
|
|
||||||
op.cost_value = cost_value_id
|
|
||||||
else:
|
|
||||||
op = row.operator("bim.enable_editing_cost_item_value", text="", icon="GREASEPENCIL")
|
|
||||||
op.cost_value = cost_value_id
|
|
||||||
op = row.operator("bim.remove_cost_item_value", text="", icon="X")
|
|
||||||
op.cost_value = cost_value_id
|
|
||||||
|
|
||||||
if self.props.active_cost_item_value_id and self.props.active_cost_item_value_id == cost_value_id:
|
if self.props.active_cost_item_value_id:
|
||||||
box = self.layout.box()
|
box = self.layout.box()
|
||||||
self.draw_editable_cost_item_value_ui(box)
|
self.draw_editable_cost_value_ui(box, Data.cost_values[self.props.active_cost_item_value_id])
|
||||||
|
|
||||||
def draw_editable_cost_item_value_ui(self, layout):
|
|
||||||
|
def draw_readonly_cost_value_ui(self, layout, cost_value_id):
|
||||||
|
cost_value = Data.cost_values[cost_value_id]
|
||||||
|
row = layout.row(align=True)
|
||||||
|
row.label(text=str(cost_value["Category"]), icon="DISC")
|
||||||
|
row.label(text=str(cost_value["AppliedValue"]))
|
||||||
|
if self.props.active_cost_item_value_id and self.props.active_cost_item_value_id == cost_value_id:
|
||||||
|
op = row.operator("bim.edit_cost_value", text="", icon="CHECKMARK")
|
||||||
|
op.cost_value = cost_value_id
|
||||||
|
op = row.operator("bim.add_cost_value", text="", icon="ADD")
|
||||||
|
op.parent = cost_value_id
|
||||||
|
op.cost_type = self.props.cost_types
|
||||||
|
if self.props.cost_types == "CATEGORY":
|
||||||
|
op.cost_category = self.props.cost_category
|
||||||
|
row.operator("bim.disable_editing_cost_item_value", text="", icon="CANCEL")
|
||||||
|
elif self.props.active_cost_item_value_id:
|
||||||
|
op = row.operator("bim.add_cost_value", text="", icon="ADD")
|
||||||
|
op.parent = cost_value_id
|
||||||
|
op.cost_type = self.props.cost_types
|
||||||
|
if self.props.cost_types == "CATEGORY":
|
||||||
|
op.cost_category = self.props.cost_category
|
||||||
|
op = row.operator("bim.remove_cost_item_value", text="", icon="X")
|
||||||
|
op.cost_value = cost_value_id
|
||||||
|
else:
|
||||||
|
op = row.operator("bim.enable_editing_cost_item_value", text="", icon="GREASEPENCIL")
|
||||||
|
op.cost_value = cost_value_id
|
||||||
|
op = row.operator("bim.add_cost_value", text="", icon="ADD")
|
||||||
|
op.parent = cost_value_id
|
||||||
|
op.cost_type = self.props.cost_types
|
||||||
|
if self.props.cost_types == "CATEGORY":
|
||||||
|
op.cost_category = self.props.cost_category
|
||||||
|
op = row.operator("bim.remove_cost_item_value", text="", icon="X")
|
||||||
|
op.cost_value = cost_value_id
|
||||||
|
|
||||||
|
if len(cost_value["Components"]):
|
||||||
|
box = layout.box()
|
||||||
|
for component_id in cost_value["Components"]:
|
||||||
|
self.draw_readonly_cost_value_ui(box, component_id)
|
||||||
|
|
||||||
|
def draw_editable_cost_value_ui(self, layout, cost_value):
|
||||||
for attribute in self.props.cost_value_attributes:
|
for attribute in self.props.cost_value_attributes:
|
||||||
row = layout.row(align=True)
|
row = layout.row(align=True)
|
||||||
if attribute.data_type == "string":
|
if attribute.data_type == "string":
|
||||||
@@ -194,6 +218,7 @@ class BIM_PT_cost_schedules(Panel):
|
|||||||
row.prop(attribute, "is_null", icon="RADIOBUT_OFF" if attribute.is_null else "RADIOBUT_ON", text="")
|
row.prop(attribute, "is_null", icon="RADIOBUT_OFF" if attribute.is_null else "RADIOBUT_ON", text="")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class BIM_UL_cost_items(UIList):
|
class BIM_UL_cost_items(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):
|
||||||
if item:
|
if item:
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
import ifcopenshell.api
|
|
||||||
|
|
||||||
|
|
||||||
class Usecase:
|
|
||||||
def __init__(self, file, **settings):
|
|
||||||
self.file = file
|
|
||||||
self.settings = {"cost_item": None, "ifc_class": "IfcQuantityCount"}
|
|
||||||
for key, value in settings.items():
|
|
||||||
self.settings[key] = value
|
|
||||||
|
|
||||||
def execute(self):
|
|
||||||
value = self.file.create_entity("IfcCostValue")
|
|
||||||
values = list(self.settings["cost_item"].CostValues or [])
|
|
||||||
values.append(value)
|
|
||||||
self.settings["cost_item"].CostValues = values
|
|
||||||
return value
|
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
class Usecase:
|
||||||
|
def __init__(self, file, **settings):
|
||||||
|
self.file = file
|
||||||
|
self.settings = {"parent": None}
|
||||||
|
for key, value in settings.items():
|
||||||
|
self.settings[key] = value
|
||||||
|
|
||||||
|
def execute(self):
|
||||||
|
value = self.file.create_entity("IfcCostValue")
|
||||||
|
if self.settings["parent"].is_a("IfcCostItem"):
|
||||||
|
values = list(self.settings["parent"].CostValues or [])
|
||||||
|
values.append(value)
|
||||||
|
self.settings["parent"].CostValues = values
|
||||||
|
elif self.settings["parent"].is_a("IfcCostValue"):
|
||||||
|
values = list(self.settings["parent"].Components or [])
|
||||||
|
values.append(value)
|
||||||
|
self.settings["parent"].Components = values
|
||||||
|
return value
|
||||||
@@ -87,12 +87,31 @@ class Data:
|
|||||||
value_data["Components"] = [c.id() for c in value_data["Components"] or []]
|
value_data["Components"] = [c.id() for c in value_data["Components"] or []]
|
||||||
value_data["AppliedValue"] = cls.calculate_applied_value(cost_item, cost_value)
|
value_data["AppliedValue"] = cls.calculate_applied_value(cost_item, cost_value)
|
||||||
cls.cost_values[cost_value.id()] = value_data
|
cls.cost_values[cost_value.id()] = value_data
|
||||||
|
for component in cost_value.Components or []:
|
||||||
|
cls.load_cost_item_value(cost_item, component)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def calculate_applied_value(cls, cost_item, cost_value, category_filter=None):
|
def calculate_applied_value(cls, cost_item, cost_value, category_filter=None):
|
||||||
result = 0
|
|
||||||
if cost_value.ArithmeticOperator and cost_value.Components:
|
if cost_value.ArithmeticOperator and cost_value.Components:
|
||||||
pass # TODO
|
component_values = []
|
||||||
|
for component in cost_value.Components:
|
||||||
|
component_values.append(cls.calculate_applied_value(cost_item, component, category_filter))
|
||||||
|
if cost_value.ArithmeticOperator == "ADD":
|
||||||
|
return sum(component_values)
|
||||||
|
result = component_values.pop(0)
|
||||||
|
if cost_value.ArithmeticOperator == "DIVIDE":
|
||||||
|
for value in component_values:
|
||||||
|
try:
|
||||||
|
result /= value
|
||||||
|
except ZeroDivisionError:
|
||||||
|
pass
|
||||||
|
elif cost_value.ArithmeticOperator == "MULTIPLY":
|
||||||
|
for value in component_values:
|
||||||
|
result *= value
|
||||||
|
elif cost_value.ArithmeticOperator == "SUBTRACT":
|
||||||
|
for value in component_values:
|
||||||
|
result -= value
|
||||||
|
return result
|
||||||
if cost_value.Category is None:
|
if cost_value.Category is None:
|
||||||
return cls.get_primitive_applied_value(cost_value.AppliedValue)
|
return cls.get_primitive_applied_value(cost_value.AppliedValue)
|
||||||
elif cost_value.Category == "*":
|
elif cost_value.Category == "*":
|
||||||
@@ -105,7 +124,7 @@ class Data:
|
|||||||
return cls.sum_child_cost_items(cost_item, category_filter=cost_value.Category)
|
return cls.sum_child_cost_items(cost_item, category_filter=cost_value.Category)
|
||||||
else:
|
else:
|
||||||
return cls.get_primitive_applied_value(cost_value.AppliedValue)
|
return cls.get_primitive_applied_value(cost_value.AppliedValue)
|
||||||
return result
|
return 0
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def sum_child_cost_items(cls, cost_item, category_filter=None):
|
def sum_child_cost_items(cls, cost_item, category_filter=None):
|
||||||
|
|||||||
Reference in New Issue
Block a user