mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-09 01:11:40 +00:00
ifc.unlink fixes after 3df75e9af
Also some changes related to #4843 add
This commit is contained in:
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user