mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-09 09:21:46 +00:00
Resource base costs are now supported with all the features coming from the cost module.
This commit is contained in:
@@ -26,8 +26,8 @@ classes = (
|
|||||||
operator.EditCostSchedule,
|
operator.EditCostSchedule,
|
||||||
operator.EditCostItem,
|
operator.EditCostItem,
|
||||||
operator.EditCostItemQuantity,
|
operator.EditCostItemQuantity,
|
||||||
operator.EditCostValue,
|
operator.EditCostItemValue,
|
||||||
operator.EditCostValueFormula,
|
operator.EditCostItemValueFormula,
|
||||||
operator.EnableEditingCostSchedule,
|
operator.EnableEditingCostSchedule,
|
||||||
operator.EnableEditingCostItems,
|
operator.EnableEditingCostItems,
|
||||||
operator.EnableEditingCostItem,
|
operator.EnableEditingCostItem,
|
||||||
|
|||||||
@@ -27,6 +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
|
||||||
|
|
||||||
|
|
||||||
class AddCostSchedule(bpy.types.Operator):
|
class AddCostSchedule(bpy.types.Operator):
|
||||||
@@ -590,6 +591,7 @@ class AddCostValue(bpy.types.Operator):
|
|||||||
|
|
||||||
def _execute(self, context):
|
def _execute(self, context):
|
||||||
self.file = IfcStore.get_file()
|
self.file = IfcStore.get_file()
|
||||||
|
parent = self.file.by_id(self.parent)
|
||||||
if self.cost_type == "FIXED":
|
if self.cost_type == "FIXED":
|
||||||
category = None
|
category = None
|
||||||
attributes = {"AppliedValue": 0.0}
|
attributes = {"AppliedValue": 0.0}
|
||||||
@@ -599,14 +601,17 @@ class AddCostValue(bpy.types.Operator):
|
|||||||
elif self.cost_type == "CATEGORY":
|
elif self.cost_type == "CATEGORY":
|
||||||
category = self.cost_category
|
category = self.cost_category
|
||||||
attributes = {"Category": category}
|
attributes = {"Category": category}
|
||||||
value = ifcopenshell.api.run("cost.add_cost_value", self.file, parent=self.file.by_id(self.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)
|
||||||
Data.load(self.file)
|
if parent.is_a("IfcConstructionResource"):
|
||||||
|
ResourceData.load(self.file)
|
||||||
|
else:
|
||||||
|
Data.load(self.file)
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
class RemoveCostItemValue(bpy.types.Operator):
|
class RemoveCostItemValue(bpy.types.Operator):
|
||||||
bl_idname = "bim.remove_cost_item_value"
|
bl_idname = "bim.remove_cost_value"
|
||||||
bl_label = "Add Cost Item Value"
|
bl_label = "Add Cost Item Value"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
parent: bpy.props.IntProperty()
|
parent: bpy.props.IntProperty()
|
||||||
@@ -617,13 +622,17 @@ class RemoveCostItemValue(bpy.types.Operator):
|
|||||||
|
|
||||||
def _execute(self, context):
|
def _execute(self, context):
|
||||||
self.file = IfcStore.get_file()
|
self.file = IfcStore.get_file()
|
||||||
|
parent = self.file.by_id(self.parent)
|
||||||
ifcopenshell.api.run(
|
ifcopenshell.api.run(
|
||||||
"cost.remove_cost_item_value",
|
"cost.remove_cost_value",
|
||||||
self.file,
|
self.file,
|
||||||
parent=self.file.by_id(self.parent),
|
parent=parent,
|
||||||
cost_value=self.file.by_id(self.cost_value),
|
cost_value=self.file.by_id(self.cost_value),
|
||||||
)
|
)
|
||||||
Data.load(self.file)
|
if parent.is_a("IfcConstructionResource"):
|
||||||
|
ResourceData.load(self.file)
|
||||||
|
else:
|
||||||
|
Data.load(self.file)
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
@@ -636,7 +645,7 @@ class EnableEditingCostItemValue(bpy.types.Operator):
|
|||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
self.props = context.scene.BIMCostProperties
|
self.props = context.scene.BIMCostProperties
|
||||||
self.props.cost_value_attributes.clear()
|
self.props.cost_value_attributes.clear()
|
||||||
self.props.active_cost_item_value_id = self.cost_value
|
self.props.active_cost_value_id = self.cost_value
|
||||||
self.props.cost_value_editing_type = "ATTRIBUTES"
|
self.props.cost_value_editing_type = "ATTRIBUTES"
|
||||||
data = Data.cost_values[self.cost_value]
|
data = Data.cost_values[self.cost_value]
|
||||||
|
|
||||||
@@ -706,7 +715,7 @@ class DisableEditingCostItemValue(bpy.types.Operator):
|
|||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
props = context.scene.BIMCostProperties
|
props = context.scene.BIMCostProperties
|
||||||
props.active_cost_item_value_id = 0
|
props.active_cost_value_id = 0
|
||||||
props.cost_value_editing_type = ""
|
props.cost_value_editing_type = ""
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
@@ -720,13 +729,13 @@ class EnableEditingCostItemValueFormula(bpy.types.Operator):
|
|||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
self.props = context.scene.BIMCostProperties
|
self.props = context.scene.BIMCostProperties
|
||||||
self.props.cost_value_attributes.clear()
|
self.props.cost_value_attributes.clear()
|
||||||
self.props.active_cost_item_value_id = self.cost_value
|
self.props.active_cost_value_id = self.cost_value
|
||||||
self.props.cost_value_editing_type = "FORMULA"
|
self.props.cost_value_editing_type = "FORMULA"
|
||||||
self.props.cost_value_formula = Data.cost_values[self.cost_value]["Formula"]
|
self.props.cost_value_formula = Data.cost_values[self.cost_value]["Formula"]
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
class EditCostValueFormula(bpy.types.Operator):
|
class EditCostItemValueFormula(bpy.types.Operator):
|
||||||
bl_idname = "bim.edit_cost_value_formula"
|
bl_idname = "bim.edit_cost_value_formula"
|
||||||
bl_label = "Edit Cost Value Formula"
|
bl_label = "Edit Cost Value Formula"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
@@ -748,7 +757,7 @@ class EditCostValueFormula(bpy.types.Operator):
|
|||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
class EditCostValue(bpy.types.Operator):
|
class EditCostItemValue(bpy.types.Operator):
|
||||||
bl_idname = "bim.edit_cost_value"
|
bl_idname = "bim.edit_cost_value"
|
||||||
bl_label = "Edit Cost Value"
|
bl_label = "Edit Cost Value"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
|||||||
@@ -244,7 +244,7 @@ class BIMCostProperties(PropertyGroup):
|
|||||||
name="Cost Types",
|
name="Cost Types",
|
||||||
)
|
)
|
||||||
cost_category: StringProperty(name="Cost Category")
|
cost_category: StringProperty(name="Cost Category")
|
||||||
active_cost_item_value_id: IntProperty(name="Active Cost Item Value Id")
|
active_cost_value_id: IntProperty(name="Active Cost Item Value Id")
|
||||||
cost_value_editing_type: StringProperty(name="Cost Value Editing Type")
|
cost_value_editing_type: StringProperty(name="Cost Value Editing Type")
|
||||||
cost_value_attributes: CollectionProperty(name="Cost Value Attributes", type=Attribute)
|
cost_value_attributes: CollectionProperty(name="Cost Value Attributes", type=Attribute)
|
||||||
cost_value_formula: StringProperty(name="Cost Value Formula")
|
cost_value_formula: StringProperty(name="Cost Value Formula")
|
||||||
|
|||||||
@@ -16,10 +16,10 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# 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/>.
|
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import blenderbim.bim.helper
|
||||||
import blenderbim.bim.module.cost.prop as CostProp
|
import blenderbim.bim.module.cost.prop as CostProp
|
||||||
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 blenderbim.bim.helper import draw_attributes
|
|
||||||
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
|
||||||
|
|
||||||
@@ -94,7 +94,7 @@ class BIM_PT_cost_schedules(Panel):
|
|||||||
self.layout.template_list("BIM_UL_cost_columns", "", self.props, "columns", self.props, "active_column_index")
|
self.layout.template_list("BIM_UL_cost_columns", "", self.props, "columns", self.props, "active_column_index")
|
||||||
|
|
||||||
def draw_editable_cost_schedule_ui(self):
|
def draw_editable_cost_schedule_ui(self):
|
||||||
draw_attributes(self.props.cost_schedule_attributes, self.layout)
|
blenderbim.bim.helper.draw_attributes(self.props.cost_schedule_attributes, self.layout)
|
||||||
|
|
||||||
def draw_editable_cost_item_ui(self, cost_schedule_id):
|
def draw_editable_cost_item_ui(self, cost_schedule_id):
|
||||||
row = self.layout.row(align=True)
|
row = self.layout.row(align=True)
|
||||||
@@ -140,7 +140,7 @@ class BIM_PT_cost_schedules(Panel):
|
|||||||
self.draw_editable_cost_item_values_ui()
|
self.draw_editable_cost_item_values_ui()
|
||||||
|
|
||||||
def draw_editable_cost_item_attributes_ui(self):
|
def draw_editable_cost_item_attributes_ui(self):
|
||||||
draw_attributes(self.props.cost_item_attributes, self.layout)
|
blenderbim.bim.helper.draw_attributes(self.props.cost_item_attributes, self.layout)
|
||||||
|
|
||||||
def draw_editable_cost_item_quantities_ui(self):
|
def draw_editable_cost_item_quantities_ui(self):
|
||||||
row = self.layout.row(align=True)
|
row = self.layout.row(align=True)
|
||||||
@@ -175,7 +175,7 @@ class BIM_PT_cost_schedules(Panel):
|
|||||||
self.draw_editable_cost_item_quantity_ui(box)
|
self.draw_editable_cost_item_quantity_ui(box)
|
||||||
|
|
||||||
def draw_editable_cost_item_quantity_ui(self, layout):
|
def draw_editable_cost_item_quantity_ui(self, layout):
|
||||||
draw_attributes(self.props.quantity_attributes, self.layout)
|
blenderbim.bim.helper.draw_attributes(self.props.quantity_attributes, self.layout)
|
||||||
|
|
||||||
def draw_editable_cost_item_values_ui(self):
|
def draw_editable_cost_item_values_ui(self):
|
||||||
row = self.layout.row(align=True)
|
row = self.layout.row(align=True)
|
||||||
@@ -194,12 +194,12 @@ class BIM_PT_cost_schedules(Panel):
|
|||||||
|
|
||||||
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_item_value_id])
|
self.draw_editable_cost_value_ui(box, Data.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 = Data.cost_values[cost_value_id]
|
||||||
|
|
||||||
if self.props.active_cost_item_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="")
|
||||||
else:
|
else:
|
||||||
cost_value_label = "{0:.2f}".format(cost_value["AppliedValue"])
|
cost_value_label = "{0:.2f}".format(cost_value["AppliedValue"])
|
||||||
@@ -209,16 +209,16 @@ class BIM_PT_cost_schedules(Panel):
|
|||||||
self.draw_cost_value_operator_ui(layout, cost_value_id, self.props.active_cost_item_id)
|
self.draw_cost_value_operator_ui(layout, cost_value_id, self.props.active_cost_item_id)
|
||||||
|
|
||||||
def draw_cost_value_operator_ui(self, layout, cost_value_id, parent_id):
|
def draw_cost_value_operator_ui(self, layout, cost_value_id, parent_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_value_id and self.props.active_cost_value_id == cost_value_id:
|
||||||
if self.props.cost_value_editing_type == "ATTRIBUTES":
|
if self.props.cost_value_editing_type == "ATTRIBUTES":
|
||||||
op = layout.operator("bim.edit_cost_value", text="", icon="CHECKMARK")
|
op = layout.operator("bim.edit_cost_item_value", text="", icon="CHECKMARK")
|
||||||
op.cost_value = cost_value_id
|
op.cost_value = cost_value_id
|
||||||
elif self.props.cost_value_editing_type == "FORMULA":
|
elif self.props.cost_value_editing_type == "FORMULA":
|
||||||
op = layout.operator("bim.edit_cost_value_formula", text="", icon="CHECKMARK")
|
op = layout.operator("bim.edit_cost_item_value_formula", text="", icon="CHECKMARK")
|
||||||
op.cost_value = cost_value_id
|
op.cost_value = cost_value_id
|
||||||
layout.operator("bim.disable_editing_cost_item_value", text="", icon="CANCEL")
|
layout.operator("bim.disable_editing_cost_item_value", text="", icon="CANCEL")
|
||||||
elif self.props.active_cost_item_value_id:
|
elif self.props.active_cost_value_id:
|
||||||
op = layout.operator("bim.remove_cost_item_value", text="", icon="X")
|
op = layout.operator("bim.remove_cost_value", text="", icon="X")
|
||||||
op.parent = parent_id
|
op.parent = parent_id
|
||||||
op.cost_value = cost_value_id
|
op.cost_value = cost_value_id
|
||||||
else:
|
else:
|
||||||
@@ -226,12 +226,12 @@ class BIM_PT_cost_schedules(Panel):
|
|||||||
op.cost_value = cost_value_id
|
op.cost_value = cost_value_id
|
||||||
op = layout.operator("bim.enable_editing_cost_item_value", text="", icon="GREASEPENCIL")
|
op = layout.operator("bim.enable_editing_cost_item_value", text="", icon="GREASEPENCIL")
|
||||||
op.cost_value = cost_value_id
|
op.cost_value = cost_value_id
|
||||||
op = layout.operator("bim.remove_cost_item_value", text="", icon="X")
|
op = layout.operator("bim.remove_cost_value", text="", icon="X")
|
||||||
op.parent = parent_id
|
op.parent = parent_id
|
||||||
op.cost_value = cost_value_id
|
op.cost_value = cost_value_id
|
||||||
|
|
||||||
def draw_editable_cost_value_ui(self, layout, cost_value):
|
def draw_editable_cost_value_ui(self, layout, cost_value):
|
||||||
draw_attributes(self.props.cost_value_attributes, layout)
|
blenderbim.bim.helper.draw_attributes(self.props.cost_value_attributes, layout)
|
||||||
|
|
||||||
|
|
||||||
class BIM_PT_cost_item_types(Panel):
|
class BIM_PT_cost_item_types(Panel):
|
||||||
|
|||||||
@@ -34,8 +34,14 @@ classes = (
|
|||||||
operator.AssignResource,
|
operator.AssignResource,
|
||||||
operator.UnassignResource,
|
operator.UnassignResource,
|
||||||
operator.EnableEditingResourceTime,
|
operator.EnableEditingResourceTime,
|
||||||
|
operator.EnableEditingResourceCosts,
|
||||||
|
operator.EnableEditingResourceCostValueFormula,
|
||||||
|
operator.EnableEditingResourceCostValue,
|
||||||
operator.EditResourceTime,
|
operator.EditResourceTime,
|
||||||
|
operator.EditResourceCostValue,
|
||||||
|
operator.EditResourceCostValueFormula,
|
||||||
operator.DisableEditingResourceTime,
|
operator.DisableEditingResourceTime,
|
||||||
|
operator.DisableEditingResourceCostValue,
|
||||||
operator.CalculateResourceWork,
|
operator.CalculateResourceWork,
|
||||||
prop.Resource,
|
prop.Resource,
|
||||||
prop.BIMResourceProperties,
|
prop.BIMResourceProperties,
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||||
#
|
#
|
||||||
@@ -19,14 +18,15 @@
|
|||||||
|
|
||||||
import bpy
|
import bpy
|
||||||
import json
|
import json
|
||||||
|
import time
|
||||||
|
import isodate
|
||||||
import ifcopenshell.api
|
import ifcopenshell.api
|
||||||
from blenderbim.bim.ifc import IfcStore
|
|
||||||
from ifcopenshell.api.resource.data import Data
|
|
||||||
import blenderbim.bim.helper
|
import blenderbim.bim.helper
|
||||||
import blenderbim.bim.module.sequence.helper as helper
|
import blenderbim.bim.module.sequence.helper as helper
|
||||||
import time
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import isodate
|
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):
|
||||||
@@ -95,7 +95,6 @@ class EnableEditingResource(bpy.types.Operator):
|
|||||||
new.enum_value = 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"
|
||||||
bl_label = "Load Resource Properties"
|
bl_label = "Load Resource Properties"
|
||||||
@@ -301,7 +300,9 @@ class EnableEditingResourceTime(bpy.types.Operator):
|
|||||||
|
|
||||||
data = Data.resource_times[resource_time_id]
|
data = Data.resource_times[resource_time_id]
|
||||||
|
|
||||||
blenderbim.bim.helper.import_attributes("IfcResourceTime", props.resource_time_attributes, data, self.import_attributes)
|
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_time_id = resource_time_id
|
||||||
props.active_resource_id = self.resource
|
props.active_resource_id = self.resource
|
||||||
props.editing_resource_type = "USAGE"
|
props.editing_resource_type = "USAGE"
|
||||||
@@ -319,7 +320,9 @@ class EnableEditingResourceTime(bpy.types.Operator):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
def add_resource_time(self):
|
def add_resource_time(self):
|
||||||
resource_time = ifcopenshell.api.run("resource.add_resource_time", self.file, resource=self.file.by_id(self.resource))
|
resource_time = ifcopenshell.api.run(
|
||||||
|
"resource.add_resource_time", self.file, resource=self.file.by_id(self.resource)
|
||||||
|
)
|
||||||
Data.load(self.file)
|
Data.load(self.file)
|
||||||
return resource_time
|
return resource_time
|
||||||
|
|
||||||
@@ -345,7 +348,9 @@ class EditResourceTime(bpy.types.Operator):
|
|||||||
|
|
||||||
def _execute(self, context):
|
def _execute(self, context):
|
||||||
self.props = context.scene.BIMResourceProperties
|
self.props = context.scene.BIMResourceProperties
|
||||||
attributes = blenderbim.bim.helper.export_attributes(self.props.resource_time_attributes, self.export_attributes)
|
attributes = blenderbim.bim.helper.export_attributes(
|
||||||
|
self.props.resource_time_attributes, self.export_attributes
|
||||||
|
)
|
||||||
|
|
||||||
self.file = IfcStore.get_file()
|
self.file = IfcStore.get_file()
|
||||||
ifcopenshell.api.run(
|
ifcopenshell.api.run(
|
||||||
@@ -365,7 +370,7 @@ class EditResourceTime(bpy.types.Operator):
|
|||||||
return True
|
return True
|
||||||
attributes[prop.name] = helper.parse_datetime(prop.string_value)
|
attributes[prop.name] = helper.parse_datetime(prop.string_value)
|
||||||
return True
|
return True
|
||||||
elif prop.name =="LevelingDelay" or "Work" in prop.name:
|
elif prop.name == "LevelingDelay" or "Work" in prop.name:
|
||||||
if prop.is_null:
|
if prop.is_null:
|
||||||
attributes[prop.name] = None
|
attributes[prop.name] = None
|
||||||
return True
|
return True
|
||||||
@@ -385,3 +390,186 @@ class CalculateResourceWork(bpy.types.Operator):
|
|||||||
Data.load(self.file)
|
Data.load(self.file)
|
||||||
bpy.ops.bim.load_resources()
|
bpy.ops.bim.load_resources()
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
|
class EnableEditingResourceCosts(bpy.types.Operator):
|
||||||
|
bl_idname = "bim.enable_editing_resource_costs"
|
||||||
|
bl_label = "Enable Editing Resource Costs"
|
||||||
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
resource: bpy.props.IntProperty()
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
props = context.scene.BIMResourceProperties
|
||||||
|
props.active_resource_id = self.resource
|
||||||
|
props.editing_resource_type = "COSTS"
|
||||||
|
bpy.ops.bim.disable_editing_resource_cost_value()
|
||||||
|
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"}
|
||||||
|
|
||||||
|
|
||||||
|
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"}
|
||||||
|
|
||||||
|
|
||||||
|
class EnableEditingResourceCostValueFormula(bpy.types.Operator):
|
||||||
|
bl_idname = "bim.enable_editing_resource_cost_value_formula"
|
||||||
|
bl_label = "Enable Editing Resource Cost Value Formula"
|
||||||
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
cost_value: bpy.props.IntProperty()
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
self.props = context.scene.BIMResourceProperties
|
||||||
|
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"}
|
||||||
|
|
||||||
|
|
||||||
|
class EnableEditingResourceCostValue(bpy.types.Operator):
|
||||||
|
bl_idname = "bim.enable_editing_resource_cost_value"
|
||||||
|
bl_label = "Enable Editing Resource Cost Value"
|
||||||
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
cost_value: bpy.props.IntProperty()
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
self.props = context.scene.BIMResourceProperties
|
||||||
|
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"}
|
||||||
|
|
||||||
|
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()
|
||||||
|
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_label = "Edit Resource Cost Value Formula"
|
||||||
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
cost_value: bpy.props.IntProperty()
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
return IfcStore.execute_ifc_operator(self, context)
|
||||||
|
|
||||||
|
def _execute(self, context):
|
||||||
|
props = context.scene.BIMResourceProperties
|
||||||
|
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):
|
||||||
|
bl_idname = "bim.edit_resource_cost_value"
|
||||||
|
bl_label = "Edit Resource Cost Value"
|
||||||
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
cost_value: bpy.props.IntProperty()
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
return IfcStore.execute_ifc_operator(self, context)
|
||||||
|
|
||||||
|
def _execute(self, context):
|
||||||
|
props = context.scene.BIMResourceProperties
|
||||||
|
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
|
||||||
|
|||||||
@@ -74,3 +74,16 @@ class BIMResourceProperties(PropertyGroup):
|
|||||||
active_resource_time_id: IntProperty(name="Active Resource Usage Id")
|
active_resource_time_id: IntProperty(name="Active Resource Usage Id")
|
||||||
resource_time_attributes: CollectionProperty(name="Resource Usage Attributes", type=Attribute)
|
resource_time_attributes: CollectionProperty(name="Resource Usage Attributes", type=Attribute)
|
||||||
editing_resource_type: StringProperty(name="Editing Resource Type")
|
editing_resource_type: StringProperty(name="Editing Resource Type")
|
||||||
|
cost_types: EnumProperty(
|
||||||
|
items=[
|
||||||
|
("FIXED", "Fixed", "The cost value is a fixed number"),
|
||||||
|
("SUM", "Sum", "The cost value is automatically derived from the sum of all nested cost items"),
|
||||||
|
("CATEGORY", "Category", "The cost value represents a single category"),
|
||||||
|
],
|
||||||
|
name="Cost Types",
|
||||||
|
)
|
||||||
|
cost_category: StringProperty(name="Cost Category")
|
||||||
|
active_cost_value_id: IntProperty(name="Active Resource Cost Value Id")
|
||||||
|
cost_value_editing_type: StringProperty(name="Cost Value Editing Type")
|
||||||
|
cost_value_attributes: CollectionProperty(name="Cost Value Attributes", type=Attribute)
|
||||||
|
cost_value_formula: StringProperty(name="Cost Value Formula")
|
||||||
|
|||||||
@@ -16,10 +16,10 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# 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/>.
|
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
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 ifcopenshell.api.resource.data import Data
|
||||||
import blenderbim.bim.helper
|
|
||||||
|
|
||||||
|
|
||||||
class BIM_PT_resources(Panel):
|
class BIM_PT_resources(Panel):
|
||||||
@@ -61,9 +61,11 @@ class BIM_PT_resources(Panel):
|
|||||||
self.props,
|
self.props,
|
||||||
"active_resource_index",
|
"active_resource_index",
|
||||||
)
|
)
|
||||||
|
|
||||||
if self.props.active_resource_id and self.props.editing_resource_type == "ATTRIBUTES":
|
if self.props.active_resource_id and self.props.editing_resource_type == "ATTRIBUTES":
|
||||||
self.draw_editable_resource_attributes_ui()
|
self.draw_editable_resource_attributes_ui()
|
||||||
|
elif self.props.active_resource_id and self.props.editing_resource_type == "COSTS":
|
||||||
|
self.draw_editable_resource_costs_ui()
|
||||||
elif self.props.active_resource_id and self.props.editing_resource_type == "USAGE":
|
elif self.props.active_resource_id and self.props.editing_resource_type == "USAGE":
|
||||||
self.draw_editable_resource_time_attributes_ui()
|
self.draw_editable_resource_time_attributes_ui()
|
||||||
|
|
||||||
@@ -107,6 +109,8 @@ class BIM_PT_resources(Panel):
|
|||||||
elif self.props.active_resource_id == ifc_definition_id and self.props.editing_resource_type == "USAGE":
|
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.edit_resource_time", text="", icon="CHECKMARK")
|
||||||
row.operator("bim.disable_editing_resource_time", text="", icon="CANCEL")
|
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:
|
elif self.props.active_resource_id:
|
||||||
row.operator("bim.add_resource", text="", icon="ADD").resource = ifc_definition_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
|
row.operator("bim.remove_resource", text="", icon="X").resource = ifc_definition_id
|
||||||
@@ -115,6 +119,8 @@ class BIM_PT_resources(Panel):
|
|||||||
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
|
||||||
row.operator("bim.enable_editing_resource_time", text="", icon="TIME").resource = ifc_definition_id
|
row.operator("bim.enable_editing_resource_time", text="", icon="TIME").resource = ifc_definition_id
|
||||||
|
op = row.operator("bim.enable_editing_resource_costs", text="", icon="DISC")
|
||||||
|
op.resource = ifc_definition_id
|
||||||
row.operator("bim.enable_editing_resource", text="", icon="GREASEPENCIL").resource = ifc_definition_id
|
row.operator("bim.enable_editing_resource", text="", icon="GREASEPENCIL").resource = ifc_definition_id
|
||||||
row.operator("bim.remove_resource", text="", icon="X").resource = ifc_definition_id
|
row.operator("bim.remove_resource", text="", icon="X").resource = ifc_definition_id
|
||||||
|
|
||||||
@@ -124,6 +130,62 @@ class BIM_PT_resources(Panel):
|
|||||||
def draw_editable_resource_time_attributes_ui(self):
|
def draw_editable_resource_time_attributes_ui(self):
|
||||||
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_costs_ui(self):
|
||||||
|
row = self.layout.row(align=True)
|
||||||
|
row.prop(self.props, "cost_types", text="")
|
||||||
|
if self.props.cost_types == "CATEGORY":
|
||||||
|
row.prop(self.props, "cost_category", text="")
|
||||||
|
op = row.operator("bim.add_cost_value", text="", icon="ADD")
|
||||||
|
op.parent = self.props.active_resource_id
|
||||||
|
op.cost_type = self.props.cost_types
|
||||||
|
if self.props.cost_types == "CATEGORY":
|
||||||
|
op.cost_category = self.props.cost_category
|
||||||
|
|
||||||
|
for cost_value_id in Data.resources[self.props.active_resource_id]["BaseCosts"] or []:
|
||||||
|
row = self.layout.row(align=True)
|
||||||
|
self.draw_readonly_cost_value_ui(row, cost_value_id)
|
||||||
|
|
||||||
|
if self.props.cost_value_editing_type == "ATTRIBUTES":
|
||||||
|
box = self.layout.box()
|
||||||
|
self.draw_editable_cost_value_ui(box, Data.cost_values[self.props.active_cost_value_id])
|
||||||
|
|
||||||
|
def draw_readonly_cost_value_ui(self, layout, cost_value_id):
|
||||||
|
cost_value = Data.cost_values[cost_value_id]
|
||||||
|
|
||||||
|
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:
|
||||||
|
cost_value_label = "{0:.2f}".format(cost_value["AppliedValue"])
|
||||||
|
cost_value_label += " = " + cost_value["Formula"]
|
||||||
|
layout.label(text=cost_value_label, icon="DISC")
|
||||||
|
|
||||||
|
self.draw_cost_value_operator_ui(layout, cost_value_id, self.props.active_resource_id)
|
||||||
|
|
||||||
|
def draw_cost_value_operator_ui(self, layout, cost_value_id, parent_id):
|
||||||
|
if self.props.active_cost_value_id and self.props.active_cost_value_id == cost_value_id:
|
||||||
|
if self.props.cost_value_editing_type == "ATTRIBUTES":
|
||||||
|
op = layout.operator("bim.edit_resource_cost_value", text="", icon="CHECKMARK")
|
||||||
|
op.cost_value = cost_value_id
|
||||||
|
elif self.props.cost_value_editing_type == "FORMULA":
|
||||||
|
op = layout.operator("bim.edit_resource_cost_value_formula", text="", icon="CHECKMARK")
|
||||||
|
op.cost_value = cost_value_id
|
||||||
|
layout.operator("bim.disable_editing_resource_cost_value", text="", icon="CANCEL")
|
||||||
|
elif self.props.active_cost_value_id:
|
||||||
|
op = layout.operator("bim.remove_cost_value", text="", icon="X")
|
||||||
|
op.parent = parent_id
|
||||||
|
op.cost_value = cost_value_id
|
||||||
|
else:
|
||||||
|
op = layout.operator("bim.enable_editing_resource_cost_value_formula", text="", icon="CON_TRANSLIKE")
|
||||||
|
op.cost_value = cost_value_id
|
||||||
|
op = layout.operator("bim.enable_editing_resource_cost_value", text="", icon="GREASEPENCIL")
|
||||||
|
op.cost_value = cost_value_id
|
||||||
|
op = layout.operator("bim.remove_cost_value", text="", icon="X")
|
||||||
|
op.parent = parent_id
|
||||||
|
op.cost_value = cost_value_id
|
||||||
|
|
||||||
|
def draw_editable_cost_value_ui(self, layout, cost_value):
|
||||||
|
blenderbim.bim.helper.draw_attributes(self.props.cost_value_attributes, layout)
|
||||||
|
|
||||||
|
|
||||||
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):
|
||||||
|
|||||||
@@ -11,6 +11,10 @@ class Usecase:
|
|||||||
values = list(self.settings["parent"].CostValues or [])
|
values = list(self.settings["parent"].CostValues or [])
|
||||||
values.append(value)
|
values.append(value)
|
||||||
self.settings["parent"].CostValues = values
|
self.settings["parent"].CostValues = values
|
||||||
|
elif self.settings["parent"].is_a("IfcConstructionResource"):
|
||||||
|
values = list(self.settings["parent"].BaseCosts or [])
|
||||||
|
values.append(value)
|
||||||
|
self.settings["parent"].BaseCosts = values
|
||||||
elif self.settings["parent"].is_a("IfcCostValue"):
|
elif self.settings["parent"].is_a("IfcCostValue"):
|
||||||
values = list(self.settings["parent"].Components or [])
|
values = list(self.settings["parent"].Components or [])
|
||||||
values.append(value)
|
values.append(value)
|
||||||
|
|||||||
@@ -3,7 +3,137 @@ import ifcopenshell.util.unit
|
|||||||
import ifcopenshell.util.cost
|
import ifcopenshell.util.cost
|
||||||
|
|
||||||
|
|
||||||
class Data:
|
class CostValueTrait:
|
||||||
|
@classmethod
|
||||||
|
def load_cost_values(cls, root_element, data):
|
||||||
|
data["CostValues"] = []
|
||||||
|
data["CategoryValues"] = {}
|
||||||
|
data["UnitBasisValueComponent"] = None
|
||||||
|
data["UnitBasisUnitSymbol"] = None
|
||||||
|
data["TotalAppliedValue"] = 0.0
|
||||||
|
data["TotalCost"] = 0.0
|
||||||
|
if root_element.is_a("IfcCostItem"):
|
||||||
|
values = root_element.CostValues
|
||||||
|
elif root_element.is_a("IfcConstructionResource"):
|
||||||
|
values = root_element.BaseCosts
|
||||||
|
for cost_value in values or []:
|
||||||
|
cls.load_cost_value(root_element, data, cost_value)
|
||||||
|
data["CostValues"].append(cost_value.id())
|
||||||
|
data["TotalAppliedValue"] += cls.cost_values[cost_value.id()]["AppliedValue"]
|
||||||
|
if cost_value.UnitBasis:
|
||||||
|
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"]
|
||||||
|
else:
|
||||||
|
data["TotalCost"] = data["TotalCostQuantity"] * data["TotalAppliedValue"]
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def load_cost_value(cls, root_element, root_element_data, cost_value):
|
||||||
|
value_data = cost_value.get_info()
|
||||||
|
del value_data["AppliedValue"]
|
||||||
|
if value_data["UnitBasis"]:
|
||||||
|
data = cost_value.UnitBasis.get_info()
|
||||||
|
data["ValueComponent"] = data["ValueComponent"].wrappedValue
|
||||||
|
data["UnitComponent"] = data["UnitComponent"].id()
|
||||||
|
data["UnitSymbol"] = ifcopenshell.util.unit.get_unit_symbol(cost_value.UnitBasis.UnitComponent)
|
||||||
|
value_data["UnitBasis"] = data
|
||||||
|
if value_data["ApplicableDate"]:
|
||||||
|
value_data["ApplicableDate"] = ifcopenshell.util.date.ifc2datetime(value_data["ApplicableDate"])
|
||||||
|
if value_data["FixedUntilDate"]:
|
||||||
|
value_data["FixedUntilDate"] = ifcopenshell.util.date.ifc2datetime(value_data["FixedUntilDate"])
|
||||||
|
value_data["Components"] = [c.id() for c in value_data["Components"] or []]
|
||||||
|
value_data["AppliedValue"] = cls.calculate_applied_value(root_element, cost_value)
|
||||||
|
|
||||||
|
if cost_value.Category not in [None, "*"]:
|
||||||
|
root_element_data["CategoryValues"].setdefault(cost_value.Category, 0)
|
||||||
|
root_element_data["CategoryValues"][cost_value.Category] += value_data["AppliedValue"]
|
||||||
|
|
||||||
|
value_data["Formula"] = ifcopenshell.util.cost.serialise_cost_value(cost_value)
|
||||||
|
|
||||||
|
cls.cost_values[cost_value.id()] = value_data
|
||||||
|
for component in cost_value.Components or []:
|
||||||
|
cls.load_cost_value(root_element, root_element_data, component)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def calculate_applied_value(cls, root_element, cost_value, category_filter=None):
|
||||||
|
if cost_value.ArithmeticOperator and cost_value.Components:
|
||||||
|
component_values = []
|
||||||
|
for component in cost_value.Components:
|
||||||
|
component_values.append(cls.calculate_applied_value(root_element, 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:
|
||||||
|
return cls.get_primitive_applied_value(cost_value.AppliedValue)
|
||||||
|
elif cost_value.Category == "*":
|
||||||
|
if root_element.IsNestedBy:
|
||||||
|
return cls.sum_child_root_elements(root_element)
|
||||||
|
else:
|
||||||
|
return cls.get_primitive_applied_value(cost_value.AppliedValue)
|
||||||
|
elif cost_value.Category:
|
||||||
|
if root_element.IsNestedBy:
|
||||||
|
return cls.sum_child_root_elements(root_element, category_filter=cost_value.Category)
|
||||||
|
else:
|
||||||
|
return cls.get_primitive_applied_value(cost_value.AppliedValue)
|
||||||
|
return 0
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def sum_child_root_elements(cls, root_element, category_filter=None):
|
||||||
|
result = 0
|
||||||
|
for rel in root_element.IsNestedBy:
|
||||||
|
for child_root_element in rel.RelatedObjects:
|
||||||
|
if root_element.is_a("IfcCostItem"):
|
||||||
|
values = child_root_element.CostValues
|
||||||
|
elif root_element.is_a("IfcConstructionResource"):
|
||||||
|
values = child_root_element.BaseCosts
|
||||||
|
for child_cost_value in values or []:
|
||||||
|
if category_filter and child_cost_value.Category != category_filter:
|
||||||
|
continue
|
||||||
|
child_applied_value = cls.calculate_applied_value(child_root_element, child_cost_value)
|
||||||
|
child_quantity = cls.get_total_quantity(child_root_element)
|
||||||
|
if child_cost_value.UnitBasis:
|
||||||
|
value_component = child_cost_value.UnitBasis.ValueComponent.wrappedValue
|
||||||
|
result += child_quantity / value_component * child_applied_value
|
||||||
|
else:
|
||||||
|
result += child_quantity * child_applied_value
|
||||||
|
return result
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_total_quantity(cls, root_element):
|
||||||
|
if root_element.is_a("IfcCostItem"):
|
||||||
|
return sum([q[3] for q in root_element.CostQuantities or []]) or 1.0
|
||||||
|
elif root_element.is_a("IfcConstructionResource"):
|
||||||
|
return root_element.BaseQuantity[3] if root_element.BaseQuantity else 1.0
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_primitive_applied_value(cls, applied_value):
|
||||||
|
if not applied_value:
|
||||||
|
return 0.0
|
||||||
|
elif isinstance(applied_value, float):
|
||||||
|
return applied_value
|
||||||
|
elif hasattr(applied_value, "wrappedValue") and isinstance(applied_value.wrappedValue, float):
|
||||||
|
return applied_value.wrappedValue
|
||||||
|
elif applied_value.is_a("IfcMeasureWithUnit"):
|
||||||
|
return applied_value.ValueComponent
|
||||||
|
assert False, "Applied value {applied_value} not implemented"
|
||||||
|
|
||||||
|
|
||||||
|
class Data(CostValueTrait):
|
||||||
is_loaded = False
|
is_loaded = False
|
||||||
cost_schedules = {}
|
cost_schedules = {}
|
||||||
cost_items = {}
|
cost_items = {}
|
||||||
@@ -63,7 +193,7 @@ class Data:
|
|||||||
parametric_quantities.extend(quantities)
|
parametric_quantities.extend(quantities)
|
||||||
cls.cost_items[cost_item.id()] = data
|
cls.cost_items[cost_item.id()] = data
|
||||||
cls.load_cost_item_quantities(cost_item, data, parametric_quantities)
|
cls.load_cost_item_quantities(cost_item, data, parametric_quantities)
|
||||||
cls.load_cost_item_values(cost_item, data)
|
cls.load_cost_values(cost_item, data)
|
||||||
cls.is_loaded = True
|
cls.is_loaded = True
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@@ -104,122 +234,3 @@ class Data:
|
|||||||
else:
|
else:
|
||||||
data["Unit"] = None
|
data["Unit"] = None
|
||||||
data["UnitSymbol"] = None
|
data["UnitSymbol"] = None
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def load_cost_item_values(cls, cost_item, data):
|
|
||||||
data["CostValues"] = []
|
|
||||||
data["CategoryValues"] = {}
|
|
||||||
data["UnitBasisValueComponent"] = None
|
|
||||||
data["UnitBasisUnitSymbol"] = None
|
|
||||||
data["TotalAppliedValue"] = 0.0
|
|
||||||
data["TotalCost"] = 0.0
|
|
||||||
for cost_value in cost_item.CostValues or []:
|
|
||||||
cls.load_cost_item_value(cost_item, data, cost_value)
|
|
||||||
data["CostValues"].append(cost_value.id())
|
|
||||||
data["TotalAppliedValue"] += cls.cost_values[cost_value.id()]["AppliedValue"]
|
|
||||||
if cost_value.UnitBasis:
|
|
||||||
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"]
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
data["TotalCost"] = data["TotalCostQuantity"] * data["TotalAppliedValue"]
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def load_cost_item_value(cls, cost_item, cost_item_data, cost_value):
|
|
||||||
value_data = cost_value.get_info()
|
|
||||||
del value_data["AppliedValue"]
|
|
||||||
if value_data["UnitBasis"]:
|
|
||||||
data = cost_value.UnitBasis.get_info()
|
|
||||||
data["ValueComponent"] = data["ValueComponent"].wrappedValue
|
|
||||||
data["UnitComponent"] = data["UnitComponent"].id()
|
|
||||||
data["UnitSymbol"] = ifcopenshell.util.unit.get_unit_symbol(cost_value.UnitBasis.UnitComponent)
|
|
||||||
value_data["UnitBasis"] = data
|
|
||||||
if value_data["ApplicableDate"]:
|
|
||||||
value_data["ApplicableDate"] = ifcopenshell.util.date.ifc2datetime(value_data["ApplicableDate"])
|
|
||||||
if value_data["FixedUntilDate"]:
|
|
||||||
value_data["FixedUntilDate"] = ifcopenshell.util.date.ifc2datetime(value_data["FixedUntilDate"])
|
|
||||||
value_data["Components"] = [c.id() for c in value_data["Components"] or []]
|
|
||||||
value_data["AppliedValue"] = cls.calculate_applied_value(cost_item, cost_value)
|
|
||||||
|
|
||||||
if cost_value.Category not in [None, "*"]:
|
|
||||||
cost_item_data["CategoryValues"].setdefault(cost_value.Category, 0)
|
|
||||||
cost_item_data["CategoryValues"][cost_value.Category] += value_data["AppliedValue"]
|
|
||||||
|
|
||||||
value_data["Formula"] = ifcopenshell.util.cost.serialise_cost_value(cost_value)
|
|
||||||
|
|
||||||
cls.cost_values[cost_value.id()] = value_data
|
|
||||||
for component in cost_value.Components or []:
|
|
||||||
cls.load_cost_item_value(cost_item, cost_item_data, component)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def calculate_applied_value(cls, cost_item, cost_value, category_filter=None):
|
|
||||||
if cost_value.ArithmeticOperator and cost_value.Components:
|
|
||||||
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:
|
|
||||||
return cls.get_primitive_applied_value(cost_value.AppliedValue)
|
|
||||||
elif cost_value.Category == "*":
|
|
||||||
if cost_item.IsNestedBy:
|
|
||||||
return cls.sum_child_cost_items(cost_item)
|
|
||||||
else:
|
|
||||||
return cls.get_primitive_applied_value(cost_value.AppliedValue)
|
|
||||||
elif cost_value.Category:
|
|
||||||
if cost_item.IsNestedBy:
|
|
||||||
return cls.sum_child_cost_items(cost_item, category_filter=cost_value.Category)
|
|
||||||
else:
|
|
||||||
return cls.get_primitive_applied_value(cost_value.AppliedValue)
|
|
||||||
return 0
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def sum_child_cost_items(cls, cost_item, category_filter=None):
|
|
||||||
result = 0
|
|
||||||
for rel in cost_item.IsNestedBy:
|
|
||||||
for child_cost_item in rel.RelatedObjects:
|
|
||||||
for child_cost_value in child_cost_item.CostValues or []:
|
|
||||||
if category_filter and child_cost_value.Category != category_filter:
|
|
||||||
continue
|
|
||||||
child_applied_value = cls.calculate_applied_value(child_cost_item, child_cost_value)
|
|
||||||
child_quantity = cls.get_total_quantity(child_cost_item)
|
|
||||||
if child_cost_value.UnitBasis:
|
|
||||||
value_component = child_cost_value.UnitBasis.ValueComponent.wrappedValue
|
|
||||||
result += child_quantity / value_component * child_applied_value
|
|
||||||
else:
|
|
||||||
result += child_quantity * child_applied_value
|
|
||||||
return result
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_total_quantity(cls, cost_item):
|
|
||||||
return sum([q[3] for q in cost_item.CostQuantities or []]) or 1.0
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_primitive_applied_value(cls, applied_value):
|
|
||||||
if not applied_value:
|
|
||||||
return 0.0
|
|
||||||
elif isinstance(applied_value, float):
|
|
||||||
return applied_value
|
|
||||||
elif hasattr(applied_value, "wrappedValue") and isinstance(applied_value.wrappedValue, float):
|
|
||||||
return applied_value.wrappedValue
|
|
||||||
elif applied_value.is_a("IfcMeasureWithUnit"):
|
|
||||||
return applied_value.ValueComponent
|
|
||||||
assert False, "Applied value {applied_value} not implemented"
|
|
||||||
|
|||||||
+4
@@ -13,6 +13,10 @@ class Usecase:
|
|||||||
values = list(self.settings["parent"].CostValues)
|
values = list(self.settings["parent"].CostValues)
|
||||||
values.remove(self.settings["cost_value"])
|
values.remove(self.settings["cost_value"])
|
||||||
self.settings["parent"].CostValues = values if values else None
|
self.settings["parent"].CostValues = values if values else None
|
||||||
|
elif self.settings["parent"].is_a("IfcConstructionResource"):
|
||||||
|
values = list(self.settings["parent"].BaseCosts)
|
||||||
|
values.remove(self.settings["cost_value"])
|
||||||
|
self.settings["parent"].BaseCosts = values if values else None
|
||||||
elif self.settings["parent"].is_a("IfcCostValue"):
|
elif self.settings["parent"].is_a("IfcCostValue"):
|
||||||
components = list(self.settings["parent"].Components)
|
components = list(self.settings["parent"].Components)
|
||||||
components.remove(self.settings["cost_value"])
|
components.remove(self.settings["cost_value"])
|
||||||
@@ -1,17 +1,20 @@
|
|||||||
import ifcopenshell
|
import ifcopenshell
|
||||||
import ifcopenshell.util.date
|
import ifcopenshell.util.date
|
||||||
|
from ifcopenshell.api.cost.data import CostValueTrait
|
||||||
|
|
||||||
|
|
||||||
class Data:
|
class Data(CostValueTrait):
|
||||||
is_loaded = False
|
is_loaded = False
|
||||||
resources = {}
|
resources = {}
|
||||||
resource_times = {}
|
resource_times = {}
|
||||||
|
cost_values = {}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def purge(cls):
|
def purge(cls):
|
||||||
cls.is_loaded = False
|
cls.is_loaded = False
|
||||||
cls.resources = {}
|
cls.resources = {}
|
||||||
cls.resource_times = {}
|
cls.resource_times = {}
|
||||||
|
cls.cost_values = {}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def load(cls, file):
|
def load(cls, file):
|
||||||
@@ -25,6 +28,7 @@ class Data:
|
|||||||
@classmethod
|
@classmethod
|
||||||
def load_resources(cls):
|
def load_resources(cls):
|
||||||
cls.resources = {}
|
cls.resources = {}
|
||||||
|
cls.cost_values = {}
|
||||||
for resource in cls._file.by_type("IfcResource"):
|
for resource in cls._file.by_type("IfcResource"):
|
||||||
data = resource.get_info()
|
data = resource.get_info()
|
||||||
del data["OwnerHistory"]
|
del data["OwnerHistory"]
|
||||||
@@ -40,6 +44,12 @@ class Data:
|
|||||||
data["HasContext"] = resource.HasContext[0].RelatingContext.id() if resource.HasContext else None
|
data["HasContext"] = resource.HasContext[0].RelatingContext.id() if resource.HasContext else None
|
||||||
if resource.Usage:
|
if resource.Usage:
|
||||||
data["Usage"] = data["Usage"].id()
|
data["Usage"] = data["Usage"].id()
|
||||||
|
data["TotalCostQuantity"] = cls.get_total_quantity(resource)
|
||||||
|
if resource.BaseQuantity:
|
||||||
|
data["BaseQuantity"] = resource.BaseQuantity.id()
|
||||||
|
if resource.BaseCosts:
|
||||||
|
data["BaseCosts"] = [e.id() for e in resource.BaseCosts]
|
||||||
|
cls.load_cost_values(resource, data)
|
||||||
cls.resources[resource.id()] = data
|
cls.resources[resource.id()] = data
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|||||||
Reference in New Issue
Block a user