geometry.remove_representation_item - add element argument

Use explicit element argument instead of props.representation_obj as representation_obj may not be there (e.g. removing rep items without item mode) or some other object might be in item mode and then booleans won't be unmarked.

Found the issue because of the failing test 🥳
This commit is contained in:
Andrej730
2025-04-02 18:24:56 +05:00
parent 156cca5932
commit 0315542237
4 changed files with 28 additions and 14 deletions
@@ -2509,11 +2509,12 @@ class RemoveRepresentationItem(bpy.types.Operator, tool.Ifc.Operator):
return True return True
def _execute(self, context): def _execute(self, context):
obj = tool.Geometry.get_active_or_representation_obj() assert (obj := tool.Geometry.get_active_or_representation_obj())
assert (element := tool.Ifc.get_entity(obj))
ifc_file = tool.Ifc.get() ifc_file = tool.Ifc.get()
representation_item = ifc_file.by_id(self.representation_item_id) representation_item = ifc_file.by_id(self.representation_item_id)
tool.Geometry.remove_representation_item(representation_item) tool.Geometry.remove_representation_item(representation_item, element)
tool.Geometry.reload_representation(obj) tool.Geometry.reload_representation(obj)
# reload items ui # reload items ui
+16 -8
View File
@@ -202,6 +202,7 @@ class Geometry(bonsai.core.tool.Geometry):
@classmethod @classmethod
def delete_ifc_item(cls, obj: bpy.types.Object) -> None: def delete_ifc_item(cls, obj: bpy.types.Object) -> None:
"""Delete IfcRepresentationItem's Object."""
props = tool.Geometry.get_geometry_props() props = tool.Geometry.get_geometry_props()
if len(props.item_objs) == 1: if len(props.item_objs) == 1:
return return
@@ -212,7 +213,9 @@ class Geometry(bonsai.core.tool.Geometry):
mesh = obj.data mesh = obj.data
assert isinstance(mesh, bpy.types.Mesh) assert isinstance(mesh, bpy.types.Mesh)
item = tool.Ifc.get().by_id(tool.Geometry.get_mesh_props(mesh).ifc_definition_id) item = tool.Ifc.get().by_id(tool.Geometry.get_mesh_props(mesh).ifc_definition_id)
cls.remove_representation_item(item) rep_obj = props.representation_obj
assert (rep_obj := props.representation_obj) and (rep_element := tool.Ifc.get_entity(rep_obj))
cls.remove_representation_item(item, rep_element)
cls.reload_representation(props.representation_obj) cls.reload_representation(props.representation_obj)
bpy.data.objects.remove(obj) bpy.data.objects.remove(obj)
@@ -1344,12 +1347,19 @@ class Geometry(bonsai.core.tool.Geometry):
) )
@classmethod @classmethod
def remove_representation_item(cls, representation_item: ifcopenshell.entity_instance) -> None: def remove_representation_item(
cls, representation_item: ifcopenshell.entity_instance, element: ifcopenshell.entity_instance
) -> None:
"""Remove IfcRepresentationItem.
:param representation_item: item to remove.
:param element: item's element. Is used to unmark manual booleans.
"""
# NOTE: we assume it's not the last representation item # NOTE: we assume it's not the last representation item
# otherwise we probably would need to remove representation too # otherwise we probably would need to remove representation too
# NOTE: a lot of shared code with `geometry.remove_representation` # NOTE: a lot of shared code with `geometry.remove_representation`
ifc_file = tool.Ifc.get() ifc_file = tool.Ifc.get()
shape_aspects = [] shape_aspects: list[ifcopenshell.entity_instance] = []
consider_inverses = [] consider_inverses = []
styled_item, colour, texture, layer = None, None, None, None styled_item, colour, texture, layer = None, None, None, None
@@ -1366,7 +1376,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
boolean_results_to_remove = 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"):
if inverse.OfShapeAspect: if inverse.OfShapeAspect:
@@ -1409,11 +1419,9 @@ class Geometry(bonsai.core.tool.Geometry):
also_consider = list(consider_inverses) also_consider = list(consider_inverses)
ifcopenshell.util.element.remove_deep2(ifc_file, representation_item, also_consider=also_consider) ifcopenshell.util.element.remove_deep2(ifc_file, representation_item, also_consider=also_consider)
props = tool.Geometry.get_geometry_props() tool.Model.unmark_manual_booleans(element, [b.id() for b in boolean_results_to_remove])
rep_element = tool.Ifc.get_entity(props.representation_obj)
tool.Model.unmark_manual_booleans(rep_element, [b.id() for b in boolean_results_to_remove])
for boolean_result in boolean_results_to_remove: for boolean_result in boolean_results_to_remove:
cls.remove_representation_item(boolean_result) cls.remove_representation_item(boolean_result, element)
@classmethod @classmethod
def create_shape_aspect( def create_shape_aspect(
+6 -2
View File
@@ -687,8 +687,12 @@ class Model(bonsai.core.tool.Model):
@classmethod @classmethod
def unmark_manual_booleans(cls, element: ifcopenshell.entity_instance, boolean_ids: list[int]) -> None: def unmark_manual_booleans(cls, element: ifcopenshell.entity_instance, boolean_ids: list[int]) -> None:
# NOTE: we use use boolean_ids instead of boolean entities """Remove boolean ids from ``element``'s 'BBIM_Boolean' pset.
# so it will be possible to unmark manual booleans after they already was deleted
:param boolean_ids: List of boolean ids to remove.
Ids are used instead of entities to make it possible to unmark already removed booleans.
Provided ids may not be marked as manual booleans previously.
"""
pset = ifcopenshell.util.element.get_pset(element, "BBIM_Boolean") pset = ifcopenshell.util.element.get_pset(element, "BBIM_Boolean")
if not pset: if not pset:
return return
+3 -2
View File
@@ -20,6 +20,7 @@ import bpy
import math import math
import numpy as np import numpy as np
import ifcopenshell import ifcopenshell
import ifcopenshell.api.geometry
import ifcopenshell.api.type import ifcopenshell.api.type
import bonsai.core.tool import bonsai.core.tool
import bonsai.tool as tool import bonsai.tool as tool
@@ -606,13 +607,13 @@ class TestRemoveRepresentationItem(NewFile):
items = [ifc.createIfcExtrudedAreaSolid(), ifc.createIfcExtrudedAreaSolid()] items = [ifc.createIfcExtrudedAreaSolid(), ifc.createIfcExtrudedAreaSolid()]
representation = ifc.createIfcShapeRepresentation(Items=items, ContextOfItems=context) representation = ifc.createIfcShapeRepresentation(Items=items, ContextOfItems=context)
tool.Ifc.run("geometry.assign_representation", product=element, representation=representation) ifcopenshell.api.geometry.assign_representation(ifc, product=element, representation=representation)
product_shape = element.Representation product_shape = element.Representation
shape_aspect = subject.create_shape_aspect(product_shape, representation, items[:1], None) shape_aspect = subject.create_shape_aspect(product_shape, representation, items[:1], None)
shape_aspect_id = shape_aspect.id() shape_aspect_id = shape_aspect.id()
subject.remove_representation_item(items[0]) subject.remove_representation_item(items[0], element)
assert tool.Ifc.get_entity_by_id(shape_aspect_id) is None assert tool.Ifc.get_entity_by_id(shape_aspect_id) is None
assert set(representation.Items) == {items[1]} assert set(representation.Items) == {items[1]}