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
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():
if (
(element := tool.Ifc.get_entity(obj))
and obj.mode == "OBJECT"
and (representation := ifcopenshell.util.representation.get_representation(element, context))
):
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,
)
if not (element := tool.Ifc.get_entity(obj)) or obj.mode != "OBJECT":
continue
# Find representation to switch to.
if (active_representation := tool.Geometry.get_active_representation(obj)) is None:
# No active representation => probably has no representations.
continue
elif obj == context.active_object:
# Prioritize provided representation.
representation = provided_representation
elif active_representation.ContextOfItems == ifc_context:
# Prioritize already active representation if context matches.
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):
+13 -2
View File
@@ -678,6 +678,7 @@ class Geometry(bonsai.core.tool.Geometry):
element = tool.Ifc.get_entity(obj)
assert element
ifc_file = tool.Ifc.get()
elements = set()
element_types = set()
representation = ifcopenshell.util.representation.resolve_representation(representation)
@@ -716,16 +717,26 @@ class Geometry(bonsai.core.tool.Geometry):
else:
iterator = None # For example, when switching representation of a type with no occurrences
meshes = {}
base_representation = representation
if iterator and iterator.initialize():
while True:
shape = iterator.get()
element = tool.Ifc.get().by_id(shape.id)
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 = meshes.get(mesh_name)
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":
mesh = tool.Loader.create_camera(element, representation, shape)
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
@classmethod
def get_mesh_name_from_shape(cls, geometry: ifcopenshell.geom.ShapeType) -> str:
representation_id = geometry.id
def get_representation_id_from_shape(cls, geometry: ifcopenshell.geom.ShapeType) -> int:
representation_id: str = geometry.id
if "-" in representation_id:
# Example: 2432-openings-2468, where
# 2432 is mapped representation id
# 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:
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)
context_id = representation.ContextOfItems.id() if hasattr(representation, "ContextOfItems") else 0
return cls.get_mesh_name(context_id, representation_id)