diff --git a/src/blenderbim/blenderbim/bim/module/classification/__init__.py b/src/blenderbim/blenderbim/bim/module/classification/__init__.py index 9fdb326907..db05b1e1a8 100644 --- a/src/blenderbim/blenderbim/bim/module/classification/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/classification/__init__.py @@ -38,6 +38,7 @@ classes = ( prop.BIMClassificationReferenceProperties, ui.BIM_PT_classifications, ui.BIM_PT_classification_references, + ui.BIM_PT_material_classifications, ui.BIM_UL_classifications, ) diff --git a/src/blenderbim/blenderbim/bim/module/classification/data.py b/src/blenderbim/blenderbim/bim/module/classification/data.py index 52e5087b58..d9422109bf 100644 --- a/src/blenderbim/blenderbim/bim/module/classification/data.py +++ b/src/blenderbim/blenderbim/bim/module/classification/data.py @@ -27,6 +27,7 @@ from blenderbim.bim.ifc import IfcStore def refresh(): ClassificationsData.is_loaded = False ClassificationReferencesData.is_loaded = False + MaterialClassificationsData.is_loaded = False class ClassificationsData: @@ -61,7 +62,17 @@ class ClassificationsData: return [(str(e.id()), e.Name, "") for e in IfcStore.classification_file.by_type("IfcClassification")] -class ClassificationReferencesData: +class ReferencesData: + @classmethod + def is_available_classification_added(cls): + if not IfcStore.classification_file or not IfcStore.classification_file.by_type("IfcClassification"): + return False + props = bpy.context.scene.BIMClassificationProperties + name = IfcStore.classification_file.by_id(int(props.available_classifications)).Name + return name in [e.Name for e in tool.Ifc.get().by_type("IfcClassification")] + + +class ClassificationReferencesData(ReferencesData): data = {} is_loaded = False @@ -82,10 +93,24 @@ class ClassificationReferencesData: results.append(data) return results + +class MaterialClassificationsData(ReferencesData): + data = {} + is_loaded = False + @classmethod - def is_available_classification_added(cls): - if not IfcStore.classification_file or not IfcStore.classification_file.by_type("IfcClassification"): - return False - props = bpy.context.scene.BIMClassificationProperties - name = IfcStore.classification_file.by_id(int(props.available_classifications)).Name - return name in [e.Name for e in tool.Ifc.get().by_type("IfcClassification")] + def load(cls): + cls.is_loaded = True + cls.data["references"] = cls.references() + cls.data["is_available_classification_added"] = cls.is_available_classification_added() + + @classmethod + def references(cls): + results = [] + element = tool.Ifc.get_entity(bpy.context.active_object.active_material) + if element: + for reference in ifcopenshell.util.classification.get_references(element): + data = reference.get_info() + del data["ReferencedSource"] + results.append(data) + return results diff --git a/src/blenderbim/blenderbim/bim/module/classification/operator.py b/src/blenderbim/blenderbim/bim/module/classification/operator.py index b0617b7370..d9b1b56845 100644 --- a/src/blenderbim/blenderbim/bim/module/classification/operator.py +++ b/src/blenderbim/blenderbim/bim/module/classification/operator.py @@ -163,16 +163,33 @@ class RemoveClassificationReference(bpy.types.Operator, tool.Ifc.Operator): bl_options = {"REGISTER", "UNDO"} reference: bpy.props.IntProperty() obj: bpy.props.StringProperty() + obj_type: bpy.props.StringProperty() def _execute(self, context): obj = bpy.data.objects.get(self.obj) if self.obj else context.active_object - self.file = IfcStore.get_file() - ifcopenshell.api.run( - "classification.remove_reference", - self.file, - reference=self.file.by_id(self.reference), - product=self.file.by_id(obj.BIMObjectProperties.ifc_definition_id), - ) + if self.obj_type == "Object": + if context.selected_objects: + objects = [o.name for o in context.selected_objects] + else: + objects = [context.active_object.name] + else: + objects = [self.obj] + + identification = tool.Ifc.get().by_id(self.reference)[0] + + for obj in objects: + ifc_definition_id = blenderbim.bim.helper.get_obj_ifc_definition_id(context, obj, self.obj_type) + element = tool.Ifc.get().by_id(ifc_definition_id) + references = ifcopenshell.util.classification.get_references(element, should_inherit=False) + for reference in references: + if reference[0] == identification: + ifcopenshell.api.run( + "classification.remove_reference", + tool.Ifc.get(), + reference=reference, + product=element, + ) + break class EditClassificationReference(bpy.types.Operator, tool.Ifc.Operator): @@ -194,7 +211,8 @@ class EditClassificationReference(bpy.types.Operator, tool.Ifc.Operator): ifcopenshell.api.run( "classification.edit_reference", self.file, - reference=self.file.by_id(props.active_reference_id), attributes=attributes, + reference=self.file.by_id(props.active_reference_id), + attributes=attributes, ) bpy.ops.bim.disable_editing_classification_reference() @@ -205,11 +223,16 @@ class AddClassificationReference(bpy.types.Operator, tool.Ifc.Operator): bl_options = {"REGISTER", "UNDO"} reference: bpy.props.IntProperty() obj: bpy.props.StringProperty() + obj_type: bpy.props.StringProperty() def _execute(self, context): - obj = bpy.data.objects.get(self.obj) if self.obj else context.active_object - self.file = IfcStore.get_file() - + if self.obj_type == "Object": + if context.selected_objects: + objects = [o.name for o in context.selected_objects] + else: + objects = [context.active_object.name] + else: + objects = [self.obj] props = context.scene.BIMClassificationProperties classification = None classification_name = IfcStore.classification_file.by_id(int(props.available_classifications)).Name @@ -218,13 +241,17 @@ class AddClassificationReference(bpy.types.Operator, tool.Ifc.Operator): classification = element break - ifcopenshell.api.run( - "classification.add_reference", - self.file, - reference=IfcStore.classification_file.by_id(self.reference), - product=tool.Ifc.get_entity(obj), - classification=classification, - ) + for obj in objects: + ifc_definition_id = blenderbim.bim.helper.get_obj_ifc_definition_id(context, obj, self.obj_type) + if not ifc_definition_id: + continue + ifcopenshell.api.run( + "classification.add_reference", + tool.Ifc.get(), + reference=IfcStore.classification_file.by_id(self.reference), + product=tool.Ifc.get().by_id(ifc_definition_id), + classification=classification, + ) class ChangeClassificationLevel(bpy.types.Operator): diff --git a/src/blenderbim/blenderbim/bim/module/classification/prop.py b/src/blenderbim/blenderbim/bim/module/classification/prop.py index 71d8f7c53b..eee7b14952 100644 --- a/src/blenderbim/blenderbim/bim/module/classification/prop.py +++ b/src/blenderbim/blenderbim/bim/module/classification/prop.py @@ -32,6 +32,7 @@ from bpy.props import ( CollectionProperty, ) + def get_available_classifications(self, context): if not ClassificationsData.is_loaded: ClassificationsData.load() diff --git a/src/blenderbim/blenderbim/bim/module/classification/ui.py b/src/blenderbim/blenderbim/bim/module/classification/ui.py index 77c7ed2764..d54867e012 100644 --- a/src/blenderbim/blenderbim/bim/module/classification/ui.py +++ b/src/blenderbim/blenderbim/bim/module/classification/ui.py @@ -21,7 +21,11 @@ import blenderbim.tool as tool import blenderbim.bim.module.classification.prop as classification_prop from bpy.types import Panel, UIList from blenderbim.bim.ifc import IfcStore -from blenderbim.bim.module.classification.data import ClassificationsData, ClassificationReferencesData +from blenderbim.bim.module.classification.data import ( + ClassificationsData, + ClassificationReferencesData, + MaterialClassificationsData, +) class BIM_PT_classifications(Panel): @@ -74,25 +78,8 @@ class BIM_PT_classifications(Panel): row.operator("bim.remove_classification", text="", icon="X").classification = classification["id"] -class BIM_PT_classification_references(Panel): - bl_label = "IFC Classification References" - bl_idname = "BIM_PT_classification_references" - bl_options = {"DEFAULT_CLOSED"} - bl_space_type = "PROPERTIES" - bl_region_type = "WINDOW" - bl_context = "object" - bl_parent_id = "BIM_PT_object_metadata" - - @classmethod - def poll(cls, context): - if not context.active_object: - return False - return bool(tool.Ifc.get_entity(context.active_object)) - - def draw(self, context): - if not ClassificationReferencesData.is_loaded: - ClassificationReferencesData.load() - +class ReferenceUI: + def draw_ui(self, context): obj = context.active_object self.oprops = obj.BIMObjectProperties self.sprops = context.scene.BIMClassificationProperties @@ -101,18 +88,18 @@ class BIM_PT_classification_references(Panel): self.draw_add_ui(context) - if not ClassificationReferencesData.data["references"]: + if not self.data.data["references"]: row = self.layout.row(align=True) row.label(text="No References") - for reference in ClassificationReferencesData.data["references"]: + for reference in self.data.data["references"]: if self.props.active_reference_id == reference["id"]: self.draw_editable_ui() else: - self.draw_ui(reference) + self.draw_reference_ui(reference) def draw_add_ui(self, context): - if not ClassificationReferencesData.data["is_available_classification_added"]: + if not self.data.data["is_available_classification_added"]: return row = self.layout.row(align=True) row.prop(self.sprops, "available_classifications", text="") @@ -125,6 +112,8 @@ class BIM_PT_classification_references(Panel): op.parent_id = self.sprops.active_library_referenced_source if self.sprops.active_library_reference_index < len(self.sprops.available_library_references): op = row.operator("bim.add_classification_reference", text="", icon="ADD") + op.obj = self.obj + op.obj_type = self.obj_type op.reference = self.sprops.available_library_references[ self.sprops.active_library_reference_index ].ifc_definition_id @@ -144,7 +133,7 @@ class BIM_PT_classification_references(Panel): row.operator("bim.disable_editing_classification_reference", text="", icon="CANCEL") blenderbim.bim.helper.draw_attributes(self.props.reference_attributes, self.layout) - def draw_ui(self, reference): + def draw_reference_ui(self, reference): row = self.layout.row(align=True) if self.file.schema == "IFC2X3": name = reference["ItemReference"] or "No Identification" @@ -155,7 +144,60 @@ class BIM_PT_classification_references(Panel): if not self.props.active_reference_id: op = row.operator("bim.enable_editing_classification_reference", text="", icon="GREASEPENCIL") op.reference = reference["id"] - row.operator("bim.remove_classification_reference", text="", icon="X").reference = reference["id"] + op = row.operator("bim.remove_classification_reference", text="", icon="X") + op.reference = reference["id"] + op.obj = self.obj + op.obj_type = self.obj_type + + +class BIM_PT_classification_references(Panel, ReferenceUI): + bl_label = "IFC Classification References" + bl_idname = "BIM_PT_classification_references" + bl_options = {"DEFAULT_CLOSED"} + bl_space_type = "PROPERTIES" + bl_region_type = "WINDOW" + bl_context = "object" + bl_parent_id = "BIM_PT_object_metadata" + + @classmethod + def poll(cls, context): + if not context.active_object: + return False + return bool(tool.Ifc.get_entity(context.active_object)) + + def draw(self, context): + if not ClassificationReferencesData.is_loaded: + ClassificationReferencesData.load() + self.data = ClassificationReferencesData + self.obj = context.active_object.name + self.obj_type = "Object" + self.draw_ui(context) + + +class BIM_PT_material_classifications(Panel, ReferenceUI): + bl_label = "IFC Material Classifications" + bl_idname = "BIM_PT_material_classifications" + bl_options = {"DEFAULT_CLOSED"} + bl_space_type = "PROPERTIES" + bl_region_type = "WINDOW" + bl_context = "material" + + @classmethod + def poll(cls, context): + if not tool.Ifc.get(): + return False + try: + return bool(context.active_object.active_material.BIMObjectProperties.ifc_definition_id) + except: + return False + + def draw(self, context): + if not MaterialClassificationsData.is_loaded: + MaterialClassificationsData.load() + self.data = MaterialClassificationsData + self.obj = context.active_object.active_material.name + self.obj_type = "Material" + self.draw_ui(context) class BIM_UL_classifications(UIList): diff --git a/src/blenderbim/test/bim/feature/classification.feature b/src/blenderbim/test/bim/feature/classification.feature index d77d87184a..16a270d987 100644 --- a/src/blenderbim/test/bim/feature/classification.feature +++ b/src/blenderbim/test/bim/feature/classification.feature @@ -64,7 +64,7 @@ Scenario: Edit classification When I press "bim.edit_classification" Then nothing happens -Scenario: Add classification reference +Scenario: Add classification reference - object Given an empty IFC project And I press "bim.load_classification_library(filepath='{cwd}/test/files/classification.ifc')" And the variable "classification" is "{classification_ifc}.by_type('IfcClassification')[0].id()" @@ -77,7 +77,7 @@ Scenario: Add classification reference And I press "bim.assign_class" And I press "bim.change_classification_level(parent_id={classification})" And the variable "reference" is "{classification_ifc}.by_type('IfcClassificationReference')[0].id()" - When I press "bim.add_classification_reference(reference={reference})" + When I press "bim.add_classification_reference(reference={reference}, obj='IfcWallType/Cube', obj_type='Object')" Then nothing happens Scenario: Change classification level @@ -124,7 +124,7 @@ Scenario: Enable editing classification reference And I press "bim.assign_class" And I press "bim.change_classification_level(parent_id={classification})" And the variable "reference" is "{classification_ifc}.by_type('IfcClassificationReference')[0].id()" - And I press "bim.add_classification_reference(reference={reference})" + And I press "bim.add_classification_reference(reference={reference}, obj='IfcWallType/Cube', obj_type='Object')" And the variable "reference" is "{ifc}.by_type('IfcClassificationReference')[0].id()" When I press "bim.enable_editing_classification_reference(reference={reference})" Then nothing happens @@ -142,13 +142,13 @@ Scenario: Disable editing classification reference And I press "bim.assign_class" And I press "bim.change_classification_level(parent_id={classification})" And the variable "reference" is "{classification_ifc}.by_type('IfcClassificationReference')[0].id()" - And I press "bim.add_classification_reference(reference={reference})" + And I press "bim.add_classification_reference(reference={reference}, obj='IfcWallType/Cube', obj_type='Object')" And the variable "reference" is "{ifc}.by_type('IfcClassificationReference')[0].id()" And I press "bim.enable_editing_classification_reference(reference={reference})" When I press "bim.disable_editing_classification_reference" Then nothing happens -Scenario: Remove classification reference +Scenario: Remove classification reference - object Given an empty IFC project And I press "bim.load_classification_library(filepath='{cwd}/test/files/classification.ifc')" And the variable "classification" is "{classification_ifc}.by_type('IfcClassification')[0].id()" @@ -161,10 +161,10 @@ Scenario: Remove classification reference And I press "bim.assign_class" And I press "bim.change_classification_level(parent_id={classification})" And the variable "reference" is "{classification_ifc}.by_type('IfcClassificationReference')[0].id()" - And I press "bim.add_classification_reference(reference={reference})" + And I press "bim.add_classification_reference(reference={reference}, obj='IfcWallType/Cube', obj_type='Object')" And the variable "reference" is "{ifc}.by_type('IfcClassificationReference')[0].id()" And I press "bim.enable_editing_classification_reference(reference={reference})" - When I press "bim.remove_classification_reference(reference={reference})" + When I press "bim.remove_classification_reference(reference={reference}, obj='IfcWallType/Cube', obj_type='Object')" Then nothing happens Scenario: Edit classification reference @@ -180,8 +180,39 @@ Scenario: Edit classification reference And I press "bim.assign_class" And I press "bim.change_classification_level(parent_id={classification})" And the variable "reference" is "{classification_ifc}.by_type('IfcClassificationReference')[0].id()" - And I press "bim.add_classification_reference(reference={reference})" + And I press "bim.add_classification_reference(reference={reference}, obj='IfcWallType/Cube', obj_type='Object')" And the variable "reference" is "{ifc}.by_type('IfcClassificationReference')[0].id()" And I press "bim.enable_editing_classification_reference(reference={reference})" When I press "bim.edit_classification_reference" Then nothing happens + +Scenario: Add classification reference - material + Given an empty IFC project + And I press "bim.load_classification_library(filepath='{cwd}/test/files/classification.ifc')" + And the variable "classification" is "{classification_ifc}.by_type('IfcClassification')[0].id()" + And I set "scene.BIMClassificationProperties.available_classifications" to "{classification}" + And I press "bim.add_classification" + And I add a cube + And I add a material + And I press "bim.add_material(obj='Material')" + And the variable "material" is "{ifc}.by_type('IfcMaterial')[0].id()" + And I press "bim.change_classification_level(parent_id={classification})" + And the variable "reference" is "{classification_ifc}.by_type('IfcClassificationReference')[0].id()" + When I press "bim.add_classification_reference(reference={reference}, obj='Material', obj_type='Material')" + Then nothing happens + +Scenario: Remove classification reference - material + Given an empty IFC project + And I press "bim.load_classification_library(filepath='{cwd}/test/files/classification.ifc')" + And the variable "classification" is "{classification_ifc}.by_type('IfcClassification')[0].id()" + And I set "scene.BIMClassificationProperties.available_classifications" to "{classification}" + And I press "bim.add_classification" + And I add a cube + And I add a material + And I press "bim.add_material(obj='Material')" + And the variable "material" is "{ifc}.by_type('IfcMaterial')[0].id()" + And I press "bim.change_classification_level(parent_id={classification})" + And the variable "reference" is "{classification_ifc}.by_type('IfcClassificationReference')[0].id()" + And I press "bim.add_classification_reference(reference={reference}, obj='Material', obj_type='Material')" + When I press "bim.remove_classification_reference(reference={reference}, obj='Material', obj_type='Material')" + Then nothing happens