From d4fc135209ed7443336b330e6a7a04ae2f2caeb4 Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Mon, 9 Aug 2021 17:12:23 +1000 Subject: [PATCH] You can now import cost schedules as CSVs into IFC in Blender --- src/blenderbim/Makefile | 2 ++ .../blenderbim/bim/module/cost/__init__.py | 7 ++++++ .../blenderbim/bim/module/cost/operator.py | 23 +++++++++++++++++++ src/ifc5d/ifc5d/csv2ifc.py | 3 +++ .../ifcopenshell/api/cost/data.py | 8 +++++-- 5 files changed, 41 insertions(+), 2 deletions(-) diff --git a/src/blenderbim/Makefile b/src/blenderbim/Makefile index 9f2dc966e6..78309ca686 100644 --- a/src/blenderbim/Makefile +++ b/src/blenderbim/Makefile @@ -118,6 +118,8 @@ endif cp -r dist/working/IfcOpenShell-0.6.0/src/ifcpatch/ifcpatch dist/blenderbim/libs/site/packages/ # Provides IFC4D functionality cp -r dist/working/IfcOpenShell-0.6.0/src/ifc4d/ifc4d dist/blenderbim/libs/site/packages/ + # Provides IFC5D functionality + cp -r dist/working/IfcOpenShell-0.6.0/src/ifc5d/ifc5d dist/blenderbim/libs/site/packages/ rm -rf dist/working # Provides Mustache templating in construction documentation diff --git a/src/blenderbim/blenderbim/bim/module/cost/__init__.py b/src/blenderbim/blenderbim/bim/module/cost/__init__.py index 5a5abd7578..e0259d2ba6 100644 --- a/src/blenderbim/blenderbim/bim/module/cost/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/cost/__init__.py @@ -33,6 +33,7 @@ classes = ( operator.CopyCostItemValues, operator.SelectCostItemProducts, operator.SelectCostScheduleProducts, + operator.ImportCostScheduleCsv, prop.CostItem, prop.BIMCostProperties, ui.BIM_PT_cost_schedules, @@ -40,9 +41,15 @@ classes = ( ) +def menu_func_import(self, context): + self.layout.operator(operator.ImportCostScheduleCsv.bl_idname, text="Cost Schedule (.csv)") + + def register(): bpy.types.Scene.BIMCostProperties = bpy.props.PointerProperty(type=prop.BIMCostProperties) + bpy.types.TOPBAR_MT_file_import.append(menu_func_import) def unregister(): del bpy.types.Scene.BIMCostProperties + bpy.types.TOPBAR_MT_file_import.remove(menu_func_import) diff --git a/src/blenderbim/blenderbim/bim/module/cost/operator.py b/src/blenderbim/blenderbim/bim/module/cost/operator.py index fb98628a93..e0ec2d12ea 100644 --- a/src/blenderbim/blenderbim/bim/module/cost/operator.py +++ b/src/blenderbim/blenderbim/bim/module/cost/operator.py @@ -1,10 +1,12 @@ import os import bpy import json +import time import ifcopenshell.api import blenderbim.bim.helper from blenderbim.bim.module.cost.prop import purge from blenderbim.bim.ifc import IfcStore +from bpy_extras.io_utils import ImportHelper from ifcopenshell.api.cost.data import Data @@ -650,3 +652,24 @@ class SelectCostScheduleProducts(bpy.types.Operator): self.related_products.extend(cost_item["Controls"]) for child_id in cost_item["IsNestedBy"]: self.get_related_products(Data.cost_items[child_id]) + + +class ImportCostScheduleCsv(bpy.types.Operator, ImportHelper): + 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"}) + + 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.execute() + Data.load(IfcStore.get_file()) + print("Import finished in {:.2f} seconds".format(time.time() - start)) + return {"FINISHED"} diff --git a/src/ifc5d/ifc5d/csv2ifc.py b/src/ifc5d/ifc5d/csv2ifc.py index 4f6d16a2a1..14433d9c01 100644 --- a/src/ifc5d/ifc5d/csv2ifc.py +++ b/src/ifc5d/ifc5d/csv2ifc.py @@ -77,6 +77,9 @@ class Csv2Ifc: if cost_item["CostValues"]: cost_value = ifcopenshell.api.run("cost.add_cost_value", self.file, parent=cost_item["ifc"]) cost_value.AppliedValue = self.file.createIfcReal(cost_item["CostValues"]) + else: + cost_value = ifcopenshell.api.run("cost.add_cost_value", self.file, parent=cost_item["ifc"]) + cost_value.Category = "*" if cost_item["CostQuantities"]: quantity_class = ifcopenshell.util.unit.get_symbol_quantity_class(cost_item["CostQuantitiesUnit"]) quantity = ifcopenshell.api.run( diff --git a/src/ifcopenshell-python/ifcopenshell/api/cost/data.py b/src/ifcopenshell-python/ifcopenshell/api/cost/data.py index cf59abfff0..6c5a846d93 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/cost/data.py +++ b/src/ifcopenshell-python/ifcopenshell/api/cost/data.py @@ -69,8 +69,12 @@ class Data: if cost_item.CostQuantities: quantity = cost_item.CostQuantities[0] unit = ifcopenshell.util.unit.get_property_unit(quantity, cls.file) - data["Unit"] = unit.id() - data["UnitSymbol"] = ifcopenshell.util.unit.get_unit_symbol(unit) + if unit: + data["Unit"] = unit.id() + data["UnitSymbol"] = ifcopenshell.util.unit.get_unit_symbol(unit) + else: + data["Unit"] = None + data["UnitSymbol"] = None @classmethod def load_cost_item_values(cls, cost_item, data):