From 26cbd82da1ee988e79af4276dd32af991b4678a6 Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Sat, 16 Oct 2021 16:52:47 +1100 Subject: [PATCH] New feature to unlink Blender materials and IFC materials --- .../bim/module/material/__init__.py | 31 ++++++------- .../bim/module/material/operator.py | 18 ++++++++ .../blenderbim/bim/module/material/ui.py | 3 +- src/blenderbim/blenderbim/core/material.py | 21 +++++++++ src/blenderbim/blenderbim/core/tool.py | 5 +++ src/blenderbim/blenderbim/tool/__init__.py | 1 + src/blenderbim/blenderbim/tool/material.py | 32 ++++++++++++++ src/blenderbim/pytest.ini | 1 + .../test/bim/feature/material.feature | 11 +++++ src/blenderbim/test/bim/feature/style.feature | 2 +- src/blenderbim/test/bim/test_feature.py | 20 +++++++++ src/blenderbim/test/core/bootstrap.py | 7 +++ src/blenderbim/test/core/test_material.py | 26 +++++++++++ src/blenderbim/test/tool/test_container.py | 2 +- src/blenderbim/test/tool/test_material.py | 43 +++++++++++++++++++ 15 files changed, 205 insertions(+), 18 deletions(-) create mode 100644 src/blenderbim/blenderbim/core/material.py create mode 100644 src/blenderbim/blenderbim/tool/material.py create mode 100644 src/blenderbim/test/bim/feature/material.feature create mode 100644 src/blenderbim/test/core/test_material.py create mode 100644 src/blenderbim/test/tool/test_material.py diff --git a/src/blenderbim/blenderbim/bim/module/material/__init__.py b/src/blenderbim/blenderbim/bim/module/material/__init__.py index aac236d890..cb1794481b 100644 --- a/src/blenderbim/blenderbim/bim/module/material/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/material/__init__.py @@ -20,27 +20,28 @@ import bpy from . import ui, prop, operator classes = ( - operator.CopyMaterial, - operator.AddMaterial, - operator.RemoveMaterial, - operator.AssignMaterial, - operator.UnassignMaterial, operator.AddConstituent, - operator.RemoveConstituent, - operator.AddProfile, - operator.RemoveProfile, - operator.AssignParameterizedProfile, operator.AddLayer, - operator.RemoveLayer, - operator.ReorderMaterialSetItem, operator.AddListItem, - operator.RemoveListItem, - operator.EnableEditingAssignedMaterial, + operator.AddMaterial, + operator.AddProfile, + operator.AssignMaterial, + operator.AssignParameterizedProfile, + operator.CopyMaterial, operator.DisableEditingAssignedMaterial, - operator.EditAssignedMaterial, - operator.EnableEditingMaterialSetItem, operator.DisableEditingMaterialSetItem, + operator.EditAssignedMaterial, operator.EditMaterialSetItem, + operator.EnableEditingAssignedMaterial, + operator.EnableEditingMaterialSetItem, + operator.RemoveConstituent, + operator.RemoveLayer, + operator.RemoveListItem, + operator.RemoveMaterial, + operator.RemoveProfile, + operator.ReorderMaterialSetItem, + operator.UnassignMaterial, + operator.UnlinkMaterial, prop.BIMObjectMaterialProperties, ui.BIM_PT_material, ui.BIM_PT_object_material, diff --git a/src/blenderbim/blenderbim/bim/module/material/operator.py b/src/blenderbim/blenderbim/bim/module/material/operator.py index d72b86bbe8..7cc6818c3c 100644 --- a/src/blenderbim/blenderbim/bim/module/material/operator.py +++ b/src/blenderbim/blenderbim/bim/module/material/operator.py @@ -23,12 +23,21 @@ import ifcopenshell.util.element import ifcopenshell.util.attribute import ifcopenshell.util.representation import blenderbim.bim.helper +import blenderbim.tool as tool +import blenderbim.core.material as core 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 from ifcopenshell.api.profile.data import Data as ProfileData +class Operator: + def execute(self, context): + IfcStore.execute_ifc_operator(self, context) + blenderbim.bim.handler.refresh_ui_data() + return {"FINISHED"} + + class AssignParameterizedProfile(bpy.types.Operator): bl_idname = "bim.assign_parameterized_profile" bl_label = "Assign Parameterized Profile" @@ -112,6 +121,15 @@ class RemoveMaterial(bpy.types.Operator): return {"FINISHED"} +class UnlinkMaterial(bpy.types.Operator, Operator): + bl_idname = "bim.unlink_material" + bl_label = "Unlink Material" + bl_options = {"REGISTER", "UNDO"} + + def _execute(self, context): + core.unlink_material(tool.Material, obj=context.active_object.active_material) + + class AssignMaterial(bpy.types.Operator): bl_idname = "bim.assign_material" bl_label = "Assign Material" diff --git a/src/blenderbim/blenderbim/bim/module/material/ui.py b/src/blenderbim/blenderbim/bim/module/material/ui.py index 02254312b5..f3cb954d33 100644 --- a/src/blenderbim/blenderbim/bim/module/material/ui.py +++ b/src/blenderbim/blenderbim/bim/module/material/ui.py @@ -36,9 +36,10 @@ class BIM_PT_material(Panel): return IfcStore.get_file() and context.active_object and context.active_object.active_material def draw(self, context): - row = self.layout.row() + row = self.layout.row(align=True) if bool(context.active_object.active_material.BIMObjectProperties.ifc_definition_id): row.operator("bim.remove_material", icon="X", text="Remove IFC Material") + row.operator("bim.unlink_material", icon="UNLINKED", text="") else: row.operator("bim.add_material", icon="ADD", text="Create IFC Material") diff --git a/src/blenderbim/blenderbim/core/material.py b/src/blenderbim/blenderbim/core/material.py new file mode 100644 index 0000000000..2707616ccc --- /dev/null +++ b/src/blenderbim/blenderbim/core/material.py @@ -0,0 +1,21 @@ +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + + +def unlink_material(material, obj=None): + material.unlink(obj) diff --git a/src/blenderbim/blenderbim/core/tool.py b/src/blenderbim/blenderbim/core/tool.py index 7a623024a5..2a6d19e7f8 100644 --- a/src/blenderbim/blenderbim/core/tool.py +++ b/src/blenderbim/blenderbim/core/tool.py @@ -72,6 +72,11 @@ class Ifc: def unlink(cls, element=None, obj=None): pass +@interface +class Material: + def unlink(cls, obj): pass + + @interface class Owner: def add_address_attribute(cls, name): pass diff --git a/src/blenderbim/blenderbim/tool/__init__.py b/src/blenderbim/blenderbim/tool/__init__.py index 04cd36f721..94c387d29f 100644 --- a/src/blenderbim/blenderbim/tool/__init__.py +++ b/src/blenderbim/blenderbim/tool/__init__.py @@ -22,6 +22,7 @@ from blenderbim.tool.collector import Collector from blenderbim.tool.container import Container from blenderbim.tool.context import Context from blenderbim.tool.ifc import Ifc +from blenderbim.tool.material import Material from blenderbim.tool.owner import Owner from blenderbim.tool.style import Style from blenderbim.tool.surveyor import Surveyor diff --git a/src/blenderbim/blenderbim/tool/material.py b/src/blenderbim/blenderbim/tool/material.py new file mode 100644 index 0000000000..f4ef4821c2 --- /dev/null +++ b/src/blenderbim/blenderbim/tool/material.py @@ -0,0 +1,32 @@ +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + +import ifcopenshell +import blenderbim.core.tool +import blenderbim.tool as tool +import blenderbim.bim.helper + + +class Material(blenderbim.core.tool.Material): + @classmethod + def link(cls, material, obj): + obj.BIMObjectProperties.ifc_definition_id = material.id() + + @classmethod + def unlink(self, obj): + obj.BIMObjectProperties.ifc_definition_id = 0 diff --git a/src/blenderbim/pytest.ini b/src/blenderbim/pytest.ini index 0fc7461a14..a4662b9470 100644 --- a/src/blenderbim/pytest.ini +++ b/src/blenderbim/pytest.ini @@ -3,6 +3,7 @@ markers = aggregate context geometry + material owner project pset_template diff --git a/src/blenderbim/test/bim/feature/material.feature b/src/blenderbim/test/bim/feature/material.feature new file mode 100644 index 0000000000..6fc0a3cbaf --- /dev/null +++ b/src/blenderbim/test/bim/feature/material.feature @@ -0,0 +1,11 @@ +@material +Feature: Material + +Scenario: Unlink object + Given an empty IFC project + And I add a cube + And the object "Cube" is selected + And I add a material + And I press "bim.add_material" + When I press "bim.unlink_material" + Then the material "Material" is not an IFC material diff --git a/src/blenderbim/test/bim/feature/style.feature b/src/blenderbim/test/bim/feature/style.feature index b8fae4472b..2c861f6003 100644 --- a/src/blenderbim/test/bim/feature/style.feature +++ b/src/blenderbim/test/bim/feature/style.feature @@ -30,7 +30,7 @@ Scenario: Unlink style And I add a material And I press "bim.add_style" When I press "bim.unlink_style" - Then nothing happens + Then the material "Material" is not an IFC style Scenario: Enable editing style Given an empty IFC project diff --git a/src/blenderbim/test/bim/test_feature.py b/src/blenderbim/test/bim/test_feature.py index 1749ed55eb..cdc9349fc5 100644 --- a/src/blenderbim/test/bim/test_feature.py +++ b/src/blenderbim/test/bim/test_feature.py @@ -159,6 +159,14 @@ def the_object_name_exists(name) -> bpy.types.Object: return obj +@then(parsers.parse('the material "{name}" exists')) +def the_material_name_exists(name) -> bpy.types.Material: + obj = bpy.data.materials.get(name) + if not obj: + assert False, f'The material "{name}" does not exist' + return obj + + @then("an IFC file does not exist") def an_ifc_file_does_not_exist(): ifc = IfcStore.get_file() @@ -249,6 +257,18 @@ def the_object_name_is_not_an_ifc_element(name): assert id == 0, f"The ID is {id}" +@then(parsers.parse('the material "{name}" is not an IFC material')) +def the_material_name_is_not_an_ifc_material(name): + id = the_material_name_exists(name).BIMObjectProperties.ifc_definition_id + assert id == 0, f"The ID is {id}" + + +@then(parsers.parse('the material "{name}" is not an IFC style')) +def the_material_name_is_not_an_ifc_material(name): + id = the_material_name_exists(name).BIMMaterialProperties.ifc_style_id + assert id == 0, f"The ID is {id}" + + @then(parsers.parse('the object "{name}" has "{number}" vertices')) def the_object_name_has_number_vertices(name, number): total = len(the_object_name_exists(name).data.vertices) diff --git a/src/blenderbim/test/core/bootstrap.py b/src/blenderbim/test/core/bootstrap.py index 2921c6d8dd..f9e50bfca2 100644 --- a/src/blenderbim/test/core/bootstrap.py +++ b/src/blenderbim/test/core/bootstrap.py @@ -49,6 +49,13 @@ def context(): prophet.verify() +@pytest.fixture +def material(): + prophet = Prophecy(blenderbim.core.tool.Material) + yield prophet + prophet.verify() + + @pytest.fixture def owner(): prophet = Prophecy(blenderbim.core.tool.Owner) diff --git a/src/blenderbim/test/core/test_material.py b/src/blenderbim/test/core/test_material.py new file mode 100644 index 0000000000..fdea88b98c --- /dev/null +++ b/src/blenderbim/test/core/test_material.py @@ -0,0 +1,26 @@ +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + +import blenderbim.core.material as subject +from test.core.bootstrap import ifc, material + + +class TestUnlinkMaterial: + def test_run(self, material): + material.unlink("obj").should_be_called() + subject.unlink_material(material, obj="obj") diff --git a/src/blenderbim/test/tool/test_container.py b/src/blenderbim/test/tool/test_container.py index e642b0d068..5ed8b91ab5 100644 --- a/src/blenderbim/test/tool/test_container.py +++ b/src/blenderbim/test/tool/test_container.py @@ -127,7 +127,7 @@ class TestImportContainers(NewFile): bpy.ops.bim.copy_class(obj=tool.Ifc.get_object(storey1).name) storey2 = tool.Ifc.get().by_type("IfcBuildingStorey")[1] storey2.Name = "Lower" - storey2.ObjectPlacement.RelativePlacement.Location.Coordinates = (0., 0., -100.) + storey2.ObjectPlacement.RelativePlacement.Location.Coordinates = (0.0, 0.0, -100.0) subject.import_containers(building) props = bpy.context.scene.BIMSpatialProperties assert len(props.containers) == 2 diff --git a/src/blenderbim/test/tool/test_material.py b/src/blenderbim/test/tool/test_material.py new file mode 100644 index 0000000000..4fcc0d5755 --- /dev/null +++ b/src/blenderbim/test/tool/test_material.py @@ -0,0 +1,43 @@ +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + +import bpy +import ifcopenshell +import blenderbim.core.tool +import blenderbim.tool as tool +from test.bim.bootstrap import NewFile +from blenderbim.tool.material import Material as subject + + +class TestLink(NewFile): + def test_run(self): + obj = bpy.data.materials.new("Material") + ifc = ifcopenshell.file() + material = ifc.createIfcMaterial() + subject.link(material, obj) + assert obj.BIMObjectProperties.ifc_definition_id == material.id() + + +class TestUnlink(NewFile): + def test_run(self): + obj = bpy.data.materials.new("Material") + ifc = ifcopenshell.file() + material = ifc.createIfcMaterial() + subject.link(material, obj) + subject.unlink(obj) + assert obj.BIMObjectProperties.ifc_definition_id == 0