mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-09 17:31:45 +00:00
IfcCSV now supports grouping and group operations like concat, sum, min, max, etc.
This commit is contained in:
@@ -81,6 +81,7 @@ class ImportCsvAttributes(bpy.types.Operator):
|
||||
new.name = attribute["name"]
|
||||
new.header = attribute["header"]
|
||||
new.sort = attribute["sort"]
|
||||
new.group = attribute["group"]
|
||||
return {"FINISHED"}
|
||||
|
||||
def invoke(self, context, event):
|
||||
@@ -102,7 +103,9 @@ class ExportCsvAttributes(bpy.types.Operator):
|
||||
|
||||
data = {
|
||||
"query": tool.Search.export_filter_query(props.filter_groups),
|
||||
"attributes": [{"name": a.name, "header": a.header, "sort": a.sort} for a in props.csv_attributes],
|
||||
"attributes": [
|
||||
{"name": a.name, "header": a.header, "sort": a.sort, "group": a.group} for a in props.csv_attributes
|
||||
],
|
||||
}
|
||||
|
||||
with open(self.filepath, "w") as outfile:
|
||||
@@ -148,9 +151,12 @@ class ExportIfcCsv(bpy.types.Operator):
|
||||
headers = [a.header for a in props.csv_attributes]
|
||||
|
||||
sort = []
|
||||
groups = []
|
||||
for attribute in props.csv_attributes:
|
||||
if attribute.sort != "NONE":
|
||||
sort.append({"name": attribute.name, "order": attribute.sort})
|
||||
if attribute.group != "NONE":
|
||||
groups.append({"name": attribute.name, "type": attribute.group, "varies_value": attribute.varies_value})
|
||||
|
||||
sep = props.csv_custom_delimiter if props.csv_delimiter == "CUSTOM" else props.csv_delimiter
|
||||
ifc_csv.export(
|
||||
@@ -167,6 +173,7 @@ class ExportIfcCsv(bpy.types.Operator):
|
||||
bool_true=props.true_value,
|
||||
bool_false=props.false_value,
|
||||
sort=sort,
|
||||
groups=groups,
|
||||
)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
@@ -36,6 +36,19 @@ class CsvAttribute(PropertyGroup):
|
||||
name: StringProperty(name="Query", default="class")
|
||||
header: StringProperty(name="Header Value", default="IFC Class")
|
||||
sort: EnumProperty(items=[("NONE", "None", ""), ("ASC", "Ascending", ""), ("DESC", "Descending", "")])
|
||||
group: EnumProperty(
|
||||
items=[
|
||||
("NONE", "None", ""),
|
||||
("GROUP", "Group", "All rows where this value is identical will be merged."),
|
||||
("CONCAT", "Concatenation", "Concatenate values if values vary within a group."),
|
||||
("VARIES", "Varies", "Show a custom value if values vary within a group."),
|
||||
("SUM", "Sum", "Sums the total value of rows in a group."),
|
||||
("AVERAGE", "Average", "Averages the total value of rows in a group."),
|
||||
("MIN", "Min", "Gets the minimum value of rows in a group."),
|
||||
("MAX", "Max", "Gets the maximum value of rows in a group."),
|
||||
]
|
||||
)
|
||||
varies_value: StringProperty(default="Varies", name="Varies Value")
|
||||
|
||||
|
||||
class CsvProperties(PropertyGroup):
|
||||
@@ -81,5 +94,6 @@ class CsvProperties(PropertyGroup):
|
||||
)
|
||||
csv_custom_delimiter: StringProperty(default="", name="Custom Delimiter")
|
||||
should_show_settings: BoolProperty(default=False, name="Show Settings")
|
||||
should_show_sort: BoolProperty(default=False, name="Show Sort")
|
||||
should_show_sort: BoolProperty(default=False, name="Show Sorting")
|
||||
should_show_group: BoolProperty(default=False, name="Show Grouping")
|
||||
should_load_from_memory: BoolProperty(default=False, name="Load from Memory")
|
||||
|
||||
@@ -48,6 +48,7 @@ class BIM_PT_ifccsv(Panel):
|
||||
row.operator("bim.import_csv_attributes", icon="IMPORT", text="")
|
||||
row.operator("bim.export_csv_attributes", icon="EXPORT", text="")
|
||||
row.prop(props, "should_show_sort", icon="SORTSIZE", text="")
|
||||
row.prop(props, "should_show_group", icon="OUTLINER_COLLECTION", text="")
|
||||
row.prop(props, "should_show_settings", icon="PREFERENCES", text="")
|
||||
|
||||
if not IfcStore.get_file() or not props.should_load_from_memory:
|
||||
@@ -90,8 +91,11 @@ class BIM_PT_ifccsv(Panel):
|
||||
row.prop(attribute, "name", text="")
|
||||
if props.should_show_sort:
|
||||
row.prop(attribute, "sort", text="")
|
||||
else:
|
||||
row.prop(attribute, "header", text="")
|
||||
if props.should_show_group:
|
||||
row.prop(attribute, "group", text="")
|
||||
if attribute.group == "VARIES":
|
||||
row.prop(attribute, "varies_value", text="")
|
||||
row.prop(attribute, "header", text="")
|
||||
row.operator("bim.remove_csv_attribute", icon="X", text="").index = index
|
||||
|
||||
row = layout.row(align=True)
|
||||
|
||||
@@ -28,6 +28,7 @@ import ifcopenshell
|
||||
import ifcopenshell.util.selector
|
||||
import ifcopenshell.util.element
|
||||
import ifcopenshell.util.schema
|
||||
from statistics import mean
|
||||
|
||||
try:
|
||||
from odf.namespaces import OFFICENS
|
||||
@@ -72,6 +73,7 @@ class IfcCsv:
|
||||
bool_true="YES",
|
||||
bool_false="NO",
|
||||
sort=None,
|
||||
groups=None,
|
||||
):
|
||||
self.ifc_file = ifc_file
|
||||
self.results = []
|
||||
@@ -110,6 +112,65 @@ class IfcCsv:
|
||||
else:
|
||||
self.headers.append(attribute)
|
||||
|
||||
if groups:
|
||||
group_results = {}
|
||||
group_indices = {}
|
||||
group_values = {}
|
||||
group_varies_values = {}
|
||||
|
||||
for group in groups:
|
||||
index = attributes.index(group["name"])
|
||||
group_indices.setdefault(group["type"], [])
|
||||
group_indices[group["type"]].append(index)
|
||||
if group["type"] == "VARIES":
|
||||
group_varies_values[index] = group["varies_value"]
|
||||
|
||||
for row in self.results:
|
||||
key = "-".join([str(row[gi]) for gi in group_indices.get("GROUP", [])])
|
||||
for group_type, gis in group_indices.items():
|
||||
if group_type in ("CONCAT", "VARIES"):
|
||||
for gi in gis:
|
||||
group_values.setdefault(key, {}).setdefault(gi, set())
|
||||
group_values[key][gi].add(str(row[gi]))
|
||||
elif group_type in ("SUM", "AVERAGE", "MIN", "MAX"):
|
||||
for gi in gis:
|
||||
group_values.setdefault(key, {}).setdefault(gi, [])
|
||||
try:
|
||||
value = float(row[gi])
|
||||
except:
|
||||
continue
|
||||
group_values[key][gi].append(value)
|
||||
group_results[key] = row
|
||||
|
||||
for group_type, gis in group_indices.items():
|
||||
if group_type == "CONCAT":
|
||||
for key, result in group_results.items():
|
||||
for gi in gis:
|
||||
result[gi] = ", ".join(group_values[key][gi])
|
||||
elif group_type == "VARIES":
|
||||
for key, result in group_results.items():
|
||||
for gi in gis:
|
||||
if len(group_values[key][gi]) > 1:
|
||||
result[gi] = group_varies_values[gi]
|
||||
elif group_type == "SUM":
|
||||
for key, result in group_results.items():
|
||||
for gi in gis:
|
||||
result[gi] = sum(group_values[key][gi])
|
||||
elif group_type == "AVERAGE":
|
||||
for key, result in group_results.items():
|
||||
for gi in gis:
|
||||
result[gi] = mean(group_values[key][gi])
|
||||
elif group_type == "MIN":
|
||||
for key, result in group_results.items():
|
||||
for gi in gis:
|
||||
result[gi] = min(group_values[key][gi])
|
||||
elif group_type == "MAX":
|
||||
for key, result in group_results.items():
|
||||
for gi in gis:
|
||||
result[gi] = max(group_values[key][gi])
|
||||
|
||||
self.results = group_results.values()
|
||||
|
||||
if sort:
|
||||
def natural_sort(value):
|
||||
if isinstance(value, str):
|
||||
|
||||
@@ -673,6 +673,7 @@ class Selector:
|
||||
value = len(list(value))
|
||||
elif isinstance(value, (list, tuple)):
|
||||
value = len(value)
|
||||
value = 1
|
||||
elif key == "class":
|
||||
value = value.is_a()
|
||||
elif key == "id":
|
||||
|
||||
Reference in New Issue
Block a user