mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-05 23:41:44 +00:00
Bonsai: generalise representation item deletion to nested items
remove_representation_item assumed a representation item's parent is always the IfcShapeRepresentation (or an IfcBooleanResult). Items that live inside a container item were detached from nothing, so they stayed in the file and were re-imported on leaving item mode (#6591). The import side is already general. The C++ mapper tags every mapped IfcRepresentationItem with its instance id, and container items are mapped through the same map_to_collection helper as IfcRepresentation.Items, so their children become individually editable items with no special casing. Deletion now mirrors that: any inverse that is itself a representation item is treated as a container, and the item is cleared from whichever attribute references it. A container left without contents is removed in turn. This covers IfcGeometricSet/IfcGeometricCurveSet Elements, IfcShellBasedSurfaceModel SbsmBoundary and IfcFaceBasedSurfaceModel FbsmFaces, rather than only the case reported in #6591. Items shared by several containers are detached from all of them, which matches item mode presenting one object per item id. Fixes #6591 Generated with the assistance of an AI coding tool.
This commit is contained in:
@@ -1785,6 +1785,7 @@ class Geometry(bonsai.core.tool.Geometry):
|
||||
[consider_inverses.append(texture := t) for t in getattr(representation_item, "HasTextures", [])]
|
||||
|
||||
representation = None
|
||||
containers: list[ifcopenshell.entity_instance] = []
|
||||
boolean_results_to_remove: set[ifcopenshell.entity_instance] = set()
|
||||
for inverse in ifc_file.get_inverse(representation_item):
|
||||
if inverse.is_a("IfcShapeRepresentation"):
|
||||
@@ -1806,6 +1807,8 @@ class Geometry(bonsai.core.tool.Geometry):
|
||||
elif inverse2.is_a("IfcShapeRepresentation"):
|
||||
inverse2.Items = tuple(set(inverse2.Items) - {inverse} | {other_operand})
|
||||
boolean_results_to_remove.add(inverse)
|
||||
elif inverse.is_a("IfcRepresentationItem") and not inverse.is_a("IfcStyledItem"):
|
||||
containers.append(inverse)
|
||||
|
||||
if styled_item:
|
||||
consider_inverses.remove(styled_item)
|
||||
@@ -1828,13 +1831,45 @@ class Geometry(bonsai.core.tool.Geometry):
|
||||
if not new_items:
|
||||
return
|
||||
representation.Items = new_items
|
||||
|
||||
emptied_containers = [c for c in containers if cls.detach_representation_item(representation_item, c)]
|
||||
|
||||
also_consider = list(consider_inverses)
|
||||
ifcopenshell.util.element.remove_deep2(ifc_file, representation_item, also_consider=also_consider)
|
||||
|
||||
for container in emptied_containers:
|
||||
cls.remove_representation_item(container, element)
|
||||
|
||||
tool.Model.unmark_manual_booleans(element, [b.id() for b in boolean_results_to_remove])
|
||||
for boolean_result in boolean_results_to_remove:
|
||||
cls.remove_representation_item(boolean_result, element)
|
||||
|
||||
@classmethod
|
||||
def detach_representation_item(
|
||||
cls, representation_item: ifcopenshell.entity_instance, container: ifcopenshell.entity_instance
|
||||
) -> bool:
|
||||
"""Clear references to an item from another item that nests it.
|
||||
|
||||
Covers containers such as IfcGeometricSet.Elements,
|
||||
IfcShellBasedSurfaceModel.SbsmBoundary or IfcCsgSolid.TreeRootExpression.
|
||||
|
||||
:param representation_item: item to detach.
|
||||
:param container: item referencing ``representation_item``.
|
||||
:return: whether ``container`` is left invalid and has to be removed too.
|
||||
"""
|
||||
is_emptied = False
|
||||
for i in range(len(container)):
|
||||
value = container[i]
|
||||
if value == representation_item:
|
||||
container[i] = None
|
||||
is_emptied = True
|
||||
elif isinstance(value, tuple) and any(v == representation_item for v in value):
|
||||
value = tuple(v for v in value if v != representation_item)
|
||||
container[i] = value
|
||||
if not value:
|
||||
is_emptied = True
|
||||
return is_emptied
|
||||
|
||||
@classmethod
|
||||
def create_shape_aspect(
|
||||
cls,
|
||||
|
||||
Reference in New Issue
Block a user