Ifc5d can now parse cost category breakdowns in CSV form

This commit is contained in:
Dion Moult
2021-08-09 17:57:34 +10:00
parent d4fc135209
commit efec360a00
3 changed files with 77 additions and 39 deletions
+56 -24
View File
@@ -1,4 +1,3 @@
# Ifc5D - IFC costing utility # Ifc5D - IFC costing utility
# Copyright (C) 2021 Dion Moult <dion@thinkmoult.com> # Copyright (C) 2021 Dion Moult <dion@thinkmoult.com>
# #
@@ -36,11 +35,21 @@ class Csv2Ifc:
def parse_csv(self): def parse_csv(self):
self.parents = {} self.parents = {}
self.headers = {}
with open(self.csv, "r") as csv_file: with open(self.csv, "r") as csv_file:
reader = csv.reader(csv_file) reader = csv.reader(csv_file)
for row in reader: for row in reader:
if not row[0]: if not row[0]:
continue continue
if row[0] == "Hierarchy":
self.has_categories = True
for i, col in enumerate(row):
if not col:
continue
if col == "Value":
self.has_categories = False
self.headers[col] = i
continue
cost_data = self.get_row_cost_data(row) cost_data = self.get_row_cost_data(row)
hierarchy_key = int(row[0]) hierarchy_key = int(row[0])
if hierarchy_key == 1: if hierarchy_key == 1:
@@ -50,11 +59,23 @@ class Csv2Ifc:
self.parents[hierarchy_key] = cost_data self.parents[hierarchy_key] = cost_data
def get_row_cost_data(self, row): def get_row_cost_data(self, row):
name = row[self.headers["Name"]]
cost_quantities = row[self.headers["Quantity"]]
cost_quantities_unit = row[self.headers["Unit"]]
if self.has_categories:
cost_values = {
k: float(row[v])
for k, v in self.headers.items()
if k not in ["Hierarchy", "Name", "Quantity", "Unit", "Subtotal"] and row[v]
}
else:
cost_values = row[self.headers["Value"]]
cost_values = float(cost_values) if cost_values else None
return { return {
"Name": str(row[1]) if row[1] else None, "Name": str(name) if name else None,
"CostQuantities": float(row[2]) if row[2] else None, "CostQuantities": float(cost_quantities) if cost_quantities else None,
"CostQuantitiesUnit": str(row[3]) if row[3] else None, "CostQuantitiesUnit": str(cost_quantities_unit) if cost_quantities_unit else None,
"CostValues": float(row[4]) if row[4] else None, "CostValues": cost_values,
"children": [], "children": [],
} }
@@ -67,26 +88,37 @@ class Csv2Ifc:
def create_cost_items(self, cost_items, parent=None): def create_cost_items(self, cost_items, parent=None):
for cost_item in cost_items: for cost_item in cost_items:
if parent is None: self.create_cost_item(cost_item, parent)
cost_item["ifc"] = ifcopenshell.api.run(
"cost.add_cost_item", self.file, cost_schedule=self.cost_schedule def create_cost_item(self, cost_item, parent):
) if parent is None:
else: cost_item["ifc"] = ifcopenshell.api.run(
cost_item["ifc"] = ifcopenshell.api.run("cost.add_cost_item", self.file, cost_item=parent) "cost.add_cost_item", self.file, cost_schedule=self.cost_schedule
cost_item["ifc"].Name = cost_item["Name"] )
if cost_item["CostValues"]: else:
cost_item["ifc"] = ifcopenshell.api.run("cost.add_cost_item", self.file, cost_item=parent)
cost_item["ifc"].Name = cost_item["Name"]
if not cost_item["CostValues"]:
cost_value = ifcopenshell.api.run("cost.add_cost_value", self.file, parent=cost_item["ifc"])
cost_value.Category = "*"
elif self.has_categories:
for category, value in cost_item["CostValues"].items():
cost_value = ifcopenshell.api.run("cost.add_cost_value", self.file, parent=cost_item["ifc"]) cost_value = ifcopenshell.api.run("cost.add_cost_value", self.file, parent=cost_item["ifc"])
cost_value.AppliedValue = self.file.createIfcReal(cost_item["CostValues"]) cost_value.AppliedValue = self.file.createIfcReal(value)
else: cost_value.Category = category
cost_value = ifcopenshell.api.run("cost.add_cost_value", self.file, parent=cost_item["ifc"]) else:
cost_value.Category = "*" cost_value = ifcopenshell.api.run("cost.add_cost_value", self.file, parent=cost_item["ifc"])
if cost_item["CostQuantities"]: cost_value.AppliedValue = self.file.createIfcReal(cost_item["CostValues"])
quantity_class = ifcopenshell.util.unit.get_symbol_quantity_class(cost_item["CostQuantitiesUnit"])
quantity = ifcopenshell.api.run( if cost_item["CostQuantities"]:
"cost.add_cost_item_quantity", self.file, cost_item=cost_item["ifc"], ifc_class=quantity_class quantity_class = ifcopenshell.util.unit.get_symbol_quantity_class(cost_item["CostQuantitiesUnit"])
) quantity = ifcopenshell.api.run(
quantity[3] = cost_item["CostQuantities"] "cost.add_cost_item_quantity", self.file, cost_item=cost_item["ifc"], ifc_class=quantity_class
self.create_cost_items(cost_item["children"], cost_item["ifc"]) )
quantity[3] = cost_item["CostQuantities"]
self.create_cost_items(cost_item["children"], cost_item["ifc"])
def create_boilerplate_ifc(self): def create_boilerplate_ifc(self):
self.file = ifcopenshell.file(schema="IFC4") self.file = ifcopenshell.file(schema="IFC4")
+14 -10
View File
@@ -1,10 +1,14 @@
1,"Demolition",,, "Hierarchy","Name","Quantity","Unit","Foo","Bar","Baz","Subtotal"
2,"Building A",,, 1,"Demolition",,,,,,301
3,"Soft strip",1,"m",5 ,,,,,,,
3,"Hard Strip",2,"m2",6 2,"Building A",,,,,,96
3,"Hazmat",3,"m3",7 ,,,,,,,
,,,, 3,"Soft strip",1,"m",5,4,3,12
2,"Building B",,, 3,"Hard Strip",2,"m2",6,5,4,30
3,"Soft strip",4,"hr",8 3,"Hazmat",3,"m3",7,6,5,54
3,"Hard Strip",5,,9 ,,,,,,,
3,"Hazmat",6,"kg",10 2,"Building B",,,,,,205
,,,,,,,
3,"Soft strip",4,"hr",8,7,,60
3,"Hard Strip",5,,9,,8,85
3,"Hazmat",6,"kg",10,,,60
1 1 Hierarchy Demolition Name Quantity Unit Foo Bar Baz Subtotal
2 2 1 Building A Demolition 301
3 3 Soft strip 1 m 5
4 3 2 Hard Strip Building A 2 m2 6 96
5 3 Hazmat 3 m3 7
6 3 Soft strip 1 m 5 4 3 12
7 2 3 Building B Hard Strip 2 m2 6 5 4 30
8 3 3 Soft strip Hazmat 4 3 hr m3 8 7 6 5 54
9 3 Hard Strip 5 9
10 3 2 Hazmat Building B 6 kg 10 205
11
12 3 Soft strip 4 hr 8 7 60
13 3 Hard Strip 5 9 8 85
14 3 Hazmat 6 kg 10 60
@@ -198,17 +198,19 @@ def get_property_unit(prop, ifc_file):
def get_symbol_quantity_class(symbol): def get_symbol_quantity_class(symbol):
# Dumb, but everybody gets it, unlike regex golf
if not symbol: if not symbol:
return "IfcQuantityCount" return "IfcQuantityCount"
elif symbol[-1:] == "g": symbol = symbol.lower()
if symbol in ["kg", "g", "mt", "kt", "t"]:
return "IfcQuantityWeight" return "IfcQuantityWeight"
elif symbol[-1:] == "s" or symbol == "hr": elif symbol in ["day", "d", "hour", "hr", "h", "minute", "min", "m", "second", "sec", "s"]:
return "IfcQuantityTime" return "IfcQuantityTime"
elif symbol[-1:] == "3": elif symbol in ["km3", "m3", "cm3", "mm3", "cy", "cft", "cin"]:
return "IfcQuantityVolume" return "IfcQuantityVolume"
elif symbol[-1:] == "2": elif symbol in ["km2", "m2", "cm2", "mm2", "sqy", "sqft", "sqin"]:
return "IfcQuantityArea" return "IfcQuantityArea"
elif symbol[-1:] == "m" or symbol in ["in", "ft", "yd"]: elif symbol in ["km", "m", "cm", "mm", "ly", "lf", "lin", "yd", "ft", "in"]:
return "IfcQuantityLength" return "IfcQuantityLength"
return "IfcQuantityCount" return "IfcQuantityCount"