mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-11 02:02:22 +00:00
BBIM 5D: Various Cost Schedule UI Improvemements
This commit is contained in:
@@ -71,7 +71,7 @@ class CostSchedulesData:
|
||||
{
|
||||
"id": schedule.id(),
|
||||
"name": schedule.Name or "Unnamed",
|
||||
"predefined_type":ifcopenshell.util.element.get_predefined_type(schedule),
|
||||
"predefined_type": ifcopenshell.util.element.get_predefined_type(schedule),
|
||||
}
|
||||
)
|
||||
return results
|
||||
@@ -109,6 +109,7 @@ class CostSchedulesData:
|
||||
data["UnitBasisUnitSymbol"] = None
|
||||
data["TotalAppliedValue"] = 0.0
|
||||
data["TotalCost"] = 0.0
|
||||
has_unit_basis = False
|
||||
if root_element.is_a("IfcCostItem"):
|
||||
values = root_element.CostValues
|
||||
elif root_element.is_a("IfcConstructionResource"):
|
||||
@@ -121,10 +122,15 @@ class CostSchedulesData:
|
||||
cost_value_data = cls._cost_values[cost_value.id()]
|
||||
data["UnitBasisValueComponent"] = cost_value_data["UnitBasis"]["ValueComponent"]
|
||||
data["UnitBasisUnitSymbol"] = cost_value_data["UnitBasis"]["UnitSymbol"]
|
||||
if data["UnitBasisValueComponent"]:
|
||||
data["TotalCost"] = data["TotalCostQuantity"] / data["UnitBasisValueComponent"] * data["TotalAppliedValue"]
|
||||
has_unit_basis = True
|
||||
if has_unit_basis:
|
||||
data["TotalCost"] = data["TotalAppliedValue"] / data["UnitBasisValueComponent"]
|
||||
else:
|
||||
data["TotalCost"] = data["TotalCostQuantity"] * data["TotalAppliedValue"]
|
||||
if data["TotalCostQuantity"] is not None:
|
||||
data["TotalCost"] = data["TotalAppliedValue"] * data["TotalCostQuantity"]
|
||||
else:
|
||||
data["TotalCost"] = data["TotalAppliedValue"]
|
||||
data["TotalAppliedValue"] = None
|
||||
|
||||
@classmethod
|
||||
def _load_cost_item_quantities(cls, cost_item, data):
|
||||
|
||||
@@ -128,6 +128,8 @@ class CostItemQuantity(PropertyGroup):
|
||||
name: StringProperty(name="Name")
|
||||
ifc_definition_id: IntProperty(name="IFC Definition ID")
|
||||
total_quantity: FloatProperty(name="Total Quantity")
|
||||
unit_symbol: StringProperty(name="Unit Symbol")
|
||||
total_cost_quantity: FloatProperty(name="Total Quantity")
|
||||
|
||||
|
||||
class CostItemType(PropertyGroup):
|
||||
@@ -204,7 +206,7 @@ class BIMCostProperties(PropertyGroup):
|
||||
cost_item_rates: CollectionProperty(name="Cost Item Rates", type=CostItem)
|
||||
active_cost_item_rate_index: IntProperty(name="Active Cost Rate Index")
|
||||
contracted_cost_item_rates: StringProperty(name="Contracted Cost Item Rates", default="[]")
|
||||
product_cost_items: CollectionProperty(name="Product Cost Items", type=CostItem)
|
||||
product_cost_items: CollectionProperty(name="Product Cost Items", type=CostItemQuantity)
|
||||
active_product_cost_item_index: IntProperty(name="Active Product Cost Item Index")
|
||||
enable_reorder: BoolProperty(name="Enable Reorder", default=False)
|
||||
show_nested_elements: BoolProperty(name="Show Nested Tasks", default=False, update=update_active_cost_item_elements)
|
||||
|
||||
@@ -59,7 +59,10 @@ class BIM_PT_cost_schedules(Panel):
|
||||
def draw_cost_schedule_ui(self, cost_schedule):
|
||||
row = self.layout.row(align=True)
|
||||
if self.props.active_cost_schedule_id and self.props.active_cost_schedule_id == cost_schedule["id"]:
|
||||
row.label(text="Currently editing: {}[{}]".format(cost_schedule["name"], cost_schedule["predefined_type"]), icon="LINENUMBERS_ON")
|
||||
row.label(
|
||||
text="Currently editing: {}[{}]".format(cost_schedule["name"], cost_schedule["predefined_type"]),
|
||||
icon="LINENUMBERS_ON",
|
||||
)
|
||||
grid = self.layout.grid_flow(columns=2, even_columns=True)
|
||||
col = grid.column()
|
||||
row1 = col.row(align=True)
|
||||
@@ -85,7 +88,9 @@ class BIM_PT_cost_schedules(Panel):
|
||||
row.operator("bim.edit_cost_schedule", text="", icon="CHECKMARK")
|
||||
row.operator("bim.disable_editing_cost_schedule", text="Disable Editing", icon="CANCEL")
|
||||
else:
|
||||
row.label(text="{}[{}]".format(cost_schedule["name"], cost_schedule["predefined_type"]), icon="LINENUMBERS_ON")
|
||||
row.label(
|
||||
text="{}[{}]".format(cost_schedule["name"], cost_schedule["predefined_type"]), icon="LINENUMBERS_ON"
|
||||
)
|
||||
row.operator("bim.enable_editing_cost_items", text="", icon="OUTLINER").cost_schedule = cost_schedule["id"]
|
||||
row.operator(
|
||||
"bim.enable_editing_cost_schedule_attributes", text="", icon="GREASEPENCIL"
|
||||
@@ -214,6 +219,7 @@ class BIM_PT_cost_schedules(Panel):
|
||||
blenderbim.bim.helper.draw_attributes(self.props.cost_value_attributes, self.layout.box())
|
||||
|
||||
def draw_readonly_cost_value_ui(self, layout, cost_value):
|
||||
print(cost_value)
|
||||
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="")
|
||||
else:
|
||||
@@ -599,7 +605,7 @@ class BIM_UL_cost_items_trait:
|
||||
row.label(text="", icon="DOT")
|
||||
|
||||
def draw_total_cost_column(self, layout, cost_item):
|
||||
layout.label(text="{0:.2f}".format(cost_item["TotalCost"]))
|
||||
layout.label(text="{0:,.2f}".format(cost_item["TotalCost"]).replace(",", " "))
|
||||
|
||||
def draw_quantity_column(self, layout, cost_item):
|
||||
if CostSchedulesData.data["is_editing_rates"]:
|
||||
@@ -608,7 +614,11 @@ class BIM_UL_cost_items_trait:
|
||||
self.draw_total_quantity_column(layout, cost_item)
|
||||
|
||||
def draw_value_column(self, layout, cost_item):
|
||||
text = "{0:.2f}".format(cost_item["TotalAppliedValue"])
|
||||
text = (
|
||||
"{0:,.2f}".format(cost_item["TotalAppliedValue"]).replace(",", " ")
|
||||
if cost_item["TotalAppliedValue"]
|
||||
else "-"
|
||||
)
|
||||
if cost_item["UnitBasisValueComponent"] not in [None, 1]:
|
||||
text += " / {}".format(round(cost_item["UnitBasisValueComponent"], 2))
|
||||
layout.label(text=text)
|
||||
@@ -628,7 +638,12 @@ class BIM_UL_cost_items_trait:
|
||||
op.new_index = cost_item["NestingIndex"] - 1
|
||||
|
||||
def draw_total_quantity_column(self, layout, cost_item):
|
||||
layout.label(text="{0:.2f}".format(cost_item["TotalCostQuantity"]) + f" {cost_item['UnitSymbol'] or '-'}")
|
||||
label = (
|
||||
"{0:.2f}".format(cost_item["TotalCostQuantity"]) + f" {cost_item['UnitSymbol'] or '-'}"
|
||||
if cost_item["TotalCostQuantity"]
|
||||
else "-"
|
||||
)
|
||||
layout.label(text=label)
|
||||
# if cost_item["DerivedTotalCostQuantity"] not in [None, 0]:
|
||||
# layout.label(text="{0:.2f}".format(cost_item["DerivedTotalCostQuantity"]) + f" {cost_item['DerivedUnitSymbol'] or '-'}")
|
||||
# else:
|
||||
@@ -685,14 +700,14 @@ class BIM_UL_cost_item_quantities(UIList):
|
||||
def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
|
||||
props = context.scene.BIMCostProperties
|
||||
cost_item = props.cost_items[props.active_cost_item_index]
|
||||
|
||||
if item:
|
||||
row = layout.row(align=True)
|
||||
op = row.operator("bim.select_product", text="", icon="RESTRICT_SELECT_OFF")
|
||||
op.product = item.ifc_definition_id
|
||||
row.split(factor=0.8)
|
||||
row.label(text=item.name)
|
||||
row.label(text="{0:.2f}".format(item.total_quantity))
|
||||
formatted_quantity = "{0:.2f}".format(item.total_quantity)
|
||||
row.label(text="{}{}".format(formatted_quantity, item.unit_symbol))
|
||||
op = row.operator("bim.unassign_cost_item_quantity", text="", icon="X")
|
||||
op.cost_item = cost_item.ifc_definition_id
|
||||
op.related_object = item.ifc_definition_id
|
||||
@@ -704,8 +719,11 @@ class BIM_UL_product_cost_items(UIList):
|
||||
row = layout.row(align=True)
|
||||
op = row.operator("bim.highlight_product_cost_item", text="", icon="STYLUS_PRESSURE")
|
||||
op.cost_item = item.ifc_definition_id
|
||||
row.split(factor=0.8)
|
||||
row.split(factor=0.5)
|
||||
row.label(text=item.name)
|
||||
qty = "{0:.2f}".format(item.total_quantity)
|
||||
formatted_total_quantity = "{0:.2f}".format(item.total_cost_quantity)
|
||||
row.label(text="{}/{} {}".format(qty, formatted_total_quantity, item.unit_symbol))
|
||||
|
||||
|
||||
class BIM_PT_Costing_Tools(Panel):
|
||||
|
||||
@@ -3,6 +3,7 @@ import bpy
|
||||
import blenderbim.tool as tool
|
||||
import ifcopenshell.util.date
|
||||
import ifcopenshell.util.cost
|
||||
import ifcopenshell.util.unit
|
||||
import blenderbim.bim.helper
|
||||
import json
|
||||
|
||||
@@ -188,8 +189,9 @@ class Cost(blenderbim.core.tool.Cost):
|
||||
new = collection.add()
|
||||
new.ifc_definition_id = product.id()
|
||||
new.name = product.Name or "Unnamed"
|
||||
total_quantity = cls.calculate_parametric_quantity(cost_item, product)
|
||||
new.total_quantity = total_quantity if total_quantity else 1
|
||||
total_quantity, unit = cls.calculate_parametric_quantity(cost_item, product)
|
||||
new.total_quantity = total_quantity or 0
|
||||
new.unit_symbol = unit or ""
|
||||
if is_deep:
|
||||
for cost_item in ifcopenshell.util.cost.get_nested_cost_items(cost_item, is_deep):
|
||||
create_list_items(collection, cost_item, is_deep=False)
|
||||
@@ -210,16 +212,21 @@ class Cost(blenderbim.core.tool.Cost):
|
||||
|
||||
@classmethod
|
||||
def calculate_parametric_quantity(cls, cost_item=None, product=None):
|
||||
if not cost_item.CostQuantities:
|
||||
return
|
||||
total_quantity = sum(
|
||||
quantity[3]
|
||||
for quantities in ifcopenshell.util.element.get_psets(product, qtos_only=True).values()
|
||||
for qto in (tool.Ifc.get().by_id(quantities["id"]).Quantities or [])
|
||||
for quantity in cost_item.CostQuantities
|
||||
if quantity == qto
|
||||
)
|
||||
return total_quantity
|
||||
quantities, unit = cls.get_assigned_quantities(cost_item, product)
|
||||
return sum(quantity[3] for quantity in quantities), unit
|
||||
|
||||
@classmethod
|
||||
def get_assigned_quantities(cls, cost_item, product):
|
||||
selected_quantitites = []
|
||||
unit = ""
|
||||
for quantities in ifcopenshell.util.element.get_psets(product, qtos_only=True).values():
|
||||
for qto in (tool.Ifc.get().by_id(quantities["id"]).Quantities or []):
|
||||
for quantity in cost_item.CostQuantities:
|
||||
if quantity == qto:
|
||||
selected_quantitites.append(quantity)
|
||||
if not unit:
|
||||
unit = cls.get_quantity_unit_symbol(quantity)
|
||||
return selected_quantitites, unit
|
||||
|
||||
@classmethod
|
||||
def get_products(cls, related_object_type=None):
|
||||
@@ -616,6 +623,18 @@ class Cost(blenderbim.core.tool.Cost):
|
||||
new = props.product_cost_items.add()
|
||||
new.name = cost_item.Name or "Unnamed"
|
||||
new.ifc_definition_id = cost_item.id()
|
||||
quantity, unit = cls.calculate_parametric_quantity(cost_item, product)
|
||||
new.total_quantity = quantity or 1
|
||||
new.unit_symbol = unit or ""
|
||||
new.total_cost_quantity = ifcopenshell.util.cost.get_total_quantity(cost_item)
|
||||
|
||||
@classmethod
|
||||
def get_quantity_unit_symbol(cls, quantity):
|
||||
unit = ifcopenshell.util.unit.get_property_unit(quantity, tool.Ifc.get())
|
||||
if unit:
|
||||
return ifcopenshell.util.unit.get_unit_symbol(unit)
|
||||
else:
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
def is_root_cost_item(cls, cost_item):
|
||||
|
||||
@@ -37,7 +37,7 @@ def get_primitive_applied_value(applied_value):
|
||||
|
||||
def get_total_quantity(root_element):
|
||||
if root_element.is_a("IfcCostItem"):
|
||||
return sum([q[3] for q in root_element.CostQuantities or []]) or 1.0
|
||||
return sum([q[3] for q in root_element.CostQuantities or []]) or None
|
||||
elif root_element.is_a("IfcConstructionResource"):
|
||||
return root_element.BaseQuantity[3] if root_element.BaseQuantity else 1.0
|
||||
|
||||
@@ -90,7 +90,7 @@ def sum_child_root_elements(root_element, category_filter=None):
|
||||
if category_filter and child_cost_value.Category != category_filter:
|
||||
continue
|
||||
child_applied_value = calculate_applied_value(child_root_element, child_cost_value)
|
||||
child_quantity = get_total_quantity(child_root_element)
|
||||
child_quantity = get_total_quantity(child_root_element) or 1.0
|
||||
if child_cost_value.UnitBasis:
|
||||
value_component = child_cost_value.UnitBasis.ValueComponent.wrappedValue
|
||||
result += child_quantity / value_component * child_applied_value
|
||||
|
||||
Reference in New Issue
Block a user