Files
IfcOpenShell/src/blenderbim/blenderbim/bim/module/cost/operator.py
T

986 lines
38 KiB
Python

# BlenderBIM Add-on - OpenBIM Blender Add-on
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
#
# This file is part of BlenderBIM Add-on.
#
# BlenderBIM Add-on is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# BlenderBIM Add-on is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# 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/>.
import os
import bpy
import json
import time
import ifcopenshell.api
import blenderbim.bim.helper
import blenderbim.tool as tool
from blenderbim.bim.ifc import IfcStore
from bpy_extras.io_utils import ImportHelper
class AddCostSchedule(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.add_cost_schedule"
bl_label = "Add Cost Schedule"
bl_options = {"REGISTER", "UNDO"}
def _execute(self, context):
ifcopenshell.api.run("cost.add_cost_schedule", IfcStore.get_file())
return {"FINISHED"}
class EditCostSchedule(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.edit_cost_schedule"
bl_label = "Edit Cost Schedule"
bl_options = {"REGISTER", "UNDO"}
def _execute(self, context):
props = context.scene.BIMCostProperties
attributes = blenderbim.bim.helper.export_attributes(props.cost_schedule_attributes)
self.file = IfcStore.get_file()
ifcopenshell.api.run(
"cost.edit_cost_schedule",
self.file,
**{"cost_schedule": self.file.by_id(props.active_cost_schedule_id), "attributes": attributes},
)
bpy.ops.bim.disable_editing_cost_schedule()
return {"FINISHED"}
class RemoveCostSchedule(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.remove_cost_schedule"
bl_label = "Remove Cost Schedule"
bl_options = {"REGISTER", "UNDO"}
cost_schedule: bpy.props.IntProperty()
def _execute(self, context):
ifcopenshell.api.run(
"cost.remove_cost_schedule",
IfcStore.get_file(),
cost_schedule=IfcStore.get_file().by_id(self.cost_schedule),
)
return {"FINISHED"}
class EnableEditingCostSchedule(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.enable_editing_cost_schedule"
bl_label = "Enable Editing Cost Schedule"
bl_options = {"REGISTER", "UNDO"}
cost_schedule: bpy.props.IntProperty()
def _execute(self, context):
self.props = context.scene.BIMCostProperties
self.props.active_cost_schedule_id = self.cost_schedule
self.props.cost_schedule_attributes.clear()
self.enable_editing_cost_schedule()
self.props.is_editing = "COST_SCHEDULE"
return {"FINISHED"}
def enable_editing_cost_schedule(self):
blenderbim.bim.helper.import_attributes2(
tool.Ifc.get().by_id(self.cost_schedule),
self.props.cost_schedule_attributes,
callback=self.import_attributes,
)
def import_attributes(self, name, prop, data):
if name in ["SubmittedOn", "UpdateDate"]:
prop.string_value = "" if prop.is_null else ifcopenshell.util.date.ifc2datetime(data[name]).isoformat()
return True
class EnableEditingCostItems(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.enable_editing_cost_items"
bl_label = "Enable Editing Cost Items"
bl_options = {"REGISTER", "UNDO"}
cost_schedule: bpy.props.IntProperty()
def _execute(self, context):
if context.preferences.addons["blenderbim"].preferences.should_play_chaching_sound:
self.play_chaching_sound() # lol
self.props = context.scene.BIMCostProperties
self.props.is_cost_update_enabled = False
self.props.active_cost_schedule_id = self.cost_schedule
self.props.cost_items.clear()
self.contracted_cost_items = json.loads(self.props.contracted_cost_items)
for rel in tool.Ifc.get().by_id(self.cost_schedule).Controls or []:
for cost_item in rel.RelatedObjects:
self.create_new_cost_item_li(cost_item, 0)
self.props.is_editing = "COST_ITEMS"
self.props.is_cost_update_enabled = True
return {"FINISHED"}
def play_chaching_sound(self):
# TODO: make pitch higher as costs rise
try:
import aud
device = aud.Device()
# chaching.mp3 is by Lucish_ CC-BY-3.0 https://freesound.org/people/Lucish_/sounds/554841/
sound = aud.Sound(os.path.join(context.scene.BIMProperties.data_dir, "chaching.mp3"))
handle = device.play(sound)
sound_buffered = aud.Sound.buffer(sound)
handle_buffered = device.play(sound_buffered)
handle.stop()
handle_buffered.stop()
except:
pass # ah well
def create_new_cost_item_li(self, cost_item, level_index):
new = self.props.cost_items.add()
new.ifc_definition_id = cost_item.id()
new.name = cost_item.Name or "Unnamed"
new.identification = cost_item.Identification or "XXX"
new.is_expanded = cost_item.id() not in self.contracted_cost_items
new.level_index = level_index
if cost_item.IsNestedBy:
new.has_children = True
if new.is_expanded:
for rel in cost_item.IsNestedBy:
for sub_cost_item in rel.RelatedObjects:
self.create_new_cost_item_li(sub_cost_item, level_index + 1)
class DisableEditingCostSchedule(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.disable_editing_cost_schedule"
bl_label = "Disable Editing Cost Schedule"
bl_options = {"REGISTER", "UNDO"}
def _execute(self, context):
context.scene.BIMCostProperties.active_cost_schedule_id = 0
return {"FINISHED"}
class AddSummaryCostItem(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.add_summary_cost_item"
bl_label = "Add Cost Item"
bl_options = {"REGISTER", "UNDO"}
cost_schedule: bpy.props.IntProperty()
def _execute(self, context):
props = context.scene.BIMCostProperties
self.file = IfcStore.get_file()
ifcopenshell.api.run("cost.add_cost_item", self.file, **{"cost_schedule": self.file.by_id(self.cost_schedule)})
bpy.ops.bim.enable_editing_cost_items(cost_schedule=self.cost_schedule)
return {"FINISHED"}
class AddCostItem(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.add_cost_item"
bl_label = "Add Cost Item"
bl_options = {"REGISTER", "UNDO"}
cost_item: bpy.props.IntProperty()
def _execute(self, context):
props = context.scene.BIMCostProperties
self.file = IfcStore.get_file()
ifcopenshell.api.run("cost.add_cost_item", self.file, **{"cost_item": self.file.by_id(self.cost_item)})
bpy.ops.bim.enable_editing_cost_items(cost_schedule=props.active_cost_schedule_id)
return {"FINISHED"}
class ExpandCostItem(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.expand_cost_item"
bl_label = "Expand Cost Item"
bl_options = {"REGISTER", "UNDO"}
cost_item: bpy.props.IntProperty()
def _execute(self, context):
props = context.scene.BIMCostProperties
self.file = IfcStore.get_file()
contracted_cost_items = json.loads(props.contracted_cost_items)
contracted_cost_items.remove(self.cost_item)
props.contracted_cost_items = json.dumps(contracted_cost_items)
bpy.ops.bim.enable_editing_cost_items(cost_schedule=props.active_cost_schedule_id)
return {"FINISHED"}
class ContractCostItem(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.contract_cost_item"
bl_label = "Contract Cost Item"
bl_options = {"REGISTER", "UNDO"}
cost_item: bpy.props.IntProperty()
def _execute(self, context):
props = context.scene.BIMCostProperties
self.file = IfcStore.get_file()
contracted_cost_items = json.loads(props.contracted_cost_items)
contracted_cost_items.append(self.cost_item)
props.contracted_cost_items = json.dumps(contracted_cost_items)
bpy.ops.bim.enable_editing_cost_items(cost_schedule=props.active_cost_schedule_id)
return {"FINISHED"}
class RemoveCostItem(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.remove_cost_item"
bl_label = "Remove Cost item"
bl_options = {"REGISTER", "UNDO"}
cost_item: bpy.props.IntProperty()
def _execute(self, context):
props = context.scene.BIMCostProperties
self.file = IfcStore.get_file()
ifcopenshell.api.run(
"cost.remove_cost_item",
self.file,
cost_item=self.file.by_id(self.cost_item),
)
contracted_cost_items = json.loads(props.contracted_cost_items)
if props.active_cost_item_index in contracted_cost_items:
contracted_cost_items.remove(props.active_cost_item_index)
props.contracted_cost_items = json.dumps(contracted_cost_items)
bpy.ops.bim.enable_editing_cost_items(cost_schedule=props.active_cost_schedule_id)
if props.active_cost_item_id == self.cost_item:
props.active_cost_item_id = 0
return {"FINISHED"}
class EnableEditingCostItem(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.enable_editing_cost_item"
bl_label = "Enable Editing Cost Item"
bl_options = {"REGISTER", "UNDO"}
cost_item: bpy.props.IntProperty()
def _execute(self, context):
props = context.scene.BIMCostProperties
props.cost_item_attributes.clear()
blenderbim.bim.helper.import_attributes2(tool.Ifc.get().by_id(self.cost_item), props.cost_item_attributes)
props.active_cost_item_id = self.cost_item
props.cost_item_editing_type = "ATTRIBUTES"
return {"FINISHED"}
class DisableEditingCostItem(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.disable_editing_cost_item"
bl_label = "Disable Editing Cost Item"
bl_options = {"REGISTER", "UNDO"}
def _execute(self, context):
context.scene.BIMCostProperties.active_cost_item_id = 0
return {"FINISHED"}
class EditCostItem(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.edit_cost_item"
bl_label = "Edit Cost Item"
bl_options = {"REGISTER", "UNDO"}
def _execute(self, context):
props = context.scene.BIMCostProperties
attributes = blenderbim.bim.helper.export_attributes(props.cost_item_attributes)
self.file = IfcStore.get_file()
ifcopenshell.api.run(
"cost.edit_cost_item",
self.file,
**{"cost_item": self.file.by_id(props.active_cost_item_id), "attributes": attributes},
)
bpy.ops.bim.disable_editing_cost_item()
bpy.ops.bim.enable_editing_cost_items(cost_schedule=props.active_cost_schedule_id)
return {"FINISHED"}
class AssignCostItemType(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.assign_cost_item_type"
bl_label = "Assign Cost Item Type Product"
bl_options = {"REGISTER", "UNDO"}
cost_item: bpy.props.IntProperty()
prop_name: bpy.props.StringProperty()
def _execute(self, context):
self.file = IfcStore.get_file()
cost_item = self.file.by_id(self.cost_item)
for obj in context.selected_objects:
if not obj.BIMObjectProperties.ifc_definition_id:
continue
product = self.file.by_id(obj.BIMObjectProperties.ifc_definition_id)
if product.is_a("IfcTypeProduct"):
ifcopenshell.api.run(
"control.assign_control", self.file, relating_control=cost_item, related_object=product
)
bpy.ops.bim.load_cost_item_types()
return {"FINISHED"}
class UnassignCostItemType(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.unassign_cost_item_type"
bl_label = "Unassign Cost Item Type"
bl_options = {"REGISTER", "UNDO"}
cost_item: bpy.props.IntProperty()
related_object: bpy.props.IntProperty()
def _execute(self, context):
self.file = IfcStore.get_file()
cost_item = self.file.by_id(self.cost_item)
if self.related_object:
products = [self.file.by_id(self.related_object)]
else:
for obj in context.selected_objects:
if not obj.BIMObjectProperties.ifc_definition_id:
continue
product = self.file.by_id(obj.BIMObjectProperties.ifc_definition_id)
if product.is_a("IfcTypeProduct"):
products.append(product)
for product in products:
ifcopenshell.api.run(
"control.unassign_control", self.file, relating_control=cost_item, related_object=product
)
bpy.ops.bim.load_cost_item_types()
return {"FINISHED"}
class AssignCostItemQuantity(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.assign_cost_item_quantity"
bl_label = "Assign Cost Item Quantity"
bl_options = {"REGISTER", "UNDO"}
cost_item: bpy.props.IntProperty()
related_object_type: bpy.props.StringProperty()
prop_name: bpy.props.StringProperty()
def _execute(self, context):
if self.related_object_type == "PRODUCT":
products = [
tool.Ifc.get().by_id(o.BIMObjectProperties.ifc_definition_id)
for o in context.selected_objects
if o.BIMObjectProperties.ifc_definition_id
]
elif self.related_object_type == "PROCESS":
products = [
tool.Ifc.get().by_id(
context.scene.BIMTaskTreeProperties.tasks[
context.scene.BIMWorkScheduleProperties.active_task_index
].ifc_definition_id
)
]
elif self.related_object_type == "RESOURCE":
products = [
tool.Ifc.get().by_id(
context.scene.BIMResourceTreeProperties.resources[
context.scene.BIMResourceProperties.active_resource_index
].ifc_definition_id
)
]
ifcopenshell.api.run(
"cost.assign_cost_item_quantity",
tool.Ifc.get(),
cost_item=tool.Ifc.get().by_id(self.cost_item),
products=products,
prop_name=self.prop_name,
)
bpy.ops.bim.load_cost_item_quantities()
return {"FINISHED"}
class UnassignCostItemQuantity(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.unassign_cost_item_quantity"
bl_label = "Unassign Cost Item Quantity"
bl_options = {"REGISTER", "UNDO"}
cost_item: bpy.props.IntProperty()
related_object: bpy.props.IntProperty()
def _execute(self, context):
self.file = IfcStore.get_file()
if self.related_object:
products = [self.file.by_id(self.related_object)]
else:
products = [
self.file.by_id(o.BIMObjectProperties.ifc_definition_id)
for o in context.selected_objects
if o.BIMObjectProperties.ifc_definition_id
]
ifcopenshell.api.run(
"cost.unassign_cost_item_quantity",
self.file,
cost_item=self.file.by_id(self.cost_item),
products=products,
)
bpy.ops.bim.load_cost_item_quantities()
return {"FINISHED"}
class EnableEditingCostItemQuantities(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.enable_editing_cost_item_quantities"
bl_label = "Enable Editing Cost Item Quantities"
bl_options = {"REGISTER", "UNDO"}
cost_item: bpy.props.IntProperty()
def _execute(self, context):
props = context.scene.BIMCostProperties
props.active_cost_item_id = self.cost_item
props.cost_item_editing_type = "QUANTITIES"
return {"FINISHED"}
class EnableEditingCostItemValues(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.enable_editing_cost_item_values"
bl_label = "Enable Editing Cost Item Values"
bl_options = {"REGISTER", "UNDO"}
cost_item: bpy.props.IntProperty()
def _execute(self, context):
props = context.scene.BIMCostProperties
props.active_cost_item_id = self.cost_item
props.cost_item_editing_type = "VALUES"
bpy.ops.bim.disable_editing_cost_item_value()
return {"FINISHED"}
class AddCostItemQuantity(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.add_cost_item_quantity"
bl_label = "Add Cost Item Quantity"
bl_options = {"REGISTER", "UNDO"}
cost_item: bpy.props.IntProperty()
ifc_class: bpy.props.StringProperty()
def _execute(self, context):
self.file = IfcStore.get_file()
self.props = context.scene.BIMCostProperties
self.add_manual_quantity()
return {"FINISHED"}
def add_manual_quantity(self):
ifcopenshell.api.run(
"cost.add_cost_item_quantity",
self.file,
cost_item=self.file.by_id(self.cost_item),
ifc_class=self.ifc_class,
)
class RemoveCostItemQuantity(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.remove_cost_item_quantity"
bl_label = "Remove Cost Item Quantity"
bl_options = {"REGISTER", "UNDO"}
cost_item: bpy.props.IntProperty()
physical_quantity: bpy.props.IntProperty()
def _execute(self, context):
self.file = IfcStore.get_file()
ifcopenshell.api.run(
"cost.remove_cost_item_quantity",
self.file,
cost_item=self.file.by_id(self.cost_item),
physical_quantity=self.file.by_id(self.physical_quantity),
)
return {"FINISHED"}
class EnableEditingCostItemQuantity(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.enable_editing_cost_item_quantity"
bl_label = "Enable Editing Cost Item Quantity"
bl_options = {"REGISTER", "UNDO"}
physical_quantity: bpy.props.IntProperty()
def _execute(self, context):
self.props = context.scene.BIMCostProperties
self.props.quantity_attributes.clear()
self.props.active_cost_item_quantity_id = self.physical_quantity
blenderbim.bim.helper.import_attributes2(
tool.Ifc.get().by_id(self.physical_quantity), self.props.quantity_attributes
)
return {"FINISHED"}
class DisableEditingCostItemQuantity(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.disable_editing_cost_item_quantity"
bl_label = "Disable Editing Cost Item Quantity"
bl_options = {"REGISTER", "UNDO"}
def _execute(self, context):
props = context.scene.BIMCostProperties
props.active_cost_item_quantity_id = 0
return {"FINISHED"}
class EditCostItemQuantity(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.edit_cost_item_quantity"
bl_label = "Edit Cost Item Quantity"
bl_options = {"REGISTER", "UNDO"}
physical_quantity: bpy.props.IntProperty()
def _execute(self, context):
props = context.scene.BIMCostProperties
attributes = blenderbim.bim.helper.export_attributes(props.quantity_attributes)
self.file = IfcStore.get_file()
ifcopenshell.api.run(
"cost.edit_cost_item_quantity",
self.file,
**{"physical_quantity": self.file.by_id(self.physical_quantity), "attributes": attributes},
)
bpy.ops.bim.disable_editing_cost_item_quantity()
return {"FINISHED"}
class AddCostValue(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.add_cost_value"
bl_label = "Add Cost Value"
bl_options = {"REGISTER", "UNDO"}
parent: bpy.props.IntProperty()
cost_type: bpy.props.StringProperty()
cost_category: bpy.props.StringProperty()
def _execute(self, context):
self.file = IfcStore.get_file()
parent = self.file.by_id(self.parent)
if self.cost_type == "FIXED":
category = None
attributes = {"AppliedValue": 0.0}
elif self.cost_type == "SUM":
category = "*"
attributes = {"Category": category}
elif self.cost_type == "CATEGORY":
category = self.cost_category
attributes = {"Category": category}
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)
return {"FINISHED"}
class RemoveCostItemValue(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.remove_cost_value"
bl_label = "Add Cost Item Value"
bl_options = {"REGISTER", "UNDO"}
parent: bpy.props.IntProperty()
cost_value: bpy.props.IntProperty()
def _execute(self, context):
self.file = IfcStore.get_file()
parent = self.file.by_id(self.parent)
ifcopenshell.api.run(
"cost.remove_cost_value",
self.file,
parent=parent,
cost_value=self.file.by_id(self.cost_value),
)
return {"FINISHED"}
class EnableEditingCostItemValue(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.enable_editing_cost_item_value"
bl_label = "Enable Editing Cost Item Value"
bl_options = {"REGISTER", "UNDO"}
cost_value: bpy.props.IntProperty()
def _execute(self, context):
self.props = context.scene.BIMCostProperties
self.props.cost_value_attributes.clear()
self.props.active_cost_value_id = self.cost_value
self.props.cost_value_editing_type = "ATTRIBUTES"
schedule = tool.Ifc.get().by_id(context.scene.BIMCostProperties.active_cost_schedule_id)
is_rates = schedule.PredefinedType == "SCHEDULEOFRATES"
cost_value = tool.Ifc.get().by_id(self.cost_value)
callback = lambda name, prop, data: self.import_attributes(name, prop, data, cost_value, is_rates)
blenderbim.bim.helper.import_attributes2(cost_value, self.props.cost_value_attributes, callback=callback)
return {"FINISHED"}
def import_attributes(self, name, prop, data, cost_value, is_rates):
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 ifcopenshell.util.cost.calculate_applied_value(
tool.Ifc.get().by_id(self.props.active_cost_item_id), cost_value
)
)
return True
if name == "UnitBasis" and is_rates:
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 in tool.Ifc.get().by_type("IfcNamedUnit"):
if unit.get("UnitType", None) in [
"AREAUNIT",
"LENGTHUNIT",
"TIMEUNIT",
"VOLUMEUNIT",
"MASSUNIT",
"USERDEFINED",
]:
if unit.is_a("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 DisableEditingCostItemValue(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.disable_editing_cost_item_value"
bl_label = "Disable Editing Cost Item Value"
bl_options = {"REGISTER", "UNDO"}
def _execute(self, context):
props = context.scene.BIMCostProperties
props.active_cost_value_id = 0
props.cost_value_editing_type = ""
return {"FINISHED"}
class EnableEditingCostItemValueFormula(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.enable_editing_cost_item_value_formula"
bl_label = "Enable Editing Cost Item Value Formula"
bl_options = {"REGISTER", "UNDO"}
cost_value: bpy.props.IntProperty()
def _execute(self, context):
self.props = context.scene.BIMCostProperties
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 = ifcopenshell.util.cost.serialise_cost_value(
tool.Ifc.get().by_id(self.cost_value)
)
return {"FINISHED"}
class EditCostItemValueFormula(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.edit_cost_value_formula"
bl_label = "Edit Cost Value Formula"
bl_options = {"REGISTER", "UNDO"}
cost_value: bpy.props.IntProperty()
def _execute(self, context):
props = context.scene.BIMCostProperties
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},
)
bpy.ops.bim.disable_editing_cost_item_value()
return {"FINISHED"}
class EditCostItemValue(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.edit_cost_value"
bl_label = "Edit Cost Value"
bl_options = {"REGISTER", "UNDO"}
cost_value: bpy.props.IntProperty()
def _execute(self, context):
props = context.scene.BIMCostProperties
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},
)
bpy.ops.bim.disable_editing_cost_item_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.BIMCostProperties.cost_value_attributes.get("UnitBasisUnit").enum_value)
),
}
return True
if prop.name == "UnitBasisUnit":
return True
class CopyCostItemValues(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.copy_cost_item_values"
bl_label = "Copy Cost Item Values"
bl_options = {"REGISTER", "UNDO"}
source: bpy.props.IntProperty()
destination: bpy.props.IntProperty()
def _execute(self, context):
self.file = IfcStore.get_file()
ifcopenshell.api.run(
"cost.copy_cost_item_values",
self.file,
**{"source": self.file.by_id(self.source), "destination": self.file.by_id(self.destination)},
)
return {"FINISHED"}
class SelectCostItemProducts(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.select_cost_item_products"
bl_label = "Select Cost Item Products"
bl_options = {"REGISTER", "UNDO"}
cost_item: bpy.props.IntProperty()
def _execute(self, context):
related_objects = []
[related_objects.extend(r.RelatedObjects) for r in tool.Ifc.get().by_id(self.cost_item).Controls or []]
related_objects = set([r.id() for r in related_objects])
for obj in context.visible_objects:
obj.select_set(False)
if obj.BIMObjectProperties.ifc_definition_id in related_objects:
obj.select_set(True)
return {"FINISHED"}
class SelectCostScheduleProducts(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.select_cost_schedule_products"
bl_label = "Select Cost Schedule Products"
bl_options = {"REGISTER", "UNDO"}
cost_schedule: bpy.props.IntProperty()
def _execute(self, context):
self.file = IfcStore.get_file()
self.related_products = []
for cost_item in tool.Ifc.get().by_id(self.cost_schedule).Controls or []:
self.get_related_products(cost_item)
self.related_products = set(self.related_products)
for obj in context.visible_objects:
obj.select_set(False)
if obj.BIMObjectProperties.ifc_definition_id in self.related_products:
obj.select_set(True)
return {"FINISHED"}
def get_related_products(self, cost_item):
[self.related_products.extend(r.RelatedObjects) for r in cost_item.Controls or []]
for rel in cost_item.IsNestedBy or []:
for sub_cost_item in rel.RelatedObjects:
self.get_related_products(sub_cost_item)
class ImportCostScheduleCsv(bpy.types.Operator, ImportHelper, tool.Ifc.Operator):
bl_idname = "import_cost_schedule_csv.bim"
bl_label = "Import Cost Schedule CSV"
bl_options = {"REGISTER", "UNDO"}
filename_ext = ".csv"
filter_glob: bpy.props.StringProperty(default="*.csv", options={"HIDDEN"})
is_schedule_of_rates: bpy.props.BoolProperty(name="Is Schedule Of Rates", default=False)
def _execute(self, context):
from ifc5d.csv2ifc import Csv2Ifc
self.file = IfcStore.get_file()
start = time.time()
csv2ifc = Csv2Ifc()
csv2ifc.csv = self.filepath
csv2ifc.file = self.file
csv2ifc.is_schedule_of_rates = self.is_schedule_of_rates
csv2ifc.execute()
print("Import finished in {:.2f} seconds".format(time.time() - start))
return {"FINISHED"}
class AddCostColumn(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.add_cost_column"
bl_label = "Add Cost Column"
bl_options = {"REGISTER", "UNDO"}
name: bpy.props.StringProperty()
def _execute(self, context):
self.props = context.scene.BIMCostProperties
new = self.props.columns.add()
new.name = self.name
return {"FINISHED"}
class RemoveCostColumn(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.remove_cost_column"
bl_label = "Remove Cost Column"
bl_options = {"REGISTER", "UNDO"}
name: bpy.props.StringProperty()
def _execute(self, context):
self.props = context.scene.BIMCostProperties
self.props.columns.remove(self.props.columns.find(self.name))
return {"FINISHED"}
class LoadCostItemQuantities(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.load_cost_item_quantities"
bl_label = "Load Cost Item Quantities"
bl_options = {"REGISTER", "UNDO"}
def _execute(self, context):
self.props = context.scene.BIMCostProperties
self.file = IfcStore.get_file()
self.props.cost_item_products.clear()
self.props.cost_item_processes.clear()
self.props.cost_item_resources.clear()
if self.props.active_cost_item_index < len(self.props.cost_items):
ifc_definition_id = self.props.cost_items[self.props.active_cost_item_index].ifc_definition_id
cost_item = tool.Ifc.get().by_id(ifc_definition_id)
# for control_id, quantity_ids in cost_item.Controls.items() or {}:
for rel in cost_item.Controls or []:
# control_id, quantity_ids
for related_object in rel.RelatedObjects:
if related_object.is_a("IfcProduct"):
new = self.props.cost_item_products.add()
elif related_object.is_a("IfcProcess"):
new = self.props.cost_item_processes.add()
elif related_object.is_a("IfcResource"):
new = self.props.cost_item_resources.add()
new.ifc_definition_id = related_object.id()
new.name = related_object.Name or "Unnamed"
total_quantity = 0
qtos = ifcopenshell.util.element.get_psets(related_object, qtos_only=True)
for qset_name, quantities in qtos.items():
qto = tool.Ifc.get().by_id(quantities["id"])
for quantity in qto.Quantities:
if quantity in cost_item.CostQuantities:
total_quantity += quantity[3]
new.total_quantity = total_quantity
return {"FINISHED"}
class LoadCostItemTypes(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.load_cost_item_types"
bl_label = "Load Cost Item Types"
bl_options = {"REGISTER", "UNDO"}
def _execute(self, context):
self.props = context.scene.BIMCostProperties
self.file = IfcStore.get_file()
self.props.cost_item_type_products.clear()
# TODO implement process and resource types
# self.props.cost_item_processes.clear()
# self.props.cost_item_resources.clear()
ifc_definition_id = self.props.cost_items[self.props.active_cost_item_index].ifc_definition_id
cost_item = tool.Ifc.get().by_id(ifc_definition_id)
for rel in cost_item.Controls or []:
for related_object in rel.RelatedObjects:
if related_object.is_a("IfcTypeProduct"):
new = self.props.cost_item_type_products.add()
# TODO implement process and resource types
# elif related_object.is_a("IfcProcess"):
# new = self.props.cost_item_processes.add()
# elif related_object.is_a("IfcResource"):
# new = self.props.cost_item_resources.add()
new.ifc_definition_id = related_object.id()
new.name = related_object.Name or "Unnamed"
return {"FINISHED"}
class AssignCostValue(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.assign_cost_value"
bl_label = "Assign Cost Value"
bl_options = {"REGISTER", "UNDO"}
cost_item: bpy.props.IntProperty()
cost_rate: bpy.props.IntProperty()
def _execute(self, context):
self.file = IfcStore.get_file()
ifcopenshell.api.run(
"cost.assign_cost_value",
self.file,
cost_item=self.file.by_id(self.cost_item),
cost_rate=self.file.by_id(self.cost_rate),
)
return {"FINISHED"}
class LoadScheduleOfRates(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.load_schedule_of_rates"
bl_label = "Load Schedule of Rates"
bl_options = {"REGISTER", "UNDO"}
cost_schedule: bpy.props.IntProperty()
def _execute(self, context):
self.props = context.scene.BIMCostProperties
self.props.is_cost_update_enabled = False
self.props.cost_item_rates.clear()
self.contracted_cost_item_rates = json.loads(self.props.contracted_cost_item_rates)
for rel in tool.Ifc.get().by_id(self.cost_schedule).Controls or []:
for cost_item in rel.RelatedObjects:
self.create_new_cost_item_li(cost_item, 0)
self.props.is_cost_update_enabled = True
return {"FINISHED"}
def create_new_cost_item_li(self, cost_item, level_index):
new = self.props.cost_item_rates.add()
new.ifc_definition_id = cost_item.id()
new.name = cost_item.Name or "Unnamed"
new.identification = cost_item.Identification or "XXX"
new.is_expanded = cost_item.id() not in self.contracted_cost_item_rates
new.level_index = level_index
if cost_item.IsNestedBy:
new.has_children = True
if new.is_expanded:
for rel in cost_item.IsNestedBy:
for sub_cost_item in rel.RelatedObjects:
self.create_new_cost_item_li(sub_cost_item, level_index + 1)
class ExpandCostItemRate(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.expand_cost_item_rate"
bl_label = "Expand Cost Item Rate"
bl_options = {"REGISTER", "UNDO"}
cost_item: bpy.props.IntProperty()
def _execute(self, context):
props = context.scene.BIMCostProperties
self.file = IfcStore.get_file()
contracted_cost_item_rates = json.loads(props.contracted_cost_item_rates)
contracted_cost_item_rates.remove(self.cost_item)
props.contracted_cost_item_rates = json.dumps(contracted_cost_item_rates)
bpy.ops.bim.load_schedule_of_rates(cost_schedule=int(props.schedule_of_rates))
return {"FINISHED"}
class ContractCostItemRate(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.contract_cost_item_rate"
bl_label = "Contract Cost Item Rate"
bl_options = {"REGISTER", "UNDO"}
cost_item: bpy.props.IntProperty()
def _execute(self, context):
props = context.scene.BIMCostProperties
self.file = IfcStore.get_file()
contracted_cost_item_rates = json.loads(props.contracted_cost_item_rates)
contracted_cost_item_rates.append(self.cost_item)
props.contracted_cost_item_rates = json.dumps(contracted_cost_item_rates)
bpy.ops.bim.load_schedule_of_rates(cost_schedule=int(props.schedule_of_rates))
return {"FINISHED"}
class CalculateCostItemResourceValue(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.calculate_cost_item_resource_value"
bl_label = "Calculate Cost Item Resource Value"
bl_options = {"REGISTER", "UNDO"}
cost_item: bpy.props.IntProperty()
def _execute(self, context):
self.file = IfcStore.get_file()
ifcopenshell.api.run(
"cost.calculate_cost_item_resource_value", self.file, cost_item=self.file.by_id(self.cost_item)
)
return {"FINISHED"}