bim.switch_representation to handle representations with the same context

1) If object had multiple representations for the same context, then switch simply wouldn't work as it would always pick up the first representation it could find. Now it prioritizes the one user is selecting in UI.

2) If some object is selected and it also has multiple representations for the same context, then switch representation would switch it to any representation in that context it first finds. As user doesn't provide representation explicitly in that case, now it will stick to the already active representation on selected object if it matches the context, to avoid accident switches.

Notcied by working with example from #5824
This commit is contained in:
Andrej730
2024-12-05 18:27:22 +05:00
parent 1b61cbba8f
commit 3446643816
3 changed files with 51 additions and 21 deletions
@@ -338,22 +338,36 @@ class SwitchRepresentation(bpy.types.Operator, tool.Ifc.Operator):
return False return False
def _execute(self, context): def _execute(self, context):
context = tool.Ifc.get().by_id(self.ifc_definition_id).ContextOfItems provided_representation = tool.Ifc.get().by_id(self.ifc_definition_id)
ifc_context = provided_representation.ContextOfItems
for obj in tool.Blender.get_selected_objects(): for obj in tool.Blender.get_selected_objects():
if ( if not (element := tool.Ifc.get_entity(obj)) or obj.mode != "OBJECT":
(element := tool.Ifc.get_entity(obj)) continue
and obj.mode == "OBJECT"
and (representation := ifcopenshell.util.representation.get_representation(element, context)) # Find representation to switch to.
): if (active_representation := tool.Geometry.get_active_representation(obj)) is None:
core.switch_representation( # No active representation => probably has no representations.
tool.Ifc, continue
tool.Geometry, elif obj == context.active_object:
obj=obj, # Prioritize provided representation.
representation=representation, representation = provided_representation
should_reload=self.should_reload, elif active_representation.ContextOfItems == ifc_context:
is_global=self.should_switch_all_meshes, # Prioritize already active representation if context matches.
should_sync_changes_first=True, representation = active_representation
) else:
representation = ifcopenshell.util.representation.get_representation(element, ifc_context)
if not representation:
continue
core.switch_representation(
tool.Ifc,
tool.Geometry,
obj=obj,
representation=representation,
should_reload=self.should_reload,
is_global=self.should_switch_all_meshes,
should_sync_changes_first=True,
)
class RemoveRepresentation(bpy.types.Operator, tool.Ifc.Operator): class RemoveRepresentation(bpy.types.Operator, tool.Ifc.Operator):
+13 -2
View File
@@ -678,6 +678,7 @@ class Geometry(bonsai.core.tool.Geometry):
element = tool.Ifc.get_entity(obj) element = tool.Ifc.get_entity(obj)
assert element assert element
ifc_file = tool.Ifc.get()
elements = set() elements = set()
element_types = set() element_types = set()
representation = ifcopenshell.util.representation.resolve_representation(representation) representation = ifcopenshell.util.representation.resolve_representation(representation)
@@ -716,16 +717,26 @@ class Geometry(bonsai.core.tool.Geometry):
else: else:
iterator = None # For example, when switching representation of a type with no occurrences iterator = None # For example, when switching representation of a type with no occurrences
meshes = {} meshes = {}
base_representation = representation
if iterator and iterator.initialize(): if iterator and iterator.initialize():
while True: while True:
shape = iterator.get() shape = iterator.get()
element = tool.Ifc.get().by_id(shape.id) element = tool.Ifc.get().by_id(shape.id)
if obj := tool.Ifc.get_object(element): if obj := tool.Ifc.get_object(element):
# It's possible that there will be multiple shapes for the same context,
# Unfortunately, iterator still processes them all and
# we need to ensure we pick the one that was requested for reimport.
representation_id = tool.Loader.get_representation_id_from_shape(shape.geometry)
representation = ifc_file.by_id(representation_id)
resolved_representation = ifcopenshell.util.representation.resolve_representation(representation)
if resolved_representation != base_representation:
if not iterator.next():
break
continue
mesh_name = tool.Loader.get_mesh_name_from_shape(shape.geometry) mesh_name = tool.Loader.get_mesh_name_from_shape(shape.geometry)
mesh = meshes.get(mesh_name) mesh = meshes.get(mesh_name)
if mesh is None: if mesh is None:
# Duplicate code
representation = tool.Ifc.get().by_id(int(shape.geometry.id.split("-")[0]))
if element.is_a("IfcAnnotation") and element.ObjectType == "DRAWING": if element.is_a("IfcAnnotation") and element.ObjectType == "DRAWING":
mesh = tool.Loader.create_camera(element, representation, shape) mesh = tool.Loader.create_camera(element, representation, shape)
elif element.is_a("IfcAnnotation") and ifc_importer.is_curve_annotation(element): elif element.is_a("IfcAnnotation") and ifc_importer.is_curve_annotation(element):
+9 -4
View File
@@ -70,15 +70,20 @@ class Loader(bonsai.core.tool.Loader):
cls.settings = settings cls.settings = settings
@classmethod @classmethod
def get_mesh_name_from_shape(cls, geometry: ifcopenshell.geom.ShapeType) -> str: def get_representation_id_from_shape(cls, geometry: ifcopenshell.geom.ShapeType) -> int:
representation_id = geometry.id representation_id: str = geometry.id
if "-" in representation_id: if "-" in representation_id:
# Example: 2432-openings-2468, where # Example: 2432-openings-2468, where
# 2432 is mapped representation id # 2432 is mapped representation id
# and 2468 is IFCRELVOIDSELEMENT # and 2468 is IFCRELVOIDSELEMENT
representation_id = int(re.sub(r"\D", "", representation_id.split("-")[0])) representation_id = re.sub(r"\D", "", representation_id.split("-")[0])
else: else:
representation_id = int(re.sub(r"\D", "", representation_id)) representation_id = re.sub(r"\D", "", representation_id)
return int(representation_id)
@classmethod
def get_mesh_name_from_shape(cls, geometry: ifcopenshell.geom.ShapeType) -> str:
representation_id = cls.get_representation_id_from_shape(geometry)
representation = tool.Ifc.get().by_id(representation_id) representation = tool.Ifc.get().by_id(representation_id)
context_id = representation.ContextOfItems.id() if hasattr(representation, "ContextOfItems") else 0 context_id = representation.ContextOfItems.id() if hasattr(representation, "ContextOfItems") else 0
return cls.get_mesh_name(context_id, representation_id) return cls.get_mesh_name(context_id, representation_id)