ifc.unlink fixes after 3df75e9af

Also some changes related to #4843

add
This commit is contained in:
Andrej730
2024-06-14 12:25:40 +05:00
parent d0f612afc2
commit 75f8e75a8e
17 changed files with 64 additions and 84 deletions
+8 -3
View File
@@ -322,9 +322,7 @@ class IfcStore:
raise TypeError("Only one argument must be provided - element or obj.")
if obj:
if isinstance(obj, bpy.types.Material):
obj.BIMMaterialProperties.ifc_style_id = 0
obj.BIMObjectProperties.ifc_definition_id = 0
IfcStore.purge_blender_ifc_data(obj)
return
assert element # Type checker.
@@ -333,6 +331,7 @@ class IfcStore:
potential_obj = IfcStore.id_map[element.id()]
if tool.Blender.is_valid_data_block(potential_obj):
obj = potential_obj
IfcStore.purge_blender_ifc_data(obj)
except:
pass
@@ -355,6 +354,12 @@ class IfcStore:
Operation(rollback=IfcStore.rollback_unlink_element, commit=IfcStore.commit_unlink_element, data=data)
)
@staticmethod
def purge_blender_ifc_data(obj: IFC_CONNECTED_TYPE) -> None:
if isinstance(obj, bpy.types.Material):
obj.BIMMaterialProperties.ifc_style_id = 0
obj.BIMObjectProperties.ifc_definition_id = 0
@staticmethod
def execute_ifc_operator(operator: bpy.types.Operator, context: bpy.types.Context, is_invoke=False):
blenderbim.last_actions.append({"type": "operator", "name": operator.bl_idname})
@@ -551,9 +551,9 @@ class HideBoundaries(bpy.types.Operator, tool.Ifc.Operator):
for boundary in element.BoundedBy or []:
boundary_obj = tool.Ifc.get_object(boundary)
if boundary_obj:
to_delete.add(boundary_obj)
for boundary_obj in to_delete:
tool.Ifc.unlink(obj=boundary_obj)
to_delete.add((boundary, boundary_obj))
for boundary, boundary_obj in to_delete:
tool.Ifc.unlink(element=boundary)
bpy.data.objects.remove(boundary_obj)
context.scene.BIMBoundaryProperties.boundaries.clear()
return {"FINISHED"}
@@ -182,7 +182,7 @@ class RemoveMaterial(bpy.types.Operator, tool.Ifc.Operator):
material: bpy.props.IntProperty()
def _execute(self, context):
res = core.remove_material(tool.Ifc, tool.Material, tool.Style, material=tool.Ifc.get().by_id(self.material))
res = core.remove_material(tool.Ifc, tool.Material, material=tool.Ifc.get().by_id(self.material))
if not res:
self.report({"ERROR"}, "Material is used in material sets and cannot be removed.")
return {"CANCELLED"}
@@ -224,7 +224,7 @@ class FilledOpeningGenerator:
else:
opening_obj = tool.Ifc.get_object(opening)
if opening_obj:
tool.Ifc.unlink(obj=opening_obj)
tool.Ifc.unlink(element=opening)
bpy.data.objects.remove(opening_obj)
filling_obj = tool.Ifc.get_object(filling)
@@ -772,9 +772,9 @@ class HideOpenings(Operator, tool.Ifc.Operator):
for opening in openings:
opening_obj = tool.Ifc.get_object(opening)
if opening_obj:
to_delete.add(opening_obj)
for opening_obj in to_delete:
tool.Ifc.unlink(obj=opening_obj)
to_delete.add((opening, opening_obj))
for opening, opening_obj in to_delete:
tool.Ifc.unlink(element=opening)
bpy.data.objects.remove(opening_obj)
tool.Model.clear_scene_openings()
return {"FINISHED"}
@@ -824,7 +824,7 @@ class EditOpenings(Operator, tool.Ifc.Operator):
building_objs.update(
self.get_all_building_objects_of_similar_openings(opening)
) # NB this has nothing to do with clone similar_opening
tool.Ifc.unlink(element=opening, obj=opening_obj)
tool.Ifc.unlink(element=opening)
bpy.data.objects.remove(opening_obj)
tool.Model.reload_body_representation(building_objs)
@@ -80,7 +80,7 @@ class RemoveStyle(bpy.types.Operator, tool.Ifc.Operator):
style: bpy.props.IntProperty()
def _execute(self, context):
core.remove_style(tool.Ifc, tool.Material, tool.Style, style=tool.Ifc.get().by_id(self.style))
core.remove_style(tool.Ifc, tool.Style, style=tool.Ifc.get().by_id(self.style))
class AddStyle(bpy.types.Operator, tool.Ifc.Operator):
@@ -74,6 +74,7 @@ class AddOpening(bpy.types.Operator, tool.Ifc.Operator):
obj1, obj2 = obj2, obj1
element1, element2 = element2, element1
# element1 - voided element, element2 - opening.
if element1.is_a("IfcOpeningElement"):
self.report({"INFO"}, "You can't add an opening to another opening.")
continue
@@ -127,7 +128,7 @@ class AddOpening(bpy.types.Operator, tool.Ifc.Operator):
)
if not has_visible_openings:
tool.Ifc.unlink(obj=obj2)
tool.Ifc.unlink(element=element2)
bpy.data.objects.remove(obj2)
context.view_layer.objects.active = obj1
@@ -148,7 +149,7 @@ class RemoveOpening(bpy.types.Operator, tool.Ifc.Operator):
if opening_obj:
opening_obj.name = "/".join(opening_obj.name.split("/")[1:])
tool.Ifc.unlink(obj=opening_obj)
tool.Ifc.unlink(element=opening)
ifcopenshell.api.run("void.remove_opening", tool.Ifc.get(), opening=opening)
+6 -7
View File
@@ -58,17 +58,16 @@ def add_material_set(ifc: tool.Ifc, material: tool.Material, set_type: str) -> i
def remove_material(
ifc: tool.Ifc, material_tool: tool.Material, style: tool.Style, material: ifcopenshell.entity_instance
ifc: tool.Ifc, material_tool: tool.Material, material: ifcopenshell.entity_instance
) -> bool:
"""returns True after deleting False,\n
returns False if material used in material sets and cannot be removed"""
"""Remove an IFC material.
Return True if deletion succeeded,\n
return False if material is used in material sets and cannot be removed.
"""
if material_tool.is_material_used_in_sets(material):
return False
obj = ifc.get_object(material)
ifc.unlink(element=material)
ifc.run("material.remove_material", material=material)
if obj and not style.get_style(obj):
material_tool.delete_object(obj)
if material_tool.is_editing_materials():
material_tool.import_material_definitions(material_tool.get_active_material_type())
return True
+4 -6
View File
@@ -59,13 +59,12 @@ def update_external_style(
def remove_style(
ifc: tool.Ifc, material: tool.Material, style_tool: tool.Style, style: ifcopenshell.entity_instance
ifc: tool.Ifc, style_tool: tool.Style, style: ifcopenshell.entity_instance
) -> None:
obj = ifc.get_object(style)
ifc.unlink(obj=obj, element=style)
ifc.unlink(element=style)
ifc.run("style.remove_style", style=style)
if obj and not ifc.get_entity(obj):
material.delete_object(obj)
style_tool.delete_object(obj)
if style_tool.is_editing_styles():
style_tool.import_presentation_styles(style_tool.get_active_style_type())
@@ -130,8 +129,7 @@ def update_style_textures(
def unlink_style(ifc: tool.Ifc, style: ifcopenshell.entity_instance) -> None:
obj = ifc.get_object(style)
ifc.unlink(obj=obj, element=style)
ifc.unlink(element=style)
def enable_editing_style(style: tool.Style, obj: bpy.types.Material) -> None:
+1 -1
View File
@@ -39,6 +39,6 @@ def purge_unused_types(ifc, type):
ifc.run("root.remove_product", product=element_type)
purged_types += 1
if obj:
ifc.unlink(obj=obj)
ifc.unlink(element=element_type)
type.remove_object(obj)
return purged_types
+4 -1
View File
@@ -656,9 +656,12 @@ 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=obj, element=element)
if element:
tool.Ifc.unlink(element=element)
obj.name = ifcopenshell.guid.new()
new_obj = bpy.data.objects.new(name, None)
if element:
tool.Ifc.link(element, new_obj)
for collection in obj.users_collection:
+1
View File
@@ -191,6 +191,7 @@ class Ifc(blenderbim.core.tool.Ifc):
def unlink(
cls, element: Optional[ifcopenshell.entity_instance] = None, obj: Optional[IFC_CONNECTED_TYPE] = None
) -> None:
"""See IfcStore.unlink_element doc for details."""
IfcStore.unlink_element(element, obj)
@classmethod
@@ -38,10 +38,6 @@ class Material(blenderbim.core.tool.Material):
def add_default_material_object(cls, name: Union[str, None]) -> bpy.types.Material:
return bpy.data.materials.new(name or "Default")
@classmethod
def delete_object(cls, obj: bpy.types.Material) -> None:
bpy.data.materials.remove(obj)
@classmethod
def disable_editing_materials(cls) -> None:
bpy.context.scene.BIMMaterialProperties.is_editing = False
+8 -3
View File
@@ -344,12 +344,17 @@ class Root(blenderbim.core.tool.Root):
@classmethod
def unlink_object(cls, obj: bpy.types.Object) -> None:
"""Purge all IFC data associated with a Blender object.
This method is safe to run on objects from other Blender sessions
as it won't try to find related IFC elements from the IFC data
to unlink them.
"""
tool.Ifc.unlink(obj=obj)
if hasattr(obj.data, "BIMMeshProperties"):
obj.data.BIMMeshProperties.ifc_definition_id = 0
for material_slot in obj.material_slots:
if material_slot.material:
blenderbim.core.style.unlink_style(tool.Ifc, style=material_slot.material)
blenderbim.core.material.unlink_material(tool.Ifc, obj=material_slot.material)
if material := material_slot.material:
tool.Ifc.unlink(obj=material)
if "Ifc" in obj.name and "/" in obj.name:
obj.name = obj.name.split("/", 1)[1]
+4
View File
@@ -49,6 +49,10 @@ class Style(blenderbim.core.tool.Style):
def can_support_rendering_style(cls, obj: bpy.types.Material) -> bool:
return obj.use_nodes and hasattr(obj.node_tree, "nodes")
@classmethod
def delete_object(cls, obj: bpy.types.Material) -> None:
bpy.data.materials.remove(obj)
@classmethod
def disable_editing(cls, obj: bpy.types.Material) -> None:
obj.BIMStyleProperties.is_editing = False
+6 -29
View File
@@ -87,46 +87,23 @@ class TestAddMaterialSet:
class TestRemoveMaterial:
def test_removing_a_material(self, ifc, material, style):
def test_removing_a_material(self, ifc, material):
material.is_material_used_in_sets("material").should_be_called().will_return(False)
ifc.get_object("material").should_be_called().will_return(None)
ifc.unlink(element="material").should_be_called()
ifc.run("material.remove_material", material="material").should_be_called()
material.is_editing_materials().should_be_called().will_return(False)
subject.remove_material(ifc, material, style, material="material")
subject.remove_material(ifc, material, material="material")
def test_removing_a_material_and_reloading_imported_materials(self, ifc, material, style):
def test_removing_a_material_and_reloading_imported_materials(self, ifc, material):
material.is_material_used_in_sets("material").should_be_called().will_return(False)
ifc.get_object("material").should_be_called().will_return(None)
ifc.unlink(element="material").should_be_called()
ifc.run("material.remove_material", material="material").should_be_called()
material.is_editing_materials().should_be_called().will_return(True)
material.get_active_material_type().should_be_called().will_return("material_type")
material.import_material_definitions("material_type").should_be_called()
subject.remove_material(ifc, material, style, material="material")
subject.remove_material(ifc, material, material="material")
def test_removing_a_material_object_if_it_has_no_style(self, ifc, material, style):
material.is_material_used_in_sets("material").should_be_called().will_return(False)
ifc.get_object("material").should_be_called().will_return("obj")
ifc.unlink(element="material").should_be_called()
ifc.run("material.remove_material", material="material").should_be_called()
style.get_style("obj").should_be_called().will_return(None)
material.delete_object("obj").should_be_called()
material.is_editing_materials().should_be_called().will_return(False)
subject.remove_material(ifc, material, style, material="material")
def test_preserving_a_material_object_if_it_is_still_used_as_a_style(self, ifc, material, style):
material.is_material_used_in_sets("material").should_be_called().will_return(False)
ifc.get_object("material").should_be_called().will_return("obj")
ifc.unlink(element="material").should_be_called()
ifc.run("material.remove_material", material="material").should_be_called()
style.get_style("obj").should_be_called().will_return("style")
material.is_editing_materials().should_be_called().will_return(False)
subject.remove_material(ifc, material, style, material="material")
def test_not_removing_a_material_if_it_is_used_in_a_material_set(self, ifc, material, style):
def test_not_removing_a_material_if_it_is_used_in_a_material_set(self, ifc, material):
material.is_material_used_in_sets("material").should_be_called().will_return(True)
subject.remove_material(ifc, material, style, material="material")
subject.remove_material(ifc, material, material="material")
class TestRemoveMaterialSet:
+8 -17
View File
@@ -53,32 +53,23 @@ class TestAddStyle:
class TestRemoveStyle:
def test_removing_a_style(self, ifc, material, style):
def test_removing_a_style(self, ifc, style):
ifc.get_object("style").should_be_called().will_return("obj")
ifc.unlink(obj="obj", element="style").should_be_called()
ifc.unlink(element="style").should_be_called()
ifc.run("style.remove_style", style="style").should_be_called()
ifc.get_entity("obj").should_be_called().will_return("material")
style.delete_object("obj").should_be_called()
style.is_editing_styles().should_be_called().will_return(False)
subject.remove_style(ifc, material, style, style="style")
subject.remove_style(ifc, style, style="style")
def test_removing_a_style_and_reloading_imported_styles(self, ifc, material, style):
def test_removing_a_style_and_reloading_imported_styles(self, ifc, style):
ifc.get_object("style").should_be_called().will_return("obj")
ifc.unlink(obj="obj", element="style").should_be_called()
ifc.unlink(element="style").should_be_called()
ifc.run("style.remove_style", style="style").should_be_called()
ifc.get_entity("obj").should_be_called().will_return("material")
style.delete_object("obj").should_be_called()
style.is_editing_styles().should_be_called().will_return(True)
style.get_active_style_type().should_be_called().will_return("style_type")
style.import_presentation_styles("style_type").should_be_called()
subject.remove_style(ifc, material, style, style="style")
def test_removing_an_object_if_it_is_not_still_used_for_a_material(self, ifc, material, style):
ifc.get_object("style").should_be_called().will_return("obj")
ifc.unlink(obj="obj", element="style").should_be_called()
ifc.run("style.remove_style", style="style").should_be_called()
ifc.get_entity("obj").should_be_called().will_return(None)
material.delete_object("obj").should_be_called()
style.is_editing_styles().should_be_called().will_return(False)
subject.remove_style(ifc, material, style, style="style")
subject.remove_style(ifc, style, style="style")
class TestUpdateStyleColours:
+1 -1
View File
@@ -47,6 +47,6 @@ class TestPurgeUnusedTypes:
type.get_type_occurrences("element_type").should_be_called().will_return([])
ifc.run("root.remove_product", product="element_type").should_be_called()
ifc.get_object("element_type").should_be_called().will_return("obj")
ifc.unlink(obj="obj").should_be_called()
ifc.unlink(element="element_type").should_be_called()
type.remove_object("obj").should_be_called()
subject.purge_unused_types(ifc, type)