diff --git a/src/bonsai/bonsai/bim/module/spatial/operator.py b/src/bonsai/bonsai/bim/module/spatial/operator.py index 039ae18b82..61fc4863b2 100644 --- a/src/bonsai/bonsai/bim/module/spatial/operator.py +++ b/src/bonsai/bonsai/bim/module/spatial/operator.py @@ -334,7 +334,7 @@ class SetDefaultContainer(bpy.types.Operator): def execute(self, context): core.set_default_container(tool.Spatial, container=tool.Ifc.get().by_id(self.container)) - core.set_orientation_slot(spatial=tool.Spatial, product=tool.Ifc.get().by_id(self.container)) + core.set_orientation_slot(tool.Spatial, container=tool.Ifc.get().by_id(self.container)) return {"FINISHED"} diff --git a/src/bonsai/bonsai/core/spatial.py b/src/bonsai/bonsai/core/spatial.py index 1e59583570..241e0a3df2 100644 --- a/src/bonsai/bonsai/core/spatial.py +++ b/src/bonsai/bonsai/core/spatial.py @@ -121,8 +121,8 @@ def import_spatial_decomposition(spatial: tool.Spatial) -> None: spatial.import_spatial_decomposition() -def set_orientation_slot(spatial: tool.Spatial, product: ifcopenshell.entity_instance) -> None: - spatial.create_orientation_slots([product], use=True) +def set_orientation_slot(spatial: tool.Spatial, container: ifcopenshell.entity_instance) -> None: + spatial.create_orientation_slot(container) def contract_container(spatial: tool.Spatial, container: ifcopenshell.entity_instance) -> None: diff --git a/src/bonsai/bonsai/tool/spatial.py b/src/bonsai/bonsai/tool/spatial.py index 54d4f45f7b..6425b5db71 100644 --- a/src/bonsai/bonsai/tool/spatial.py +++ b/src/bonsai/bonsai/tool/spatial.py @@ -502,65 +502,49 @@ class Spatial(bonsai.core.tool.Spatial): cls.import_spatial_element(child, level_index + 1) @classmethod - def create_orientation_slots(cls, products: list[ifcopenshell.entity_instance], use: bool = False) -> None: + def create_orientation_slot(cls, container: ifcopenshell.entity_instance) -> None: active_slot = bpy.context.scene.transform_orientation_slots[0] - initial_orientation = active_slot.type + placement = container.ObjectPlacement + combined_matrix = ifcopenshell.util.placement.get_local_placement(placement)[:3, :3] - for product in products: - placement = product.ObjectPlacement - combined_matrix = ifcopenshell.util.placement.get_local_placement(placement)[:3, :3] - if np.allclose(combined_matrix, np.eye(3), atol=1e-6): - # this product has global orientation - active_slot.type = "GLOBAL" - continue - elif ( - hasattr(product, "Decomposes") - and product.Decomposes - and hasattr(product.Decomposes[0].RelatingObject, "ObjectPlacement") - ): - # this product is part of a decomposition - parent_placement = product.Decomposes[0].RelatingObject.ObjectPlacement - parent_matrix = ifcopenshell.util.placement.get_local_placement(parent_placement)[:3, :3] - if np.allclose(combined_matrix, parent_matrix, atol=1e-6): - # this product has the same orientation as its parent - cls.create_orientation_slots(products=[product.Decomposes[0].RelatingObject], use=use) - continue - elif ( - hasattr(product, "ContainedInStructure") - and product.ContainedInStructure - and hasattr(product.ContainedInStructure[0].RelatingStructure, "Objectplacement") - ): - # contained in a spatial element - parent_placement = product.ContainedInStructure[0].RelatingStructure.ObjectPlacement - parent_matrix = ifcopenshell.util.placement.get_local_placement(parent_placement)[:3, :3] - if np.allclose(combined_matrix, parent_matrix, atol=1e-6): - # this product has the same orientation as its container - cls.create_orientation_slots(products=[product.ContainedInStructure[0].RelatingStructure], use=use) - continue + if np.allclose(combined_matrix, np.eye(3), atol=1e-6): + # this spatial element has global orientation + active_slot.type = "GLOBAL" + return + elif ( + hasattr(container, "Decomposes") + and container.Decomposes + and hasattr(container.Decomposes[0].RelatingObject, "ObjectPlacement") + ): + # this spatial element is part of a decomposition + parent_placement = container.Decomposes[0].RelatingObject.ObjectPlacement + parent_matrix = ifcopenshell.util.placement.get_local_placement(parent_placement)[:3, :3] + if np.allclose(combined_matrix, parent_matrix, atol=1e-6): + # this spatial element has the same orientation as its parent + cls.create_orientation_slot(container=container.Decomposes[0].RelatingObject) + return - # this product has a unique orientation - orientation_name = product.is_a() + "/" + product.Name + # this spatial element has a unique orientation + orientation_name = container.is_a() + "/" + container.Name - # stash selected objects - active_object = bpy.context.view_layer.objects.active - selected_objects = list(bpy.context.view_layer.objects.selected) - # bpy.ops.transform.create_orientation() requires a dummy object - bpy.ops.object.empty_add(type="PLAIN_AXES") + # stash selected objects + active_object = bpy.context.view_layer.objects.active + selected_objects = list(bpy.context.view_layer.objects.selected) - bpy.ops.transform.create_orientation(name=orientation_name, overwrite=True) - active_slot.type = orientation_name - active_slot.custom_orientation.matrix = np.linalg.inv(combined_matrix) + # bpy.ops.transform.create_orientation() requires a dummy object + bpy.ops.object.empty_add(type="PLAIN_AXES") + bpy.ops.transform.create_orientation(name=orientation_name, overwrite=True) + active_slot.type = orientation_name + active_slot.custom_orientation.matrix = np.linalg.inv(combined_matrix) - # delete dummy object - bpy.ops.object.delete() - # reinstate selected objects - for obj in selected_objects: - obj.select_set(True) - if active_object: - bpy.context.view_layer.objects.active = active_object + # delete dummy object + bpy.ops.object.delete() - if not use: - active_slot.type = initial_orientation + # reinstate selected objects + for obj in selected_objects: + obj.select_set(True) + if active_object: + bpy.context.view_layer.objects.active = active_object @classmethod def edit_container_attributes(cls, entity: ifcopenshell.entity_instance) -> None: