diff --git a/src/blenderbim/blenderbim/bim/ifc.py b/src/blenderbim/blenderbim/bim/ifc.py index 25fcdf9148..5b400d2284 100644 --- a/src/blenderbim/blenderbim/bim/ifc.py +++ b/src/blenderbim/blenderbim/bim/ifc.py @@ -84,7 +84,10 @@ class IfcStore: ifc_hash = hashlib.md5(ifc_key.encode("utf-8")).hexdigest() IfcStore.cache_path = os.path.join(bpy.context.scene.BIMProperties.data_dir, "cache", f"{ifc_hash}.h5") cache_settings = ifcopenshell.geom.settings() - IfcStore.cache = ifcopenshell.geom.serializers.hdf5(IfcStore.cache_path, cache_settings) + try: + IfcStore.cache = ifcopenshell.geom.serializers.hdf5(IfcStore.cache_path, cache_settings) + except: + return return IfcStore.cache @staticmethod @@ -255,7 +258,9 @@ class IfcStore: except: pass - if obj: + if element.is_a("IfcSurfaceStyle"): + obj.BIMMaterialProperties.ifc_style_id = 0 + elif obj: obj.BIMObjectProperties.ifc_definition_id = 0 @staticmethod diff --git a/src/blenderbim/blenderbim/bim/import_ifc.py b/src/blenderbim/blenderbim/bim/import_ifc.py index 331d43a782..8c9f181bde 100644 --- a/src/blenderbim/blenderbim/bim/import_ifc.py +++ b/src/blenderbim/blenderbim/bim/import_ifc.py @@ -625,7 +625,9 @@ class IfcImporter: ) else: iterator = ifcopenshell.geom.iterator(self.settings, self.file, include=products) - iterator.set_cache(IfcStore.get_cache()) + cache = IfcStore.get_cache() + if cache: + iterator.set_cache(cache) valid_file = iterator.initialize() if not valid_file: return results @@ -771,7 +773,9 @@ class IfcImporter: ) else: iterator = ifcopenshell.geom.iterator(self.settings_2d, self.file, include=products) - iterator.set_cache(IfcStore.get_cache()) + cache = IfcStore.get_cache() + if cache: + iterator.set_cache(cache) valid_file = iterator.initialize() if not valid_file: return results diff --git a/src/blenderbim/blenderbim/bim/module/root/operator.py b/src/blenderbim/blenderbim/bim/module/root/operator.py index 2f88a204a0..fab321445a 100644 --- a/src/blenderbim/blenderbim/bim/module/root/operator.py +++ b/src/blenderbim/blenderbim/bim/module/root/operator.py @@ -316,8 +316,8 @@ class UnlinkObject(bpy.types.Operator): IfcStore.unlink_element(obj=obj) for material_slot in obj.material_slots: if material_slot.material: - blenderbim.core.style.unlink_style(tool.Style, obj=material_slot.material) - blenderbim.core.material.unlink_material(tool.Material, obj=material_slot.material) + blenderbim.core.style.unlink_style(tool.Ifc, tool.Style, obj=material_slot.material) + blenderbim.core.material.unlink_material(tool.Ifc, obj=material_slot.material) if "Ifc" in obj.name and "/" in obj.name: obj.name = "/".join(obj.name.split("/")[1:]) return {"FINISHED"} diff --git a/src/blenderbim/blenderbim/bim/module/style/operator.py b/src/blenderbim/blenderbim/bim/module/style/operator.py index cc7c2d6b81..fdd23e47e7 100644 --- a/src/blenderbim/blenderbim/bim/module/style/operator.py +++ b/src/blenderbim/blenderbim/bim/module/style/operator.py @@ -63,7 +63,7 @@ class UnlinkStyle(bpy.types.Operator, Operator): bl_options = {"REGISTER", "UNDO"} def _execute(self, context): - core.unlink_style(tool.Style, obj=context.active_object.active_material) + core.unlink_style(tool.Ifc, tool.Style, obj=context.active_object.active_material) class EnableEditingStyle(bpy.types.Operator, Operator): diff --git a/src/blenderbim/blenderbim/core/style.py b/src/blenderbim/blenderbim/core/style.py index 6369034106..0cc161c0be 100644 --- a/src/blenderbim/blenderbim/core/style.py +++ b/src/blenderbim/blenderbim/core/style.py @@ -19,7 +19,7 @@ def add_style(ifc, style, obj=None): element = ifc.run("style.add_style", name=style.get_name(obj)) - style.link(element, obj) + ifc.link(element, obj) ifc.run( "style.add_surface_style", style=element, @@ -33,8 +33,9 @@ def add_style(ifc, style, obj=None): def remove_style(ifc, style, obj=None): - ifc.run("style.remove_style", style=style.get_style(obj)) - style.unlink(obj=obj) + element = style.get_style(obj) + ifc.unlink(obj=obj, element=element) + ifc.run("style.remove_style", style=element) def update_style_colours(ifc, style, obj=None): @@ -50,8 +51,8 @@ def update_style_colours(ifc, style, obj=None): ifc.run("style.edit_surface_style", style=shading_style, attributes=attributes) -def unlink_style(style, obj=None): - style.unlink(obj) +def unlink_style(ifc, style, obj=None): + ifc.unlink(obj=obj, element=style.get_style(obj)) def enable_editing_style(style, obj=None): diff --git a/src/blenderbim/blenderbim/core/tool.py b/src/blenderbim/blenderbim/core/tool.py index b4f3fadb8c..41901ebde4 100644 --- a/src/blenderbim/blenderbim/core/tool.py +++ b/src/blenderbim/blenderbim/core/tool.py @@ -226,8 +226,6 @@ class Style: def get_surface_shading_attributes(cls, obj): pass def get_surface_shading_style(cls, obj): pass def import_surface_attributes(cls, style, obj): pass - def link(cls, style, obj): pass - def unlink(cls, obj): pass @interface diff --git a/src/blenderbim/blenderbim/tool/geometry.py b/src/blenderbim/blenderbim/tool/geometry.py index b39dd5900b..b56f09bfb7 100644 --- a/src/blenderbim/blenderbim/tool/geometry.py +++ b/src/blenderbim/blenderbim/tool/geometry.py @@ -36,7 +36,9 @@ class Geometry(blenderbim.core.tool.Geometry): @classmethod def clear_cache(cls, element): - IfcStore.get_cache().remove(element.GlobalId) + cache = IfcStore.get_cache() + if cache: + cache.remove(element.GlobalId) @classmethod def clear_modifiers(cls, obj): @@ -224,7 +226,7 @@ class Geometry(blenderbim.core.tool.Geometry): def replace_object_with_empty(cls, obj): element = tool.Ifc.get_entity(obj) name = obj.name - tool.Ifc.unlink(obj) + tool.Ifc.unlink(obj=obj, element=element) obj.name = ifcopenshell.guid.new() new_obj = bpy.data.objects.new(name, None) if element: diff --git a/src/blenderbim/blenderbim/tool/style.py b/src/blenderbim/blenderbim/tool/style.py index 116b121654..a0d3e5cbf8 100644 --- a/src/blenderbim/blenderbim/tool/style.py +++ b/src/blenderbim/blenderbim/tool/style.py @@ -108,11 +108,3 @@ class Style(blenderbim.core.tool.Style): def import_surface_attributes(cls, style, obj): obj.BIMStyleProperties.attributes.clear() blenderbim.bim.helper.import_attributes2(style, obj.BIMStyleProperties.attributes) - - @classmethod - def link(cls, style, obj): - obj.BIMMaterialProperties.ifc_style_id = style.id() - - @classmethod - def unlink(self, obj): - obj.BIMMaterialProperties.ifc_style_id = 0 diff --git a/src/blenderbim/test/bim/feature/project.feature b/src/blenderbim/test/bim/feature/project.feature index ef76a7e0ac..508fdd92ea 100644 --- a/src/blenderbim/test/bim/feature/project.feature +++ b/src/blenderbim/test/bim/feature/project.feature @@ -387,3 +387,17 @@ Scenario: Export IFC - with changed object scale synchronised And an empty Blender session is started And I press "bim.load_project(filepath='{cwd}/test/files/export.ifc')" Then the object "IfcWall/Cube" dimensions are "4,4,4" + +Scenario: Export IFC - with changed style colour synchronised + Given an empty IFC project + And I add a cube + And the object "Cube" is selected + And I add a material + And I set "scene.BIMRootProperties.ifc_class" to "IfcWall" + And I press "bim.assign_class" + And the object "IfcWall/Cube" is selected + When the material "Material" colour is set to "1,0,0,1" + And I press "export_ifc.bim(filepath='{cwd}/test/files/export.ifc')" + And an empty Blender session is started + And I press "bim.load_project(filepath='{cwd}/test/files/export.ifc')" + Then the material "Material" colour is "1,0,0,1" diff --git a/src/blenderbim/test/bim/test_feature.py b/src/blenderbim/test/bim/test_feature.py index 254a7c14c9..251640514e 100644 --- a/src/blenderbim/test/bim/test_feature.py +++ b/src/blenderbim/test/bim/test_feature.py @@ -95,6 +95,14 @@ def i_add_a_material(): bpy.context.active_object.active_material = bpy.data.materials.new("Material") +@given(parsers.parse('the material "{name}" colour is set to "{colour}"')) +@when(parsers.parse('the material "{name}" colour is set to "{colour}"')) +def the_material_name_colour_is_set_to_colour(name, colour): + obj = the_material_name_exists(name) + obj.diffuse_color = [float(c) for c in colour.split(",")] + blenderbim.bim.handler.color_callback(obj, None) + + @given("I add an array modifier") def i_add_a_cube(): bpy.ops.object.modifier_add(type="ARRAY") @@ -385,6 +393,12 @@ def the_material_name_is_not_an_ifc_material(name): assert id == 0, f"The ID is {id}" +@then(parsers.parse('the material "{name}" colour is "{colour}"')) +def the_material_name_colour_is_set_to_colour(name, colour): + diffuse_color = list(the_material_name_exists(name).diffuse_color) + assert diffuse_color == [float(c) for c in colour.split(",")], f"The colour is {diffuse_color}" + + @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/test_style.py b/src/blenderbim/test/core/test_style.py index 298434335c..64dc5adea8 100644 --- a/src/blenderbim/test/core/test_style.py +++ b/src/blenderbim/test/core/test_style.py @@ -24,7 +24,7 @@ class TestAddStyle: def predict(self, ifc, style, obj="obj"): style.get_name(obj).should_be_called().will_return("name") ifc.run("style.add_style", name="name").should_be_called().will_return("style") - style.link("style", obj).should_be_called() + ifc.link("style", obj).should_be_called() style.get_surface_rendering_attributes(obj).should_be_called().will_return("attributes") ifc.run( "style.add_surface_style", style="style", ifc_class="IfcSurfaceStyleRendering", attributes="attributes" @@ -38,7 +38,7 @@ class TestAddStyle: def test_adding_a_style_linked_to_a_material(self, ifc, style): style.get_name("obj").should_be_called().will_return("name") ifc.run("style.add_style", name="name").should_be_called().will_return("style") - style.link("style", "obj").should_be_called() + ifc.link("style", "obj").should_be_called() style.get_surface_rendering_attributes("obj").should_be_called().will_return("attributes") ifc.run( "style.add_surface_style", style="style", ifc_class="IfcSurfaceStyleRendering", attributes="attributes" @@ -52,8 +52,8 @@ class TestAddStyle: class TestRemoveStyle: def test_run(self, ifc, style): style.get_style("obj").should_be_called().will_return("style") + ifc.unlink(obj="obj", element="style").should_be_called() ifc.run("style.remove_style", style="style").should_be_called() - style.unlink(obj="obj").should_be_called() subject.remove_style(ifc, style, obj="obj") @@ -73,9 +73,10 @@ class TestUpdateStyleColours: class TestUnlinkStyle: - def test_run(self, style): - style.unlink("obj").should_be_called() - subject.unlink_style(style, obj="obj") + def test_run(self, ifc, style): + style.get_style("obj").should_be_called().will_return("style") + ifc.unlink(obj="obj", element="style").should_be_called() + subject.unlink_style(ifc, style, obj="obj") class TestEnableEditingStyle: diff --git a/src/blenderbim/test/tool/test_ifc.py b/src/blenderbim/test/tool/test_ifc.py index fa805371a0..0501618bec 100644 --- a/src/blenderbim/test/tool/test_ifc.py +++ b/src/blenderbim/test/tool/test_ifc.py @@ -119,6 +119,26 @@ class TestLink(test.bim.bootstrap.NewFile): assert subject.get_entity(obj) == element assert subject.get_object(element) == obj + def test_link_a_style(self): + ifc = ifcopenshell.file() + subject.set(ifc) + element = ifc.createIfcSurfaceStyle() + obj = bpy.data.materials.new("Material") + subject.link(element, obj) + assert subject.get_object(element) == obj + + def test_link_a_material_and_style(self): + ifc = ifcopenshell.file() + subject.set(ifc) + style = ifc.createIfcSurfaceStyle() + material = ifc.createIfcMaterial() + obj = bpy.data.materials.new("Material") + subject.link(style, obj) + subject.link(material, obj) + assert subject.get_entity(obj) == material + assert subject.get_object(style) == obj + assert subject.get_object(material) == obj + class TestUnlink(test.bim.bootstrap.NewFile): def test_unlink_an_object(self): @@ -141,6 +161,31 @@ class TestUnlink(test.bim.bootstrap.NewFile): assert subject.get_entity(obj) is None assert subject.get_object(element) is None + def test_unlink_a_style(self): + ifc = ifcopenshell.file() + subject.set(ifc) + element = ifc.createIfcSurfaceStyle() + obj = bpy.data.materials.new("Material") + subject.link(element, obj) + subject.unlink(element, obj) + assert subject.get_object(element) is None + + def test_unlink_a_style_and_material(self): + ifc = ifcopenshell.file() + subject.set(ifc) + style = ifc.createIfcSurfaceStyle() + material = ifc.createIfcMaterial() + obj = bpy.data.materials.new("Material") + subject.link(style, obj) + subject.link(material, obj) + subject.unlink(element=style, obj=obj) + assert subject.get_entity(obj) == material + assert subject.get_object(material) == obj + assert subject.get_object(style) is None + subject.unlink(element=material, obj=obj) + assert subject.get_entity(obj) is None + assert subject.get_object(material) is None + def test_unlinking_using_an_object(self): ifc = ifcopenshell.file() subject.set(ifc) diff --git a/src/blenderbim/test/tool/test_style.py b/src/blenderbim/test/tool/test_style.py index 6071d49e2e..d297eb9abe 100644 --- a/src/blenderbim/test/tool/test_style.py +++ b/src/blenderbim/test/tool/test_style.py @@ -189,22 +189,3 @@ class TestImportSurfaceAttributes(NewFile): assert len(obj.BIMStyleProperties.attributes) == 2 assert obj.BIMStyleProperties.attributes.get("Name").string_value == "Name" assert obj.BIMStyleProperties.attributes.get("Side").enum_value == "BOTH" - - -class TestLink(NewFile): - def test_run(self): - obj = bpy.data.materials.new("Material") - ifc = ifcopenshell.file() - style = ifc.createIfcSurfaceStyle() - subject.link(style, obj) - assert obj.BIMMaterialProperties.ifc_style_id == style.id() - - -class TestUnlink(NewFile): - def test_run(self): - obj = bpy.data.materials.new("Material") - ifc = ifcopenshell.file() - style = ifc.createIfcSurfaceStyle() - subject.link(style, obj) - subject.unlink(obj) - assert obj.BIMMaterialProperties.ifc_style_id == 0