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):
+58 -4
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,11 +236,57 @@ 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
self.process_row(ifc_file, row, headers, attributes, null, bool_true, bool_false)
def import_xlsx(self, ifc_file, table, attributes, null, bool_true, bool_false):
workbook = openpyxl.load_workbook(filename=table, read_only=True)
worksheet = workbook.active # Assuming data is on the first sheet
headers = None
for row in worksheet.iter_rows(values_only=True):
if not headers:
headers = list(row)
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, 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: try:
element = ifc_file.by_guid(row[0]) element = ifc_file.by_guid(row[0])
except: except:
print("The element with GUID {} was not found".format(row[0])) print("The element with GUID {} was not found".format(row[0]))
continue return
for i, value in enumerate(row): for i, value in enumerate(row):
if i == 0: if i == 0:
continue # Skip GlobalId continue # Skip GlobalId