From 4c50b2d22452f645e3f0931cfe9d87f460d30d1d Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Wed, 9 Jun 2021 11:23:34 +1000 Subject: [PATCH] Support editing profile set usage attributes cardinal point and reference extent. Thanks Jesusbill! --- .../bim/module/material/operator.py | 74 ++++++++++++++++--- .../blenderbim/bim/module/material/prop.py | 1 + .../blenderbim/bim/module/material/ui.py | 37 ++++++++++ src/blenderbim/blenderbim/bim/prop.py | 6 +- 4 files changed, 105 insertions(+), 13 deletions(-) diff --git a/src/blenderbim/blenderbim/bim/module/material/operator.py b/src/blenderbim/blenderbim/bim/module/material/operator.py index 1ca74fb40d..8cfb2ccf60 100644 --- a/src/blenderbim/blenderbim/bim/module/material/operator.py +++ b/src/blenderbim/blenderbim/bim/module/material/operator.py @@ -2,6 +2,7 @@ import bpy import json import ifcopenshell.api import ifcopenshell.util.attribute +import blenderbim.bim.helper from blenderbim.bim.module.material.prop import purge as material_prop_purge from blenderbim.bim.ifc import IfcStore from ifcopenshell.api.material.data import Data @@ -26,7 +27,7 @@ class AssignParameterizedProfile(bpy.types.Operator): ifcopenshell.api.run( "material.assign_profile", self.file, - **{"material_profile": self.file.by_id(self.material_profile), "profile": profile} + **{"material_profile": self.file.by_id(self.material_profile), "profile": profile}, ) Data.load_profiles() ProfileData.load(self.file) @@ -175,9 +176,7 @@ class RemoveProfile(bpy.types.Operator): def execute(self, context): obj = bpy.data.objects.get(self.obj) if self.obj else bpy.context.active_object self.file = IfcStore.get_file() - ifcopenshell.api.run( - "material.remove_profile", self.file, **{"profile": self.file.by_id(self.profile)} - ) + ifcopenshell.api.run("material.remove_profile", self.file, **{"profile": self.file.by_id(self.profile)}) Data.load_profiles() return {"FINISHED"} @@ -313,20 +312,28 @@ class EnableEditingAssignedMaterial(bpy.types.Operator): elif product_data["type"] == "IfcMaterialLayerSet": material_set_data = Data.layer_sets[product_data["id"]] elif product_data["type"] == "IfcMaterialLayerSetUsage": - layer_set_usage = Data.layer_set_usages[product_data["id"]] - material_set_data = Data.layer_sets[layer_set_usage["ForLayerSet"]] + material_set_usage = Data.layer_set_usages[product_data["id"]] + material_set_data = Data.layer_sets[material_set_usage["ForLayerSet"]] material_set_class = "IfcMaterialLayerSet" elif product_data["type"] == "IfcMaterialProfileSet": material_set_data = Data.profile_sets[product_data["id"]] elif product_data["type"] == "IfcMaterialProfileSetUsage": - profile_set_usage = Data.profile_set_usages[product_data["id"]] - material_set_data = Data.profile_sets[profile_set_usage["ForProfileSet"]] + material_set_usage = Data.profile_set_usages[product_data["id"]] + material_set_data = Data.profile_sets[material_set_usage["ForProfileSet"]] material_set_class = "IfcMaterialProfileSet" elif product_data["type"] == "IfcMaterialList": material_set_data = Data.lists[product_data["id"]] else: material_set_data = {} + while len(props.material_set_usage_attributes) > 0: + props.material_set_usage_attributes.remove(0) + + if "Usage" in product_data["type"]: + blenderbim.bim.helper.import_attributes( + product_data["type"], props.material_set_usage_attributes, material_set_usage, self.import_attributes + ) + while len(props.material_set_attributes) > 0: props.material_set_attributes.remove(0) @@ -340,6 +347,36 @@ class EnableEditingAssignedMaterial(bpy.types.Operator): new.string_value = "" if new.is_null else material_set_data[attribute.name()] return {"FINISHED"} + def import_attributes(self, name, prop, data): + if name == "CardinalPoint": + # TODO: complain to buildingSMART + cardinal_point_map = { + 1: "bottom left", + 2: "bottom centre", + 3: "bottom right", + 4: "mid-depth left", + 5: "mid-depth centre", + 6: "mid-depth right", + 7: "top left", + 8: "top centre", + 9: "top right", + 10: "geometric centroid", + 11: "bottom in line with the geometric centroid", + 12: "left in line with the geometric centroid", + 13: "right in line with the geometric centroid", + 14: "top in line with the geometric centroid", + 15: "shear centre", + 16: "bottom in line with the shear centre", + 17: "left in line with the shear centre", + 18: "right in line with the shear centre", + 19: "top in line with the shear centre", + } + prop.data_type = "enum" + prop.enum_items = json.dumps(cardinal_point_map) + if data[name]: + prop.enum_value = str(data[name]) + return True + class DisableEditingAssignedMaterial(bpy.types.Operator): bl_idname = "bim.disable_editing_assigned_material" @@ -358,6 +395,7 @@ class EditAssignedMaterial(bpy.types.Operator): bl_label = "Edit Assigned Material" obj: bpy.props.StringProperty() material_set: bpy.props.IntProperty() + material_set_usage: bpy.props.IntProperty() def execute(self, context): self.file = IfcStore.get_file() @@ -379,12 +417,24 @@ class EditAssignedMaterial(bpy.types.Operator): ifcopenshell.api.run( "material.edit_assigned_material", self.file, - **{ - "element": material_set, - "attributes": attributes, - }, + **{"element": material_set, "attributes": attributes}, ) Data.load(IfcStore.get_file(), obj.BIMObjectProperties.ifc_definition_id) + + if self.material_set_usage: + material_set_usage = self.file.by_id(self.material_set_usage) + attributes = blenderbim.bim.helper.export_attributes(props.material_set_usage_attributes) + attributes["CardinalPoint"] = int(attributes["CardinalPoint"]) if attributes["CardinalPoint"] else None + ifcopenshell.api.run( + "material.edit_assigned_material", + self.file, + **{"element": material_set_usage, "attributes": attributes}, + ) + if material_set_usage.is_a("IfcMaterialLayerSetUsage"): + Data.load_layer_usages() + elif material_set_usage.is_a("IfcMaterialProfileSetUsage"): + Data.load_profile_usages() + if material_set.is_a("IfcMaterialConstituentSet"): Data.load_constituents() elif material_set.is_a("IfcMaterialLayerSet"): diff --git a/src/blenderbim/blenderbim/bim/module/material/prop.py b/src/blenderbim/blenderbim/bim/module/material/prop.py index 1ef527f10d..088a5c7962 100644 --- a/src/blenderbim/blenderbim/bim/module/material/prop.py +++ b/src/blenderbim/blenderbim/bim/module/material/prop.py @@ -83,6 +83,7 @@ class BIMObjectMaterialProperties(PropertyGroup): material_type: EnumProperty(items=getMaterialTypes, name="Material Type") material: EnumProperty(items=getMaterials, name="Material") is_editing: BoolProperty(name="Is Editing", default=False) + material_set_usage_attributes: CollectionProperty(name="Material Set Usage Attributes", type=Attribute) material_set_attributes: CollectionProperty(name="Material Set Attributes", type=Attribute) active_material_set_item_id: IntProperty(name="Active Material Set ID") material_set_item_attributes: CollectionProperty(name="Material Set Item Attributes", type=Attribute) diff --git a/src/blenderbim/blenderbim/bim/module/material/ui.py b/src/blenderbim/blenderbim/bim/module/material/ui.py index 7f6fb8c451..17dc5f1450 100644 --- a/src/blenderbim/blenderbim/bim/module/material/ui.py +++ b/src/blenderbim/blenderbim/bim/module/material/ui.py @@ -1,3 +1,4 @@ +import blenderbim.bim.helper from bpy.types import Panel from ifcopenshell.api.material.data import Data from ifcopenshell.api.profile.data import Data as ProfileData @@ -109,6 +110,8 @@ class BIM_PT_object_material(Panel): if self.props.is_editing: op = row.operator("bim.edit_assigned_material", icon="CHECKMARK", text="") op.material_set = self.material_set_id + if "Usage" in self.product_data["type"]: + op.material_set_usage = self.product_data["id"] row.operator("bim.disable_editing_assigned_material", icon="CANCEL", text="") else: row.operator("bim.enable_editing_assigned_material", icon="GREASEPENCIL", text="") @@ -140,6 +143,8 @@ class BIM_PT_object_material(Panel): self.draw_read_only_set_ui() def draw_editable_set_ui(self): + blenderbim.bim.helper.draw_attributes(self.props.material_set_usage_attributes, self.layout) + for attribute in self.props.material_set_attributes: row = self.layout.row(align=True) row.prop(attribute, "string_value", text=attribute.name) @@ -265,6 +270,38 @@ class BIM_PT_object_material(Panel): row.label(text="Description") row.label(text=str(self.material_set_data["Description"])) + if self.product_data["type"] == "IfcMaterialProfileSetUsage": + # TODO: complain to buildingSMART + cardinal_point_map = { + 1: "bottom left", + 2: "bottom centre", + 3: "bottom right", + 4: "mid-depth left", + 5: "mid-depth centre", + 6: "mid-depth right", + 7: "top left", + 8: "top centre", + 9: "top right", + 10: "geometric centroid", + 11: "bottom in line with the geometric centroid", + 12: "left in line with the geometric centroid", + 13: "right in line with the geometric centroid", + 14: "top in line with the geometric centroid", + 15: "shear centre", + 16: "bottom in line with the shear centre", + 17: "left in line with the shear centre", + 18: "right in line with the shear centre", + 19: "top in line with the shear centre", + } + if self.material_set_usage["CardinalPoint"]: + row = self.layout.row(align=True) + row.label(text="CardinalPoint") + row.label(text=cardinal_point_map[self.material_set_usage["CardinalPoint"]]) + if self.material_set_usage["ReferenceExtent"]: + row = self.layout.row(align=True) + row.label(text="ReferenceExtent") + row.label(text=str(self.material_set_usage["ReferenceExtent"])) + total_thickness = 0 for item_id in self.set_items: if self.product_data["type"] == "IfcMaterialList": diff --git a/src/blenderbim/blenderbim/bim/prop.py b/src/blenderbim/blenderbim/bim/prop.py index 24da24f836..5a2a0c421e 100644 --- a/src/blenderbim/blenderbim/bim/prop.py +++ b/src/blenderbim/blenderbim/bim/prop.py @@ -27,7 +27,11 @@ target_views_enum = [] def getAttributeEnumValues(self, context): - return [(e, e, "") for e in json.loads(self.enum_items)] + # Support weird buildingSMART dictionary mappings which behave like enums + data = json.loads(self.enum_items) + if isinstance(data, dict): + return [(str(k), v, "") for k, v in data.items()] + return [(e, e, "") for e in data] def updateSchemaDir(self, context):