IfcCSV now supports importing from ODS, XLSX, and Pandas dataframes in addition to CSV

This commit is contained in:
Dion Moult
2023-08-20 16:55:01 +10:00
parent 00c81a3add
commit eac84c6965
2 changed files with 75 additions and 21 deletions
@@ -166,8 +166,8 @@ class ExportIfcCsv(bpy.types.Operator):
class ImportIfcCsv(bpy.types.Operator): class ImportIfcCsv(bpy.types.Operator):
bl_idname = "bim.import_ifccsv" bl_idname = "bim.import_ifccsv"
bl_label = "Import CSV to IFC" bl_label = "Import to IFC"
filename_ext = ".csv" filter_glob: bpy.props.StringProperty(default="*.csv;*.ods;*.xlsx", options={"HIDDEN"})
filepath: bpy.props.StringProperty(subtype="FILE_PATH") filepath: bpy.props.StringProperty(subtype="FILE_PATH")
def invoke(self, context, event): def invoke(self, context, event):
+73 -19
View File
@@ -29,11 +29,10 @@ import ifcopenshell.util.element
import ifcopenshell.util.schema import ifcopenshell.util.schema
try: try:
from odf.opendocument import OpenDocumentSpreadsheet from odf.opendocument import OpenDocumentSpreadsheet, load
from odf.style import Style, TableCellProperties from odf.style import Style, TableCellProperties
from odf.table import Table, TableRow, TableCell from odf.table import Table, TableRow, TableCell
from odf.text import P from odf.text import P
from odf.opendocument import load
except: except:
pass # No ODF support pass # No ODF support
@@ -216,7 +215,16 @@ class IfcCsv:
return ["{}.{}".format(pset_qto_name, n) for n in results] return ["{}.{}".format(pset_qto_name, n) for n in results]
def Import(self, ifc_file, table, attributes=None, delimiter=",", null="-", bool_true="YES", bool_false="NO"): def Import(self, ifc_file, table, attributes=None, delimiter=",", null="-", bool_true="YES", bool_false="NO"):
# Currently only supports CSV. ext = table.split(".")[-1].lower()
if ext == "csv":
self.import_csv(ifc_file, table, attributes, delimiter, null, bool_true, bool_false)
elif ext == "ods":
self.import_ods(ifc_file, table, attributes, null, bool_true, bool_false)
elif ext == "xlsx":
self.import_xlsx(ifc_file, table, attributes, null, bool_true, bool_false)
def import_csv(self, ifc_file, table, attributes=None, delimiter=",", null="-", bool_true="YES", bool_false="NO"):
with open(table, newline="", encoding="utf-8") as f: with open(table, newline="", encoding="utf-8") as f:
reader = csv.reader(f, delimiter=delimiter) reader = csv.reader(f, delimiter=delimiter)
headers = [] headers = []
@@ -228,22 +236,68 @@ class IfcCsv:
elif len(attributes) == len(headers) - 1: elif len(attributes) == len(headers) - 1:
attributes.insert(0, "") # The GlobalId column attributes.insert(0, "") # The GlobalId column
continue continue
try: self.process_row(ifc_file, row, headers, attributes, null, bool_true, bool_false)
element = ifc_file.by_guid(row[0])
except: def import_xlsx(self, ifc_file, table, attributes, null, bool_true, bool_false):
print("The element with GUID {} was not found".format(row[0])) workbook = openpyxl.load_workbook(filename=table, read_only=True)
continue worksheet = workbook.active # Assuming data is on the first sheet
for i, value in enumerate(row): headers = None
if i == 0:
continue # Skip GlobalId for row in worksheet.iter_rows(values_only=True):
if value == null: if not headers:
value = None headers = list(row)
elif value == bool_true: if not attributes:
value = True attributes = [None] * len(headers)
elif value == bool_false: elif len(attributes) == len(headers) - 1:
value = False attributes.insert(0, "") # The GlobalId column
key = attributes[i] or headers[i] continue
ifcopenshell.util.selector.set_element_value(ifc_file, element, key, value) self.process_row(ifc_file, row, headers, attributes, null, bool_true, bool_false)
def import_ods(self, ifc_file, table, attributes, null, bool_true, bool_false):
doc = load(table)
first_sheet = doc.spreadsheet.getElementsByType(Table)[0]
rows = first_sheet.getElementsByType(TableRow)
headers = None
for row in rows:
values = [cell.getElementsByType(P)[0].childNodes[0].data for cell in row.getElementsByType(TableCell)]
if not headers:
headers = values
if not attributes:
attributes = [None] * len(headers)
elif len(attributes) == len(headers) - 1:
attributes.insert(0, "") # The GlobalId column
continue
self.process_row(ifc_file, values, headers, attributes, null, bool_true, bool_false)
def import_pd(self, ifc_file, df, attributes=None, null="-", bool_true="YES", bool_false="NO"):
headers = df.columns.tolist()
if not attributes:
attributes = [None] * len(headers)
elif len(attributes) == len(headers) - 1:
attributes.insert(0, "") # The GlobalId column
for _, row in df.iterrows():
self.process_row(ifc_file, row.tolist(), headers, attributes, null, bool_true, bool_false)
def process_row(self, ifc_file, row, headers, attributes, null, bool_true, bool_false):
try:
element = ifc_file.by_guid(row[0])
except:
print("The element with GUID {} was not found".format(row[0]))
return
for i, value in enumerate(row):
if i == 0:
continue # Skip GlobalId
if value == null:
value = None
elif value == bool_true:
value = True
elif value == bool_false:
value = False
key = attributes[i] or headers[i]
ifcopenshell.util.selector.set_element_value(ifc_file, element, key, value)
if __name__ == "__main__": if __name__ == "__main__":