mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-30 16:43:00 +00:00
Bonsai: delete representation items nested in an IfcGeometricSet (#6807)
Deleting a part (segment) of a dimension in item mode silently failed and the part reappeared when the representation reloaded. Multi-segment dimension annotations store their segments as Elements INSIDE an IfcGeometricCurveSet; tool.Geometry.remove_representation_item only recognized IfcShapeRepresentation and IfcBooleanResult inverses, so for a nested segment the item was never detached and remove_deep2 refused to purge it (an external inverse remained). The Blender object vanished, the IFC entity stayed, and the reload brought it back. Recognize IfcGeometricSet inverses: detach the item from Elements and let remove_deep2 purge it. If the item is the set's last element (Elements is SET [1:?]), remove the whole set recursively instead, which keeps the representation valid. This affects all GeometricSet-based annotations (dimensions, leaders, etc.), not just the reported model. Verified live in headless Blender on the reporter's model: deleting item #286487 of annotation #82782 left the entity in the file before the fix ("victim entity STILL EXISTS") and removes it after ("victim entity gone", Elements reduced, saved file verified clean with pure ifcopenshell); deleting both elements removes the entire curve set leaving a valid Items list. TestRemoveRepresentationItem + shape-aspect tests: 4 passed. Generated with the assistance of an AI coding tool. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1774,6 +1774,7 @@ class Geometry(bonsai.core.tool.Geometry):
|
|||||||
[consider_inverses.append(texture := t) for t in getattr(representation_item, "HasTextures", [])]
|
[consider_inverses.append(texture := t) for t in getattr(representation_item, "HasTextures", [])]
|
||||||
|
|
||||||
representation = None
|
representation = None
|
||||||
|
geometric_set = None
|
||||||
boolean_results_to_remove: set[ifcopenshell.entity_instance] = set()
|
boolean_results_to_remove: set[ifcopenshell.entity_instance] = set()
|
||||||
for inverse in ifc_file.get_inverse(representation_item):
|
for inverse in ifc_file.get_inverse(representation_item):
|
||||||
if inverse.is_a("IfcShapeRepresentation"):
|
if inverse.is_a("IfcShapeRepresentation"):
|
||||||
@@ -1781,6 +1782,10 @@ class Geometry(bonsai.core.tool.Geometry):
|
|||||||
shape_aspects.append(inverse.OfShapeAspect[0])
|
shape_aspects.append(inverse.OfShapeAspect[0])
|
||||||
else:
|
else:
|
||||||
representation = inverse
|
representation = inverse
|
||||||
|
elif inverse.is_a("IfcGeometricSet"):
|
||||||
|
# E.g. a dimension segment (curve) nested inside an
|
||||||
|
# IfcGeometricCurveSet of an annotation representation.
|
||||||
|
geometric_set = inverse
|
||||||
elif inverse.is_a("IfcBooleanResult"):
|
elif inverse.is_a("IfcBooleanResult"):
|
||||||
if inverse.SecondOperand == representation_item:
|
if inverse.SecondOperand == representation_item:
|
||||||
other_operand = inverse.FirstOperand
|
other_operand = inverse.FirstOperand
|
||||||
@@ -1812,6 +1817,15 @@ class Geometry(bonsai.core.tool.Geometry):
|
|||||||
for shape_aspect in shape_aspects:
|
for shape_aspect in shape_aspects:
|
||||||
cls.remove_representation_items_from_shape_aspect([representation_item], shape_aspect)
|
cls.remove_representation_items_from_shape_aspect([representation_item], shape_aspect)
|
||||||
|
|
||||||
|
if geometric_set:
|
||||||
|
new_elements = tuple(e for e in geometric_set.Elements if e != representation_item)
|
||||||
|
if not new_elements:
|
||||||
|
# An IfcGeometricSet must keep at least one element, so
|
||||||
|
# removing the set's last element removes the set itself
|
||||||
|
# (which purges the element together with the set's subgraph).
|
||||||
|
cls.remove_representation_item(geometric_set, element)
|
||||||
|
return
|
||||||
|
geometric_set.Elements = new_elements
|
||||||
if representation:
|
if representation:
|
||||||
new_items = tuple(set(representation.Items) - {representation_item})
|
new_items = tuple(set(representation.Items) - {representation_item})
|
||||||
if not new_items:
|
if not new_items:
|
||||||
|
|||||||
Reference in New Issue
Block a user