mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-27 18:57:17 +00:00
Fix critical bug where copied representations would be inefficiently or incorrectly replicated.
This commit is contained in:
@@ -808,7 +808,7 @@ def copy(ifc_file, element):
|
|||||||
return new
|
return new
|
||||||
|
|
||||||
|
|
||||||
def copy_deep(ifc_file, element, exclude=None, exclude_callback=None):
|
def copy_deep(ifc_file, element, exclude=None, exclude_callback=None, copied_entities=None):
|
||||||
"""
|
"""
|
||||||
Recursively copy an element and all of its directly related subelements.
|
Recursively copy an element and all of its directly related subelements.
|
||||||
|
|
||||||
@@ -825,10 +825,22 @@ def copy_deep(ifc_file, element, exclude=None, exclude_callback=None):
|
|||||||
:param exclude_callback: A callback to determine whether or not to exclude
|
:param exclude_callback: A callback to determine whether or not to exclude
|
||||||
an entity or not. Returns True to exclude and False to exclude.
|
an entity or not. Returns True to exclude and False to exclude.
|
||||||
:type exclude_callback: function,optional
|
:type exclude_callback: function,optional
|
||||||
|
:param copied_entities: A dictionary of IDs as keys and entities as values
|
||||||
|
to reuse when coming across the same entity twice. This can typically
|
||||||
|
be left as None.
|
||||||
|
:type copied_entities: dict[int:ifcopenshell.entity_instance.entity_instance]
|
||||||
:return: The newly copied element
|
:return: The newly copied element
|
||||||
:rtype: ifcopenshell.entity_instance.entity_instance
|
:rtype: ifcopenshell.entity_instance.entity_instance
|
||||||
"""
|
"""
|
||||||
|
if copied_entities is None:
|
||||||
|
copied_entities = {}
|
||||||
|
else:
|
||||||
|
copied_entity = copied_entities.get(element.id(), None)
|
||||||
|
if copied_entity:
|
||||||
|
return copied_entity
|
||||||
new = ifc_file.create_entity(element.is_a())
|
new = ifc_file.create_entity(element.is_a())
|
||||||
|
if element.id():
|
||||||
|
copied_entities[element.id()] = new
|
||||||
for i, attribute in enumerate(element):
|
for i, attribute in enumerate(element):
|
||||||
if attribute is None:
|
if attribute is None:
|
||||||
continue
|
continue
|
||||||
@@ -838,7 +850,7 @@ def copy_deep(ifc_file, element, exclude=None, exclude_callback=None):
|
|||||||
elif exclude_callback and exclude_callback(attribute):
|
elif exclude_callback and exclude_callback(attribute):
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
attribute = copy_deep(ifc_file, attribute, exclude=exclude)
|
attribute = copy_deep(ifc_file, attribute, exclude=exclude, copied_entities=copied_entities)
|
||||||
elif isinstance(attribute, tuple) and attribute and isinstance(attribute[0], ifcopenshell.entity_instance):
|
elif isinstance(attribute, tuple) and attribute and isinstance(attribute[0], ifcopenshell.entity_instance):
|
||||||
if exclude and any([attribute[0].is_a(e) for e in exclude]):
|
if exclude and any([attribute[0].is_a(e) for e in exclude]):
|
||||||
pass
|
pass
|
||||||
@@ -847,7 +859,13 @@ def copy_deep(ifc_file, element, exclude=None, exclude_callback=None):
|
|||||||
else:
|
else:
|
||||||
attribute = list(attribute)
|
attribute = list(attribute)
|
||||||
for j, item in enumerate(attribute):
|
for j, item in enumerate(attribute):
|
||||||
attribute[j] = copy_deep(ifc_file, item, exclude=exclude, exclude_callback=exclude_callback)
|
attribute[j] = copy_deep(
|
||||||
|
ifc_file,
|
||||||
|
item,
|
||||||
|
exclude=exclude,
|
||||||
|
exclude_callback=exclude_callback,
|
||||||
|
copied_entities=copied_entities,
|
||||||
|
)
|
||||||
if new.attribute_name(i) == "GlobalId":
|
if new.attribute_name(i) == "GlobalId":
|
||||||
new[i] = ifcopenshell.guid.new()
|
new[i] = ifcopenshell.guid.new()
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -707,3 +707,19 @@ class TestCopyDeepIFC4(test.bootstrap.IFC4):
|
|||||||
rel.RelatedObjects = [element]
|
rel.RelatedObjects = [element]
|
||||||
rel2 = subject.copy_deep(self.file, rel, exclude_callback=lambda x: x.is_a("IfcWall"))
|
rel2 = subject.copy_deep(self.file, rel, exclude_callback=lambda x: x.is_a("IfcWall"))
|
||||||
assert rel.RelatedObjects == rel2.RelatedObjects
|
assert rel.RelatedObjects == rel2.RelatedObjects
|
||||||
|
|
||||||
|
def test_copying_and_reusing_element_references(self):
|
||||||
|
points = self.file.createIfcCartesianPointList2D()
|
||||||
|
subelement1 = self.file.createIfcIndexedPolyCurve(points)
|
||||||
|
subelement2 = self.file.createIfcIndexedPolyCurve(points)
|
||||||
|
element = self.file.createIfcGeometricCurveSet([subelement1, subelement2])
|
||||||
|
element2 = subject.copy_deep(self.file, element)
|
||||||
|
assert element2.Elements[0].Points.id() == element2.Elements[1].Points.id()
|
||||||
|
|
||||||
|
def test_copying_primitive_entities(self):
|
||||||
|
element = self.file.createIfcIndexedPolyCurve(
|
||||||
|
Segments=(self.file.createIfcLineIndex((1, 2)), self.file.createIfcLineIndex((3, 4)))
|
||||||
|
)
|
||||||
|
element2 = subject.copy_deep(self.file, element)
|
||||||
|
assert element2.Segments[0][0] == (1, 2)
|
||||||
|
assert element2.Segments[1][0] == (3, 4)
|
||||||
|
|||||||
Reference in New Issue
Block a user