mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-05 23:41:44 +00:00
Bonsai: remove_representation handles occurrence reps mapped to a floating map
remove_representation took its type-level branch for any mapped representation, which no-ops when the map is not one of the element type's RepresentationMaps -- a floating/shared map (typical of Revit imports where the type's RepresentationMaps is empty). The occurrence's mapped rep was then unremovable: unassign_representation on the type finds no matching map, and remove_representation can't delete the geometry still referenced by the floating map. Take the type-level branch only when the object is the type itself, or the mapped rep is genuinely anchored to the type (new tool.Geometry.is_mapped_representation_of_type). A floating mapped rep now falls through to occurrence-level removal, which unassigns it from just that occurrence and lets remove_deep2 GC the map once its last user is gone. No change for local reps or type-anchored mapped reps. Fixes #9216. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -150,7 +150,15 @@ def remove_representation(
|
||||
element_type = geometry.get_element_type(element)
|
||||
data = None
|
||||
data_removed_by_switch_representation = False
|
||||
if element_type and (geometry.is_mapped_representation(representation) or geometry.is_type_product(element)):
|
||||
# Take the type-level branch only when the removal really is type-scoped: the
|
||||
# object is the type itself, or the mapped rep is anchored to the type's
|
||||
# RepresentationMaps. A mapped rep pointing at a *floating* map not owned by
|
||||
# the type (typical of Revit imports) must be removed at the occurrence level
|
||||
# instead -- the type branch would no-op and leave it unremovable.
|
||||
if element_type and (
|
||||
geometry.is_type_product(element)
|
||||
or geometry.is_mapped_representation_of_type(representation, element_type)
|
||||
):
|
||||
representation = geometry.resolve_mapped_representation(representation)
|
||||
data = geometry.get_representation_data(representation)
|
||||
if data and geometry.has_data_users(data):
|
||||
|
||||
@@ -477,6 +477,7 @@ class Geometry:
|
||||
def is_box_representation(cls, representation): pass
|
||||
def is_data_supported_for_adding_representation(cls, data): pass
|
||||
def is_mapped_representation(cls, representation): pass
|
||||
def is_mapped_representation_of_type(cls, representation, element_type): pass
|
||||
def is_type_product(cls, element): pass
|
||||
def link(cls, element, obj): pass
|
||||
def record_object_materials(cls, obj): pass
|
||||
|
||||
@@ -1317,6 +1317,25 @@ class Geometry(bonsai.core.tool.Geometry):
|
||||
def is_mapped_representation(cls, representation: ifcopenshell.entity_instance) -> bool:
|
||||
return representation.RepresentationType == "MappedRepresentation"
|
||||
|
||||
@classmethod
|
||||
def is_mapped_representation_of_type(
|
||||
cls,
|
||||
representation: ifcopenshell.entity_instance,
|
||||
element_type: Union[ifcopenshell.entity_instance, None],
|
||||
) -> bool:
|
||||
"""``True`` when ``representation`` is a mapped representation whose
|
||||
``IfcRepresentationMap`` is one of ``element_type``'s ``RepresentationMaps``
|
||||
-- i.e. a genuine type-anchored shared representation, as opposed to a
|
||||
floating map not owned by the type (which Revit exports produce)."""
|
||||
if element_type is None or representation.RepresentationType != "MappedRepresentation":
|
||||
return False
|
||||
if not representation.Items:
|
||||
return False
|
||||
item = representation.Items[0]
|
||||
if not item.is_a("IfcMappedItem"):
|
||||
return False
|
||||
return item.MappingSource in (element_type.RepresentationMaps or [])
|
||||
|
||||
@classmethod
|
||||
def is_meshlike(cls, representation: ifcopenshell.entity_instance) -> bool:
|
||||
if ifcopenshell.util.representation.resolve_representation(representation).RepresentationType in (
|
||||
|
||||
Reference in New Issue
Block a user