mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-18 06:21:40 +00:00
csv2ifc import - rename required column from hierarchy to index #5492
To prevent confusion with 'Hierarchy' column that's added on the export and make current and export compatible. Indices now always start from 1 for consistency.
This commit is contained in:
@@ -30,6 +30,11 @@ See example files as a CSV file format reference:
|
|||||||
Some notes on the format:
|
Some notes on the format:
|
||||||
- Empty lines are ignored.
|
- Empty lines are ignored.
|
||||||
- Importing ods/xlsx is not currently supported, only csv.
|
- Importing ods/xlsx is not currently supported, only csv.
|
||||||
|
- 'Hierarchy' is just an informational column that doesn't affect the import.
|
||||||
|
E.g. '1', '1.1', '1.1.1', etc.
|
||||||
|
- 'Index' column is a hierarchy depth that's used for building hierarchy during csv import, starting from 1.
|
||||||
|
E.g. root items of the same level have index '1', their children have '2', etc.
|
||||||
|
- 'Index' was preferred for import hierarchy source over 'Hierarchy' as it's easier to edit from the table view.
|
||||||
|
|
||||||
## Usage IFC to CSV, ODS, XSLS
|
## Usage IFC to CSV, ODS, XSLS
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ from typing import Any, Union, Optional, TypedDict, NotRequired
|
|||||||
|
|
||||||
|
|
||||||
class CsvHeader(TypedDict):
|
class CsvHeader(TypedDict):
|
||||||
|
Index: int
|
||||||
Name: int
|
Name: int
|
||||||
Quantity: int
|
Quantity: int
|
||||||
Unit: int
|
Unit: int
|
||||||
@@ -86,13 +87,16 @@ class Csv2Ifc:
|
|||||||
locale.setlocale(locale.LC_ALL, "") # set the system locale
|
locale.setlocale(locale.LC_ALL, "") # set the system locale
|
||||||
non_sor_fields = {"Property", "Query"}
|
non_sor_fields = {"Property", "Query"}
|
||||||
|
|
||||||
|
# TODO: 25-04-17 Deprecated 0 indices, should fully remove later.
|
||||||
|
min_index = None
|
||||||
|
|
||||||
with open(self.csv, "r", encoding="utf-8") as csv_file:
|
with open(self.csv, "r", encoding="utf-8") 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
|
||||||
# parse header
|
# parse header
|
||||||
if row[0] == "Hierarchy":
|
if not self.headers:
|
||||||
self.has_categories = True
|
self.has_categories = True
|
||||||
for i, col in enumerate(row):
|
for i, col in enumerate(row):
|
||||||
if not col:
|
if not col:
|
||||||
@@ -129,12 +133,18 @@ class Csv2Ifc:
|
|||||||
|
|
||||||
continue
|
continue
|
||||||
cost_data = self.get_row_cost_data(row)
|
cost_data = self.get_row_cost_data(row)
|
||||||
hierarchy_key = int(row[0])
|
index = int(row[self.headers["Index"]])
|
||||||
if hierarchy_key == 1:
|
if min_index is None and index in (0, 1):
|
||||||
|
if index == 0:
|
||||||
|
print(
|
||||||
|
"WARNING. Indices in csv table start from 0, they should start from 1. It will be deprecated soon completely."
|
||||||
|
)
|
||||||
|
min_index = index
|
||||||
|
if index == min_index:
|
||||||
self.cost_items.append(cost_data)
|
self.cost_items.append(cost_data)
|
||||||
else:
|
else:
|
||||||
parents[hierarchy_key - 1]["children"].append(cost_data)
|
parents[index - 1]["children"].append(cost_data)
|
||||||
parents[hierarchy_key] = cost_data
|
parents[index] = cost_data
|
||||||
|
|
||||||
def get_row_cost_data(self, row: list[str]) -> CostItem:
|
def get_row_cost_data(self, row: list[str]) -> CostItem:
|
||||||
name = row[self.headers["Name"]]
|
name = row[self.headers["Name"]]
|
||||||
|
|||||||
@@ -160,9 +160,8 @@ class IfcDataGetter:
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def get_cost_items_data(file: ifcopenshell.file, schedule: ifcopenshell.entity_instance) -> list[CostItem]:
|
def get_cost_items_data(file: ifcopenshell.file, schedule: ifcopenshell.entity_instance) -> list[CostItem]:
|
||||||
cost_items_data: list[CostItem] = []
|
cost_items_data: list[CostItem] = []
|
||||||
index = 0
|
|
||||||
for cost_item in IfcDataGetter.get_root_costs(schedule):
|
for cost_item in IfcDataGetter.get_root_costs(schedule):
|
||||||
IfcDataGetter.process_cost_data(file, cost_item, cost_items_data, index)
|
IfcDataGetter.process_cost_data(file, cost_item, cost_items_data)
|
||||||
return cost_items_data
|
return cost_items_data
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
"Hierarchy","Identification","Name","Quantity","Unit","Value"
|
"Index","Identification","Name","Quantity","Unit","Value"
|
||||||
1,1,"Rates",,,
|
1,1,"Rates",,,
|
||||||
,,,,,
|
,,,,,
|
||||||
2,1.1,"Category A",,,
|
2,1.1,"Category A",,,
|
||||||
|
|||||||
|
@@ -1,4 +1,4 @@
|
|||||||
Hierarchy,Identification,Name,Quantity,Unit,Contract,Rate,Material Rate,Labor Rate,Subtotal,Property,Query
|
Index,Identification,Name,Quantity,Unit,Contract,Rate,Material Rate,Labor Rate,Subtotal,Property,Query
|
||||||
1,DB,Design and build,,,,,,,,,
|
1,DB,Design and build,,,,,,,,,
|
||||||
2,DB.1,Design,,,,,,,,,
|
2,DB.1,Design,,,,,,,,,
|
||||||
3,DB.1.1,Architecte,1,unit,40000,,,,40000,,
|
3,DB.1.1,Architecte,1,unit,40000,,,,40000,,
|
||||||
|
|||||||
|
@@ -1,4 +1,4 @@
|
|||||||
"Hierarchy","Identification","Name","Quantity","Unit","Foo","Bar","Baz","Subtotal"
|
"Index","Identification","Name","Quantity","Unit","Foo","Bar","Baz","Subtotal"
|
||||||
1,1,"Demolition",,,,,,301
|
1,1,"Demolition",,,,,,301
|
||||||
,,,,,,,,
|
,,,,,,,,
|
||||||
2,1.1,"Building A",,,,,,96
|
2,1.1,"Building A",,,,,,96
|
||||||
|
|||||||
|
Reference in New Issue
Block a user