Copy deep can now exclude things, useful for copying representation graphs where you don't want to duplicate the context

This commit is contained in:
Dion Moult
2022-10-09 17:15:39 +11:00
parent 3ee4b1f0e3
commit 232252f61d
2 changed files with 56 additions and 11 deletions
@@ -190,13 +190,17 @@ def get_elements_by_material(ifc_file, material):
"""
Retrieves the elements related to a material.
This includes elements using the material as part of a material set or set
usage.
:param ifc_file: The IFC file
:param material: The IFC Material entity
:return: The elements related to the material
:return: A list of elements using the to the material
Example::
material = file.by_type("IfcMaterial")[0]
elements = ifcopenshell.util.element.get_elements_by_material(file, material)
material = file.by_type("IfcMaterial")[0]
elements = ifcopenshell.util.element.get_elements_by_material(file, material)
"""
results = set()
for inverse in ifc_file.get_inverse(material):
@@ -229,9 +233,9 @@ def get_elements_by_style(ifc_file, style):
:return: The elements related to the style
Example::
style = file.by_type("IfcSurfaceStyle")[0]
elements = ifcopenshell.util.element.get_elements_by_style(file, style)
style = file.by_type("IfcSurfaceStyle")[0]
elements = ifcopenshell.util.element.get_elements_by_style(file, style)
"""
results = set()
inverses = list(ifc_file.get_inverse(style))
@@ -482,6 +486,15 @@ def remove_deep2(ifc_file, element, also_consider=[], do_not_delete=[]):
def copy(ifc_file, element):
"""
Copy a single element. Any referenced elements are not copied.
GlobalIds are regenerated.
:param ifc_file: The IFC file object
:param element: The IFC element to copy
:return: The newly copied element
"""
new = ifc_file.create_entity(element.is_a())
for i, attribute in enumerate(element):
if attribute is None:
@@ -493,16 +506,33 @@ def copy(ifc_file, element):
return new
def copy_deep(ifc_file, element):
def copy_deep(ifc_file, element, exclude=None):
"""
Recursively copy an element and all of its directly related subelements.
GlobalIds are regenerated.
:param ifc_file: The IFC file object
:param element: The IFC element to copy
:param exclude: An optional list of strings of IFC class names to not copy.
If any of the subelement is this class, it will not be copied and the
original instance will be referenced.
:return: The newly copied element
"""
new = ifc_file.create_entity(element.is_a())
for i, attribute in enumerate(element):
if attribute is None:
continue
if isinstance(attribute, ifcopenshell.entity_instance):
attribute = copy_deep(ifc_file, attribute)
if not exclude or (exclude and not any([attribute.is_a(e) for e in exclude])):
attribute = copy_deep(ifc_file, attribute, exclude=exclude)
elif isinstance(attribute, tuple) and attribute and isinstance(attribute[0], ifcopenshell.entity_instance):
attribute = list(attribute)
for j, item in enumerate(attribute):
attribute[j] = copy_deep(ifc_file, item)
new[i] = attribute
if not exclude or (exclude and not any([attribute[0].is_a(e) for e in exclude])):
attribute = list(attribute)
for j, item in enumerate(attribute):
attribute[j] = copy_deep(ifc_file, item, exclude=exclude)
if new.attribute_name(i) == "GlobalId":
new[i] = ifcopenshell.guid.new()
else:
new[i] = attribute
return new
@@ -668,6 +668,7 @@ class TestCopyDeepIFC4(test.bootstrap.IFC4):
element = self.file.createIfcWall(GlobalId="id", Name="name", OwnerHistory=owner)
element2 = subject.copy_deep(self.file, element)
assert element.OwnerHistory != element2.OwnerHistory
assert element.GlobalId != element2.GlobalId
assert element.OwnerHistory.State == element2.OwnerHistory.State
def test_copying_an_element_recursively_even_if_references_are_aggregated(self):
@@ -677,3 +678,17 @@ class TestCopyDeepIFC4(test.bootstrap.IFC4):
rel2 = subject.copy_deep(self.file, rel)
assert rel.RelatedObjects != rel2.RelatedObjects
assert rel.RelatedObjects[0].Name == rel2.RelatedObjects[0].Name
def test_copying_an_element_recursively_with_an_exclude_filter(self):
owner = self.file.createIfcOwnerHistory()
owner.State = "READWRITE"
element = self.file.createIfcWall(GlobalId="id", Name="name", OwnerHistory=owner)
element2 = subject.copy_deep(self.file, element, exclude=["IfcOwnerHistory"])
assert element.OwnerHistory == element2.OwnerHistory
def test_copying_an_element_recursively_with_aggregates_with_an_exclude_filter(self):
element = self.file.createIfcWall(Name="name")
rel = self.file.createIfcRelAggregates()
rel.RelatedObjects = [element]
rel2 = subject.copy_deep(self.file, rel, exclude=["IfcWall"])
assert rel.RelatedObjects == rel2.RelatedObjects